about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock13
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs64
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs84
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs1
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs25
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs57
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs20
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs52
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs29
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs35
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs30
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs16
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs9
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs17
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/mod.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs45
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs12
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs5
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0071.md14
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0439.md4
-rw-r--r--compiler/rustc_expand/src/expand.rs15
-rw-r--r--compiler/rustc_hir/Cargo.toml1
-rw-r--r--compiler/rustc_hir/src/def_path_hash_map.rs37
-rw-r--r--compiler/rustc_hir/src/definitions.rs22
-rw-r--r--compiler/rustc_hir/src/hir.rs16
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir/src/lib.rs1
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs8
-rw-r--r--compiler/rustc_lint/src/late.rs6
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/src/creader.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs156
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs15
-rw-r--r--compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs58
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs13
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs2
-rw-r--r--compiler/rustc_middle/src/arena.rs3
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs18
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs7
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs116
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs13
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/middle/cstore.rs8
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs3
-rw-r--r--compiler/rustc_middle/src/mir/query.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs25
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs112
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs314
-rw-r--r--compiler/rustc_middle/src/ty/query.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs17
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs24
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs11
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs25
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs20
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs45
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs2
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs6
-rw-r--r--compiler/rustc_passes/src/stability.rs10
-rw-r--r--compiler/rustc_query_impl/src/keys.rs22
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs213
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs12
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs14
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs4
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs29
-rw-r--r--compiler/rustc_span/src/caching_source_map_view.rs14
-rw-r--r--compiler/rustc_span/src/lib.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs43
-rw-r--r--compiler/rustc_span/src/symbol/tests.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs50
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs19
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs9
-rw-r--r--compiler/rustc_typeck/src/check/check.rs2
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs12
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs2
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs38
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs28
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs7
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs3
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs15
-rw-r--r--compiler/rustc_typeck/src/errors.rs8
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check.rs4
-rw-r--r--compiler/rustc_typeck/src/lib.rs8
-rw-r--r--compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs14
-rw-r--r--library/alloc/src/collections/vec_deque/into_iter.rs8
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs2
-rw-r--r--library/core/src/lazy.rs11
-rw-r--r--library/core/src/panic.rs9
-rw-r--r--library/core/src/panicking.rs7
-rw-r--r--library/std/src/error.rs4
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/os/linux/fs.rs4
-rw-r--r--library/std/src/os/linux/process.rs4
-rw-r--r--library/std/src/os/unix/ffi/mod.rs4
-rw-r--r--library/std/src/os/unix/fs.rs74
-rw-r--r--library/std/src/os/unix/mod.rs7
-rw-r--r--library/std/src/os/unix/net/mod.rs2
-rw-r--r--library/std/src/os/unix/process.rs4
-rw-r--r--library/std/src/os/unix/thread.rs4
-rw-r--r--library/std/src/os/wasi/ffi.rs4
-rw-r--r--library/std/src/os/wasi/fs.rs4
-rw-r--r--library/std/src/os/wasi/mod.rs3
-rw-r--r--library/std/src/os/windows/ffi.rs3
-rw-r--r--library/std/src/os/windows/fs.rs4
-rw-r--r--library/std/src/os/windows/mod.rs16
-rw-r--r--library/std/src/os/windows/process.rs4
-rw-r--r--library/std/src/os/windows/thread.rs4
-rw-r--r--library/std/src/panic.rs6
-rw-r--r--library/std/src/rt.rs7
-rw-r--r--library/std/src/sys/unix/fs.rs17
-rw-r--r--library/std/src/time/monotonic.rs57
-rw-r--r--src/bootstrap/doc.rs63
-rw-r--r--src/librustdoc/core.rs8
-rw-r--r--src/librustdoc/html/render/write_shared.rs16
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css15
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css4
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css4
-rw-r--r--src/librustdoc/html/static/css/themes/light.css4
-rw-r--r--src/librustdoc/html/static/js/main.js9
-rw-r--r--src/test/debuginfo/basic-types.rs7
-rw-r--r--src/test/debuginfo/msvc-pretty-enums.rs124
-rw-r--r--src/test/debuginfo/pretty-std.rs16
-rw-r--r--src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot14
-rw-r--r--src/test/mir-opt/inline/inline_diverging.h.Inline.diff2
-rw-r--r--src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff29
-rw-r--r--src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff34
-rw-r--r--src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff29
-rw-r--r--src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir32
-rw-r--r--src/test/ui/async-await/issue-76547.nll.stderr22
-rw-r--r--src/test/ui/borrowck/borrowck-in-static.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-move-by-capture.stderr21
-rw-r--r--src/test/ui/borrowck/issue-87456-point-to-closure.rs14
-rw-r--r--src/test/ui/borrowck/issue-87456-point-to-closure.stderr22
-rw-r--r--src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr14
-rw-r--r--src/test/ui/const-generics/issues/issue-87493.rs14
-rw-r--r--src/test/ui/const-generics/issues/issue-87493.stderr28
-rw-r--r--src/test/ui/consts/const-eval/const_panic.rs8
-rw-r--r--src/test/ui/consts/const-eval/const_panic.stderr38
-rw-r--r--src/test/ui/consts/const-eval/const_panic_2021.rs16
-rw-r--r--src/test/ui/consts/const-eval/const_panic_2021.stderr58
-rw-r--r--src/test/ui/consts/const_fn_trait_bound.rs4
-rw-r--r--src/test/ui/consts/const_fn_trait_bound.stock.stderr4
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.rs10
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.stderr10
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs4
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr4
-rw-r--r--src/test/ui/error-codes/E0439.rs8
-rw-r--r--src/test/ui/error-codes/E0439.stderr9
-rw-r--r--src/test/ui/issues/issue-4335.stderr5
-rw-r--r--src/test/ui/issues/issue-51102.stderr5
-rw-r--r--src/test/ui/issues/issue-55796.stderr4
-rw-r--r--src/test/ui/issues/issue-61882-2.stderr2
-rw-r--r--src/test/ui/issues/issue-75777.stderr2
-rw-r--r--src/test/ui/lifetimes/issue-77175.rs19
-rw-r--r--src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr22
-rw-r--r--src/test/ui/loops/loops-reject-duplicate-labels-2.rs6
-rw-r--r--src/test/ui/loops/loops-reject-duplicate-labels-2.stderr10
-rw-r--r--src/test/ui/loops/loops-reject-duplicate-labels.rs11
-rw-r--r--src/test/ui/loops/loops-reject-duplicate-labels.stderr26
-rw-r--r--src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs13
-rw-r--r--src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr10
-rw-r--r--src/test/ui/macros/lint-trailing-macro-call.rs16
-rw-r--r--src/test/ui/macros/lint-trailing-macro-call.stderr18
-rw-r--r--src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr5
-rw-r--r--src/test/ui/nll/issue-46036.stderr2
-rw-r--r--src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr5
-rw-r--r--src/test/ui/nll/issue-55394.stderr2
-rw-r--r--src/test/ui/nll/type-alias-free-regions.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-enums.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-structs.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-enums.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-struct.stderr6
-rw-r--r--src/test/ui/nll/where_clauses_in_structs.stderr2
-rw-r--r--src/test/ui/numeric/numeric-fields.stderr5
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-elision.stderr4
-rw-r--r--src/test/ui/parser/recover-for-loop-parens-around-head.rs2
-rw-r--r--src/test/ui/parser/recover-for-loop-parens-around-head.stderr15
-rw-r--r--src/test/ui/regions/region-object-lifetime-in-coercion.stderr2
-rw-r--r--src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr2
-rw-r--r--src/test/ui/regions/regions-creating-enums4.stderr2
-rw-r--r--src/test/ui/regions/regions-ret-borrowed-1.stderr2
-rw-r--r--src/test/ui/regions/regions-ret-borrowed.stderr2
-rw-r--r--src/test/ui/regions/regions-trait-object-subtyping.stderr2
-rw-r--r--src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.rs33
-rw-r--r--src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.stderr21
-rw-r--r--src/test/ui/simd/monomorphize-shuffle-index.rs40
-rw-r--r--src/test/ui/simd/shuffle-not-out-of-bounds.rs10
-rw-r--r--src/test/ui/simd/shuffle-not-out-of-bounds.stderr8
-rw-r--r--src/test/ui/simd/shuffle.rs24
-rw-r--r--src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr14
-rw-r--r--src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr554
-rw-r--r--src/test/ui/suggestions/option-content-move2.stderr27
-rw-r--r--src/test/ui/typeck/issue-88844.rs14
-rw-r--r--src/test/ui/typeck/issue-88844.stderr12
-rw-r--r--src/test/ui/typeck/issue-89044-wrapped-expr-method.fixed9
-rw-r--r--src/test/ui/typeck/issue-89044-wrapped-expr-method.rs9
-rw-r--r--src/test/ui/typeck/issue-89044-wrapped-expr-method.stderr14
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr20
m---------src/tools/cargo0
-rw-r--r--src/tools/tidy/src/deps.rs1
218 files changed, 2843 insertions, 1568 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f119f2050e9..7d7e44d1e5e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -267,7 +267,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
 
 [[package]]
 name = "cargo"
-version = "0.57.0"
+version = "0.58.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -2322,6 +2322,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "odht"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b18a8d1c919d3e7b5c49708d08ef7d60bc2150a7c3a8244257c54ca3f625010"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
+[[package]]
 name = "once_cell"
 version = "1.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3859,6 +3868,7 @@ version = "0.0.0"
 name = "rustc_hir"
 version = "0.0.0"
 dependencies = [
+ "odht",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_feature",
@@ -4045,6 +4055,7 @@ name = "rustc_metadata"
 version = "0.0.0"
 dependencies = [
  "libc",
+ "odht",
  "rustc_ast",
  "rustc_attr",
  "rustc_data_structures",
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index ca804ec6758..14a894d61f4 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -55,7 +55,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                 }
                 StmtKind::Item(ref it) => {
-                    stmts.extend(self.lower_item_id(it).into_iter().enumerate().map(
+                    stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
                         |(i, item_id)| {
                             let hir_id = match i {
                                 0 => self.lower_node_id(s.id),
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index a77e3e1997f..980036c662a 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -40,6 +40,7 @@ impl ItemLowerer<'_, '_, '_> {
 
 impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
     fn visit_item(&mut self, item: &'a Item) {
+        self.lctx.allocate_hir_id_counter(item.id);
         let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
             lctx.without_in_scope_lifetime_defs(|lctx| {
                 let hir_item = lctx.lower_item(item);
@@ -50,12 +51,6 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
         self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
             let this = &mut ItemLowerer { lctx: this };
             match item.kind {
-                ItemKind::Mod(..) => {
-                    let def_id = this.lctx.lower_node_id(item.id).expect_owner();
-                    let old_current_module = mem::replace(&mut this.lctx.current_module, def_id);
-                    visit::walk_item(this, item);
-                    this.lctx.current_module = old_current_module;
-                }
                 ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
                     this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
                 }
@@ -77,6 +72,7 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
     }
 
     fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
+        self.lctx.allocate_hir_id_counter(item.id);
         self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
             AssocCtxt::Trait => {
                 let hir_item = lctx.lower_trait_item(item);
@@ -154,41 +150,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
     pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
         hir::Mod {
             inner: self.lower_span(inner),
-            item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_id(x))),
+            item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_ref(x))),
         }
     }
 
-    pub(super) fn lower_item_id(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
-        let node_ids = match i.kind {
-            ItemKind::Use(ref use_tree) => {
-                let mut vec = smallvec![i.id];
-                self.lower_item_id_use_tree(use_tree, i.id, &mut vec);
-                vec
-            }
-            ItemKind::Fn(..) | ItemKind::Impl(box ImplKind { of_trait: None, .. }) => {
-                smallvec![i.id]
-            }
-            _ => smallvec![i.id],
-        };
-
+    pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
+        let mut node_ids = smallvec![hir::ItemId { def_id: self.resolver.local_def_id(i.id) }];
+        if let ItemKind::Use(ref use_tree) = &i.kind {
+            self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids);
+        }
         node_ids
-            .into_iter()
-            .map(|node_id| hir::ItemId {
-                def_id: self.allocate_hir_id_counter(node_id).expect_owner(),
-            })
-            .collect()
     }
 
     fn lower_item_id_use_tree(
         &mut self,
         tree: &UseTree,
         base_id: NodeId,
-        vec: &mut SmallVec<[NodeId; 1]>,
+        vec: &mut SmallVec<[hir::ItemId; 1]>,
     ) {
         match tree.kind {
             UseTreeKind::Nested(ref nested_vec) => {
                 for &(ref nested, id) in nested_vec {
-                    vec.push(id);
+                    vec.push(hir::ItemId { def_id: self.resolver.local_def_id(id) });
                     self.lower_item_id_use_tree(nested, id, vec);
                 }
             }
@@ -197,7 +180,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 for (_, &id) in
                     iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
                 {
-                    vec.push(id);
+                    vec.push(hir::ItemId { def_id: self.resolver.local_def_id(id) });
                 }
             }
         }
@@ -486,7 +469,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     }
                 }
 
-                let mut resolutions = self.expect_full_res_from_use(id);
+                let mut resolutions = self.expect_full_res_from_use(id).fuse();
                 // We want to return *something* from this function, so hold onto the first item
                 // for later.
                 let ret_res = self.lower_res(resolutions.next().unwrap_or(Res::Err));
@@ -496,7 +479,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // won't be dealing with macros in the rest of the compiler.
                 // Essentially a single `use` which imports two names is desugared into
                 // two imports.
-                for (res, &new_node_id) in iter::zip(resolutions, &[id1, id2]) {
+                for new_node_id in [id1, id2] {
+                    // Associate an HirId to both ids even if there is no resolution.
+                    let new_id = self.allocate_hir_id_counter(new_node_id);
+
+                    let res = if let Some(res) = resolutions.next() { res } else { continue };
                     let ident = *ident;
                     let mut path = path.clone();
                     for seg in &mut path.segments {
@@ -505,17 +492,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let span = path.span;
 
                     self.with_hir_id_owner(new_node_id, |this| {
-                        let new_id = this.lower_node_id(new_node_id);
                         let res = this.lower_res(res);
                         let path = this.lower_path_extra(res, &path, ParamMode::Explicit, None);
                         let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
                         let vis = this.rebuild_vis(&vis);
                         if let Some(attrs) = attrs {
-                            this.attrs.insert(new_id, attrs);
+                            this.attrs.insert(hir::HirId::make_owner(new_id), attrs);
                         }
 
                         this.insert_item(hir::Item {
-                            def_id: new_id.expect_owner(),
+                            def_id: new_id,
                             ident: this.lower_ident(ident),
                             kind,
                             vis,
@@ -564,7 +550,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
                 // Add all the nested `PathListItem`s to the HIR.
                 for &(ref use_tree, id) in trees {
-                    let new_hir_id = self.lower_node_id(id);
+                    let new_hir_id = self.allocate_hir_id_counter(id);
 
                     let mut prefix = prefix.clone();
 
@@ -585,11 +571,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         let kind =
                             this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs);
                         if let Some(attrs) = attrs {
-                            this.attrs.insert(new_hir_id, attrs);
+                            this.attrs.insert(hir::HirId::make_owner(new_hir_id), attrs);
                         }
 
                         this.insert_item(hir::Item {
-                            def_id: new_hir_id.expect_owner(),
+                            def_id: new_hir_id,
                             ident: this.lower_ident(ident),
                             kind,
                             vis,
@@ -700,7 +686,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef<'hir> {
         hir::ForeignItemRef {
-            id: hir::ForeignItemId { def_id: self.lower_node_id(i.id).expect_owner() },
+            id: hir::ForeignItemId { def_id: self.allocate_hir_id_counter(i.id) },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
             vis: self.lower_visibility(&i.vis, Some(i.id)),
@@ -839,7 +825,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
             AssocItemKind::MacCall(..) => unimplemented!(),
         };
-        let id = hir::TraitItemId { def_id: self.lower_node_id(i.id).expect_owner() };
+        let id = hir::TraitItemId { def_id: self.resolver.local_def_id(i.id) };
         let defaultness = hir::Defaultness::Default { has_value: has_default };
         hir::TraitItemRef {
             id,
@@ -925,7 +911,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let has_value = true;
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         hir::ImplItemRef {
-            id: hir::ImplItemId { def_id: self.lower_node_id(i.id).expect_owner() },
+            id: hir::ImplItemId { def_id: self.allocate_hir_id_counter(i.id) },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
             vis: self.lower_visibility(&i.vis, Some(i.id)),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 4cf54b07dbe..66bcd698e6a 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -38,7 +38,7 @@
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::token::{self, Token};
 use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
-use rustc_ast::visit::{self, AssocCtxt, Visitor};
+use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::captures::Captures;
@@ -102,8 +102,6 @@ struct LoweringContext<'a, 'hir: 'a> {
     owners: IndexVec<LocalDefId, Option<hir::OwnerNode<'hir>>>,
     bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>,
 
-    modules: BTreeMap<LocalDefId, hir::ModuleItems>,
-
     generator_kind: Option<hir::GeneratorKind>,
 
     attrs: BTreeMap<hir::HirId, &'hir [Attribute]>,
@@ -152,8 +150,6 @@ struct LoweringContext<'a, 'hir: 'a> {
     /// vector.
     in_scope_lifetimes: Vec<ParamName>,
 
-    current_module: LocalDefId,
-
     current_hir_id_owner: (LocalDefId, u32),
     item_local_id_counters: NodeMap<u32>,
     node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
@@ -327,7 +323,6 @@ pub fn lower_crate<'a, 'hir>(
         arena,
         owners: IndexVec::default(),
         bodies: BTreeMap::new(),
-        modules: BTreeMap::new(),
         attrs: BTreeMap::default(),
         catch_scope: None,
         loop_scope: None,
@@ -335,7 +330,6 @@ pub fn lower_crate<'a, 'hir>(
         is_in_trait_impl: false,
         is_in_dyn_type: false,
         anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
-        current_module: CRATE_DEF_ID,
         current_hir_id_owner: (CRATE_DEF_ID, 0),
         item_local_id_counters: Default::default(),
         node_id_to_hir_id: IndexVec::new(),
@@ -418,60 +412,9 @@ enum AnonymousLifetimeMode {
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> {
-        /// Full-crate AST visitor that inserts into a fresh
-        /// `LoweringContext` any information that may be
-        /// needed from arbitrary locations in the crate,
-        /// e.g., the number of lifetime generic parameters
-        /// declared for every type and trait definition.
-        struct MiscCollector<'tcx, 'lowering, 'hir> {
-            lctx: &'tcx mut LoweringContext<'lowering, 'hir>,
-        }
-
-        impl MiscCollector<'_, '_, '_> {
-            fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree) {
-                match tree.kind {
-                    UseTreeKind::Simple(_, id1, id2) => {
-                        for id in [id1, id2] {
-                            self.lctx.allocate_hir_id_counter(id);
-                        }
-                    }
-                    UseTreeKind::Glob => (),
-                    UseTreeKind::Nested(ref trees) => {
-                        for &(ref use_tree, id) in trees {
-                            self.lctx.allocate_hir_id_counter(id);
-                            self.allocate_use_tree_hir_id_counters(use_tree);
-                        }
-                    }
-                }
-            }
-        }
-
-        impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> {
-            fn visit_item(&mut self, item: &'tcx Item) {
-                self.lctx.allocate_hir_id_counter(item.id);
-
-                if let ItemKind::Use(ref use_tree) = item.kind {
-                    self.allocate_use_tree_hir_id_counters(use_tree);
-                }
-
-                visit::walk_item(self, item);
-            }
-
-            fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) {
-                self.lctx.allocate_hir_id_counter(item.id);
-                visit::walk_assoc_item(self, item, ctxt);
-            }
-
-            fn visit_foreign_item(&mut self, item: &'tcx ForeignItem) {
-                self.lctx.allocate_hir_id_counter(item.id);
-                visit::walk_foreign_item(self, item);
-            }
-        }
-
         self.lower_node_id(CRATE_NODE_ID);
         debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == Some(hir::CRATE_HIR_ID));
 
-        visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
         visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
 
         let module = self.arena.alloc(self.lower_mod(&c.items, c.span));
@@ -508,13 +451,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
         }
 
-        let krate = hir::Crate {
-            owners: self.owners,
-            bodies: self.bodies,
-            modules: self.modules,
-            trait_map,
-            attrs: self.attrs,
-        };
+        let krate =
+            hir::Crate { owners: self.owners, bodies: self.bodies, trait_map, attrs: self.attrs };
         self.arena.alloc(krate)
     }
 
@@ -523,7 +461,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let item = self.arena.alloc(item);
         self.owners.ensure_contains_elem(id.def_id, || None);
         self.owners[id.def_id] = Some(hir::OwnerNode::Item(item));
-        self.modules.entry(self.current_module).or_default().items.insert(id);
         id
     }
 
@@ -532,7 +469,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let item = self.arena.alloc(item);
         self.owners.ensure_contains_elem(id.def_id, || None);
         self.owners[id.def_id] = Some(hir::OwnerNode::ForeignItem(item));
-        self.modules.entry(self.current_module).or_default().foreign_items.insert(id);
         id
     }
 
@@ -541,7 +477,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let item = self.arena.alloc(item);
         self.owners.ensure_contains_elem(id.def_id, || None);
         self.owners[id.def_id] = Some(hir::OwnerNode::ImplItem(item));
-        self.modules.entry(self.current_module).or_default().impl_items.insert(id);
         id
     }
 
@@ -550,17 +485,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let item = self.arena.alloc(item);
         self.owners.ensure_contains_elem(id.def_id, || None);
         self.owners[id.def_id] = Some(hir::OwnerNode::TraitItem(item));
-        self.modules.entry(self.current_module).or_default().trait_items.insert(id);
         id
     }
 
-    fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
+    fn allocate_hir_id_counter(&mut self, owner: NodeId) -> LocalDefId {
         // Set up the counter if needed.
         self.item_local_id_counters.entry(owner).or_insert(0);
         // Always allocate the first `HirId` for the owner itself.
         let lowered = self.lower_node_id_with_owner(owner, owner);
         debug_assert_eq!(lowered.local_id.as_u32(), 0);
-        lowered
+        lowered.owner
     }
 
     fn create_stable_hashing_context(&self) -> LoweringHasher<'_> {
@@ -1494,9 +1428,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
-
-        self.allocate_hir_id_counter(opaque_ty_node_id);
+        let opaque_ty_def_id = self.allocate_hir_id_counter(opaque_ty_node_id);
 
         let collected_lifetimes = self.with_hir_id_owner(opaque_ty_node_id, move |lctx| {
             let hir_bounds = lower_bounds(lctx);
@@ -1753,9 +1685,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-        let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
-
-        self.allocate_hir_id_counter(opaque_ty_node_id);
+        let opaque_ty_def_id = self.allocate_hir_id_counter(opaque_ty_node_id);
 
         // When we create the opaque type for this async fn, it is going to have
         // to capture all the lifetimes involved in the signature (including in the
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 30bc4edd7e6..06e9d9ed329 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -702,10 +702,16 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
 }
 
 fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
+    // checks if `#![feature]` has been used to enable any lang feature
+    // does not check the same for lib features unless there's at least one
+    // declared lang feature
     use rustc_errors::Applicability;
 
     if !sess.opts.unstable_features.is_nightly_build() {
         let lang_features = &sess.features_untracked().declared_lang_features;
+        if lang_features.len() == 0 {
+            return;
+        }
         for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
             let mut err = struct_span_err!(
                 sess.parse_sess.span_diagnostic,
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 3c114084586..b23ce281bef 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -336,15 +336,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() =>
             {
                 let closure_kind_ty = closure_substs.as_closure().kind_ty();
-                let closure_kind = closure_kind_ty.to_opt_closure_kind();
-                let capture_description = match closure_kind {
-                    Some(ty::ClosureKind::Fn) => "captured variable in an `Fn` closure",
-                    Some(ty::ClosureKind::FnMut) => "captured variable in an `FnMut` closure",
+                let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
+                    Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
                     Some(ty::ClosureKind::FnOnce) => {
                         bug!("closure kind does not match first argument type")
                     }
                     None => bug!("closure kind not inferred by borrowck"),
                 };
+                let capture_description =
+                    format!("captured variable in an `{}` closure", closure_kind);
 
                 let upvar = &self.upvars[upvar_field.unwrap().index()];
                 let upvar_hir_id = upvar.place.get_root_variable();
@@ -368,6 +368,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 let mut diag = self.cannot_move_out_of(span, &place_description);
 
                 diag.span_label(upvar_span, "captured outer variable");
+                diag.span_label(
+                    self.body.span,
+                    format!("captured by this `{}` closure", closure_kind),
+                );
 
                 diag
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 57d2a3c5ce9..0761d63c665 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -40,6 +40,7 @@ impl ConstraintDescription for ConstraintCategory {
             ConstraintCategory::CopyBound => "copying this value ",
             ConstraintCategory::OpaqueType => "opaque type ",
             ConstraintCategory::ClosureUpvar(_) => "closure capture ",
+            ConstraintCategory::Usage => "this usage ",
             ConstraintCategory::Boring
             | ConstraintCategory::BoringNoLocation
             | ConstraintCategory::Internal => "",
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 39b83e50431..d790e31105c 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -46,7 +46,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
     /// which has no `external_name` in which case we use `'empty` as the
     /// region to pass to `infer_opaque_definition_from_instantiation`.
-    #[instrument(skip(self, infcx))]
+    #[instrument(level = "debug", skip(self, infcx))]
     pub(crate) fn infer_opaque_types(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 41c004ea596..5ccf3806025 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1388,11 +1388,24 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             ConstraintCategory::Return(ReturnConstraint::Normal)
                         }
                     }
+                    Some(l)
+                        if matches!(
+                            body.local_decls[l].local_info,
+                            Some(box LocalInfo::AggregateTemp)
+                        ) =>
+                    {
+                        ConstraintCategory::Usage
+                    }
                     Some(l) if !body.local_decls[l].is_user_variable() => {
                         ConstraintCategory::Boring
                     }
                     _ => ConstraintCategory::Assignment,
                 };
+                debug!(
+                    "assignment category: {:?} {:?}",
+                    category,
+                    place.as_local().map(|l| &body.local_decls[l])
+                );
 
                 let place_ty = place.ty(body, tcx).ty;
                 let place_ty = self.normalize(place_ty, location);
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 13790409e59..15bb9067805 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -5,7 +5,7 @@ mod pass_mode;
 mod returning;
 
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::ty::layout::FnAbiExt;
+use rustc_middle::ty::layout::FnAbiOf;
 use rustc_target::abi::call::{Conv, FnAbi};
 use rustc_target::spec::abi::Abi;
 
@@ -53,7 +53,11 @@ pub(crate) fn get_function_sig<'tcx>(
     inst: Instance<'tcx>,
 ) -> Signature {
     assert!(!inst.substs.needs_infer());
-    clif_sig_from_fn_abi(tcx, triple, &FnAbi::of_instance(&RevealAllLayoutCx(tcx), inst, &[]))
+    clif_sig_from_fn_abi(
+        tcx,
+        triple,
+        &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
+    )
 }
 
 /// Instance must be monomorphized
@@ -350,14 +354,13 @@ pub(crate) fn codegen_terminator_call<'tcx>(
     };
 
     let extra_args = &args[fn_sig.inputs().len()..];
-    let extra_args = extra_args
-        .iter()
-        .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))
-        .collect::<Vec<_>>();
+    let extra_args = fx
+        .tcx
+        .mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
     let fn_abi = if let Some(instance) = instance {
-        FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args)
+        RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
     } else {
-        FnAbi::of_fn_ptr(&RevealAllLayoutCx(fx.tcx), fn_ty.fn_sig(fx.tcx), &extra_args)
+        RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
     };
 
     let is_cold = instance
@@ -525,7 +528,8 @@ pub(crate) fn codegen_drop<'tcx>(
                     def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
                     substs: drop_instance.substs,
                 };
-                let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), virtual_drop, &[]);
+                let fn_abi =
+                    RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
 
                 let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi);
                 let sig = fx.bcx.import_signature(sig);
@@ -534,7 +538,8 @@ pub(crate) fn codegen_drop<'tcx>(
             _ => {
                 assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
 
-                let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), drop_instance, &[]);
+                let fn_abi =
+                    RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
 
                 let arg_value = drop_place.place_ref(
                     fx,
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index d29558a4e1f..d8fa2c76904 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -3,8 +3,7 @@
 use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::adjustment::PointerCast;
-use rustc_middle::ty::layout::FnAbiExt;
-use rustc_target::abi::call::FnAbi;
+use rustc_middle::ty::layout::FnAbiOf;
 
 use crate::constant::ConstantCx;
 use crate::prelude::*;
@@ -62,7 +61,7 @@ pub(crate) fn codegen_fn<'tcx>(
         instance,
         symbol_name,
         mir,
-        fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
+        fn_abi: Some(RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())),
 
         bcx,
         block_map,
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 6f7ca51d038..0e84681d9ad 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -1,5 +1,7 @@
 use rustc_index::vec::IndexVec;
-use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers};
+use rustc_middle::ty::layout::{
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
+};
 use rustc_middle::ty::SymbolName;
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{Integer, Primitive};
@@ -239,7 +241,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
     pub(crate) instance: Instance<'tcx>,
     pub(crate) symbol_name: SymbolName<'tcx>,
     pub(crate) mir: &'tcx Body<'tcx>,
-    pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>,
+    pub(crate) fn_abi: Option<&'tcx FnAbi<'tcx, Ty<'tcx>>>,
 
     pub(crate) bcx: FunctionBuilder<'clif>,
     pub(crate) block_map: IndexVec<BasicBlock, Block>,
@@ -266,6 +268,20 @@ impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
     }
 }
 
+impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
+    }
+}
+
 impl<'tcx> layout::HasTyCtxt<'tcx> for FunctionCx<'_, '_, 'tcx> {
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.tcx
@@ -378,6 +394,43 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
     }
 }
 
+impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+            self.0.sess.span_fatal(span, &err.to_string())
+        } else {
+            match fn_abi_request {
+                FnAbiRequest::OfFnPtr { sig, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
+                        sig,
+                        extra_args,
+                        err
+                    );
+                }
+                FnAbiRequest::OfInstance { instance, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_instance({}, {:?})` failed: {}",
+                        instance,
+                        extra_args,
+                        err
+                    );
+                }
+            }
+        }
+    }
+}
+
 impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> {
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.0
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 424a0d742d1..5c4991f1fb6 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -129,9 +129,7 @@ pub(crate) fn codegen_constant<'tcx>(
     };
     let const_val = match const_.val {
         ConstKind::Value(const_val) => const_val,
-        ConstKind::Unevaluated(uv)
-            if fx.tcx.is_static(uv.def.did) =>
-        {
+        ConstKind::Unevaluated(uv) if fx.tcx.is_static(uv.def.did) => {
             assert!(uv.substs(fx.tcx).is_empty());
             assert!(uv.promoted.is_none());
 
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index 05db74745a1..ec846d71960 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -61,9 +61,8 @@ use cranelift_codegen::{
     write::{FuncWriter, PlainWriter},
 };
 
-use rustc_middle::ty::layout::FnAbiExt;
+use rustc_middle::ty::layout::FnAbiOf;
 use rustc_session::config::OutputType;
-use rustc_target::abi::call::FnAbi;
 
 use crate::prelude::*;
 
@@ -81,7 +80,10 @@ impl CommentWriter {
             vec![
                 format!("symbol {}", tcx.symbol_name(instance).name),
                 format!("instance {:?}", instance),
-                format!("abi {:?}", FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
+                format!(
+                    "abi {:?}",
+                    RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())
+                ),
                 String::new(),
             ]
         } else {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 799f9a57e93..dab7d3eaa8c 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -15,10 +15,12 @@ use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::MemFlags;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
+use rustc_middle::ty::layout::{
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
+};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
-use rustc_target::abi::{self, Align, Size, WrappingRange};
+use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
 use rustc_target::spec::{HasTargetSpec, Target};
 use std::borrow::Cow;
 use std::ffi::CStr;
@@ -97,6 +99,20 @@ impl LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
     }
 }
 
+impl FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        self.cx.handle_fn_abi_err(err, span, fn_abi_request)
+    }
+}
+
 impl Deref for Builder<'_, 'll, 'tcx> {
     type Target = CodegenCx<'ll, 'tcx>;
 
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index bb16c90cd12..a96ba148a6c 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -4,7 +4,7 @@
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
-use crate::abi::{FnAbi, FnAbiLlvmExt};
+use crate::abi::FnAbiLlvmExt;
 use crate::attributes;
 use crate::context::CodegenCx;
 use crate::llvm;
@@ -12,7 +12,7 @@ use crate::value::Value;
 use rustc_codegen_ssa::traits::*;
 use tracing::debug;
 
-use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, TypeFoldable};
 
 /// Codegens a reference to a fn/method item, monomorphizing and
@@ -42,7 +42,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
         sym
     );
 
-    let fn_abi = FnAbi::of_instance(cx, instance, &[]);
+    let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
 
     let llfn = if let Some(llfn) = cx.get_declared_value(&sym) {
         // Create a fn pointer with the new signature.
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 2d397dc5835..52a12b2fd81 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -15,14 +15,19 @@ use rustc_data_structures::base_n;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_middle::mir::mono::CodegenUnit;
-use rustc_middle::ty::layout::{HasParamEnv, LayoutError, LayoutOfHelpers, TyAndLayout};
+use rustc_middle::ty::layout::{
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
+    TyAndLayout,
+};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CFGuard, CrateType, DebugInfo};
 use rustc_session::Session;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
-use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
+use rustc_target::abi::{
+    call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
+};
 use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
 use smallvec::SmallVec;
 
@@ -835,6 +840,12 @@ impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 }
 
+impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> {
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        ty::ParamEnv::reveal_all()
+    }
+}
+
 impl LayoutOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
     type LayoutOfResult = TyAndLayout<'tcx>;
 
@@ -848,8 +859,39 @@ impl LayoutOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 }
 
-impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> {
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        ty::ParamEnv::reveal_all()
+impl FnAbiOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+            self.sess().span_fatal(span, &err.to_string())
+        } else {
+            match fn_abi_request {
+                FnAbiRequest::OfFnPtr { sig, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
+                        sig,
+                        extra_args,
+                        err
+                    );
+                }
+                FnAbiRequest::OfInstance { instance, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_instance({}, {:?})` failed: {}",
+                        instance,
+                        extra_args,
+                        err
+                    );
+                }
+            }
+        }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 019bf4a09a7..093aceda2b7 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -1,6 +1,6 @@
 use crate::llvm;
 
-use crate::abi::{Abi, FnAbi};
+use crate::abi::Abi;
 use crate::builder::Builder;
 use crate::common::CodegenCx;
 
@@ -20,7 +20,7 @@ use rustc_middle::mir::coverage::{
     CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op,
 };
 use rustc_middle::ty;
-use rustc_middle::ty::layout::FnAbiExt;
+use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::Instance;
 
@@ -200,8 +200,7 @@ fn declare_unused_fn(cx: &CodegenCx<'ll, 'tcx>, def_id: &DefId) -> Instance<'tcx
 
     let llfn = cx.declare_fn(
         &tcx.symbol_name(instance).name,
-        &FnAbi::of_fn_ptr(
-            cx,
+        &cx.fn_abi_of_fn_ptr(
             ty::Binder::dummy(tcx.mk_fn_sig(
                 iter::once(tcx.mk_unit()),
                 tcx.mk_unit(),
@@ -209,7 +208,7 @@ fn declare_unused_fn(cx: &CodegenCx<'ll, 'tcx>, def_id: &DefId) -> Instance<'tcx
                 hir::Unsafety::Unsafe,
                 Abi::Rust,
             )),
-            &[],
+            ty::List::empty(),
         ),
     );
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index c2725b83f50..1612922d439 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -3,12 +3,11 @@ use super::utils::DIB;
 use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
 use rustc_codegen_ssa::traits::*;
 
-use crate::abi::FnAbi;
 use crate::common::CodegenCx;
 use crate::llvm;
 use crate::llvm::debuginfo::{DILocation, DIScope};
 use rustc_middle::mir::{Body, SourceScope};
-use rustc_middle::ty::layout::FnAbiExt;
+use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::{self, Instance};
 use rustc_session::config::DebugInfo;
 
@@ -94,7 +93,7 @@ fn make_mir_scope(
                 ty::ParamEnv::reveal_all(),
                 callee,
             );
-            let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]);
+            let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
             cx.dbg_scope_fn(callee, &callee_fn_abi, None)
         }
         None => unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 1060f911a9e..37b3279fb80 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -15,7 +15,7 @@ use rustc_codegen_ssa::mir::operand::OperandRef;
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::*;
 use rustc_hir as hir;
