about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/regression.md68
-rw-r--r--.github/workflows/ci.yml34
-rw-r--r--Cargo.lock95
-rw-r--r--compiler/rustc_ast/src/ast.rs10
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs19
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs22
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs33
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs35
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs261
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs58
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs24
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs45
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs15
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/fingerprint.rs4
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs6
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs2
-rw-r--r--compiler/rustc_driver/src/lib.rs49
-rw-r--r--compiler/rustc_hir/src/definitions.rs2
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs6
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs4
-rw-r--r--compiler/rustc_interface/src/queries.rs38
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp39
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs2
-rw-r--r--compiler/rustc_middle/src/ich/impls_syntax.rs22
-rw-r--r--compiler/rustc_middle/src/middle/region.rs10
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/query.rs36
-rw-r--r--compiler/rustc_middle/src/mir/terminator/mod.rs113
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs3
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/query/on_disk_cache.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs6
-rw-r--r--compiler/rustc_mir/src/borrow_check/invalidation.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/mod.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs2
-rw-r--r--compiler/rustc_mir/src/const_eval/eval_queries.rs2
-rw-r--r--compiler/rustc_mir/src/dataflow/framework/direction.rs18
-rw-r--r--compiler/rustc_mir/src/interpret/eval_context.rs8
-rw-r--r--compiler/rustc_mir/src/interpret/machine.rs7
-rw-r--r--compiler/rustc_mir/src/interpret/operand.rs6
-rw-r--r--compiler/rustc_mir/src/interpret/place.rs13
-rw-r--r--compiler/rustc_mir/src/interpret/terminator.rs10
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs18
-rw-r--r--compiler/rustc_mir/src/transform/check_const_item_mutation.rs2
-rw-r--r--compiler/rustc_mir/src/transform/early_otherwise_branch.rs35
-rw-r--r--compiler/rustc_mir/src/transform/generator.rs6
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs2
-rw-r--r--compiler/rustc_mir/src/transform/match_branches.rs9
-rw-r--r--compiler/rustc_mir/src/transform/mod.rs8
-rw-r--r--compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs2
-rw-r--r--compiler/rustc_mir/src/transform/simplify_branches.rs9
-rw-r--r--compiler/rustc_mir/src/transform/simplify_comparison_integral.rs48
-rw-r--r--compiler/rustc_mir/src/transform/simplify_try.rs14
-rw-r--r--compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs23
-rw-r--r--compiler/rustc_mir/src/transform/unreachable_prop.rs20
-rw-r--r--compiler/rustc_mir/src/transform/validate.rs17
-rw-r--r--compiler/rustc_mir/src/util/elaborate_drops.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs60
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs8
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs40
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs21
-rw-r--r--compiler/rustc_resolve/src/late.rs20
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs219
-rw-r--r--compiler/rustc_resolve/src/lib.rs2
-rw-r--r--compiler/rustc_serialize/src/opaque.rs6
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_target/src/spec/android_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/dragonfly_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/freebsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs15
-rw-r--r--compiler/rustc_target/src/spec/netbsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/openbsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/windows_gnu_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs5
-rw-r--r--compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs33
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs145
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs51
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs59
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs168
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs95
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs2
-rw-r--r--library/alloc/src/collections/btree/node.rs52
m---------library/backtrace0
-rw-r--r--library/core/src/ffi.rs2
-rw-r--r--library/core/src/slice/mod.rs68
-rw-r--r--library/core/tests/num/int_macros.rs4
-rw-r--r--library/core/tests/slice.rs32
-rw-r--r--library/std/src/sys/unix/time.rs56
-rw-r--r--library/std/src/sys/unsupported/common.rs13
-rw-r--r--library/std/src/sys/unsupported/mod.rs2
-rw-r--r--library/std/src/sys/unsupported/mutex.rs22
-rw-r--r--library/std/src/sys/unsupported/rwlock.rs33
-rw-r--r--library/std/src/sys/wasi/ext/io.rs18
-rw-r--r--library/std/src/sys/wasi/mod.rs1
-rw-r--r--library/std/src/sys/wasm/mod.rs1
-rw-r--r--library/std/src/sys/windows/time.rs36
-rw-r--r--library/std/src/sys_common/mutex.rs1
-rw-r--r--library/test/src/formatters/json.rs4
-rw-r--r--src/bootstrap/README.md6
-rw-r--r--src/bootstrap/bin/main.rs8
-rw-r--r--src/bootstrap/builder.rs43
-rw-r--r--src/bootstrap/config.rs2
-rw-r--r--src/bootstrap/dist.rs68
-rw-r--r--src/bootstrap/flags.rs7
-rw-r--r--src/bootstrap/lib.rs5
-rw-r--r--src/bootstrap/run.rs1
-rw-r--r--src/bootstrap/setup.rs11
-rw-r--r--src/bootstrap/test.rs9
-rw-r--r--src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile4
-rw-r--r--src/ci/github-actions/ci.yml49
-rwxr-xr-xsrc/ci/scripts/install-clang.sh14
-rwxr-xr-xsrc/ci/scripts/install-mingw.sh7
-rwxr-xr-xsrc/ci/scripts/select-xcode.sh13
-rw-r--r--src/doc/rustc/src/codegen-options/index.md20
-rw-r--r--src/doc/rustc/src/platform-support.md8
-rw-r--r--src/etc/gdb_providers.py63
-rw-r--r--src/librustdoc/clean/types.rs54
-rw-r--r--src/librustdoc/clean/utils.rs4
-rw-r--r--src/librustdoc/html/static/rustdoc.css10
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs36
-rw-r--r--src/librustdoc/passes/collapse_docs.rs5
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs311
-rw-r--r--src/librustdoc/passes/doc_test_lints.rs15
-rw-r--r--src/test/codegen/tune-cpu-on-functions.rs21
-rw-r--r--src/test/debuginfo/pretty-std-collections.rs16
-rw-r--r--src/test/incremental/thinlto/cgu_invalidated_via_import.rs4
-rw-r--r--src/test/incremental/thinlto/cgu_keeps_identical_fn.rs47
-rw-r--r--src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs4
-rw-r--r--src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs58
-rw-r--r--src/test/rustdoc-ui/coverage/allow_missing_docs.rs41
-rw-r--r--src/test/rustdoc-ui/coverage/allow_missing_docs.stderr20
-rw-r--r--src/test/rustdoc-ui/coverage/allow_missing_docs.stdout7
-rw-r--r--src/test/rustdoc-ui/intra-links-ambiguity.rs4
-rw-r--r--src/test/rustdoc-ui/intra-links-ambiguity.stderr17
-rw-r--r--src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs6
-rw-r--r--src/test/rustdoc/auxiliary/reexport-check.rs2
-rw-r--r--src/test/rustdoc/intra-link-reexport-additional-docs.rs9
-rw-r--r--src/test/rustdoc/primitive-link.rs3
-rw-r--r--src/test/rustdoc/reexport-check.rs8
-rw-r--r--src/test/ui-fulldeps/compiler-calls.rs11
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr12
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.rs4
-rw-r--r--src/test/ui/const-generics/const-argument-if-length.min.stderr6
-rw-r--r--src/test/ui/const-generics/const-argument-if-length.rs2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr6
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr12
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr6
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs2
-rw-r--r--src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr12
-rw-r--r--src/test/ui/const-generics/generic-function-call-in-array-length.rs4
-rw-r--r--src/test/ui/const-generics/generic-sum-in-array-length.min.stderr12
-rw-r--r--src/test/ui/const-generics/generic-sum-in-array-length.rs4
-rw-r--r--src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr6
-rw-r--r--src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs2
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr12
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.rs4
-rw-r--r--src/test/ui/const-generics/issue-67375.min.stderr6
-rw-r--r--src/test/ui/const-generics/issue-67375.rs2
-rw-r--r--src/test/ui/const-generics/issue-67945-1.min.stderr12
-rw-r--r--src/test/ui/const-generics/issue-67945-1.rs4
-rw-r--r--src/test/ui/const-generics/issue-67945-2.min.stderr12
-rw-r--r--src/test/ui/const-generics/issue-67945-2.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-61747.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-61747.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-64494.min.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-64494.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-66205.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-66205.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-67739.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-67739.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-68366.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-68366.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-68977.min.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-68977.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-72787.min.stderr24
-rw-r--r--src/test/ui/const-generics/issues/issue-72787.rs8
-rw-r--r--src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs4
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-expression.rs8
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-expression.stderr24
-rw-r--r--src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr6
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr6
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs2
-rw-r--r--src/test/ui/const-generics/wf-misc.min.stderr12
-rw-r--r--src/test/ui/const-generics/wf-misc.rs4
-rw-r--r--src/test/ui/generator/yielding-in-match-guards.rs24
-rw-r--r--src/test/ui/lto-opt-level-s.rs7
-rw-r--r--src/test/ui/lto-opt-level-z.rs7
-rw-r--r--src/test/ui/parser/float-field.stderr10
-rw-r--r--src/test/ui/traits/assoc_type_bound_with_struct.rs19
-rw-r--r--src/test/ui/traits/assoc_type_bound_with_struct.stderr83
-rw-r--r--src/test/ui/traits/trait-bounds-not-on-struct.rs33
-rw-r--r--src/test/ui/traits/trait-bounds-not-on-struct.stderr165
-rw-r--r--src/test/ui/tuple/index-invalid.stderr8
-rw-r--r--src/test/ui/union/union-deref.stderr6
-rw-r--r--src/tools/build-manifest/Cargo.toml1
-rw-r--r--src/tools/build-manifest/README.md4
-rw-r--r--src/tools/build-manifest/src/main.rs37
-rw-r--r--src/tools/build-manifest/src/versions.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs1
-rw-r--r--src/tools/clippy/src/driver.rs4
m---------src/tools/miri24
-rwxr-xr-xsrc/tools/publish_toolstate.py2
m---------src/tools/rls0
-rw-r--r--triagebot.toml1
242 files changed, 2886 insertions, 1792 deletions
diff --git a/.github/ISSUE_TEMPLATE/regression.md b/.github/ISSUE_TEMPLATE/regression.md
new file mode 100644
index 00000000000..ffab883987c
--- /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 23058b7a808..828a3bc71b8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -89,6 +89,9 @@ jobs:
       - 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
@@ -300,6 +303,20 @@ jobs:
               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_beta.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"
@@ -369,7 +386,7 @@ jobs:
             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
@@ -379,6 +396,12 @@ jobs:
               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"
@@ -437,6 +460,9 @@ jobs:
       - 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
@@ -544,6 +570,9 @@ jobs:
       - 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 +677,9 @@ jobs:
       - 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/Cargo.lock b/Cargo.lock
index ec4f3091d2d..9c48ff86769 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -132,13 +132,13 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
 
 [[package]]
 name = "backtrace"
-version = "0.3.52"
+version = "0.3.53"
 dependencies = [
  "addr2line",
- "cfg-if",
+ "cfg-if 1.0.0",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.21.1",
  "rustc-demangle",
 ]
 
@@ -243,6 +243,7 @@ dependencies = [
  "anyhow",
  "flate2",
  "hex 0.4.2",
+ "num_cpus",
  "rayon",
  "serde",
  "serde_json",
@@ -441,6 +442,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
 name = "chalk-derive"
 version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -722,17 +729,17 @@ version = "1.2.0"
 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]]
@@ -753,7 +760,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
 dependencies = [
  "autocfg",
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "lazy_static",
  "maybe-uninit",
@@ -776,7 +783,7 @@ version = "0.2.3"
 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",
 ]
@@ -787,7 +794,7 @@ version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "lazy_static",
 ]
 