-use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, LayoutOf};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{sym, symbol::kw, Span, Symbol};
@@ -737,7 +737,7 @@ fn gen_fn<'ll, 'tcx>(
     rust_fn_sig: ty::PolyFnSig<'tcx>,
     codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
 ) -> (&'ll Type, &'ll Value) {
-    let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]);
+    let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
     let llty = fn_abi.llvm_type(cx);
     let llfn = cx.declare_fn(name, &fn_abi);
     cx.set_frame_pointer_type(llfn);
@@ -918,12 +918,29 @@ fn generic_simd_intrinsic(
     }
 
     if let Some(stripped) = name_str.strip_prefix("simd_shuffle") {
-        let n: u64 = stripped.parse().unwrap_or_else(|_| {
-            span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
-        });
+        // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
+        // If there is no suffix, use the index array length.
+        let n: u64 = if stripped.is_empty() {
+            // Make sure this is actually an array, since typeck only checks the length-suffixed
+            // version of this intrinsic.
+            match args[2].layout.ty.kind() {
+                ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
+                    len.try_eval_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
+                        span_bug!(span, "could not evaluate shuffle index array length")
+                    })
+                }
+                _ => return_error!(
+                    "simd_shuffle index must be an array of `u32`, got `{}`",
+                    args[2].layout.ty
+                ),
+            }
+        } else {
+            stripped.parse().unwrap_or_else(|_| {
+                span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
+            })
+        };
 
         require_simd!(ret_ty, "return");
-
         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             out_len == n,
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 8ba3e870fbb..34982f769d0 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -1,4 +1,3 @@
-use crate::abi::FnAbi;
 use crate::attributes;
 use crate::base;
 use crate::context::CodegenCx;
@@ -8,7 +7,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 pub use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::mir::mono::{Linkage, Visibility};
-use rustc_middle::ty::layout::{FnAbiExt, LayoutOf};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
 use rustc_middle::ty::{self, Instance, TypeFoldable};
 use rustc_session::config::CrateType;
 use rustc_target::spec::RelocModel;
@@ -53,7 +52,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     ) {
         assert!(!instance.substs.needs_infer());
 
-        let fn_abi = FnAbi::of_instance(self, instance, &[]);
+        let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
         let lldecl = self.declare_fn(symbol_name, &fn_abi);
         unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
         let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 3e39bf3e995..757ccbddbee 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -1,10 +1,9 @@
-use crate::abi::FnAbi;
 use crate::common::*;
 use crate::context::TypeLowering;
 use crate::type_::Type;
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::bug;
-use rustc_middle::ty::layout::{FnAbiExt, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TypeFoldable};
 use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
@@ -231,7 +230,9 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
                 ty::Adt(def, _) if def.is_box() => {
                     cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx))
                 }
-                ty::FnPtr(sig) => cx.fn_ptr_backend_type(&FnAbi::of_fn_ptr(cx, sig, &[])),
+                ty::FnPtr(sig) => {
+                    cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty()))
+                }
                 _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO),
             };
             cx.scalar_lltypes.borrow_mut().insert(self.ty, llty);
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index cd0e9354c24..4be050fb88c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -14,7 +14,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
 use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::{self, SwitchTargets};
-use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, LayoutOf};
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_span::source_map::Span;
@@ -124,7 +124,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         &self,
         fx: &mut FunctionCx<'a, 'tcx, Bx>,
         bx: &mut Bx,
-        fn_abi: FnAbi<'tcx, Ty<'tcx>>,
+        fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
         fn_ptr: Bx::Value,
         llargs: &[Bx::Value],
         destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
@@ -337,7 +337,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
                     substs: drop_fn.substs,
                 };
-                let fn_abi = FnAbi::of_instance(&bx, virtual_drop, &[]);
+                let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
                 let vtable = args[1];
                 args = &args[..1];
                 (
@@ -346,7 +346,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     fn_abi,
                 )
             }
-            _ => (bx.get_fn_addr(drop_fn), FnAbi::of_instance(&bx, drop_fn, &[])),
+            _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
         };
         helper.do_call(
             self,
@@ -433,7 +433,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // Obtain the panic entry point.
         let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
         let instance = ty::Instance::mono(bx.tcx(), def_id);
-        let fn_abi = FnAbi::of_instance(&bx, instance, &[]);
+        let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
         let llfn = bx.get_fn_addr(instance);
 
         // Codegen the actual panic invoke/call.
@@ -494,7 +494,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let def_id =
                     common::langcall(bx.tcx(), Some(source_info.span), "", LangItem::Panic);
                 let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let fn_abi = FnAbi::of_instance(bx, instance, &[]);
+                let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
                 let llfn = bx.get_fn_addr(instance);
 
                 // Codegen the actual panic invoke/call.
@@ -570,17 +570,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         };
 
         let extra_args = &args[sig.inputs().skip_binder().len()..];
-        let extra_args = extra_args
-            .iter()
-            .map(|op_arg| {
-                let op_ty = op_arg.ty(self.mir, bx.tcx());
-                self.monomorphize(op_ty)
-            })
-            .collect::<Vec<_>>();
+        let extra_args = bx.tcx().mk_type_list(extra_args.iter().map(|op_arg| {
+            let op_ty = op_arg.ty(self.mir, bx.tcx());
+            self.monomorphize(op_ty)
+        }));
 
         let fn_abi = match instance {
-            Some(instance) => FnAbi::of_instance(&bx, instance, &extra_args),
-            None => FnAbi::of_fn_ptr(&bx, sig, &extra_args),
+            Some(instance) => bx.fn_abi_of_instance(instance, extra_args),
+            None => bx.fn_abi_of_fn_ptr(sig, extra_args),
         };
 
         if intrinsic == Some(sym::transmute) {
@@ -665,8 +662,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
                             if let mir::Operand::Constant(constant) = arg {
                                 let c = self.eval_mir_constant(constant);
-                                let (llval, ty) =
-                                    self.simd_shuffle_indices(&bx, constant.span, constant.ty(), c);
+                                let (llval, ty) = self.simd_shuffle_indices(
+                                    &bx,
+                                    constant.span,
+                                    self.monomorphize(constant.ty()),
+                                    c,
+                                );
                                 return OperandRef {
                                     val: Immediate(llval),
                                     layout: bx.layout_of(ty),
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index e2edd448267..8e3982c72d7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -2,7 +2,7 @@ use crate::traits::*;
 use rustc_errors::ErrorReported;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_target::abi::call::{FnAbi, PassMode};
 
@@ -29,7 +29,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 
     cx: &'a Bx::CodegenCx,
 
-    fn_abi: FnAbi<'tcx, Ty<'tcx>>,
+    fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
 
     /// When unwinding is initiated, we have to store this personality
     /// value somewhere so that we can load it and re-use it in the
@@ -139,7 +139,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     let mir = cx.tcx().instance_mir(instance.def);
 
-    let fn_abi = FnAbi::of_instance(cx, instance, &[]);
+    let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
     debug!("fn_abi: {:?}", fn_abi);
 
     let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, &mir);
@@ -152,20 +152,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 
     let cleanup_kinds = analyze::cleanup_kinds(&mir);
-    // Allocate a `Block` for every basic block, except
-    // the start block, if nothing loops back to it.
-    let reentrant_start_block = !mir.predecessors()[mir::START_BLOCK].is_empty();
-    let cached_llbbs: IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>> =
-        mir.basic_blocks()
-            .indices()
-            .map(|bb| {
-                if bb == mir::START_BLOCK && !reentrant_start_block {
-                    Some(start_llbb)
-                } else {
-                    None
-                }
-            })
-            .collect();
+    let cached_llbbs: IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>> = mir
+        .basic_blocks()
+        .indices()
+        .map(|bb| if bb == mir::START_BLOCK { Some(start_llbb) } else { None })
+        .collect();
 
     let mut fx = FunctionCx {
         instance,
@@ -247,11 +238,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     // Apply debuginfo to the newly allocated locals.
     fx.debug_introduce_locals(&mut bx);
 
-    // Branch to the START block, if it's not the entry block.
-    if reentrant_start_block {
-        bx.br(fx.llbb(mir::START_BLOCK));
-    }
-
     // Codegen the body of each block using reverse postorder
     // FIXME(eddyb) reuse RPO iterator between `analysis` and this.
     for (bb, _) in traversal::reverse_postorder(&mir) {
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index dbb7e1ee8b1..82b79fd0b2a 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -8,14 +8,15 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorReported;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
-use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_session::{
     config::{self, OutputFilenames, PrintRequest},
     Session,
 };
 use rustc_span::symbol::Symbol;
+use rustc_target::abi::call::FnAbi;
 use rustc_target::spec::Target;
 
 pub use rustc_data_structures::sync::MetadataRef;
@@ -38,12 +39,19 @@ pub trait BackendTypes {
 }
 
 pub trait Backend<'tcx>:
-    Sized + BackendTypes + HasTyCtxt<'tcx> + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
+    Sized
+    + BackendTypes
+    + HasTyCtxt<'tcx>
+    + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
+    + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>>
 {
 }
 
 impl<'tcx, T> Backend<'tcx> for T where
-    Self: BackendTypes + HasTyCtxt<'tcx> + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
+    Self: BackendTypes
+        + HasTyCtxt<'tcx>
+        + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
+        + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>>
 {
 }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 8a90686b900..ae20f6f97b2 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -36,12 +36,17 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
         let def_id = instance.def_id();
         if Some(def_id) == self.tcx.lang_items().panic_fn()
             || Some(def_id) == self.tcx.lang_items().panic_str()
+            || Some(def_id) == self.tcx.lang_items().panic_display()
             || Some(def_id) == self.tcx.lang_items().begin_panic_fn()
         {
-            // &str
+            // &str or &&str
             assert!(args.len() == 1);
 
-            let msg_place = self.deref_operand(&args[0])?;
+            let mut msg_place = self.deref_operand(&args[0])?;
+            while msg_place.layout.ty.is_ref() {
+                msg_place = self.deref_operand(&msg_place.into())?;
+            }
+
             let msg = Symbol::intern(self.read_str(&msg_place)?);
             let span = self.find_closest_untracked_caller_location();
             let (file, line, col) = self.location_triple_for_span(span);
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index d5682f702ba..9eec930f59e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -384,11 +384,11 @@ impl Checker<'mir, 'tcx> {
                         match pred.skip_binder() {
                             ty::ExistentialPredicate::AutoTrait(_)
                             | ty::ExistentialPredicate::Projection(_) => {
-                                self.check_op(ops::ty::TraitBound(kind))
+                                self.check_op(ops::ty::DynTrait(kind))
                             }
                             ty::ExistentialPredicate::Trait(trait_ref) => {
                                 if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
-                                    self.check_op(ops::ty::TraitBound(kind))
+                                    self.check_op(ops::ty::DynTrait(kind))
                                 }
                             }
                         }
@@ -888,6 +888,10 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
                 if is_lang_panic_fn(tcx, callee) {
                     self.check_op(ops::Panic);
 
+                    // `begin_panic` and `panic_display` are generic functions that accept
+                    // types other than str. Check to enforce that only str can be used in
+                    // const-eval.
+
                     // const-eval of the `begin_panic` fn assumes the argument is `&str`
                     if Some(callee) == tcx.lang_items().begin_panic_fn() {
                         match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
@@ -896,6 +900,15 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
                         }
                     }
 
+                    // const-eval of the `panic_display` fn assumes the argument is `&&str`
+                    if Some(callee) == tcx.lang_items().panic_display() {
+                        match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+                            ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
+                                {}
+                            _ => self.check_op(ops::PanicNonStr),
+                        }
+                    }
+
                     return;
                 }
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index a5cb0f4e14b..d1fd3ceaa58 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -79,6 +79,7 @@ pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
     // Keep in sync with what that function handles!
     Some(def_id) == tcx.lang_items().panic_fn()
         || Some(def_id) == tcx.lang_items().panic_str()
+        || Some(def_id) == tcx.lang_items().panic_display()
         || Some(def_id) == tcx.lang_items().begin_panic_fn()
         || Some(def_id) == tcx.lang_items().panic_fmt()
         || Some(def_id) == tcx.lang_items().begin_panic_fmt()
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 2a296750838..1d0ee949a22 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -599,7 +599,7 @@ pub mod ty {
         }
 
         fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-            let mut builder = feature_err(
+            let mut err = feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_fn_trait_bound,
                 span,
@@ -608,12 +608,51 @@ pub mod ty {
 
             match ccx.fn_sig() {
                 Some(fn_sig) if !fn_sig.span.contains(span) => {
-                    builder.span_label(fn_sig.span, "function declared as const here");
+                    err.span_label(fn_sig.span, "function declared as const here");
                 }
                 _ => {}
             }
 
-            builder
+            err
+        }
+    }
+
+    #[derive(Debug)]
+    pub struct DynTrait(pub mir::LocalKind);
+    impl NonConstOp for DynTrait {
+        fn importance(&self) -> DiagnosticImportance {
+            match self.0 {
+                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
+                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
+                    DiagnosticImportance::Primary
+                }
+            }
+        }
+
+        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+            if ccx.const_kind() != hir::ConstContext::ConstFn {
+                Status::Allowed
+            } else {
+                Status::Unstable(sym::const_fn_trait_bound)
+            }
+        }
+
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+            let mut err = feature_err(
+                &ccx.tcx.sess.parse_sess,
+                sym::const_fn_trait_bound,
+                span,
+                "trait objects in const fn are unstable",
+            );
+
+            match ccx.fn_sig() {
+                Some(fn_sig) if !fn_sig.span.contains(span) => {
+                    err.span_label(fn_sig.span, "function declared as const here");
+                }
+                _ => {}
+            }
+
+            err
         }
     }
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index dc3927ed85b..cb9b4bcb77a 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -111,7 +111,17 @@ impl Qualif for NeedsNonConstDrop {
         qualifs.needs_drop
     }
 
-    fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+    fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
+        // Avoid selecting for simple cases.
+        match ty::util::needs_drop_components(ty, &cx.tcx.data_layout).as_deref() {
+            Ok([]) => return false,
+            Err(ty::util::AlwaysRequiresDrop) => return true,
+            // If we've got a single component, select with that
+            // to increase the chance that we hit the selection cache.
+            Ok([t]) => ty = t,
+            Ok([..]) => {}
+        }
+
         let drop_trait = if let Some(did) = cx.tcx.lang_items().drop_trait() {
             did
         } else {
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 40a32a76c94..b09b2227f3e 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
     AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem,
     PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
-    TerminatorKind,
+    TerminatorKind, START_BLOCK,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
@@ -130,6 +130,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     }
 
     fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
+        if bb == START_BLOCK {
+            self.fail(location, "start block must not have predecessors")
+        }
         if let Some(bb) = self.body.basic_blocks().get(bb) {
             let src = self.body.basic_blocks().get(location.block).unwrap();
             match (src.is_cleanup, bb.is_cleanup, edge_kind) {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0071.md b/compiler/rustc_error_codes/src/error_codes/E0071.md
index bc2c03a0220..a6d6d19762b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0071.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0071.md
@@ -15,13 +15,13 @@ form of initializer was used.
 For example, the code above can be fixed to:
 
 ```
-enum Foo {
-    FirstValue(i32)
-}
+type U32 = u32;
+let t: U32 = 4;
+```
 
-fn main() {
-    let u = Foo::FirstValue(0i32);
+or:
 
-    let t = 4;
-}
+```
+struct U32 { value: u32 }
+let t = U32 { value: 4 };
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0439.md b/compiler/rustc_error_codes/src/error_codes/E0439.md
index 3e663df866c..24268aef222 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0439.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0439.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 The length of the platform-intrinsic function `simd_shuffle` wasn't specified.
 
 Erroneous code example:
 
-```compile_fail,E0439
+```ignore (no longer emitted)
 #![feature(platform_intrinsics)]
 
 extern "platform-intrinsic" {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 62066ca9657..d32593f34ad 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1386,14 +1386,17 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
         // See #78991 for an investigation of treating macros in this position
         // as statements, rather than expressions, during parsing.
-        if let StmtKind::Expr(expr) = &stmt.kind {
-            if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) {
+        let res = match &stmt.kind {
+            StmtKind::Expr(expr)
+                if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) =>
+            {
                 self.cx.current_expansion.is_trailing_mac = true;
+                // Don't use `assign_id` for this statement - it may get removed
+                // entirely due to a `#[cfg]` on the contained expression
+                noop_flat_map_stmt(stmt, self)
             }
-        }
-
-        let res = assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self));
-
+            _ => assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self)),
+        };
         self.cx.current_expansion.is_trailing_mac = false;
         res
     }
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index c92551c2930..ff6758e66df 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -17,3 +17,4 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
 tracing = "0.1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+odht = { version = "0.2.1", features = ["nightly"] }
diff --git a/compiler/rustc_hir/src/def_path_hash_map.rs b/compiler/rustc_hir/src/def_path_hash_map.rs
new file mode 100644
index 00000000000..8bfb47af26f
--- /dev/null
+++ b/compiler/rustc_hir/src/def_path_hash_map.rs
@@ -0,0 +1,37 @@
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_span::def_id::{DefIndex, DefPathHash};
+
+#[derive(Clone, Default)]
+pub struct Config;
+
+impl odht::Config for Config {
+    type Key = DefPathHash;
+    type Value = DefIndex;
+
+    type EncodedKey = [u8; 16];
+    type EncodedValue = [u8; 4];
+
+    type H = odht::UnHashFn;
+
+    #[inline]
+    fn encode_key(k: &DefPathHash) -> [u8; 16] {
+        k.0.to_le_bytes()
+    }
+
+    #[inline]
+    fn encode_value(v: &DefIndex) -> [u8; 4] {
+        v.as_u32().to_le_bytes()
+    }
+
+    #[inline]
+    fn decode_key(k: &[u8; 16]) -> DefPathHash {
+        DefPathHash(Fingerprint::from_le_bytes(*k))
+    }
+
+    #[inline]
+    fn decode_value(v: &[u8; 4]) -> DefIndex {
+        DefIndex::from_u32(u32::from_le_bytes(*v))
+    }
+}
+
+pub type DefPathHashMap = odht::HashTableOwned<Config>;
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 5f56f3a32ad..ca29351455e 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -6,11 +6,11 @@
 
 pub use crate::def_id::DefPathHash;
 use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::def_path_hash_map::DefPathHashMap;
 use crate::hir;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_data_structures::unhash::UnhashMap;
 use rustc_index::vec::IndexVec;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -28,7 +28,7 @@ use tracing::debug;
 pub struct DefPathTable {
     index_to_key: IndexVec<DefIndex, DefKey>,
     def_path_hashes: IndexVec<DefIndex, DefPathHash>,
-    def_path_hash_to_index: UnhashMap<DefPathHash, DefIndex>,
+    def_path_hash_to_index: DefPathHashMap,
 }
 
 impl DefPathTable {
@@ -44,7 +44,7 @@ impl DefPathTable {
 
         // Check for hash collisions of DefPathHashes. These should be
         // exceedingly rare.
-        if let Some(existing) = self.def_path_hash_to_index.insert(def_path_hash, index) {
+        if let Some(existing) = self.def_path_hash_to_index.insert(&def_path_hash, &index) {
             let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx));
             let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx));
 
@@ -87,7 +87,7 @@ impl DefPathTable {
 
     pub fn enumerated_keys_and_path_hashes(
         &self,
-    ) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + '_ {
+    ) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + ExactSizeIterator + '_ {
         self.index_to_key
             .iter_enumerated()
             .map(move |(index, key)| (index, key, &self.def_path_hashes[index]))
@@ -110,6 +110,9 @@ pub struct Definitions {
     expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
 
     def_id_to_span: IndexVec<LocalDefId, Span>,
+
+    /// The [StableCrateId] of the local crate.
+    stable_crate_id: StableCrateId,
 }
 
 /// A unique identifier that we can use to lookup a definition
@@ -356,6 +359,7 @@ impl Definitions {
             hir_id_to_def_id: Default::default(),
             expansions_that_defined: Default::default(),
             def_id_to_span,
+            stable_crate_id,
         }
     }
 
@@ -439,11 +443,17 @@ impl Definitions {
     }
 
     #[inline(always)]
-    pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> {
+    pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> LocalDefId {
+        debug_assert!(hash.stable_crate_id() == self.stable_crate_id);
         self.table
             .def_path_hash_to_index
             .get(&hash)
-            .map(|&local_def_index| LocalDefId { local_def_index })
+            .map(|local_def_index| LocalDefId { local_def_index })
+            .unwrap()
+    }
+
+    pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
+        &self.table.def_path_hash_to_index
     }
 }
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 5655c4c0e97..f5fc693ce25 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -21,7 +21,7 @@ use rustc_target::asm::InlineAsmRegOrRegClass;
 use rustc_target::spec::abi::Abi;
 
 use smallvec::SmallVec;
-use std::collections::{BTreeMap, BTreeSet};
+use std::collections::BTreeMap;
 use std::fmt;
 
 #[derive(Copy, Clone, Encodable, HashStable_Generic)]
@@ -653,16 +653,6 @@ pub struct WhereEqPredicate<'hir> {
     pub rhs_ty: &'hir Ty<'hir>,
 }
 
-#[derive(Default, Encodable, Debug, HashStable_Generic)]
-pub struct ModuleItems {
-    // Use BTreeSets here so items are in the same order as in the
-    // list of all items in Crate
-    pub items: BTreeSet<ItemId>,
-    pub trait_items: BTreeSet<TraitItemId>,
-    pub impl_items: BTreeSet<ImplItemId>,
-    pub foreign_items: BTreeSet<ForeignItemId>,
-}
-
 /// The top-level data structure that stores the entire contents of
 /// the crate currently being compiled.
 ///
@@ -674,10 +664,6 @@ pub struct Crate<'hir> {
     pub owners: IndexVec<LocalDefId, Option<OwnerNode<'hir>>>,
     pub bodies: BTreeMap<BodyId, Body<'hir>>,
 
-    /// A list of modules written out in the order in which they
-    /// appear in the crate. This includes the main crate module.
-    pub modules: BTreeMap<LocalDefId, ModuleItems>,
-
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
     pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>,
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index b85ed0cb4bb..d69a2470540 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -283,6 +283,7 @@ language_item_table! {
     // a weak lang item, but do not have it defined.
     Panic,                   sym::panic,               panic_fn,                   Target::Fn,             GenericRequirement::None;
     PanicFmt,                sym::panic_fmt,           panic_fmt,                  Target::Fn,             GenericRequirement::None;
+    PanicDisplay,            sym::panic_display,       panic_display,              Target::Fn,             GenericRequirement::None;
     PanicStr,                sym::panic_str,           panic_str,                  Target::Fn,             GenericRequirement::None;
     ConstPanicFmt,           sym::const_panic_fmt,     const_panic_fmt,            Target::Fn,             GenericRequirement::None;
     PanicBoundsCheck,        sym::panic_bounds_check,  panic_bounds_check_fn,      Target::Fn,             GenericRequirement::None;
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 42575273839..ce36648d6df 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -16,6 +16,7 @@ extern crate rustc_data_structures;
 
 mod arena;
 pub mod def;
+pub mod def_path_hash_map;
 pub mod definitions;
 pub use rustc_span::def_id;
 mod hir;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 593d06bad7b..35c8786dcd3 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             ObligationCauseCode::MatchImpl(parent, impl_def_id) => (parent, impl_def_id),
             _ => return None,
         };
-        let binding_span = match **parent {
+        let binding_span = match parent.code {
             ObligationCauseCode::BindingObligation(_def_id, binding_span) => binding_span,
             _ => return None,
         };
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 81059fbcb10..2d47e72780e 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -189,7 +189,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         }
         if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin {
             let code = match &cause.code {
-                ObligationCauseCode::MatchImpl(parent, ..) => &**parent,
+                ObligationCauseCode::MatchImpl(parent, ..) => &parent.code,
                 _ => &cause.code,
             };
             if let ObligationCauseCode::ItemObligation(item_def_id) = *code {
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 1f3d6f70ff8..cb7529b527e 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -8,7 +8,7 @@ use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::parallel;
-use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
+use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorReported, PResult};
 use rustc_expand::base::ExtCtxt;
@@ -861,7 +861,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
                 CStore::from_tcx(tcx).report_unused_deps(tcx);
             },
             {
-                par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
+                tcx.hir().par_for_each_module(|module| {
                     tcx.ensure().check_mod_loops(module);
                     tcx.ensure().check_mod_attrs(module);
                     tcx.ensure().check_mod_naked_functions(module);
@@ -893,7 +893,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
             },
             {
                 sess.time("liveness_and_intrinsic_checking", || {
-                    par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
+                    tcx.hir().par_for_each_module(|module| {
                         // this must run before MIR dump, because
                         // "not all control paths return a value" is reported here.
                         //
@@ -963,7 +963,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
             },
             {
                 sess.time("privacy_checking_modules", || {
-                    par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
+                    tcx.hir().par_for_each_module(|module| {
                         tcx.ensure().check_mod_privacy(module);
                     });
                 });
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 2070fd69d3f..00c3a6fa25e 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -16,7 +16,7 @@
 
 use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
 use rustc_ast as ast;
-use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
+use rustc_data_structures::sync::join;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit as hir_visit;
@@ -501,9 +501,7 @@ pub fn check_crate<'tcx, T: LateLintPass<'tcx>>(
         || {
             tcx.sess.time("module_lints", || {
                 // Run per-module lints
-                par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
-                    tcx.ensure().lint_mod(module);
-                });
+                tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module));
             });
         },
     );
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 7c79aa5e00b..42596f3318d 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -8,6 +8,7 @@ doctest = false
 
 [dependencies]
 libc = "0.2"
+odht = { version = "0.2.1", features = ["nightly"] }
 snap = "1"
 tracing = "0.1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 99030febb73..48d8cdf57dc 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -45,7 +45,7 @@ pub struct CStore {
 
     /// This map is used to verify we get no hash conflicts between
     /// `StableCrateId` values.
-    stable_crate_ids: FxHashMap<StableCrateId, CrateNum>,
+    pub(crate) stable_crate_ids: FxHashMap<StableCrateId, CrateNum>,
 
     /// Unused externs of the crate
     unused_externs: Vec<Symbol>,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 2a0332a1124..eb3a9f576a7 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -48,7 +48,26 @@ use rustc_span::hygiene::HygieneDecodeContext;
 
 mod cstore_impl;
 
-crate struct MetadataBlob(MetadataRef);
+/// A reference to the raw binary version of crate metadata.
+/// A `MetadataBlob` internally is just a reference counted pointer to
+/// the actual data, so cloning it is cheap.
+#[derive(Clone)]
+crate struct MetadataBlob(Lrc<MetadataRef>);
+
+// This is needed so we can create an OwningRef into the blob.
+// The data behind a `MetadataBlob` has a stable address because it is
+// contained within an Rc/Arc.
+unsafe impl rustc_data_structures::owning_ref::StableAddress for MetadataBlob {}
+
+// This is needed so we can create an OwningRef into the blob.
+impl std::ops::Deref for MetadataBlob {
+    type Target = [u8];
+
+    #[inline]
+    fn deref(&self) -> &[u8] {
+        &self.0[..]
+    }
+}
 
 // A map from external crate numbers (as decoded from some crate file) to
 // local crate numbers (as generated during this session). Each external
@@ -76,10 +95,8 @@ crate struct CrateMetadata {
     raw_proc_macros: Option<&'static [ProcMacro]>,
     /// Source maps for code from the crate.
     source_map_import_info: OnceCell<Vec<ImportedSourceFile>>,
-    /// For every definition in this crate, maps its `DefPathHash` to its
-    /// `DefIndex`. See `raw_def_id_to_def_id` for more details about how
-    /// this is used.
-    def_path_hash_map: OnceCell<UnhashMap<DefPathHash, DefIndex>>,
+    /// For every definition in this crate, maps its `DefPathHash` to its `DefIndex`.
+    def_path_hash_map: DefPathHashMapRef<'static>,
     /// Likewise for ExpnHash.
     expn_hash_map: OnceCell<UnhashMap<ExpnHash, ExpnIndex>>,
     /// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
@@ -134,6 +151,7 @@ struct ImportedSourceFile {
 pub(super) struct DecodeContext<'a, 'tcx> {
     opaque: opaque::Decoder<'a>,
     cdata: Option<CrateMetadataRef<'a>>,
+    blob: &'a MetadataBlob,
     sess: Option<&'tcx Session>,
     tcx: Option<TyCtxt<'tcx>>,
 
@@ -148,7 +166,8 @@ pub(super) struct DecodeContext<'a, 'tcx> {
 
 /// Abstract over the various ways one can create metadata decoders.
 pub(super) trait Metadata<'a, 'tcx>: Copy {
-    fn raw_bytes(self) -> &'a [u8];
+    fn blob(self) -> &'a MetadataBlob;
+
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
         None
     }
@@ -162,8 +181,9 @@ pub(super) trait Metadata<'a, 'tcx>: Copy {
     fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
         let tcx = self.tcx();
         DecodeContext {
-            opaque: opaque::Decoder::new(self.raw_bytes(), pos),
+            opaque: opaque::Decoder::new(self.blob(), pos),
             cdata: self.cdata(),
+            blob: self.blob(),
             sess: self.sess().or(tcx.map(|tcx| tcx.sess)),
             tcx,
             last_source_file_index: 0,
@@ -176,17 +196,19 @@ pub(super) trait Metadata<'a, 'tcx>: Copy {
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
-    fn raw_bytes(self) -> &'a [u8] {
-        &self.0
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        self
     }
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) {
-    fn raw_bytes(self) -> &'a [u8] {
-        let (blob, _) = self;
-        &blob.0
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        self.0
     }
 
+    #[inline]
     fn sess(self) -> Option<&'tcx Session> {
         let (_, sess) = self;
         Some(sess)
@@ -194,33 +216,41 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) {
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadataRef<'a> {
-    fn raw_bytes(self) -> &'a [u8] {
-        self.blob.raw_bytes()
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        &self.blob
     }
+    #[inline]
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
         Some(*self)
     }
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, &'tcx Session) {
-    fn raw_bytes(self) -> &'a [u8] {
-        self.0.raw_bytes()
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        &self.0.blob
     }
+    #[inline]
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
         Some(*self.0)
     }
+    #[inline]
     fn sess(self) -> Option<&'tcx Session> {
         Some(&self.1)
     }
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) {
-    fn raw_bytes(self) -> &'a [u8] {
-        self.0.raw_bytes()
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        &self.0.blob
     }
+    #[inline]
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
         Some(*self.0)
     }
+    #[inline]
     fn tcx(self) -> Option<TyCtxt<'tcx>> {
         Some(self.1)
     }
@@ -246,12 +276,21 @@ impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<[T]> {
 }
 
 impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
+    #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx.expect("missing TyCtxt in DecodeContext")
+        debug_assert!(self.tcx.is_some(), "missing TyCtxt in DecodeContext");
+        self.tcx.unwrap()
+    }
+
+    #[inline]
+    pub fn blob(&self) -> &'a MetadataBlob {
+        self.blob
     }
 
-    fn cdata(&self) -> CrateMetadataRef<'a> {
-        self.cdata.expect("missing CrateMetadata in DecodeContext")
+    #[inline]
+    pub fn cdata(&self) -> CrateMetadataRef<'a> {
+        debug_assert!(self.cdata.is_some(), "missing CrateMetadata in DecodeContext");
+        self.cdata.unwrap()
     }
 
     fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
@@ -276,6 +315,11 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
         self.lazy_state = LazyState::Previous(NonZeroUsize::new(position + min_size).unwrap());
         Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta))
     }
+
+    #[inline]
+    pub fn read_raw_bytes(&mut self, len: usize) -> &'a [u8] {
+        self.opaque.read_raw_bytes(len)
+    }
 }
 
 impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
@@ -586,11 +630,11 @@ implement_ty_decoder!(DecodeContext<'a, 'tcx>);
 
 impl MetadataBlob {
     crate fn new(metadata_ref: MetadataRef) -> MetadataBlob {
-        MetadataBlob(metadata_ref)
+        MetadataBlob(Lrc::new(metadata_ref))
     }
 
     crate fn is_compatible(&self) -> bool {
-        self.raw_bytes().starts_with(METADATA_HEADER)
+        self.blob().starts_with(METADATA_HEADER)
     }
 
     crate fn get_rustc_version(&self) -> String {
@@ -599,7 +643,7 @@ impl MetadataBlob {
     }
 
     crate fn get_root(&self) -> CrateRoot<'tcx> {
-        let slice = self.raw_bytes();
+        let slice = &self.blob()[..];
         let offset = METADATA_HEADER.len();
         let pos = (((slice[offset + 0] as u32) << 24)
             | ((slice[offset + 1] as u32) << 16)
@@ -1552,58 +1596,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .or_insert_with(|| self.root.tables.def_keys.get(self, index).unwrap().decode(self))
     }
 
-    /// Finds the corresponding `DefId` for the provided `DefPathHash`, if it exists.
-    /// This is used by incremental compilation to map a serialized `DefPathHash` to
-    /// its `DefId` in the current session.
-    /// Normally, only one 'main' crate will change between incremental compilation sessions:
-    /// all dependencies will be completely unchanged. In this case, we can avoid
-    /// decoding every `DefPathHash` in the crate, since the `DefIndex` from the previous
-    /// session will still be valid. If our 'guess' is wrong (the `DefIndex` no longer exists,
-    /// or has a different `DefPathHash`, then we need to decode all `DefPathHashes` to determine
-    /// the correct mapping).
-    fn def_path_hash_to_def_id(
-        &self,
-        krate: CrateNum,
-        index_guess: u32,
-        hash: DefPathHash,
-    ) -> Option<DefId> {
-        let def_index_guess = DefIndex::from_u32(index_guess);
-        let old_hash = self
-            .root
-            .tables
-            .def_path_hashes
-            .get(self, def_index_guess)
-            .map(|lazy| lazy.decode(self));
-
-        // Fast path: the definition and its index is unchanged from the
-        // previous compilation session. There is no need to decode anything
-        // else
-        if old_hash == Some(hash) {
-            return Some(DefId { krate, index: def_index_guess });
-        }
-
-        let is_proc_macro = self.is_proc_macro_crate();
-
-        // Slow path: We need to find out the new `DefIndex` of the provided
-        // `DefPathHash`, if its still exists. This requires decoding every `DefPathHash`
-        // stored in this crate.
-        let map = self.cdata.def_path_hash_map.get_or_init(|| {
-            let end_id = self.root.tables.def_path_hashes.size() as u32;
-            let mut map = UnhashMap::with_capacity_and_hasher(end_id as usize, Default::default());
-            for i in 0..end_id {
-                let def_index = DefIndex::from_u32(i);
-                // There may be gaps in the encoded table if we're decoding a proc-macro crate
-                if let Some(hash) = self.root.tables.def_path_hashes.get(self, def_index) {
-                    map.insert(hash.decode(self), def_index);
-                } else if !is_proc_macro {
-                    panic!("Missing def_path_hashes entry for {:?}", def_index);
-                }
-            }
-            map
-        });
-        map.get(&hash).map(|index| DefId { krate, index: *index })
-    }
-
     // Returns the path leading to the thing with this `id`.
     fn def_path(&self, id: DefIndex) -> DefPath {
         debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
@@ -1626,6 +1618,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.def_path_hash_unlocked(index, &mut def_path_hashes)
     }
 
+    #[inline]
+    fn def_path_hash_to_def_index(&self, hash: DefPathHash) -> DefIndex {
+        self.def_path_hash_map.def_path_hash_to_def_index(&hash)
+    }
+
     fn expn_hash_to_expn_id(&self, index_guess: u32, hash: ExpnHash) -> ExpnId {
         debug_assert_eq!(ExpnId::from_hash(hash), None);
         let index_guess = ExpnIndex::from_u32(index_guess);
@@ -1892,13 +1889,18 @@ impl CrateMetadata {
         let alloc_decoding_state =
             AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect());
         let dependencies = Lock::new(cnum_map.iter().cloned().collect());
+
+        // Pre-decode the DefPathHash->DefIndex table. This is a cheap operation
+        // that does not copy any data. It just does some data verification.
+        let def_path_hash_map = root.def_path_hash_map.decode(&blob);
+
         CrateMetadata {
             blob,
             root,
             trait_impls,
             raw_proc_macros,
             source_map_import_info: OnceCell::new(),
-            def_path_hash_map: Default::default(),
+            def_path_hash_map,
             expn_hash_map: Default::default(),
             alloc_decoding_state,
             cnum,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index a01eaf68f01..70952d388d5 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -498,6 +498,10 @@ impl CrateStore for CStore {
         self.get_crate_data(cnum).root.stable_crate_id
     }
 
+    fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum {
+        self.stable_crate_ids[&stable_crate_id]
+    }
+
     /// Returns the `DefKey` for a given `DefId`. This indicates the
     /// parent `DefId` as well as some idea of what kind of data the
     /// `DefId` refers to.
@@ -513,14 +517,9 @@ impl CrateStore for CStore {
         self.get_crate_data(def.krate).def_path_hash(def.index)
     }
 
-    // See `CrateMetadataRef::def_path_hash_to_def_id` for more details
-    fn def_path_hash_to_def_id(
-        &self,
-        cnum: CrateNum,
-        index_guess: u32,
-        hash: DefPathHash,
-    ) -> Option<DefId> {
-        self.get_crate_data(cnum).def_path_hash_to_def_id(cnum, index_guess, hash)
+    fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId {
+        let def_index = self.get_crate_data(cnum).def_path_hash_to_def_index(hash);
+        DefId { krate: cnum, index: def_index }
     }
 
     fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId {
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
new file mode 100644
index 00000000000..d6435bb649d
--- /dev/null
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -0,0 +1,58 @@
+use crate::rmeta::DecodeContext;
+use crate::rmeta::EncodeContext;
+use crate::rmeta::MetadataBlob;
+use rustc_data_structures::owning_ref::OwningRef;
+use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap};
+use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
+use rustc_span::def_id::{DefIndex, DefPathHash};
+
+crate enum DefPathHashMapRef<'tcx> {
+    OwnedFromMetadata(odht::HashTable<HashMapConfig, OwningRef<MetadataBlob, [u8]>>),
+    BorrowedFromTcx(&'tcx DefPathHashMap),
+}
+
+impl DefPathHashMapRef<'tcx> {
+    #[inline]
+    pub fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex {
+        match *self {
+            DefPathHashMapRef::OwnedFromMetadata(ref map) => map.get(def_path_hash).unwrap(),
+            DefPathHashMapRef::BorrowedFromTcx(_) => {
+                panic!("DefPathHashMap::BorrowedFromTcx variant only exists for serialization")
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> {
+    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        match *self {
+            DefPathHashMapRef::BorrowedFromTcx(def_path_hash_map) => {
+                let bytes = def_path_hash_map.raw_bytes();
+                e.emit_usize(bytes.len())?;
+                e.emit_raw_bytes(bytes)
+            }
+            DefPathHashMapRef::OwnedFromMetadata(_) => {
+                panic!("DefPathHashMap::OwnedFromMetadata variant only exists for deserialization")
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<DefPathHashMapRef<'static>, String> {
+        // Import TyDecoder so we can access the DecodeContext::position() method
+        use crate::rustc_middle::ty::codec::TyDecoder;
+
+        let len = d.read_usize()?;
+        let pos = d.position();
+        let o = OwningRef::new(d.blob().clone()).map(|x| &x[pos..pos + len]);
+
+        // Although we already have the data we need via the OwningRef, we still need
+        // to advance the DecodeContext's position so it's in a valid state after
+        // the method. We use read_raw_bytes() for that.
+        let _ = d.read_raw_bytes(len);
+
+        let inner = odht::HashTable::from_raw_bytes(o).map_err(|e| format!("{}", e))?;
+        Ok(DefPathHashMapRef::OwnedFromMetadata(inner))
+    }
+}
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index b0d22037f21..a50c4549d3d 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1,3 +1,4 @@
+use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
 use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
 use crate::rmeta::*;
 
@@ -472,6 +473,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
+    fn encode_def_path_hash_map(&mut self) -> Lazy<DefPathHashMapRef<'tcx>> {
+        self.lazy(DefPathHashMapRef::BorrowedFromTcx(
+            self.tcx.resolutions(()).definitions.def_path_hash_to_def_index_map(),
+        ))
+    }
+
     fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
         let source_map = self.tcx.sess.source_map();
         let all_source_files = source_map.files();
@@ -675,6 +682,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let (syntax_contexts, expn_data, expn_hashes) = self.encode_hygiene();
         let hygiene_bytes = self.position() - i;
 
+        i = self.position();
+        let def_path_hash_map = self.encode_def_path_hash_map();
+        let def_path_hash_map_bytes = self.position() - i;
+
         // Encode source_map. This needs to be done last,
         // since encoding `Span`s tells us which `SourceFiles` we actually
         // need to encode.
@@ -722,6 +733,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             syntax_contexts,
             expn_data,
             expn_hashes,
+            def_path_hash_map,
         });
 
         let total_bytes = self.position();
@@ -744,6 +756,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             eprintln!("            impl bytes: {}", impl_bytes);
             eprintln!("    exp. symbols bytes: {}", exported_symbols_bytes);
             eprintln!("  def-path table bytes: {}", def_path_table_bytes);
+            eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes);
             eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
             eprintln!("             mir bytes: {}", mir_bytes);
             eprintln!("            item bytes: {}", item_bytes);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 1f307f3fdee..eb2bd80f46e 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,4 +1,5 @@
 use decoder::Metadata;
+use def_path_hash_map::DefPathHashMapRef;
 use table::{Table, TableBuilder};
 
 use rustc_ast::{self as ast, MacroDef};
@@ -35,6 +36,7 @@ use encoder::EncodeContext;
 use rustc_span::hygiene::SyntaxContextData;
 
 mod decoder;
+mod def_path_hash_map;
 mod encoder;
 mod table;
 
@@ -231,6 +233,8 @@ crate struct CrateRoot<'tcx> {
     expn_data: ExpnDataTable,
     expn_hashes: ExpnHashTable,
 
+    def_path_hash_map: Lazy<DefPathHashMapRef<'tcx>>,
+
     source_map: Lazy<[rustc_span::SourceFile]>,
 
     compiler_builtins: bool,
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 62c0ce15845..4dfefda490b 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -199,7 +199,7 @@ where
         debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
 
         let start = self.position.get();
-        let bytes = &metadata.raw_bytes()[start..start + self.meta];
+        let bytes = &metadata.blob()[start..start + self.meta];
         <Option<T>>::maybe_read_from_bytes_at(bytes, i.index())?
     }
 
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 59db2c6636f..2dd43a4e852 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -11,7 +11,8 @@
 macro_rules! arena_types {
     ($macro:path, $tcx:lifetime) => (
         $macro!([
-            [] layouts: rustc_target::abi::Layout,
+            [] layout: rustc_target::abi::Layout,
+            [] fn_abi: rustc_target::abi::call::FnAbi<$tcx, rustc_middle::ty::Ty<$tcx>>,
             // AdtDef are interned and compared by address
             [] adt_def: rustc_middle::ty::AdtDef,
             [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<$tcx>>,
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 8476929eaec..e788dd4be85 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -336,7 +336,11 @@ impl DepNodeExt for DepNode {
     /// has been removed.
     fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
         if self.kind.can_reconstruct_query_key() {
-            tcx.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into()))
+            Some(
+                tcx.on_disk_cache
+                    .as_ref()?
+                    .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())),
+            )
         } else {
             None
         }
@@ -385,17 +389,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
     }
 
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
-        let hash = tcx.def_path_hash(*self);
-        // If this is a foreign `DefId`, store its current value
-        // in the incremental cache. When we decode the cache,
-        // we will use the old DefIndex as an initial guess for
-        // a lookup into the crate metadata.
-        if !self.is_local() {
-            if let Some(cache) = &tcx.on_disk_cache {
-                cache.store_foreign_def_id_hash(*self, hash);
-            }
-        }
-        hash.0
+        tcx.def_path_hash(*self).0
     }
 
     fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index aa61219ad78..35dc1631db3 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -92,12 +92,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
     type DepKind = DepKind;
     type StableHashingContext = StableHashingContext<'tcx>;
 
-    fn register_reused_dep_node(&self, dep_node: &DepNode) {
-        if let Some(cache) = self.on_disk_cache.as_ref() {
-            cache.register_reused_dep_node(*self, dep_node)
-        }
-    }
-
+    #[inline]
     fn create_stable_hashing_context(&self) -> Self::StableHashingContext {
         TyCtxt::create_stable_hashing_context(*self)
     }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 10714a4b706..0c2c653e92e 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,13 +1,13 @@
 use self::collector::NodeCollector;
 
-use crate::hir::{AttributeMap, IndexedHir, Owner};
+use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner};
 use crate::ty::TyCtxt;
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
@@ -19,6 +19,7 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
+use std::collections::VecDeque;
 
 pub mod blocks;
 mod collector;
@@ -206,11 +207,6 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> {
-        // FIXME(eddyb) support `find` on the crate root.
-        if local_def_id.to_def_id().index == CRATE_DEF_INDEX {
-            return Some(DefKind::Mod);
-        }
-
         let hir_id = self.local_def_id_to_hir_id(local_def_id);
         let def_kind = match self.find(hir_id)? {
             Node::Item(item) => match item.kind {
@@ -541,23 +537,55 @@ impl<'hir> Map<'hir> {
     {
         let module = self.tcx.hir_module_items(module);
 
-        for id in &module.items {
+        for id in module.items.iter() {
             visitor.visit_item(self.item(*id));
         }
 
-        for id in &module.trait_items {
+        for id in module.trait_items.iter() {
             visitor.visit_trait_item(self.trait_item(*id));
         }
 
-        for id in &module.impl_items {
+        for id in module.impl_items.iter() {
             visitor.visit_impl_item(self.impl_item(*id));
         }
 
-        for id in &module.foreign_items {
+        for id in module.foreign_items.iter() {
             visitor.visit_foreign_item(self.foreign_item(*id));
         }
     }
 
+    pub fn for_each_module(&self, f: impl Fn(LocalDefId)) {
+        let mut queue = VecDeque::new();
+        queue.push_back(CRATE_DEF_ID);
+
+        while let Some(id) = queue.pop_front() {
+            f(id);
+            let items = self.tcx.hir_module_items(id);
+            queue.extend(items.submodules.iter().copied())
+        }
+    }
+
+    #[cfg(not(parallel_compiler))]
+    #[inline]
+    pub fn par_for_each_module(&self, f: impl Fn(LocalDefId)) {
+        self.for_each_module(f)
+    }
+
+    #[cfg(parallel_compiler)]
+    pub fn par_for_each_module(&self, f: impl Fn(LocalDefId) + Sync) {
+        use rustc_data_structures::sync::{par_iter, ParallelIterator};
+        par_iter_submodules(self.tcx, CRATE_DEF_ID, &f);
+
+        fn par_iter_submodules<F>(tcx: TyCtxt<'_>, module: LocalDefId, f: &F)
+        where
+            F: Fn(LocalDefId) + Sync,
+        {
+            (*f)(module);
+            let items = tcx.hir_module_items(module);
+            par_iter(&items.submodules[..]).for_each(|&sm| par_iter_submodules(tcx, sm, f));
+        }
+    }
+
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
     /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
     pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> {
@@ -1118,3 +1146,69 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String {
         None => format!("unknown node{}", id_str),
     }
 }
+
+pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> ModuleItems {
+    let mut collector = ModuleCollector {
+        tcx,
+        submodules: Vec::default(),
+        items: Vec::default(),
+        trait_items: Vec::default(),
+        impl_items: Vec::default(),
+        foreign_items: Vec::default(),
+    };
+
+    let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id);
+    collector.visit_mod(hir_mod, span, hir_id);
+
+    let ModuleCollector { submodules, items, trait_items, impl_items, foreign_items, .. } =
+        collector;
+    return ModuleItems {
+        submodules: submodules.into_boxed_slice(),
+        items: items.into_boxed_slice(),
+        trait_items: trait_items.into_boxed_slice(),
+        impl_items: impl_items.into_boxed_slice(),
+        foreign_items: foreign_items.into_boxed_slice(),
+    };
+
+    struct ModuleCollector<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        submodules: Vec<LocalDefId>,
+        items: Vec<ItemId>,
+        trait_items: Vec<TraitItemId>,
+        impl_items: Vec<ImplItemId>,
+        foreign_items: Vec<ForeignItemId>,
+    }
+
+    impl<'hir> Visitor<'hir> for ModuleCollector<'hir> {
+        type Map = Map<'hir>;
+
+        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+            intravisit::NestedVisitorMap::All(self.tcx.hir())
+        }
+
+        fn visit_item(&mut self, item: &'hir Item<'hir>) {
+            self.items.push(item.item_id());
+            if let ItemKind::Mod(..) = item.kind {
+                // If this declares another module, do not recurse inside it.
+                self.submodules.push(item.def_id);
+            } else {
+                intravisit::walk_item(self, item)
+            }
+        }
+
+        fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
+            self.trait_items.push(item.trait_item_id());
+            intravisit::walk_trait_item(self, item)
+        }
+
+        fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
+            self.impl_items.push(item.impl_item_id());
+            intravisit::walk_impl_item(self, item)
+        }
+
+        fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
+            self.foreign_items.push(item.foreign_item_id());
+            intravisit::walk_foreign_item(self, item)
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index c8ea7454f0b..de4b75f9463 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -121,6 +121,17 @@ impl<'tcx> AttributeMap<'tcx> {
     }
 }
 
+/// Gather the LocalDefId for each item-like within a module, including items contained within
+/// bodies.  The Ids are in visitor order.  This is used to partition a pass between modules.
+#[derive(Debug, HashStable)]
+pub struct ModuleItems {
+    submodules: Box<[LocalDefId]>,
+    items: Box<[ItemId]>,
+    trait_items: Box<[TraitItemId]>,
+    impl_items: Box<[ImplItemId]>,
+    foreign_items: Box<[ForeignItemId]>,
+}
+
 impl<'tcx> TyCtxt<'tcx> {
     #[inline(always)]
     pub fn hir(self) -> map::Map<'tcx> {
@@ -140,7 +151,7 @@ pub fn provide(providers: &mut Providers) {
     providers.hir_crate = |tcx, ()| tcx.untracked_crate;
     providers.index_hir = map::index_hir;
     providers.crate_hash = map::crate_hash;
-    providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
+    providers.hir_module_items = map::hir_module_items;
     providers.hir_owner = |tcx, id| {
         let owner = tcx.index_hir(()).map[id].as_ref()?;
         let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 94267ec64c7..02f0294c8ad 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -33,6 +33,7 @@
 #![feature(discriminant_kind)]
 #![feature(exhaustive_patterns)]
 #![feature(if_let_guard)]
+#![feature(map_first_last)]
 #![feature(never_type)]
 #![feature(extern_types)]
 #![feature(new_uninit)]
diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs
index 8150e679295..81c44b27033 100644
--- a/compiler/rustc_middle/src/middle/cstore.rs
+++ b/compiler/rustc_middle/src/middle/cstore.rs
@@ -199,14 +199,10 @@ pub trait CrateStore: std::fmt::Debug {
     // incr.  comp. uses to identify a CrateNum.
     fn crate_name(&self, cnum: CrateNum) -> Symbol;
     fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId;
+    fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum;
 
     /// Fetch a DefId from a DefPathHash for a foreign crate.
-    fn def_path_hash_to_def_id(
-        &self,
-        cnum: CrateNum,
-        index_guess: u32,
-        hash: DefPathHash,
-    ) -> Option<DefId>;
+    fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId;
     fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId;
 
     // utility functions
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index e8d30034dc4..3e9c02ee268 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -992,6 +992,9 @@ pub enum LocalInfo<'tcx> {
     StaticRef { def_id: DefId, is_thread_local: bool },
     /// A temporary created that references the const with the given `DefId`
     ConstRef { def_id: DefId },
+    /// A temporary created during the creation of an aggregate
+    /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`)
+    AggregateTemp,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 567f65e83d9..b003a504691 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -332,17 +332,15 @@ pub enum ConstraintCategory {
     CopyBound,
     SizedBound,
     Assignment,
+    /// A constraint that came from a usage of a variable (e.g. in an ADT expression
+    /// like `Foo { field: my_val }`)
+    Usage,
     OpaqueType,
     ClosureUpvar(hir::HirId),
 
     /// A "boring" constraint (caused by the given location) is one that
     /// the user probably doesn't want to see described in diagnostics,
     /// because it is kind of an artifact of the type system setup.
-    /// Example: `x = Foo { field: y }` technically creates
-    /// intermediate regions representing the "type of `Foo { field: y
-    /// }`", and data flows from `y` into those variables, but they
-    /// are not very interesting. The assignment into `x` on the other
-    /// hand might be.
     Boring,
     // Boring and applicable everywhere.
     BoringNoLocation,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4296acce1ff..c13d7720e37 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -52,8 +52,8 @@ rustc_queries! {
     ///
     /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
     /// Avoid calling this query directly.
-    query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems {
-        eval_always
+    query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems {
+        storage(ArenaCacheSelector<'tcx>)
         desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
@@ -1128,6 +1128,27 @@ rustc_queries! {
         desc { "computing layout of `{}`", key.value }
     }
 
+    /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
+    ///
+    /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
+    /// instead, where the instance is an `InstanceDef::Virtual`.
+    query fn_abi_of_fn_ptr(
+        key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
+    ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
+        desc { "computing call ABI of `{}` function pointers", key.value.0 }
+    }
+
+    /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
+    /// direct calls to an `fn`.
+    ///
+    /// NB: that includes virtual calls, which are represented by "direct calls"
+    /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
+    query fn_abi_of_instance(
+        key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
+    ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
+        desc { "computing call ABI of `{}`", key.value.0 }
+    }
+
     query dylib_dependency_formats(_: CrateNum)
                                     -> &'tcx [(CrateNum, LinkagePreference)] {
         desc { "dylib dependency formats of crate" }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index b4ae56adf32..88a7722c9cc 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -349,7 +349,7 @@ pub enum ObligationCauseCode<'tcx> {
     WellFormed(Option<WellFormedLoc>),
 
     /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against.
-    MatchImpl(Lrc<ObligationCauseCode<'tcx>>, DefId),
+    MatchImpl(ObligationCause<'tcx>, DefId),
 }
 
 /// The 'location' at which we try to perform HIR-based wf checking.
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 1f5057d1da2..72b8d7cce71 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1,7 +1,7 @@
 //! Type context book-keeping.
 
 use crate::arena::Arena;
-use crate::dep_graph::{DepGraph, DepNode};
+use crate::dep_graph::DepGraph;
 use crate::hir::place::Place as HirPlace;
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
@@ -83,23 +83,7 @@ pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
     /// session, if it still exists. This is used during incremental compilation to
     /// turn a deserialized `DefPathHash` into its current `DefId`.
-    fn def_path_hash_to_def_id(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        def_path_hash: DefPathHash,
-    ) -> Option<DefId>;
-
-    /// If the given `dep_node`'s hash still exists in the current compilation,
-    /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it.
-    ///
-    /// Normally, `store_foreign_def_id_hash` can be called directly by
-    /// the dependency graph when we construct a `DepNode`. However,
-    /// when we re-use a deserialized `DepNode` from the previous compilation
-    /// session, we only have the `DefPathHash` available. This method is used
-    /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written
-    /// out for usage in the next compilation session.
-    fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode);
-    fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash);
+    fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, def_path_hash: DefPathHash) -> DefId;
 
     fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>);
 
@@ -118,8 +102,8 @@ pub struct CtxtInterners<'tcx> {
     /// The arena that types, regions, etc. are allocated from.
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
 
-    /// Specifically use a speedy hash algorithm for these hash sets, since
-    /// they're accessed quite often.
+    // Specifically use a speedy hash algorithm for these hash sets, since
+    // they're accessed quite often.
     type_: InternedSet<'tcx, TyS<'tcx>>,
     type_list: InternedSet<'tcx, List<Ty<'tcx>>>,
     substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
@@ -132,9 +116,9 @@ pub struct CtxtInterners<'tcx> {
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
     const_: InternedSet<'tcx, Const<'tcx>>,
-    /// Const allocations.
-    allocation: InternedSet<'tcx, Allocation>,
+    const_allocation: InternedSet<'tcx, Allocation>,
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
+    layout: InternedSet<'tcx, Layout>,
 }
 
 impl<'tcx> CtxtInterners<'tcx> {
@@ -152,8 +136,9 @@ impl<'tcx> CtxtInterners<'tcx> {
             projs: Default::default(),
             place_elems: Default::default(),
             const_: Default::default(),
-            allocation: Default::default(),
+            const_allocation: Default::default(),
             bound_variable_kinds: Default::default(),
+            layout: Default::default(),
         }
     }
 
@@ -1062,10 +1047,9 @@ pub struct GlobalCtxt<'tcx> {
     /// Stores memory for globals (statics/consts).
     pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
 
-    layout_interner: ShardedHashMap<&'tcx Layout, ()>,
-
     output_filenames: Arc<OutputFilenames>,
 
+    // FIXME(eddyb) this doesn't belong here and should be using a query.
     pub(super) vtables_cache:
         Lock<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), AllocId>>,
 }
@@ -1107,13 +1091,6 @@ impl<'tcx> TyCtxt<'tcx> {
         self.arena.alloc(ty::AdtDef::new(self, did, kind, variants, repr))
     }
 
-    pub fn intern_const_alloc(self, alloc: Allocation) -> &'tcx Allocation {
-        self.interners
-            .allocation
-            .intern(alloc, |alloc| Interned(self.interners.arena.alloc(alloc)))
-            .0
-    }
-
     /// Allocates a read-only byte or string literal for `mir::interpret`.
     pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
         // Create an allocation that just contains these bytes.
@@ -1122,20 +1099,19 @@ impl<'tcx> TyCtxt<'tcx> {
         self.create_memory_alloc(alloc)
     }
 
+    // FIXME(eddyb) move to `direct_interners!`.
     pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability {
         self.stability_interner.intern(stab, |stab| self.arena.alloc(stab))
     }
 
+    // FIXME(eddyb) move to `direct_interners!`.
     pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
         self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab))
     }
 
-    pub fn intern_layout(self, layout: Layout) -> &'tcx Layout {
-        self.layout_interner.intern(layout, |layout| self.arena.alloc(layout))
-    }
-
     /// Returns a range of the start/end indices specified with the
     /// `rustc_layout_scalar_valid_range` attribute.
+    // FIXME(eddyb) this is an awkward spot for this method, maybe move it?
     pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
         let attrs = self.get_attrs(def_id);
         let get = |name| {
@@ -1210,7 +1186,6 @@ impl<'tcx> TyCtxt<'tcx> {
             evaluation_cache: Default::default(),
             crate_name: Symbol::intern(crate_name),
             data_layout,
-            layout_interner: Default::default(),
             stability_interner: Default::default(),
             const_stability_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
@@ -1316,6 +1291,17 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    /// Maps a StableCrateId to the corresponding CrateNum. This method assumes
+    /// that the crate in question has already been loaded by the CrateStore.
+    #[inline]
+    pub fn stable_crate_id_to_crate_num(self, stable_crate_id: StableCrateId) -> CrateNum {
+        if stable_crate_id == self.sess.local_stable_crate_id() {
+            LOCAL_CRATE
+        } else {
+            self.untracked_resolutions.cstore.stable_crate_id_to_crate_num(stable_crate_id)
+        }
+    }
+
     pub fn def_path_debug_str(self, def_id: DefId) -> String {
         // We are explicitly not going through queries here in order to get
         // crate name and stable crate id since this code is called from debug!()
@@ -1670,7 +1656,7 @@ macro_rules! nop_list_lift {
 nop_lift! {type_; Ty<'a> => Ty<'tcx>}
 nop_lift! {region; Region<'a> => Region<'tcx>}
 nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
-nop_lift! {allocation; &'a Allocation => &'tcx Allocation}
+nop_lift! {const_allocation; &'a Allocation => &'tcx Allocation}
 nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>}
 
 nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
@@ -1962,8 +1948,12 @@ impl<'tcx> TyCtxt<'tcx> {
                     "Const Stability interner: #{}",
                     self.0.const_stability_interner.len()
                 )?;
-                writeln!(fmt, "Allocation interner: #{}", self.0.interners.allocation.len())?;
-                writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?;
+                writeln!(
+                    fmt,
+                    "Const Allocation interner: #{}",
+                    self.0.interners.const_allocation.len()
+                )?;
+                writeln!(fmt, "Layout interner: #{}", self.0.interners.layout.len())?;
 
                 Ok(())
             }
@@ -2051,38 +2041,6 @@ impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
     }
 }
 
-impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
-    fn borrow(&self) -> &RegionKind {
-        &self.0
-    }
-}
-
-impl<'tcx> Borrow<Const<'tcx>> for Interned<'tcx, Const<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a Const<'tcx> {
-        &self.0
-    }
-}
-
-impl<'tcx> Borrow<Allocation> for Interned<'tcx, Allocation> {
-    fn borrow<'a>(&'a self) -> &'a Allocation {
-        &self.0
-    }
-}
-
-impl<'tcx> PartialEq for Interned<'tcx, Allocation> {
-    fn eq(&self, other: &Self) -> bool {
-        self.0 == other.0
-    }
-}
-
-impl<'tcx> Eq for Interned<'tcx, Allocation> {}
-
-impl<'tcx> Hash for Interned<'tcx, Allocation> {
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        self.0.hash(s)
-    }
-}
-
 macro_rules! direct_interners {
     ($($name:ident: $method:ident($ty:ty),)+) => {
         $(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
@@ -2099,9 +2057,15 @@ macro_rules! direct_interners {
             }
         }
 
+        impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
+            fn borrow<'a>(&'a self) -> &'a $ty {
+                &self.0
+            }
+        }
+
         impl<'tcx> TyCtxt<'tcx> {
             pub fn $method(self, v: $ty) -> &'tcx $ty {
-                self.interners.$name.intern_ref(&v, || {
+                self.interners.$name.intern(v, |v| {
                     Interned(self.interners.arena.alloc(v))
                 }).0
             }
@@ -2112,6 +2076,8 @@ macro_rules! direct_interners {
 direct_interners! {
     region: mk_region(RegionKind),
     const_: mk_const(Const<'tcx>),
+    const_allocation: intern_const_alloc(Allocation),
+    layout: intern_layout(Layout),
 }
 
 macro_rules! slice_interners {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 1bea1cbc3b9..cfbbec374a1 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,4 +1,3 @@
-use crate::ich::StableHashingContext;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
 use crate::ty::subst::Subst;
@@ -6,7 +5,6 @@ use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
 
 use rustc_ast as ast;
 use rustc_attr as attr;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::BitSet;
@@ -18,15 +16,19 @@ use rustc_target::abi::call::{
     ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
 };
 use rustc_target::abi::*;
-use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy};
+use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
 
 use std::cmp;
 use std::fmt;
 use std::iter;
-use std::mem;
 use std::num::NonZeroUsize;
 use std::ops::Bound;
 
+pub fn provide(providers: &mut ty::query::Providers) {
+    *providers =
+        ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
+}
+
 pub trait IntegerExt {
     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
     fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer;
@@ -191,7 +193,7 @@ pub const FAT_PTR_EXTRA: usize = 1;
 /// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
 pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
 
-#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
 pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
     SizeOverflow(Ty<'tcx>),
@@ -248,10 +250,6 @@ fn layout_of<'tcx>(
     })
 }
 
-pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { layout_of, ..*providers };
-}
-
 pub struct LayoutCx<'tcx, C> {
     pub tcx: C,
     pub param_env: ty::ParamEnv<'tcx>,
@@ -2015,6 +2013,12 @@ impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
     }
 }
 
+impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.sess.target
+    }
+}
+
 impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
     #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
@@ -2029,6 +2033,12 @@ impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
     }
 }
 
+impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.sess.target
+    }
+}
+
 impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
     #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
@@ -2048,6 +2058,12 @@ impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
     }
 }
 
+impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
+    fn target_spec(&self) -> &Target {
+        self.tcx.target_spec()
+    }
+}
+
 impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx.tcx()
@@ -2130,10 +2146,10 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
     #[inline]
     fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
         let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
+        let tcx = self.tcx().at(span);
+
         MaybeResult::from(
-            self.tcx()
-                .at(span)
-                .layout_of(self.param_env().and(ty))
+            tcx.layout_of(self.param_env().and(ty))
                 .map_err(|err| self.handle_layout_err(err, span, ty)),
         )
     }
@@ -2519,24 +2535,12 @@ where
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for LayoutError<'tcx> {
-    #[inline]
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        use crate::ty::layout::LayoutError::*;
-        mem::discriminant(self).hash_stable(hcx, hasher);
-
-        match *self {
-            Unknown(t) | SizeOverflow(t) => t.hash_stable(hcx, hasher),
-        }
-    }
-}
-
 impl<'tcx> ty::Instance<'tcx> {
     // NOTE(eddyb) this is private to avoid using it from outside of
-    // `FnAbi::of_instance` - any other uses are either too high-level
+    // `fn_abi_of_instance` - any other uses are either too high-level
     // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
     // or should go through `FnAbi` instead, to avoid losing any
-    // adjustments `FnAbi::of_instance` might be performing.
+    // adjustments `fn_abi_of_instance` might be performing.
     fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
         // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function.
         let ty = self.ty(tcx, ty::ParamEnv::reveal_all());
@@ -2633,34 +2637,6 @@ impl<'tcx> ty::Instance<'tcx> {
     }
 }
 
-pub trait FnAbiExt<'tcx, C>
-where
-    C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
-{
-    /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
-    ///
-    /// NB: this doesn't handle virtual calls - those should use `FnAbi::of_instance`
-    /// instead, where the instance is an `InstanceDef::Virtual`.
-    fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
-
-    /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
-    /// direct calls to an `fn`.
-    ///
-    /// NB: that includes virtual calls, which are represented by "direct calls"
-    /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
-    fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
-
-    fn new_internal(
-        cx: &C,
-        sig: ty::PolyFnSig<'tcx>,
-        extra_args: &[Ty<'tcx>],
-        caller_location: Option<Ty<'tcx>>,
-        codegen_fn_attr_flags: CodegenFnAttrFlags,
-        make_self_ptr_thin: bool,
-    ) -> Self;
-    fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
-}
-
 /// Calculates whether a function's ABI can unwind or not.
 ///
 /// This takes two primary parameters:
@@ -2816,48 +2792,175 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
     }
 }
 
-impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
-where
-    C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
-{
-    fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
-        call::FnAbi::new_internal(cx, sig, extra_args, None, CodegenFnAttrFlags::empty(), false)
+/// Error produced by attempting to compute or adjust a `FnAbi`.
+#[derive(Clone, Debug, HashStable)]
+pub enum FnAbiError<'tcx> {
+    /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
+    Layout(LayoutError<'tcx>),
+
+    /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
+    AdjustForForeignAbi(call::AdjustForForeignAbiError),
+}
+
+impl From<LayoutError<'tcx>> for FnAbiError<'tcx> {
+    fn from(err: LayoutError<'tcx>) -> Self {
+        Self::Layout(err)
     }
+}
 
-    fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
-        let sig = instance.fn_sig_for_fn_abi(cx.tcx());
+impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
+    fn from(err: call::AdjustForForeignAbiError) -> Self {
+        Self::AdjustForForeignAbi(err)
+    }
+}
 