@@ -798,7 +805,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
 dependencies = [
  "autocfg",
- "cfg-if",
+ "cfg-if 0.1.10",
  "lazy_static",
 ]
 
@@ -928,7 +935,7 @@ version = "2.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "dirs-sys",
 ]
 
@@ -1070,7 +1077,7 @@ version = "0.2.12"
 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",
@@ -1088,7 +1095,7 @@ version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "crc32fast",
  "libc",
  "libz-sys",
@@ -1219,7 +1226,7 @@ version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "wasi",
 ]
@@ -1230,7 +1237,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "wasi",
 ]
@@ -1759,7 +1766,7 @@ version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
 ]
 
 [[package]]
@@ -1989,7 +1996,7 @@ version = "0.6.22"
 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",
@@ -2070,7 +2077,7 @@ version = "0.2.34"
 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",
 ]
@@ -2122,6 +2129,12 @@ dependencies = [
 ]
 
 [[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"
@@ -2164,7 +2177,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
 dependencies = [
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "foreign-types",
  "lazy_static",
  "libc",
@@ -2179,9 +2192,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
 
 [[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",
 ]
@@ -2221,14 +2234,14 @@ version = "0.3.3"
 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",
@@ -2239,7 +2252,7 @@ name = "panic_unwind"
 version = "0.0.0"
 dependencies = [
  "alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
@@ -2302,7 +2315,7 @@ version = "0.6.2"
 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",
@@ -2317,7 +2330,7 @@ version = "0.7.2"
 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",
@@ -2331,7 +2344,7 @@ version = "0.8.0"
 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",
@@ -3035,7 +3048,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "14ffd17a37e00d77926a0713f191c59ff3aeb2b551a024c7cfffce14bab79be8"
 dependencies = [
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "ena",
  "indexmap",
@@ -3211,7 +3224,7 @@ version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1c267f15c3cfc82a8a441d2bf86bcccf299d1eb625822468e3d8ee6f7c5a1c89"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "md-5",
  "rustc-ap-rustc_arena",
  "rustc-ap-rustc_data_structures",
@@ -3504,7 +3517,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "ena",
  "indexmap",
@@ -4055,7 +4068,7 @@ dependencies = [
 name = "rustc_span"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "md-5",
  "rustc_arena",
  "rustc_data_structures",
@@ -4416,7 +4429,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1"
 dependencies = [
  "block-buffer 0.9.0",
- "cfg-if",
+ "cfg-if 0.1.10",
  "cpuid-bool",
  "digest 0.9.0",
  "opaque-debug 0.3.0",
@@ -4502,7 +4515,7 @@ version = "0.3.12"
 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",
@@ -4521,7 +4534,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "21ccb4c06ec57bc82d0f610f1a2963d7648700e43a6f513e564b9c89f7991786"
 dependencies = [
  "cc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "psm",
  "winapi 0.3.9",
@@ -4533,7 +4546,7 @@ version = "0.0.0"
 dependencies = [
  "addr2line",
  "alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "dlmalloc",
@@ -4542,7 +4555,7 @@ dependencies = [
  "hermit-abi",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.20.0",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
@@ -4675,7 +4688,7 @@ version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "rand",
  "redox_syscall",
@@ -4735,7 +4748,7 @@ dependencies = [
 name = "test"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "core",
  "getopts",
  "libc",
@@ -5080,7 +5093,7 @@ version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "tracing-attributes",
  "tracing-core",
 ]
@@ -5277,7 +5290,7 @@ name = "unwind"
 version = "0.0.0"
 dependencies = [
  "cc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 8d9d4123c79..245353c2e07 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1884,6 +1884,16 @@ impl Clone for Ty {
     }
 }
 
+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)]
 pub struct BareFnTy {
     pub unsafety: Unsafe,
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index ca7f127ced6..95f969d7691 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -170,17 +170,11 @@ pub enum Token {
 
 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 }))
     }
 }
 
@@ -491,12 +485,9 @@ impl Printer {
     }
 
     fn get_top(&mut self) -> PrintStackElem {
-        match self.print_stack.last() {
-            Some(el) => *el,
-            None => {
-                PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
-            }
-        }
+        *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_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index f4924997d1a..2e52d2a3923 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 @@ impl<'a> MethodDef<'a> {
     /// 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 @@ impl<'a> MethodDef<'a> {
                 // 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 @@ impl<'a> MethodDef<'a> {
             // 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 @@ impl<'a> MethodDef<'a> {
             // 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 9c8e0fc2f01..bf950934928 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -68,7 +68,14 @@ fn call_intrinsic(
 ) -> 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 ff81b5eca13..b69b00d65f2 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -385,7 +385,7 @@ pub mod printf {
         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 @@ pub mod printf {
                     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 @@ pub mod printf {
         }
 
         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 @@ pub mod printf {
         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 @@ pub mod printf {
                     }
                 }
                 '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 @@ pub mod printf {
 
     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 @@ pub mod printf {
         }
     }
 
-    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 @@ pub mod shell {
     }
 
     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_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index f02c30c3ee3..f1fa9864616 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -6,7 +6,7 @@ use rustc_codegen_ssa::traits::*;
 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;
@@ -194,6 +194,18 @@ pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     );
 }
 
+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) {
@@ -303,6 +315,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     // 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())
@@ -352,23 +367,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     }
 }
 
-pub fn provide(providers: &mut Providers) {
-    use rustc_codegen_ssa::target_features::{all_known_features, supported_target_features};
-    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.
-            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()
-        }
-    };
-
-    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/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 4b2d5907a02..ff312bade25 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -2,14 +2,14 @@ use crate::back::write::{
     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 tracing::{debug, info};
 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 @@ fn thin_lto(
         )
         .ok_or_else(|| write::llvm_err(&diag_handler, "failed to prepare thin LTO context"))?;
 
-        info!("thin LTO data created");
+        let data = ThinData(data);
 
-        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");
+        info!("thin LTO data created");
 
-        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 @@ fn thin_lto(
         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 @@ fn thin_lto(
         }
 
         // 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 @@ fn thin_lto(
     }
 }
 
-/// 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 @@ pub unsafe fn optimize_thin_module(
     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/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 1696f35563d..d3c71ff501b 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -417,7 +417,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 
     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) {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 7cdd366175d..6516869e47b 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -120,10 +120,8 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         // 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.target.options.dwarf_version {
+            llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), version)
         }
 
         // Indicate that we want CodeView debug information on MSVC
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 1237b39b300..5974b59d39e 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::back::write::{CodegenContext, FatLTOInput, ModuleConfig};
 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 {
@@ -116,6 +115,9 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
     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 {
@@ -249,11 +251,11 @@ impl CodegenBackend for LlvmCodegenBackend {
     }
 
     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>(
@@ -274,47 +276,27 @@ impl CodegenBackend for LlvmCodegenBackend {
         &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", || {
@@ -331,16 +313,6 @@ impl CodegenBackend for LlvmCodegenBackend {
             );
         });
 
-        // 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/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index af3f3e7aa03..4c1fee0106a 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2362,4 +2362,10 @@ extern "C" {
         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_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index d42020047fd..88d73f2a864 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -122,7 +122,7 @@ unsafe fn configure_llvm(sess: &Session) {
 
     llvm::LLVMInitializePasses();
 
-    ::rustc_llvm::initialize_available_targets();
+    rustc_llvm::initialize_available_targets();
 
     llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
 }
@@ -202,11 +202,7 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) {
     }
 }
 
-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;
     }
@@ -217,3 +213,19 @@ pub fn target_cpu(sess: &Session) -> &str {
         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.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_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 0ddf8bd316f..09dc51c57c2 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -221,10 +221,8 @@ impl<'a> GccLinker<'a> {
         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));
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 0edf0fcd1a2..3a7676d30bb 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::fx::FxHashMap;
 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};
@@ -414,7 +413,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     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 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     OngoingCodegen {
         backend,
         crate_name,
-        crate_hash,
         metadata,
         windows_subsystem,
         linker_info,
@@ -658,15 +655,6 @@ fn produce_final_output_artifacts(
     // 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>),
@@ -1175,7 +1163,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     // 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>| {
@@ -1720,7 +1708,6 @@ impl SharedEmitterMain {
 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 +1753,6 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
         (
             CodegenResults {
                 crate_name: self.crate_name,
-                crate_hash: self.crate_hash,
                 metadata: self.metadata,
                 windows_subsystem: self.windows_subsystem,
                 linker_info: self.linker_info,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 8e6f8e193c0..7f918bd168e 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -695,7 +695,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         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);
 
@@ -754,8 +754,8 @@ impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
 }
 
 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/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index e34371ef59a..70b92b234e9 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -21,7 +21,6 @@ extern crate tracing;
 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;
@@ -134,7 +133,6 @@ pub struct CodegenResults {
     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,
@@ -144,6 +142,7 @@ pub struct CodegenResults {
 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 703a17b200a..353189ae1f0 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -12,9 +12,9 @@ use crate::MemFlags;
 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::call::{ArgAbi, FnAbi, PassMode};
 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> {
@@ -198,42 +196,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         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))),
             );
         }
     }
@@ -975,8 +968,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 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/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 4c61e21901b..24cd27cf3cf 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,3 +1,5 @@
+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;
@@ -148,3 +150,16 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt
         _ => &[],
     }
 }
+
+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 48c07b00894..3fb189e1984 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 @@ pub trait CodegenBackend {
         &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 @@ pub trait CodegenBackend {
     fn link(
         &self,
         sess: &Session,
-        codegen_results: Box<dyn Any>,
+        codegen_results: CodegenResults,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorReported>;
 }
@@ -124,4 +124,5 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
         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/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs
index 698ef6083e6..82518b7f0c3 100644
--- a/compiler/rustc_codegen_ssa/src/traits/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs
@@ -85,7 +85,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
 }
 
 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_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index aba0bbbac80..ec2f9597b18 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -71,8 +71,8 @@ impl Fingerprint {
     }
 }
 
-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/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 7cf5202d919..c0193e9fa0c 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 @@ pub enum ProcessResult<O, E> {
 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`,
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 4807380595d..9a28f8f4e21 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -93,7 +93,7 @@ impl<K: Ord, V> SortedMap<K, V> {
 
     /// 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 @@ impl<K: Ord, V> SortedMap<K, V> {
         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> SortedMap<K, V> {
 
 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/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 68875b3fbde..579eb1cb7da 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -20,7 +20,7 @@ pub struct StableHasher {
 }
 
 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)
     }
 }
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index dd9643913ed..c7fb6a55d5a 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -134,9 +134,52 @@ pub fn diagnostics_registry() -> Registry {
     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>>,
@@ -599,7 +642,7 @@ impl RustcDefaultCalls {
             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")
         }
@@ -1285,7 +1328,7 @@ pub fn main() -> ! {
                 })
             })
             .collect::<Vec<_>>();
-        run_compiler(&args, &mut callbacks, None, 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_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index afefde07f92..8f76551677c 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -118,7 +118,7 @@ impl DefKey {
 
         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.
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 839891f322c..5295ebfafa8 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -341,7 +341,7 @@ where
         // 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);
@@ -680,7 +680,7 @@ where
             //   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 +709,7 @@ where
             // 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 2851da89ab2..eb1a7806256 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -110,7 +110,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
 
     /// 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_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 66d3765d347..d9c24cc3994 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -551,6 +551,10 @@ fn write_out_deps(
             .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 8b82217a91a..1de7350a3e2 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -3,6 +3,7 @@ use crate::passes::{self, BoxedResolver, QueryContext};
 
 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::arena::Arena;
 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 @@ impl<'tcx> Queries<'tcx> {
     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 @@ impl<'tcx> Queries<'tcx> {
             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 @@ pub struct Linker {
     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 @@ impl Linker {
         {
             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 07ce9d0cd94..6553d0ecfdb 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -585,6 +585,7 @@ fn test_debugging_options_tracking_hash() {
     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_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 7b1c3f9ba2c..71ca4f23bbb 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1212,6 +1212,7 @@ struct LLVMRustThinLTOData {
   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 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
   //
   // 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 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
   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 @@ extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload
 // 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 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
   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_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 60705f68681..05b8dad3097 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -94,7 +94,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     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 => {
diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs
index e3d4655831b..7aba4fc64a9 100644
--- a/compiler/rustc_middle/src/ich/impls_syntax.rs
+++ b/compiler/rustc_middle/src/ich/impls_syntax.rs
@@ -5,7 +5,7 @@ use crate::ich::StableHashingContext;
 
 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 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
     }
 }
 
-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 @@ fn stable_non_narrow_char(
     (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/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 4c6ac820604..38cb3c1701f 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -283,23 +283,27 @@ pub struct ScopeTree {
     /// 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.
     ///
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index ee1ea816e01..5ebe38b2d7e 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -40,7 +40,7 @@ pub struct Allocation<Tag = (), Extra = ()> {
     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/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 3751249853f..893ab79f4f5 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -58,7 +58,7 @@ impl<'tcx> ConstValue<'tcx> {
 
     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))
+            std::str::from_utf8(data.inspect_with_uninit_and_ptr_outside_interpreter(start..end))
                 .ok()
         } else {
             None
@@ -465,7 +465,7 @@ impl<'tcx, Tag> Scalar<Tag> {
 
     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 92a2baa30ee..ef0639bcd79 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -775,7 +775,7 @@ mod binding_form_impl {
     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),
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 0878e9313d8..b5cdd7edb8d 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,7 +408,12 @@ pub struct CoverageInfo {
     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> {
+    #[inline]
     pub fn mir_borrowck_opt_const_arg(
         self,
         def: ty::WithOptConstParam<LocalDefId>,
@@ -419,6 +425,7 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    #[inline]
     pub fn mir_const_qualif_opt_const_arg(
         self,
         def: ty::WithOptConstParam<LocalDefId>,
@@ -430,7 +437,8 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    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 +448,28 @@ impl<'tcx> TyCtxt<'tcx> {
             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/terminator/mod.rs b/compiler/rustc_middle/src/mir/terminator/mod.rs
index 8909f02270c..e1071454e65 100644
--- a/compiler/rustc_middle/src/mir/terminator/mod.rs
+++ b/compiler/rustc_middle/src/mir/terminator/mod.rs
@@ -1,6 +1,7 @@
 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,
@@ -16,6 +17,87 @@ 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.
@@ -32,23 +114,7 @@ pub enum TerminatorKind<'tcx> {
         /// 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>,
+        targets: SwitchTargets,
     },
 
     /// Indicates that the landing pad is finished and unwinding should
@@ -227,12 +293,10 @@ impl<'tcx> TerminatorKind<'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],
+            targets: SwitchTargets::static_if(0, f, t),
         }
     }
 
@@ -263,7 +327,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             | 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[..]),
+            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))
             }
@@ -297,7 +361,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             | 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[..]),
+            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))
             }
@@ -469,11 +533,12 @@ impl<'tcx> TerminatorKind<'tcx> {
         match *self {
             Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
             Goto { .. } => vec!["".into()],
-            SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| {
+            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;
-                values
+                targets
+                    .values
                     .iter()
                     .map(|&u| {
                         ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index ad2eae0298c..9297aed66a4 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -21,10 +21,9 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
 
         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 9a6bfa10189..1adebe30b5e 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -453,7 +453,6 @@ macro_rules! make_mir_visitor {
                     TerminatorKind::SwitchInt {
                         discr,
                         switch_ty,
-                        values: _,
                         targets: _
                     } => {
                         self.visit_operand(discr, location);
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index f6f71d002a8..fd24de1529d 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1894,7 +1894,7 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
     }
 }
 
-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>;
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f069faed9e2..cccfc5eced9 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2953,13 +2953,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// 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(..)
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 48a62b64604..a594a8ad512 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 @@ impl<'tcx> TyCtxt<'tcx> {
     {
         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/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index e1f02d0f704..68c36642c88 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1142,7 +1142,7 @@ pub trait PrettyPrinter<'tcx>:
                 // 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)
             }
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 b0c48a860eb..6cfa6dbeccd 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 @@ impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> {
 // 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,
 {
@@ -1023,7 +1023,7 @@ where
     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/util.rs b/compiler/rustc_middle/src/ty/util.rs
index d8ea2f67393..8734acad9b2 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -341,7 +341,7 @@ impl<'tcx> TyCtxt<'tcx> {
     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);
@@ -646,8 +646,8 @@ impl<'tcx> ty::TyS<'tcx> {
             }
             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_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs
index c84ccafaff5..8c05e6fd5d0 100644
--- a/compiler/rustc_mir/src/borrow_check/invalidation.rs
+++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs
@@ -117,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
         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 9b34db1de40..4b7af271bae 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -671,7 +671,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
         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: _ } => {
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 f8a8801595a..4fc1c570e46 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -1777,7 +1777,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 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);
                 }
             }
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index 57aa216850a..6ef73b04238 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -343,7 +343,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                     // 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/dataflow/framework/direction.rs b/compiler/rustc_mir/src/dataflow/framework/direction.rs
index ca2bb6e0bf7..8a9ced91eb3 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 @@ impl Direction for Forward {
                 }
             }
 
-            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 @@ impl Direction for Forward {
                 } = 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 @@ impl Direction for Forward {
 
 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 @@ where
         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 @@ where
 
         // 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/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index 93da6e3d38a..ec1195d3703 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -477,16 +477,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
         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))
                 }
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs
index 3718da1723b..66dbacb2f9d 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 @@ pub trait AllocMap<K: Hash + Eq, V> {
 /// 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 735f890a33b..d8f27ec9545 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -133,7 +133,7 @@ impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
     }
 }
 
-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 struct OpTy<'tcx, Tag = ()> {
     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 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     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 72551b23370..fe25f8ce962 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 struct PlaceTy<'tcx, Tag = ()> {
     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 struct MPlaceTy<'tcx, Tag = ()> {
     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 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
 }
 
 // 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<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
     }
 }
 
-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<Tag: ::std::fmt::Debug> Place<Tag> {
     }
 }
 
-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<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
 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 9f200ca62b8..bb11c2a23bd 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_mir/src/interpret/terminator.rs
@@ -24,16 +24,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             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 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         )?
                         .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 7e12cc9176e..417176564b9 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -197,6 +197,7 @@ use rustc_session::config::EntryFnType;
 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 enum MonoItemCollectionMode {
 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 @@ impl<'tcx> InliningMap<'tcx> {
         }
 
         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 @@ impl<'tcx> InliningMap<'tcx> {
     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 @@ impl<'tcx> InliningMap<'tcx> {
     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/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
index 26993a6b941..fb89b36060a 100644
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
@@ -53,7 +53,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
         //
         //     #[const_mutation_allowed]
         //     pub const LOG: Log = Log { msg: "" };
-        match self.tcx.calculate_dtor(def_id, &mut |_, _| Ok(())) {
+        match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) {
             Some(_) => None,
             None => Some(def_id),
         }
diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
index 237a5c7864b..f97dcf4852d 100644
--- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
+++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
@@ -1,7 +1,7 @@
 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;
 
@@ -95,15 +95,17 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
                 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();
+
+            let targets = SwitchTargets::new(
+                new_targets,
+                opt_to_apply.infos[0].first_switch_info.otherwise_bb,
+            );
 
-            // add otherwise case in the end
-            targets_to_jump_to.push(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,
@@ -111,8 +113,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
                     // 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,
                 },
             }));
 
@@ -176,7 +177,7 @@ struct SwitchDiscriminantInfo<'tcx> {
     /// 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>,
@@ -211,7 +212,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
         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())
         });
 
@@ -253,7 +254,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
             }
 
             // 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;
             }
@@ -270,7 +271,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
             //  ```
             // 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"
@@ -296,18 +297,14 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
         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/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index 924bb4996fc..039d4753a8c 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -71,7 +71,6 @@ use rustc_middle::ty::GeneratorSubsts;
 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;
@@ -839,11 +838,12 @@ fn insert_switch<'tcx>(
 ) {
     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);
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index bec1eb79047..34aaefdcbea 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -771,7 +771,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                 *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/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index dad3812c5cd..8b2d6b09aa8 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -46,10 +46,13 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
                     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 b4f5947f5a3..ffb84950fc9 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -137,7 +137,7 @@ fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> FxHashSet<LocalDefId> {
 /// 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) }
 }
 
@@ -287,11 +287,7 @@ fn mir_promoted(
     // 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();
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 b45c533d2c0..31e201c3a5b 100644
--- a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
@@ -43,7 +43,7 @@ impl RemoveNoopLandingPads {
                     // 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/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs
index 161856a38ee..5f63c03993d 100644
--- a/compiler/rustc_mir/src/transform/simplify_branches.rs
+++ b/compiler/rustc_mir/src/transform/simplify_branches.rs
@@ -29,17 +29,16 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranches {
                 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 9f837cf78a6..6372f8960dd 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 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},
 };
@@ -43,19 +45,21 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
                 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 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
                 }
                 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 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
                 }
             }
 
-            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 @@ impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> {
             .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 @@ impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> {
                                         branch_value_scalar,
                                         branch_value_ty,
                                         op: *op,
-                                        values: values.clone().into_owned(),
                                         targets: targets.clone(),
                                     })
                                 }
@@ -220,8 +226,6 @@ struct OptimizationInfo<'tcx> {
     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 a4e7a5a9453..27bb1def726 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir/src/transform/simplify_try.rs
@@ -576,15 +576,13 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
             .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,
                 };
 
diff --git a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
index 87906e83ed5..465832c89fd 100644
--- a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
@@ -3,7 +3,8 @@
 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};
@@ -101,21 +102,15 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
 
             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);
-
-                values.to_mut().retain(|var| allowed_variants.contains(var));
+                let new_targets = SwitchTargets::new(
+                    targets.iter().filter(|(val, _)| allowed_variants.contains(val)),
+                    targets.otherwise(),
+                );
+
+                *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 c6426a06ea1..f6d39dae342 100644
--- a/compiler/rustc_mir/src/transform/unreachable_prop.rs
+++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs
@@ -7,7 +7,6 @@ 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;
 
@@ -69,14 +68,15 @@ where
 {
     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();
+        TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => {
+            let otherwise = targets.otherwise();
+
+            let original_targets_len = targets.iter().len() + 1;
             let (mut values, mut targets): (Vec<_>, Vec<_>) =
-                values.iter().zip(targets.iter()).filter(|(_, &t)| !predicate(t)).unzip();
+                targets.iter().filter(|(_, bb)| !predicate(*bb)).unzip();
 
-            if !predicate(*otherwise) {
-                targets.push(*otherwise);
+            if !predicate(otherwise) {
+                targets.push(otherwise);
             } else {
                 values.pop();
             }
@@ -91,8 +91,10 @@ where
                 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 cf51e86c5bc..48477f60ef7 100644
--- a/compiler/rustc_mir/src/transform/validate.rs
+++ b/compiler/rustc_mir/src/transform/validate.rs
@@ -334,7 +334,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             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(
@@ -345,19 +345,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         ),
                     );
                 }
-                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 {
-                    self.check_edge(location, *target, EdgeKind::Normal);
+                for (_, target) in targets.iter() {
+                    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);
diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs
index 43fa15d7e49..0e2d8e5495b 100644
--- a/compiler/rustc_mir/src/util/elaborate_drops.rs
+++ b/compiler/rustc_mir/src/util/elaborate_drops.rs
@@ -588,8 +588,10 @@ where
                 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(),
@@ -758,8 +760,6 @@ where
         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)),