-        let caller_location = if instance.def.requires_caller_location(cx.tcx()) {
-            Some(cx.tcx().caller_location_ty())
-        } else {
-            None
-        };
+impl<'tcx> fmt::Display for FnAbiError<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Layout(err) => err.fmt(f),
+            Self::AdjustForForeignAbi(err) => err.fmt(f),
+        }
+    }
+}
+
+// FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
+// just for error handling.
+#[derive(Debug)]
+pub enum FnAbiRequest<'tcx> {
+    OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
+    OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
+}
+
+/// Trait for contexts that want to be able to compute `FnAbi`s.
+/// This automatically gives access to `FnAbiOf`, through a blanket `impl`.
+pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
+    /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be
+    /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`).
+    type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>;
 
-        let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
+    /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a
+    /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
+    ///
+    /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
+    /// but this hook allows e.g. codegen to return only `&FnAbi` from its
+    /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
+    /// (and any `FnAbiError`s are turned into fatal errors or ICEs).
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
+}
+
+/// Blanket extension trait for contexts that can compute `FnAbi`s.
+pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
+    /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
+    ///
+    /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
+    /// instead, where the instance is an `InstanceDef::Virtual`.
+    #[inline]
+    fn fn_abi_of_fn_ptr(
+        &self,
+        sig: ty::PolyFnSig<'tcx>,
+        extra_args: &'tcx ty::List<Ty<'tcx>>,
+    ) -> Self::FnAbiOfResult {
+        // FIXME(eddyb) get a better `span` here.
+        let span = self.layout_tcx_at_span();
+        let tcx = self.tcx().at(span);
+
+        MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
+            |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
+        ))
+    }
 
-        call::FnAbi::new_internal(
-            cx,
-            sig,
-            extra_args,
-            caller_location,
-            attrs,
-            matches!(instance.def, ty::InstanceDef::Virtual(..)),
+    /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
+    /// direct calls to an `fn`.
+    ///
+    /// NB: that includes virtual calls, which are represented by "direct calls"
+    /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
+    #[inline]
+    fn fn_abi_of_instance(
+        &self,
+        instance: ty::Instance<'tcx>,
+        extra_args: &'tcx ty::List<Ty<'tcx>>,
+    ) -> Self::FnAbiOfResult {
+        // FIXME(eddyb) get a better `span` here.
+        let span = self.layout_tcx_at_span();
+        let tcx = self.tcx().at(span);
+
+        MaybeResult::from(
+            tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
+                // HACK(eddyb) at least for definitions of/calls to `Instance`s,
+                // we can get some kind of span even if one wasn't provided.
+                // However, we don't do this early in order to avoid calling
+                // `def_span` unconditionally (which may have a perf penalty).
+                let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
+                self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
+            }),
         )
     }
+}
 
-    fn new_internal(
-        cx: &C,
+impl<C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
+
+fn fn_abi_of_fn_ptr<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+    let (param_env, (sig, extra_args)) = query.into_parts();
+
+    LayoutCx { tcx, param_env }.fn_abi_new_uncached(
+        sig,
+        extra_args,
+        None,
+        CodegenFnAttrFlags::empty(),
+        false,
+    )
+}
+
+fn fn_abi_of_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+    let (param_env, (instance, extra_args)) = query.into_parts();
+
+    let sig = instance.fn_sig_for_fn_abi(tcx);
+
+    let caller_location = if instance.def.requires_caller_location(tcx) {
+        Some(tcx.caller_location_ty())
+    } else {
+        None
+    };
+
+    let attrs = tcx.codegen_fn_attrs(instance.def_id()).flags;
+
+    LayoutCx { tcx, param_env }.fn_abi_new_uncached(
+        sig,
+        extra_args,
+        caller_location,
+        attrs,
+        matches!(instance.def, ty::InstanceDef::Virtual(..)),
+    )
+}
+
+impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
+    // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
+    // arguments of this method, into a separate `struct`.
+    fn fn_abi_new_uncached(
+        &self,
         sig: ty::PolyFnSig<'tcx>,
         extra_args: &[Ty<'tcx>],
         caller_location: Option<Ty<'tcx>>,
         codegen_fn_attr_flags: CodegenFnAttrFlags,
+        // FIXME(eddyb) replace this with something typed, like an `enum`.
         force_thin_self_ptr: bool,
-    ) -> Self {
-        debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
+    ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+        debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args);
 
-        let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+        let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig);
 
-        let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
+        let conv = conv_from_spec_abi(self.tcx(), sig.abi);
 
         let mut inputs = sig.inputs();
         let extra_args = if sig.abi == RustCall {
@@ -2884,7 +2987,7 @@ where
             extra_args.to_vec()
         };
 
-        let target = &cx.tcx().sess.target;
+        let target = &self.tcx.sess.target;
         let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl");
         let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
         let linux_s390x_gnu_like =
@@ -2917,7 +3020,7 @@ where
                 attrs.set(ArgAttribute::NonNull);
             }
 
-            if let Some(pointee) = layout.pointee_info_at(cx, offset) {
+            if let Some(pointee) = layout.pointee_info_at(self, offset) {
                 if let Some(kind) = pointee.safe {
                     attrs.pointee_align = Some(pointee.align);
 
@@ -2961,20 +3064,20 @@ where
             }
         };
 
-        let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
+        let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
             let is_return = arg_idx.is_none();
 
-            let layout = cx.layout_of(ty);
+            let layout = self.layout_of(ty)?;
             let layout = if force_thin_self_ptr && arg_idx == Some(0) {
                 // Don't pass the vtable, it's not an argument of the virtual fn.
                 // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
                 // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
-                make_thin_self_ptr(cx, layout)
+                make_thin_self_ptr(self, layout)
             } else {
                 layout
             };
 
-            let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| {
+            let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| {
                 let mut attrs = ArgAttributes::new();
                 adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return);
                 attrs
@@ -2995,11 +3098,11 @@ where
                 }
             }
 
-            arg
+            Ok(arg)
         };
 
         let mut fn_abi = FnAbi {
-            ret: arg_of(sig.output(), None),
+            ret: arg_of(sig.output(), None)?,
             args: inputs
                 .iter()
                 .cloned()
@@ -3007,20 +3110,24 @@ where
                 .chain(caller_location)
                 .enumerate()
                 .map(|(i, ty)| arg_of(ty, Some(i)))
-                .collect(),
+                .collect::<Result<_, _>>()?,
             c_variadic: sig.c_variadic,
             fixed_count: inputs.len(),
             conv,
-            can_unwind: fn_can_unwind(cx.tcx(), codegen_fn_attr_flags, sig.abi),
+            can_unwind: fn_can_unwind(self.tcx(), codegen_fn_attr_flags, sig.abi),
         };
-        fn_abi.adjust_for_abi(cx, sig.abi);
-        debug!("FnAbi::new_internal = {:?}", fn_abi);
-        fn_abi
+        self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?;
+        debug!("fn_abi_new_uncached = {:?}", fn_abi);
+        Ok(self.tcx.arena.alloc(fn_abi))
     }
 
-    fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) {
+    fn fn_abi_adjust_for_abi(
+        &self,
+        fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
+        abi: SpecAbi,
+    ) -> Result<(), FnAbiError<'tcx>> {
         if abi == SpecAbi::Unadjusted {
-            return;
+            return Ok(());
         }
 
         if abi == SpecAbi::Rust
@@ -3057,7 +3164,7 @@ where
                     // anyway, we control all calls to it in libstd.
                     Abi::Vector { .. }
                         if abi != SpecAbi::PlatformIntrinsic
-                            && cx.tcx().sess.target.simd_types_indirect =>
+                            && self.tcx.sess.target.simd_types_indirect =>
                     {
                         arg.make_indirect();
                         return;
@@ -3068,7 +3175,7 @@ where
 
                 // Pass and return structures up to 2 pointers in size by value, matching `ScalarPair`.
                 // LLVM will usually pass these in 2 registers, which is more efficient than by-ref.
-                let max_by_val_size = Pointer.size(cx) * 2;
+                let max_by_val_size = Pointer.size(self) * 2;
                 let size = arg.layout.size;
 
                 if arg.layout.is_unsized() || size > max_by_val_size {
@@ -3080,16 +3187,15 @@ where
                     arg.cast_to(Reg { kind: RegKind::Integer, size });
                 }
             };
-            fixup(&mut self.ret);
-            for arg in &mut self.args {
+            fixup(&mut fn_abi.ret);
+            for arg in &mut fn_abi.args {
                 fixup(arg);
             }
-            return;
+        } else {
+            fn_abi.adjust_for_foreign_abi(self, abi)?;
         }
 
-        if let Err(msg) = self.adjust_for_cabi(cx, abi) {
-            cx.tcx().sess.fatal(&msg);
-        }
+        Ok(())
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 15a8888ee65..154b26464a8 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -48,6 +48,7 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
 use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Limits;
+use rustc_target::abi;
 use rustc_target::spec::PanicStrategy;
 
 use rustc_ast as ast;
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index bbb2f89fda9..b627b0763a2 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -20,7 +20,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let local_scope = self.local_scope();
-        self.as_operand(block, Some(local_scope), expr)
+        self.as_operand(block, Some(local_scope), expr, None)
     }
 
     /// Returns an operand suitable for use until the end of the current scope expression and
@@ -85,6 +85,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// temporary `tmp = x`, so that we capture the value of `x` at
     /// this time.
     ///
+    /// If we end up needing to create a temporary, then we will use
+    /// `local_info` as its `LocalInfo`, unless `as_temporary`
+    /// has already assigned it a non-`None` `LocalInfo`.
+    /// Normally, you should use `None` for `local_info`
+    ///
     /// The operand is known to be live until the end of `scope`.
     ///
     /// Like `as_local_call_operand`, except that the argument will
@@ -94,15 +99,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         mut block: BasicBlock,
         scope: Option<region::Scope>,
         expr: &Expr<'tcx>,
+        local_info: Option<Box<LocalInfo<'tcx>>>,
     ) -> BlockAnd<Operand<'tcx>> {
-        debug!("as_operand(block={:?}, expr={:?})", block, expr);
+        debug!("as_operand(block={:?}, expr={:?} local_info={:?})", block, expr, local_info);
         let this = self;
 
         if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
             return this.in_scope(region_scope, lint_level, |this| {
-                this.as_operand(block, scope, &this.thir[value])
+                this.as_operand(block, scope, &this.thir[value], local_info)
             });
         }
 
@@ -115,6 +121,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             Category::Place | Category::Rvalue(..) => {
                 let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
+                if this.local_decls[operand].local_info.is_none() {
+                    this.local_decls[operand].local_info = local_info;
+                }
                 block.and(Operand::Move(Place::from(operand)))
             }
         }
@@ -167,6 +176,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
-        this.as_operand(block, scope, expr)
+        this.as_operand(block, scope, expr, None)
     }
 }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index be0d5d2f1b2..4b40faaf195 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -52,16 +52,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             ExprKind::Repeat { value, count } => {
                 let value_operand =
-                    unpack!(block = this.as_operand(block, scope, &this.thir[value]));
+                    unpack!(block = this.as_operand(block, scope, &this.thir[value], None));
                 block.and(Rvalue::Repeat(value_operand, count))
             }
             ExprKind::Binary { op, lhs, rhs } => {
-                let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs]));
-                let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs]));
+                let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs], None));
+                let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs], None));
                 this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
             }
             ExprKind::Unary { op, arg } => {
-                let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg]));
+                let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg], None));
                 // Check for -MIN on signed integers
                 if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
                     let bool_ty = this.tcx.types.bool;
@@ -116,11 +116,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(Rvalue::Use(Operand::Move(Place::from(result))))
             }
             ExprKind::Cast { source } => {
-                let source = unpack!(block = this.as_operand(block, scope, &this.thir[source]));
+                let source =
+                    unpack!(block = this.as_operand(block, scope, &this.thir[source], None));
                 block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
             }
             ExprKind::Pointer { cast, source } => {
-                let source = unpack!(block = this.as_operand(block, scope, &this.thir[source]));
+                let source =
+                    unpack!(block = this.as_operand(block, scope, &this.thir[source], None));
                 block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
             }
             ExprKind::Array { ref fields } => {
@@ -155,7 +157,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let fields: Vec<_> = fields
                     .into_iter()
                     .copied()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
+                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f], None)))
                     .collect();
 
                 block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(el_ty)), fields))
@@ -166,7 +168,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let fields: Vec<_> = fields
                     .into_iter()
                     .copied()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
+                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f], None)))
                     .collect();
 
                 block.and(Rvalue::Aggregate(Box::new(AggregateKind::Tuple), fields))
@@ -242,7 +244,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                             &this.thir[arg],
                                         )
                                     ),
-                                    _ => unpack!(block = this.as_operand(block, scope, upvar)),
+                                    _ => {
+                                        unpack!(block = this.as_operand(block, scope, upvar, None))
+                                    }
                                 }
                             }
                         }
@@ -304,7 +308,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     Category::of(&expr.kind),
                     Some(Category::Rvalue(RvalueFunc::AsRvalue))
                 ));
-                let operand = unpack!(block = this.as_operand(block, scope, expr));
+                let operand = unpack!(block = this.as_operand(block, scope, expr, None));
                 block.and(Rvalue::Use(operand))
             }
         }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index e30e758e637..1803a18441c 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -326,10 +326,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let fields_map: FxHashMap<_, _> = fields
                     .into_iter()
                     .map(|f| {
+                        let local_info = Box::new(LocalInfo::AggregateTemp);
                         (
                             f.name,
                             unpack!(
-                                block = this.as_operand(block, Some(scope), &this.thir[f.expr])
+                                block = this.as_operand(
+                                    block,
+                                    Some(scope),
+                                    &this.thir[f.expr],
+                                    Some(local_info)
+                                )
                             ),
                         )
                     })
@@ -508,7 +514,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             ExprKind::Yield { value } => {
                 let scope = this.local_scope();
-                let value = unpack!(block = this.as_operand(block, Some(scope), &this.thir[value]));
+                let value =
+                    unpack!(block = this.as_operand(block, Some(scope), &this.thir[value], None));
                 let resume = this.cfg.start_new_block();
                 this.cfg.terminate(
                     block,
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index e3cfd1d0afc..d6cd505cbb5 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -95,8 +95,6 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
     pub fn simplify(mut self) {
         self.strip_nops();
 
-        let mut start = START_BLOCK;
-
         // Vec of the blocks that should be merged. We store the indices here, instead of the
         // statements itself to avoid moving the (relatively) large statements twice.
         // We do not push the statements directly into the target block (`bb`) as that is slower
@@ -105,8 +103,6 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
         loop {
             let mut changed = false;
 
-            self.collapse_goto_chain(&mut start, &mut changed);
-
             for bb in self.basic_blocks.indices() {
                 if self.pred_count[bb] == 0 {
                     continue;
@@ -149,27 +145,6 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
                 break;
             }
         }
-
-        if start != START_BLOCK {
-            debug_assert!(self.pred_count[START_BLOCK] == 0);
-            self.basic_blocks.swap(START_BLOCK, start);
-            self.pred_count.swap(START_BLOCK, start);
-
-            // pred_count == 1 if the start block has no predecessor _blocks_.
-            if self.pred_count[START_BLOCK] > 1 {
-                for (bb, data) in self.basic_blocks.iter_enumerated_mut() {
-                    if self.pred_count[bb] == 0 {
-                        continue;
-                    }
-
-                    for target in data.terminator_mut().successors_mut() {
-                        if *target == start {
-                            *target = START_BLOCK;
-                        }
-                    }
-                }
-            }
-        }
     }
 
     /// This function will return `None` if
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 3c55a4b0a8f..0f768b7819b 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -30,7 +30,7 @@ pub fn provide(providers: &mut Providers) {
 /// Determine which generic parameters are used by the function/method/closure represented by
 /// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty`
 /// indicates all parameters are used).
-#[instrument(skip(tcx))]
+#[instrument(level = "debug", skip(tcx))]
 fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
     if !tcx.sess.opts.debugging_opts.polymorphize {
         // If polymorphization disabled, then all parameters are used.
@@ -100,7 +100,7 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
 /// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
 /// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
 /// be `true` if the item that `unused_generic_params` was invoked on is a closure.
-#[instrument(skip(tcx, def_id, generics, unused_parameters))]
+#[instrument(level = "debug", skip(tcx, def_id, generics, unused_parameters))]
 fn mark_used_by_default_parameters<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
@@ -158,7 +158,7 @@ fn mark_used_by_default_parameters<'tcx>(
 
 /// Search the predicates on used generic parameters for any unused generic parameters, and mark
 /// those as used.
-#[instrument(skip(tcx, def_id))]
+#[instrument(level = "debug", skip(tcx, def_id))]
 fn mark_used_by_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
@@ -196,7 +196,7 @@ fn mark_used_by_predicates<'tcx>(
 
 /// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
 /// parameter which was unused.
-#[instrument(skip(tcx, generics))]
+#[instrument(level = "debug", skip(tcx, generics))]
 fn emit_unused_generic_params_error<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
@@ -241,7 +241,7 @@ struct MarkUsedGenericParams<'a, 'tcx> {
 impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
     /// Invoke `unused_generic_params` on a body contained within the current item (e.g.
     /// a closure, generator or constant).
-    #[instrument(skip(self, def_id, substs))]
+    #[instrument(level = "debug", skip(self, def_id, substs))]
     fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) {
         let unused = self.tcx.unused_generic_params(def_id);
         debug!(?self.unused_parameters, ?unused);
@@ -256,7 +256,7 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
-    #[instrument(skip(self, local))]
+    #[instrument(level = "debug", skip(self, local))]
     fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
         if local == Local::from_usize(1) {
             let def_kind = self.tcx.def_kind(self.def_id);
@@ -286,7 +286,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
     fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
         Some(self.tcx)
     }
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !c.potentially_has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
@@ -319,7 +319,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !ty.potentially_has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
@@ -361,7 +361,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> {
         Some(self.tcx)
     }
 
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !c.potentially_has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
@@ -379,7 +379,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !ty.potentially_has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 4fccfc287fd..708df5e46d4 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1334,30 +1334,25 @@ impl<'a> Parser<'a> {
     pub(super) fn recover_parens_around_for_head(
         &mut self,
         pat: P<Pat>,
-        expr: &Expr,
         begin_paren: Option<Span>,
     ) -> P<Pat> {
         match (&self.token.kind, begin_paren) {
             (token::CloseDelim(token::Paren), Some(begin_par_sp)) => {
                 self.bump();
 
-                let pat_str = self
-                    // Remove the `(` from the span of the pattern:
-                    .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap())
-                    .unwrap_or_else(|_| pprust::pat_to_string(&pat));
-
-                self.struct_span_err(self.prev_token.span, "unexpected closing `)`")
-                    .span_label(begin_par_sp, "opening `(`")
-                    .span_suggestion(
-                        begin_par_sp.to(self.prev_token.span),
-                        "remove parenthesis in `for` loop",
-                        format!("{} in {}", pat_str, pprust::expr_to_string(&expr)),
-                        // With e.g. `for (x) in y)` this would replace `(x) in y)`
-                        // with `x) in y)` which is syntactically invalid.
-                        // However, this is prevented before we get here.
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                self.struct_span_err(
+                    MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]),
+                    "unexpected parenthesis surrounding `for` loop head",
+                )
+                .multipart_suggestion(
+                    "remove parenthesis in `for` loop",
+                    vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())],
+                    // With e.g. `for (x) in y)` this would replace `(x) in y)`
+                    // with `x) in y)` which is syntactically invalid.
+                    // However, this is prevented before we get here.
+                    Applicability::MachineApplicable,
+                )
+                .emit();
 
                 // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
                 pat.and_then(|pat| match pat.kind {
@@ -1955,7 +1950,19 @@ impl<'a> Parser<'a> {
         }
         match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
             Ok(expr) => {
-                if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() {
+                // Find a mistake like `MyTrait<Assoc == S::Assoc>`.
+                if token::EqEq == snapshot.token.kind {
+                    err.span_suggestion(
+                        snapshot.token.span,
+                        "if you meant to use an associated type binding, replace `==` with `=`",
+                        "=".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                    let value = self.mk_expr_err(start.to(expr.span));
+                    err.emit();
+                    return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
+                } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg()
+                {
                     // Avoid the following output by checking that we consumed a full const arg:
                     // help: expressions must be enclosed in braces to be used as const generic
                     //       arguments
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 737f1d9cbb1..d8f9fc9179e 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2042,7 +2042,7 @@ impl<'a> Parser<'a> {
         self.check_for_for_in_in_typo(self.prev_token.span);
         let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
 
-        let pat = self.recover_parens_around_for_head(pat, &expr, begin_paren);
+        let pat = self.recover_parens_around_for_head(pat, begin_paren);
 
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 18f61c6e1c1..eff1096c855 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
+use rustc_data_structures::sync::Lock;
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::intravisit;
@@ -18,9 +18,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     let errors = Lock::new(Vec::new());
     let hir_map = tcx.hir();
 
-    par_iter(&hir_map.krate().modules).for_each(|(&module_id, _)| {
+    hir_map.par_for_each_module(|module_id| {
         hir_map
-            .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors });
+            .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors })
     });
 
     let errors = errors.into_inner();
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index b7e43b7785d..d7c354aeb49 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -929,6 +929,16 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     let declared_lib_features = &tcx.features().declared_lib_features;
     let mut remaining_lib_features = FxHashMap::default();
     for (feature, span) in declared_lib_features {
+        if !tcx.sess.opts.unstable_features.is_nightly_build() {
+            struct_span_err!(
+                tcx.sess,
+                *span,
+                E0554,
+                "`#![feature]` may not be used on the {} release channel",
+                env!("CFG_RELEASE_CHANNEL")
+            )
+            .emit();
+        }
         if remaining_lib_features.contains_key(&feature) {
             // Warn if the user enables a lib feature multiple times.
             duplicate_feature_err(tcx.sess, *span, *feature);
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 42e8b4023cf..563a3cf1438 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -449,3 +449,25 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
         DUMMY_SP
     }
 }
+
+impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
+impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.0.default_span(tcx)
+    }
+}
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index bfd36bfb2db..d8cff0bd188 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -1,12 +1,12 @@
 use crate::QueryCtxt;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::memmap::Mmap;
-use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell, RwLock};
+use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathHash;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, interpret};
 use rustc_middle::thir;
@@ -25,7 +25,6 @@ use rustc_span::hygiene::{
 use rustc_span::source_map::{SourceMap, StableSourceFileId};
 use rustc_span::CachingSourceMapView;
 use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span};
-use std::collections::hash_map::Entry;
 use std::mem;
 
 const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
@@ -51,8 +50,6 @@ pub struct OnDiskCache<'sess> {
     // session.
     current_side_effects: Lock<FxHashMap<DepNodeIndex, QuerySideEffects>>,
 
-    cnum_map: OnceCell<UnhashMap<StableCrateId, CrateNum>>,
-
     source_map: &'sess SourceMap,
     file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
 
@@ -87,27 +84,11 @@ pub struct OnDiskCache<'sess> {
     expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>,
     // Additional information used when decoding hygiene data.
     hygiene_context: HygieneDecodeContext,
-    // Maps `DefPathHash`es to their `RawDefId`s from the *previous*
+    // Maps `ExpnHash`es to their raw value from the *previous*
     // compilation session. This is used as an initial 'guess' when
-    // we try to map a `DefPathHash` to its `DefId` in the current compilation
-    // session.
-    foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
-    // Likewise for ExpnId.
+    // we try to map an `ExpnHash` to its value in the current
+    // compilation session.
     foreign_expn_data: UnhashMap<ExpnHash, u32>,
-
-    // The *next* compilation sessison's `foreign_def_path_hashes` - at
-    // the end of our current compilation session, this will get written
-    // out to the `foreign_def_path_hashes` field of the `Footer`, which
-    // will become `foreign_def_path_hashes` of the next compilation session.
-    // This stores any `DefPathHash` that we may need to map to a `DefId`
-    // during the next compilation session.
-    latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>,
-
-    // Caches all lookups of `DefPathHashes`, both for local and foreign
-    // definitions. A definition from the previous compilation session
-    // may no longer exist in the current compilation session, so
-    // we use `Option<DefId>` so that we can cache a lookup failure.
-    def_path_hash_to_def_id_cache: Lock<UnhashMap<DefPathHash, Option<DefId>>>,
 }
 
 // This type is used only for serialization and deserialization.
@@ -122,7 +103,6 @@ struct Footer {
     syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
     // See `OnDiskCache.expn_data`
     expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>,
-    foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
     foreign_expn_data: UnhashMap<ExpnHash, u32>,
 }
 
@@ -145,19 +125,6 @@ impl AbsoluteBytePos {
     }
 }
 
-/// Represents a potentially invalid `DefId`. This is used during incremental
-/// compilation to represent a `DefId` from the *previous* compilation session,
-/// which may no longer be valid. This is used to help map a `DefPathHash`
-/// to a `DefId` in the current compilation session.
-#[derive(Encodable, Decodable, Copy, Clone, Debug)]
-crate struct RawDefId {
-    // We deliberately do not use `CrateNum` and `DefIndex`
-    // here, since a crate/index from the previous compilation
-    // session may no longer exist.
-    pub krate: u32,
-    pub index: u32,
-}
-
 /// An `EncodedSourceFileId` is the same as a `StableSourceFileId` except that
 /// the source crate is represented as a [StableCrateId] instead of as a
 /// `CrateNum`. This way `EncodedSourceFileId` can be encoded and decoded
@@ -170,8 +137,8 @@ struct EncodedSourceFileId {
 }
 
 impl EncodedSourceFileId {
-    fn translate(&self, cnum_map: &UnhashMap<StableCrateId, CrateNum>) -> StableSourceFileId {
-        let cnum = cnum_map[&self.stable_crate_id];
+    fn translate(&self, tcx: TyCtxt<'_>) -> StableSourceFileId {
+        let cnum = tcx.stable_crate_id_to_crate_num(self.stable_crate_id);
         StableSourceFileId { file_name_hash: self.file_name_hash, cnum }
     }
 
@@ -211,7 +178,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
             serialized_data: RwLock::new(Some(data)),
             file_index_to_stable_id: footer.file_index_to_stable_id,
             file_index_to_file: Default::default(),
-            cnum_map: OnceCell::new(),
             source_map: sess.source_map(),
             current_side_effects: Default::default(),
             query_result_index: footer.query_result_index.into_iter().collect(),
@@ -221,9 +187,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
             expn_data: footer.expn_data,
             foreign_expn_data: footer.foreign_expn_data,
             hygiene_context: Default::default(),
-            foreign_def_path_hashes: footer.foreign_def_path_hashes,
-            latest_foreign_def_path_hashes: Default::default(),
-            def_path_hash_to_def_id_cache: Default::default(),
         }
     }
 
@@ -232,7 +195,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
             serialized_data: RwLock::new(None),
             file_index_to_stable_id: Default::default(),
             file_index_to_file: Default::default(),
-            cnum_map: OnceCell::new(),
             source_map,
             current_side_effects: Default::default(),
             query_result_index: Default::default(),
@@ -242,9 +204,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
             expn_data: UnhashMap::default(),
             foreign_expn_data: UnhashMap::default(),
             hygiene_context: Default::default(),
-            foreign_def_path_hashes: Default::default(),
-            latest_foreign_def_path_hashes: Default::default(),
-            def_path_hash_to_def_id_cache: Default::default(),
         }
     }
 
@@ -254,13 +213,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
     /// In order to serialize the new on-disk cache, the former on-disk cache file needs to be
     /// deleted, hence we won't be able to refer to its memmapped data.
     fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>) {
-        // Register any dep nodes that we reused from the previous session,
-        // but didn't `DepNode::construct` in this session. This ensures
-        // that their `DefPathHash` to `RawDefId` mappings are registered
-        // in 'latest_foreign_def_path_hashes' if necessary, since that
-        // normally happens in `DepNode::construct`.
-        tcx.dep_graph.register_reused_dep_nodes(tcx);
-
         // Load everything into memory so we can write it out to the on-disk
         // cache. The vast majority of cacheable query results should already
         // be in memory, so this should be a cheap operation.
@@ -294,7 +246,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
                 (file_to_file_index, file_index_to_stable_id)
             };
 
-            let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone();
             let hygiene_encode_context = HygieneEncodeContext::default();
 
             let mut encoder = CacheEncoder {
@@ -306,7 +257,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
                 source_map: CachingSourceMapView::new(tcx.sess.source_map()),
                 file_to_file_index,
                 hygiene_context: &hygiene_encode_context,
-                latest_foreign_def_path_hashes,
             };
 
             // Encode query results.
@@ -383,9 +333,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
                 },
             )?;
 
-            let foreign_def_path_hashes =
-                std::mem::take(&mut encoder.latest_foreign_def_path_hashes);
-
             // `Encode the file footer.
             let footer_pos = encoder.position() as u64;
             encoder.encode_tagged(
@@ -398,7 +345,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
                     syntax_contexts,
                     expn_data,
                     foreign_expn_data,
-                    foreign_def_path_hashes,
                 },
             )?;
 
@@ -413,80 +359,21 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
         })
     }
 
-    fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> Option<DefId> {
-        let mut cache = self.def_path_hash_to_def_id_cache.lock();
-        match cache.entry(hash) {
-            Entry::Occupied(e) => *e.get(),
-            Entry::Vacant(e) => {
-                debug!("def_path_hash_to_def_id({:?})", hash);
-                // Check if the `DefPathHash` corresponds to a definition in the current
-                // crate
-                if let Some(def_id) =
-                    tcx.definitions_untracked().local_def_path_hash_to_def_id(hash)
-                {
-                    let def_id = def_id.to_def_id();
-                    e.insert(Some(def_id));
-                    return Some(def_id);
-                }
-                // This `raw_def_id` represents the `DefId` of this `DefPathHash` in
-                // the *previous* compliation session. The `DefPathHash` includes the
-                // owning crate, so if the corresponding definition still exists in the
-                // current compilation session, the crate is guaranteed to be the same
-                // (otherwise, we would compute a different `DefPathHash`).
-                let raw_def_id = self.get_raw_def_id(&hash)?;
-                debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id);
-                // If the owning crate no longer exists, the corresponding definition definitely
-                // no longer exists.
-                let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?;
-                debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate);
-                // If our `DefPathHash` corresponded to a definition in the local crate,
-                // we should have either found it in `local_def_path_hash_to_def_id`, or
-                // never attempted to load it in the first place. Any query result or `DepNode`
-                // that references a local `DefId` should depend on some HIR-related `DepNode`.
-                // If a local definition is removed/modified such that its old `DefPathHash`
-                // no longer has a corresponding definition, that HIR-related `DepNode` should
-                // end up red. This should prevent us from ever calling
-                // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any
-                // queries involved.
-                debug_assert_ne!(krate, LOCAL_CRATE);
-                // Try to find a definition in the current session, using the previous `DefIndex`
-                // as an initial guess.
-                let opt_def_id =
-                    tcx.cstore_untracked().def_path_hash_to_def_id(krate, raw_def_id.index, hash);
-                debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id);
-                e.insert(opt_def_id);
-                opt_def_id
-            }
-        }
-    }
+    fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> DefId {
+        debug!("def_path_hash_to_def_id({:?})", hash);
 
-    fn register_reused_dep_node(&self, tcx: TyCtxt<'sess>, dep_node: &DepNode) {
-        // For reused dep nodes, we only need to store the mapping if the node
-        // is one whose query key we can reconstruct from the hash. We use the
-        // mapping to aid that reconstruction in the next session. While we also
-        // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`,
-        // they're already registered during `DefId` encoding.
-        if dep_node.kind.can_reconstruct_query_key() {
-            let hash = DefPathHash(dep_node.hash.into());
-
-            // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to
-            // `latest_foreign_def_path_hashes`, since the `RawDefId` might have
-            // changed in the current compilation session (e.g. we've added/removed crates,
-            // or added/removed definitions before/after the target definition).
-            if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) {
-                if !def_id.is_local() {
-                    self.store_foreign_def_id_hash(def_id, hash);
-                }
-            }
-        }
-    }
+        let stable_crate_id = hash.stable_crate_id();
 
-    fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) {
-        // We may overwrite an existing entry, but it will have the same value,
-        // so it's fine
-        self.latest_foreign_def_path_hashes
-            .lock()
-            .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() });
+        // If this is a DefPathHash from the local crate, we can look up the
+        // DefId in the tcx's `Definitions`.
+        if stable_crate_id == tcx.sess.local_stable_crate_id() {
+            tcx.definitions_untracked().local_def_path_hash_to_def_id(hash).to_def_id()
+        } else {
+            // If this is a DefPathHash from an upstream crate, let the CrateStore map
+            // it to a DefId.
+            let cnum = tcx.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id);
+            tcx.cstore_untracked().def_path_hash_to_def_id(cnum, hash)
+        }
     }
 }
 
@@ -518,17 +405,6 @@ impl<'sess> OnDiskCache<'sess> {
         debug_assert!(prev.is_none());
     }
 
-    fn get_raw_def_id(&self, hash: &DefPathHash) -> Option<RawDefId> {
-        self.foreign_def_path_hashes.get(hash).copied()
-    }
-
-    fn try_remap_cnum(&self, tcx: TyCtxt<'_>, stable_crate_id: StableCrateId) -> Option<CrateNum> {
-        let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
-        debug!("try_remap_cnum({:?}): cnum_map={:?}", stable_crate_id, cnum_map);
-
-        cnum_map.get(&stable_crate_id).copied()
-    }
-
     /// Returns the cached query result if there is something in the cache for
     /// the given `SerializedDepNodeIndex`; otherwise returns `None`.
     pub fn try_load_query_result<'tcx, T>(
@@ -586,14 +462,11 @@ impl<'sess> OnDiskCache<'sess> {
     where
         T: Decodable<CacheDecoder<'a, 'tcx>>,
     {
-        let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
-
         let serialized_data = self.serialized_data.read();
         let mut decoder = CacheDecoder {
             tcx,
             opaque: opaque::Decoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()),
             source_map: self.source_map,
-            cnum_map,
             file_index_to_file: &self.file_index_to_file,
             file_index_to_stable_id: &self.file_index_to_stable_id,
             alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(),
@@ -604,23 +477,6 @@ impl<'sess> OnDiskCache<'sess> {
         };
         f(&mut decoder)
     }
-
-    // This function builds mapping from previous-session-`CrateNum` to
-    // current-session-`CrateNum`. There might be `CrateNum`s from the previous
-    // `Session` that don't occur in the current one. For these, the mapping
-    // maps to None.
-    fn compute_cnum_map(tcx: TyCtxt<'_>) -> UnhashMap<StableCrateId, CrateNum> {
-        tcx.dep_graph.with_ignore(|| {
-            tcx.crates(())
-                .iter()
-                .chain(std::iter::once(&LOCAL_CRATE))
-                .map(|&cnum| {
-                    let hash = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
-                    (hash, cnum)
-                })
-                .collect()
-        })
-    }
 }
 
 //- DECODING -------------------------------------------------------------------
@@ -632,7 +488,6 @@ pub struct CacheDecoder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     opaque: opaque::Decoder<'a>,
     source_map: &'a SourceMap,
-    cnum_map: &'a UnhashMap<StableCrateId, CrateNum>,
     file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
     file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, EncodedSourceFileId>,
     alloc_decoding_session: AllocDecodingSession<'a>,
@@ -645,10 +500,10 @@ pub struct CacheDecoder<'a, 'tcx> {
 impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
     fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> {
         let CacheDecoder {
+            tcx,
             ref file_index_to_file,
             ref file_index_to_stable_id,
             ref source_map,
-            ref cnum_map,
             ..
         } = *self;
 
@@ -656,7 +511,7 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
             .borrow_mut()
             .entry(index)
             .or_insert_with(|| {
-                let stable_id = file_index_to_stable_id[&index].translate(cnum_map);
+                let stable_id = file_index_to_stable_id[&index].translate(tcx);
                 source_map
                     .source_file_by_stable_id(stable_id)
                     .expect("failed to lookup `SourceFile` in new context")
@@ -798,7 +653,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
             return Ok(expn_id);
         }
 
-        let krate = decoder.cnum_map[&hash.stable_crate_id()];
+        let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id());
 
         let expn_id = if krate == LOCAL_CRATE {
             // We look up the position of the associated `ExpnData` and decode it.
@@ -871,7 +726,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
         let stable_id = StableCrateId::decode(d)?;
-        let cnum = d.cnum_map[&stable_id];
+        let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id);
         Ok(cnum)
     }
 }
@@ -899,12 +754,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
         // If we get to this point, then all of the query inputs were green,
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
-        Ok(d.tcx()
-            .on_disk_cache
-            .as_ref()
-            .unwrap()
-            .def_path_hash_to_def_id(d.tcx(), def_path_hash)
-            .unwrap())
+        Ok(d.tcx().on_disk_cache.as_ref().unwrap().def_path_hash_to_def_id(d.tcx(), def_path_hash))
     }
 }
 
@@ -969,7 +819,6 @@ pub struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
     source_map: CachingSourceMapView<'tcx>,
     file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
     hygiene_context: &'a HygieneEncodeContext,
-    latest_foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
 }
 
 impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E>
@@ -1102,17 +951,7 @@ where
     E: 'a + OpaqueEncoder,
 {
     fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
-        let def_path_hash = s.tcx.def_path_hash(*self);
-        // Store additional information when we encode a foreign `DefId`,
-        // so that we can map its `DefPathHash` back to a `DefId` in the next
-        // compilation session.
-        if !self.is_local() {
-            s.latest_foreign_def_path_hashes.insert(
-                def_path_hash,
-                RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() },
-            );
-        }
-        def_path_hash.encode(s)
+        s.tcx.def_path_hash(*self).encode(s)
     }
 }
 
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index 59ef6052a60..46dc0c720ce 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -53,18 +53,6 @@ use std::hash::Hash;
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub struct DepNode<K> {
     pub kind: K,
-    // Important - whenever a `DepNode` is constructed, we need to make
-    // sure to register a `DefPathHash -> DefId` mapping if needed.
-    // This is currently done in two places:
-    //
-    // * When a `DepNode::construct` is called, `arg.to_fingerprint()`
-    //   is responsible for calling `OnDiskCache::store_foreign_def_id_hash`
-    //   if needed
-    // * When we serialize the on-disk cache, `OnDiskCache::serialize` is
-    //   responsible for calling `DepGraph::register_reused_dep_nodes`.
-    //
-    // FIXME: Enforce this by preventing manual construction of `DefNode`
-    // (e.g. add a `_priv: ()` field)
     pub hash: PackedFingerprint,
 }
 
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index e589d16992f..23a43771842 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -760,20 +760,6 @@ impl<K: DepKind> DepGraph<K> {
         }
     }
 