@@ -771,11 +771,11 @@ where
                 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),
-                    ],
+                    ),
                 },
             }),
         };
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index a28a181e935..e46274770be 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 @@ use std::mem;
 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 02dcf0394f6..c4191900147 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 } 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);
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 047bf7db4c8..25a8565fb43 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -96,14 +96,14 @@ impl PatCtxt<'_, '_> {
                 }
                 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",
                     )
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 718ed78889f..d46e9a98825 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -1060,13 +1060,13 @@ crate fn compare_const_vals<'tcx>(
         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/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0eac04df3c9..a6df41f47ce 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust;
 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;
 
@@ -839,9 +840,10 @@ impl<'a> Parser<'a> {
         }
         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 @@ impl<'a> Parser<'a> {
             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,21 +873,40 @@ impl<'a> Parser<'a> {
             }
             // 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.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);
+                let next_token1 = Token::new(token::Dot, dot_span);
                 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);
+                let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
                 self.bump_with(next_token2); // `.`
                 self.parse_tuple_field_access_expr(lo, base1, symbol2, suffix, None)
             }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index e3cf6d12bd5..774a147c114 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -469,24 +469,17 @@ impl<'a> Resolver<'a> {
             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",
-                );
-                err.span_label(
-                    span,
-                    &format!(
-                        "non-trivial anonymous constants must not depend on the parameter `{}`",
-                        name
-                    ),
+                    "generic parameters may not be used in const operations",
                 );
+                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
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 2c01934b490..219517b4ab2 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -384,6 +384,13 @@ struct DiagnosticMetadata<'ast> {
 
     /// 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 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         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 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                     .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(
@@ -660,6 +672,14 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         }
         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 15e72228870..bee05e77382 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,6 +8,7 @@ use crate::{PathResult, PathSource, Segment};
 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;
@@ -19,7 +20,7 @@ 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;
 
@@ -439,27 +440,213 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             }
         }
 
-        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);
-
-            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 !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();
+
+                    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>)> {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index fe8f5926385..6677a5ffe28 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -218,7 +218,7 @@ enum ResolutionError<'a> {
     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 },
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index fa4423e261d..8b79c93e760 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -107,7 +107,7 @@ impl serialize::Encoder for Encoder {
 
     #[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 @@ impl<'a> serialize::Decoder for Decoder<'a> {
     #[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/options.rs b/compiler/rustc_session/src/options.rs
index a106007c274..627adcceb3f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1078,6 +1078,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "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
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index da9c93143bf..183a11a5277 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -132,7 +132,7 @@ impl SymbolMangler<'tcx> {
             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),
             };
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index bb11ce8ef28..0824bc30358 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -9,6 +9,7 @@ pub fn opts() -> TargetOptions {
         .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;
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index e7b565ae9ca..2e3c835c0e5 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions {
         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/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index c7062e1ca51..82dc5f54659 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions {
         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 d2a087ab62f..051325a8df6 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -26,6 +26,7 @@ pub fn opts() -> TargetOptions {
         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/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0cb072f387f..6f400854ec6 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -816,6 +816,9 @@ pub struct TargetOptions {
     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
@@ -1012,6 +1015,7 @@ impl Default for TargetOptions {
             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,
@@ -1165,6 +1169,15 @@ impl Target {
                     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) {
@@ -1417,6 +1430,7 @@ impl Target {
         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);
@@ -1654,6 +1668,7 @@ impl ToJson for Target {
         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);
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index 988346af2d7..d7baf81fce3 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions {
         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/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index cadd14df693..92a382e826b 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -26,6 +26,7 @@ pub fn opts() -> TargetOptions {
         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/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs
index 0234ff55f01..98e42f6c37c 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 @@ pub fn opts() -> TargetOptions {
             "-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_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
index e93755d1aa4..c901102ed6c 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
@@ -3,7 +3,10 @@ use crate::spec::{LinkerFlavor, LldFlavor, Target};
 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);
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 b288271406c..a775cfc4f79 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
@@ -3,7 +3,10 @@ use crate::spec::{LinkerFlavor, LldFlavor, Target};
 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);
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 3828cf4d302..1e1eb16faf4 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -147,11 +147,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     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();
@@ -212,13 +208,7 @@ impl AbstractConst<'tcx> {
         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 }))
     }
 
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 967374ffdc2..0584c56c9cb 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::{
 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 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     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()
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 27751eb554d..97dd180b27b 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -120,7 +120,8 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
         &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();
 
@@ -173,7 +174,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         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 +192,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         );
         self.register_predicate_obligations(infcx, obligations);
 
-        debug!("normalize_projection_type: result={:?}", normalized_ty);
+        debug!(?normalized_ty);
 
         normalized_ty
     }
@@ -205,7 +206,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         // 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 +343,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 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();
 
@@ -509,7 +510,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 }
 
                 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.
@@ -601,6 +602,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self, obligation, stalled_on))]
     fn process_trait_obligation(
         &mut self,
         obligation: &PredicateObligation<'tcx>,
@@ -613,8 +615,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
             // 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![]);
             }
@@ -622,17 +624,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
 
         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
@@ -652,10 +648,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 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))
             }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index de42aa0e6b7..8dbf7ec51c6 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -157,6 +157,7 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> {
 ///    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>,
@@ -164,8 +165,6 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
     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 =
@@ -191,7 +190,7 @@ fn project_and_unify_type<'cx, 'tcx>(
     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(
@@ -207,10 +206,7 @@ fn project_and_unify_type<'cx, 'tcx>(
         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
@@ -275,6 +271,7 @@ where
     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>,
@@ -286,16 +283,10 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
 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
 }
 
@@ -396,12 +387,11 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                     &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
             }
@@ -473,6 +463,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>(
 /// 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>,
@@ -486,13 +477,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
     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
@@ -508,10 +492,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             // 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) => {
@@ -529,10 +510,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             // 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);
         }
@@ -548,11 +526,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             // 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.
@@ -565,10 +539,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             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));
@@ -586,13 +557,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             // 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(
@@ -604,11 +569,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
                 );
                 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 {
@@ -621,21 +582,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             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)
         }
@@ -755,15 +709,12 @@ impl<'tcx> Progress<'tcx> {
 
     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
@@ -778,7 +729,7 @@ fn project_type<'cx, 'tcx>(
     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!");
@@ -787,7 +738,7 @@ fn project_type<'cx, 'tcx>(
 
     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())));
@@ -951,10 +902,11 @@ fn assemble_candidates_from_predicates<'cx, '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);
         if let ty::PredicateAtom::Projection(data) = predicate.skip_binders() {
             let data = ty::Binder::bind(data);
             let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
@@ -969,11 +921,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
                     )
                 });
 
-            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));
@@ -997,6 +945,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
     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();
@@ -1009,7 +959,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 return Err(());
             }
             Err(e) => {
-                debug!("assemble_candidates_from_impls: selection error {:?}", e);
+                debug!(error = ?e, "selection error");
                 candidate_set.mark_error(e);
                 return Err(());
             }
@@ -1020,7 +970,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
             | super::ImplSource::Generator(_)
             | super::ImplSource::FnPointer(_)
             | super::ImplSource::TraitAlias(_) => {
-                debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source);
+                debug!(?impl_source);
                 true
             }
             super::ImplSource::UserDefined(impl_data) => {
@@ -1066,10 +1016,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         !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
                     }
@@ -1176,8 +1125,7 @@ fn confirm_candidate<'cx, 'tcx>(
     obligation: &ProjectionTyObligation<'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::Object(poly_projection) => {
@@ -1220,9 +1168,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
         | 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 `{:?}`",
@@ -1246,10 +1193,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
         &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();
 
@@ -1339,10 +1283,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
         &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)
@@ -1357,7 +1298,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
 ) -> 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);
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index bdbf45f78a2..d748fc8235e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -44,7 +44,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
     {
         debug!(
             "normalize::<{}>(value={:?}, param_env={:?})",
-            ::std::any::type_name::<T>(),
+            std::any::type_name::<T>(),
             value,
             self.param_env,
         );
@@ -65,13 +65,13 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
         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 {
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 038ba431c47..fdf1641c986 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -22,6 +22,7 @@ use super::SelectionCandidate::{self, *};
 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>,
@@ -35,16 +36,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // 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;
         }
 
@@ -57,7 +55,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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,
@@ -103,7 +101,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         } else {
                             IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
                         };
-                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        debug!(?cause, "evaluate_stack: pushing cause");
                         self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
                     }
                 }
@@ -120,7 +118,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let mut candidates = candidate_set.vec;
 
-        debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
+        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
@@ -163,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .flat_map(Result::transpose)
             .collect::<Result<Vec<_>, _>>()?;
 
-        debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
+        debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len());
 
         let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
 
@@ -181,10 +179,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     )
                 });
                 if is_dup {
-                    debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
+                    debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
                     candidates.swap_remove(i);
                 } else {
-                    debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
+                    debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
                     i += 1;
 
                     // If there are *STILL* multiple candidates, give up
@@ -257,7 +255,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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.
@@ -308,7 +306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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.
@@ -341,7 +339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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
@@ -383,10 +381,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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);
             }
@@ -423,10 +418,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // 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);
                         }
@@ -503,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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
@@ -537,7 +532,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> 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();
 
@@ -604,8 +599,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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| {
@@ -645,7 +640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 _ => return,
             };
 
-            debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref);
+            debug!(?poly_trait_ref, "assemble_candidates_from_object_ty");
 
             // Count only those upcast versions that match the trait-ref
             // we are looking for. Specifically, do not only check for the
@@ -697,7 +692,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         };
         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).
@@ -758,7 +753,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> 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();
 
@@ -778,7 +773,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> 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 96f0bedf6f1..37d619d5942 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -42,13 +42,12 @@ use super::SelectionContext;
 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);
@@ -191,7 +190,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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
@@ -214,7 +213,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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 {
@@ -247,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             vec![]
         };
 
-        debug!("confirm_builtin_candidate: obligations={:?}", obligations);
+        debug!(?obligations);
 
         ImplSourceBuiltinData { nested: obligations }
     }
@@ -262,7 +261,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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());
@@ -278,7 +277,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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(
@@ -308,7 +307,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // 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 }
         })
@@ -319,13 +318,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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(
@@ -347,10 +346,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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,
@@ -360,10 +356,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             &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
@@ -379,8 +372,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> {
+        debug!(?obligation, "confirm_object_candidate");
         let tcx = self.tcx();
-        debug!("confirm_object_candidate({:?})", obligation);
 
         let trait_predicate =
             self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
@@ -507,7 +500,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
         }
 
-        debug!("confirm_object_candidate: nested: {:?}", nested);
+        debug!(?nested, "object nested obligations");
         ImplSourceObjectData { upcast_trait_ref, vtable_base, nested }
     }
 
@@ -516,7 +509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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());
@@ -554,7 +547,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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 =
@@ -571,10 +564,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 &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 }
         })
@@ -594,7 +584,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => 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(|| {
@@ -607,11 +597,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             )
         });
 
-        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(),
@@ -627,7 +613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &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()
@@ -654,10 +640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             )
         });
 
-        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(),
@@ -731,7 +714,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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 a142ba58a69..57b680b0e53 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -236,7 +236,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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(),
@@ -311,11 +311,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     /// 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();
@@ -344,7 +344,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
             Err(e) => Err(e),
             Ok(candidate) => {
-                debug!("select: candidate = {:?}", candidate);
+                debug!(?candidate);
                 Ok(Some(candidate))
             }
         }
@@ -362,7 +362,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     /// 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.
@@ -419,10 +419,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
     {
         let mut result = EvaluatedToOk;
-        debug!("evaluate_predicates_recursively({:?})", predicates);
+        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.
@@ -434,17 +433,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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(obligation={:?}, previous_stack={:?})",
-            obligation,
-            previous_stack.head()
-        );
-
         // `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
@@ -454,7 +452,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             None => self.check_recursion_limit(&obligation, &obligation)?,
         }
 
-        ensure_sufficient_stack(|| {
+        let result = ensure_sufficient_stack(|| {
             match obligation.predicate.skip_binders() {
                 ty::PredicateAtom::Trait(t, _) => {
                     let t = ty::Binder::bind(t);
@@ -561,10 +559,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
 
                 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 +605,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
             }
-        })
+        });
+
+        debug!(?result);
+
+        result
     }
 
     fn evaluate_trait_predicate_recursively<'o>(
@@ -618,7 +617,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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 +626,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // 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 +664,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         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 +676,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 );
             });
         } 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 +721,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             })
             .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 +741,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             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 +785,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // 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 +803,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 },
                             });
 
-                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        debug!(?cause, "evaluate_stack: pushing cause");
                         self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
                     }
                 }
@@ -824,10 +820,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     )
             })
         {
-            debug!(
-                "evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
-                stack.fresh_trait_ref
-            );
+            debug!("evaluate_stack --> unbound argument, recursive --> giving up",);
             return Ok(EvaluatedToUnknown);
         }
 
@@ -860,27 +853,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             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) => {
-                    debug!("evaluate_candidate: selection = {:?}", selection);
+                    debug!(?selection);
                     this.evaluate_predicates_recursively(
                         stack.list(),
                         selection.nested_obligations().into_iter(),
@@ -889,10 +883,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Err(..) => Ok(EvaluatedToErr),
             }
         })?;
-        debug!(
-            "evaluate_candidate: depth={} result={:?}",
-            stack.obligation.recursion_depth, result
-        );
+        debug!(?result);
         Ok(result)
     }
 
@@ -925,10 +916,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         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
@@ -938,7 +926,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
         }
 
-        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);
     }
 
@@ -1127,11 +1115,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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;
         }
 
@@ -1140,10 +1124,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // 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;
@@ -1151,10 +1132,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
         }
 
-        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);
     }
 
@@ -1172,9 +1150,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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;
@@ -1225,11 +1202,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             })
             .collect();
 
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             matching_bounds={:?}",
-            matching_bounds
-        );
+        debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds");
         matching_bounds
     }
 
@@ -1816,6 +1789,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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
@@ -1844,11 +1818,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 )
             });
 
-        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
@@ -1864,7 +1834,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return Err(());
         }
 
-        debug!("match_impl: success impl_substs={:?}", impl_substs);
+        debug!(?impl_substs, "match_impl: success");
         Ok(Normalized { value: impl_substs, obligations: nested_obligations })
     }
 
@@ -1926,10 +1896,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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)
@@ -1976,10 +1943,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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
@@ -2030,7 +1997,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         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,
@@ -2152,10 +2119,10 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
             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();
         }
@@ -2282,10 +2249,10 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
     /// `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)
     }
@@ -2308,14 +2275,11 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
         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 });
     }
@@ -2329,7 +2293,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
     /// 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);
@@ -2350,7 +2314,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
         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");
@@ -2358,7 +2322,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
         }
 
         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_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 93fdf93e9e3..3fc5f02a4a4 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_data_structures::fx::{FxHashSet, FxIndexSet};
 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 @@ struct InteriorVisitor<'a, 'tcx> {
     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 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
         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 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
                         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 @@ pub fn resolve_interior<'a, 'tcx>(
         expr_count: 0,
         kind,
         prev_unresolved_span: None,
+        guard_bindings: <_>::default(),
+        guard_bindings_set: <_>::default(),
     };
     intravisit::walk_body(&mut visitor, body);
 
@@ -210,6 +227,38 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         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(..) {
+                assert!(
+                    self.guard_bindings_set.remove(&var_id),
+                    "variable should be placed in scope earlier"
+                );
+            }
+        }
+        self.visit_expr(body);
+    }
+
     fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
         intravisit::walk_pat(self, pat);
 
@@ -218,11 +267,12 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         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 +299,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
                 }
                 _ => 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 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // 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 +327,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // 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 +347,30 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // 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/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 2dc769486c2..24ffe944128 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -264,7 +264,7 @@ pub fn provide(providers: &mut Providers) {
 }
 
 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
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 880627e94c3..4fa97ff053e 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -170,6 +170,22 @@ impl<K, V> Root<K, V> {
         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 }
     }
@@ -188,14 +204,11 @@ impl<K, V> Root<K, V> {
         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.
@@ -212,11 +225,8 @@ impl<K, V> Root<K, V> {
 
         let top = self.node.ptr;
 
-        self.node = unsafe {
-            BoxedNode::from_ptr(
-                self.node_as_mut().cast_unchecked::<marker::Internal>().first_edge().descend().node,
-            )
-        };
+        let internal_node = unsafe { self.internal_node_as_mut() };
+        self.node = unsafe { BoxedNode::from_ptr(internal_node.first_edge().descend().node) };
         self.height -= 1;
         self.node_as_mut().as_leaf_mut().parent = None;
 
@@ -443,9 +453,9 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
 }
 
 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 }
     }
 
@@ -943,10 +953,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
                     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);
@@ -1006,10 +1013,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
                     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,
-                    )
+                    Handle::new_edge(right.internal_node_as_mut(), insert_idx)
                 },
             };
             insertion_edge.insert_fit(key, val, edge);
@@ -1205,7 +1209,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
 
             let mut new_root = Root { node: BoxedNode::from_internal(new_node), height };
 
-            new_root.node_as_mut().cast_unchecked().correct_childrens_parent_links(0..=new_len);
+            new_root.internal_node_as_mut().correct_childrens_parent_links(0..=new_len);
 
             (self.node, k, v, new_root)
         }
@@ -1258,8 +1262,8 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
             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/backtrace b/library/backtrace
-Subproject 8eee2e473e71e659cbd5d32ee78aaf42e8b7575
+Subproject 893fbb23688e98376e54c26b59432a2966a8cc9
diff --git a/library/core/src/ffi.rs b/library/core/src/ffi.rs
index 4525ba78ba0..e146a97ae94 100644
--- a/library/core/src/ffi.rs
+++ b/library/core/src/ffi.rs
@@ -280,7 +280,7 @@ impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
 // 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/slice/mod.rs b/library/core/src/slice/mod.rs