-    // Register reused dep nodes (i.e. nodes we've marked red or green) with the context.
-    pub fn register_reused_dep_nodes<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
-        let data = self.data.as_ref().unwrap();
-        for prev_index in data.colors.values.indices() {
-            match data.colors.get(prev_index) {
-                Some(DepNodeColor::Red) | Some(DepNodeColor::Green(_)) => {
-                    let dep_node = data.previous.index_to_node(prev_index);
-                    tcx.register_reused_dep_node(&dep_node);
-                }
-                None => {}
-            }
-        }
-    }
-
     pub fn print_incremental_info(&self) {
         if let Some(data) = &self.data {
             data.current.encoder.borrow().print_incremental_info(
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 15e2633c4f1..b5be1192ce7 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -27,8 +27,6 @@ pub trait DepContext: Copy {
     /// Access the DepGraph.
     fn dep_graph(&self) -> &DepGraph<Self::DepKind>;
 
-    fn register_reused_dep_node(&self, dep_node: &DepNode<Self::DepKind>);
-
     /// Access the profiler.
     fn profiler(&self) -> &SelfProfilerRef;
 
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 73c00fc49ba..f5f67fcd0a0 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -99,7 +99,7 @@ impl<K: DepKind> SerializedDepGraph<K> {
 impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<'a>>
     for SerializedDepGraph<K>
 {
-    #[instrument(skip(d))]
+    #[instrument(level = "debug", skip(d))]
     fn decode(d: &mut opaque::Decoder<'a>) -> Result<SerializedDepGraph<K>, String> {
         let start_position = d.position();
 
@@ -187,7 +187,7 @@ impl<K: DepKind> EncoderState<K> {
         }
     }
 
-    #[instrument(skip(self, record_graph))]
+    #[instrument(level = "debug", skip(self, record_graph))]
     fn encode_node(
         &mut self,
         node: &NodeInfo<K>,
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 4c1d537d55f..a158e0e48e8 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -1652,7 +1652,11 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
     }
 
     fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
-        if let hir::ExprKind::Loop(_, Some(label), ..) = ex.kind { Some(label.ident) } else { None }
+        match ex.kind {
+            hir::ExprKind::Loop(_, Some(label), ..) => Some(label.ident),
+            hir::ExprKind::Block(_, Some(label)) => Some(label.ident),
+            _ => None,
+        }
     }
 
     fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
@@ -2024,7 +2028,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         // ensure that we issue lints in a repeatable order
         def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id));
 
-        for def_id in def_ids {
+        'lifetimes: for def_id in def_ids {
             debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id);
 
             let lifetimeuseset = self.lifetime_uses.remove(&def_id);
@@ -2067,6 +2071,27 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                 {
                                     continue;
                                 }
+
+                                // opaque types generated when desugaring an async function can have a single
+                                // use lifetime even if it is explicitly denied (Issue #77175)
+                                if let hir::Node::Item(hir::Item {
+                                    kind: hir::ItemKind::OpaqueTy(ref opaque),
+                                    ..
+                                }) = self.tcx.hir().get(parent_hir_id)
+                                {
+                                    if opaque.origin != hir::OpaqueTyOrigin::AsyncFn {
+                                        continue 'lifetimes;
+                                    }
+                                    // We want to do this only if the liftime identifier is already defined
+                                    // in the async function that generated this. Otherwise it could be
+                                    // an opaque type defined by the developer and we still want this
+                                    // lint to fail compilation
+                                    for p in opaque.generics.params {
+                                        if defined_by.contains_key(&p.name) {
+                                            continue 'lifetimes;
+                                        }
+                                    }
+                                }
                             }
                         }
 
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs
index 8e21b9ff44a..fdabf404a37 100644
--- a/compiler/rustc_span/src/caching_source_map_view.rs
+++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -215,13 +215,13 @@ impl<'sm> CachingSourceMapView<'sm> {
 
         // Span lo and hi may equal line end when last line doesn't
         // end in newline, hence the inclusive upper bounds below.
-        debug_assert!(span_data.lo >= lo.line.start);
-        debug_assert!(span_data.lo <= lo.line.end);
-        debug_assert!(span_data.hi >= hi.line.start);
-        debug_assert!(span_data.hi <= hi.line.end);
-        debug_assert!(lo.file.contains(span_data.lo));
-        debug_assert!(lo.file.contains(span_data.hi));
-        debug_assert_eq!(lo.file_index, hi.file_index);
+        assert!(span_data.lo >= lo.line.start);
+        assert!(span_data.lo <= lo.line.end);
+        assert!(span_data.hi >= hi.line.start);
+        assert!(span_data.hi <= hi.line.end);
+        assert!(lo.file.contains(span_data.lo));
+        assert!(lo.file.contains(span_data.hi));
+        assert_eq!(lo.file_index, hi.file_index);
 
         Some((
             lo.file.clone(),
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index eb496140553..9c5469f635f 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -78,7 +78,7 @@ mod tests;
 // threads within the compilation session, but is not accessible outside the
 // session.
 pub struct SessionGlobals {
-    symbol_interner: Lock<symbol::Interner>,
+    symbol_interner: symbol::Interner,
     span_interner: Lock<span_encoding::SpanInterner>,
     hygiene_data: Lock<hygiene::HygieneData>,
     source_map: Lock<Option<Lrc<SourceMap>>>,
@@ -87,7 +87,7 @@ pub struct SessionGlobals {
 impl SessionGlobals {
     pub fn new(edition: Edition) -> SessionGlobals {
         SessionGlobals {
-            symbol_interner: Lock::new(symbol::Interner::fresh()),
+            symbol_interner: symbol::Interner::fresh(),
             span_interner: Lock::new(span_encoding::SpanInterner::default()),
             hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
             source_map: Lock::new(None),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 760357644a5..322bea3806c 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -5,6 +5,7 @@
 use rustc_arena::DroplessArena;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::sync::Lock;
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
@@ -923,6 +924,7 @@ symbols! {
         panic_2021,
         panic_abort,
         panic_bounds_check,
+        panic_display,
         panic_fmt,
         panic_handler,
         panic_impl,
@@ -1210,6 +1212,7 @@ symbols! {
         simd_select_bitmask,
         simd_shl,
         simd_shr,
+        simd_shuffle,
         simd_sub,
         simd_trunc,
         simd_xor,
@@ -1622,14 +1625,15 @@ impl Symbol {
 
     /// Maps a string to its interned representation.
     pub fn intern(string: &str) -> Self {
-        with_interner(|interner| interner.intern(string))
+        with_session_globals(|session_globals| session_globals.symbol_interner.intern(string))
     }
 
     /// Convert to a `SymbolStr`. This is a slowish operation because it
     /// requires locking the symbol interner.
     pub fn as_str(self) -> SymbolStr {
-        with_interner(|interner| unsafe {
-            SymbolStr { string: std::mem::transmute::<&str, &str>(interner.get(self)) }
+        with_session_globals(|session_globals| {
+            let symbol_str = session_globals.symbol_interner.get(self);
+            unsafe { SymbolStr { string: std::mem::transmute::<&str, &str>(symbol_str) } }
         })
     }
 
@@ -1638,7 +1642,7 @@ impl Symbol {
     }
 
     pub fn len(self) -> usize {
-        with_interner(|interner| interner.get(self).len())
+        with_session_globals(|session_globals| session_globals.symbol_interner.get(self).len())
     }
 
     pub fn is_empty(self) -> bool {
@@ -1695,6 +1699,9 @@ impl<CTX> ToStableHashKey<CTX> for Symbol {
     }
 }
 
+#[derive(Default)]
+pub(crate) struct Interner(Lock<InternerInner>);
+
 // The `&'static str`s in this type actually point into the arena.
 //
 // The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278
@@ -1704,7 +1711,7 @@ impl<CTX> ToStableHashKey<CTX> for Symbol {
 // This type is private to prevent accidentally constructing more than one `Interner` on the same
 // thread, which makes it easy to mixup `Symbol`s between `Interner`s.
 #[derive(Default)]
-pub(crate) struct Interner {
+struct InternerInner {
     arena: DroplessArena,
     names: FxHashMap<&'static str, Symbol>,
     strings: Vec<&'static str>,
@@ -1712,37 +1719,38 @@ pub(crate) struct Interner {
 
 impl Interner {
     fn prefill(init: &[&'static str]) -> Self {
-        Interner {
+        Interner(Lock::new(InternerInner {
             strings: init.into(),
             names: init.iter().copied().zip((0..).map(Symbol::new)).collect(),
             ..Default::default()
-        }
+        }))
     }
 
     #[inline]
-    pub fn intern(&mut self, string: &str) -> Symbol {
-        if let Some(&name) = self.names.get(string) {
+    fn intern(&self, string: &str) -> Symbol {
+        let mut inner = self.0.lock();
+        if let Some(&name) = inner.names.get(string) {
             return name;
         }
 
-        let name = Symbol::new(self.strings.len() as u32);
+        let name = Symbol::new(inner.strings.len() as u32);
 
         // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be
         // UTF-8.
         let string: &str =
-            unsafe { str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes())) };
+            unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) };
         // It is safe to extend the arena allocation to `'static` because we only access
         // these while the arena is still alive.
         let string: &'static str = unsafe { &*(string as *const str) };
-        self.strings.push(string);
-        self.names.insert(string, name);
+        inner.strings.push(string);
+        inner.names.insert(string, name);
         name
     }
 
     // Get the symbol as a string. `Symbol::as_str()` should be used in
     // preference to this function.
-    pub fn get(&self, symbol: Symbol) -> &str {
-        self.strings[symbol.0.as_usize()]
+    fn get(&self, symbol: Symbol) -> &str {
+        self.0.lock().strings[symbol.0.as_usize()]
     }
 }
 
@@ -1873,11 +1881,6 @@ impl Ident {
     }
 }
 
-#[inline]
-fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
-    with_session_globals(|session_globals| f(&mut *session_globals.symbol_interner.lock()))
-}
-
 /// An alternative to [`Symbol`], useful when the chars within the symbol need to
 /// be accessed. It deliberately has limited functionality and should only be
 /// used for temporary values.
diff --git a/compiler/rustc_span/src/symbol/tests.rs b/compiler/rustc_span/src/symbol/tests.rs
index 11dea265b4e..0958fce5fee 100644
--- a/compiler/rustc_span/src/symbol/tests.rs
+++ b/compiler/rustc_span/src/symbol/tests.rs
@@ -4,7 +4,7 @@ use crate::create_default_session_globals_then;
 
 #[test]
 fn interner_tests() {
-    let mut i: Interner = Interner::default();
+    let i = Interner::default();
     // first one is zero:
     assert_eq!(i.intern("dog"), Symbol::new(0));
     // re-use gets the same entry:
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 4f52535aa50..d9eb299e2fd 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -1,6 +1,7 @@
 use crate::abi::{self, Abi, Align, FieldsShape, Size};
 use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
 use crate::spec::{self, HasTargetSpec};
+use std::fmt;
 
 mod aarch64;
 mod amdgpu;
@@ -25,7 +26,7 @@ mod x86;
 mod x86_64;
 mod x86_win64;
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum PassMode {
     /// Ignore the argument.
     ///
@@ -60,7 +61,7 @@ pub use attr_impl::ArgAttribute;
 mod attr_impl {
     // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
     bitflags::bitflags! {
-        #[derive(Default)]
+        #[derive(Default, HashStable_Generic)]
         pub struct ArgAttribute: u16 {
             const NoAlias   = 1 << 1;
             const NoCapture = 1 << 2;
@@ -77,7 +78,7 @@ mod attr_impl {
 /// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum
 /// defines if this extension should be zero-extension or sign-extension when necessary. When it is
 /// not necessary to extend the argument, this enum is ignored.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum ArgExtension {
     None,
     Zext,
@@ -86,7 +87,7 @@ pub enum ArgExtension {
 
 /// A compact representation of LLVM attributes (at least those relevant for this module)
 /// that can be manipulated without interacting with LLVM's Attribute machinery.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct ArgAttributes {
     pub regular: ArgAttribute,
     pub arg_ext: ArgExtension,
@@ -127,14 +128,14 @@ impl ArgAttributes {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum RegKind {
     Integer,
     Float,
     Vector,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct Reg {
     pub kind: RegKind,
     pub size: Size,
@@ -184,7 +185,7 @@ impl Reg {
 
 /// An argument passed entirely registers with the
 /// same kind (e.g., HFA / HVA on PPC64 and AArch64).
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct Uniform {
     pub unit: Reg,
 
@@ -209,7 +210,7 @@ impl Uniform {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct CastTarget {
     pub prefix: [Option<RegKind>; 8],
     pub prefix_chunk_size: Size,
@@ -437,7 +438,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
 
 /// Information about how to pass an argument to,
 /// or return a value from, a function, under some ABI.
-#[derive(Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct ArgAbi<'a, Ty> {
     pub layout: TyAndLayout<'a, Ty>,
 
@@ -545,7 +546,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum Conv {
     // General language calling conventions, for which every target
     // should have its own backend (e.g. LLVM) support.
@@ -579,7 +580,7 @@ pub enum Conv {
 ///
 /// I will do my best to describe this structure, but these
 /// comments are reverse-engineered and may be inaccurate. -NDM
-#[derive(Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct FnAbi<'a, Ty> {
     /// The LLVM types of each argument.
     pub args: Vec<ArgAbi<'a, Ty>>,
@@ -600,8 +601,29 @@ pub struct FnAbi<'a, Ty> {
     pub can_unwind: bool,
 }
 
+/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
+#[derive(Clone, Debug, HashStable_Generic)]
+pub enum AdjustForForeignAbiError {
+    /// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
+    Unsupported { arch: String, abi: spec::abi::Abi },
+}
+
+impl fmt::Display for AdjustForForeignAbiError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Unsupported { arch, abi } => {
+                write!(f, "target architecture {:?} does not support `extern {}` ABI", arch, abi)
+            }
+        }
+    }
+}
+
 impl<'a, Ty> FnAbi<'a, Ty> {
-    pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String>
+    pub fn adjust_for_foreign_abi<C>(
+        &mut self,
+        cx: &C,
+        abi: spec::abi::Abi,
+    ) -> Result<(), AdjustForForeignAbiError>
     where
         Ty: TyAbiInterface<'a, C> + Copy,
         C: HasDataLayout + HasTargetSpec,
@@ -657,7 +679,9 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             }
             "asmjs" => wasm::compute_c_abi_info(cx, self),
             "bpf" => bpf::compute_abi_info(self),
-            a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
+            arch => {
+                return Err(AdjustForForeignAbiError::Unsupported { arch: arch.to_string(), abi });
+            }
         }
 
         Ok(())
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index b743c809ca2..8abcdb5e89b 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -499,7 +499,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     /// - `substs`, the substs  used to instantiate this opaque type
     /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
     ///   `opaque_defn.concrete_ty`
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn infer_opaque_definition_from_instantiation(
         &self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
@@ -863,7 +863,7 @@ struct Instantiator<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Instantiator<'a, 'tcx> {
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
         let tcx = self.infcx.tcx;
         value.fold_with(&mut BottomUpFolder {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index d5660c1c7ba..b966779500b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -974,6 +974,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
     ) -> Option<EvaluationResult> {
+        // Neither the global nor local cache is aware of intercrate
+        // mode, so don't do any caching. In particular, we might
+        // re-use the same `InferCtxt` with both an intercrate
+        // and non-intercrate `SelectionContext`
+        if self.intercrate {
+            return None;
+        }
+
         let tcx = self.tcx();
         if self.can_use_global_caches(param_env) {
             if let Some(res) = tcx.evaluation_cache.get(&param_env.and(trait_ref), tcx) {
@@ -996,6 +1004,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return;
         }
 
+        // Neither the global nor local cache is aware of intercrate
+        // mode, so don't do any caching. In particular, we might
+        // re-use the same `InferCtxt` with both an intercrate
+        // and non-intercrate `SelectionContext`
+        if self.intercrate {
+            return;
+        }
+
         if self.can_use_global_caches(param_env) {
             if !trait_ref.needs_infer() {
                 debug!(?trait_ref, ?result, "insert_evaluation_cache global");
@@ -1052,6 +1068,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ///
     /// The weird return type of this function allows it to be used with the `try` (`?`)
     /// operator within certain functions.
+    #[inline(always)]
     fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>(
         &self,
         obligation: &Obligation<'tcx, T>,
@@ -2017,7 +2034,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let cause = ObligationCause::new(
             obligation.cause.span,
             obligation.cause.body_id,
-            ObligationCauseCode::MatchImpl(Lrc::new(obligation.cause.code.clone()), impl_def_id),
+            ObligationCauseCode::MatchImpl(obligation.cause.clone(), impl_def_id),
         );
 
         let InferOk { obligations, .. } = self
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 14550690e63..4ea7a8694c0 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -362,6 +362,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                                 ),
                                 self.cast_ty,
                                 AllowTwoPhase::No,
+                                None,
                             )
                             .is_ok()
                         {
@@ -379,6 +380,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                                     ),
                                     self.cast_ty,
                                     AllowTwoPhase::No,
+                                    None,
                                 )
                                 .is_ok()
                         {
@@ -394,6 +396,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                                 fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
                                 self.cast_ty,
                                 AllowTwoPhase::No,
+                                None,
                             )
                             .is_ok()
                     {
@@ -409,6 +412,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             ),
                             self.cast_ty,
                             AllowTwoPhase::No,
+                            None,
                         )
                         .is_ok()
                     {
@@ -666,6 +670,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             self.expr_ty,
                             fcx.tcx.mk_fn_ptr(f),
                             AllowTwoPhase::No,
+                            None,
                         );
                         if let Err(TypeError::IntrinsicCast) = res {
                             return Err(CastError::IllegalCast);
@@ -829,7 +834,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
                 // Coerce to a raw pointer so that we generate AddressOf in MIR.
                 let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
-                fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
+                fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
                     .unwrap_or_else(|_| {
                         bug!(
                         "could not cast from reference to array to pointer to array ({:?} to {:?})",
@@ -861,7 +866,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'_>> {
-        match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
+        match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) {
             Ok(_) => Ok(()),
             Err(err) => Err(err),
         }
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 1fd1253e527..54e4eb47688 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -214,7 +214,7 @@ pub(super) fn check_fn<'a, 'tcx>(
         fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
     } else {
         fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-        fcx.check_return_expr(&body.value);
+        fcx.check_return_expr(&body.value, false);
     }
     fcx.in_tail_expr = false;
 
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 013aecae586..92d0470bc2f 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -935,11 +935,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr_ty: Ty<'tcx>,
         target: Ty<'tcx>,
         allow_two_phase: AllowTwoPhase,
+        cause: Option<ObligationCause<'tcx>>,
     ) -> RelateResult<'tcx, Ty<'tcx>> {
         let source = self.resolve_vars_with_obligations(expr_ty);
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
-        let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
+        let cause =
+            cause.unwrap_or_else(|| self.cause(expr.span, ObligationCauseCode::ExprAssignable));
         let coerce = Coerce::new(self, cause, allow_two_phase);
         let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
 
@@ -1363,7 +1365,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 // Special-case the first expression we are coercing.
                 // To be honest, I'm not entirely sure why we do this.
                 // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
-                fcx.try_coerce(expression, expression_ty, self.expected_ty, AllowTwoPhase::No)
+                fcx.try_coerce(
+                    expression,
+                    expression_ty,
+                    self.expected_ty,
+                    AllowTwoPhase::No,
+                    Some(cause.clone()),
+                )
             } else {
                 match self.expressions {
                     Expressions::Dynamic(ref exprs) => fcx.try_find_coercion_lub(
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index a86db2d31b3..722b110ed61 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -134,7 +134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
         let expected = self.resolve_vars_with_obligations(expected);
 
-        let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase) {
+        let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) {
             Ok(ty) => return (ty, None),
             Err(e) => e,
         };
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 917adf0e2b9..11b6c93a115 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -765,7 +765,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if self.ret_coercion_span.get().is_none() {
                 self.ret_coercion_span.set(Some(e.span));
             }
-            self.check_return_expr(e);
+            self.check_return_expr(e, true);
         } else {
             let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
             if self.ret_coercion_span.get().is_none() {
@@ -794,16 +794,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.tcx.types.never
     }
 
-    pub(super) fn check_return_expr(&self, return_expr: &'tcx hir::Expr<'tcx>) {
+    /// `explicit_return` is `true` if we're checkng an explicit `return expr`,
+    /// and `false` if we're checking a trailing expression.
+    pub(super) fn check_return_expr(
+        &self,
+        return_expr: &'tcx hir::Expr<'tcx>,
+        explicit_return: bool,
+    ) {
         let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
             span_bug!(return_expr.span, "check_return_expr called outside fn body")
         });
 
         let ret_ty = ret_coercion.borrow().expected_ty();
         let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
+        let mut span = return_expr.span;
+        // Use the span of the trailing expression for our cause,
+        // not the span of the entire function
+        if !explicit_return {
+            if let ExprKind::Block(body, _) = return_expr.kind {
+                if let Some(last_expr) = body.expr {
+                    span = last_expr.span;
+                }
+            }
+        }
         ret_coercion.borrow_mut().coerce(
             self,
-            &self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
+            &self.cause(span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
             return_expr,
             return_expr_ty,
         );
@@ -1844,6 +1860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 field,
                 expr_t,
                 expr,
+                None,
             );
         }
         err.emit();
@@ -1870,9 +1887,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
         let expr_snippet =
             self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new());
-        if expr_is_call && expr_snippet.starts_with("(") && expr_snippet.ends_with(")") {
-            let after_open = expr.span.lo() + rustc_span::BytePos(1);
-            let before_close = expr.span.hi() - rustc_span::BytePos(1);
+        let is_wrapped = expr_snippet.starts_with("(") && expr_snippet.ends_with(")");
+        let after_open = expr.span.lo() + rustc_span::BytePos(1);
+        let before_close = expr.span.hi() - rustc_span::BytePos(1);
+
+        if expr_is_call && is_wrapped {
             err.multipart_suggestion(
                 "remove wrapping parentheses to call the method",
                 vec![
@@ -1882,12 +1901,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Applicability::MachineApplicable,
             );
         } else if !self.expr_in_place(expr.hir_id) {
+            // Suggest call parentheses inside the wrapping parentheses
+            let span = if is_wrapped {
+                expr.span.with_lo(after_open).with_hi(before_close)
+            } else {
+                expr.span
+            };
             self.suggest_method_call(
                 &mut err,
                 "use parentheses to call the method",
                 field,
                 expr_t,
                 expr,
+                Some(span),
             );
         } else {
             err.help("methods are immutable and cannot be assigned to");
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 9cf00bad10b..551522334aa 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -532,15 +532,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             Some((variant, ty))
         } else {
-            struct_span_err!(
-                self.tcx.sess,
-                path_span,
-                E0071,
-                "expected struct, variant or union type, found {}",
-                ty.sort_string(self.tcx)
-            )
-            .span_label(path_span, "not a struct")
-            .emit();
+            match ty.kind() {
+                ty::Error(_) => {
+                    // E0071 might be caused by a spelling error, which will have
+                    // already caused an error message and probably a suggestion
+                    // elsewhere. Refrain from emitting more unhelpful errors here
+                    // (issue #88844).
+                }
+                _ => {
+                    struct_span_err!(
+                        self.tcx.sess,
+                        path_span,
+                        E0071,
+                        "expected struct, variant or union type, found {}",
+                        ty.sort_string(self.tcx)
+                    )
+                    .span_label(path_span, "not a struct")
+                    .emit();
+                }
+            }
             None
         }
     }
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 664954b0eb7..ff7a26853b1 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -2,7 +2,7 @@
 //! intrinsics that the compiler exposes.
 
 use crate::errors::{
-    SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
+    UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
     WrongNumberOfGenericArgumentsToIntrinsic,
 };
 use crate::require_same_types;
@@ -468,6 +468,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         | sym::simd_reduce_max
         | sym::simd_reduce_min_nanless
         | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)),
+        sym::simd_shuffle => (3, vec![param(0), param(0), param(1)], param(2)),
         name if name.as_str().starts_with("simd_shuffle") => {
             match name.as_str()["simd_shuffle".len()..].parse() {
                 Ok(n) => {
@@ -475,7 +476,9 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
                     (2, params, param(1))
                 }
                 Err(_) => {
-                    tcx.sess.emit_err(SimdShuffleMissingLength { span: it.span, name });
+                    let msg =
+                        format!("unrecognized platform-specific intrinsic function: `{}`", name);
+                    tcx.sess.struct_span_err(it.span, &msg).emit();
                     return;
                 }
             }
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 2136d925423..8e09aa97dcf 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -141,6 +141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         method_name: Ident,
         self_ty: Ty<'tcx>,
         call_expr: &hir::Expr<'_>,
+        span: Option<Span>,
     ) {
         let params = self
             .probe_for_name(
@@ -159,7 +160,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .unwrap_or(0);
 
         // Account for `foo.bar<T>`;
-        let sugg_span = call_expr.span.shrink_to_hi();
+        let sugg_span = span.unwrap_or_else(|| call_expr.span).shrink_to_hi();
         let (suggestion, applicability) = (
             format!("({})", (0..params).map(|_| "_").collect::<Vec<_>>().join(", ")),
             if params > 0 { Applicability::HasPlaceholders } else { Applicability::MaybeIncorrect },
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index a056ab6aef2..829268e3cb5 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1452,7 +1452,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     plural
                 ),
             );
-            if plural == "" {
+
+            if unmentioned_fields.len() == 1 {
                 let input =
                     unmentioned_fields.iter().map(|(_, field)| field.name).collect::<Vec<_>>();
                 let suggested_name = find_best_match_for_name(&input, ident.name, None);
@@ -1473,6 +1474,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // We don't want to throw `E0027` in case we have thrown `E0026` for them.
                         unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
                     }
+                } else if inexistent_fields.len() == 1 {
+                    let unmentioned_field = unmentioned_fields[0].1.name;
+                    err.span_suggestion_short(
+                        ident.span,
+                        &format!(
+                            "`{}` has a field named `{}`",
+                            tcx.def_path_str(variant.def_id),
+                            unmentioned_field
+                        ),
+                        unmentioned_field.to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
                 }
             }
         }
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 1e6a240b2f8..47077779616 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -122,14 +122,6 @@ pub struct AssocTypeBindingNotAllowed {
 }
 
 #[derive(SessionDiagnostic)]
-#[error = "E0439"]
-pub struct SimdShuffleMissingLength {
-    #[message = "invalid `simd_shuffle`, needs length: `{name}`"]
-    pub span: Span,
-    pub name: Symbol,
-}
-
-#[derive(SessionDiagnostic)]
 #[error = "E0436"]
 pub struct FunctionalRecordUpdateOnNonStruct {
     #[message = "functional record update syntax requires a struct"]
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs
index 194c4efdbb0..9b23bf241cc 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check.rs
@@ -58,9 +58,7 @@ pub fn impl_wf_check(tcx: TyCtxt<'_>) {
     // We will tag this as part of the WF check -- logically, it is,
     // but it's one that we must perform earlier than the rest of
     // WfCheck.
-    for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_impl_wf(module);
-    }
+    tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module))
 }
 
 fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index c703ca96ada..f8714cdc70c 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -473,9 +473,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
     // FIXME(matthewjasper) We shouldn't need to use `track_errors`.
     tcx.sess.track_errors(|| {
         tcx.sess.time("type_collecting", || {
-            for &module in tcx.hir().krate().modules.keys() {
-                tcx.ensure().collect_mod_item_types(module);
-            }
+            tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module))
         });
     })?;
 
@@ -505,9 +503,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
 
     // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
     tcx.sess.time("item_types_checking", || {
-        for &module in tcx.hir().krate().modules.keys() {
-            tcx.ensure().check_mod_item_types(module);
-        }
+        tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
     });
 
     tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(()));
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index bccc19774e0..7e69ad21d03 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -136,10 +136,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             AngleBrackets::Missing => 0,
             // Only lifetime arguments can be implied
             AngleBrackets::Implied => self.gen_args.args.len(),
-            AngleBrackets::Available => self.gen_args.args.iter().fold(0, |acc, arg| match arg {
-                hir::GenericArg::Lifetime(_) => acc + 1,
-                _ => acc,
-            }),
+            AngleBrackets::Available => self.gen_args.num_lifetime_params(),
         }
     }
 
@@ -148,10 +145,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             AngleBrackets::Missing => 0,
             // Only lifetime arguments can be implied
             AngleBrackets::Implied => 0,
-            AngleBrackets::Available => self.gen_args.args.iter().fold(0, |acc, arg| match arg {
-                hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => acc + 1,
-                _ => acc,
-            }),
+            AngleBrackets::Available => self.gen_args.num_generic_params(),
         }
     }
 
@@ -651,7 +645,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             let mut found_redundant = false;
             for arg in self.gen_args.args {
                 match arg {
-                    hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => {
+                    hir::GenericArg::Type(_)
+                    | hir::GenericArg::Const(_)
+                    | hir::GenericArg::Infer(_) => {
                         gen_arg_spans.push(arg.span());
                         if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
                             found_redundant = true;
diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs
index 5f13c3bf303..54a157be0b9 100644
--- a/library/alloc/src/collections/vec_deque/into_iter.rs
+++ b/library/alloc/src/collections/vec_deque/into_iter.rs
@@ -17,7 +17,13 @@ pub struct IntoIter<
     T,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
 > {
-    pub(crate) inner: VecDeque<T, A>,
+    inner: VecDeque<T, A>,
+}
+
+impl<T, A: Allocator> IntoIter<T, A> {
+    pub(super) fn new(inner: VecDeque<T, A>) -> Self {
+        IntoIter { inner }
+    }
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index e4b28204158..10144cc17bf 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2827,7 +2827,7 @@ impl<T, A: Allocator> IntoIterator for VecDeque<T, A> {
     /// Consumes the `VecDeque` into a front-to-back iterator yielding elements by
     /// value.
     fn into_iter(self) -> IntoIter<T, A> {
-        IntoIter { inner: self }
+        IntoIter::new(self)
     }
 }
 
diff --git a/library/core/src/lazy.rs b/library/core/src/lazy.rs
index 2c517371c2c..e6bea462fa9 100644
--- a/library/core/src/lazy.rs
+++ b/library/core/src/lazy.rs
@@ -214,7 +214,16 @@ impl<T> OnceCell<T> {
         if let Some(val) = self.get() {
             return Ok(val);
         }
-        let val = f()?;
+        /// Avoid inlining the initialization closure into the common path that fetches
+        /// the already initialized value
+        #[cold]
+        fn outlined_call<F, T, E>(f: F) -> Result<T, E>
+        where
+            F: FnOnce() -> Result<T, E>,
+        {
+            f()
+        }
+        let val = outlined_call(f)?;
         // Note that *some* forms of reentrant initialization might lead to
         // UB (see `reentrant_init` test). I believe that just removing this
         // `assert`, while keeping `set/get` would be sound, but it seems
diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs
index 463bec37265..7a8b04d6f3c 100644
--- a/library/core/src/panic.rs
+++ b/library/core/src/panic.rs
@@ -27,9 +27,14 @@ pub macro panic_2015 {
     ($msg:literal $(,)?) => (
         $crate::panicking::panic($msg)
     ),
+    // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint.
     ($msg:expr $(,)?) => (
         $crate::panicking::panic_str($msg)
     ),
+    // Special-case the single-argument case for const_panic.
+    ("{}", $arg:expr $(,)?) => (
+        $crate::panicking::panic_display(&$arg)
+    ),
     ($fmt:expr, $($arg:tt)+) => (
         $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
     ),
@@ -44,6 +49,10 @@ pub macro panic_2021 {
     () => (
         $crate::panicking::panic("explicit panic")
     ),
+    // Special-case the single-argument case for const_panic.
+    ("{}", $arg:expr $(,)?) => (
+        $crate::panicking::panic_display(&$arg)
+    ),
     ($($t:tt)+) => (
         $crate::panicking::panic_fmt($crate::const_format_args!($($t)+))
     ),
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 02f32675247..a6aa4bf43c8 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -60,6 +60,13 @@ pub fn panic_str(expr: &str) -> ! {
     panic_fmt(format_args!("{}", expr));
 }
 
+#[inline]
+#[track_caller]
+#[cfg_attr(not(bootstrap), lang = "panic_display")] // needed for const-evaluated panics
+pub fn panic_display<T: fmt::Display>(x: &T) -> ! {
+    panic_fmt(format_args!("{}", *x));
+}
+
 #[cold]
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[track_caller]
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index ec9f0122950..8164ec56985 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -182,7 +182,7 @@ impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
     ///
     /// impl fmt::Display for AnError {
     ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f , "An error")
+    ///         write!(f, "An error")
     ///     }
     /// }
     ///
@@ -215,7 +215,7 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
     ///
     /// impl fmt::Display for AnError {
     ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f , "An error")
+    ///         write!(f, "An error")
     ///     }
     /// }
     ///
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 83c6ba0e6ea..f69baba9e73 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -234,6 +234,7 @@
 #![feature(atomic_mut_ptr)]
 #![feature(auto_traits)]
 #![feature(bench_black_box)]
+#![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(c_unwind)]
 #![feature(c_variadic)]
@@ -258,6 +259,7 @@
 #![feature(const_trait_impl)]
 #![feature(container_error_extra)]
 #![feature(core_intrinsics)]
+#![feature(core_panic)]
 #![feature(custom_test_frameworks)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs
index 9b7af97616c..9d18ccbeb24 100644
--- a/library/std/src/os/linux/fs.rs
+++ b/library/std/src/os/linux/fs.rs
@@ -1,4 +1,6 @@
-//! Linux-specific extensions to primitives in the `std::fs` module.
+//! Linux-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
 
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs
index e3e7143c851..540363c0349 100644
--- a/library/std/src/os/linux/process.rs
+++ b/library/std/src/os/linux/process.rs
@@ -1,4 +1,6 @@
-//! Linux-specific extensions to primitives in the `std::process` module.
+//! Linux-specific extensions to primitives in the [`std::process`] module.
+//!
+//! [`std::process`]: crate::process
 
 #![unstable(feature = "linux_pidfd", issue = "82971")]
 
diff --git a/library/std/src/os/unix/ffi/mod.rs b/library/std/src/os/unix/ffi/mod.rs
index c29df6596fd..5b49f50763d 100644
--- a/library/std/src/os/unix/ffi/mod.rs
+++ b/library/std/src/os/unix/ffi/mod.rs
@@ -1,4 +1,4 @@
-//! Unix-specific extension to the primitives in the `std::ffi` module.
+//! Unix-specific extensions to primitives in the [`std::ffi`] module.
 //!
 //! # Examples
 //!
@@ -31,6 +31,8 @@
 //! let bytes = os_str.as_bytes();
 //! assert_eq!(bytes, b"foo");
 //! ```
+//!
+//! [`std::ffi`]: crate::ffi
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 6cf37f23c57..0284a428b5d 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -1,10 +1,13 @@
-//! Unix-specific extensions to primitives in the `std::fs` module.
+//! Unix-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use super::platform::fs::MetadataExt as _;
 use crate::fs::{self, OpenOptions, Permissions};
 use crate::io;
+use crate::os::unix::io::{AsFd, AsRawFd};
 use crate::path::Path;
 use crate::sys;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
@@ -924,6 +927,75 @@ impl DirBuilderExt for fs::DirBuilder {
     }
 }
 
+/// Change the owner and group of the specified path.
+///
+/// Specifying either the uid or gid as `None` will leave it unchanged.
+///
+/// Changing the owner typically requires privileges, such as root or a specific capability.
+/// Changing the group typically requires either being the owner and a member of the group, or
+/// having privileges.
+///
+/// If called on a symbolic link, this will change the owner and group of the link target. To
+/// change the owner and group of the link itself, see [`lchown`].
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::chown("/sandbox", Some(0), Some(0))?;
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chown", issue = "88989")]
+pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+    sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the owner and group of the file referenced by the specified open file descriptor.
+///
+/// For semantics and required privileges, see [`chown`].
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     let f = std::fs::File::open("/file")?;
+///     fs::fchown(f, Some(0), Some(0))?;
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chown", issue = "88989")]
+pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+    sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the owner and group of the specified path, without dereferencing symbolic links.
+///
+/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
+/// and group of the link itself rather than the owner and group of the link target.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::lchown("/symlink", Some(0), Some(0))?;
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chown", issue = "88989")]
+pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+    sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
 /// Change the root directory of the current process to the specified path.
 ///
 /// This typically requires privileges, such as root or a specific capability.
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 17a02595724..62f750fa607 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -4,8 +4,8 @@
 //! exposes Unix-specific functions that would otherwise be inappropriate as
 //! part of the core `std` library.
 //!
-//! It exposes more ways to deal with platform-specific strings (`OsStr`,
-//! `OsString`), allows to set permissions more granularly, extract low-level
+//! It exposes more ways to deal with platform-specific strings ([`OsStr`],
+//! [`OsString`]), allows to set permissions more granularly, extract low-level
 //! file descriptors from files and sockets, and has platform-specific helpers
 //! for spawning processes.
 //!
@@ -24,6 +24,9 @@
 //!     Ok(())
 //! }
 //! ```
+//!
+//! [`OsStr`]: crate::ffi::OsStr
+//! [`OsString`]: crate::ffi::OsString
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![doc(cfg(unix))]
diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs
index d462bd4b5f7..8ce82208854 100644
--- a/library/std/src/os/unix/net/mod.rs
+++ b/library/std/src/os/unix/net/mod.rs
@@ -1,4 +1,4 @@
-//! Unix-specific networking functionality
+//! Unix-specific networking functionality.
 
 #![stable(feature = "unix_socket", since = "1.10.0")]
 
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 650dcbabbae..4d23805e479 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -1,4 +1,6 @@
-//! Unix-specific extensions to primitives in the `std::process` module.
+//! Unix-specific extensions to primitives in the [`std::process`] module.
+//!
+//! [`std::process`]: crate::process
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/unix/thread.rs b/library/std/src/os/unix/thread.rs
index 7221da1a9a7..03dcc3a4f9b 100644
--- a/library/std/src/os/unix/thread.rs
+++ b/library/std/src/os/unix/thread.rs
@@ -1,4 +1,6 @@
-//! Unix-specific extensions to primitives in the `std::thread` module.
+//! Unix-specific extensions to primitives in the [`std::thread`] module.
+//!
+//! [`std::thread`]: crate::thread
 
 #![stable(feature = "thread_extensions", since = "1.9.0")]
 
diff --git a/library/std/src/os/wasi/ffi.rs b/library/std/src/os/wasi/ffi.rs
index 17e12a395a6..41dd8702e98 100644
--- a/library/std/src/os/wasi/ffi.rs
+++ b/library/std/src/os/wasi/ffi.rs
@@ -1,4 +1,6 @@
-//! WASI-specific extension to the primitives in the `std::ffi` module
+//! WASI-specific extensions to primitives in the [`std::ffi`] module
+//!
+//! [`std::ffi`]: crate::ffi
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 3df27563e21..907368061d7 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -1,4 +1,6 @@
-//! WASI-specific extensions to primitives in the `std::fs` module.
+//! WASI-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
 
 #![deny(unsafe_op_in_unsafe_fn)]
 #![unstable(feature = "wasi_ext", issue = "71213")]
diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs
index d767c149dc5..bbaf328f457 100644
--- a/library/std/src/os/wasi/mod.rs
+++ b/library/std/src/os/wasi/mod.rs
@@ -24,6 +24,9 @@
 //!     Ok(())
 //! }
 //! ```
+//!
+//! [`OsStr`]: crate::ffi::OsStr
+//! [`OsString`]: crate::ffi::OsString
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs
index 8d29fa7d66f..a9493a94cac 100644
--- a/library/std/src/os/windows/ffi.rs
+++ b/library/std/src/os/windows/ffi.rs
@@ -1,4 +1,4 @@
-//! Windows-specific extensions to the primitives in the `std::ffi` module.
+//! Windows-specific extensions to primitives in the [`std::ffi`] module.
 //!
 //! # Overview
 //!
@@ -49,6 +49,7 @@
 //! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
 //! [`collect`]: crate::iter::Iterator::collect
 //! [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
+//! [`std::ffi`]: crate::ffi
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
index 71563a02dcb..be35ab0ca1e 100644
--- a/library/std/src/os/windows/fs.rs
+++ b/library/std/src/os/windows/fs.rs
@@ -1,4 +1,6 @@
-//! Windows-specific extensions for the primitives in the `std::fs` module.
+//! Windows-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs
index 969054dd3b3..52eb3b7c067 100644
--- a/library/std/src/os/windows/mod.rs
+++ b/library/std/src/os/windows/mod.rs
@@ -5,6 +5,22 @@
 //! the core `std` library. These extensions allow developers to use
 //! `std` types and idioms with Windows in a way that the normal
 //! platform-agnostic idioms would not normally support.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::windows::prelude::*;
+//!
+//! fn main() -> std::io::Result<()> {
+//!     let f = File::create("foo.txt")?;
+//!     let handle = f.as_raw_handle();
+//!
+//!     // use handle with native windows bindings
+//!
+//!     Ok(())
+//! }
+//! ```
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![doc(cfg(windows))]
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index b246599dfc0..9510d104806 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -1,4 +1,6 @@
-//! Extensions to `std::process` for Windows.
+//! Windows-specific extensions to primitives in the [`std::process`] module.
+//!
+//! [`std::process`]: crate::process
 
 #![stable(feature = "process_extensions", since = "1.2.0")]
 
diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs
index fb1bf66ceed..d81d6d0ac28 100644
--- a/library/std/src/os/windows/thread.rs
+++ b/library/std/src/os/windows/thread.rs
@@ -1,4 +1,6 @@
-//! Extensions to `std::thread` for Windows.
+//! Windows-specific extensions to primitives in the [`std::thread`] module.
+//!
+//! [`std::thread`]: crate::thread
 
 #![stable(feature = "thread_extensions", since = "1.9.0")]
 
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index c1c03958497..21e9669c110 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -10,7 +10,7 @@ use crate::thread::Result;
 
 #[doc(hidden)]
 #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
-#[allow_internal_unstable(libstd_sys_internals, const_format_args)]
+#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")]
 #[rustc_macro_transparency = "semitransparent"]
 pub macro panic_2015 {
@@ -20,6 +20,10 @@ pub macro panic_2015 {
     ($msg:expr $(,)?) => ({
         $crate::rt::begin_panic($msg)
     }),
+    // Special-case the single-argument case for const_panic.
+    ("{}", $arg:expr $(,)?) => ({
+        $crate::rt::panic_display(&$arg)
+    }),
     ($fmt:expr, $($arg:tt)+) => ({
         $crate::rt::begin_panic_fmt(&$crate::const_format_args!($fmt, $($arg)+))
     }),
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 72e6c23ee49..893167e3730 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -16,6 +16,7 @@
 
 // Re-export some of our utilities which are expected by other crates.
 pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
+pub use core::panicking::panic_display;
 
 // To reduce the generated code of the new `lang_start`, this function is doing
 // the real work.
@@ -59,10 +60,10 @@ fn lang_start<T: crate::process::Termination + 'static>(
     argc: isize,
     argv: *const *const u8,
 ) -> isize {
-    lang_start_internal(
+    let Ok(v) = lang_start_internal(
         &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(),
         argc,
         argv,
-    )
-    .into_ok()
+    );
+    v
 }
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 6d7524a733a..a4fff9b2e64 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1416,6 +1416,23 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     Ok(bytes_copied as u64)
 }
 
+pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
+    let path = cstr(path)?;
+    cvt(unsafe { libc::chown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })?;
+    Ok(())
+}
+
+pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> {
+    cvt(unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) })?;
+    Ok(())
+}
+
+pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
+    let path = cstr(path)?;
+    cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })?;
+    Ok(())
+}
+
 #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
 pub fn chroot(dir: &Path) -> io::Result<()> {
     let dir = cstr(dir)?;
diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs
index fa96b7abff6..198ae739b55 100644
--- a/library/std/src/time/monotonic.rs
+++ b/library/std/src/time/monotonic.rs
@@ -37,35 +37,36 @@ pub mod inner {
         // This could be a problem for programs that call instants at intervals greater
         // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
         let packed = (secs << 32) | nanos;
-        let old = mono.load(Relaxed);
-
-        if old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2 {
-            mono.store(packed, Relaxed);
-            raw
-        } else {
-            // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
-            // passed in value and the 64bits loaded from the atomic
-            let seconds_lower = old >> 32;
-            let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
-            if secs & 0xffff_ffff > seconds_lower {
-                // Backslide caused the lower 32bit of the seconds part to wrap.
-                // This must be the case because the seconds part is larger even though
-                // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
-                //
-                // We assume that backslides are smaller than 2^32 seconds
-                // which means we need to add 1 to the upper half to restore it.
-                //
-                // Example:
-                // most recent observed time: 0xA1_0000_0000_0000_0000u128
-                // bits stored in AtomicU64:     0x0000_0000_0000_0000u64
-                // backslide by 1s
-                // caller time is             0xA0_ffff_ffff_0000_0000u128
-                // -> we can fix up the upper half time by adding 1 << 32
-                seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
+        let updated = mono.fetch_update(Relaxed, Relaxed, |old| {
+            (old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2).then_some(packed)
+        });
+        match updated {
+            Ok(_) => raw,
+            Err(newer) => {
+                // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
+                // passed in value and the 64bits loaded from the atomic
+                let seconds_lower = newer >> 32;
+                let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
+                if secs & 0xffff_ffff > seconds_lower {
+                    // Backslide caused the lower 32bit of the seconds part to wrap.
+                    // This must be the case because the seconds part is larger even though
+                    // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
+                    //
+                    // We assume that backslides are smaller than 2^32 seconds
+                    // which means we need to add 1 to the upper half to restore it.
+                    //
+                    // Example:
+                    // most recent observed time: 0xA1_0000_0000_0000_0000u128
+                    // bits stored in AtomicU64:     0x0000_0000_0000_0000u64
+                    // backslide by 1s
+                    // caller time is             0xA0_ffff_ffff_0000_0000u128
+                    // -> we can fix up the upper half time by adding 1 << 32
+                    seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
+                }
+                let secs = seconds_upper | seconds_lower;
+                let nanos = newer as u32;
+                ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
             }
-            let secs = seconds_upper | seconds_lower;
-            let nanos = old as u32;
-            ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
         }
     }
 }
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index b7478d83955..af3774b7c75 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -537,7 +537,7 @@ impl Step for Rustc {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.krate("rustc-main").default_condition(builder.config.docs)
+        run.krate("rustc-main").path("compiler").default_condition(builder.config.docs)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -553,9 +553,24 @@ impl Step for Rustc {
     fn run(self, builder: &Builder<'_>) {
         let stage = self.stage;
         let target = self.target;
+        let mut is_explicit_request = false;
         builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
 
-        if !builder.config.compiler_docs {
+        let paths = builder
+            .paths
+            .iter()
+            .map(components_simplified)
+            .filter_map(|path| {
+                if path.get(0) == Some(&"compiler") {
+                    is_explicit_request = true;
+                    path.get(1).map(|p| p.to_owned())
+                } else {
+                    None
+                }
+            })
+            .collect::<Vec<_>>();
+
+        if !builder.config.compiler_docs && !is_explicit_request {
             builder.info("\tskipping - compiler/librustdoc docs disabled");
             return;
         }
@@ -604,26 +619,54 @@ impl Step for Rustc {
         cargo.rustdocflag("--extern-html-root-url");
         cargo.rustdocflag("ena=https://docs.rs/ena/latest/");
 
-        // Find dependencies for top level crates.
         let mut compiler_crates = HashSet::new();
-        for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
-            compiler_crates.extend(
-                builder
-                    .in_tree_crates(root_crate, Some(target))
-                    .into_iter()
-                    .map(|krate| krate.name),
-            );
+
+        if paths.is_empty() {
+            // Find dependencies for top level crates.
+            for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
+                compiler_crates.extend(
+                    builder
+                        .in_tree_crates(root_crate, Some(target))
+                        .into_iter()
+                        .map(|krate| krate.name),
+                );
+            }
+        } else {
+            for root_crate in paths {
+                if !builder.src.join("compiler").join(&root_crate).exists() {
+                    builder.info(&format!(
+                        "\tskipping - compiler/{} (unknown compiler crate)",
+                        root_crate
+                    ));
+                } else {
+                    compiler_crates.extend(
+                        builder
+                            .in_tree_crates(root_crate, Some(target))
+                            .into_iter()
+                            .map(|krate| krate.name),
+                    );
+                }
+            }
         }
 
+        let mut to_open = None;
         for krate in &compiler_crates {
             // Create all crate output directories first to make sure rustdoc uses
             // relative links.
             // FIXME: Cargo should probably do this itself.
             t!(fs::create_dir_all(out_dir.join(krate)));
             cargo.arg("-p").arg(krate);
+            if to_open.is_none() {
+                to_open = Some(krate);
+            }
         }
 
         builder.run(&mut cargo.into());
+        // Let's open the first crate documentation page:
+        if let Some(krate) = to_open {
+            let index = out.join(krate).join("index.html");
+            open(builder, &index);
+        }
     }
 }
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index d86b3b785d1..765c77d5646 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -329,18 +329,14 @@ crate fn run_global_ctxt(
 
     // NOTE: This is copy/pasted from typeck/lib.rs and should be kept in sync with those changes.
     tcx.sess.time("item_types_checking", || {
-        for &module in tcx.hir().krate().modules.keys() {
-            tcx.ensure().check_mod_item_types(module);
-        }
+        tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
     });
     tcx.sess.abort_if_errors();
     tcx.sess.time("missing_docs", || {
         rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
     });
     tcx.sess.time("check_mod_attrs", || {
-        for &module in tcx.hir().krate().modules.keys() {
-            tcx.ensure().check_mod_attrs(module);
-        }
+        tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module))
     });
     rustc_passes::stability::check_unused_or_stable_features(tcx);
 
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 1dd0917699b..c1a83ad5820 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -268,10 +268,18 @@ pub(super) fn write_shared(
     // Maybe we can change the representation to move this out of main.js?
     write_minify(
         "main.js",
-        static_files::MAIN_JS.replace(
-            "/* INSERT THEMES HERE */",
-            &format!(" = {}", serde_json::to_string(&themes).unwrap()),
-        ),
+        static_files::MAIN_JS
+            .replace(
+                "/* INSERT THEMES HERE */",
+                &format!(" = {}", serde_json::to_string(&themes).unwrap()),
+            )
+            .replace(
+                "/* INSERT RUSTDOC_VERSION HERE */",
+                &format!(
+                    "rustdoc {}",
+                    rustc_interface::util::version_str().unwrap_or("unknown version")
+                ),
+            ),
         cx,
         options,
     )?;
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 2d4bfc62af6..eb7cc9309f4 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -928,15 +928,24 @@ body.blur > :not(#help) {
 	display: block;
 	margin-right: 0.5rem;
 }
-#help > div > span {
+#help span.top, #help span.bottom {
 	text-align: center;
 	display: block;
-	margin: 10px 0;
 	font-size: 18px;
-	border-bottom: 1px solid #ccc;
+
+}
+#help span.top {
+	text-align: center;
+	display: block;
+	margin: 10px 0;
+	border-bottom: 1px solid;
 	padding-bottom: 4px;
 	margin-bottom: 6px;
 }
+#help span.bottom {
+	clear: both;
+	border-top: 1px solid;
+}
 #help dd { margin: 5px 35px; }
 #help .infos { padding-left: 0; }
 #help h1, #help h2 { margin-top: 0; }
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index eada8f4a04d..c79801e8308 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -286,8 +286,8 @@ details.undocumented > summary::before {
 	border-radius: 4px;
 }
 
-#help > div > span {
-	border-bottom-color: #5c6773;
+#help span.bottom, #help span.top {
+	border-color: #5c6773;
 }
 
 .since {
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index d9348be6994..d2e54070acd 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -242,8 +242,8 @@ details.undocumented > summary::before {
 	border-color: #bfbfbf;
 }
 
-#help > div > span {
-	border-bottom-color: #bfbfbf;
+#help span.bottom, #help span.top {
+	border-color: #bfbfbf;
 }
 
 #help dt {
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 0ffe5929ea5..25d810560c1 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -232,8 +232,8 @@ details.undocumented > summary::before {
 	border-color: #bfbfbf;
 }
 
-#help > div > span {
-	border-bottom-color: #bfbfbf;
+#help span.bottom, #help span.top {
+	border-color: #bfbfbf;
 }
 
 .since {
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 1eebd392564..e396fd9d288 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -911,6 +911,7 @@ function hideThemeButtonState() {
         });
 
         var book_info = document.createElement("span");
+        book_info.className = "top";
         book_info.innerHTML = "You can find more information in \
             <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
 
@@ -961,6 +962,14 @@ function hideThemeButtonState() {
         container.appendChild(div_shortcuts);
         container.appendChild(div_infos);
 
+        var rustdoc_version = document.createElement("span");
+        rustdoc_version.className = "bottom";
+        var rustdoc_version_code = document.createElement("code");
+        rustdoc_version_code.innerText = "/* INSERT RUSTDOC_VERSION HERE */";
+        rustdoc_version.appendChild(rustdoc_version_code);
+
+        container.appendChild(rustdoc_version);
+
         popup.appendChild(container);
         insertAfter(popup, searchState.outputElement());
         // So that it's only built once and then it'll do nothing when called!
diff --git a/src/test/debuginfo/basic-types.rs b/src/test/debuginfo/basic-types.rs
index d300e374bec..c8879856b96 100644
--- a/src/test/debuginfo/basic-types.rs
+++ b/src/test/debuginfo/basic-types.rs
@@ -9,10 +9,6 @@
 // This fails on lldb 6.0.1 on x86-64 Fedora 28; so ignore Linux for now.
 // ignore-linux
 
-// This started failing in windows too. See https://github.com/rust-lang/rust/issues/88796
-// FIXME: fix and unignore this on windows
-// ignore-windows
-
 // compile-flags:-g
 
 // === GDB TESTS ===================================================================================
@@ -132,8 +128,9 @@
 // cdb-command:dx f64
 // cdb-check:f64              : 3.500000 [Type: double]
 // cdb-command:.enable_unicode 1
+// FIXME(#88840): The latest version of the Windows SDK broke the visualizer for str.
 // cdb-command:dx  s
-// cdb-check:s                : "Hello, World!" [Type: str]
+// cdb-check:s                : [...] [Type: str]
 
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs
index 67b5da510f8..642694355ad 100644
--- a/src/test/debuginfo/msvc-pretty-enums.rs
+++ b/src/test/debuginfo/msvc-pretty-enums.rs
@@ -1,67 +1,45 @@
 // only-cdb
-// ignore-tidy-linelength
 // compile-flags:-g
 
-// This started failing recently. See https://github.com/rust-lang/rust/issues/88796
-// FIXME: fix and unignore this
-// ignore-windows
-
 // cdb-command: g
 
-// Note: The natvis used to visualize niche-layout enums don't work correctly in cdb
-//       so the best we can do is to make sure we are generating the right debuginfo.
-//       Therefore, we use the `!` [format specifier](https://docs.microsoft.com/en-us/visualstudio/debugger/format-specifiers-in-cpp?view=vs-2019#BKMK_Visual_Studio_2012_format_specifiers)
-//       to disable the natvis for a given expression. We also provide the `-r2` flag
-//       to expand the expression 2 levels.
-
-// cdb-command: dx -r2 a,!
-// cdb-check:a,!              [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>]
-// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>::Some]
-// cdb-check:        [+0x000] __0              : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
-// cdb-check:    [+0x000] discriminant     : 0x2 [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>::Discriminant$]
-
-// cdb-command: dx -r2 b,!
-// cdb-check:b,!              [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>]
-// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>::Some]
-// cdb-check:        [+0x000] __0              : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
-// cdb-check:    [+0x000] discriminant     : None (0x11) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>::Discriminant$]
-
-// cdb-command: dx -r2 c,!
-// cdb-check:c,!              [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
-// cdb-check:    [+0x000] dataful_variant  [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
-// cdb-check:        [+0x000] my_data          : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
-// cdb-check:    [+0x000] discriminant     : Tag1 (0x11) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
-
-// cdb-command: dx -r2 d,!
-// cdb-check:d,!              [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
-// cdb-check:    [+0x000] dataful_variant  [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
-// cdb-check:        [+0x000] my_data          : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
-// cdb-check:    [+0x000] discriminant     : 0x10 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
-
-// cdb-command: dx -r2 e,!
-// cdb-check:e,!              [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
-// cdb-check:    [+0x000] dataful_variant  [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
-// cdb-check:        [+0x000] my_data          : 0x13 [Type: msvc_pretty_enums::CStyleEnum]
-// cdb-check:    [+0x000] discriminant     : Tag2 (0x13) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
-
-// cdb-command: dx -r2 f,!
-// cdb-check:f,!              [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
-// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>::Some]
-// cdb-check:        [+0x000] __0              : 0x[...] : 0x1 [Type: unsigned int *]
-// cdb-check:    [+0x000] discriminant     : 0x[...] [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>::Discriminant$]
-
-// cdb-command: dx -r2 g,!
-// cdb-check:g,!              [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
-// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>::Some]
-// cdb-check:        [+0x000] __0              : 0x0 [Type: unsigned int *]
-// cdb-check:    [+0x000] discriminant     : None (0x0) [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>::Discriminant$]
-
-// cdb-command: dx -r2 h,!
-// cdb-check:h,!              : Some [Type: enum$<core::option::Option<u32> >]
-// cdb-check:    [+0x000] variant0         [Type: enum$<core::option::Option<u32> >::None]
-// cdb-check:    [+0x000] variant1         [Type: enum$<core::option::Option<u32> >::Some]
-// cdb-check:        [+0x004] __0              : 0xc [Type: unsigned int]
-// cdb-check:    [+0x000] discriminant     : Some (0x1) [Type: core::option::Option]
+// cdb-command: dx a
+// cdb-check:a                :  Some({...}) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>]
+// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>]
+// cdb-check:    [variant]        :  Some
+// cdb-check:    [+0x000] __0              : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
+
+// cdb-command: dx b
+// cdb-check:b                : None [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>]
+// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>]
+// cdb-check:    [variant]        : None
+
+// cdb-command: dx c
+// cdb-check:c                : Tag1 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [<Raw View>]     [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [variant]        : Tag1
+
+// cdb-command: dx d
+// cdb-check:d                :  Data({...}) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [<Raw View>]     [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [variant]        :  Data
+// cdb-check:    [+0x000] my_data          : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
+
+// cdb-command: dx e
+// cdb-check:e                : Tag2 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [<Raw View>]     [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [variant]        : Tag2
+
+// cdb-command: dx f
+// cdb-check:f                :  Some({...}) [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
+// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
+// cdb-check:    [variant]        :  Some
+// cdb-check:    [+0x000] __0              : 0x[...] : 0x1 [Type: unsigned int *]
+
+// cdb-command: dx g
+// cdb-check:g                : None [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
+// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
+// cdb-check:    [variant]        : None
 
 // cdb-command: dx h
 // cdb-check:h                : Some [Type: enum$<core::option::Option<u32> >]
@@ -69,13 +47,6 @@
 // cdb-check:    [variant]        : Some
 // cdb-check:    [+0x004] __0              : 0xc [Type: unsigned int]
 
-// cdb-command: dx -r2 i,!
-// cdb-check:i,!              : None [Type: enum$<core::option::Option<u32> >]
-// cdb-check:    [+0x000] variant0         [Type: enum$<core::option::Option<u32> >::None]
-// cdb-check:    [+0x000] variant1         [Type: enum$<core::option::Option<u32> >::Some]
-// cdb-check:        [+0x004] __0              : 0x[...] [Type: unsigned int]
-// cdb-check:    [+0x000] discriminant     : None (0x0) [Type: core::option::Option]
-
 // cdb-command: dx i
 // cdb-check:i                : None [Type: enum$<core::option::Option<u32> >]
 // cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<u32> >]
@@ -84,16 +55,17 @@
 // cdb-command: dx j
 // cdb-check:j                : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
 
-// cdb-command: dx -r2 k,!
-// cdb-check:k,!              [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
-// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Some]
-// cdb-check:        [+0x000] __0              [Type: alloc::string::String]
-// cdb-check:    [+0x000] discriminant     : 0x[...] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Discriminant$]
-
-// cdb-command: dx -r2 l,!
-// cdb-check:l,!              : $T2 [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>]
-// cdb-check:    [+0x000] Ok               [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>::Ok]
-// cdb-check:        [+0x000] __0              : 0x2a [Type: unsigned int]
+// cdb-command: dx k
+// cdb-check:k                :  Some({...}) [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
+// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
+// cdb-check:    [variant]        :  Some
+// cdb-check:    [+0x000] __0              : "IAMA optional string!" [Type: alloc::string::String]
+
+// cdb-command: dx l
+// cdb-check:l                :  Ok [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>]
+// cdb-check:    [<Raw View>]     [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>]
+// cdb-check:    [variant]        :  Ok
+// cdb-check:    [+0x000] __0              : 0x2a [Type: unsigned int]
 
 pub enum CStyleEnum {
     Low = 2,
diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs
index cb2e6c618b1..55a4ecc1c1a 100644
--- a/src/test/debuginfo/pretty-std.rs
+++ b/src/test/debuginfo/pretty-std.rs
@@ -6,10 +6,6 @@
 // min-lldb-version: 310
 // min-cdb-version: 10.0.18317.1001
 
-// This started failing recently. See https://github.com/rust-lang/rust/issues/88796
-// FIXME: fix and unignore this
-// ignore-windows
-
 // === GDB TESTS ===================================================================================
 
 // gdb-command: run
@@ -115,9 +111,11 @@
 // cdb-check:    [11]             : 33 '!' [Type: char]
 
 // cdb-command: dx os_string
-// cdb-check:os_string        : "IAMA OS string 😃" [Type: std::ffi::os_str::OsString]
+// NOTE: OSString is WTF-8 encoded which Windows debuggers don't understand. Verify the UTF-8
+//       portion displays correctly.
+// cdb-check:os_string        : "IAMA OS string [...]" [Type: std::ffi::os_str::OsString]
 // cdb-check:    [<Raw View>]     [Type: std::ffi::os_str::OsString]
-// cdb-check:    [chars]          : "IAMA OS string 😃"
+// cdb-check:    [chars]          : "IAMA OS string [...]"
 
 // cdb-command: dx some
 // cdb-check:some             : Some [Type: enum$<core::option::Option<i16> >]
@@ -131,8 +129,10 @@
 // cdb-check:    [variant]        : None
 
 // cdb-command: dx some_string
-// NOTE: cdb fails to interpret debug info of Option enums on i686.
-// cdb-check:some_string      [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
+// cdb-check:some_string      :  Some({...}) [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
+// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
+// cdb-check:    [variant]        :  Some
+// cdb-check:    [+0x000] __0              : "IAMA optional string!" [Type: alloc::string::String]
 
 // cdb-command: dx linkedlist
 // cdb-check:linkedlist       : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList<i32>]
diff --git a/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot b/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot
index eeedbb215c0..ca0eb7e845a 100644
--- a/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot
+++ b/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot
@@ -2,10 +2,12 @@ digraph Cov_0_3 {
     graph [fontname="Courier, monospace"];
     node [fontname="Courier, monospace"];
     edge [fontname="Courier, monospace"];
-    bcb2__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb0 - bcb1) at 13:10-13:10<br/>    13:10-13:10: @4[0]: Coverage::Expression(4294967295) = 1 - 2 for $DIR/coverage_graphviz.rs:13:10 - 13:11</td></tr><tr><td align="left" balign="left">bb4: Goto</td></tr></table>>];
-    bcb1__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb1</td></tr><tr><td align="left" balign="left">Counter(bcb1) at 12:13-12:18<br/>    12:13-12:18: @3[0]: Coverage::Expression(4294967294) = 2 + 0 for $DIR/coverage_graphviz.rs:15:1 - 15:2<br/>Expression(bcb1 + 0) at 15:2-15:2<br/>    15:2-15:2: @3.Return: return</td></tr><tr><td align="left" balign="left">bb3: Return</td></tr></table>>];
-    bcb0__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 9:1-11:17<br/>    11:12-11:17: @1.Call: _2 = bar() -&gt; [return: bb2, unwind: bb5]</td></tr><tr><td align="left" balign="left">bb0: FalseUnwind<br/>bb1: Call</td></tr><tr><td align="left" balign="left">bb2: SwitchInt</td></tr></table>>];
-    bcb2__Cov_0_3 -> bcb0__Cov_0_3 [label=<>];
-    bcb0__Cov_0_3 -> bcb2__Cov_0_3 [label=<false>];
-    bcb0__Cov_0_3 -> bcb1__Cov_0_3 [label=<otherwise>];
+    bcb3__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb3</td></tr><tr><td align="left" balign="left">Counter(bcb3) at 13:10-13:10<br/>    13:10-13:10: @5[0]: Coverage::Counter(2) for $DIR/coverage_graphviz.rs:13:10 - 13:11</td></tr><tr><td align="left" balign="left">bb5: Goto</td></tr></table>>];
+    bcb2__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb1:(bcb0 + bcb3) - bcb3) at 12:13-12:18<br/>    12:13-12:18: @4[0]: Coverage::Expression(4294967293) = 4294967294 + 0 for $DIR/coverage_graphviz.rs:15:1 - 15:2<br/>Expression(bcb2:(bcb1:(bcb0 + bcb3) - bcb3) + 0) at 15:2-15:2<br/>    15:2-15:2: @4.Return: return</td></tr><tr><td align="left" balign="left">bb4: Return</td></tr></table>>];
+    bcb1__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb1</td></tr><tr><td align="left" balign="left">Expression(bcb0 + bcb3) at 10:5-11:17<br/>    11:12-11:17: @2.Call: _2 = bar() -&gt; [return: bb3, unwind: bb6]</td></tr><tr><td align="left" balign="left">bb1: FalseUnwind<br/>bb2: Call</td></tr><tr><td align="left" balign="left">bb3: SwitchInt</td></tr></table>>];
+    bcb0__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 9:1-9:11<br/>    </td></tr><tr><td align="left" balign="left">bb0: Goto</td></tr></table>>];
+    bcb3__Cov_0_3 -> bcb1__Cov_0_3 [label=<>];
+    bcb1__Cov_0_3 -> bcb3__Cov_0_3 [label=<false>];
+    bcb1__Cov_0_3 -> bcb2__Cov_0_3 [label=<otherwise>];
+    bcb0__Cov_0_3 -> bcb1__Cov_0_3 [label=<>];
 }
diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
index e2fad5b60eb..f810beeeee3 100644
--- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
+++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
@@ -47,7 +47,7 @@
 +         _4 = &_2;                        // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
 +         StorageLive(_9);                 // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
 +         _9 = const ();                   // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
-+         goto -> bb1;                     // scope 4 at $DIR/inline-diverging.rs:22:5: 22:22
++         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:22:5: 22:22
       }
   
       bb1: {
diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
index 3539fc8b487..34ba7dfdcc5 100644
--- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
+++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
@@ -8,38 +8,43 @@
       let mut _3: !;                       // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10
   
       bb0: {
-+         Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
-          falseUnwind -> [real: bb1, cleanup: bb5]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
++         Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 10:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
+          goto -> bb1;                     // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
       }
   
       bb1: {
++         Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:11:5 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
+          falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
+      }
+  
+      bb2: {
           StorageLive(_2);                 // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
-          _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
+          _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
                                            // mir::Constant
                                            // + span: /the/src/instrument_coverage.rs:12:12: 12:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb2: {
-          switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
+      bb3: {
+          switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
       }
   
-      bb3: {
-+         Coverage::Expression(4294967294) = 2 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2
-+         Coverage::Counter(2) for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2
+      bb4: {
++         Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2
++         Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2
           _0 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18
           StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:14:9: 14:10
           return;                          // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2
       }
   
-      bb4: {
-+         Coverage::Expression(4294967295) = 1 - 2 for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
+      bb5: {
++         Coverage::Counter(2) for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
           _1 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:14:10: 14:10
           StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:14:9: 14:10
-          goto -> bb0;                     // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
+          goto -> bb1;                     // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
       }
   
-      bb5 (cleanup): {
+      bb6 (cleanup): {
           resume;                          // scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2
       }
   }
diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
index eac9328500d..1c5a8900236 100644
--- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
+++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
@@ -8,40 +8,44 @@
       let mut _3: !;                       // in scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10
   
       bb0: {
--         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
+          goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
+      }
+  
+      bb1: {
+-         goto -> bb2;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
 -     }
 - 
--     bb1: {
+-     bb2: {
           StorageLive(_2);                 // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
--         _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
-+         _2 = bar() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
+-         _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
++         _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
                                            // mir::Constant
                                            // + span: $DIR/simplify_cfg.rs:9:12: 9:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
--     bb2: {
--         switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
-+     bb1: {
-+         switchInt(move _2) -> [false: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
-      }
-  
 -     bb3: {
+-         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
 +     bb2: {
++         switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
+      }
+  
+-     bb4: {
++     bb3: {
           _0 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18
           StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10
           return;                          // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2
       }
   
--     bb4: {
-+     bb3: {
+-     bb5: {
++     bb4: {
           _1 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:11:10: 11:10
           StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10
-          goto -> bb0;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
+          goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
       }
   
--     bb5 (cleanup): {
-+     bb4 (cleanup): {
+-     bb6 (cleanup): {
++     bb5 (cleanup): {
           resume;                          // scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2
       }
   }
diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
index f5ac2a41f5f..b079bd7b57c 100644
--- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
+++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
@@ -8,38 +8,35 @@
       let mut _3: !;                       // in scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10
   
       bb0: {
--         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
-+         falseUnwind -> [real: bb1, cleanup: bb5]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
+          goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
       }
   
       bb1: {
 -         falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
--     }
-- 
--     bb2: {
++         falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
+      }
+  
+      bb2: {
           StorageLive(_2);                 // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
 -         _2 = bar() -> [return: bb3, unwind: bb11]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
-+         _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
++         _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
                                            // mir::Constant
                                            // + span: $DIR/simplify_cfg.rs:9:12: 9:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
--     bb3: {
--         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
-+     bb2: {
-+         switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
+      bb3: {
+          switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
       }
   
--     bb4: {
-+     bb3: {
+      bb4: {
           _0 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18
 -         goto -> bb10;                    // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18
 +         StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10
 +         return;                          // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2
       }
   
--     bb5: {
+      bb5: {
 -         goto -> bb8;                     // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
 -     }
 - 
@@ -52,15 +49,13 @@
 -     }
 - 
 -     bb8: {
-+     bb4: {
           _1 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:11:10: 11:10
 -         goto -> bb9;                     // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10
 -     }
 - 
 -     bb9: {
           StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10
--         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
-+         goto -> bb0;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
+          goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
       }
   
 -     bb10: {
@@ -69,7 +64,7 @@
 -     }
 - 
 -     bb11 (cleanup): {
-+     bb5 (cleanup): {
++     bb6 (cleanup): {
           resume;                          // scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2
       }
   }
diff --git a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
index 9db77d705ff..ec2d161251b 100644
--- a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
+++ b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
@@ -9,51 +9,55 @@ fn while_loop(_1: bool) -> () {
     let mut _5: bool;                    // in scope 0 at $DIR/while-storage.rs:11:21: 11:22
 
     bb0: {
+        goto -> bb1;                     // scope 0 at $DIR/while-storage.rs:10:5: 14:6
+    }
+
+    bb1: {
         StorageLive(_2);                 // scope 0 at $DIR/while-storage.rs:10:11: 10:22
         StorageLive(_3);                 // scope 0 at $DIR/while-storage.rs:10:20: 10:21
         _3 = _1;                         // scope 0 at $DIR/while-storage.rs:10:20: 10:21
-        _2 = get_bool(move _3) -> bb1;   // scope 0 at $DIR/while-storage.rs:10:11: 10:22
+        _2 = get_bool(move _3) -> bb2;   // scope 0 at $DIR/while-storage.rs:10:11: 10:22
                                          // mir::Constant
                                          // + span: $DIR/while-storage.rs:10:11: 10:19
                                          // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1: {
+    bb2: {
         StorageDead(_3);                 // scope 0 at $DIR/while-storage.rs:10:21: 10:22
-        switchInt(move _2) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/while-storage.rs:10:11: 10:22
+        switchInt(move _2) -> [false: bb7, otherwise: bb3]; // scope 0 at $DIR/while-storage.rs:10:11: 10:22
     }
 
-    bb2: {
+    bb3: {
         StorageLive(_4);                 // scope 0 at $DIR/while-storage.rs:11:12: 11:23
         StorageLive(_5);                 // scope 0 at $DIR/while-storage.rs:11:21: 11:22
         _5 = _1;                         // scope 0 at $DIR/while-storage.rs:11:21: 11:22
-        _4 = get_bool(move _5) -> bb3;   // scope 0 at $DIR/while-storage.rs:11:12: 11:23
+        _4 = get_bool(move _5) -> bb4;   // scope 0 at $DIR/while-storage.rs:11:12: 11:23
                                          // mir::Constant
                                          // + span: $DIR/while-storage.rs:11:12: 11:20
                                          // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb3: {
+    bb4: {
         StorageDead(_5);                 // scope 0 at $DIR/while-storage.rs:11:22: 11:23
-        switchInt(move _4) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/while-storage.rs:11:12: 11:23
+        switchInt(move _4) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/while-storage.rs:11:12: 11:23
     }
 
-    bb4: {
+    bb5: {
         StorageDead(_4);                 // scope 0 at $DIR/while-storage.rs:13:9: 13:10
-        goto -> bb7;                     // scope 0 at no-location
+        goto -> bb8;                     // scope 0 at no-location
     }
 
-    bb5: {
+    bb6: {
         StorageDead(_4);                 // scope 0 at $DIR/while-storage.rs:13:9: 13:10
         StorageDead(_2);                 // scope 0 at $DIR/while-storage.rs:14:5: 14:6
-        goto -> bb0;                     // scope 0 at $DIR/while-storage.rs:10:5: 14:6
+        goto -> bb1;                     // scope 0 at $DIR/while-storage.rs:10:5: 14:6
     }
 
-    bb6: {
-        goto -> bb7;                     // scope 0 at no-location
+    bb7: {
+        goto -> bb8;                     // scope 0 at no-location
     }
 
-    bb7: {
+    bb8: {
         StorageDead(_2);                 // scope 0 at $DIR/while-storage.rs:14:5: 14:6
         return;                          // scope 0 at $DIR/while-storage.rs:15:2: 15:2
     }
diff --git a/src/test/ui/async-await/issue-76547.nll.stderr b/src/test/ui/async-await/issue-76547.nll.stderr
index 2456d6a1474..0ac2a396669 100644
--- a/src/test/ui/async-await/issue-76547.nll.stderr
+++ b/src/test/ui/async-await/issue-76547.nll.stderr
@@ -1,20 +1,22 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-76547.rs:19:14
+  --> $DIR/issue-76547.rs:20:13
    |
 LL | async fn fut(bufs: &mut [&mut [u8]]) {
-   |              ^^^^  -     - let's call the lifetime of this reference `'2`
-   |              |     |
-   |              |     let's call the lifetime of this reference `'1`
-   |              assignment requires that `'1` must outlive `'2`
+   |                    -     - let's call the lifetime of this reference `'2`
+   |                    |
+   |                    let's call the lifetime of this reference `'1`
+LL |     ListFut(bufs).await
+   |             ^^^^ this usage requires that `'1` must outlive `'2`
 
 error: lifetime may not live long enough
-  --> $DIR/issue-76547.rs:33:15
+  --> $DIR/issue-76547.rs:34:14
    |
 LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
-   |               ^^^^  -     - let's call the lifetime of this reference `'2`
-   |               |     |
-   |               |     let's call the lifetime of this reference `'1`
-   |               assignment requires that `'1` must outlive `'2`
+   |                     -     - let's call the lifetime of this reference `'2`
+   |                     |
+   |                     let's call the lifetime of this reference `'1`
+LL |     ListFut2(bufs).await
+   |              ^^^^ this usage requires that `'1` must outlive `'2`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-in-static.stderr b/src/test/ui/borrowck/borrowck-in-static.stderr
index f73c787346d..30e74c5ec95 100644
--- a/src/test/ui/borrowck/borrowck-in-static.stderr
+++ b/src/test/ui/borrowck/borrowck-in-static.stderr
@@ -4,7 +4,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
 LL |     let x = Box::new(0);
    |         - captured outer variable
 LL |     Box::new(|| x)
-   |                 ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |              ---^
+   |              |  |
+   |              |  move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |              captured by this `Fn` closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr
index 628f206e0a8..05489cf18e7 100644
--- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr
+++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr
@@ -1,15 +1,18 @@
 error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure
   --> $DIR/borrowck-move-by-capture.rs:9:29
    |
-LL |     let bar: Box<_> = box 3;
-   |         --- captured outer variable
-LL |     let _g = to_fn_mut(|| {
-LL |         let _h = to_fn_once(move || -> isize { *bar });
-   |                             ^^^^^^^^^^^^^^^^   ----
-   |                             |                  |
-   |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
-   |                             |                  move occurs due to use in closure
-   |                             move out of `bar` occurs here
+LL |       let bar: Box<_> = box 3;
+   |           --- captured outer variable
+LL |       let _g = to_fn_mut(|| {
+   |  ________________________-
+LL | |         let _h = to_fn_once(move || -> isize { *bar });
+   | |                             ^^^^^^^^^^^^^^^^   ----
+   | |                             |                  |
+   | |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
+   | |                             |                  move occurs due to use in closure
+   | |                             move out of `bar` occurs here
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-87456-point-to-closure.rs b/src/test/ui/borrowck/issue-87456-point-to-closure.rs
new file mode 100644
index 00000000000..9fc12ba7490
--- /dev/null
+++ b/src/test/ui/borrowck/issue-87456-point-to-closure.rs
@@ -0,0 +1,14 @@
+// Regression test for #87456.
+
+fn take_mut(_val: impl FnMut()) {}
+
+fn main() {
+    let val = String::new();
+    //~^ NOTE: captured outer variable
+    take_mut(|| {
+    //~^ NOTE: captured by this `FnMut` closure
+        let _foo: String = val;
+        //~^ ERROR: cannot move out of `val`, a captured variable in an `FnMut` closure [E0507]
+        //~| NOTE: move occurs because
+    })
+}
diff --git a/src/test/ui/borrowck/issue-87456-point-to-closure.stderr b/src/test/ui/borrowck/issue-87456-point-to-closure.stderr
new file mode 100644
index 00000000000..fd38ad7bb0a
--- /dev/null
+++ b/src/test/ui/borrowck/issue-87456-point-to-closure.stderr
@@ -0,0 +1,22 @@
+error[E0507]: cannot move out of `val`, a captured variable in an `FnMut` closure
+  --> $DIR/issue-87456-point-to-closure.rs:10:28
+   |
+LL |       let val = String::new();
+   |           --- captured outer variable
+LL |
+LL |       take_mut(|| {
+   |  ______________-
+LL | |
+LL | |         let _foo: String = val;
+   | |                            ^^^
+   | |                            |
+   | |                            move occurs because `val` has type `String`, which does not implement the `Copy` trait
+   | |                            help: consider borrowing here: `&val`
+LL | |
+LL | |
+LL | |     })
+   | |_____- captured by this `FnMut` closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
index dbba33f0183..1663ce81d6c 100644
--- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
+++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
@@ -1,11 +1,15 @@
 error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure
   --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9
    |
-LL |     let y = vec![format!("World")];
-   |         - captured outer variable
-LL |     call(|| {
-LL |         y.into_iter();
-   |         ^ move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
+LL |       let y = vec![format!("World")];
+   |           - captured outer variable
+LL |       call(|| {
+   |  __________-
+LL | |         y.into_iter();
+   | |         ^ move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
+LL | |
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-87493.rs b/src/test/ui/const-generics/issues/issue-87493.rs
new file mode 100644
index 00000000000..d8599ab22a3
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-87493.rs
@@ -0,0 +1,14 @@
+pub trait MyTrait {
+    type Assoc;
+}
+
+pub fn foo<S, T>(_s: S, _t: T)
+where
+    S: MyTrait,
+    T: MyTrait<Assoc == S::Assoc>,
+    //~^ ERROR: expected one of `,` or `>`, found `==`
+    //~| ERROR: this trait takes 0 generic arguments but 1 generic argument was supplied
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-87493.stderr b/src/test/ui/const-generics/issues/issue-87493.stderr
new file mode 100644
index 00000000000..8f92eeaffd1
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-87493.stderr
@@ -0,0 +1,28 @@
+error: expected one of `,` or `>`, found `==`
+  --> $DIR/issue-87493.rs:8:22
+   |
+LL |     T: MyTrait<Assoc == S::Assoc>,
+   |                      ^^ expected one of `,` or `>`
+   |
+help: if you meant to use an associated type binding, replace `==` with `=`
+   |
+LL |     T: MyTrait<Assoc = S::Assoc>,
+   |                      ~
+
+error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-87493.rs:8:8
+   |
+LL |     T: MyTrait<Assoc == S::Assoc>,
+   |        ^^^^^^^------------------- help: remove these generics
+   |        |
+   |        expected 0 generic arguments
+   |
+note: trait defined here, with 0 generic parameters
+  --> $DIR/issue-87493.rs:1:11
+   |
+LL | pub trait MyTrait {
+   |           ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs
index e4455d86a14..100faded079 100644
--- a/src/test/ui/consts/const-eval/const_panic.rs
+++ b/src/test/ui/consts/const-eval/const_panic.rs
@@ -15,10 +15,13 @@ const Y: () = std::unreachable!();
 
 const X: () = std::unimplemented!();
 //~^ ERROR evaluation of constant value failed
-//
+
 const W: () = std::panic!(MSG);
 //~^ ERROR evaluation of constant value failed
 
+const W2: () = std::panic!("{}", MSG);
+//~^ ERROR evaluation of constant value failed
+
 const Z_CORE: () = core::panic!("cheese");
 //~^ ERROR evaluation of constant value failed
 
@@ -33,3 +36,6 @@ const X_CORE: () = core::unimplemented!();
 
 const W_CORE: () = core::panic!(MSG);
 //~^ ERROR evaluation of constant value failed
+
+const W2_CORE: () = core::panic!("{}", MSG);
+//~^ ERROR evaluation of constant value failed
diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr
index c0c749ede56..e98e4a506c0 100644
--- a/src/test/ui/consts/const-eval/const_panic.stderr
+++ b/src/test/ui/consts/const-eval/const_panic.stderr
@@ -39,45 +39,61 @@ LL | const W: () = std::panic!(MSG);
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic.rs:22:20
+  --> $DIR/const_panic.rs:22:16
+   |
+LL | const W2: () = std::panic!("{}", MSG);
+   |                ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:22:16
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const_panic.rs:25:20
    |
 LL | const Z_CORE: () = core::panic!("cheese");
-   |                    ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:22:20
+   |                    ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:25:20
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic.rs:25:21
+  --> $DIR/const_panic.rs:28:21
    |
 LL | const Z2_CORE: () = core::panic!();
-   |                     ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:25:21
+   |                     ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:28:21
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic.rs:28:20
+  --> $DIR/const_panic.rs:31:20
    |
 LL | const Y_CORE: () = core::unreachable!();
-   |                    ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:28:20
+   |                    ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:31:20
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic.rs:31:20
+  --> $DIR/const_panic.rs:34:20
    |
 LL | const X_CORE: () = core::unimplemented!();
-   |                    ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:31:20
+   |                    ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:34:20
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic.rs:34:20
+  --> $DIR/const_panic.rs:37:20
    |
 LL | const W_CORE: () = core::panic!(MSG);
-   |                    ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:34:20
+   |                    ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:37:20
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const_panic.rs:40:21
+   |
+LL | const W2_CORE: () = core::panic!("{}", MSG);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:40:21
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/const_panic_2021.rs b/src/test/ui/consts/const-eval/const_panic_2021.rs
index daef34cd6a3..9b8652a776e 100644
--- a/src/test/ui/consts/const-eval/const_panic_2021.rs
+++ b/src/test/ui/consts/const-eval/const_panic_2021.rs
@@ -2,6 +2,8 @@
 #![feature(const_panic)]
 #![crate_type = "lib"]
 
+const MSG: &str = "hello";
+
 const A: () = std::panic!("blåhaj");
 //~^ ERROR evaluation of constant value failed
 
@@ -14,14 +16,20 @@ const C: () = std::unreachable!();
 const D: () = std::unimplemented!();
 //~^ ERROR evaluation of constant value failed
 
-const E: () = core::panic!("shark");
+const E: () = std::panic!("{}", MSG);
+//~^ ERROR evaluation of constant value failed
+
+const A_CORE: () = core::panic!("shark");
+//~^ ERROR evaluation of constant value failed
+
+const B_CORE: () = core::panic!();
 //~^ ERROR evaluation of constant value failed
 
-const F: () = core::panic!();
+const C_CORE: () = core::unreachable!();
 //~^ ERROR evaluation of constant value failed
 
-const G: () = core::unreachable!();
+const D_CORE: () = core::unimplemented!();
 //~^ ERROR evaluation of constant value failed
 
-const H: () = core::unimplemented!();
+const E_CORE: () = core::panic!("{}", MSG);
 //~^ ERROR evaluation of constant value failed
diff --git a/src/test/ui/consts/const-eval/const_panic_2021.stderr b/src/test/ui/consts/const-eval/const_panic_2021.stderr
index c1bdab3693d..9eb241ae8e5 100644
--- a/src/test/ui/consts/const-eval/const_panic_2021.stderr
+++ b/src/test/ui/consts/const-eval/const_panic_2021.stderr
@@ -1,67 +1,83 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic_2021.rs:5:15
+  --> $DIR/const_panic_2021.rs:7:15
    |
 LL | const A: () = std::panic!("blåhaj");
-   |               ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:5:15
+   |               ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:7:15
    |
    = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic_2021.rs:8:15
+  --> $DIR/const_panic_2021.rs:10:15
    |
 LL | const B: () = std::panic!();
-   |               ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:8:15
+   |               ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:10:15
    |
    = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic_2021.rs:11:15
+  --> $DIR/const_panic_2021.rs:13:15
    |
 LL | const C: () = std::unreachable!();
-   |               ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:11:15
+   |               ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:13:15
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic_2021.rs:14:15
+  --> $DIR/const_panic_2021.rs:16:15
    |
 LL | const D: () = std::unimplemented!();
-   |               ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:14:15
+   |               ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:16:15
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic_2021.rs:17:15
+  --> $DIR/const_panic_2021.rs:19:15
    |
-LL | const E: () = core::panic!("shark");
-   |               ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:17:15
+LL | const E: () = std::panic!("{}", MSG);
+   |               ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:19:15
    |
    = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic_2021.rs:20:15
+  --> $DIR/const_panic_2021.rs:22:20
    |
-LL | const F: () = core::panic!();
-   |               ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:20:15
+LL | const A_CORE: () = core::panic!("shark");
+   |                    ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:22:20
    |
    = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic_2021.rs:23:15
+  --> $DIR/const_panic_2021.rs:25:20
    |
-LL | const G: () = core::unreachable!();
-   |               ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:23:15
+LL | const B_CORE: () = core::panic!();
+   |                    ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:25:20
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const_panic_2021.rs:28:20
+   |
+LL | const C_CORE: () = core::unreachable!();
+   |                    ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:28:20
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_panic_2021.rs:26:15
+  --> $DIR/const_panic_2021.rs:31:20
    |
-LL | const H: () = core::unimplemented!();
-   |               ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:26:15
+LL | const D_CORE: () = core::unimplemented!();
+   |                    ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:31:20
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 8 previous errors
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const_panic_2021.rs:34:20
+   |
+LL | const E_CORE: () = core::panic!("{}", MSG);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:34:20
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const_fn_trait_bound.rs b/src/test/ui/consts/const_fn_trait_bound.rs
index b1ef820d827..19c08b62144 100644
--- a/src/test/ui/consts/const_fn_trait_bound.rs
+++ b/src/test/ui/consts/const_fn_trait_bound.rs
@@ -8,9 +8,9 @@
 const fn test1<T: std::ops::Add>() {}
 //[stock]~^ trait bounds
 const fn test2(_x: &dyn Send) {}
-//[stock]~^ trait bounds
+//[stock]~^ trait objects in const fn are unstable
 const fn test3() -> &'static dyn Send { loop {} }
-//[stock]~^ trait bounds
+//[stock]~^ trait objects in const fn are unstable
 
 
 #[rustc_error]
diff --git a/src/test/ui/consts/const_fn_trait_bound.stock.stderr b/src/test/ui/consts/const_fn_trait_bound.stock.stderr
index 2ad45f3afde..d652b5268a8 100644
--- a/src/test/ui/consts/const_fn_trait_bound.stock.stderr
+++ b/src/test/ui/consts/const_fn_trait_bound.stock.stderr
@@ -7,7 +7,7 @@ LL | const fn test1<T: std::ops::Add>() {}
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0658]: trait objects in const fn are unstable
   --> $DIR/const_fn_trait_bound.rs:10:16
    |
 LL | const fn test2(_x: &dyn Send) {}
@@ -16,7 +16,7 @@ LL | const fn test2(_x: &dyn Send) {}
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0658]: trait objects in const fn are unstable
   --> $DIR/const_fn_trait_bound.rs:12:21
    |
 LL | const fn test3() -> &'static dyn Send { loop {} }
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
index bb525d57197..10347a02074 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs
@@ -130,16 +130,16 @@ const fn no_apit(_x: impl std::fmt::Debug) {}
 //~^ ERROR trait bounds other than `Sized`
 //~| ERROR destructor
 const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
-//~^ ERROR trait bounds other than `Sized`
+//~^ ERROR trait objects in const fn are unstable
 const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-//~^ ERROR trait bounds other than `Sized`
+//~^ ERROR trait objects in const fn are unstable
 
 const fn no_unsafe() { unsafe {} }
 
 const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-//~^ ERROR trait bounds other than `Sized`
-//~| ERROR trait bounds other than `Sized`
-//~| ERROR trait bounds other than `Sized`
+//~^ ERROR trait objects in const fn are unstable
+//~| ERROR trait objects in const fn are unstable
+//~| ERROR trait objects in const fn are unstable
 
 const fn no_fn_ptrs(_x: fn()) {}
 //~^ ERROR function pointer
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
index d1c2a04d6a6..1e275d77bac 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
@@ -279,7 +279,7 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                  |
    |                  constant functions cannot evaluate destructors
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0658]: trait objects in const fn are unstable
   --> $DIR/min_const_fn.rs:132:23
    |
 LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
@@ -288,7 +288,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0658]: trait objects in const fn are unstable
   --> $DIR/min_const_fn.rs:134:32
    |
 LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
@@ -297,7 +297,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0658]: trait objects in const fn are unstable
   --> $DIR/min_const_fn.rs:139:41
    |
 LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
@@ -308,7 +308,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0658]: trait objects in const fn are unstable
   --> $DIR/min_const_fn.rs:139:42
    |
 LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
@@ -319,7 +319,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0658]: trait objects in const fn are unstable
   --> $DIR/min_const_fn.rs:139:42
    |
 LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
index 6ca1e59b3af..1ab8253b414 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
@@ -7,9 +7,9 @@ struct Hide(HasDyn);
 const fn no_inner_dyn_trait(_x: Hide) {}
 const fn no_inner_dyn_trait2(x: Hide) {
     x.0.field;
-//~^ ERROR trait bounds other than `Sized`
+//~^ ERROR trait objects in const fn are unstable
 }
 const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-//~^ ERROR trait bounds other than `Sized`
+//~^ ERROR trait objects in const fn are unstable
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
index 2cad8a862be..6eec1df5aec 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
@@ -1,4 +1,4 @@
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0658]: trait objects in const fn are unstable
   --> $DIR/min_const_fn_dyn.rs:9:5
    |
 LL | const fn no_inner_dyn_trait2(x: Hide) {
@@ -9,7 +9,7 @@ LL |     x.0.field;
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0658]: trait objects in const fn are unstable
   --> $DIR/min_const_fn_dyn.rs:12:66
    |
 LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
diff --git a/src/test/ui/error-codes/E0439.rs b/src/test/ui/error-codes/E0439.rs
deleted file mode 100644
index 86e9cb55a9c..00000000000
--- a/src/test/ui/error-codes/E0439.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(platform_intrinsics)]
-
-extern "platform-intrinsic" {
-    fn simd_shuffle<A,B>(a: A, b: A, c: [u32; 8]) -> B; //~ ERROR E0439
-}
-
-fn main () {
-}
diff --git a/src/test/ui/error-codes/E0439.stderr b/src/test/ui/error-codes/E0439.stderr
deleted file mode 100644
index 8021f7d3951..00000000000
--- a/src/test/ui/error-codes/E0439.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0439]: invalid `simd_shuffle`, needs length: `simd_shuffle`
-  --> $DIR/E0439.rs:4:5
-   |
-LL |     fn simd_shuffle<A,B>(a: A, b: A, c: [u32; 8]) -> B;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0439`.
diff --git a/src/test/ui/issues/issue-4335.stderr b/src/test/ui/issues/issue-4335.stderr
index f187969ff4e..fa3b58e1279 100644
--- a/src/test/ui/issues/issue-4335.stderr
+++ b/src/test/ui/issues/issue-4335.stderr
@@ -4,7 +4,10 @@ error[E0507]: cannot move out of `*v`, as `v` is a captured variable in an `FnMu
 LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
    |             - captured outer variable
 LL |     id(Box::new(|| *v))
-   |                    ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait
+   |                 ---^^
+   |                 |  |
+   |                 |  move occurs because `*v` has type `T`, which does not implement the `Copy` trait
+   |                 captured by this `FnMut` closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-51102.stderr b/src/test/ui/issues/issue-51102.stderr
index eb9eb680200..09c52292dcc 100644
--- a/src/test/ui/issues/issue-51102.stderr
+++ b/src/test/ui/issues/issue-51102.stderr
@@ -2,7 +2,10 @@ error[E0026]: struct `SimpleStruct` does not have a field named `state`
   --> $DIR/issue-51102.rs:13:17
    |
 LL |                 state: 0,
-   |                 ^^^^^ struct `SimpleStruct` does not have this field
+   |                 ^^^^^
+   |                 |
+   |                 struct `SimpleStruct` does not have this field
+   |                 help: `SimpleStruct` has a field named `no_state_here`
 
 error[E0025]: field `no_state_here` bound multiple times in the pattern
   --> $DIR/issue-51102.rs:24:17
diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr
index ffe3bb737ad..952159ffc3b 100644
--- a/src/test/ui/issues/issue-55796.stderr
+++ b/src/test/ui/issues/issue-55796.stderr
@@ -15,7 +15,7 @@ note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/iss
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/issue-55796.rs:18:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
@@ -40,7 +40,7 @@ note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/iss
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/issue-55796.rs:23:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
diff --git a/src/test/ui/issues/issue-61882-2.stderr b/src/test/ui/issues/issue-61882-2.stderr
index 03a65540ced..0b8e134c966 100644
--- a/src/test/ui/issues/issue-61882-2.stderr
+++ b/src/test/ui/issues/issue-61882-2.stderr
@@ -5,7 +5,7 @@ LL |         Self(&x);
    |              ^^
    |              |
    |              borrowed value does not live long enough
-   |              requires that `x` is borrowed for `'static`
+   |              this usage requires that `x` is borrowed for `'static`
 LL |
 LL |     }
    |     - `x` dropped here while still borrowed
diff --git a/src/test/ui/issues/issue-75777.stderr b/src/test/ui/issues/issue-75777.stderr
index 16249a33c2f..25562f6347e 100644
--- a/src/test/ui/issues/issue-75777.stderr
+++ b/src/test/ui/issues/issue-75777.stderr
@@ -17,7 +17,7 @@ LL |     Box::new(move |_| fut)
    = note: expected `(Pin<Box<dyn Future<Output = A> + Send>>,)`
               found `(Pin<Box<(dyn Future<Output = A> + Send + 'a)>>,)`
    = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/issue-75777.rs:13:5
    |
 LL |     Box::new(move |_| fut)
diff --git a/src/test/ui/lifetimes/issue-77175.rs b/src/test/ui/lifetimes/issue-77175.rs
new file mode 100644
index 00000000000..2282752b6c1
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-77175.rs
@@ -0,0 +1,19 @@
+#[deny(single_use_lifetimes)]
+// edition:2018
+// check-pass
+
+// Prior to the fix, the compiler complained that the 'a lifetime was only used
+// once. This was obviously wrong since the lifetime is used twice: For the s3
+// parameter and the return type. The issue was caused by the compiler
+// desugaring the async function into a generator that uses only a single
+// lifetime, which then the validator complained about becauase of the
+// single_use_lifetimes constraints.
+async fn bar<'a>(s1: String, s2: &'_ str, s3: &'a str) -> &'a str {
+    s3
+}
+
+fn foo<'a>(s1: String, s2: &'_ str, s3: &'a str) -> &'a str {
+    s3
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
index 8c87f6da8dc..e18d725faef 100644
--- a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
+++ b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
@@ -9,6 +9,17 @@ LL |     a: &'b str,
    = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
 
 error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
+   |
+LL | #[derive(Eq, PartialEq)]
+   |          -- lifetime `'b` is missing in item created through this procedural macro
+LL | struct Test {
+LL |     a: &'b str,
+   |         ^^ undeclared lifetime
+   |
+   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
+
+error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:13:13
    |
 LL |     fn foo(&'b self) {}
@@ -24,17 +35,6 @@ help: consider introducing lifetime `'b` here
 LL |     fn foo<'b>(&'b self) {}
    |           ++++
 
-error[E0261]: use of undeclared lifetime name `'b`
-  --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
-   |
-LL | #[derive(Eq, PartialEq)]
-   |          -- lifetime `'b` is missing in item created through this procedural macro
-LL | struct Test {
-LL |     a: &'b str,
-   |         ^^ undeclared lifetime
-   |
-   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0261`.
diff --git a/src/test/ui/loops/loops-reject-duplicate-labels-2.rs b/src/test/ui/loops/loops-reject-duplicate-labels-2.rs
index 3a860f508ff..68a19a8f6f7 100644
--- a/src/test/ui/loops/loops-reject-duplicate-labels-2.rs
+++ b/src/test/ui/loops/loops-reject-duplicate-labels-2.rs
@@ -1,7 +1,7 @@
 // check-pass
+#![feature(label_break_value)]
 
-
-// Issue #21633: reject duplicate loop labels in function bodies.
+// Issue #21633: reject duplicate loop labels and block labels in function bodies.
 //
 // This is testing the generalization (to the whole function body)
 // discussed here:
@@ -26,6 +26,8 @@ pub fn foo() {
     { 'lt: loop { break; } }
     { 'lt: while let Some(_) = None::<i32> { break; } }
                                          //~^ WARN label name `'lt` shadows a label name that is already in scope
+    { 'bl: {} }
+    { 'bl: {} } //~ WARN label name `'bl` shadows a label name that is already in scope
 }
 
 
diff --git a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr
index 6c53d04e107..2c372fcff7a 100644
--- a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr
+++ b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr
@@ -62,5 +62,13 @@ LL |     { 'lt: loop { break; } }
 LL |     { 'lt: while let Some(_) = None::<i32> { break; } }
    |       ^^^ label `'lt` already in scope
 
-warning: 8 warnings emitted
+warning: label name `'bl` shadows a label name that is already in scope
+  --> $DIR/loops-reject-duplicate-labels-2.rs:30:7
+   |
+LL |     { 'bl: {} }
+   |       --- first declared here
+LL |     { 'bl: {} }
+   |       ^^^ label `'bl` already in scope
+
+warning: 9 warnings emitted
 
diff --git a/src/test/ui/loops/loops-reject-duplicate-labels.rs b/src/test/ui/loops/loops-reject-duplicate-labels.rs
index d9334ce3857..c34bcf3df1d 100644
--- a/src/test/ui/loops/loops-reject-duplicate-labels.rs
+++ b/src/test/ui/loops/loops-reject-duplicate-labels.rs
@@ -1,8 +1,7 @@
 // check-pass
+#![feature(label_break_value)]
 
-
-// Issue #21633: reject duplicate loop labels in function bodies.
-// This is testing the exact cases that are in the issue description.
+// Issue #21633: reject duplicate loop labels and block labels in function bodies.
 
 #[allow(unused_labels)]
 fn foo() {
@@ -24,6 +23,8 @@ fn foo() {
     'lt: loop { break; }
     'lt: while let Some(_) = None::<i32> { break; }
                                    //~^ WARN label name `'lt` shadows a label name that is already in scope
+    'bl: {}
+    'bl: {} //~ WARN label name `'bl` shadows a label name that is already in scope
 }
 
 // Note however that it is okay for the same label to be reused in
@@ -33,6 +34,8 @@ struct S;
 impl S {
     fn m1(&self) { 'okay: loop { break 'okay; } }
     fn m2(&self) { 'okay: loop { break 'okay; } }
+    fn m3(&self) { 'okay: { break 'okay; } }
+    fn m4(&self) { 'okay: { break 'okay; } }
 }
 
 
@@ -40,5 +43,7 @@ pub fn main() {
     let s = S;
     s.m1();
     s.m2();
+    s.m3();
+    s.m4();
     foo();
 }
diff --git a/src/test/ui/loops/loops-reject-duplicate-labels.stderr b/src/test/ui/loops/loops-reject-duplicate-labels.stderr
index 5bdf64849f3..3bf3af763ec 100644
--- a/src/test/ui/loops/loops-reject-duplicate-labels.stderr
+++ b/src/test/ui/loops/loops-reject-duplicate-labels.stderr
@@ -1,5 +1,5 @@
 warning: label name `'fl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:10:5
+  --> $DIR/loops-reject-duplicate-labels.rs:9:5
    |
 LL |     'fl: for _ in 0..10 { break; }
    |     --- first declared here
@@ -7,7 +7,7 @@ LL |     'fl: loop { break; }
    |     ^^^ label `'fl` already in scope
 
 warning: label name `'lf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:13:5
+  --> $DIR/loops-reject-duplicate-labels.rs:12:5
    |
 LL |     'lf: loop { break; }
    |     --- first declared here
@@ -15,7 +15,7 @@ LL |     'lf: for _ in 0..10 { break; }
    |     ^^^ label `'lf` already in scope
 
 warning: label name `'wl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:15:5
+  --> $DIR/loops-reject-duplicate-labels.rs:14:5
    |
 LL |     'wl: while 2 > 1 { break; }
    |     --- first declared here
@@ -23,7 +23,7 @@ LL |     'wl: loop { break; }
    |     ^^^ label `'wl` already in scope
 
 warning: label name `'lw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:17:5
+  --> $DIR/loops-reject-duplicate-labels.rs:16:5
    |
 LL |     'lw: loop { break; }
    |     --- first declared here
@@ -31,7 +31,7 @@ LL |     'lw: while 2 > 1 { break; }
    |     ^^^ label `'lw` already in scope
 
 warning: label name `'fw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:19:5
+  --> $DIR/loops-reject-duplicate-labels.rs:18:5
    |
 LL |     'fw: for _ in 0..10 { break; }
    |     --- first declared here
@@ -39,7 +39,7 @@ LL |     'fw: while 2 > 1 { break; }
    |     ^^^ label `'fw` already in scope
 
 warning: label name `'wf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:21:5
+  --> $DIR/loops-reject-duplicate-labels.rs:20:5
    |
 LL |     'wf: while 2 > 1 { break; }
    |     --- first declared here
@@ -47,7 +47,7 @@ LL |     'wf: for _ in 0..10 { break; }
    |     ^^^ label `'wf` already in scope
 
 warning: label name `'tl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:23:5
+  --> $DIR/loops-reject-duplicate-labels.rs:22:5
    |
 LL |     'tl: while let Some(_) = None::<i32> { break; }
    |     --- first declared here
@@ -55,12 +55,20 @@ LL |     'tl: loop { break; }
    |     ^^^ label `'tl` already in scope
 
 warning: label name `'lt` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:25:5
+  --> $DIR/loops-reject-duplicate-labels.rs:24:5
    |
 LL |     'lt: loop { break; }
    |     --- first declared here
 LL |     'lt: while let Some(_) = None::<i32> { break; }
    |     ^^^ label `'lt` already in scope
 
-warning: 8 warnings emitted
+warning: label name `'bl` shadows a label name that is already in scope
+  --> $DIR/loops-reject-duplicate-labels.rs:27:5
+   |
+LL |     'bl: {}
+   |     --- first declared here
+LL |     'bl: {}
+   |     ^^^ label `'bl` already in scope
+
+warning: 9 warnings emitted
 
diff --git a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs
index 3212b78b08c..ce2d07eb06a 100644
--- a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs
+++ b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs
@@ -1,10 +1,10 @@
 // check-pass
-
+#![feature(label_break_value)]
 #![allow(dead_code, unused_variables)]
 
-// Issue #21633:  reject duplicate loop labels in function bodies.
+// Issue #21633:  reject duplicate loop labels and block labels in function bodies.
 //
-// Test rejection of lifetimes in *expressions* that shadow loop labels.
+// Test rejection of lifetimes in *expressions* that shadow labels.
 
 fn foo() {
     // Reusing lifetime `'a` in function item is okay.
@@ -23,8 +23,13 @@ fn foo() {
         assert_eq!((*b)(&z), z);
         break 'a;
     }
-}
 
+    'b: {
+        let b = Box::new(|x: &()| ()) as Box<dyn for <'b> Fn(&'b ())>;
+        //~^ WARN lifetime name `'b` shadows a label name that is already in scope
+        break 'b;
+    }
+}
 
 pub fn main() {
     foo();
diff --git a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr
index dcee1a80090..9702b71600b 100644
--- a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr
+++ b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr
@@ -6,5 +6,13 @@ LL |     'a: loop {
 LL |         let b = Box::new(|x: &i8| *x) as Box<dyn for <'a> Fn(&'a i8) -> i8>;
    |                                                       ^^ label `'a` already in scope
 
-warning: 1 warning emitted
+warning: lifetime name `'b` shadows a label name that is already in scope
+  --> $DIR/loops-reject-lifetime-shadowing-label.rs:28:55
+   |
+LL |     'b: {
+   |     -- first declared here
+LL |         let b = Box::new(|x: &()| ()) as Box<dyn for <'b> Fn(&'b ())>;
+   |                                                       ^^ label `'b` already in scope
+
+warning: 2 warnings emitted
 
diff --git a/src/test/ui/macros/lint-trailing-macro-call.rs b/src/test/ui/macros/lint-trailing-macro-call.rs
new file mode 100644
index 00000000000..f8e84756391
--- /dev/null
+++ b/src/test/ui/macros/lint-trailing-macro-call.rs
@@ -0,0 +1,16 @@
+// check-pass
+//
+// Ensures that we properly lint
+// a removed 'expression' resulting from a macro
+// in trailing expression position
+
+macro_rules! expand_it {
+    () => {
+        #[cfg(FALSE)] 25; //~  WARN trailing semicolon in macro
+                          //~| WARN this was previously
+    }
+}
+
+fn main() {
+    expand_it!()
+}
diff --git a/src/test/ui/macros/lint-trailing-macro-call.stderr b/src/test/ui/macros/lint-trailing-macro-call.stderr
new file mode 100644
index 00000000000..a98a559c8af
--- /dev/null
+++ b/src/test/ui/macros/lint-trailing-macro-call.stderr
@@ -0,0 +1,18 @@
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/lint-trailing-macro-call.rs:9:25
+   |
+LL |         #[cfg(FALSE)] 25;
+   |                         ^
+...
+LL |     expand_it!()
+   |     ------------ in this macro invocation
+   |
+   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: macro invocations at the end of a block are treated as expressions
+   = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it`
+   = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
index 9427ba546a9..e12af2d4527 100644
--- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
+++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
@@ -4,7 +4,10 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure
 LL |     let i = box 3;
    |         - captured outer variable
 LL |     let _f = to_fn(|| test(i));
-   |                            ^ move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
+   |                    --------^-
+   |                    |       |
+   |                    |       move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
+   |                    captured by this `Fn` closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-46036.stderr b/src/test/ui/nll/issue-46036.stderr
index 49dd0e267b8..e6e95ee6136 100644
--- a/src/test/ui/nll/issue-46036.stderr
+++ b/src/test/ui/nll/issue-46036.stderr
@@ -5,7 +5,7 @@ LL |     let foo = Foo { x: &a };
    |                        ^^
    |                        |
    |                        borrowed value does not live long enough
-   |                        requires that `a` is borrowed for `'static`
+   |                        this usage requires that `a` is borrowed for `'static`
 LL |     loop { }
 LL | }
    | - `a` dropped here while still borrowed
diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
index 67115a5ccdd..c9324f0422c 100644
--- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
+++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
@@ -4,7 +4,10 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn`
 LL |        let x = (vec![22], vec![44]);
    |            - captured outer variable
 LL |        expect_fn(|| drop(x.0));
-   |                          ^^^ move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait
+   |                  --------^^^-
+   |                  |       |
+   |                  |       move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait
+   |                  captured by this `Fn` closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr
index 36721f923f7..dbc478e5b4c 100644
--- a/src/test/ui/nll/issue-55394.stderr
+++ b/src/test/ui/nll/issue-55394.stderr
@@ -19,7 +19,7 @@ note: but, the lifetime must be valid for the lifetime `'_` as defined on the im
    |
 LL | impl Foo<'_> {
    |          ^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/issue-55394.rs:9:9
    |
 LL |         Foo { bar }
diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr
index 6498ecfbe6f..dbb63b71af8 100644
--- a/src/test/ui/nll/type-alias-free-regions.stderr
+++ b/src/test/ui/nll/type-alias-free-regions.stderr
@@ -21,7 +21,7 @@ note: but, the lifetime must be valid for the lifetime `'a` as defined on the im
    |
 LL | impl<'a> FromBox<'a> for C<'a> {
    |      ^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/type-alias-free-regions.rs:17:9
    |
 LL |         C { f: b }
@@ -52,7 +52,7 @@ note: but, the lifetime must be valid for the lifetime `'a` as defined on the im
    |
 LL | impl<'a> FromTuple<'a> for C<'a> {
    |      ^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/type-alias-free-regions.rs:27:9
    |
 LL |         C { f: Box::new(b.0) }
diff --git a/src/test/ui/nll/user-annotations/adt-brace-enums.stderr b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr
index e38b77fdcea..253e3825110 100644
--- a/src/test/ui/nll/user-annotations/adt-brace-enums.stderr
+++ b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr
@@ -5,7 +5,7 @@ LL |     SomeEnum::SomeVariant::<&'static u32> { t: &c };
    |                                                ^^
    |                                                |
    |                                                borrowed value does not live long enough
-   |                                                requires that `c` is borrowed for `'static`
+   |                                                this usage requires that `c` is borrowed for `'static`
 LL | }
    | - `c` dropped here while still borrowed
 
@@ -19,7 +19,7 @@ LL |     SomeEnum::SomeVariant::<&'a u32> { t: &c };
    |                                           ^^
    |                                           |
    |                                           borrowed value does not live long enough
-   |                                           requires that `c` is borrowed for `'a`
+   |                                           this usage requires that `c` is borrowed for `'a`
 LL | }
    | - `c` dropped here while still borrowed
 
@@ -33,7 +33,7 @@ LL |         SomeEnum::SomeVariant::<&'a u32> { t: &c };
    |                                               ^^
    |                                               |
    |                                               borrowed value does not live long enough
-   |                                               requires that `c` is borrowed for `'a`
+   |                                               this usage requires that `c` is borrowed for `'a`
 LL |     };
    |     - `c` dropped here while still borrowed
 
diff --git a/src/test/ui/nll/user-annotations/adt-brace-structs.stderr b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr
index 3c3003477c2..8b9d1705df6 100644
--- a/src/test/ui/nll/user-annotations/adt-brace-structs.stderr
+++ b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr
@@ -5,7 +5,7 @@ LL |     SomeStruct::<&'static u32> { t: &c };
    |                                     ^^
    |                                     |
    |                                     borrowed value does not live long enough
-   |                                     requires that `c` is borrowed for `'static`
+   |                                     this usage requires that `c` is borrowed for `'static`
 LL | }
    | - `c` dropped here while still borrowed
 
@@ -19,7 +19,7 @@ LL |     SomeStruct::<&'a u32> { t: &c };
    |                                ^^
    |                                |
    |                                borrowed value does not live long enough
-   |                                requires that `c` is borrowed for `'a`
+   |                                this usage requires that `c` is borrowed for `'a`
 LL | }
    | - `c` dropped here while still borrowed
 
@@ -33,7 +33,7 @@ LL |         SomeStruct::<&'a u32> { t: &c };
    |                                    ^^
    |                                    |
    |                                    borrowed value does not live long enough
-   |                                    requires that `c` is borrowed for `'a`
+   |                                    this usage requires that `c` is borrowed for `'a`
 LL |     };
    |     - `c` dropped here while still borrowed
 
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr
index 810912bf886..2fa7042631d 100644
--- a/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr
+++ b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr
@@ -5,7 +5,7 @@ LL |     SomeEnum::SomeVariant::<&'static u32>(&c);
    |                                           ^^
    |                                           |
    |                                           borrowed value does not live long enough
-   |                                           requires that `c` is borrowed for `'static`
+   |                                           this usage requires that `c` is borrowed for `'static`
 LL | }
    | - `c` dropped here while still borrowed
 
@@ -19,7 +19,7 @@ LL |     SomeEnum::SomeVariant::<&'a u32>(&c);
    |                                      ^^
    |                                      |
    |                                      borrowed value does not live long enough
-   |                                      requires that `c` is borrowed for `'a`
+   |                                      this usage requires that `c` is borrowed for `'a`
 LL | }
    | - `c` dropped here while still borrowed
 
@@ -33,7 +33,7 @@ LL |         SomeEnum::SomeVariant::<&'a u32>(&c);
    |                                          ^^
    |                                          |
    |                                          borrowed value does not live long enough
-   |                                          requires that `c` is borrowed for `'a`
+   |                                          this usage requires that `c` is borrowed for `'a`
 LL |     };
    |     - `c` dropped here while still borrowed
 
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr
index 4d2140eca1b..76b5252258c 100644
--- a/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr
+++ b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr
@@ -5,7 +5,7 @@ LL |     SomeStruct::<&'static u32>(&c);
    |                                ^^
    |                                |
    |                                borrowed value does not live long enough
-   |                                requires that `c` is borrowed for `'static`
+   |                                this usage requires that `c` is borrowed for `'static`
 LL | }
    | - `c` dropped here while still borrowed
 
@@ -19,7 +19,7 @@ LL |     SomeStruct::<&'a u32>(&c);
    |                           ^^
    |                           |
    |                           borrowed value does not live long enough
-   |                           requires that `c` is borrowed for `'a`
+   |                           this usage requires that `c` is borrowed for `'a`
 LL | }
    | - `c` dropped here while still borrowed
 
@@ -33,7 +33,7 @@ LL |         SomeStruct::<&'a u32>(&c);
    |                               ^^
    |                               |
    |                               borrowed value does not live long enough
-   |                               requires that `c` is borrowed for `'a`
+   |                               this usage requires that `c` is borrowed for `'a`
 LL |     };
    |     - `c` dropped here while still borrowed
 
diff --git a/src/test/ui/nll/where_clauses_in_structs.stderr b/src/test/ui/nll/where_clauses_in_structs.stderr
index 2e990131e61..8499b00f6f5 100644
--- a/src/test/ui/nll/where_clauses_in_structs.stderr
+++ b/src/test/ui/nll/where_clauses_in_structs.stderr
@@ -6,7 +6,7 @@ LL | fn bar<'a, 'b>(x: Cell<&'a u32>, y: Cell<&'b u32>) {
    |        |
    |        lifetime `'a` defined here
 LL |     Foo { x, y };
-   |           ^ requires that `'a` must outlive `'b`
+   |           ^ this usage requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/numeric/numeric-fields.stderr b/src/test/ui/numeric/numeric-fields.stderr
index b328fbe2cfb..668405ed638 100644
--- a/src/test/ui/numeric/numeric-fields.stderr
+++ b/src/test/ui/numeric/numeric-fields.stderr
@@ -16,7 +16,10 @@ error[E0026]: struct `S` does not have a field named `0x1`
   --> $DIR/numeric-fields.rs:7:17
    |
 LL |         S{0: a, 0x1: b, ..} => {}
-   |                 ^^^ struct `S` does not have this field
+   |                 ^^^
+   |                 |
+   |                 struct `S` does not have this field
+   |                 help: `S` has a field named `1`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
index 79ded5fc875..ee1a4612572 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
@@ -19,7 +19,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
    |
 LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
    |             ^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/object-lifetime-default-elision.rs:71:5
    |
 LL |     ss
@@ -48,7 +48,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
    |
 LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
    |             ^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/object-lifetime-default-elision.rs:71:5
    |
 LL |     ss
diff --git a/src/test/ui/parser/recover-for-loop-parens-around-head.rs b/src/test/ui/parser/recover-for-loop-parens-around-head.rs
index 779e1646344..8080dbc332a 100644
--- a/src/test/ui/parser/recover-for-loop-parens-around-head.rs
+++ b/src/test/ui/parser/recover-for-loop-parens-around-head.rs
@@ -9,7 +9,7 @@ fn main() {
 
     for ( elem in vec ) {
         //~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in`
-        //~| ERROR unexpected closing `)`
+        //~| ERROR unexpected parenthesis surrounding `for` loop head
         const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
     }
 }
diff --git a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr
index e97cf544ac2..21991348327 100644
--- a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr
+++ b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr
@@ -4,14 +4,17 @@ error: expected one of `)`, `,`, `@`, or `|`, found keyword `in`
 LL |     for ( elem in vec ) {
    |                ^^ expected one of `)`, `,`, `@`, or `|`
 
-error: unexpected closing `)`
-  --> $DIR/recover-for-loop-parens-around-head.rs:10:23
+error: unexpected parenthesis surrounding `for` loop head
+  --> $DIR/recover-for-loop-parens-around-head.rs:10:9
    |
 LL |     for ( elem in vec ) {
-   |         --------------^
-   |         |
-   |         opening `(`
-   |         help: remove parenthesis in `for` loop: `elem in vec`
+   |         ^             ^
+   |
+help: remove parenthesis in `for` loop
+   |
+LL -     for ( elem in vec ) {
+LL +     for  elem in vec  {
+   | 
 
 error[E0308]: mismatched types
   --> $DIR/recover-for-loop-parens-around-head.rs:13:38
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
index 1c8840f540e..852ca0f21b1 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
@@ -69,7 +69,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
    |
 LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
    |         ^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/region-object-lifetime-in-coercion.rs:23:5
    |
 LL |     Box::new(v)
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
index 0cce89215d3..bf29c76a0f0 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
@@ -19,7 +19,7 @@ note: but, the lifetime must be valid for the lifetime `'c` as defined on the fu
    |
 LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
    |                          ^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
    |
 LL |     box v as Box<dyn SomeTrait + 'a>
diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr
index b24db1df18b..44bd88e01a2 100644
--- a/src/test/ui/regions/regions-creating-enums4.stderr
+++ b/src/test/ui/regions/regions-creating-enums4.stderr
@@ -21,7 +21,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
    |
 LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
    |                   ^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/regions-creating-enums4.rs:7:5
    |
 LL |     Ast::Add(x, y)
diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr
index bba968cfde4..b5b54bc3c8b 100644
--- a/src/test/ui/regions/regions-ret-borrowed-1.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr
@@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on th
    |
 LL |     with(|o| o)
    |          ^^^^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/regions-ret-borrowed-1.rs:10:14
    |
 LL |     with(|o| o)
diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr
index 4b93ca0ae67..debae47d16d 100644
--- a/src/test/ui/regions/regions-ret-borrowed.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed.stderr
@@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on th
    |
 LL |     with(|o| o)
    |          ^^^^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/regions-ret-borrowed.rs:13:14
    |
 LL |     with(|o| o)
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr
index 7478b53bd3c..f16dfdd6e8c 100644
--- a/src/test/ui/regions/regions-trait-object-subtyping.stderr
+++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr
@@ -36,7 +36,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
    |
 LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
    |            ^^
-note: ...so that the expression is assignable
+note: ...so that the types are compatible
   --> $DIR/regions-trait-object-subtyping.rs:15:5
    |
 LL |     x
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.rs b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.rs
new file mode 100644
index 00000000000..9611780ac07
--- /dev/null
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.rs
@@ -0,0 +1,33 @@
+// build-fail
+
+// Test that the simd_shuffle intrinsic produces ok-ish error
+// messages when misused.
+
+#![feature(repr_simd, platform_intrinsics)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct Simd<T, const N: usize>([T; N]);
+
+extern "platform-intrinsic" {
+    fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
+}
+
+fn main() {
+    const I: [u32; 2] = [0; 2];
+    const I2: [f32; 2] = [0.; 2];
+    let v = Simd::<u32, 4>([0; 4]);
+
+    unsafe {
+        let _: Simd<u32, 2> = simd_shuffle(v, v, I);
+
+        let _: Simd<u32, 4> = simd_shuffle(v, v, I);
+        //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
+
+        let _: Simd<f32, 2> = simd_shuffle(v, v, I);
+        //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
+
+        let _: Simd<u32, 2> = simd_shuffle(v, v, I2);
+        //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
+    }
+}
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.stderr
new file mode 100644
index 00000000000..9eeb000fd26
--- /dev/null
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.stderr
@@ -0,0 +1,21 @@
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd<u32, 4_usize>` with length 4
+  --> $DIR/simd-intrinsic-generic-shuffle.rs:24:31
+   |
+LL |         let _: Simd<u32, 4> = simd_shuffle(v, v, I);
+   |                               ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd<u32, 4_usize>`), found `Simd<f32, 2_usize>` with element type `f32`
+  --> $DIR/simd-intrinsic-generic-shuffle.rs:27:31
+   |
+LL |         let _: Simd<f32, 2> = simd_shuffle(v, v, I);
+   |                               ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: simd_shuffle index must be an array of `u32`, got `[f32; 2]`
+  --> $DIR/simd-intrinsic-generic-shuffle.rs:30:31
+   |
+LL |         let _: Simd<u32, 2> = simd_shuffle(v, v, I2);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0511`.
diff --git a/src/test/ui/simd/monomorphize-shuffle-index.rs b/src/test/ui/simd/monomorphize-shuffle-index.rs
new file mode 100644
index 00000000000..2467baa08b0
--- /dev/null
+++ b/src/test/ui/simd/monomorphize-shuffle-index.rs
@@ -0,0 +1,40 @@
+//run-pass
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct Simd<T, const N: usize>([T; N]);
+
+trait Shuffle<const N: usize> {
+    const I: [u32; N];
+
+    unsafe fn shuffle<T, const M: usize>(&self, a: Simd<T, M>, b: Simd<T, M>) -> Simd<T, N> {
+        simd_shuffle(a, b, Self::I)
+    }
+}
+
+fn main() {
+    struct I1;
+    impl Shuffle<4> for I1 {
+        const I: [u32; 4] = [0, 2, 4, 6];
+    }
+
+    struct I2;
+    impl Shuffle<2> for I2 {
+        const I: [u32; 2] = [1, 5];
+    }
+
+    let a = Simd::<u8, 4>([0, 1, 2, 3]);
+    let b = Simd::<u8, 4>([4, 5, 6, 7]);
+    unsafe {
+        let x: Simd<u8, 4> = I1.shuffle(a, b);
+        assert_eq!(x.0, [0, 2, 4, 6]);
+
+        let y: Simd<u8, 2> = I2.shuffle(a, b);
+        assert_eq!(y.0, [1, 5]);
+    }
+}
diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.rs b/src/test/ui/simd/shuffle-not-out-of-bounds.rs
index 8a533453e75..aae6ce4663f 100644
--- a/src/test/ui/simd/shuffle-not-out-of-bounds.rs
+++ b/src/test/ui/simd/shuffle-not-out-of-bounds.rs
@@ -188,4 +188,14 @@ fn main() {
          48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
          32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
          16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+
+    extern "platform-intrinsic" {
+        fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
+    }
+    let v = u8x2(0, 0);
+    const I: [u32; 2] = [4, 4];
+    unsafe {
+        let _: u8x2 = simd_shuffle(v, v, I);
+        //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
+    }
 }
diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.stderr b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
index 07253a4ae46..737fb5e6e51 100644
--- a/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
+++ b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
@@ -71,6 +71,12 @@ LL | |          16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 6 previous errors
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4)
+  --> $DIR/shuffle-not-out-of-bounds.rs:198:23
+   |
+LL |         let _: u8x2 = simd_shuffle(v, v, I);
+   |                       ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0511`.
diff --git a/src/test/ui/simd/shuffle.rs b/src/test/ui/simd/shuffle.rs
new file mode 100644
index 00000000000..3592adfdc6a
--- /dev/null
+++ b/src/test/ui/simd/shuffle.rs
@@ -0,0 +1,24 @@
+//run-pass
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct Simd<T, const N: usize>([T; N]);
+
+fn main() {
+    const I1: [u32; 4] = [0, 2, 4, 6];
+    const I2: [u32; 2] = [1, 5];
+    let a = Simd::<u8, 4>([0, 1, 2, 3]);
+    let b = Simd::<u8, 4>([4, 5, 6, 7]);
+    unsafe {
+        let x: Simd<u8, 4> = simd_shuffle(a, b, I1);
+        assert_eq!(x.0, [0, 2, 4, 6]);
+
+        let y: Simd<u8, 2> = simd_shuffle(a, b, I2);
+        assert_eq!(y.0, [1, 5]);
+    }
+}
diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
index ab1fa2a4d87..0f630abd148 100644
--- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
+++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
@@ -29,11 +29,17 @@ LL |     f.f.call_mut(())
 error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13
    |
-LL |     let mut f = move |g: Box<dyn FnMut(isize)>, b: isize| {
-   |         ----- captured outer variable
+LL |       let mut f = move |g: Box<dyn FnMut(isize)>, b: isize| {
+   |           ----- captured outer variable
 ...
-LL |         foo(f);
-   |             ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait
+LL |       f(Box::new(|a| {
+   |  ________________-
+LL | |
+LL | |         foo(f);
+   | |             ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait
+LL | |
+LL | |     }), 3);
+   | |_____- captured by this `FnMut` closure
 
 error[E0505]: cannot move out of `f` because it is borrowed
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16
diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
index c50cbcde855..fb1055c9c30 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
+++ b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
@@ -1,281 +1,487 @@
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:28:21
    |
-LL |     let x = X(Y);
-   |         - captured outer variable
+LL |       let x = X(Y);
+   |           - captured outer variable
 ...
-LL |         let X(_t) = x;
-   |               --    ^ help: consider borrowing here: `&x`
-   |               |
-   |               data moved here
-   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+   | |               --    ^ help: consider borrowing here: `&x`
+   | |               |
+   | |               data moved here
+   | |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+LL | |
+LL | |
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:32:34
    |
-LL |     let e = Either::One(X(Y));
-   |         - captured outer variable
+LL |       let e = Either::One(X(Y));
+   |           - captured outer variable
 ...
-LL |         if let Either::One(_t) = e { }
-   |                            --    ^ help: consider borrowing here: `&e`
-   |                            |
-   |                            data moved here
-   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+LL | |
+LL | |         if let Either::One(_t) = e { }
+   | |                            --    ^ help: consider borrowing here: `&e`
+   | |                            |
+   | |                            data moved here
+   | |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:36:37
    |
-LL |     let e = Either::One(X(Y));
-   |         - captured outer variable
+LL |       let e = Either::One(X(Y));
+   |           - captured outer variable
 ...
-LL |         while let Either::One(_t) = e { }
-   |                               --    ^ help: consider borrowing here: `&e`
-   |                               |
-   |                               data moved here
-   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         while let Either::One(_t) = e { }
+   | |                               --    ^ help: consider borrowing here: `&e`
+   | |                               |
+   | |                               data moved here
+   | |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:40:15
    |
-LL |     let e = Either::One(X(Y));
-   |         - captured outer variable
+LL |       let e = Either::One(X(Y));
+   |           - captured outer variable
 ...
-LL |         match e {
-   |               ^ help: consider borrowing here: `&e`
-...
-LL |             Either::One(_t)
-   |                         --
-   |                         |
-   |                         data moved here
-   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         match e {
+   | |               ^ help: consider borrowing here: `&e`
+...  |
+LL | |             Either::One(_t)
+   | |                         --
+   | |                         |
+   | |                         data moved here
+   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:47:15
    |
-LL |     let e = Either::One(X(Y));
-   |         - captured outer variable
-...
-LL |         match e {
-   |               ^ help: consider borrowing here: `&e`
+LL |       let e = Either::One(X(Y));
+   |           - captured outer variable
 ...
-LL |             Either::One(_t) => (),
-   |                         --
-   |                         |
-   |                         data moved here
-   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         match e {
+   | |               ^ help: consider borrowing here: `&e`
+...  |
+LL | |             Either::One(_t) => (),
+   | |                         --
+   | |                         |
+   | |                         data moved here
+   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:56:25
    |
-LL |     let x = X(Y);
-   |         - captured outer variable
+LL |       let x = X(Y);
+   |           - captured outer variable
 ...
-LL |         let X(mut _t) = x;
-   |               ------    ^ help: consider borrowing here: `&x`
-   |               |
-   |               data moved here
-   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         let X(mut _t) = x;
+   | |               ------    ^ help: consider borrowing here: `&x`
+   | |               |
+   | |               data moved here
+   | |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:60:38
    |
-LL |     let mut em = Either::One(X(Y));
-   |         ------ captured outer variable
+LL |       let mut em = Either::One(X(Y));
+   |           ------ captured outer variable
 ...
-LL |         if let Either::One(mut _t) = em { }
-   |                            ------    ^^ help: consider borrowing here: `&em`
-   |                            |
-   |                            data moved here
-   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         if let Either::One(mut _t) = em { }
+   | |                            ------    ^^ help: consider borrowing here: `&em`
+   | |                            |
+   | |                            data moved here
+   | |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:64:41
    |
-LL |     let mut em = Either::One(X(Y));
-   |         ------ captured outer variable
+LL |       let mut em = Either::One(X(Y));
+   |           ------ captured outer variable
 ...
-LL |         while let Either::One(mut _t) = em { }
-   |                               ------    ^^ help: consider borrowing here: `&em`
-   |                               |
-   |                               data moved here
-   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         while let Either::One(mut _t) = em { }
+   | |                               ------    ^^ help: consider borrowing here: `&em`
+   | |                               |
+   | |                               data moved here
+   | |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:68:15
    |
-LL |     let mut em = Either::One(X(Y));
-   |         ------ captured outer variable
-...
-LL |         match em {
-   |               ^^ help: consider borrowing here: `&em`
+LL |       let mut em = Either::One(X(Y));
+   |           ------ captured outer variable
 ...
-LL |             Either::One(mut _t)
-   |                         ------
-   |                         |
-   |                         data moved here
-   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         match em {
+   | |               ^^ help: consider borrowing here: `&em`
+...  |
+LL | |             Either::One(mut _t)
+   | |                         ------
+   | |                         |
+   | |                         data moved here
+   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:75:15
    |
-LL |     let mut em = Either::One(X(Y));
-   |         ------ captured outer variable
+LL |       let mut em = Either::One(X(Y));
+   |           ------ captured outer variable
 ...
-LL |         match em {
-   |               ^^ help: consider borrowing here: `&em`
-...
-LL |             Either::One(mut _t) => (),
-   |                         ------
-   |                         |
-   |                         data moved here
-   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fn(|| {
+   |  ________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         match em {
+   | |               ^^ help: consider borrowing here: `&em`
+...  |
+LL | |             Either::One(mut _t) => (),
+   | |                         ------
+   | |                         |
+   | |                         data moved here
+   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `Fn` closure
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:95:21
    |
-LL |     let x = X(Y);
-   |         - captured outer variable
+LL |       let x = X(Y);
+   |           - captured outer variable
 ...
-LL |         let X(_t) = x;
-   |               --    ^ help: consider borrowing here: `&x`
-   |               |
-   |               data moved here
-   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+   | |               --    ^ help: consider borrowing here: `&x`
+   | |               |
+   | |               data moved here
+   | |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+LL | |
+LL | |
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:99:34
    |
-LL |     let e = Either::One(X(Y));
-   |         - captured outer variable
+LL |       let e = Either::One(X(Y));
+   |           - captured outer variable
 ...
-LL |         if let Either::One(_t) = e { }
-   |                            --    ^ help: consider borrowing here: `&e`
-   |                            |
-   |                            data moved here
-   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+LL | |
+LL | |         if let Either::One(_t) = e { }
+   | |                            --    ^ help: consider borrowing here: `&e`
+   | |                            |
+   | |                            data moved here
+   | |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:103:37
    |
-LL |     let e = Either::One(X(Y));
-   |         - captured outer variable
+LL |       let e = Either::One(X(Y));
+   |           - captured outer variable
 ...
-LL |         while let Either::One(_t) = e { }
-   |                               --    ^ help: consider borrowing here: `&e`
-   |                               |
-   |                               data moved here
-   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         while let Either::One(_t) = e { }
+   | |                               --    ^ help: consider borrowing here: `&e`
+   | |                               |
+   | |                               data moved here
+   | |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:107:15
    |
-LL |     let e = Either::One(X(Y));
-   |         - captured outer variable
-...
-LL |         match e {
-   |               ^ help: consider borrowing here: `&e`
+LL |       let e = Either::One(X(Y));
+   |           - captured outer variable
 ...
-LL |             Either::One(_t)
-   |                         --
-   |                         |
-   |                         data moved here
-   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         match e {
+   | |               ^ help: consider borrowing here: `&e`
+...  |
+LL | |             Either::One(_t)
+   | |                         --
+   | |                         |
+   | |                         data moved here
+   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:114:15
    |
-LL |     let e = Either::One(X(Y));
-   |         - captured outer variable
+LL |       let e = Either::One(X(Y));
+   |           - captured outer variable
 ...
-LL |         match e {
-   |               ^ help: consider borrowing here: `&e`
-...
-LL |             Either::One(_t) => (),
-   |                         --
-   |                         |
-   |                         data moved here
-   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         match e {
+   | |               ^ help: consider borrowing here: `&e`
+...  |
+LL | |             Either::One(_t) => (),
+   | |                         --
+   | |                         |
+   | |                         data moved here
+   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:123:25
    |
-LL |     let x = X(Y);
-   |         - captured outer variable
+LL |       let x = X(Y);
+   |           - captured outer variable
 ...
-LL |         let X(mut _t) = x;
-   |               ------    ^ help: consider borrowing here: `&x`
-   |               |
-   |               data moved here
-   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         let X(mut _t) = x;
+   | |               ------    ^ help: consider borrowing here: `&x`
+   | |               |
+   | |               data moved here
+   | |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:127:38
    |
-LL |     let mut em = Either::One(X(Y));
-   |         ------ captured outer variable
+LL |       let mut em = Either::One(X(Y));
+   |           ------ captured outer variable
 ...
-LL |         if let Either::One(mut _t) = em { }
-   |                            ------    ^^ help: consider borrowing here: `&em`
-   |                            |
-   |                            data moved here
-   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         if let Either::One(mut _t) = em { }
+   | |                            ------    ^^ help: consider borrowing here: `&em`
+   | |                            |
+   | |                            data moved here
+   | |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:131:41
    |
-LL |     let mut em = Either::One(X(Y));
-   |         ------ captured outer variable
+LL |       let mut em = Either::One(X(Y));
+   |           ------ captured outer variable
 ...
-LL |         while let Either::One(mut _t) = em { }
-   |                               ------    ^^ help: consider borrowing here: `&em`
-   |                               |
-   |                               data moved here
-   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         while let Either::One(mut _t) = em { }
+   | |                               ------    ^^ help: consider borrowing here: `&em`
+   | |                               |
+   | |                               data moved here
+   | |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:135:15
    |
-LL |     let mut em = Either::One(X(Y));
-   |         ------ captured outer variable
-...
-LL |         match em {
-   |               ^^ help: consider borrowing here: `&em`
+LL |       let mut em = Either::One(X(Y));
+   |           ------ captured outer variable
 ...
-LL |             Either::One(mut _t)
-   |                         ------
-   |                         |
-   |                         data moved here
-   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         match em {
+   | |               ^^ help: consider borrowing here: `&em`
+...  |
+LL | |             Either::One(mut _t)
+   | |                         ------
+   | |                         |
+   | |                         data moved here
+   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:142:15
    |
-LL |     let mut em = Either::One(X(Y));
-   |         ------ captured outer variable
+LL |       let mut em = Either::One(X(Y));
+   |           ------ captured outer variable
 ...
-LL |         match em {
-   |               ^^ help: consider borrowing here: `&em`
-...
-LL |             Either::One(mut _t) => (),
-   |                         ------
-   |                         |
-   |                         data moved here
-   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         match em {
+   | |               ^^ help: consider borrowing here: `&em`
+...  |
+LL | |             Either::One(mut _t) => (),
+   | |                         ------
+   | |                         |
+   | |                         data moved here
+   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:150:15
    |
-LL |     let mut em = Either::One(X(Y));
-   |         ------ captured outer variable
-...
-LL |         match em {
-   |               ^^ help: consider borrowing here: `&em`
+LL |       let mut em = Either::One(X(Y));
+   |           ------ captured outer variable
 ...
-LL |             Either::One(mut _t) => (),
-   |                         ------
-   |                         |
-   |                         data moved here
-   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+LL |       consume_fnmut(|| {
+   |  ___________________-
+LL | |         let X(_t) = x;
+LL | |
+LL | |
+...  |
+LL | |         match em {
+   | |               ^^ help: consider borrowing here: `&em`
+...  |
+LL | |             Either::One(mut _t) => (),
+   | |                         ------
+   | |                         |
+   | |                         data moved here
+   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+...  |
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error: aborting due to 21 previous errors
 
diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr
index cfbee1518cd..a0ce7d05b4d 100644
--- a/src/test/ui/suggestions/option-content-move2.stderr
+++ b/src/test/ui/suggestions/option-content-move2.stderr
@@ -1,17 +1,22 @@
 error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
   --> $DIR/option-content-move2.rs:9:9
    |
-LL |     let mut var = None;
-   |         ------- captured outer variable
-...
-LL |         move || {
-   |         ^^^^^^^ move out of `var` occurs here
-LL |
-LL |             var = Some(NotCopyable);
-   |             ---
-   |             |
-   |             move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
-   |             move occurs due to use in closure
+LL |       let mut var = None;
+   |           ------- captured outer variable
+LL |       func(|| {
+   |  __________-
+LL | |         // Shouldn't suggest `move ||.as_ref()` here
+LL | |         move || {
+   | |         ^^^^^^^ move out of `var` occurs here
+LL | |
+LL | |             var = Some(NotCopyable);
+   | |             ---
+   | |             |
+   | |             move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
+   | |             move occurs due to use in closure
+LL | |         }
+LL | |     });
+   | |_____- captured by this `FnMut` closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/typeck/issue-88844.rs b/src/test/ui/typeck/issue-88844.rs
new file mode 100644
index 00000000000..116c75aabdb
--- /dev/null
+++ b/src/test/ui/typeck/issue-88844.rs
@@ -0,0 +1,14 @@
+// Regression test for #88844.
+
+struct Struct { value: i32 }
+//~^ NOTE: similarly named struct `Struct` defined here
+
+impl Stuct {
+//~^ ERROR: cannot find type `Stuct` in this scope [E0412]
+//~| HELP: a struct with a similar name exists
+    fn new() -> Self {
+        Self { value: 42 }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-88844.stderr b/src/test/ui/typeck/issue-88844.stderr
new file mode 100644
index 00000000000..90bba90be34
--- /dev/null
+++ b/src/test/ui/typeck/issue-88844.stderr
@@ -0,0 +1,12 @@
+error[E0412]: cannot find type `Stuct` in this scope
+  --> $DIR/issue-88844.rs:6:6
+   |
+LL | struct Struct { value: i32 }
+   | ------------- similarly named struct `Struct` defined here
+...
+LL | impl Stuct {
+   |      ^^^^^ help: a struct with a similar name exists: `Struct`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/typeck/issue-89044-wrapped-expr-method.fixed b/src/test/ui/typeck/issue-89044-wrapped-expr-method.fixed
new file mode 100644
index 00000000000..0a3086a345d
--- /dev/null
+++ b/src/test/ui/typeck/issue-89044-wrapped-expr-method.fixed
@@ -0,0 +1,9 @@
+// run-rustfix
+
+fn main() {
+    let a = Some(42);
+    println!(
+        "The value is {}.",
+        (a.unwrap()) //~ERROR [E0615]
+    );
+}
diff --git a/src/test/ui/typeck/issue-89044-wrapped-expr-method.rs b/src/test/ui/typeck/issue-89044-wrapped-expr-method.rs
new file mode 100644
index 00000000000..83617e035e9
--- /dev/null
+++ b/src/test/ui/typeck/issue-89044-wrapped-expr-method.rs
@@ -0,0 +1,9 @@
+// run-rustfix
+
+fn main() {
+    let a = Some(42);
+    println!(
+        "The value is {}.",
+        (a.unwrap) //~ERROR [E0615]
+    );
+}
diff --git a/src/test/ui/typeck/issue-89044-wrapped-expr-method.stderr b/src/test/ui/typeck/issue-89044-wrapped-expr-method.stderr
new file mode 100644
index 00000000000..6fa0915dcaf
--- /dev/null
+++ b/src/test/ui/typeck/issue-89044-wrapped-expr-method.stderr
@@ -0,0 +1,14 @@
+error[E0615]: attempted to take value of method `unwrap` on type `Option<{integer}>`
+  --> $DIR/issue-89044-wrapped-expr-method.rs:7:12
+   |
+LL |         (a.unwrap)
+   |            ^^^^^^ method, not a field
+   |
+help: use parentheses to call the method
+   |
+LL |         (a.unwrap())
+   |                  ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0615`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
index f8c90176ff1..482d3e44fe4 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
@@ -4,7 +4,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
 LL |         let x = Box::new(0);
    |             - captured outer variable
 LL |         let f = to_fn(|| drop(x));
-   |                               ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                       --------^-
+   |                       |       |
+   |                       |       move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                       captured by this `Fn` closure
 
 error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
   --> $DIR/unboxed-closure-illegal-move.rs:19:35
@@ -12,7 +15,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
 LL |         let x = Box::new(0);
    |             - captured outer variable
 LL |         let f = to_fn_mut(|| drop(x));
-   |                                   ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                           --------^-
+   |                           |       |
+   |                           |       move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                           captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
   --> $DIR/unboxed-closure-illegal-move.rs:28:36
@@ -20,7 +26,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
 LL |         let x = Box::new(0);
    |             - captured outer variable
 LL |         let f = to_fn(move || drop(x));
-   |                                    ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                       -------------^-
+   |                       |            |
+   |                       |            move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                       captured by this `Fn` closure
 
 error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
   --> $DIR/unboxed-closure-illegal-move.rs:32:40
@@ -28,7 +37,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
 LL |         let x = Box::new(0);
    |             - captured outer variable
 LL |         let f = to_fn_mut(move || drop(x));
-   |                                        ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                           -------------^-
+   |                           |            |
+   |                           |            move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                           captured by this `FnMut` closure
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject e515c3277bf0681bfc79a9e763861bfe26bb05d
+Subproject 9a28ac83c9eb73e42ffafac552c0a55f00dbf40
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 5f1267fc3d2..60703384e9e 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -144,6 +144,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "num-integer",
     "num-traits",
     "object",
+    "odht",
     "once_cell",
     "opaque-debug",
     "parking_lot",