index d0d88c01f5b..349c2cde274 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -2035,6 +2035,50 @@ impl<T> [T] {
     }
 
     /// 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 +2102,10 @@ impl<T> [T] {
     /// # 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 +2114,9 @@ impl<T> [T] {
     ///         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 +2150,10 @@ impl<T> [T] {
     /// # 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 +2162,9 @@ impl<T> [T] {
     ///         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 +2202,10 @@ impl<T> [T] {
     /// # 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 +2214,9 @@ impl<T> [T] {
     ///         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,
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 27e6760e7cb..fcb0d6031be 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -204,8 +204,8 @@ macro_rules! int_module {
 
             #[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/slice.rs b/library/core/tests/slice.rs
index 5ef30b1a889..ac5c9353ccb 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -1571,7 +1571,7 @@ fn sort_unstable() {
 #[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;
@@ -1597,7 +1597,7 @@ fn partition_at_index() {
                 // 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 {
@@ -1610,7 +1610,7 @@ fn partition_at_index() {
                 // 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);
 
@@ -1633,7 +1633,7 @@ fn partition_at_index() {
 
                 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 {
@@ -1654,7 +1654,7 @@ fn partition_at_index() {
     }
 
     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);
@@ -1662,28 +1662,28 @@ fn partition_at_index() {
     }
 
     // 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 {
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index f2a9cb5a0e8..fac4b05ad0b 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -117,8 +117,7 @@ impl Hash for Timespec {
 #[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 @@ mod inner {
     }
 
     fn info() -> mach_timebase_info {
-        static mut INFO: mach_timebase_info = mach_timebase_info { numer: 0, denom: 0 };
-        static STATE: AtomicUsize = AtomicUsize::new(0);
-
-        unsafe {
-            // If a previous thread has filled in this global state, use that.
-            if STATE.load(SeqCst) == 2 {
-                return INFO;
-            }
+        // 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);
+
+        // 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 ...
-            let mut info = mem::zeroed();
-            extern "C" {
-                fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
-            }
+        // ... 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);
-
-            // ... 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;
         }
+        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 80311d26819..2cdd9c4d19e 100644
--- a/library/std/src/sys/unsupported/common.rs
+++ b/library/std/src/sys/unsupported/common.rs
@@ -39,10 +39,13 @@ pub fn hashmap_random_keys() -> (u64, u64) {
 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/mod.rs b/library/std/src/sys/unsupported/mod.rs
index 8ba870c5dbc..d9efdec33d9 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 06ea9a1e2c1..b3203c16c50 100644
--- a/library/std/src/sys/unsupported/mutex.rs
+++ b/library/std/src/sys/unsupported/mutex.rs
@@ -1,7 +1,8 @@
-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;
@@ -10,9 +11,8 @@ 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]
@@ -20,25 +20,17 @@ impl Mutex {
 
     #[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/rwlock.rs b/library/std/src/sys/unsupported/rwlock.rs
index d37f34ac935..6982b2b155f 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 @@ unsafe impl Sync for RWLock {} // no threads on this platform
 
 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 @@ impl RWLock {
 
     #[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 @@ impl RWLock {
 
     #[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 @@ impl RWLock {
 
     #[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/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs
index 661214e8f4c..81413f39dc1 100644
--- a/library/std/src/sys/wasi/ext/io.rs
+++ b/library/std/src/sys/wasi/ext/io.rs
@@ -160,3 +160,21 @@ impl AsRawFd for io::Stderr {
         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 a7a4407ac38..a0a37ef8316 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -53,6 +53,7 @@ pub mod thread_local_key;
 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/mod.rs b/library/std/src/sys/wasm/mod.rs
index 2934ea59ab5..18295e1129a 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -66,5 +66,6 @@ cfg_if::cfg_if! {
 }
 
 #[path = "../unsupported/common.rs"]
+#[deny(unsafe_op_in_unsafe_fn)]
 mod common;
 pub use common::*;
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index 900260169c7..91e4f765484 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -165,7 +165,7 @@ fn intervals2dur(intervals: u64) -> Duration {
 
 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 @@ mod perf_counter {
     }
 
     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);
+
+        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 {
-            // 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
         }
+
+        FREQUENCY.store(frequency as u64, Ordering::Relaxed);
+        frequency
     }
 
     fn query() -> c::LARGE_INTEGER {
diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs
index a1e11d24465..91d919a3f9b 100644
--- a/library/std/src/sys_common/mutex.rs
+++ b/library/std/src/sys_common/mutex.rs
@@ -21,7 +21,6 @@ impl StaticMutex {
     /// first used with any of the functions below.
     /// Also, the behavior is undefined if this mutex is ever used reentrantly,
     /// i.e., `lock` is called by the thread currently holding the lock.
-    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
     pub const fn new() -> Self {
         Self(imp::Mutex::new())
     }
diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs
index 9ebc991d638..41e7e6adcf1 100644
--- a/library/test/src/formatters/json.rs
+++ b/library/test/src/formatters/json.rs
@@ -182,8 +182,8 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
 /// 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/src/bootstrap/README.md b/src/bootstrap/README.md
index bc8bae14b21..84ed9446ae7 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -93,12 +93,12 @@ handled naturally. `./configure` should almost never be used for local
 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 d31f95ee5e9..07e582d4d29 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 main() {
 }
 
 fn check_version(config: &Config) -> Option<String> {
-    const VERSION: usize = 2;
-
     let mut msg = String::new();
 
     let suggestion = if let Some(seen) = config.changelog_seen {
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 4bc162abee6..707c1ff3efa 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -193,37 +193,37 @@ impl StepDescription {
             );
         }
 
-        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());
+            }
         }
     }
 }
@@ -462,6 +462,7 @@ impl<'a> Builder<'a> {
                 dist::LlvmTools,
                 dist::RustDev,
                 dist::Extended,
+                dist::BuildManifest,
                 dist::HashSign
             ),
             Kind::Install => describe!(
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 6265bbaf5c2..db82155bd6a 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -61,6 +61,7 @@ pub struct Config {
     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,
@@ -532,6 +533,7 @@ impl Config {
 
         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;
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 3a0743da7a4..1887b805da1 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -2353,7 +2353,6 @@ impl Step for HashSign {
         cmd.arg(today.trim());
         cmd.arg(addr);
         cmd.arg(&builder.config.channel);
-        cmd.arg(&builder.src);
         cmd.env("BUILD_MANIFEST_LEGACY", "1");
 
         builder.create_dir(&distdir(builder));
@@ -2584,3 +2583,70 @@ impl Step for RustDev {
         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/flags.rs b/src/bootstrap/flags.rs
index 319a0b4e611..c10188875fb 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -30,6 +30,7 @@ pub struct Flags {
     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,
@@ -137,6 +138,11 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
         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(
@@ -618,6 +624,7 @@ Arguments:
                 .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"),
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index bf81c4bf28e..22a8e828862 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -177,8 +177,13 @@ const LLVM_TOOLS: &[&str] = &[
     "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
diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs
index 80c093e713e..7c64e5a0aad 100644
--- a/src/bootstrap/run.rs
+++ b/src/bootstrap/run.rs
@@ -77,7 +77,6 @@ impl Step for BuildManifest {
         cmd.arg(today.trim());
         cmd.arg(addr);
         cmd.arg(&builder.config.channel);
-        cmd.arg(&builder.src);
 
         builder.create_dir(&distdir(builder));
         builder.run(&mut cmd);
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index dcfb9fd6734..2a9507cfc4c 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -1,4 +1,4 @@
-use crate::t;
+use crate::{t, VERSION};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{
@@ -30,7 +30,7 @@ impl FromStr for Profile {
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s {
             "a" | "lib" | "library" => Ok(Profile::Library),
-            "b" | "compiler" => Ok(Profile::Compiler),
+            "b" | "compiler" | "rustdoc" => Ok(Profile::Compiler),
             "c" | "llvm" | "codegen" => Ok(Profile::Codegen),
             "d" | "maintainer" | "user" => Ok(Profile::User),
             _ => Err(format!("unknown profile: '{}'", s)),
@@ -69,8 +69,9 @@ pub fn setup(src_path: &Path, profile: Profile) {
     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",
-        profile
+    profile = \"{}\"\n\
+    changelog-seen = {}\n",
+        profile, VERSION
     );
     t!(fs::write(path, settings));
 
@@ -107,7 +108,7 @@ pub fn interactive_path() -> io::Result<Profile> {
     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
+b) Contribute to the compiler or rustdoc
 c) Contribute to the compiler, and also modify LLVM or codegen
 d) Install Rust from source"
     );
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 00522ee6b67..bda9e0f5784 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -966,6 +966,15 @@ impl Step for Compiletest {
     /// 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/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile
index 3c39a638496..f3f52ed61d1 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 @@ RUN riscv64-linux-gnu-gcc addentropy.c -o rootfs/addentropy -static
 # 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-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 58e2567a58f..14700aeea05 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 @@ ENV RUST_CONFIGURE_ARGS \
       --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/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 101716d1601..090b06f2a0a 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -149,6 +149,10 @@ x--expand-yaml-anchors--remove:
         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
@@ -457,6 +461,37 @@ jobs:
               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_beta.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  #
           ######################
@@ -565,7 +600,7 @@ jobs:
               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
@@ -584,6 +619,18 @@ jobs:
               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
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index a1481f22f50..8070e90f155 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -12,10 +12,18 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 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 ae85d5cab01..1685fbbbbba 100755
--- a/src/ci/scripts/install-mingw.sh
+++ b/src/ci/scripts/install-mingw.sh
@@ -42,6 +42,13 @@ if isWindows; then
             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 00000000000..3b9c77d42ba
--- /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/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index bed10ca16d3..f6493e49c3c 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -497,8 +497,10 @@ point instructions in software. It takes one of the following values:
 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 @@ This also supports the feature `+crt-static` and `-crt-static` to control
 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 6c605f045e5..ae55297b78c 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -37,7 +37,7 @@ target | std | host | notes
 `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 @@ Specifically, these platforms are required to have each of the following:
 
 target | std | host | notes
 -------|-----|------|-------
+`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
@@ -145,7 +146,6 @@ not available.
 
 target | std | host | notes
 -------|-----|------|-------
-`aarch64-apple-darwin` | ? |  | ARM64 macOS
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
 `aarch64-unknown-cloudabi` | ✓ |  | ARM64 CloudABI
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
@@ -168,7 +168,7 @@ target | std | host | notes
 `avr-unknown-gnu-atmega328` | ✗ |  | AVR. Requires `-Z build-std=core`
 `hexagon-unknown-linux-musl` | ? |  |
 `i386-apple-ios` | ✓ |  | 32-bit x86 iOS
-`i686-apple-darwin` | ✓ | ✓ | 32-bit OSX (10.7+, Lion+)
+`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
diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py
index bae51e6f9ee..b2d343fd7af 100644
--- a/src/etc/gdb_providers.py
+++ b/src/etc/gdb_providers.py
@@ -207,30 +207,46 @@ class StdRefCellProvider:
         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 None
+            val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else None
+            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 i, (key, val) in enumerate(children_of_node(boxed_root_node, height)):
+            if key is not None:
+                yield "key{}".format(i), key
+            if val is not None:
+                yield "val{}".format(i), val
 
 
 class StdBTreeSetProvider:
@@ -242,15 +258,8 @@ class StdBTreeSetProvider:
 
     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 child in children_of_map(inner_map):
+            yield child
 
     @staticmethod
     def display_hint():
@@ -265,16 +274,8 @@ class StdBTreeMapProvider:
         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 child in children_of_map(self.valobj):
+            yield child
 
     @staticmethod
     def display_hint():
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 903f44a0f93..76efdfc1675 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -12,6 +12,7 @@ use std::{slice, vec};
 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_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -392,24 +393,6 @@ pub enum DocFragmentKind {
     /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
     /// given filename and the file contents.
     Include { filename: String },
-    /// A doc fragment used to distinguish between documentation in different modules.
-    ///
-    /// In particular, this prevents `collapse_docs` from turning all documentation comments
-    /// into a single giant attributes even when the item is re-exported with documentation on the re-export.
-    Divider,
-}
-
-impl DocFragment {
-    /// Creates a dummy doc-fragment which divides earlier and later fragments.
-    fn divider() -> Self {
-        DocFragment {
-            line: 0,
-            span: DUMMY_SP,
-            parent_module: None,
-            doc: String::new(),
-            kind: DocFragmentKind::Divider,
-        }
-    }
 }
 
 impl<'a> FromIterator<&'a DocFragment> for String {
@@ -550,7 +533,7 @@ impl Attributes {
         attrs: &[ast::Attribute],
         additional_attrs: Option<(&[ast::Attribute], DefId)>,
     ) -> Attributes {
-        let doc_strings = RefCell::new(vec![]);
+        let mut doc_strings = vec![];
         let mut sp = None;
         let mut cfg = Cfg::True;
         let mut doc_line = 0;
@@ -567,7 +550,7 @@ impl Attributes {
 
                 let line = doc_line;
                 doc_line += value.lines().count();
-                doc_strings.borrow_mut().push(DocFragment {
+                doc_strings.push(DocFragment {
                     line,
                     span: attr.span,
                     doc: value,
@@ -592,7 +575,7 @@ impl Attributes {
                         {
                             let line = doc_line;
                             doc_line += contents.lines().count();
-                            doc_strings.borrow_mut().push(DocFragment {
+                            doc_strings.push(DocFragment {
                                 line,
                                 span: attr.span,
                                 doc: contents,
@@ -609,10 +592,7 @@ impl Attributes {
         // Additional documentation should be shown before the original documentation
         let other_attrs = additional_attrs
             .into_iter()
-            .map(|(attrs, id)| {
-                doc_strings.borrow_mut().push(DocFragment::divider());
-                attrs.iter().map(move |attr| (attr, Some(id)))
-            })
+            .map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
             .flatten()
             .chain(attrs.iter().map(|attr| (attr, None)))
             .filter_map(clean_attr)
@@ -641,7 +621,7 @@ impl Attributes {
             .map_or(true, |a| a.style == AttrStyle::Inner);
 
         Attributes {
-            doc_strings: doc_strings.into_inner(),
+            doc_strings,
             other_attrs,
             cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
             span: sp,
@@ -1279,6 +1259,28 @@ impl GetDefId for Type {
 }
 
 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),
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 913342e2715..cdea5a7af20 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -109,7 +109,7 @@ 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 +159,7 @@ pub fn external_generic_args(
 
 // 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>,
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 391526f0a30..80aca24da9f 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -390,17 +390,13 @@ nav.sub {
 	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;
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 4bca3996eb4..ced26fcf5b0 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 @@ pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
 };
 
 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 @@ impl ItemCount {
         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 @@ impl ops::AddAssign for ItemCount {
     }
 }
 
-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 @@ fn limit_filename_len(filename: String) -> String {
     }
 }
 
-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 @@ impl CoverageCalculator {
         .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 CoverageCalculator {
     }
 }
 
-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() => {
@@ -245,11 +252,18 @@ impl fold::DocFolder for CoverageCalculator {
                 );
 
                 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 be7250f833f..c2f7f97a673 100644
--- a/src/librustdoc/passes/collapse_docs.rs
+++ b/src/librustdoc/passes/collapse_docs.rs
@@ -36,7 +36,10 @@ fn collapse(doc_strings: &mut Vec<DocFragment>) {
             let curr_kind = &curr_frag.kind;
             let new_kind = &frag.kind;
 
-            if matches!(*curr_kind, DocFragmentKind::Include { .. }) || curr_kind != new_kind {
+            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
                 {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index fb79272768e..8be9482acff 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -16,6 +16,7 @@ use rustc_session::lint::{
     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;
@@ -234,6 +235,56 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         }
     }
 
+    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,
@@ -275,6 +326,19 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         })
     }
 
+    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>(
@@ -287,22 +351,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     ) -> 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);
                 }
@@ -321,17 +381,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 _ => {
                     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.
@@ -359,70 +409,30 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 }
             })?;
 
-        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`
@@ -462,7 +472,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     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)));
@@ -508,13 +518,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                         _ => 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
@@ -571,30 +575,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         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)
-        };
-        // 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))
+        // 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),
         };
-        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))
+
+        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,
         };
-        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)
     }
 }
 
@@ -1095,7 +1090,7 @@ impl LinkCollector<'_, '_> {
                         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];
@@ -1952,55 +1947,57 @@ fn handle_variant(
     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();
diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs
index 78af9f9b856..686ec51fb06 100644
--- a/src/librustdoc/passes/doc_test_lints.rs
+++ b/src/librustdoc/passes/doc_test_lints.rs
@@ -9,6 +9,7 @@ use crate::clean::*;
 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 @@ impl crate::doctest::Tester for Tests {
     }
 }
 
-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 @@ pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool {
         | 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 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
     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/test/codegen/tune-cpu-on-functions.rs b/src/test/codegen/tune-cpu-on-functions.rs
new file mode 100644
index 00000000000..9121799cdbf
--- /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/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs
index a4fbff5725c..c6d2090759f 100644
--- a/src/test/debuginfo/pretty-std-collections.rs
+++ b/src/test/debuginfo/pretty-std-collections.rs
@@ -34,17 +34,20 @@
 // 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_btree_map
+// gdb-check:$7 = BTreeMap(size=1)
+
 // gdb-command: print vec_deque
-// gdb-check:$7 = VecDeque(size=3) = {5, 3, 7}
+// gdb-check:$8 = 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:$9 = 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:$10 = 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:$11 = HashSet(size=4) = {1, 2, 3, 4}
 
 // === LLDB TESTS ==================================================================================
 
@@ -69,9 +72,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 +114,9 @@ fn main() {
         nasty_btree_map.insert(i, MyLeafNode(i));
     }
 
+    let mut zst_btree_map: BTreeMap<(), ()> = BTreeMap::new();
+    zst_btree_map.insert((), ());
+
     // VecDeque
     let mut vec_deque = VecDeque::new();
     vec_deque.push_back(5);
diff --git a/src/test/incremental/thinlto/cgu_invalidated_via_import.rs b/src/test/incremental/thinlto/cgu_invalidated_via_import.rs
index 8160f8f3a99..5fe435d796f 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 @@ mod foo {
 
     #[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 00000000000..0fd5abee118
--- /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 24e5d2438bd..045f2011958 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 @@ mod foo {
 
     #[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/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
index dd49ca67c67..0e1bef6f68d 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_span;
 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 @@ pub struct NoLlvmMetadataLoader;
 
 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 @@ impl CodegenBackend for TheBackend {
         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/rustdoc-ui/coverage/allow_missing_docs.rs b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs
new file mode 100644
index 00000000000..c077be31b20
--- /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 00000000000..3d5b512d14d
--- /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 00000000000..17e8ee9e23d
--- /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/intra-links-ambiguity.rs b/src/test/rustdoc-ui/intra-links-ambiguity.rs
index d1597cdca66..f63435337cf 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.rs
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.rs
@@ -34,3 +34,7 @@ pub mod foo {
 ///
 /// 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 17891ca05ef..21b92a96737 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
@@ -82,5 +82,20 @@ help: to link to the function, add parentheses
 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/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs
new file mode 100644
index 00000000000..fc51995a94e
--- /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 00000000000..672ccb1cf0e
--- /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/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-link-reexport-additional-docs.rs
index adb072a7ed5..96f3580f305 100644
--- a/src/test/rustdoc/intra-link-reexport-additional-docs.rs
+++ b/src/test/rustdoc/intra-link-reexport-additional-docs.rs
@@ -1,6 +1,9 @@
+// aux-build:intra-link-reexport-additional-docs.rs
+// build-aux-docs
 #![crate_name = "foo"]
+extern crate inner;
 
-// @has foo/struct.JoinPathsError.html '//a[@href="../foo/fn.with_code.html"]' 'crate::with_code'
+// @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]
@@ -11,7 +14,9 @@
 #[doc = "has an attr in the way"]
 ///
 /// [reference link]: me_three
-pub use std::env::JoinPathsError;
+// 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() {}
diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs
index 8f69b894a22..3041ff77684 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
index dea72b81a57..066b0cfe5e8 100644
--- a/src/test/rustdoc/reexport-check.rs
+++ b/src/test/rustdoc/reexport-check.rs
@@ -1,5 +1,8 @@
+// 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'
@@ -7,3 +10,8 @@ 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/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs
index 0025b47403d..a9520b59277 100644
--- a/src/test/ui-fulldeps/compiler-calls.rs
+++ b/src/test/ui-fulldeps/compiler-calls.rs
@@ -26,13 +26,8 @@ fn main() {
     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,
-            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/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 0fc45513cd7..cfaacf7a5be 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 dd45b6ed278..768180d0813 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 @@ struct B<const CFG: Config> {
     //[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.min.stderr b/src/test/ui/const-generics/const-argument-if-length.min.stderr
index c666dce479f..bce701ade86 100644
--- a/src/test/ui/const-generics/const-argument-if-length.min.stderr
+++ b/src/test/ui/const-generics/const-argument-if-length.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/const-argument-if-length.rs:19:24
    |
 LL |     pad: [u8; is_zst::<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[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/const-argument-if-length.rs:17:12
diff --git a/src/test/ui/const-generics/const-argument-if-length.rs b/src/test/ui/const-generics/const-argument-if-length.rs
index 481ff97d68d..a8bffd17b91 100644
--- a/src/test/ui/const-generics/const-argument-if-length.rs
+++ b/src/test/ui/const-generics/const-argument-if-length.rs
@@ -17,7 +17,7 @@ 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 must not be used inside of non-trivial constant values
+    //[min]~^ ERROR generic parameters may not be used in const operations
     //[full]~^^ ERROR evaluation of constant value failed
 }
 
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 4b3235fd087..359c2d2a22f 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 d552e0f5430..9746adab29b 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/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
index 85a15b1e75f..46485262cc4 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.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
index 2eac9505624..981d993f589 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 637c940f714..5e2c080927f 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/generic-function-call-in-array-length.min.stderr b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
index e7e968e4c2a..84449018e46 100644
--- 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
@@ -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/generic-function-call-in-array-length.rs:9:39
    |
 LL | fn bar<const N: usize>() -> [u32; foo(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/generic-function-call-in-array-length.rs:12:13
    |
 LL |     [0; foo(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: 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
index c8bbae29343..c838070dc95 100644
--- 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
@@ -7,10 +7,10 @@
 const fn foo(n: usize) -> usize { n * 2 }
 
 fn bar<const N: usize>() -> [u32; foo(N)] {
-    //[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
     //[full]~^^ ERROR constant expression depends on a generic parameter
     [0; foo(N)]
-    //[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/generic-sum-in-array-length.min.stderr b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
index 6f157fbbbbb..d3f7143327e 100644
--- 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
@@ -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/generic-sum-in-array-length.rs:7:53
    |
 LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
-   |                                                     ^ non-trivial anonymous constants must not depend on the parameter `A`
+   |                                                     ^ cannot perform const operation using `A`
    |
-   = help: it is currently only allowed to use either `A` or `{ A }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `A`
 
-error: generic parameters must not be used inside of non-trivial constant values
+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]) {}
-   |                                                         ^ non-trivial anonymous constants must not depend on the parameter `B`
+   |                                                         ^ cannot perform const operation using `B`
    |
-   = help: it is currently only allowed to use either `B` or `{ B }` as generic constants
+   = 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
index 810095b384b..84ddfe055dc 100644
--- a/src/test/ui/const-generics/generic-sum-in-array-length.rs
+++ b/src/test/ui/const-generics/generic-sum-in-array-length.rs
@@ -5,8 +5,8 @@
 #![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
-//[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
 //[full]~^^^ ERROR constant expression depends on a generic parameter
 
 fn main() {}
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
index 307db088bf8..20a8d9fdaab 100644
--- 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
@@ -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/intrinsics-type_name-as-const-argument.rs:15:44
    |
 LL |     T: Trait<{std::intrinsics::type_name::<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: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22
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
index 37b6cf4bab9..8971c00ed5a 100644
--- 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
@@ -13,7 +13,7 @@ trait Trait<const S: &'static str> {}
 struct Bug<T>
 where
     T: Trait<{std::intrinsics::type_name::<T>()}>
-    //[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
     //[full]~^^ ERROR constant expression depends on a generic parameter
 {
     t: T
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 2c1bc055b28..526807f0a24 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 81443b90d61..8c0a3a03774 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.min.stderr b/src/test/ui/const-generics/issue-67375.min.stderr
index b13d9fdab0d..3c344edbf1d 100644
--- a/src/test/ui/const-generics/issue-67375.min.stderr
+++ b/src/test/ui/const-generics/issue-67375.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-67375.rs:9:25
    |
 LL |     inner: [(); { [|_: &T| {}; 0].len() }],
-   |                         ^ 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[E0392]: parameter `T` is never used
   --> $DIR/issue-67375.rs:7:12
diff --git a/src/test/ui/const-generics/issue-67375.rs b/src/test/ui/const-generics/issue-67375.rs
index 994ec92cfb5..ecc76bcae06 100644
--- a/src/test/ui/const-generics/issue-67375.rs
+++ b/src/test/ui/const-generics/issue-67375.rs
@@ -7,7 +7,7 @@
 struct Bug<T> {
     //~^ ERROR parameter `T` is never used
     inner: [(); { [|_: &T| {}; 0].len() }],
-    //[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
     //[full]~^^ WARN cannot use constants which depend on generic parameters in types
     //[full]~^^^ WARN this was previously accepted by the compiler
 }
diff --git a/src/test/ui/const-generics/issue-67945-1.min.stderr b/src/test/ui/const-generics/issue-67945-1.min.stderr
index 949b5da5920..804236c30bd 100644
--- a/src/test/ui/const-generics/issue-67945-1.min.stderr
+++ b/src/test/ui/const-generics/issue-67945-1.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-67945-1.rs:14:16
    |
 LL |         let x: S = MaybeUninit::uninit();
-   |                ^ non-trivial anonymous constants must not depend on the parameter `S`
+   |                ^ cannot perform const operation using `S`
    |
-   = 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-67945-1.rs:17:45
    |
 LL |         let b = &*(&x as *const _ as *const S);
-   |                                             ^ non-trivial anonymous constants must not depend on the parameter `S`
+   |                                             ^ cannot perform const operation using `S`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error[E0392]: parameter `S` is never used
   --> $DIR/issue-67945-1.rs:11:12
diff --git a/src/test/ui/const-generics/issue-67945-1.rs b/src/test/ui/const-generics/issue-67945-1.rs
index d1a83e978d1..6771603f259 100644
--- a/src/test/ui/const-generics/issue-67945-1.rs
+++ b/src/test/ui/const-generics/issue-67945-1.rs
@@ -12,10 +12,10 @@ struct Bug<S> {
     //~^ ERROR parameter `S` is never used
     A: [(); {
         let x: S = MaybeUninit::uninit();
-        //[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
         //[full]~^^ ERROR mismatched types
         let b = &*(&x as *const _ as *const S);
-        //[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/issue-67945-2.min.stderr b/src/test/ui/const-generics/issue-67945-2.min.stderr
index ed445b3e8f7..2de942c1220 100644
--- a/src/test/ui/const-generics/issue-67945-2.min.stderr
+++ b/src/test/ui/const-generics/issue-67945-2.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-67945-2.rs:12:16
    |
 LL |         let x: S = MaybeUninit::uninit();
-   |                ^ non-trivial anonymous constants must not depend on the parameter `S`
+   |                ^ cannot perform const operation using `S`
    |
-   = 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-67945-2.rs:15:45
    |
 LL |         let b = &*(&x as *const _ as *const S);
-   |                                             ^ non-trivial anonymous constants must not depend on the parameter `S`
+   |                                             ^ cannot perform const operation using `S`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error[E0392]: parameter `S` is never used
   --> $DIR/issue-67945-2.rs:9:12
diff --git a/src/test/ui/const-generics/issue-67945-2.rs b/src/test/ui/const-generics/issue-67945-2.rs
index 7f789297df0..72dbb674e66 100644
--- a/src/test/ui/const-generics/issue-67945-2.rs
+++ b/src/test/ui/const-generics/issue-67945-2.rs
@@ -10,10 +10,10 @@ struct Bug<S> {
     //~^ ERROR parameter `S` is never used
     A: [(); {
         let x: S = MaybeUninit::uninit();
-        //[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
         //[full]~^^ ERROR mismatched types
         let b = &*(&x as *const _ as *const S);
-        //[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-61747.min.stderr b/src/test/ui/const-generics/issues/issue-61747.min.stderr
index fdd9a569748..b176f9d1c75 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 4e5cde17f39..3a4dd1cdd18 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 @@ struct Const<const N: usize>;
 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 f461a31eeae..9e31466259f 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 a181a8dabe5..9fa02329a71 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 @@ impl<const N: usize> Foo for [(); N]
     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 84975e8f3be..3bd127ee74a 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 5694dc6d04d..2017473fa9e 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 f94ba8c0c9b..c73f62a4a07 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 338ec42799d..cbb2a11a931 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 f712171bbac..8b02fd108bd 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 b62ebf846d5..014742be03d 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 True for Is<{true}> {}
 
 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 a18126ccfef..282f72be6da 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 668f49852e1..4e37c247d00 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 ba378de4156..35d97c46248 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 296e4d423c4..21d13de22eb 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 @@ pub trait Trait {
     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 73d6fec6f9b..b900a0d096a 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 ac313eb3b2f..474cdb7258d 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 @@ struct Collatz<const N: Option<usize>>;
 
 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 59d2be3ce4b..7828d859394 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 49b305a5a78..4fea94cb465 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 @@ fxp_storage_impls! {
 
 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 a4c80b1d8c0..d960d9513b7 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 779c1d2950e..57572e23aa4 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 @@ pub trait True {}
 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 @@ where
 //[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 afc14c7dcff..9fec3eb946d 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 65c7f00a72a..6182042bde7 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-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
index 0db948d0a45..c10db84ea6e 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 3c5bfb03f08..9051c36fe81 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 c6380f6394d..8257ffbf491 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 @@ fn ok<const M: usize>() -> [u8; M] {
 }
 
 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 d8897f53d7f..73768ac03a4 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/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
index 7dc81bf45af..64da5e07df2 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/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 0dd591d891f..39aa8087cec 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 @@ LL | struct Bar<T = [u8; N], const N: usize>(T);
    |
    = 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 b9d74850f37..51f0cff3f21 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 1c52d601749..935f12dd2c3 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 f8c41404c46..103c580f28f 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 @@ struct Const<const N: usize>;
 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/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs
new file mode 100644
index 00000000000..d8aa354b1c6
--- /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/lto-opt-level-s.rs b/src/test/ui/lto-opt-level-s.rs
new file mode 100644
index 00000000000..a7d9d5024d3
--- /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 00000000000..bf1f5e2b263
--- /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/parser/float-field.stderr b/src/test/ui/parser/float-field.stderr
index 62202b99964..7090efc5014 100644
--- a/src/test/ui/parser/float-field.stderr
+++ b/src/test/ui/parser/float-field.stderr
@@ -271,10 +271,10 @@ LL |     s.1e1;
    = 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 @@ error[E0609]: no field `0x1` on type `S`
   --> $DIR/float-field.rs:25:7
    |
 LL |     s.0x1.;
-   |       ^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
@@ -296,7 +296,7 @@ error[E0609]: no field `0x1` on type `S`
   --> $DIR/float-field.rs:28:7
    |
 LL |     s.0x1.1;
-   |       ^^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
@@ -304,7 +304,7 @@ error[E0609]: no field `0x1` on type `S`
   --> $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/traits/assoc_type_bound_with_struct.rs b/src/test/ui/traits/assoc_type_bound_with_struct.rs
new file mode 100644
index 00000000000..c66009fe24c
--- /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 00000000000..7cf872eb6ac
--- /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/trait-bounds-not-on-struct.rs b/src/test/ui/traits/trait-bounds-not-on-struct.rs
index c6e93e75525..8633e9d7a4c 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 a649a4eee55..0f97e3bdf18 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 TypeAlias<T> = Box<dyn Vec<T>>;
+   |                             ^^^^^^ not a trait
+
+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 {
+   |           --
+
+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 | type A<T> = Box<dyn Vec<T>>;
-   |                     ^^^^^^ not a trait
+LL | fn g() -> Trait + 'static {
+   |           ^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 11 previous errors
 
-For more information about this error, try `rustc --explain E0404`.
+Some errors have detailed explanations: E0226, E0404.
+For more information about an error, try `rustc --explain E0226`.
diff --git a/src/test/ui/tuple/index-invalid.stderr b/src/test/ui/tuple/index-invalid.stderr
index 800b5a31d98..8d22f458a6c 100644
--- a/src/test/ui/tuple/index-invalid.stderr
+++ b/src/test/ui/tuple/index-invalid.stderr
@@ -2,19 +2,19 @@ error[E0609]: no field `1` on type `(((),),)`
   --> $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/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr
index fb16649767f..f7722764cd3 100644
--- a/src/test/ui/union/union-deref.stderr
+++ b/src/test/ui/union/union-deref.stderr
@@ -29,7 +29,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field
   --> $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 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field
   --> $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 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field
   --> $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/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml
index 4ae4dbfc06e..4a2c710811f 100644
--- a/src/tools/build-manifest/Cargo.toml
+++ b/src/tools/build-manifest/Cargo.toml
@@ -14,3 +14,4 @@ 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 26e96c9fd8f..b77c5a907c1 100644
--- a/src/tools/build-manifest/README.md
+++ b/src/tools/build-manifest/README.md
@@ -21,8 +21,8 @@ Then, you can generate the manifest and all the packages from `path/to/dist` to
 
 ```
 $ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com \
-    CHANNEL path/to/rust/repo
+    CHANNEL VERSION
 ```
 
 Remember to replace `CHANNEL` with the channel you produced dist artifacts of
-and `path/to/rust/repo` with the path to your checkout of the Rust repository.
+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 b35f3a595fb..f8c517a9395 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -22,6 +22,7 @@ use std::sync::Mutex;
 use std::time::Instant;
 
 static HOSTS: &[&str] = &[
+    "aarch64-apple-darwin",
     "aarch64-unknown-linux-gnu",
     "aarch64-unknown-linux-musl",
     "arm-unknown-linux-gnueabi",
@@ -55,6 +56,7 @@ static HOSTS: &[&str] = &[
 ];
 
 static TARGETS: &[&str] = &[
+    "aarch64-apple-darwin",
     "aarch64-apple-ios",
     "aarch64-fuchsia",
     "aarch64-linux-android",
@@ -205,15 +207,20 @@ fn main() {
     //
     // 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("BUILD_MANIFEST_LEGACY").is_ok();
-
-    // Avoid overloading the old server in legacy mode.
-    if legacy {
-        rayon::ThreadPoolBuilder::new()
-            .num_threads(1)
-            .build_global()
-            .expect("failed to initialize Rayon");
-    }
+    let legacy = env::var_os("BUILD_MANIFEST_LEGACY").is_some();
+
+    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());
@@ -221,7 +228,6 @@ fn main() {
     let date = args.next().unwrap();
     let s3_address = args.next().unwrap();
     let channel = args.next().unwrap();
-    let monorepo_path = args.next().unwrap();
 
     // Do not ask for a passphrase while manually testing
     let mut passphrase = String::new();
@@ -231,7 +237,7 @@ fn main() {
     }
 
     Builder {
-        versions: Versions::new(&channel, &input, Path::new(&monorepo_path)).unwrap(),
+        versions: Versions::new(&channel, &input).unwrap(),
 
         input,
         output,
@@ -252,12 +258,13 @@ impl Builder {
         }
         let manifest = self.build_manifest();
 
-        let rust_version = self.versions.rustc_version();
         self.write_channel_files(self.versions.channel(), &manifest);
-        if self.versions.channel() != rust_version {
-            self.write_channel_files(&rust_version, &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);
         }
diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs
index 75b6979b54a..79f2ef8dfc4 100644
--- a/src/tools/build-manifest/src/versions.rs
+++ b/src/tools/build-manifest/src/versions.rs
@@ -1,4 +1,4 @@
-use anyhow::{Context, Error};
+use anyhow::Error;
 use flate2::read::GzDecoder;
 use std::collections::HashMap;
 use std::fs::File;
@@ -7,6 +7,7 @@ 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 {
@@ -87,26 +88,13 @@ pub(crate) struct VersionInfo {
 
 pub(crate) struct Versions {
     channel: String,
-    rustc_version: String,
     dist_path: PathBuf,
     versions: HashMap<PkgType, VersionInfo>,
 }
 
 impl Versions {
-    pub(crate) fn new(
-        channel: &str,
-        dist_path: &Path,
-        monorepo_root: &Path,
-    ) -> Result<Self, Error> {
-        Ok(Self {
-            channel: channel.into(),
-            rustc_version: std::fs::read_to_string(monorepo_root.join("src").join("version"))
-                .context("failed to read the rustc version from src/version")?
-                .trim()
-                .to_string(),
-            dist_path: dist_path.into(),
-            versions: HashMap::new(),
-        })
+    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 {
@@ -184,10 +172,10 @@ impl Versions {
     ) -> Result<String, Error> {
         let component_name = package.tarball_component_name();
         let version = match self.channel.as_str() {
-            "stable" => self.rustc_version.clone(),
+            "stable" => RUSTC_VERSION.into(),
             "beta" => "beta".into(),
             "nightly" => "nightly".into(),
-            _ => format!("{}-dev", self.rustc_version),
+            _ => format!("{}-dev", RUSTC_VERSION),
         };
 
         if package.target_independent() {
@@ -198,6 +186,6 @@ impl Versions {
     }
 
     pub(crate) fn rustc_version(&self) -> &str {
-        &self.rustc_version
+        RUSTC_VERSION
     }
 }
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 1b4f2034272..7cb7d0a26b6 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
@@ -282,7 +282,6 @@ fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Termin
         TerminatorKind::SwitchInt {
             discr,
             switch_ty: _,
-            values: _,
             targets: _,
         } => check_operand(tcx, discr, span, body),
 
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index f4f2259cefd..377f6d22446 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -357,7 +357,7 @@ pub fn main() {
                 args.extend(vec!["--sysroot".into(), sys_root]);
             };
 
-            return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, 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 @@ pub fn main() {
         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, None)
+        rustc_driver::RunCompiler::new(&args, callbacks).run()
     }))
 }
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 3fafb835ea42e6e3af27f5dc8f26bda590cb49e
+Subproject 8beccc4bef598e95e31536f996ea5771d8126d0
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 33613e2dc10..7586f5aa3b5 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -33,7 +33,7 @@ MAINTAINERS = {
     '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 = {
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 9bfb47a79299d52f45304367762c9bfc96d9ed7
+Subproject 1f686d5f707269b1086f6afcdced36225c0c5ff
diff --git a/triagebot.toml b/triagebot.toml
index 8b7b536bcbf..fc733b9e45f 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -75,6 +75,7 @@ label = "I-prioritize"
 
 [autolabel."I-prioritize"]
 trigger_labels = [
+    "regression-untriaged",
     "regression-from-stable-to-stable",
     "regression-from-stable-to-beta",
     "regression-from-stable-to-nightly",