about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc/src/main.rs41
-rw-r--r--compiler/rustc_ast/src/ast.rs6
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs29
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs132
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs23
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs37
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs4
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs47
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/mod.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs153
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs44
-rw-r--r--compiler/rustc_borrowck/src/lib.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs20
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs17
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs105
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs28
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml15
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml2
-rw-r--r--compiler/rustc_codegen_cranelift/.gitignore1
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml19
-rw-r--r--compiler/rustc_codegen_cranelift/Readme.md2
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_backend.rs31
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/docs/usage.md6
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs (renamed from compiler/rustc_codegen_cranelift/scripts/cargo.rs)0
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh16
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/tests.sh36
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs25
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs18
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_gcc/Cargo.lock69
-rw-r--r--compiler/rustc_codegen_gcc/Cargo.toml5
-rw-r--r--compiler/rustc_codegen_gcc/Readme.md2
-rw-r--r--compiler/rustc_codegen_gcc/config.sh2
-rw-r--r--compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch20
-rw-r--r--compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch24
-rw-r--r--compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch30
-rw-r--r--compiler/rustc_codegen_gcc/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs111
-rw-r--r--compiler/rustc_codegen_gcc/src/back/write.rs24
-rw-r--r--compiler/rustc_codegen_gcc/src/base.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs51
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs14
-rw-r--r--compiler/rustc_codegen_gcc/src/consts.rs18
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs12
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs32
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/type_.rs6
-rwxr-xr-xcompiler/rustc_codegen_gcc/test.sh2
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/asm.rs31
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs59
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs30
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs34
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs38
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs257
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs101
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs31
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs23
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs43
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs318
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs9
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs1
-rw-r--r--compiler/rustc_const_eval/src/util/aggregate.rs3
-rw-r--r--compiler/rustc_data_structures/src/sip128.rs18
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs5
-rw-r--r--compiler/rustc_data_structures/src/thin_vec.rs14
-rw-r--r--compiler/rustc_driver/Cargo.toml6
-rw-r--r--compiler/rustc_driver/src/lib.rs59
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0227.md33
-rw-r--r--compiler/rustc_expand/src/expand.rs24
-rw-r--r--compiler/rustc_expand/src/placeholders.rs7
-rw-r--r--compiler/rustc_hir/src/hir.rs20
-rw-r--r--compiler/rustc_hir/src/intravisit.rs14
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs9
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs29
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs42
-rw-r--r--compiler/rustc_index/Cargo.toml1
-rw-r--r--compiler/rustc_index/src/interval.rs269
-rw-r--r--compiler/rustc_index/src/interval/tests.rs199
-rw-r--r--compiler/rustc_index/src/lib.rs1
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs41
-rw-r--r--compiler/rustc_interface/src/interface.rs38
-rw-r--r--compiler/rustc_interface/src/passes.rs4
-rw-r--r--compiler/rustc_interface/src/tests.rs10
-rw-r--r--compiler/rustc_interface/src/util.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp18
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp24
-rw-r--r--compiler/rustc_log/Cargo.toml16
-rw-r--r--compiler/rustc_log/src/lib.rs115
-rw-r--r--compiler/rustc_macros/src/serialize.rs26
-rw-r--r--compiler/rustc_metadata/src/creader.rs161
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs232
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs56
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs115
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs13
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs7
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs34
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs7
-rw-r--r--compiler/rustc_middle/src/query/mod.rs42
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs45
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs5
-rw-r--r--compiler/rustc_middle/src/ty/context.rs6
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs12
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs11
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/query.rs1
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs37
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs30
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs9
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs14
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs4
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs11
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs15
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs2
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs14
-rw-r--r--compiler/rustc_parse/src/parser/item.rs55
-rw-r--r--compiler/rustc_passes/src/check_const.rs13
-rw-r--r--compiler/rustc_passes/src/lib_features.rs6
-rw-r--r--compiler/rustc_passes/src/stability.rs19
-rw-r--r--compiler/rustc_privacy/src/lib.rs6
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs14
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs14
-rw-r--r--compiler/rustc_query_system/src/ich/impls_hir.rs25
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs4
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs9
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs4
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs10
-rw-r--r--compiler/rustc_resolve/src/late.rs7
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs9
-rw-r--r--compiler/rustc_resolve/src/lib.rs41
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs28
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs12
-rw-r--r--compiler/rustc_save_analysis/src/sig.rs4
-rw-r--r--compiler/rustc_serialize/src/opaque.rs23
-rw-r--r--compiler/rustc_session/src/config.rs137
-rw-r--r--compiler/rustc_session/src/cstore.rs6
-rw-r--r--compiler/rustc_session/src/options.rs53
-rw-r--r--compiler/rustc_span/src/def_id.rs20
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs4
-rw-r--r--compiler/rustc_target/src/spec/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs33
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs34
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs18
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_traits/src/lib.rs1
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs2
-rw-r--r--compiler/rustc_traits/src/type_op.rs12
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs239
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs43
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs2
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs119
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs10
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs4
-rw-r--r--compiler/rustc_typeck/src/check/check.rs208
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs6
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs7
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs227
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs3
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs76
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs4
-rw-r--r--compiler/rustc_typeck/src/collect.rs49
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs15
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs9
200 files changed, 3746 insertions, 2309 deletions
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs
index c80fab99496..4edd095af10 100644
--- a/compiler/rustc/src/main.rs
+++ b/compiler/rustc/src/main.rs
@@ -1,25 +1,32 @@
-// Configure jemalloc as the `global_allocator` when configured. This is
-// so that we use the sized deallocation apis jemalloc provides
-// (namely `sdallocx`).
+// A note about jemalloc: rustc uses jemalloc when built for CI and
+// distribution. The obvious way to do this is with the `#[global_allocator]`
+// mechanism. However, for complicated reasons (see
+// https://github.com/rust-lang/rust/pull/81782#issuecomment-784438001 for some
+// details) that mechanism doesn't work here. Also, we must use a consistent
+// allocator across the rustc <-> llvm boundary, and `#[global_allocator]`
+// wouldn't provide that.
 //
-// The symbol overrides documented below are also performed so that we can
-// ensure that we use a consistent allocator across the rustc <-> llvm boundary
-#[cfg(feature = "jemalloc")]
-#[global_allocator]
-static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
-
+// Instead, we use a lower-level mechanism. rustc is linked with jemalloc in a
+// way such that jemalloc's implementation of `malloc`, `free`, etc., override
+// the libc allocator's implementation. This means that Rust's `System`
+// allocator, which calls `libc::malloc()` et al., is actually calling into
+// jemalloc.
+//
+// A consequence of not using `GlobalAlloc` (and the `tikv-jemallocator` crate
+// provides an impl of that trait, which is called `Jemalloc`) is that we
+// cannot use the sized deallocation APIs (`sdallocx`) that jemalloc provides.
+// It's unclear how much performance is lost because of this.
+//
+// As for the symbol overrides in `main` below: we're pulling in a static copy
+// of jemalloc. We need to actually reference its symbols for it to get linked.
+// The two crates we link to here, `std` and `rustc_driver`, are both dynamic
+// libraries. So we must reference jemalloc symbols one way or another, because
+// this file is the only object code in the rustc executable.
 #[cfg(feature = "tikv-jemalloc-sys")]
 use tikv_jemalloc_sys as jemalloc_sys;
 
 fn main() {
-    // Pull in jemalloc when enabled.
-    //
-    // Note that we're pulling in a static copy of jemalloc which means that to
-    // pull it in we need to actually reference its symbols for it to get
-    // linked. The two crates we link to here, std and rustc_driver, are both
-    // dynamic libraries. That means to pull in jemalloc we actually need to
-    // reference allocation symbols one way or another (as this file is the only
-    // object code in the rustc executable).
+    // See the comment at the top of this file for an explanation of this.
     #[cfg(feature = "tikv-jemalloc-sys")]
     {
         use std::os::raw::{c_int, c_void};
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 4f55f37e2e9..a2d32cdc00f 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -510,8 +510,10 @@ pub struct Crate {
     pub attrs: Vec<Attribute>,
     pub items: Vec<P<Item>>,
     pub span: Span,
-    // Placeholder ID if the crate node is a macro placeholder.
-    pub is_placeholder: Option<NodeId>,
+    /// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold
+    /// expansion placeholders or an unassigned value (`DUMMY_NODE_ID`) before that.
+    pub id: NodeId,
+    pub is_placeholder: bool,
 }
 
 /// Possible values inside of compile-time attribute lists.
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 927d7c6aaf6..d66774040f7 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -136,15 +136,15 @@ impl Attribute {
 
     pub fn value_str(&self) -> Option<Symbol> {
         match self.kind {
-            AttrKind::Normal(ref item, _) => item.meta(self.span).and_then(|meta| meta.value_str()),
+            AttrKind::Normal(ref item, _) => item.meta_kind().and_then(|kind| kind.value_str()),
             AttrKind::DocComment(..) => None,
         }
     }
 
     pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
         match self.kind {
-            AttrKind::Normal(ref item, _) => match item.meta(self.span) {
-                Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
+            AttrKind::Normal(ref item, _) => match item.meta_kind() {
+                Some(MetaItemKind::List(list)) => Some(list),
                 _ => None,
             },
             AttrKind::DocComment(..) => None,
@@ -228,6 +228,10 @@ impl AttrItem {
             span,
         })
     }
+
+    pub fn meta_kind(&self) -> Option<MetaItemKind> {
+        Some(MetaItemKind::from_mac_args(&self.args)?)
+    }
 }
 
 impl Attribute {
@@ -242,7 +246,7 @@ impl Attribute {
         match self.kind {
             AttrKind::DocComment(.., data) => Some(data),
             AttrKind::Normal(ref item, _) if item.path == sym::doc => {
-                item.meta(self.span).and_then(|meta| meta.value_str())
+                item.meta_kind().and_then(|kind| kind.value_str())
             }
             _ => None,
         }
@@ -270,6 +274,13 @@ impl Attribute {
         }
     }
 
+    pub fn meta_kind(&self) -> Option<MetaItemKind> {
+        match self.kind {
+            AttrKind::Normal(ref item, _) => item.meta_kind(),
+            AttrKind::DocComment(..) => None,
+        }
+    }
+
     pub fn tokens(&self) -> AttrAnnotatedTokenStream {
         match self.kind {
             AttrKind::Normal(_, ref tokens) => tokens
@@ -436,6 +447,16 @@ impl MetaItem {
 }
 
 impl MetaItemKind {
+    pub fn value_str(&self) -> Option<Symbol> {
+        match self {
+            MetaItemKind::NameValue(ref v) => match v.kind {
+                LitKind::Str(ref s, _) => Some(*s),
+                _ => None,
+            },
+            _ => None,
+        }
+    }
+
     pub fn mac_args(&self, span: Span) -> MacArgs {
         match self {
             MetaItemKind::Word => MacArgs::Empty,
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 6bf23af81bf..9ef78aaf667 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -14,13 +14,14 @@ use crate::tokenstream::*;
 
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::thin_vec::ThinVec;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
 use smallvec::{smallvec, Array, SmallVec};
 use std::ops::DerefMut;
-use std::{panic, process, ptr};
+use std::{panic, ptr};
 
 pub trait ExpectOne<A: Array> {
     fn expect_one(self, err: &'static str) -> A::Item;
@@ -283,23 +284,21 @@ pub trait MutVisitor: Sized {
 
 /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
 /// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
-/// method. Abort the program if the closure panics.
-///
-/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler.
-/// Instead of aborting on catching a panic we need to reset the visited node to some valid but
-/// possibly meaningless value and rethrow the panic.
+/// method.
 //
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-pub fn visit_clobber<T, F>(t: &mut T, f: F)
-where
-    F: FnOnce(T) -> T,
-{
+pub fn visit_clobber<T: DummyAstNode>(t: &mut T, f: impl FnOnce(T) -> T) {
     unsafe {
         // Safe because `t` is used in a read-only fashion by `read()` before
         // being overwritten by `write()`.
         let old_t = ptr::read(t);
-        let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t)))
-            .unwrap_or_else(|_| process::abort());
+        let new_t =
+            panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t))).unwrap_or_else(|err| {
+                // Set `t` to some valid but possible meaningless value,
+                // and pass the fatal error further.
+                ptr::write(t, T::dummy());
+                panic::resume_unwind(err);
+            });
         ptr::write(t, new_t);
     }
 }
@@ -1110,7 +1109,8 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
 }
 
 pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
-    let Crate { attrs, items, span, is_placeholder: _ } = krate;
+    let Crate { attrs, items, span, id, is_placeholder: _ } = krate;
+    vis.visit_id(id);
     visit_attrs(attrs, vis);
     items.flat_map_in_place(|item| vis.flat_map_item(item));
     vis.visit_span(span);
@@ -1454,3 +1454,109 @@ pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
     }
     vis.visit_span(&mut visibility.span);
 }
+
+/// Some value for the AST node that is valid but possibly meaningless.
+pub trait DummyAstNode {
+    fn dummy() -> Self;
+}
+
+impl<T> DummyAstNode for Option<T> {
+    fn dummy() -> Self {
+        Default::default()
+    }
+}
+
+impl<T: DummyAstNode + 'static> DummyAstNode for P<T> {
+    fn dummy() -> Self {
+        P(DummyAstNode::dummy())
+    }
+}
+
+impl<T> DummyAstNode for ThinVec<T> {
+    fn dummy() -> Self {
+        Default::default()
+    }
+}
+
+impl DummyAstNode for Item {
+    fn dummy() -> Self {
+        Item {
+            attrs: Default::default(),
+            id: DUMMY_NODE_ID,
+            span: Default::default(),
+            vis: Visibility {
+                kind: VisibilityKind::Public,
+                span: Default::default(),
+                tokens: Default::default(),
+            },
+            ident: Ident::empty(),
+            kind: ItemKind::ExternCrate(None),
+            tokens: Default::default(),
+        }
+    }
+}
+
+impl DummyAstNode for Expr {
+    fn dummy() -> Self {
+        Expr {
+            id: DUMMY_NODE_ID,
+            kind: ExprKind::Err,
+            span: Default::default(),
+            attrs: Default::default(),
+            tokens: Default::default(),
+        }
+    }
+}
+
+impl DummyAstNode for Ty {
+    fn dummy() -> Self {
+        Ty {
+            id: DUMMY_NODE_ID,
+            kind: TyKind::Err,
+            span: Default::default(),
+            tokens: Default::default(),
+        }
+    }
+}
+
+impl DummyAstNode for Pat {
+    fn dummy() -> Self {
+        Pat {
+            id: DUMMY_NODE_ID,
+            kind: PatKind::Wild,
+            span: Default::default(),
+            tokens: Default::default(),
+        }
+    }
+}
+
+impl DummyAstNode for Stmt {
+    fn dummy() -> Self {
+        Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Empty, span: Default::default() }
+    }
+}
+
+impl DummyAstNode for Block {
+    fn dummy() -> Self {
+        Block {
+            stmts: Default::default(),
+            id: DUMMY_NODE_ID,
+            rules: BlockCheckMode::Default,
+            span: Default::default(),
+            tokens: Default::default(),
+            could_be_bare_literal: Default::default(),
+        }
+    }
+}
+
+impl DummyAstNode for Crate {
+    fn dummy() -> Self {
+        Crate {
+            attrs: Default::default(),
+            items: Default::default(),
+            span: Default::default(),
+            id: DUMMY_NODE_ID,
+            is_placeholder: Default::default(),
+        }
+    }
+}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 6ee1dbe4ae3..75f384405bb 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -34,7 +34,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 }
                 ExprKind::Repeat(ref expr, ref count) => {
                     let expr = self.lower_expr(expr);
-                    let count = self.lower_anon_const(count);
+                    let count = self.lower_array_length(count);
                     hir::ExprKind::Repeat(expr, count)
                 }
                 ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 77738b2c5cc..35eb716949a 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -56,6 +56,7 @@ use rustc_hir::{ConstArg, GenericArg, ParamName};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::LintBuffer;
+use rustc_session::parse::feature_err;
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
 use rustc_span::hygiene::ExpnId;
@@ -1248,7 +1249,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 ))
             }
             TyKind::Array(ref ty, ref length) => {
-                hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length))
+                hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
             }
             TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
             TyKind::TraitObject(ref bounds, kind) => {
@@ -2039,6 +2040,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.expr_block(block, AttrVec::new())
     }
 
+    fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
+        match c.value.kind {
+            ExprKind::Underscore => {
+                if self.sess.features_untracked().generic_arg_infer {
+                    hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
+                } else {
+                    feature_err(
+                        &self.sess.parse_sess,
+                        sym::generic_arg_infer,
+                        c.value.span,
+                        "using `_` for array lengths is unstable",
+                    )
+                    .emit();
+                    hir::ArrayLen::Body(self.lower_anon_const(c))
+                }
+            }
+            _ => hir::ArrayLen::Body(self.lower_anon_const(c)),
+        }
+    }
+
     fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
         self.with_new_scopes(|this| hir::AnonConst {
             hir_id: this.lower_node_id(c.id),
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 0a9b264aa42..ebae7798433 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -24,7 +24,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
                         break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
                     }
-                    PatKind::Lit(ref e) => break hir::PatKind::Lit(self.lower_expr(e)),
+                    PatKind::Lit(ref e) => {
+                        break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
+                    }
                     PatKind::TupleStruct(ref qself, ref path, ref pats) => {
                         let qpath = self.lower_qpath(
                             pattern.id,
@@ -81,8 +83,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                     PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => {
                         break hir::PatKind::Range(
-                            e1.as_deref().map(|e| self.lower_expr(e)),
-                            e2.as_deref().map(|e| self.lower_expr(e)),
+                            e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
+                            e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
                             self.lower_range_end(end, e2.is_some()),
                         );
                     }
@@ -314,4 +316,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included,
         }
     }
+
+    /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
+    /// or paths for ranges.
+    //
+    // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
+    // That means making this work:
+    //
+    // ```rust,ignore (FIXME)
+    // struct S;
+    // macro_rules! m {
+    //     ($a:expr) => {
+    //         let $a = S;
+    //     }
+    // }
+    // m!(S);
+    // ```
+    fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
+        match expr.kind {
+            ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
+            ExprKind::Path(..) if allow_paths => {}
+            ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
+            _ => {
+                self.diagnostic()
+                    .span_err(expr.span, "arbitrary expressions aren't allowed in patterns");
+                return self.arena.alloc(self.expr_err(expr.span));
+            }
+        }
+        self.lower_expr(expr)
+    }
 }
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 78afc339748..46928a18465 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -277,7 +277,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
             let elided_lifetime_span = if generic_args.span.is_empty() {
                 // If there are no brackets, use the identifier span.
-                path_span
+                // HACK: we use find_ancestor_inside to properly suggest elided spans in paths
+                // originating from macros, since the segment's span might be from a macro arg.
+                segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
             } else if generic_args.is_empty() {
                 // If there are brackets, but not generic arguments, then use the opening bracket
                 generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 3c3ea2bfd35..6237a01f694 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -302,34 +302,6 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
-    /// or paths for ranges.
-    //
-    // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
-    // That means making this work:
-    //
-    // ```rust,ignore (FIXME)
-    // struct S;
-    // macro_rules! m {
-    //     ($a:expr) => {
-    //         let $a = S;
-    //     }
-    // }
-    // m!(S);
-    // ```
-    fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
-        match expr.kind {
-            ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
-            ExprKind::Path(..) if allow_paths => {}
-            ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
-            _ => self.err_handler().span_err(
-                expr.span,
-                "arbitrary expressions aren't allowed \
-                                                         in patterns",
-            ),
-        }
-    }
-
     fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
         // Check only lifetime parameters are present and that the lifetime
         // parameters that are present have no bounds.
@@ -1426,25 +1398,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         visit::walk_param_bound(self, bound)
     }
 
-    fn visit_pat(&mut self, pat: &'a Pat) {
-        match &pat.kind {
-            PatKind::Lit(expr) => {
-                self.check_expr_within_pat(expr, false);
-            }
-            PatKind::Range(start, end, _) => {
-                if let Some(expr) = start {
-                    self.check_expr_within_pat(expr, true);
-                }
-                if let Some(expr) = end {
-                    self.check_expr_within_pat(expr, true);
-                }
-            }
-            _ => {}
-        }
-
-        visit::walk_pat(self, pat)
-    }
-
     fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
         self.check_late_bound_lifetime_defs(&t.bound_generic_params);
         visit::walk_poly_trait_ref(self, t, m);
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
index 4b5703a429e..ac9e7d06c4e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/mod.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -73,11 +73,11 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String {
 }
 
 pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
-    State::new().to_string(f)
+    State::to_string(f)
 }
 
 pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String {
-    State::new().to_string(|s| {
+    State::to_string(|s| {
         s.print_inner_attributes(&krate.attrs);
         for item in &krate.items {
             s.print_item(item);
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 6c5b38bc4bb..fa9a20f2e03 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -211,7 +211,7 @@ pub fn literal_to_string(lit: token::Lit) -> String {
 }
 
 fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
-    format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s)
+    format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
 }
 
 impl std::ops::Deref for State<'_> {
@@ -387,23 +387,23 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         self.print_string(sym.as_str(), style);
     }
 
-    fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
+    fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
     }
 
-    fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
+    fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
     }
 
-    fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
+    fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
     }
 
-    fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
+    fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
     }
 
-    fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
+    fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
     }
 
@@ -413,20 +413,21 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         kind: ast::AttrStyle,
         is_inline: bool,
         trailing_hardbreak: bool,
-    ) {
-        let mut count = 0;
+    ) -> bool {
+        let mut printed = false;
         for attr in attrs {
             if attr.style == kind {
                 self.print_attribute_inline(attr, is_inline);
                 if is_inline {
                     self.nbsp();
                 }
-                count += 1;
+                printed = true;
             }
         }
-        if count > 0 && trailing_hardbreak && !is_inline {
+        if printed && trailing_hardbreak && !is_inline {
             self.hardbreak_if_not_bol();
         }
+        printed
     }
 
     fn print_attribute(&mut self, attr: &ast::Attribute) {
@@ -792,55 +793,55 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
     }
 
     fn ty_to_string(&self, ty: &ast::Ty) -> String {
-        self.to_string(|s| s.print_type(ty))
+        Self::to_string(|s| s.print_type(ty))
     }
 
     fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
-        self.to_string(|s| s.print_type_bounds("", bounds))
+        Self::to_string(|s| s.print_type_bounds("", bounds))
     }
 
     fn pat_to_string(&self, pat: &ast::Pat) -> String {
-        self.to_string(|s| s.print_pat(pat))
+        Self::to_string(|s| s.print_pat(pat))
     }
 
     fn expr_to_string(&self, e: &ast::Expr) -> String {
-        self.to_string(|s| s.print_expr(e))
+        Self::to_string(|s| s.print_expr(e))
     }
 
     fn tt_to_string(&self, tt: &TokenTree) -> String {
-        self.to_string(|s| s.print_tt(tt, false))
+        Self::to_string(|s| s.print_tt(tt, false))
     }
 
     fn tts_to_string(&self, tokens: &TokenStream) -> String {
-        self.to_string(|s| s.print_tts(tokens, false))
+        Self::to_string(|s| s.print_tts(tokens, false))
     }
 
     fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
-        self.to_string(|s| s.print_stmt(stmt))
+        Self::to_string(|s| s.print_stmt(stmt))
     }
 
     fn item_to_string(&self, i: &ast::Item) -> String {
-        self.to_string(|s| s.print_item(i))
+        Self::to_string(|s| s.print_item(i))
     }
 
     fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String {
-        self.to_string(|s| s.print_generic_params(generic_params))
+        Self::to_string(|s| s.print_generic_params(generic_params))
     }
 
     fn path_to_string(&self, p: &ast::Path) -> String {
-        self.to_string(|s| s.print_path(p, false, 0))
+        Self::to_string(|s| s.print_path(p, false, 0))
     }
 
     fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
-        self.to_string(|s| s.print_path_segment(p, false))
+        Self::to_string(|s| s.print_path_segment(p, false))
     }
 
     fn vis_to_string(&self, v: &ast::Visibility) -> String {
-        self.to_string(|s| s.print_visibility(v))
+        Self::to_string(|s| s.print_visibility(v))
     }
 
     fn block_to_string(&self, blk: &ast::Block) -> String {
-        self.to_string(|s| {
+        Self::to_string(|s| {
             // Containing cbox, will be closed by `print_block` at `}`.
             s.cbox(INDENT_UNIT);
             // Head-ibox, will be closed by `print_block` after `{`.
@@ -850,22 +851,22 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
     }
 
     fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
-        self.to_string(|s| s.print_meta_list_item(li))
+        Self::to_string(|s| s.print_meta_list_item(li))
     }
 
     fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
-        self.to_string(|s| s.print_attr_item(ai, ai.path.span))
+        Self::to_string(|s| s.print_attr_item(ai, ai.path.span))
     }
 
     fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
-        self.to_string(|s| s.print_attribute(attr))
+        Self::to_string(|s| s.print_attribute(attr))
     }
 
     fn param_to_string(&self, arg: &ast::Param) -> String {
-        self.to_string(|s| s.print_param(arg, false))
+        Self::to_string(|s| s.print_param(arg, false))
     }
 
-    fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String {
+    fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
         let mut printer = State::new();
         f(&mut printer);
         printer.s.eof()
@@ -1115,7 +1116,9 @@ impl<'a> State<'a> {
         self.print_ident(ident);
         self.word_space(":");
         self.print_type(ty);
-        self.space();
+        if body.is_some() {
+            self.space();
+        }
         self.end(); // end the head-ibox
         if let Some(body) = body {
             self.word_space("=");
@@ -1199,7 +1202,7 @@ impl<'a> State<'a> {
                 );
             }
             ast::ItemKind::Mod(unsafety, ref mod_kind) => {
-                self.head(self.to_string(|s| {
+                self.head(Self::to_string(|s| {
                     s.print_visibility(&item.vis);
                     s.print_unsafety(unsafety);
                     s.word("mod");
@@ -1225,7 +1228,7 @@ impl<'a> State<'a> {
                 }
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
-                self.head(self.to_string(|s| {
+                self.head(Self::to_string(|s| {
                     s.print_unsafety(nmod.unsafety);
                     s.word("extern");
                 }));
@@ -1284,14 +1287,17 @@ impl<'a> State<'a> {
                 self.print_visibility(&item.vis);
                 self.print_defaultness(defaultness);
                 self.print_unsafety(unsafety);
-                self.word_nbsp("impl");
-                self.print_constness(constness);
+                self.word("impl");
 
-                if !generics.params.is_empty() {
+                if generics.params.is_empty() {
+                    self.nbsp();
+                } else {
                     self.print_generic_params(&generics.params);
                     self.space();
                 }
 
+                self.print_constness(constness);
+
                 if let ast::ImplPolarity::Negative(_) = polarity {
                     self.word("!");
                 }
@@ -1444,7 +1450,7 @@ impl<'a> State<'a> {
                 ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
             },
             ast::VisibilityKind::Restricted { ref path, .. } => {
-                let path = self.to_string(|s| s.print_path(path, false, 0));
+                let path = Self::to_string(|s| s.print_path(path, false, 0));
                 if path == "self" || path == "super" {
                     self.word_nbsp(format!("pub({})", path))
                 } else {
@@ -1646,7 +1652,7 @@ impl<'a> State<'a> {
         self.ann.pre(self, AnnNode::Block(blk));
         self.bopen();
 
-        self.print_inner_attributes(attrs);
+        let has_attrs = self.print_inner_attributes(attrs);
 
         for (i, st) in blk.stmts.iter().enumerate() {
             match st.kind {
@@ -1660,7 +1666,7 @@ impl<'a> State<'a> {
             }
         }
 
-        let empty = attrs.is_empty() && blk.stmts.is_empty();
+        let empty = !has_attrs && blk.stmts.is_empty();
         self.bclose_maybe_open(blk.span, empty, close_box);
         self.ann.post(self, AnnNode::Block(blk))
     }
@@ -2238,7 +2244,6 @@ impl<'a> State<'a> {
             }
             ast::ExprKind::TryBlock(ref blk) => {
                 self.head("try");
-                self.space();
                 self.print_block_with_attrs(blk, attrs)
             }
             ast::ExprKind::Err => {
@@ -2459,7 +2464,11 @@ impl<'a> State<'a> {
                     self.print_path(path, true, 0);
                 }
                 self.nbsp();
-                self.word_space("{");
+                self.word("{");
+                let empty = fields.is_empty() && !etc;
+                if !empty {
+                    self.space();
+                }
                 self.commasep_cmnt(
                     Consistent,
                     &fields,
@@ -2480,7 +2489,9 @@ impl<'a> State<'a> {
                     }
                     self.word("..");
                 }
-                self.space();
+                if !empty {
+                    self.space();
+                }
                 self.word("}");
             }
             PatKind::Tuple(ref elts) => {
@@ -2514,7 +2525,6 @@ impl<'a> State<'a> {
             PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
                 if let Some(e) = begin {
                     self.print_expr(e);
-                    self.space();
                 }
                 match *end_kind {
                     RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."),
@@ -2780,34 +2790,34 @@ impl<'a> State<'a> {
                 self.word_space(",");
             }
 
-            match *predicate {
-                ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
-                    ref bound_generic_params,
-                    ref bounded_ty,
-                    ref bounds,
-                    ..
-                }) => {
-                    self.print_formal_generic_params(bound_generic_params);
-                    self.print_type(bounded_ty);
-                    self.print_type_bounds(":", bounds);
-                }
-                ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
-                    ref lifetime,
-                    ref bounds,
-                    ..
-                }) => {
-                    self.print_lifetime_bounds(*lifetime, bounds);
-                }
-                ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
-                    ref lhs_ty,
-                    ref rhs_ty,
-                    ..
-                }) => {
-                    self.print_type(lhs_ty);
-                    self.space();
-                    self.word_space("=");
-                    self.print_type(rhs_ty);
-                }
+            self.print_where_predicate(predicate);
+        }
+    }
+
+    pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
+        match predicate {
+            ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                bound_generic_params,
+                bounded_ty,
+                bounds,
+                ..
+            }) => {
+                self.print_formal_generic_params(bound_generic_params);
+                self.print_type(bounded_ty);
+                self.print_type_bounds(":", bounds);
+            }
+            ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+                lifetime,
+                bounds,
+                ..
+            }) => {
+                self.print_lifetime_bounds(*lifetime, bounds);
+            }
+            ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
+                self.print_type(lhs_ty);
+                self.space();
+                self.word_space("=");
+                self.print_type(rhs_ty);
             }
         }
     }
@@ -2908,10 +2918,7 @@ impl<'a> State<'a> {
         generic_params: &[ast::GenericParam],
     ) {
         self.ibox(INDENT_UNIT);
-        if !generic_params.is_empty() {
-            self.word("for");
-            self.print_generic_params(generic_params);
-        }
+        self.print_formal_generic_params(generic_params);
         let generics = ast::Generics {
             params: Vec::new(),
             where_clause: ast::WhereClause {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 11cdbe84acc..df23eaf24bc 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -6,7 +6,7 @@ use rustc_infer::infer::{
     error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
 };
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span};
@@ -334,13 +334,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
         match variance_info {
             ty::VarianceDiagInfo::None => {}
-            ty::VarianceDiagInfo::Mut { kind, ty } => {
-                let kind_name = match kind {
-                    ty::VarianceDiagMutKind::Ref => "reference",
-                    ty::VarianceDiagMutKind::RawPtr => "pointer",
+            ty::VarianceDiagInfo::Invariant { ty, param_index } => {
+                let (desc, note) = match ty.kind() {
+                    ty::RawPtr(ty_mut) => {
+                        assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut);
+                        (
+                            format!("a mutable pointer to {}", ty_mut.ty),
+                            "mutable pointers are invariant over their type parameter".to_string(),
+                        )
+                    }
+                    ty::Ref(_, inner_ty, mutbl) => {
+                        assert_eq!(*mutbl, rustc_hir::Mutability::Mut);
+                        (
+                            format!("a mutable reference to {}", inner_ty),
+                            "mutable references are invariant over their type parameter"
+                                .to_string(),
+                        )
+                    }
+                    ty::Adt(adt, substs) => {
+                        let generic_arg = substs[param_index as usize];
+                        let identity_substs =
+                            InternalSubsts::identity_for_item(self.infcx.tcx, adt.did);
+                        let base_ty = self.infcx.tcx.mk_adt(adt, identity_substs);
+                        let base_generic_arg = identity_substs[param_index as usize];
+                        let adt_desc = adt.descr();
+
+                        let desc = format!(
+                            "the type {ty}, which makes the generic argument {generic_arg} invariant"
+                        );
+                        let note = format!(
+                            "the {adt_desc} {base_ty} is invariant over the parameter {base_generic_arg}"
+                        );
+                        (desc, note)
+                    }
+                    _ => panic!("Unexpected type {:?}", ty),
                 };
-                diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",));
-                diag.note(&format!("mutable {kind_name}s are invariant over their type parameter"));
+                diag.note(&format!("requirement occurs because of {desc}",));
+                diag.note(&note);
                 diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
             }
         }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 63ffcb3ec45..fe34d6e7ca9 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1394,10 +1394,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
             Rvalue::NullaryOp(_op, _ty) => {
                 // nullary ops take no dynamic input; no borrowck effect.
-                //
-                // FIXME: is above actually true? Do we want to track
-                // the fact that uninitialized data can be created via
-                // `NullOp::Box`?
             }
 
             Rvalue::Aggregate(ref aggregate_kind, ref operands) => {
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index 100ac578f92..4a70535c63b 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -1,5 +1,7 @@
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
+use rustc_index::bit_set::SparseBitMatrix;
+use rustc_index::interval::IntervalSet;
+use rustc_index::interval::SparseIntervalMatrix;
 use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::{BasicBlock, Body, Location};
@@ -110,11 +112,11 @@ crate enum RegionElement {
     PlaceholderRegion(ty::PlaceholderRegion),
 }
 
-/// When we initially compute liveness, we use a bit matrix storing
-/// points for each region-vid.
+/// When we initially compute liveness, we use an interval matrix storing
+/// liveness ranges for each region-vid.
 crate struct LivenessValues<N: Idx> {
     elements: Rc<RegionValueElements>,
-    points: SparseBitMatrix<N, PointIndex>,
+    points: SparseIntervalMatrix<N, PointIndex>,
 }
 
 impl<N: Idx> LivenessValues<N> {
@@ -122,7 +124,7 @@ impl<N: Idx> LivenessValues<N> {
     /// Each of the regions in num_region_variables will be initialized with an
     /// empty set of points and no causal information.
     crate fn new(elements: Rc<RegionValueElements>) -> Self {
-        Self { points: SparseBitMatrix::new(elements.num_points), elements }
+        Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
     }
 
     /// Iterate through each region that has a value in this set.
@@ -140,7 +142,7 @@ impl<N: Idx> LivenessValues<N> {
 
     /// Adds all the elements in the given bit array into the given
     /// region. Returns whether any of them are newly added.
-    crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool {
+    crate fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool {
         debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
         self.points.union_row(row, locations)
     }
@@ -153,7 +155,7 @@ impl<N: Idx> LivenessValues<N> {
     /// Returns `true` if the region `r` contains the given element.
     crate fn contains(&self, row: N, location: Location) -> bool {
         let index = self.elements.point_from_location(location);
-        self.points.contains(row, index)
+        self.points.row(row).map_or(false, |r| r.contains(index))
     }
 
     /// Returns an iterator of all the elements contained by the region `r`
@@ -221,7 +223,7 @@ impl PlaceholderIndices {
 crate struct RegionValues<N: Idx> {
     elements: Rc<RegionValueElements>,
     placeholder_indices: Rc<PlaceholderIndices>,
-    points: SparseBitMatrix<N, PointIndex>,
+    points: SparseIntervalMatrix<N, PointIndex>,
     free_regions: SparseBitMatrix<N, RegionVid>,
 
     /// Placeholders represent bound regions -- so something like `'a`
@@ -241,7 +243,7 @@ impl<N: Idx> RegionValues<N> {
         let num_placeholders = placeholder_indices.len();
         Self {
             elements: elements.clone(),
-            points: SparseBitMatrix::new(elements.num_points),
+            points: SparseIntervalMatrix::new(elements.num_points),
             placeholder_indices: placeholder_indices.clone(),
             free_regions: SparseBitMatrix::new(num_universal_regions),
             placeholders: SparseBitMatrix::new(num_placeholders),
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 0969b9a508f..094af20f52e 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::bit_set::HybridBitSet;
+use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
 use rustc_middle::ty::{Ty, TypeFoldable};
@@ -105,12 +106,12 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> {
 
     /// Points where the current variable is "use live" -- meaning
     /// that there is a future "full use" that may use its value.
-    use_live_at: HybridBitSet<PointIndex>,
+    use_live_at: IntervalSet<PointIndex>,
 
     /// Points where the current variable is "drop live" -- meaning
     /// that there is no future "full use" that may use its value, but
     /// there is a future drop.
-    drop_live_at: HybridBitSet<PointIndex>,
+    drop_live_at: IntervalSet<PointIndex>,
 
     /// Locations where drops may occur.
     drop_locations: Vec<Location>,
@@ -125,8 +126,8 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
         LivenessResults {
             cx,
             defs: HybridBitSet::new_empty(num_points),
-            use_live_at: HybridBitSet::new_empty(num_points),
-            drop_live_at: HybridBitSet::new_empty(num_points),
+            use_live_at: IntervalSet::new(num_points),
+            drop_live_at: IntervalSet::new(num_points),
             drop_locations: vec![],
             stack: vec![],
         }
@@ -165,7 +166,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
         drop_used: Vec<(Local, Location)>,
         live_locals: FxHashSet<Local>,
     ) {
-        let locations = HybridBitSet::new_empty(self.cx.elements.num_points());
+        let locations = IntervalSet::new(self.cx.elements.num_points());
 
         for (local, location) in drop_used {
             if !live_locals.contains(&local) {
@@ -456,7 +457,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
     fn add_use_live_facts_for(
         &mut self,
         value: impl TypeFoldable<'tcx>,
-        live_at: &HybridBitSet<PointIndex>,
+        live_at: &IntervalSet<PointIndex>,
     ) {
         debug!("add_use_live_facts_for(value={:?})", value);
 
@@ -473,7 +474,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         dropped_local: Local,
         dropped_ty: Ty<'tcx>,
         drop_locations: &[Location],
-        live_at: &HybridBitSet<PointIndex>,
+        live_at: &IntervalSet<PointIndex>,
     ) {
         debug!(
             "add_drop_live_constraint(\
@@ -521,7 +522,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         elements: &RegionValueElements,
         typeck: &mut TypeChecker<'_, 'tcx>,
         value: impl TypeFoldable<'tcx>,
-        live_at: &HybridBitSet<PointIndex>,
+        live_at: &IntervalSet<PointIndex>,
     ) {
         debug!("make_all_regions_live(value={:?})", value);
         debug!(
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 872a4321447..1f745f977d4 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1916,7 +1916,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let tcx = self.tcx();
 
         match *ak {
-            AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => {
+            AggregateKind::Adt(adt_did, variant_index, substs, _, active_field_index) => {
+                let def = tcx.adt_def(adt_did);
                 let variant = &def.variants[variant_index];
                 let adj_field_index = active_field_index.unwrap_or(field_index);
                 if let Some(field) = variant.fields.get(adj_field_index) {
@@ -2621,8 +2622,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
 
         let (def_id, instantiated_predicates) = match aggregate_kind {
-            AggregateKind::Adt(def, _, substs, _, _) => {
-                (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs))
+            AggregateKind::Adt(adt_did, _, substs, _, _) => {
+                (*adt_did, tcx.predicates_of(*adt_did).instantiate(tcx, substs))
             }
 
             // For closures, we have some **extra requirements** we
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 41856761916..1a93b9be99e 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -809,7 +809,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
     })
 }
 
-pub fn expand_asm<'cx>(
+pub(super) fn expand_asm<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
@@ -836,7 +836,7 @@ pub fn expand_asm<'cx>(
     }
 }
 
-pub fn expand_global_asm<'cx>(
+pub(super) fn expand_global_asm<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index a107f5993b5..eb08170959b 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -72,6 +72,52 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne
     }
 }
 
+fn handle_array_element(
+    cx: &mut base::ExtCtxt<'_>,
+    has_errors: &mut bool,
+    missing_literals: &mut Vec<rustc_span::Span>,
+    expr: &P<rustc_ast::Expr>,
+) -> Option<u8> {
+    match expr.kind {
+        ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
+            if !*has_errors {
+                cx.span_err(expr.span, "cannot concatenate doubly nested array");
+            }
+            *has_errors = true;
+            None
+        }
+        ast::ExprKind::Lit(ref lit) => match lit.kind {
+            ast::LitKind::Int(
+                val,
+                ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
+            ) if val <= u8::MAX.into() => Some(val as u8),
+
+            ast::LitKind::Byte(val) => Some(val),
+            ast::LitKind::ByteStr(_) => {
+                if !*has_errors {
+                    cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
+                        .note("byte strings are treated as arrays of bytes")
+                        .help("try flattening the array")
+                        .emit();
+                }
+                *has_errors = true;
+                None
+            }
+            _ => {
+                if !*has_errors {
+                    invalid_type_err(cx, expr, true);
+                }
+                *has_errors = true;
+                None
+            }
+        },
+        _ => {
+            missing_literals.push(expr.span);
+            None
+        }
+    }
+}
+
 pub fn expand_concat_bytes(
     cx: &mut base::ExtCtxt<'_>,
     sp: rustc_span::Span,
@@ -88,48 +134,27 @@ pub fn expand_concat_bytes(
         match e.kind {
             ast::ExprKind::Array(ref exprs) => {
                 for expr in exprs {
-                    match expr.kind {
-                        ast::ExprKind::Array(_) => {
-                            if !has_errors {
-                                cx.span_err(expr.span, "cannot concatenate doubly nested array");
-                            }
-                            has_errors = true;
-                        }
-                        ast::ExprKind::Lit(ref lit) => match lit.kind {
-                            ast::LitKind::Int(
-                                val,
-                                ast::LitIntType::Unsuffixed
-                                | ast::LitIntType::Unsigned(ast::UintTy::U8),
-                            ) if val <= u8::MAX.into() => {
-                                accumulator.push(val as u8);
-                            }
-
-                            ast::LitKind::Byte(val) => {
-                                accumulator.push(val);
-                            }
-                            ast::LitKind::ByteStr(_) => {
-                                if !has_errors {
-                                    cx.struct_span_err(
-                                        expr.span,
-                                        "cannot concatenate doubly nested array",
-                                    )
-                                    .note("byte strings are treated as arrays of bytes")
-                                    .help("try flattening the array")
-                                    .emit();
-                                }
-                                has_errors = true;
-                            }
-                            _ => {
-                                if !has_errors {
-                                    invalid_type_err(cx, expr, true);
-                                }
-                                has_errors = true;
-                            }
-                        },
-                        _ => {
-                            missing_literals.push(expr.span);
+                    if let Some(elem) =
+                        handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
+                    {
+                        accumulator.push(elem);
+                    }
+                }
+            }
+            ast::ExprKind::Repeat(ref expr, ref count) => {
+                if let ast::ExprKind::Lit(ast::Lit {
+                    kind: ast::LitKind::Int(count_val, _), ..
+                }) = count.value.kind
+                {
+                    if let Some(elem) =
+                        handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
+                    {
+                        for _ in 0..count_val {
+                            accumulator.push(elem);
                         }
                     }
+                } else {
+                    cx.span_err(count.value.span, "repeat count is not a positive number");
                 }
             }
             ast::ExprKind::Lit(ref lit) => match lit.kind {
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index bfddd7073ff..ecd16736e7c 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -7,28 +7,29 @@ pub(crate) mod printf {
     pub enum Substitution<'a> {
         /// A formatted output substitution with its internal byte offset.
         Format(Format<'a>),
-        /// A literal `%%` escape.
-        Escape,
+        /// A literal `%%` escape, with its start and end indices.
+        Escape((usize, usize)),
     }
 
     impl<'a> Substitution<'a> {
         pub fn as_str(&self) -> &str {
             match *self {
                 Substitution::Format(ref fmt) => fmt.span,
-                Substitution::Escape => "%%",
+                Substitution::Escape(_) => "%%",
             }
         }
 
         pub fn position(&self) -> Option<InnerSpan> {
             match *self {
                 Substitution::Format(ref fmt) => Some(fmt.position),
-                _ => None,
+                Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)),
             }
         }
 
         pub fn set_position(&mut self, start: usize, end: usize) {
-            if let Substitution::Format(ref mut fmt) = self {
-                fmt.position = InnerSpan::new(start, end);
+            match self {
+                Substitution::Format(ref mut fmt) => fmt.position = InnerSpan::new(start, end),
+                Substitution::Escape(ref mut pos) => *pos = (start, end),
             }
         }
 
@@ -39,7 +40,7 @@ pub(crate) mod printf {
         pub fn translate(&self) -> Result<String, Option<String>> {
             match *self {
                 Substitution::Format(ref fmt) => fmt.translate(),
-                Substitution::Escape => Err(None),
+                Substitution::Escape(_) => Err(None),
             }
         }
     }
@@ -304,14 +305,9 @@ pub(crate) mod printf {
         fn next(&mut self) -> Option<Self::Item> {
             let (mut sub, tail) = parse_next_substitution(self.s)?;
             self.s = tail;
-            match sub {
-                Substitution::Format(_) => {
-                    if let Some(inner_span) = sub.position() {
-                        sub.set_position(inner_span.start + self.pos, inner_span.end + self.pos);
-                        self.pos += inner_span.end;
-                    }
-                }
-                Substitution::Escape => self.pos += 2,
+            if let Some(InnerSpan { start, end }) = sub.position() {
+                sub.set_position(start + self.pos, end + self.pos);
+                self.pos += end;
             }
             Some(sub)
         }
@@ -340,7 +336,7 @@ pub(crate) mod printf {
         let at = {
             let start = s.find('%')?;
             if let '%' = s[start + 1..].chars().next()? {
-                return Some((Substitution::Escape, &s[start + 2..]));
+                return Some((Substitution::Escape((start, start + 2)), &s[start + 2..]));
             }
 
             Cur::new_at(s, start)
diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
index 1336aab7316..fc7442470ac 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
@@ -13,9 +13,9 @@ macro_rules! assert_eq_pnsat {
 fn test_escape() {
     assert_eq!(pns("has no escapes"), None);
     assert_eq!(pns("has no escapes, either %"), None);
-    assert_eq!(pns("*so* has a %% escape"), Some((S::Escape, " escape")));
-    assert_eq!(pns("%% leading escape"), Some((S::Escape, " leading escape")));
-    assert_eq!(pns("trailing escape %%"), Some((S::Escape, "")));
+    assert_eq!(pns("*so* has a %% escape"), Some((S::Escape((11, 13)), " escape")));
+    assert_eq!(pns("%% leading escape"), Some((S::Escape((0, 2)), " leading escape")));
+    assert_eq!(pns("trailing escape %%"), Some((S::Escape((16, 18)), "")));
 }
 
 #[test]
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 3e8b43fea8a..8c3ef2864f4 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -19,7 +19,6 @@ use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
 use rustc_span::symbol::sym;
 
-mod asm;
 mod assert;
 mod cfg;
 mod cfg_accessible;
@@ -42,6 +41,7 @@ mod test;
 mod trace_macros;
 mod util;
 
+pub mod asm;
 pub mod cmdline_attrs;
 pub mod proc_macro_harness;
 pub mod standard_library_imports;
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 7b73d3c00e6..3aba528abfd 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -5,6 +5,21 @@ on:
   - pull_request
 
 jobs:
+  rustfmt:
+    runs-on: ubuntu-latest
+    timeout-minutes: 10
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Install rustfmt
+      run: |
+        rustup component add rustfmt
+
+    - name: Rustfmt
+      run: |
+        cargo fmt --check
+
   build:
     runs-on: ${{ matrix.os }}
     timeout-minutes: 60
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
index c5b96a47828..a019793edd8 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
@@ -3,7 +3,7 @@ name: Test nightly Cranelift
 on:
   push:
   schedule:
-    - cron: '1 17 * * *' # At 01:17 UTC every day.
+    - cron: '17 1 * * *' # At 01:17 UTC every day.
 
 jobs:
   build:
diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore
index b6567aca786..5aeaf3a1788 100644
--- a/compiler/rustc_codegen_cranelift/.gitignore
+++ b/compiler/rustc_codegen_cranelift/.gitignore
@@ -7,6 +7,7 @@ perf.data.old
 *.events
 *.string*
 /y.bin
+/y.bin.dSYM
 /build
 /build_sysroot/sysroot_src
 /build_sysroot/compiler-builtins
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 900411286b5..3be4250296e 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -40,31 +40,12 @@ unstable-features = ["jit", "inline_asm"]
 jit = ["cranelift-jit", "libloading"]
 inline_asm = []
 
-[profile.dev]
-# By compiling dependencies with optimizations, performing tests gets much faster.
-opt-level = 3
-
-[profile.dev.package.rustc_codegen_cranelift]
-# Disabling optimizations for cg_clif itself makes compilation after a change faster.
-opt-level = 0
-
-[profile.release.package.rustc_codegen_cranelift]
-incremental = true
-
 # Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the
 # execution time of build scripts is so fast that optimizing them slows down the total build time.
-[profile.dev.build-override]
-opt-level = 0
-debug = false
-
 [profile.release.build-override]
 opt-level = 0
 debug = false
 
-[profile.dev.package.cranelift-codegen-meta]
-opt-level = 0
-debug = false
-
 [profile.release.package.cranelift-codegen-meta]
 opt-level = 0
 debug = false
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index dad8ed90b53..8a2db5a43ec 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -37,7 +37,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo
 In the directory with your project (where you can do the usual `cargo build`), run:
 
 ```bash
-$ $cg_clif_dir/build/cargo build
+$ $cg_clif_dir/build/cargo-clif build
 ```
 
 This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
index ccc50ee4a59..1382c7e5379 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
@@ -10,6 +10,18 @@ pub(crate) fn build_backend(
     let mut cmd = Command::new("cargo");
     cmd.arg("build").arg("--target").arg(host_triple);
 
+    cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
+
+    let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default();
+
+    if env::var("CI").as_ref().map(|val| &**val) == Ok("true") {
+        // Deny warnings on CI
+        rustflags += " -Dwarnings";
+
+        // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
+        cmd.env("CARGO_BUILD_INCREMENTAL", "false");
+    }
+
     if use_unstable_features {
         cmd.arg("--features").arg("unstable-features");
     }
@@ -22,25 +34,20 @@ pub(crate) fn build_backend(
         _ => unreachable!(),
     }
 
+    // Set the rpath to make the cg_clif executable find librustc_codegen_cranelift without changing
+    // LD_LIBRARY_PATH
     if cfg!(unix) {
         if cfg!(target_os = "macos") {
-            cmd.env(
-                "RUSTFLAGS",
-                "-Csplit-debuginfo=unpacked \
+            rustflags += " -Csplit-debuginfo=unpacked \
                 -Clink-arg=-Wl,-rpath,@loader_path/../lib \
-                -Zosx-rpath-install-name"
-                    .to_string()
-                    + env::var("RUSTFLAGS").as_deref().unwrap_or(""),
-            );
+                -Zosx-rpath-install-name";
         } else {
-            cmd.env(
-                "RUSTFLAGS",
-                "-Clink-arg=-Wl,-rpath=$ORIGIN/../lib ".to_string()
-                    + env::var("RUSTFLAGS").as_deref().unwrap_or(""),
-            );
+            rustflags += " -Clink-arg=-Wl,-rpath=$ORIGIN/../lib ";
         }
     }
 
+    cmd.env("RUSTFLAGS", rustflags);
+
     eprintln!("[BUILD] rustc_codegen_cranelift");
     crate::utils::spawn_and_wait(cmd);
 
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index 1c78e7b5171..2956fb698e1 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -46,9 +46,9 @@ pub(crate) fn build_sysroot(
     // Build and copy cargo wrapper
     let mut build_cargo_wrapper_cmd = Command::new("rustc");
     build_cargo_wrapper_cmd
-        .arg("scripts/cargo.rs")
+        .arg("scripts/cargo-clif.rs")
         .arg("-o")
-        .arg(target_dir.join("cargo"))
+        .arg(target_dir.join("cargo-clif"))
         .arg("-g");
     spawn_and_wait(build_cargo_wrapper_cmd);
 
diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md
index bcc5745d9d1..785c7383783 100644
--- a/compiler/rustc_codegen_cranelift/docs/usage.md
+++ b/compiler/rustc_codegen_cranelift/docs/usage.md
@@ -9,7 +9,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo
 In the directory with your project (where you can do the usual `cargo build`), run:
 
 ```bash
-$ $cg_clif_dir/build/cargo build
+$ $cg_clif_dir/build/cargo-clif build
 ```
 
 This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
@@ -32,7 +32,7 @@ In jit mode cg_clif will immediately execute your code without creating an execu
 > The jit mode will probably need cargo integration to make this possible.
 
 ```bash
-$ $cg_clif_dir/build/cargo jit
+$ $cg_clif_dir/build/cargo-clif jit
 ```
 
 or
@@ -45,7 +45,7 @@ There is also an experimental lazy jit mode. In this mode functions are only com
 first called.
 
 ```bash
-$ $cg_clif_dir/build/cargo lazy-jit
+$ $cg_clif_dir/build/cargo-clif lazy-jit
 ```
 
 ## Shell
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index cbfdb3c44f3..ef3b575d393 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -129,6 +129,7 @@ fn call_return_u128_pair() {
     return_u128_pair();
 }
 
+#[allow(unreachable_code)] // FIXME false positive
 fn main() {
     take_unique(Unique {
         pointer: 0 as *const (),
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 7b5db307a2d..cab94c0b8cf 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-12-20"
+channel = "nightly-2021-12-30"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
index 41d82b581cd..41d82b581cd 100644
--- a/compiler/rustc_codegen_cranelift/scripts/cargo.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index 46c3b5b7f11..73600faa1e9 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 set -e
 
-./y.rs build
+./y.rs build --no-unstable-features
 source scripts/config.sh
 
 echo "[SETUP] Rust fork"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 99fddf5361e..6bcc3049ecc 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -47,6 +47,8 @@ rm src/test/ui/codegen/init-large-type.rs # same
 rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected
 rm src/test/ui/issues/issue-33992.rs # unsupported linkages
 rm src/test/ui/issues/issue-51947.rs # same
+rm src/test/incremental/hashes/function_interfaces.rs # same
+rm src/test/incremental/hashes/statics.rs # same
 rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result
 rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
 rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
@@ -60,18 +62,14 @@ rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and n
 
 rm src/test/incremental/hashes/inline_asm.rs # inline asm
 rm src/test/incremental/issue-72386.rs # same
-rm src/test/incremental/issue-49482.rs # same
-rm src/test/incremental/issue-54059.rs # same
 rm src/test/incremental/lto.rs # requires lto
+rm src/test/incremental/dirty_clean.rs # TODO
 
 rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
 rm -r src/test/run-make/unstable-flag-required # same
 rm -r src/test/run-make/rustdoc-* # same
 rm -r src/test/run-make/emit-named-files # requires full --emit support
 
-rm src/test/pretty/asm.rs # inline asm
-rm src/test/pretty/raw-str-nonexpr.rs # same
-
 rm -r src/test/run-pass-valgrind/unsized-locals
 
 rm src/test/ui/json-bom-plus-crlf-multifile.rs # differing warning
@@ -97,6 +95,12 @@ rm src/test/ui/command/command-current-dir.rs # can't find libstd.so
 
 rm src/test/ui/abi/stack-protector.rs # requires stack protector support
 
+rm src/test/incremental/issue-80691-bad-eval-cache.rs # wrong exit code
+rm src/test/incremental/spike-neg1.rs # errors out for some reason
+rm src/test/incremental/spike-neg2.rs # same
+
+rm src/test/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM
+
 echo "[TEST] rustc test suite"
-RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui}
+RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
 popd
diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh
index fd2b3761ff0..bdb3de0936d 100755
--- a/compiler/rustc_codegen_cranelift/scripts/tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh
@@ -80,73 +80,73 @@ function base_sysroot_tests() {
 
 function extended_sysroot_tests() {
     pushd rand
-    ../build/cargo clean
+    ../build/cargo-clif clean
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
         echo "[TEST] rust-random/rand"
-        ../build/cargo test --workspace
+        ../build/cargo-clif test --workspace
     else
         echo "[AOT] rust-random/rand"
-        ../build/cargo build --workspace --target $TARGET_TRIPLE --tests
+        ../build/cargo-clif build --workspace --target $TARGET_TRIPLE --tests
     fi
     popd
 
     pushd simple-raytracer
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
         echo "[BENCH COMPILE] ebobby/simple-raytracer"
-        hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo clean" \
+        hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \
         "RUSTC=rustc RUSTFLAGS='' cargo build" \
-        "../build/cargo build"
+        "../build/cargo-clif build"
 
         echo "[BENCH RUN] ebobby/simple-raytracer"
         cp ./target/debug/main ./raytracer_cg_clif
         hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_clif
     else
-        ../build/cargo clean
+        ../build/cargo-clif clean
         echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
         echo "[COMPILE] ebobby/simple-raytracer"
-        ../build/cargo build --target $TARGET_TRIPLE
+        ../build/cargo-clif build --target $TARGET_TRIPLE
         echo "[BENCH RUN] ebobby/simple-raytracer (skipped)"
     fi
     popd
 
     pushd build_sysroot/sysroot_src/library/core/tests
     echo "[TEST] libcore"
-    ../../../../../build/cargo clean
+    ../../../../../build/cargo-clif clean
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
-        ../../../../../build/cargo test
+        ../../../../../build/cargo-clif test
     else
-        ../../../../../build/cargo build --target $TARGET_TRIPLE --tests
+        ../../../../../build/cargo-clif build --target $TARGET_TRIPLE --tests
     fi
     popd
 
     pushd regex
     echo "[TEST] rust-lang/regex example shootout-regex-dna"
-    ../build/cargo clean
+    ../build/cargo-clif clean
     export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning
     # Make sure `[codegen mono items] start` doesn't poison the diff
-    ../build/cargo build --example shootout-regex-dna --target $TARGET_TRIPLE
+    ../build/cargo-clif build --example shootout-regex-dna --target $TARGET_TRIPLE
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
         cat examples/regexdna-input.txt \
-            | ../build/cargo run --example shootout-regex-dna --target $TARGET_TRIPLE \
+            | ../build/cargo-clif run --example shootout-regex-dna --target $TARGET_TRIPLE \
             | grep -v "Spawned thread" > res.txt
         diff -u res.txt examples/regexdna-output.txt
     fi
 
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
         echo "[TEST] rust-lang/regex tests"
-        ../build/cargo test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
+        ../build/cargo-clif test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
     else
         echo "[AOT] rust-lang/regex tests"
-        ../build/cargo build --tests --target $TARGET_TRIPLE
+        ../build/cargo-clif build --tests --target $TARGET_TRIPLE
     fi
     popd
 
     pushd portable-simd
     echo "[TEST] rust-lang/portable-simd"
-    ../build/cargo clean
-    ../build/cargo build --all-targets --target $TARGET_TRIPLE
+    ../build/cargo-clif clean
+    ../build/cargo-clif build --all-targets --target $TARGET_TRIPLE
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
-        ../build/cargo test -q
+        ../build/cargo-clif test -q
     fi
     popd
 }
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index fc2f04f146e..b16f5af66f2 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -715,30 +715,6 @@ fn codegen_stmt<'tcx>(
                     let operand = operand.load_scalar(fx);
                     lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
                 }
-                Rvalue::NullaryOp(NullOp::Box, content_ty) => {
-                    let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap();
-                    let content_ty = fx.monomorphize(content_ty);
-                    let layout = fx.layout_of(content_ty);
-                    let llsize = fx.bcx.ins().iconst(usize_type, layout.size.bytes() as i64);
-                    let llalign = fx.bcx.ins().iconst(usize_type, layout.align.abi.bytes() as i64);
-                    let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
-
-                    // Allocate space:
-                    let def_id =
-                        match fx.tcx.lang_items().require(rustc_hir::LangItem::ExchangeMalloc) {
-                            Ok(id) => id,
-                            Err(s) => {
-                                fx.tcx
-                                    .sess
-                                    .fatal(&format!("allocation of `{}` {}", box_layout.ty, s));
-                            }
-                        };
-                    let instance = ty::Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
-                    let func_ref = fx.get_function_ref(instance);
-                    let call = fx.bcx.ins().call(func_ref, &[llsize, llalign]);
-                    let ptr = fx.bcx.inst_results(call)[0];
-                    lval.write_cvalue(fx, CValue::by_val(ptr, box_layout));
-                }
                 Rvalue::NullaryOp(null_op, ty) => {
                     assert!(
                         lval.layout()
@@ -749,7 +725,6 @@ fn codegen_stmt<'tcx>(
                     let val = match null_op {
                         NullOp::SizeOf => layout.size.bytes(),
                         NullOp::AlignOf => layout.align.abi.bytes(),
-                        NullOp::Box => unreachable!(),
                     };
                     let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into());
                     lval.write_cvalue(fx, val);
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 644204d10b8..3b6025c73d1 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -237,7 +237,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
     pub(crate) module: &'m mut dyn Module,
     pub(crate) tcx: TyCtxt<'tcx>,
     pub(crate) target_config: TargetFrontendConfig, // Cached from module
-    pub(crate) pointer_type: Type, // Cached from module
+    pub(crate) pointer_type: Type,                  // Cached from module
     pub(crate) constants_cx: ConstantCx,
 
     pub(crate) instance: Instance<'tcx>,
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
index 4120ba6e533..589910ede96 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
@@ -67,7 +67,7 @@ impl WriterRelocate {
     }
 
     /// Perform the collected relocations to be usable for JIT usage.
-    #[cfg(feature = "jit")]
+    #[cfg(all(feature = "jit", not(windows)))]
     pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> {
         for reloc in self.relocs.drain(..) {
             match reloc.name {
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index dd19dd5d2b9..638b025be22 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -10,7 +10,7 @@ use crate::prelude::*;
 use rustc_index::vec::IndexVec;
 
 use cranelift_codegen::entity::EntityRef;
-use cranelift_codegen::ir::{LabelValueLoc, ValueLabel};
+use cranelift_codegen::ir::{Endianness, LabelValueLoc, ValueLabel};
 use cranelift_codegen::isa::TargetIsa;
 use cranelift_codegen::ValueLocRange;
 
@@ -23,15 +23,6 @@ use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64};
 pub(crate) use emit::{DebugReloc, DebugRelocName};
 pub(crate) use unwind::UnwindContext;
 
-fn target_endian(tcx: TyCtxt<'_>) -> RunTimeEndian {
-    use rustc_target::abi::Endian;
-
-    match tcx.data_layout.endian {
-        Endian::Big => RunTimeEndian::Big,
-        Endian::Little => RunTimeEndian::Little,
-    }
-}
-
 pub(crate) struct DebugContext<'tcx> {
     tcx: TyCtxt<'tcx>,
 
@@ -60,6 +51,11 @@ impl<'tcx> DebugContext<'tcx> {
             address_size: isa.frontend_config().pointer_bytes(),
         };
 
+        let endian = match isa.endianness() {
+            Endianness::Little => RunTimeEndian::Little,
+            Endianness::Big => RunTimeEndian::Big,
+        };
+
         let mut dwarf = DwarfUnit::new(encoding);
 
         let producer = format!(
@@ -108,7 +104,7 @@ impl<'tcx> DebugContext<'tcx> {
         DebugContext {
             tcx,
 
-            endian: target_endian(tcx),
+            endian,
 
             dwarf,
             unit_range_list: RangeList(Vec::new()),
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
index f0896ea0e16..e4f28338096 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
@@ -2,6 +2,7 @@
 
 use crate::prelude::*;
 
+use cranelift_codegen::ir::Endianness;
 use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
 
 use cranelift_object::ObjectProduct;
@@ -17,8 +18,11 @@ pub(crate) struct UnwindContext {
 }
 
 impl UnwindContext {
-    pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
-        let endian = super::target_endian(tcx);
+    pub(crate) fn new(isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
+        let endian = match isa.endianness() {
+            Endianness::Little => RunTimeEndian::Little,
+            Endianness::Big => RunTimeEndian::Big,
+        };
         let mut frame_table = FrameTable::default();
 
         let cie_id = if let Some(mut cie) = isa.create_systemv_cie() {
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 7f888c80464..046e4393a68 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -243,7 +243,7 @@ pub(crate) fn run_aot(
     let isa = crate::build_isa(tcx.sess, &backend_config);
     let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string());
     assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
-    let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
+    let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true);
     let created_alloc_shim =
         crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
 
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 3f288474827..cb18f42f741 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -141,7 +141,7 @@ impl<'tcx> CodegenCx<'tcx> {
         assert_eq!(pointer_ty(tcx), isa.pointer_type());
 
         let unwind_context =
-            UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
+            UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
         let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
         CodegenCx {
             tcx,
diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock
index 60a2101c689..47925f72c2c 100644
--- a/compiler/rustc_codegen_gcc/Cargo.lock
+++ b/compiler/rustc_codegen_gcc/Cargo.lock
@@ -18,12 +18,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1"
 
 [[package]]
-name = "autocfg"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
-
-[[package]]
 name = "bitflags"
 version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -36,15 +30,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
-name = "crc32fast"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
 name = "fm"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -56,7 +41,7 @@ dependencies = [
 [[package]]
 name = "gccjit"
 version = "1.0.0"
-source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+source = "git+https://github.com/antoyo/gccjit.rs#0672b78d162d65b6f36ea4062947253affe9fdef"
 dependencies = [
  "gccjit_sys",
 ]
@@ -64,7 +49,7 @@ dependencies = [
 [[package]]
 name = "gccjit_sys"
 version = "0.0.1"
-source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+source = "git+https://github.com/antoyo/gccjit.rs#0672b78d162d65b6f36ea4062947253affe9fdef"
 dependencies = [
  "libc 0.1.12",
 ]
@@ -85,33 +70,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
 dependencies = [
  "cfg-if",
- "libc 0.2.102",
+ "libc 0.2.112",
  "wasi",
 ]
 
 [[package]]
-name = "hashbrown"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
-
-[[package]]
 name = "hermit-abi"
 version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 dependencies = [
- "libc 0.2.102",
-]
-
-[[package]]
-name = "indexmap"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
-dependencies = [
- "autocfg",
- "hashbrown",
+ "libc 0.2.112",
 ]
 
 [[package]]
@@ -122,7 +91,7 @@ checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090"
 dependencies = [
  "fm",
  "getopts",
- "libc 0.2.102",
+ "libc 0.2.112",
  "num_cpus",
  "termcolor",
  "threadpool",
@@ -138,9 +107,9 @@ checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122"
 
 [[package]]
 name = "libc"
-version = "0.2.102"
+version = "0.2.112"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
+checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
 
 [[package]]
 name = "memchr"
@@ -155,25 +124,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
 dependencies = [
  "hermit-abi",
- "libc 0.2.102",
-]
-
-[[package]]
-name = "object"
-version = "0.25.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7"
-dependencies = [
- "crc32fast",
- "indexmap",
- "memchr",
+ "libc 0.2.112",
 ]
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.10"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
 
 [[package]]
 name = "rand"
@@ -181,7 +139,7 @@ version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
 dependencies = [
- "libc 0.2.102",
+ "libc 0.2.112",
  "rand_chacha",
  "rand_core",
  "rand_hc",
@@ -257,7 +215,6 @@ dependencies = [
  "ar",
  "gccjit",
  "lang_tester",
- "object",
  "target-lexicon",
  "tempfile",
 ]
@@ -284,7 +241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
 dependencies = [
  "cfg-if",
- "libc 0.2.102",
+ "libc 0.2.112",
  "rand",
  "redox_syscall",
  "remove_dir_all",
@@ -321,7 +278,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
 dependencies = [
- "libc 0.2.102",
+ "libc 0.2.112",
 ]
 
 [[package]]
diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml
index 9e8c195c15f..21f0bfbf69d 100644
--- a/compiler/rustc_codegen_gcc/Cargo.toml
+++ b/compiler/rustc_codegen_gcc/Cargo.toml
@@ -23,11 +23,6 @@ target-lexicon = "0.10.0"
 
 ar = "0.8.0"
 
-[dependencies.object]
-version = "0.25.0"
-default-features = false
-features = ["read", "std", "write"] # We don't need WASM support.
-
 [dev-dependencies]
 lang_tester = "0.3.9"
 tempfile = "3.1.0"
diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md
index 709d93c6edb..1fcfb5f6e20 100644
--- a/compiler/rustc_codegen_gcc/Readme.md
+++ b/compiler/rustc_codegen_gcc/Readme.md
@@ -111,6 +111,8 @@ Or add a breakpoint to `add_error` in gdb and print the line number using:
 p loc->m_line
 ```
 
+To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo build`.
+
 ### How to use a custom-build rustc
 
  * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`).
diff --git a/compiler/rustc_codegen_gcc/config.sh b/compiler/rustc_codegen_gcc/config.sh
index 87df2f2102b..a932c1c8372 100644
--- a/compiler/rustc_codegen_gcc/config.sh
+++ b/compiler/rustc_codegen_gcc/config.sh
@@ -38,7 +38,7 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
    fi
 fi
 
-export RUSTFLAGS="$linker -Cpanic=abort -Zsymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"
+export RUSTFLAGS="$linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"
 
 # FIXME(antoyo): remove once the atomic shim is gone
 if [[ `uname` == 'Darwin' ]]; then
diff --git a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch
index ee5ba449fb8..73e9c858caf 100644
--- a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch
+++ b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch
@@ -46,4 +46,24 @@ index 4bc44e9..8e3c7a4 100644
  
  #[test]
  fn cell_allows_array_cycle() {
+diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
+index 3e00e0a..8e5663b 100644
+--- a/library/core/tests/slice.rs
++++ b/library/core/tests/slice.rs
+@@ -2108,6 +2108,7 @@ fn test_copy_within_panics_src_out_of_bounds() {
+     bytes.copy_within(usize::MAX..=usize::MAX, 0);
+ }
+ 
++/*
+ #[test]
+ fn test_is_sorted() {
+     let empty: [i32; 0] = [];
+@@ -2122,6 +2123,7 @@ fn test_is_sorted() {
+     assert!(!["c", "bb", "aaa"].is_sorted());
+     assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
+ }
++*/
+ 
+ #[test]
+ fn test_slice_run_destructors() {
 -- 2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch
new file mode 100644
index 00000000000..8954f91021f
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch
@@ -0,0 +1,24 @@
+From b1ae000f6da1abd3b8e9b80c40bc11c89b8ae93c Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Thu, 30 Dec 2021 16:54:40 +0100
+Subject: [PATCH] [core] Disable portable-simd test
+
+---
+ library/core/tests/lib.rs | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
+index ec70034..7cd9e21 100644
+--- a/library/core/tests/lib.rs
++++ b/library/core/tests/lib.rs
+@@ -121,7 +121,6 @@ mod pattern;
+ mod pin;
+ mod ptr;
+ mod result;
+-mod simd;
+ mod slice;
+ mod str;
+ mod str_lossy;
+-- 
+2.26.2.7.g19db9cfb68
+
diff --git a/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch
new file mode 100644
index 00000000000..bf74a74c7c4
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch
@@ -0,0 +1,30 @@
+From 0ffdd8eda8df364391c8ac6e1ce92c73ba9254d4 Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Fri, 3 Dec 2021 12:16:30 +0100
+Subject: [PATCH] Disable long running tests
+
+---
+ library/core/tests/slice.rs | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
+index 2c8f00a..44847ee 100644
+--- a/library/core/tests/slice.rs
++++ b/library/core/tests/slice.rs
+@@ -2332,7 +2332,8 @@ macro_rules! empty_max_mut {
+     };
+ }
+ 
++/*
+ #[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
+ take_tests! {
+     slice: &[(); usize::MAX], method: take,
+     (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]),
+@@ -2345,3 +2347,4 @@ take_tests! {
+     (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
+     (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
+ }
++*/
+-- 
+2.26.2.7.g19db9cfb68
+
diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain
index d311a33f807..ee0822f6c31 100644
--- a/compiler/rustc_codegen_gcc/rust-toolchain
+++ b/compiler/rustc_codegen_gcc/rust-toolchain
@@ -1 +1 @@
-nightly-2021-09-28
+nightly-2021-12-30
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 10edcf36955..453bcd601d3 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -18,30 +18,30 @@ use crate::type_of::LayoutGccExt;
 
 // Rust asm! and GCC Extended Asm semantics differ substantially.
 //
-// 1. Rust asm operands go along as one list of operands. Operands themselves indicate 
-//    if they're "in" or "out". "In" and "out" operands can interleave. One operand can be 
+// 1. Rust asm operands go along as one list of operands. Operands themselves indicate
+//    if they're "in" or "out". "In" and "out" operands can interleave. One operand can be
 //    both "in" and "out" (`inout(reg)`).
 //
-//    GCC asm has two different lists for "in" and "out" operands. In terms of gccjit, 
-//    this means that all "out" operands must go before "in" operands. "In" and "out" operands 
+//    GCC asm has two different lists for "in" and "out" operands. In terms of gccjit,
+//    this means that all "out" operands must go before "in" operands. "In" and "out" operands
 //    cannot interleave.
 //
-// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important 
+// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important
 //    because the asm template refers to operands by index.
 //
 //    Mapping from Rust to GCC index would be 1-1 if it wasn't for...
 //
-// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. 
-//    Contrary, Rust expresses clobbers through "out" operands that aren't tied to 
+// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes.
+//    Contrary, Rust expresses clobbers through "out" operands that aren't tied to
 //    a variable (`_`),  and such "clobbers" do have index.
 //
-// 4. Furthermore, GCC Extended Asm does not support explicit register constraints 
-//    (like `out("eax")`) directly, offering so-called "local register variables" 
-//    as a workaround. These variables need to be declared and initialized *before* 
-//    the Extended Asm block but *after* normal local variables 
+// 4. Furthermore, GCC Extended Asm does not support explicit register constraints
+//    (like `out("eax")`) directly, offering so-called "local register variables"
+//    as a workaround. These variables need to be declared and initialized *before*
+//    the Extended Asm block but *after* normal local variables
 //    (see comment in `codegen_inline_asm` for explanation).
 //
-// With that in mind, let's see how we translate Rust syntax to GCC 
+// With that in mind, let's see how we translate Rust syntax to GCC
 // (from now on, `CC` stands for "constraint code"):
 //
 // * `out(reg_class) var`   -> translated to output operand: `"=CC"(var)`
@@ -52,18 +52,17 @@ use crate::type_of::LayoutGccExt;
 //
 // * `out("explicit register") _` -> not translated to any operands, register is simply added to clobbers list
 //
-// * `inout(reg_class) in_var => out_var` -> translated to two operands: 
+// * `inout(reg_class) in_var => out_var` -> translated to two operands:
 //                              output: `"=CC"(in_var)`
-//                              input:  `"num"(out_var)` where num is the GCC index 
+//                              input:  `"num"(out_var)` where num is the GCC index
 //                                       of the corresponding output operand
 //
-// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`, 
+// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`,
 //                                      where "tmp" is a temporary unused variable
 //
-// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above 
-//                                              with `"r"(var)` constraint, 
+// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above
+//                                              with `"r"(var)` constraint,
 //                                              and one register variable assigned to the desired register.
-// 
 
 const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t";
 const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix";
@@ -131,7 +130,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
         let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX);
 
-        // GCC index of an output operand equals its position in the array 
+        // GCC index of an output operand equals its position in the array
         let mut outputs = vec![];
 
         // GCC index of an input operand equals its position in the array
@@ -145,9 +144,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         let mut constants_len = 0;
 
         // There are rules we must adhere to if we want GCC to do the right thing:
-        // 
+        //
         // * Every local variable that the asm block uses as an output must be declared *before*
-        //   the asm block. 
+        //   the asm block.
         // * There must be no instructions whatsoever between the register variables and the asm.
         //
         // Therefore, the backend must generate the instructions strictly in this order:
@@ -159,7 +158,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         // We also must make sure that no input operands are emitted before output operands.
         //
         // This is why we work in passes, first emitting local vars, then local register vars.
-        // Also, we don't emit any asm operands immediately; we save them to 
+        // Also, we don't emit any asm operands immediately; we save them to
         // the one of the buffers to be emitted later.
 
         // 1. Normal variables (and saving operands to buffers).
@@ -172,7 +171,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                         (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)),
                         // When `reg` is a class and not an explicit register but the out place is not specified,
                         // we need to create an unused output variable to assign the output to. This var
-                        // needs to be of a type that's "compatible" with the register class, but specific type 
+                        // needs to be of a type that's "compatible" with the register class, but specific type
                         // doesn't matter.
                         (Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())),
                         (Register(_), Some(_)) => {
@@ -200,7 +199,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
 
                     let tmp_var = self.current_func().new_local(None, ty, "output_register");
                     outputs.push(AsmOutOperand {
-                        constraint, 
+                        constraint,
                         rust_idx,
                         late,
                         readwrite: false,
@@ -211,12 +210,12 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
 
                 InlineAsmOperandRef::In { reg, value } => {
                     if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
-                        inputs.push(AsmInOperand { 
-                            constraint: Cow::Borrowed(constraint), 
-                            rust_idx, 
+                        inputs.push(AsmInOperand {
+                            constraint: Cow::Borrowed(constraint),
+                            rust_idx,
                             val: value.immediate()
                         });
-                    } 
+                    }
                     else {
                         // left for the next pass
                         continue
@@ -226,7 +225,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                 InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
                     let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
                         constraint
-                    } 
+                    }
                     else {
                         // left for the next pass
                         continue
@@ -235,22 +234,22 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     // Rustc frontend guarantees that input and output types are "compatible",
                     // so we can just use input var's type for the output variable.
                     //
-                    // This decision is also backed by the fact that LLVM needs in and out 
-                    // values to be of *exactly the same type*, not just "compatible". 
+                    // This decision is also backed by the fact that LLVM needs in and out
+                    // values to be of *exactly the same type*, not just "compatible".
                     // I'm not sure if GCC is so picky too, but better safe than sorry.
                     let ty = in_value.layout.gcc_type(self.cx, false);
                     let tmp_var = self.current_func().new_local(None, ty, "output_register");
 
                     // If the out_place is None (i.e `inout(reg) _` syntax was used), we translate
-                    // it to one "readwrite (+) output variable", otherwise we translate it to two 
+                    // it to one "readwrite (+) output variable", otherwise we translate it to two
                     // "out and tied in" vars as described above.
                     let readwrite = out_place.is_none();
                     outputs.push(AsmOutOperand {
-                        constraint, 
+                        constraint,
                         rust_idx,
                         late,
                         readwrite,
-                        tmp_var, 
+                        tmp_var,
                         out_place,
                     });
 
@@ -259,8 +258,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                         let constraint = Cow::Owned(out_gcc_idx.to_string());
 
                         inputs.push(AsmInOperand {
-                            constraint, 
-                            rust_idx, 
+                            constraint,
+                            rust_idx,
                             val: in_value.immediate()
                         });
                     }
@@ -287,7 +286,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
                         let out_place = if let Some(place) = place {
                             place
-                        } 
+                        }
                         else {
                             // processed in the previous pass
                             continue
@@ -298,7 +297,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                         tmp_var.set_register_name(reg_name);
 
                         outputs.push(AsmOutOperand {
-                            constraint: "r".into(), 
+                            constraint: "r".into(),
                             rust_idx,
                             late,
                             readwrite: false,
@@ -318,9 +317,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                         reg_var.set_register_name(reg_name);
                         self.llbb().add_assignment(None, reg_var, value.immediate());
 
-                        inputs.push(AsmInOperand { 
-                            constraint: "r".into(), 
-                            rust_idx, 
+                        inputs.push(AsmInOperand {
+                            constraint: "r".into(),
+                            rust_idx,
                             val: reg_var.to_rvalue()
                         });
                     }
@@ -331,31 +330,23 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                 // `inout("explicit register") in_var => out_var`
                 InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
                     if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
-                        let out_place = if let Some(place) = out_place {
-                            place
-                        } 
-                        else {
-                            // processed in the previous pass
-                            continue
-                        };
-
                         // See explanation in the first pass.
                         let ty = in_value.layout.gcc_type(self.cx, false);
                         let tmp_var = self.current_func().new_local(None, ty, "output_register");
                         tmp_var.set_register_name(reg_name);
 
                         outputs.push(AsmOutOperand {
-                            constraint: "r".into(), 
+                            constraint: "r".into(),
                             rust_idx,
                             late,
                             readwrite: false,
                             tmp_var,
-                            out_place: Some(out_place)
+                            out_place,
                         });
 
                         let constraint = Cow::Owned((outputs.len() - 1).to_string());
-                        inputs.push(AsmInOperand { 
-                            constraint, 
+                        inputs.push(AsmInOperand {
+                            constraint,
                             rust_idx,
                             val: in_value.immediate()
                         });
@@ -364,8 +355,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     // processed in the previous pass
                 }
 
-                InlineAsmOperandRef::Const { .. } 
-                | InlineAsmOperandRef::SymFn { .. } 
+                InlineAsmOperandRef::Const { .. }
+                | InlineAsmOperandRef::SymFn { .. }
                 | InlineAsmOperandRef::SymStatic { .. } => {
                     // processed in the previous pass
                 }
@@ -460,7 +451,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         if !intel_dialect {
             template_str.push_str(INTEL_SYNTAX_INS);
         }
-        
+
         // 4. Generate Extended Asm block
 
         let block = self.llbb();
@@ -479,7 +470,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         }
 
         if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) {
-            // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient 
+            // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient
             // on all architectures. For instance, what about FP stack?
             extended_asm.add_clobber("cc");
         }
@@ -498,10 +489,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
             self.call(self.type_void(), builtin_unreachable, &[], None);
         }
 
-        // Write results to outputs. 
+        // Write results to outputs.
         //
         // We need to do this because:
-        //  1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases 
+        //  1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases
         //     (especially with current `rustc_backend_ssa` API).
         //  2. Not every output operand has an `out_place`, and it's required by `add_output_operand`.
         //
@@ -509,7 +500,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         // generates `out_place = tmp_var;` assignments if out_place exists.
         for op in &outputs {
             if let Some(place) = op.out_place {
-                OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place);                
+                OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place);
             }
         }
 
diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs
index 4962d016152..334ef32f1d1 100644
--- a/compiler/rustc_codegen_gcc/src/back/write.rs
+++ b/compiler/rustc_codegen_gcc/src/back/write.rs
@@ -1,4 +1,4 @@
-use std::fs;
+use std::{env, fs};
 
 use gccjit::OutputKind;
 use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
@@ -42,17 +42,17 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han
                 let _timer = cgcx
                     .prof
                     .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
-                match &*module.name {
-                    "std_example.7rcbfp3g-cgu.15" => {
-                        println!("Dumping reproducer {}", module.name);
-                        let _ = fs::create_dir("/tmp/reproducers");
-                        // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by
-                        // transmuting an rvalue to an lvalue.
-                        // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue
-                        context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name));
-                        println!("Dumped reproducer {}", module.name);
-                    },
-                    _ => (),
+                if env::var("CG_GCCJIT_DUMP_MODULE_NAMES").as_deref() == Ok("1") {
+                    println!("Module {}", module.name);
+                }
+                if env::var("CG_GCCJIT_DUMP_MODULE").as_deref() == Ok(&module.name) {
+                    println!("Dumping reproducer {}", module.name);
+                    let _ = fs::create_dir("/tmp/reproducers");
+                    // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by
+                    // transmuting an rvalue to an lvalue.
+                    // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue
+                    context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name));
+                    println!("Dumped reproducer {}", module.name);
                 }
                 context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str"));
             }
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index dee70bf7536..8b23e96066e 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -81,7 +81,10 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (Modul
         for arg in &tcx.sess.opts.cg.llvm_args {
             context.add_command_line_option(arg);
         }
+        // NOTE: an optimization (https://github.com/rust-lang/rustc_codegen_gcc/issues/53).
         context.add_command_line_option("-fno-semantic-interposition");
+        // NOTE: Rust relies on LLVM not doing TBAA (https://github.com/rust-lang/unsafe-code-guidelines/issues/292).
+        context.add_command_line_option("-fno-strict-aliasing");
         if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") {
             context.set_dump_code_on_compile(true);
         }
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index fff2aa6df7c..379c88bbd40 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -200,7 +200,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
     fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
         let mut all_args_match = true;
         let mut param_types = vec![];
-        let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
+        let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr");
         for (index, arg) in args.iter().enumerate().take(gcc_func.get_param_count()) {
             let param = gcc_func.get_param_type(index);
             if param != arg.get_type() {
@@ -277,7 +277,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
 
         // gccjit requires to use the result of functions, even when it's not used.
         // That's why we assign the result to a local or call add_eval().
-        let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
+        let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr");
         let mut return_type = gcc_func.get_return_type();
         let current_block = self.current_block.borrow().expect("block");
         let void_type = self.context.new_type::<()>();
@@ -605,22 +605,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
-        // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
-        // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
         if a.get_type() != b.get_type() {
             b = self.context.new_cast(None, b, a.get_type());
         }
-        let res = self.current_func().new_local(None, b.get_type(), "andResult");
-        self.llbb().add_assignment(None, res, a & b);
-        res.to_rvalue()
+        a & b
     }
 
-    fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
-        // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
-        // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
-        let res = self.current_func().new_local(None, b.get_type(), "orResult");
-        self.llbb().add_assignment(None, res, a | b);
-        res.to_rvalue()
+    fn or(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+        if a.get_type() != b.get_type() {
+            b = self.context.new_cast(None, b, a.get_type());
+        }
+        a | b
     }
 
     fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@@ -628,8 +623,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
-        // TODO(antoyo): use new_unary_op()?
-        self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a
+        self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a)
     }
 
     fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
@@ -816,7 +810,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes()));
         let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
 
-        let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+        let volatile_const_void_ptr_type = self.context.new_type::<()>()
+            .make_const()
+            .make_volatile()
+            .make_pointer();
         let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
         self.context.new_call(None, atomic_load, &[ptr, ordering])
     }
@@ -941,7 +938,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         // TODO(antoyo): handle alignment.
         let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes()));
         let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
-        let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+        let volatile_const_void_ptr_type = self.context.new_type::<()>()
+            .make_volatile()
+            .make_pointer();
         let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
 
         // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because
@@ -981,12 +980,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         assert_eq!(idx as usize as u64, idx);
         let value = ptr.dereference(None).to_rvalue();
 
-        if value_type.is_array().is_some() {
+        if value_type.dyncast_array().is_some() {
             let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
             let element = self.context.new_array_access(None, value, index);
             element.get_address(None)
         }
-        else if let Some(vector_type) = value_type.is_vector() {
+        else if let Some(vector_type) = value_type.dyncast_vector() {
             let array_type = vector_type.get_element_type().make_pointer();
             let array = self.bitcast(ptr, array_type);
             let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
@@ -1009,7 +1008,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
 
     fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
         // TODO(antoyo): check that it indeed sign extend the value.
-        if dest_ty.is_vector().is_some() {
+        if dest_ty.dyncast_vector().is_some() {
             // TODO(antoyo): nothing to do as it is only for LLVM?
             return value;
         }
@@ -1081,7 +1080,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         let right_type = rhs.get_type();
         if left_type != right_type {
             // NOTE: because libgccjit cannot compare function pointers.
-            if left_type.is_function_ptr_type().is_some() && right_type.is_function_ptr_type().is_some() {
+            if left_type.dyncast_function_ptr_type().is_some() && right_type.dyncast_function_ptr_type().is_some() {
                 lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer());
                 rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer());
             }
@@ -1189,12 +1188,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         assert_eq!(idx as usize as u64, idx);
         let value_type = aggregate_value.get_type();
 
-        if value_type.is_array().is_some() {
+        if value_type.dyncast_array().is_some() {
             let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
             let element = self.context.new_array_access(None, aggregate_value, index);
             element.get_address(None)
         }
-        else if value_type.is_vector().is_some() {
+        else if value_type.dyncast_vector().is_some() {
             panic!();
         }
         else if let Some(pointer_type) = value_type.get_pointee() {
@@ -1221,11 +1220,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         let value_type = aggregate_value.get_type();
 
         let lvalue =
-            if value_type.is_array().is_some() {
+            if value_type.dyncast_array().is_some() {
                 let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
                 self.context.new_array_access(None, aggregate_value, index)
             }
-            else if value_type.is_vector().is_some() {
+            else if value_type.dyncast_vector().is_some() {
                 panic!();
             }
             else if let Some(pointer_type) = value_type.get_pointee() {
@@ -1404,7 +1403,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         self.cx
     }
 
-    fn do_not_inline(&mut self, _llret: RValue<'gcc>) {
+    fn apply_attrs_to_cleanup_callsite(&mut self, _llret: RValue<'gcc>) {
         unimplemented!();
     }
 
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index ec542e55681..5851826147d 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -1,5 +1,4 @@
 use std::convert::TryFrom;
-use std::convert::TryInto;
 
 use gccjit::LValue;
 use gccjit::{Block, CType, RValue, Type, ToRValue};
@@ -44,7 +43,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
         let string = self.context.new_string_literal(&*string);
         let sym = self.generate_local_symbol_name("str");
         let global = self.declare_private_global(&sym, self.val_ty(string));
-        global.global_set_initializer_value(string);
+        global.global_set_initializer_rvalue(string);
         global
         // TODO(antoyo): set linkage.
     }
@@ -79,7 +78,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
         bytes.iter()
         .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
         .collect();
-    context.new_rvalue_from_array(None, typ, &elements)
+    context.new_array_constructor(None, typ, &elements)
 }
 
 pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool {
@@ -120,13 +119,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     }
 
     fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
-        let num64: Result<i64, _> = num.try_into();
-        if let Ok(num) = num64 {
-            // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant.
-            // The operations >> 64 and | low are making the normal case a non-constant.
-            return self.context.new_rvalue_from_long(typ, num as i64);
-        }
-
         if num >> 64 != 0 {
             // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()?
             let low = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
@@ -193,7 +185,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         // TODO(antoyo): cache the type? It's anonymous, so probably not.
         let typ = self.type_struct(&fields, packed);
         let struct_type = typ.is_struct().expect("struct type");
-        self.context.new_rvalue_from_struct(None, struct_type, values)
+        self.context.new_struct_constructor(None, struct_type.as_type(), None, values)
     }
 
     fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index 205498acc31..ba4589bd810 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -20,7 +20,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
     pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> {
         if value.get_type() == self.bool_type.make_pointer() {
             if let Some(pointee) = typ.get_pointee() {
-                if pointee.is_vector().is_some() {
+                if pointee.dyncast_vector().is_some() {
                     panic!()
                 }
             }
@@ -31,9 +31,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
 
 impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
     fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
-        if let Some(global_value) = self.const_globals.borrow().get(&cv) {
-            // TODO(antoyo): upgrade alignment.
-            return *global_value;
+        // TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the
+        // following:
+        for (value, variable) in &*self.const_globals.borrow() {
+            if format!("{:?}", value) == format!("{:?}", cv) {
+                // TODO(antoyo): upgrade alignment.
+                return *variable;
+            }
         }
         let global_value = self.static_addr_of_mut(cv, align, kind);
         // TODO(antoyo): set global constant.
@@ -77,7 +81,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
             else {
                 value
             };
-        global.global_set_initializer_value(value);
+        global.global_set_initializer_rvalue(value);
 
         // As an optimization, all shared statics which do not have interior
         // mutability are placed into read-only memory.
@@ -176,7 +180,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
             };
         // FIXME(antoyo): I think the name coming from generate_local_symbol_name() above cannot be used
         // globally.
-        global.global_set_initializer_value(cv);
+        global.global_set_initializer_rvalue(cv);
         // TODO(antoyo): set unnamed address.
         global.get_address(None)
     }
@@ -371,7 +375,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg
         real_name.push_str(&sym);
         let global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section);
         // TODO(antoyo): set linkage.
-        global2.global_set_initializer_value(global1.get_address(None));
+        global2.global_set_initializer_rvalue(global1.get_address(None));
         // TODO(antoyo): use global_set_initializer() when it will work.
         global2
     }
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 7677ade7314..dfcd1b62312 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -1,16 +1,6 @@
 use std::cell::{Cell, RefCell};
 
-use gccjit::{
-    Block,
-    Context,
-    CType,
-    Function,
-    FunctionType,
-    LValue,
-    RValue,
-    Struct,
-    Type,
-};
+use gccjit::{Block, CType, Context, Function, FunctionType, LValue, RValue, Struct, Type};
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use rustc_codegen_ssa::traits::{
     BackendTypes,
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 0782adeb6a1..572ac559d09 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -526,7 +526,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
 
         let value =
             if result_type.is_signed(self.cx) {
-                self.context.new_bitcast(None, value, typ)
+                self.context.new_cast(None, value, typ)
             }
             else {
                 value
@@ -690,7 +690,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                 },
             };
 
-        self.context.new_bitcast(None, result, result_type)
+        self.context.new_cast(None, result, result_type)
     }
 
     fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
@@ -741,6 +741,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                 let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
                 let not_low_and_not_high = not_low & not_high;
                 let index = not_high + not_low_and_not_high;
+                // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in
+                // gcc.
+                // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the
+                // compilation stage.
+                let index = self.context.new_cast(None, index, self.i32_type);
 
                 let res = self.context.new_array_access(None, result, index);
 
@@ -764,7 +769,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         let arg =
             if result_type.is_signed(self.cx) {
                 let new_type = result_type.to_unsigned(self.cx);
-                self.context.new_bitcast(None, arg, new_type)
+                self.context.new_cast(None, arg, new_type)
             }
             else {
                 arg
@@ -816,10 +821,15 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                 let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
                 let not_low_and_not_high = not_low & not_high;
                 let index = not_low + not_low_and_not_high;
+                // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in
+                // gcc.
+                // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the
+                // compilation stage.
+                let index = self.context.new_cast(None, index, self.i32_type);
 
                 let res = self.context.new_array_access(None, result, index);
 
-                return self.context.new_bitcast(None, res, result_type);
+                return self.context.new_cast(None, res, result_type);
             }
             else {
                 unimplemented!("count_trailing_zeroes for {:?}", arg_type);
@@ -833,7 +843,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                 arg
             };
         let res = self.context.new_call(None, count_trailing_zeroes, &[arg]);
-        self.context.new_bitcast(None, res, result_type)
+        self.context.new_cast(None, res, result_type)
     }
 
     fn int_width(&self, typ: Type<'gcc>) -> i64 {
@@ -847,7 +857,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
 
         let value =
             if result_type.is_signed(self.cx) {
-                self.context.new_bitcast(None, value, value_type)
+                self.context.new_cast(None, value, value_type)
             }
             else {
                 value
@@ -863,7 +873,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
             let low = self.context.new_cast(None, value, self.cx.ulonglong_type);
             let low = self.context.new_call(None, popcount, &[low]);
             let res = high + low;
-            return self.context.new_bitcast(None, res, result_type);
+            return self.context.new_cast(None, res, result_type);
         }
 
         // First step.
@@ -888,7 +898,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         let value = left + right;
 
         if value_type.is_u8(&self.cx) {
-            return self.context.new_bitcast(None, value, result_type);
+            return self.context.new_cast(None, value, result_type);
         }
 
         // Fourth step.
@@ -899,7 +909,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         let value = left + right;
 
         if value_type.is_u16(&self.cx) {
-            return self.context.new_bitcast(None, value, result_type);
+            return self.context.new_cast(None, value, result_type);
         }
 
         // Fifth step.
@@ -910,7 +920,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         let value = left + right;
 
         if value_type.is_u32(&self.cx) {
-            return self.context.new_bitcast(None, value, result_type);
+            return self.context.new_cast(None, value, result_type);
         }
 
         // Sixth step.
@@ -920,7 +930,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         let right = shifted & mask;
         let value = left + right;
 
-        self.context.new_bitcast(None, value, result_type)
+        self.context.new_cast(None, value, result_type)
     }
 
     // Algorithm from: https://blog.regehr.org/archives/1063
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 30a33b99e50..20347f18786 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -20,7 +20,6 @@ extern crate rustc_metadata;
 extern crate rustc_middle;
 extern crate rustc_session;
 extern crate rustc_span;
-extern crate rustc_symbol_mangling;
 extern crate rustc_target;
 
 // This prevents duplicating functions and statics that are already part of the host rustc process.
@@ -91,8 +90,6 @@ impl CodegenBackend for GccCodegenBackend {
         let target_cpu = target_cpu(tcx.sess);
         let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module);
 
-        rustc_symbol_mangling::test::report_symbol_names(tcx);
-
         Box::new(res)
     }
 
diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
index 3545e1b6281..28e2adc492b 100644
--- a/compiler/rustc_codegen_gcc/src/type_.rs
+++ b/compiler/rustc_codegen_gcc/src/type_.rs
@@ -122,7 +122,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         if typ.is_integral() {
             TypeKind::Integer
         }
-        else if typ.is_vector().is_some() {
+        else if typ.dyncast_vector().is_some() {
             TypeKind::Vector
         }
         else {
@@ -141,10 +141,10 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     }
 
     fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
-        if let Some(typ) = ty.is_array() {
+        if let Some(typ) = ty.dyncast_array() {
             typ
         }
-        else if let Some(vector_type) = ty.is_vector() {
+        else if let Some(vector_type) = ty.dyncast_vector() {
             vector_type.get_element_type()
         }
         else if let Some(typ) = ty.get_pointee() {
diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh
index 944d0ce516e..b9aeee79550 100755
--- a/compiler/rustc_codegen_gcc/test.sh
+++ b/compiler/rustc_codegen_gcc/test.sh
@@ -183,7 +183,7 @@ EOF
     git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs
     rm src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs || true # TODO(antoyo): Enable back this test if I ever implement the llvm_asm! macro.
 
-    RUSTC_ARGS="-Zpanic-abort-tests -Zsymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort"
+    RUSTC_ARGS="-Zpanic-abort-tests -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort"
 
     echo "[TEST] rustc test suite"
     COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 src/test/ui/ --rustc-args "$RUSTC_ARGS"
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
index 48c0203d594..46abbb553bf 100644
--- a/compiler/rustc_codegen_gcc/tests/run/asm.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -3,6 +3,10 @@
 // Run-time:
 //   status: 0
 
+#![feature(asm_const, asm_sym)]
+
+use std::arch::{asm, global_asm};
+
 global_asm!("
     .global add_asm
 add_asm:
@@ -15,6 +19,16 @@ extern "C" {
     fn add_asm(a: i64, b: i64) -> i64;
 }
 
+pub unsafe fn mem_cpy(dst: *mut u8, src: *const u8, len: usize) {
+    asm!(
+        "rep movsb",
+        inout("rdi") dst => _,
+        inout("rsi") src => _,
+        inout("rcx") len => _,
+        options(preserves_flags, nostack)
+    );
+}
+
 fn main() {
     unsafe {
         asm!("nop");
@@ -60,11 +74,11 @@ fn main() {
     }
     assert_eq!(x, 43);
 
-    // check inout(reg_class) x 
+    // check inout(reg_class) x
     let mut x: u64 = 42;
     unsafe {
         asm!("add {0}, {0}",
-            inout(reg) x 
+            inout(reg) x
         );
     }
     assert_eq!(x, 84);
@@ -73,7 +87,7 @@ fn main() {
     let mut x: u64 = 42;
     unsafe {
         asm!("add r11, r11",
-            inout("r11") x 
+            inout("r11") x
         );
     }
     assert_eq!(x, 84);
@@ -96,12 +110,12 @@ fn main() {
     assert_eq!(res, 7);
     assert_eq!(rem, 2);
 
-    // check const 
+    // check const
     let mut x: u64 = 42;
     unsafe {
         asm!("add {}, {}",
             inout(reg) x,
-            const 1 
+            const 1
         );
     }
     assert_eq!(x, 43);
@@ -148,4 +162,11 @@ fn main() {
     assert_eq!(x, 42);
 
     assert_eq!(unsafe { add_asm(40, 2) }, 42);
+
+    let array1 = [1u8, 2, 3];
+    let mut array2 = [0u8, 0, 0];
+    unsafe {
+        mem_cpy(array2.as_mut_ptr(), array1.as_ptr(), 3);
+    }
+    assert_eq!(array1, array2);
 }
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 4bb1fed2d51..ddba43cd1f1 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -3,7 +3,7 @@ use crate::back::write::{
 };
 use crate::llvm::archive_ro::ArchiveRO;
 use crate::llvm::{self, build_string, False, True};
-use crate::{LlvmCodegenBackend, ModuleLlvm};
+use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm};
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{
@@ -596,7 +596,10 @@ pub(crate) fn run_pass_manager(
     //      tools/lto/LTOCodeGenerator.cpp
     debug!("running the pass manager");
     unsafe {
-        if write::should_use_new_llvm_pass_manager(cgcx, config) {
+        if llvm_util::should_use_new_llvm_pass_manager(
+            &config.new_llvm_pass_manager,
+            &cgcx.target_arch,
+        ) {
             let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
             let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
             write::optimize_with_new_llvm_pass_manager(
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index fb194a98a0d..384596dfff5 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -23,7 +23,7 @@ use rustc_errors::{FatalError, Handler, Level};
 use rustc_fs_util::{link_or_copy, path_to_c_string};
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{self, Lto, OutputType, Passes, SwitchWithOptPath};
+use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
@@ -106,7 +106,11 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
 
 pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
     let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
-        tcx.output_filenames(()).split_dwarf_path(tcx.sess.split_debuginfo(), Some(mod_name))
+        tcx.output_filenames(()).split_dwarf_path(
+            tcx.sess.split_debuginfo(),
+            tcx.sess.opts.debugging_opts.split_dwarf_kind,
+            Some(mod_name),
+        )
     } else {
         None
     };
@@ -416,21 +420,6 @@ fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option<CString> {
         .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap())
 }
 
-pub(crate) fn should_use_new_llvm_pass_manager(
-    cgcx: &CodegenContext<LlvmCodegenBackend>,
-    config: &ModuleConfig,
-) -> bool {
-    // The new pass manager is enabled by default for LLVM >= 13.
-    // This matches Clang, which also enables it since Clang 13.
-
-    // FIXME: There are some perf issues with the new pass manager
-    // when targeting s390x, so it is temporarily disabled for that
-    // arch, see https://github.com/rust-lang/rust/issues/89609
-    config
-        .new_llvm_pass_manager
-        .unwrap_or_else(|| cgcx.target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0))
-}
-
 pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     diag_handler: &Handler,
@@ -473,6 +462,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
 
     let extra_passes = config.passes.join(",");
 
+    let llvm_plugins = config.llvm_plugins.join(",");
+
     // FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
     // We would have to add upstream support for this first, before we can support
     // config.inline_threshold and our more aggressive default thresholds.
@@ -502,6 +493,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
         selfprofile_after_pass_callback,
         extra_passes.as_ptr().cast(),
         extra_passes.len(),
+        llvm_plugins.as_ptr().cast(),
+        llvm_plugins.len(),
     );
     result.into_result().map_err(|()| llvm_err(diag_handler, "failed to run LLVM passes"))
 }
@@ -530,7 +523,10 @@ pub(crate) unsafe fn optimize(
     }
 
     if let Some(opt_level) = config.opt_level {
-        if should_use_new_llvm_pass_manager(cgcx, config) {
+        if llvm_util::should_use_new_llvm_pass_manager(
+            &config.new_llvm_pass_manager,
+            &cgcx.target_arch,
+        ) {
             let opt_stage = match cgcx.lto {
                 Lto::Fat => llvm::OptStage::PreLinkFatLTO,
                 Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
@@ -900,17 +896,18 @@ pub(crate) unsafe fn codegen(
                     .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
 
                 let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
-                let dwo_out = match cgcx.split_debuginfo {
-                    // Don't change how DWARF is emitted in single mode (or when disabled).
-                    SplitDebuginfo::Off | SplitDebuginfo::Packed => None,
-                    // Emit (a subset of the) DWARF into a separate file in split mode.
-                    SplitDebuginfo::Unpacked => {
-                        if cgcx.target_can_use_split_dwarf {
-                            Some(dwo_out.as_path())
-                        } else {
-                            None
-                        }
-                    }
+                let dwo_out = match (cgcx.split_debuginfo, cgcx.split_dwarf_kind) {
+                    // Don't change how DWARF is emitted when disabled.
+                    (SplitDebuginfo::Off, _) => None,
+                    // Don't provide a DWARF object path if split debuginfo is enabled but this is
+                    // a platform that doesn't support Split DWARF.
+                    _ if !cgcx.target_can_use_split_dwarf => None,
+                    // Don't provide a DWARF object path in single mode, sections will be written
+                    // into the object as normal but ignored by linker.
+                    (_, SplitDwarfKind::Single) => None,
+                    // Emit (a subset of the) DWARF into a separate dwarf object file in split
+                    // mode.
+                    (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
                 };
 
                 with_codegen(tm, llmod, config.no_builtins, |cpm| {
@@ -947,7 +944,9 @@ pub(crate) unsafe fn codegen(
 
     Ok(module.into_compiled_module(
         config.emit_obj != EmitObj::None,
-        cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
+        cgcx.target_can_use_split_dwarf
+            && cgcx.split_debuginfo != SplitDebuginfo::Off
+            && cgcx.split_dwarf_kind == SplitDwarfKind::Split,
         config.emit_bc,
         &cgcx.output_filenames,
     ))
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 8c3054b23ff..5217fa2758f 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1201,8 +1201,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         unsafe { llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, UNNAMED) }
     }
 
-    fn do_not_inline(&mut self, llret: &'ll Value) {
-        llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret);
+    fn apply_attrs_to_cleanup_callsite(&mut self, llret: &'ll Value) {
+        // Cleanup is always the cold path.
+        llvm::Attribute::Cold.apply_callsite(llvm::AttributePlace::Function, llret);
+
+        // In LLVM versions with deferred inlining (currently, system LLVM < 14),
+        // inlining drop glue can lead to exponential size blowup, see #41696 and #92110.
+        if !llvm_util::is_rust_llvm() && llvm_util::get_version() < (14, 0, 0) {
+            llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret);
+        }
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 9f24a95482c..bb16bc5dccd 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::layout::{
 };
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_session::config::{CFGuard, CrateType, DebugInfo};
+use rustc_session::config::{BranchProtection, CFGuard, CrateType, DebugInfo, PAuthKey, PacRet};
 use rustc_session::Session;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
@@ -242,6 +242,34 @@ pub unsafe fn create_module<'ll>(
         }
     }
 
+    if sess.target.arch == "aarch64" {
+        let BranchProtection { bti, pac_ret: pac } = sess.opts.debugging_opts.branch_protection;
+
+        llvm::LLVMRustAddModuleFlag(
+            llmod,
+            "branch-target-enforcement\0".as_ptr().cast(),
+            bti.into(),
+        );
+
+        llvm::LLVMRustAddModuleFlag(
+            llmod,
+            "sign-return-address\0".as_ptr().cast(),
+            pac.is_some().into(),
+        );
+        let pac_opts = pac.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
+        llvm::LLVMRustAddModuleFlag(
+            llmod,
+            "sign-return-address-all\0".as_ptr().cast(),
+            pac_opts.leaf.into(),
+        );
+        let is_bkey = if pac_opts.key == PAuthKey::A { false } else { true };
+        llvm::LLVMRustAddModuleFlag(
+            llmod,
+            "sign-return-address-with-bkey\0".as_ptr().cast(),
+            is_bkey.into(),
+        );
+    }
+
     llmod
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 5f9c4189168..60ff18af0a9 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -18,6 +18,7 @@ use crate::llvm::debuginfo::{
 use crate::value::Value;
 
 use cstr::cstr;
+use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
@@ -933,16 +934,16 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l
 
     // When targeting MSVC, emit MSVC style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let msvc_like_names = cx.tcx.sess.target.is_like_msvc;
+    let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx);
 
     let (name, encoding) = match t.kind() {
         ty::Never => ("!", DW_ATE_unsigned),
         ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
         ty::Bool => ("bool", DW_ATE_boolean),
         ty::Char => ("char", DW_ATE_unsigned_char),
-        ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed),
-        ty::Uint(uint_ty) if msvc_like_names => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
-        ty::Float(float_ty) if msvc_like_names => (float_ty.msvc_basic_name(), DW_ATE_float),
+        ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
+        ty::Uint(uint_ty) if cpp_like_debuginfo => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
+        ty::Float(float_ty) if cpp_like_debuginfo => (float_ty.msvc_basic_name(), DW_ATE_float),
         ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed),
         ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned),
         ty::Float(float_ty) => (float_ty.name_str(), DW_ATE_float),
@@ -959,7 +960,7 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l
         )
     };
 
-    if !msvc_like_names {
+    if !cpp_like_debuginfo {
         return ty_metadata;
     }
 
@@ -1072,7 +1073,11 @@ pub fn compile_unit_metadata<'ll, 'tcx>(
     let output_filenames = tcx.output_filenames(());
     let split_name = if tcx.sess.target_can_use_split_dwarf() {
         output_filenames
-            .split_dwarf_path(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
+            .split_dwarf_path(
+                tcx.sess.split_debuginfo(),
+                tcx.sess.opts.debugging_opts.split_dwarf_kind,
+                Some(codegen_unit_name),
+            )
             // We get a path relative to the working directory from split_dwarf_path
             .map(|f| tcx.sess.source_map().path_mapping().map_prefix(f).0)
     } else {
@@ -1521,13 +1526,6 @@ fn prepare_union_metadata<'ll, 'tcx>(
 // Enums
 //=-----------------------------------------------------------------------------
 
-/// DWARF variant support is only available starting in LLVM 8, but
-/// on MSVC we have to use the fallback mode, because LLVM doesn't
-/// lower variant parts to PDB.
-fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
-    cx.sess().target.is_like_msvc
-}
-
 // FIXME(eddyb) maybe precompute this? Right now it's computed once
 // per generator monomorphization, but it doesn't depend on substs.
 fn generator_layout_and_saved_local_names<'tcx>(
@@ -1602,7 +1600,10 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
             _ => bug!(),
         };
 
-        let fallback = use_enum_fallback(cx);
+        // While LLVM supports generating debuginfo for variant types (enums), it doesn't support
+        // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting
+        // msvc, then we need to use a different, fallback encoding of the debuginfo.
+        let fallback = cpp_like_debuginfo(cx.tcx);
         // This will always find the metadata in the type map.
         let self_metadata = type_metadata(cx, self.enum_type, self.span);
 
@@ -2155,7 +2156,10 @@ fn prepare_enum_metadata<'ll, 'tcx>(
         return FinalMetadata(discriminant_type_metadata(tag.value));
     }
 
-    if use_enum_fallback(cx) {
+    // While LLVM supports generating debuginfo for variant types (enums), it doesn't support
+    // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting
+    // msvc, then we need to use a different encoding of the debuginfo.
+    if cpp_like_debuginfo(tcx) {
         let discriminant_type_metadata = match layout.variants {
             Variants::Single { .. } => None,
             Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 3e7371179cc..01f7868df34 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -160,17 +160,17 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
         // the values should match the ones in the DWARF standard anyway.
         let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
         let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
-        let mut addr_ops = SmallVec::<[_; 8]>::new();
+        let mut addr_ops = SmallVec::<[u64; 8]>::new();
 
         if direct_offset.bytes() > 0 {
             addr_ops.push(op_plus_uconst());
-            addr_ops.push(direct_offset.bytes() as i64);
+            addr_ops.push(direct_offset.bytes() as u64);
         }
         for &offset in indirect_offsets {
             addr_ops.push(op_deref());
             if offset.bytes() > 0 {
                 addr_ops.push(op_plus_uconst());
-                addr_ops.push(offset.bytes() as i64);
+                addr_ops.push(offset.bytes() as u64);
             }
         }
 
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 90d0d5caba1..a6e06ffa819 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -47,6 +47,7 @@ fn declare_raw_fn<'ll>(
 
     attributes::default_optimisation_attrs(cx.tcx.sess, llfn);
     attributes::non_lazy_bind(cx.sess(), llfn);
+
     llfn
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 6c911938ccc..f2782f84f55 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1902,6 +1902,8 @@ extern "C" {
     pub fn LLVMRustVersionMinor() -> u32;
     pub fn LLVMRustVersionPatch() -> u32;
 
+    pub fn LLVMRustIsRustLLVM() -> bool;
+
     pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32);
 
     pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
@@ -2106,7 +2108,7 @@ extern "C" {
         Builder: &DIBuilder<'a>,
         Val: &'a Value,
         VarInfo: &'a DIVariable,
-        AddrOps: *const i64,
+        AddrOps: *const u64,
         AddrOpsCount: c_uint,
         DL: &'a DILocation,
         InsertAtEnd: &'a BasicBlock,
@@ -2197,8 +2199,8 @@ extern "C" {
         Scope: &'a DIScope,
         InlinedAt: Option<&'a DILocation>,
     ) -> &'a DILocation;
-    pub fn LLVMRustDIBuilderCreateOpDeref() -> i64;
-    pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64;
+    pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
+    pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
 
     #[allow(improper_ctypes)]
     pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
@@ -2313,6 +2315,8 @@ extern "C" {
         end_callback: SelfProfileAfterPassCallback,
         ExtraPasses: *const c_char,
         ExtraPassesLen: size_t,
+        LLVMPlugins: *const c_char,
+        LLVMPluginsLen: size_t,
     ) -> LLVMRustResult;
     pub fn LLVMRustPrintModule(
         M: &Module,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index e4935ac431c..d49df29f453 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -121,14 +121,20 @@ unsafe fn configure_llvm(sess: &Session) {
 
     llvm::LLVMInitializePasses();
 
-    // Register LLVM plugins by loading them into the compiler process.
-    for plugin in &sess.opts.debugging_opts.llvm_plugins {
-        let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e));
-        debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin);
-
-        // Intentionally leak the dynamic library. We can't ever unload it
-        // since the library can make things that will live arbitrarily long.
-        mem::forget(lib);
+    // Use the legacy plugin registration if we don't use the new pass manager
+    if !should_use_new_llvm_pass_manager(
+        &sess.opts.debugging_opts.new_llvm_pass_manager,
+        &sess.target.arch,
+    ) {
+        // Register LLVM plugins by loading them into the compiler process.
+        for plugin in &sess.opts.debugging_opts.llvm_plugins {
+            let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e));
+            debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin);
+
+            // Intentionally leak the dynamic library. We can't ever unload it
+            // since the library can make things that will live arbitrarily long.
+            mem::forget(lib);
+        }
     }
 
     rustc_llvm::initialize_available_targets();
@@ -217,6 +223,12 @@ pub fn get_version() -> (u32, u32, u32) {
     }
 }
 
+/// Returns `true` if this LLVM is Rust's bundled LLVM (and not system LLVM).
+pub fn is_rust_llvm() -> bool {
+    // Can be called without initializing LLVM
+    unsafe { llvm::LLVMRustIsRustLLVM() }
+}
+
 pub fn print_passes() {
     // Can be called without initializing LLVM
     unsafe {
@@ -411,3 +423,13 @@ pub fn tune_cpu(sess: &Session) -> Option<&str> {
     let name = sess.opts.debugging_opts.tune_cpu.as_ref()?;
     Some(handle_native(name))
 }
+
+pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_arch: &str) -> bool {
+    // The new pass manager is enabled by default for LLVM >= 13.
+    // This matches Clang, which also enables it since Clang 13.
+
+    // FIXME: There are some perf issues with the new pass manager
+    // when targeting s390x, so it is temporarily disabled for that
+    // arch, see https://github.com/rust-lang/rust/issues/89609
+    user_opt.unwrap_or_else(|| target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0))
+}
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 18dbcd8e52d..5c13dfdc1b5 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -14,12 +14,14 @@ tracing = "0.1"
 libc = "0.2.50"
 jobserver = "0.1.22"
 tempfile = "3.2"
+thorin-dwp = "0.1.1"
 pathdiff = "0.2.0"
 snap = "1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 regex = "1.4"
 
 rustc_serialize = { path = "../rustc_serialize" }
+rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 42a28f94298..f7fe194d207 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1,11 +1,13 @@
+use rustc_arena::TypedArena;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorReported, Handler};
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
-use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
+use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
 use rustc_session::cstore::DllImport;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
@@ -32,7 +34,10 @@ use cc::windows_registry;
 use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
-use std::ffi::{OsStr, OsString};
+use std::borrow::Borrow;
+use std::ffi::OsString;
+use std::fs::{File, OpenOptions};
+use std::io::{BufWriter, Write};
 use std::lazy::OnceCell;
 use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
@@ -134,31 +139,47 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
         }
     }
 
-    // Remove the temporary object file and metadata if we aren't saving temps
+    // Remove the temporary object file and metadata if we aren't saving temps.
     sess.time("link_binary_remove_temps", || {
-        if !sess.opts.cg.save_temps {
-            let remove_temps_from_module = |module: &CompiledModule| {
-                if let Some(ref obj) = module.object {
-                    ensure_removed(sess.diagnostic(), obj);
-                }
-
-                if let Some(ref obj) = module.dwarf_object {
-                    ensure_removed(sess.diagnostic(), obj);
-                }
-            };
+        // If the user requests that temporaries are saved, don't delete any.
+        if sess.opts.cg.save_temps {
+            return;
+        }
 
-            if sess.opts.output_types.should_link() && !preserve_objects_for_their_debuginfo(sess) {
-                for module in &codegen_results.modules {
-                    remove_temps_from_module(module);
-                }
+        let remove_temps_from_module = |module: &CompiledModule| {
+            if let Some(ref obj) = module.object {
+                ensure_removed(sess.diagnostic(), obj);
             }
+        };
+
+        // Otherwise, always remove the metadata and allocator module temporaries.
+        if let Some(ref metadata_module) = codegen_results.metadata_module {
+            remove_temps_from_module(metadata_module);
+        }
+
+        if let Some(ref allocator_module) = codegen_results.allocator_module {
+            remove_temps_from_module(allocator_module);
+        }
 
-            if let Some(ref metadata_module) = codegen_results.metadata_module {
-                remove_temps_from_module(metadata_module);
+        // If no requested outputs require linking, then the object temporaries should
+        // be kept.
+        if !sess.opts.output_types.should_link() {
+            return;
+        }
+
+        // Potentially keep objects for their debuginfo.
+        let (preserve_objects, preserve_dwarf_objects) = preserve_objects_for_their_debuginfo(sess);
+        debug!(?preserve_objects, ?preserve_dwarf_objects);
+
+        for module in &codegen_results.modules {
+            if !preserve_objects {
+                remove_temps_from_module(module);
             }
 
-            if let Some(ref allocator_module) = codegen_results.allocator_module {
-                remove_temps_from_module(allocator_module);
+            if !preserve_dwarf_objects {
+                if let Some(ref obj) = module.dwarf_object {
+                    ensure_removed(sess.diagnostic(), obj);
+                }
             }
         }
     });
@@ -245,8 +266,14 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
 
     let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None);
 
-    for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
-        ab.add_file(obj);
+    for m in &codegen_results.modules {
+        if let Some(obj) = m.object.as_ref() {
+            ab.add_file(obj);
+        }
+
+        if let Some(dwarf_obj) = m.dwarf_object.as_ref() {
+            ab.add_file(dwarf_obj);
+        }
     }
 
     // Note that in this loop we are ignoring the value of `lib.cfg`. That is,
@@ -502,59 +529,108 @@ fn escape_stdout_stderr_string(s: &[u8]) -> String {
     })
 }
 
-const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp";
-
-/// Invoke `llvm-dwp` (shipped alongside rustc) to link debuginfo in object files into a `dwp`
-/// file.
-fn link_dwarf_object<'a, I>(sess: &'a Session, executable_out_filename: &Path, object_files: I)
-where
-    I: IntoIterator<Item: AsRef<OsStr>>,
-{
-    info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap());
-
+/// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a
+/// DWARF package.
+fn link_dwarf_object<'a>(
+    sess: &'a Session,
+    cg_results: &CodegenResults,
+    executable_out_filename: &Path,
+) {
     let dwp_out_filename = executable_out_filename.with_extension("dwp");
-    let mut cmd = Command::new(LLVM_DWP_EXECUTABLE);
-    cmd.arg("-o");
-    cmd.arg(&dwp_out_filename);
-    cmd.args(object_files);
+    debug!(?dwp_out_filename, ?executable_out_filename);
 
-    let mut new_path = sess.get_tools_search_paths(false);
-    if let Some(path) = env::var_os("PATH") {
-        new_path.extend(env::split_paths(&path));
+    #[derive(Default)]
+    struct ThorinSession<Relocations> {
+        arena_data: TypedArena<Vec<u8>>,
+        arena_mmap: TypedArena<Mmap>,
+        arena_relocations: TypedArena<Relocations>,
     }
-    let new_path = env::join_paths(new_path).unwrap();
-    cmd.env("PATH", new_path);
 
-    info!("{:?}", &cmd);
-    match sess.time("run_dwp", || cmd.output()) {
-        Ok(prog) if !prog.status.success() => {
-            sess.struct_err(&format!(
-                "linking dwarf objects with `{}` failed: {}",
-                LLVM_DWP_EXECUTABLE, prog.status
-            ))
-            .note(&format!("{:?}", &cmd))
-            .note(&escape_stdout_stderr_string(&prog.stdout))
-            .note(&escape_stdout_stderr_string(&prog.stderr))
-            .emit();
-            info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr));
-            info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout));
+    impl<Relocations> ThorinSession<Relocations> {
+        fn alloc_mmap<'arena>(&'arena self, data: Mmap) -> &'arena Mmap {
+            (*self.arena_mmap.alloc(data)).borrow()
         }
-        Ok(_) => {}
-        Err(e) => {
-            let dwp_not_found = e.kind() == io::ErrorKind::NotFound;
-            let mut err = if dwp_not_found {
-                sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE))
-            } else {
-                sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE))
-            };
+    }
 
-            err.note(&e.to_string());
+    impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
+        fn alloc_data<'arena>(&'arena self, data: Vec<u8>) -> &'arena [u8] {
+            (*self.arena_data.alloc(data)).borrow()
+        }
 
-            if !dwp_not_found {
-                err.note(&format!("{:?}", &cmd));
+        fn alloc_relocation<'arena>(&'arena self, data: Relocations) -> &'arena Relocations {
+            (*self.arena_relocations.alloc(data)).borrow()
+        }
+
+        fn read_input<'arena>(&'arena self, path: &Path) -> std::io::Result<&'arena [u8]> {
+            let file = File::open(&path)?;
+            let mmap = (unsafe { Mmap::map(file) })?;
+            Ok(self.alloc_mmap(mmap))
+        }
+    }
+
+    match sess.time("run_thorin", || -> Result<(), thorin::Error> {
+        let thorin_sess = ThorinSession::default();
+        let mut package = thorin::DwarfPackage::new(&thorin_sess);
+
+        // Input objs contain .o/.dwo files from the current crate.
+        match sess.opts.debugging_opts.split_dwarf_kind {
+            SplitDwarfKind::Single => {
+                for input_obj in cg_results.modules.iter().filter_map(|m| m.object.as_ref()) {
+                    package.add_input_object(input_obj)?;
+                }
             }
+            SplitDwarfKind::Split => {
+                for input_obj in cg_results.modules.iter().filter_map(|m| m.dwarf_object.as_ref()) {
+                    package.add_input_object(input_obj)?;
+                }
+            }
+        }
 
-            err.emit();
+        // Input rlibs contain .o/.dwo files from dependencies.
+        let input_rlibs = cg_results
+            .crate_info
+            .used_crate_source
+            .values()
+            .filter_map(|csource| csource.rlib.as_ref())
+            .map(|(path, _)| path);
+        for input_rlib in input_rlibs {
+            debug!(?input_rlib);
+            package.add_input_object(input_rlib)?;
+        }
+
+        // Failing to read the referenced objects is expected for dependencies where the path in the
+        // executable will have been cleaned by Cargo, but the referenced objects will be contained
+        // within rlibs provided as inputs.
+        //
+        // If paths have been remapped, then .o/.dwo files from the current crate also won't be
+        // found, but are provided explicitly above.
+        //
+        // Adding an executable is primarily done to make `thorin` check that all the referenced
+        // dwarf objects are found in the end.
+        package.add_executable(
+            &executable_out_filename,
+            thorin::MissingReferencedObjectBehaviour::Skip,
+        )?;
+
+        let output = package.finish()?.write()?;
+        let mut output_stream = BufWriter::new(
+            OpenOptions::new()
+                .read(true)
+                .write(true)
+                .create(true)
+                .truncate(true)
+                .open(dwp_out_filename)?,
+        );
+        output_stream.write_all(&output)?;
+        output_stream.flush()?;
+
+        Ok(())
+    }) {
+        Ok(()) => {}
+        Err(e) => {
+            sess.struct_err("linking dwarf objects with thorin failed")
+                .note(&format!("{:?}", e))
+                .emit();
         }
     }
 }
@@ -900,14 +976,11 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
 
         // ... and otherwise we're processing a `*.dwp` packed dwarf file.
+        //
         // We cannot rely on the .o paths in the exectuable because they may have been
-        // remapped by --remap-path-prefix and therefore invalid. So we need to provide
-        // the .o paths explicitly
-        SplitDebuginfo::Packed => link_dwarf_object(
-            sess,
-            &out_filename,
-            codegen_results.modules.iter().filter_map(|m| m.object.as_ref()),
-        ),
+        // remapped by --remap-path-prefix and therefore invalid, so we need to provide
+        // the .o/.dwo paths explicitly.
+        SplitDebuginfo::Packed => link_dwarf_object(sess, codegen_results, out_filename),
     }
 
     let strip = strip_value(sess);
@@ -1138,26 +1211,36 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
     bug!("Not enough information provided to determine how to invoke the linker");
 }
 
-/// Returns a boolean indicating whether we should preserve the object files on
-/// the filesystem for their debug information. This is often useful with
-/// split-dwarf like schemes.
-fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
+/// Returns a pair of boolean indicating whether we should preserve the object and
+/// dwarf object files on the filesystem for their debug information. This is often
+/// useful with split-dwarf like schemes.
+fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) {
     // If the objects don't have debuginfo there's nothing to preserve.
     if sess.opts.debuginfo == config::DebugInfo::None {
-        return false;
+        return (false, false);
     }
 
     // If we're only producing artifacts that are archives, no need to preserve
     // the objects as they're losslessly contained inside the archives.
-    let output_linked =
-        sess.crate_types().iter().any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib);
-    if !output_linked {
-        return false;
+    if sess.crate_types().iter().all(|&x| x.is_archive()) {
+        return (false, false);
+    }
+
+    match (sess.split_debuginfo(), sess.opts.debugging_opts.split_dwarf_kind) {
+        // If there is no split debuginfo then do not preserve objects.
+        (SplitDebuginfo::Off, _) => (false, false),
+        // If there is packed split debuginfo, then the debuginfo in the objects
+        // has been packaged and the objects can be deleted.
+        (SplitDebuginfo::Packed, _) => (false, false),
+        // If there is unpacked split debuginfo and the current target can not use
+        // split dwarf, then keep objects.
+        (SplitDebuginfo::Unpacked, _) if !sess.target_can_use_split_dwarf() => (true, false),
+        // If there is unpacked split debuginfo and the target can use split dwarf, then
+        // keep the object containing that debuginfo (whether that is an object file or
+        // dwarf object file depends on the split dwarf kind).
+        (SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => (true, false),
+        (SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => (false, true),
     }
-
-    // "unpacked" split debuginfo means that we leave object files as the
-    // debuginfo is found in the original object files themselves
-    sess.split_debuginfo() == SplitDebuginfo::Unpacked
 }
 
 fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 7c97143e807..79c24f0f172 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -6,8 +6,8 @@ use std::path::Path;
 
 use object::write::{self, StandardSegment, Symbol, SymbolSection};
 use object::{
-    elf, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, SectionFlags,
-    SectionKind, SymbolFlags, SymbolKind, SymbolScope,
+    elf, pe, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection,
+    SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
 };
 
 use snap::write::FrameEncoder;
@@ -216,13 +216,12 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
     );
     match file.format() {
         BinaryFormat::Coff => {
-            const IMAGE_SCN_LNK_REMOVE: u32 = 0;
             file.section_mut(section).flags =
-                SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
+                SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE };
         }
         BinaryFormat::Elf => {
-            const SHF_EXCLUDE: u64 = 0x80000000;
-            file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
+            file.section_mut(section).flags =
+                SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 };
         }
         _ => {}
     };
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index d6af6104155..bea454458c4 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -113,6 +113,7 @@ pub struct ModuleConfig {
     pub inline_threshold: Option<u32>,
     pub new_llvm_pass_manager: Option<bool>,
     pub emit_lifetime_markers: bool,
+    pub llvm_plugins: Vec<String>,
 }
 
 impl ModuleConfig {
@@ -260,6 +261,7 @@ impl ModuleConfig {
             inline_threshold: sess.opts.cg.inline_threshold,
             new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager,
             emit_lifetime_markers: sess.emit_lifetime_markers(),
+            llvm_plugins: if_regular!(sess.opts.debugging_opts.llvm_plugins.clone(), vec![]),
         }
     }
 
@@ -284,7 +286,11 @@ impl TargetMachineFactoryConfig {
         module_name: &str,
     ) -> TargetMachineFactoryConfig {
         let split_dwarf_file = if cgcx.target_can_use_split_dwarf {
-            cgcx.output_filenames.split_dwarf_path(cgcx.split_debuginfo, Some(module_name))
+            cgcx.output_filenames.split_dwarf_path(
+                cgcx.split_debuginfo,
+                cgcx.split_dwarf_kind,
+                Some(module_name),
+            )
         } else {
             None
         };
@@ -327,6 +333,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub target_arch: String,
     pub debuginfo: config::DebugInfo,
     pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
+    pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
 
     // Number of cgus excluding the allocator/metadata modules
     pub total_cgus: usize,
@@ -1058,6 +1065,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         target_arch: tcx.sess.target.arch.clone(),
         debuginfo: tcx.sess.opts.debuginfo,
         split_debuginfo: tcx.sess.split_debuginfo(),
+        split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf_kind,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 00e76800d47..93bb1aee25f 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -53,14 +53,14 @@ fn push_debuginfo_type_name<'tcx>(
 ) {
     // When targeting MSVC, emit C++ style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let cpp_like_names = cpp_like_names(tcx);
+    let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
 
     match *t.kind() {
         ty::Bool => output.push_str("bool"),
         ty::Char => output.push_str("char"),
         ty::Str => output.push_str("str"),
         ty::Never => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 output.push_str("never$");
             } else {
                 output.push('!');
@@ -71,7 +71,7 @@ fn push_debuginfo_type_name<'tcx>(
         ty::Float(float_ty) => output.push_str(float_ty.name_str()),
         ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
         ty::Adt(def, substs) => {
-            if def.is_enum() && cpp_like_names {
+            if def.is_enum() && cpp_like_debuginfo {
                 msvc_enum_fallback(tcx, t, def, substs, output, visited);
             } else {
                 push_item_name(tcx, def.did, qualified, output);
@@ -79,7 +79,7 @@ fn push_debuginfo_type_name<'tcx>(
             }
         }
         ty::Tuple(component_types) => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 output.push_str("tuple$<");
             } else {
                 output.push('(');
@@ -87,20 +87,20 @@ fn push_debuginfo_type_name<'tcx>(
 
             for component_type in component_types {
                 push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited);
-                push_arg_separator(cpp_like_names, output);
+                push_arg_separator(cpp_like_debuginfo, output);
             }
             if !component_types.is_empty() {
                 pop_arg_separator(output);
             }
 
-            if cpp_like_names {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             } else {
                 output.push(')');
             }
         }
         ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 match mutbl {
                     hir::Mutability::Not => output.push_str("ptr_const$<"),
                     hir::Mutability::Mut => output.push_str("ptr_mut$<"),
@@ -115,8 +115,8 @@ fn push_debuginfo_type_name<'tcx>(
 
             push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
 
-            if cpp_like_names {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             }
         }
         ty::Ref(_, inner_type, mutbl) => {
@@ -126,7 +126,7 @@ fn push_debuginfo_type_name<'tcx>(
             // types out to aid debugging in MSVC.
             let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);
 
-            if !cpp_like_names {
+            if !cpp_like_debuginfo {
                 output.push('&');
                 output.push_str(mutbl.prefix_str());
             } else if !is_slice_or_str {
@@ -138,12 +138,12 @@ fn push_debuginfo_type_name<'tcx>(
 
             push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
 
-            if cpp_like_names && !is_slice_or_str {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo && !is_slice_or_str {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             }
         }
         ty::Array(inner_type, len) => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 output.push_str("array$<");
                 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
                 match len.val {
@@ -162,7 +162,7 @@ fn push_debuginfo_type_name<'tcx>(
             }
         }
         ty::Slice(inner_type) => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 output.push_str("slice$<");
             } else {
                 output.push('[');
@@ -170,8 +170,8 @@ fn push_debuginfo_type_name<'tcx>(
 
             push_debuginfo_type_name(tcx, inner_type, true, output, visited);
 
-            if cpp_like_names {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             } else {
                 output.push(']');
             }
@@ -179,7 +179,7 @@ fn push_debuginfo_type_name<'tcx>(
         ty::Dynamic(ref trait_data, ..) => {
             let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect();
 
-            let has_enclosing_parens = if cpp_like_names {
+            let has_enclosing_parens = if cpp_like_debuginfo {
                 output.push_str("dyn$<");
                 false
             } else {
@@ -216,14 +216,14 @@ fn push_debuginfo_type_name<'tcx>(
                     }
 
                     for (item_def_id, ty) in projection_bounds {
-                        push_arg_separator(cpp_like_names, output);
+                        push_arg_separator(cpp_like_debuginfo, output);
 
-                        if cpp_like_names {
+                        if cpp_like_debuginfo {
                             output.push_str("assoc$<");
                             push_item_name(tcx, item_def_id, false, output);
-                            push_arg_separator(cpp_like_names, output);
+                            push_arg_separator(cpp_like_debuginfo, output);
                             push_debuginfo_type_name(tcx, ty, true, output, visited);
-                            push_close_angle_bracket(cpp_like_names, output);
+                            push_close_angle_bracket(cpp_like_debuginfo, output);
                         } else {
                             push_item_name(tcx, item_def_id, false, output);
                             output.push('=');
@@ -231,11 +231,11 @@ fn push_debuginfo_type_name<'tcx>(
                         }
                     }
 
-                    push_close_angle_bracket(cpp_like_names, output);
+                    push_close_angle_bracket(cpp_like_debuginfo, output);
                 }
 
                 if auto_traits.len() != 0 {
-                    push_auto_trait_separator(cpp_like_names, output);
+                    push_auto_trait_separator(cpp_like_debuginfo, output);
                 }
             }
 
@@ -252,14 +252,14 @@ fn push_debuginfo_type_name<'tcx>(
 
                 for auto_trait in auto_traits {
                     output.push_str(&auto_trait);
-                    push_auto_trait_separator(cpp_like_names, output);
+                    push_auto_trait_separator(cpp_like_debuginfo, output);
                 }
 
                 pop_auto_trait_separator(output);
             }
 
-            if cpp_like_names {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             } else if has_enclosing_parens {
                 output.push(')');
             }
@@ -279,7 +279,7 @@ fn push_debuginfo_type_name<'tcx>(
             // use a dummy string that should make it clear
             // that something unusual is going on
             if !visited.insert(t) {
-                output.push_str(if cpp_like_names {
+                output.push_str(if cpp_like_debuginfo {
                     "recursive_type$"
                 } else {
                     "<recursive_type>"
@@ -290,7 +290,7 @@ fn push_debuginfo_type_name<'tcx>(
             let sig =
                 tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx));
 
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 // Format as a C++ function pointer: return_type (*)(params...)
                 if sig.output().is_unit() {
                     output.push_str("void");
@@ -313,7 +313,7 @@ fn push_debuginfo_type_name<'tcx>(
             if !sig.inputs().is_empty() {
                 for &parameter_type in sig.inputs() {
                     push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
-                    push_arg_separator(cpp_like_names, output);
+                    push_arg_separator(cpp_like_debuginfo, output);
                 }
                 pop_arg_separator(output);
             }
@@ -328,7 +328,7 @@ fn push_debuginfo_type_name<'tcx>(
 
             output.push(')');
 
-            if !cpp_like_names && !sig.output().is_unit() {
+            if !cpp_like_debuginfo && !sig.output().is_unit() {
                 output.push_str(" -> ");
                 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
             }
@@ -426,9 +426,9 @@ fn push_debuginfo_type_name<'tcx>(
 
     const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + ";
 
-    fn push_auto_trait_separator(cpp_like_names: bool, output: &mut String) {
-        if cpp_like_names {
-            push_arg_separator(cpp_like_names, output);
+    fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) {
+        if cpp_like_debuginfo {
+            push_arg_separator(cpp_like_debuginfo, output);
         } else {
             output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR);
         }
@@ -457,11 +457,11 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
     t: Ty<'tcx>,
     trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
 ) -> String {
-    let cpp_like_names = cpp_like_names(tcx);
+    let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
 
     let mut vtable_name = String::with_capacity(64);
 
-    if cpp_like_names {
+    if cpp_like_debuginfo {
         vtable_name.push_str("impl$<");
     } else {
         vtable_name.push('<');
@@ -470,7 +470,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
     let mut visited = FxHashSet::default();
     push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited);
 
-    if cpp_like_names {
+    if cpp_like_debuginfo {
         vtable_name.push_str(", ");
     } else {
         vtable_name.push_str(" as ");
@@ -486,9 +486,9 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
         vtable_name.push_str("_");
     }
 
-    push_close_angle_bracket(cpp_like_names, &mut vtable_name);
+    push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
 
-    let suffix = if cpp_like_names { "::vtable$" } else { "::{vtable}" };
+    let suffix = if cpp_like_debuginfo { "::vtable$" } else { "::{vtable}" };
 
     vtable_name.reserve_exact(suffix.len());
     vtable_name.push_str(suffix);
@@ -521,7 +521,7 @@ fn push_unqualified_item_name(
         DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => {
             // Generators look like closures, but we want to treat them differently
             // in the debug info.
-            if cpp_like_names(tcx) {
+            if cpp_like_debuginfo(tcx) {
                 write!(output, "generator${}", disambiguated_data.disambiguator).unwrap();
             } else {
                 write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap();
@@ -532,7 +532,7 @@ fn push_unqualified_item_name(
                 output.push_str(name.as_str());
             }
             DefPathDataName::Anon { namespace } => {
-                if cpp_like_names(tcx) {
+                if cpp_like_debuginfo(tcx) {
                     write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap();
                 } else {
                     write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator)
@@ -560,7 +560,7 @@ fn push_generic_params_internal<'tcx>(
 
     debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs));
 
-    let cpp_like_names = cpp_like_names(tcx);
+    let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
 
     output.push('<');
 
@@ -575,10 +575,10 @@ fn push_generic_params_internal<'tcx>(
             other => bug!("Unexpected non-erasable generic: {:?}", other),
         }
 
-        push_arg_separator(cpp_like_names, output);
+        push_arg_separator(cpp_like_debuginfo, output);
     }
     pop_arg_separator(output);
-    push_close_angle_bracket(cpp_like_names, output);
+    push_close_angle_bracket(cpp_like_debuginfo, output);
 
     true
 }
@@ -617,7 +617,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output:
                 // avoiding collisions and will make the emitted type names shorter.
                 let hash: u64 = hasher.finish();
 
-                if cpp_like_names(tcx) {
+                if cpp_like_debuginfo(tcx) {
                     write!(output, "CONST${:x}", hash)
                 } else {
                     write!(output, "{{CONST#{:x}}}", hash)
@@ -634,10 +634,10 @@ pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, out
     push_generic_params_internal(tcx, substs, output, &mut visited);
 }
 
-fn push_close_angle_bracket(cpp_like_names: bool, output: &mut String) {
+fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
     // MSVC debugger always treats `>>` as a shift, even when parsing templates,
     // so add a space to avoid confusion.
-    if cpp_like_names && output.ends_with('>') {
+    if cpp_like_debuginfo && output.ends_with('>') {
         output.push(' ')
     };
 
@@ -652,11 +652,11 @@ fn pop_close_angle_bracket(output: &mut String) {
     }
 }
 
-fn push_arg_separator(cpp_like_names: bool, output: &mut String) {
+fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) {
     // Natvis does not always like having spaces between parts of the type name
     // and this causes issues when we need to write a typename in natvis, for example
     // as part of a cast like the `HashMap` visualizer does.
-    if cpp_like_names {
+    if cpp_like_debuginfo {
         output.push(',');
     } else {
         output.push_str(", ");
@@ -673,6 +673,7 @@ fn pop_arg_separator(output: &mut String) {
     output.pop();
 }
 
-fn cpp_like_names(tcx: TyCtxt<'_>) -> bool {
+/// Check if we should generate C++ like names and debug information.
+pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool {
     tcx.sess.target.is_like_msvc
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index e914e493269..dcfe5fcc2ca 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -160,11 +160,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
             let llret = bx.call(fn_ty, fn_ptr, &llargs, self.funclet(fx));
             bx.apply_attrs_callsite(&fn_abi, llret);
             if fx.mir[self.bb].is_cleanup {
-                // Cleanup is always the cold path. Don't inline
-                // drop glue. Also, when there is a deeply-nested
-                // struct, there are "symmetry" issues that cause
-                // exponential inlining - see issue #41696.
-                bx.do_not_inline(llret);
+                bx.apply_attrs_to_cleanup_callsite(llret);
             }
 
             if let Some((ret_dest, target)) = destination {
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index f087b9f7815..679c4576701 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -8,7 +8,6 @@ use crate::traits::*;
 use crate::MemFlags;
 
 use rustc_apfloat::{ieee, Float, Round, Status};
-use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir;
 use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
@@ -112,9 +111,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
                 let (dest, active_field_index) = match **kind {
-                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
+                    mir::AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => {
                         dest.codegen_set_discr(&mut bx, variant_index);
-                        if adt_def.is_enum() {
+                        if bx.tcx().adt_def(adt_did).is_enum() {
                             (dest.project_downcast(&mut bx, variant_index), active_field_index)
                         } else {
                             (dest, active_field_index)
@@ -486,31 +485,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 )
             }
 
-            mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => {
-                let content_ty = self.monomorphize(content_ty);
-                let content_layout = bx.cx().layout_of(content_ty);
-                let llsize = bx.cx().const_usize(content_layout.size.bytes());
-                let llalign = bx.cx().const_usize(content_layout.align.abi.bytes());
-                let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty));
-                let llty_ptr = bx.cx().backend_type(box_layout);
-
-                // Allocate space:
-                let def_id = match bx.tcx().lang_items().require(LangItem::ExchangeMalloc) {
-                    Ok(id) => id,
-                    Err(s) => {
-                        bx.cx().sess().fatal(&format!("allocation of `{}` {}", box_layout.ty, s));
-                    }
-                };
-                let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let r = bx.cx().get_fn_addr(instance);
-                let ty = bx.type_func(&[bx.type_isize(), bx.type_isize()], bx.type_i8p());
-                let call = bx.call(ty, r, &[llsize, llalign], None);
-                let val = bx.pointercast(call, llty_ptr);
-
-                let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
-                (bx, operand)
-            }
-
             mir::Rvalue::NullaryOp(null_op, ty) => {
                 let ty = self.monomorphize(ty);
                 assert!(bx.cx().type_is_sized(ty));
@@ -518,7 +492,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let val = match null_op {
                     mir::NullOp::SizeOf => layout.size.bytes(),
                     mir::NullOp::AlignOf => layout.align.abi.bytes(),
-                    mir::NullOp::Box => unreachable!(),
                 };
                 let val = bx.cx().const_usize(val);
                 let tcx = self.cx.tcx();
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 158e658301e..48d88095855 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -311,5 +311,5 @@ pub trait BuilderMethods<'a, 'tcx>:
     ) -> Self::Value;
     fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
 
-    fn do_not_inline(&mut self, llret: Self::Value);
+    fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value);
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index c5412affafe..3ec9f3ca3b8 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -63,7 +63,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
         cid.instance,
         body,
         Some(&ret.into()),
-        StackPopCleanup::None { cleanup: false },
+        StackPopCleanup::Root { cleanup: false },
     )?;
 
     // The main interpreter loop.
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 550715abc10..30e9cbe4403 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -260,7 +260,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         args: &[OpTy<'tcx>],
         _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
         _unwind: StackPopUnwind, // unwinding is not supported in consts
-    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
+    ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
         debug!("find_mir_or_eval_fn: {:?}", instance);
 
         // Only check non-glue functions
@@ -279,11 +279,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
 
             if let Some(new_instance) = ecx.hook_special_const_fn(instance, args)? {
                 // We call another const fn instead.
-                return Self::find_mir_or_eval_fn(ecx, new_instance, _abi, args, _ret, _unwind);
+                // However, we return the *original* instance to make backtraces work out
+                // (and we hope this does not confuse the FnAbi checks too much).
+                return Ok(Self::find_mir_or_eval_fn(
+                    ecx,
+                    new_instance,
+                    _abi,
+                    args,
+                    _ret,
+                    _unwind,
+                )?
+                .map(|(body, _instance)| (body, instance)));
             }
         }
         // This is a const fn. Call it.
-        Ok(Some(ecx.load_mir(instance.def, None)?))
+        Ok(Some((ecx.load_mir(instance.def, None)?, instance)))
     }
 
     fn call_intrinsic(
@@ -388,13 +398,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
     }
 
-    fn box_alloc(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _dest: &PlaceTy<'tcx>,
-    ) -> InterpResult<'tcx> {
-        Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into())
-    }
-
     fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
         // The step limit has already been hit in a previous call to `before_terminator`.
         if ecx.machine.steps_remaining == 0 {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index d9faa6777ea..0a8112da2ab 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -8,7 +8,10 @@ use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpError, InvalidProgramInfo};
-use rustc_middle::ty::layout::{self, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
+use rustc_middle::ty::layout::{
+    self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
+    TyAndLayout,
+};
 use rustc_middle::ty::{
     self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
 };
@@ -16,7 +19,7 @@ use rustc_mir_dataflow::storage::AlwaysLiveLocals;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::Limit;
 use rustc_span::{Pos, Span};
-use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
+use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
 
 use super::{
     AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
@@ -153,11 +156,11 @@ pub enum StackPopCleanup {
     /// `ret` stores the block we jump to on a normal return, while `unwind`
     /// stores the block used for cleanup during unwinding.
     Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
-    /// Just do nothing: Used by Main and for the `box_alloc` hook in miri.
+    /// The root frame of the stack: nowhere else to jump to.
     /// `cleanup` says whether locals are deallocated. Static computation
     /// wants them leaked to intern what they need (and just throw away
     /// the entire `ecx` when it is done).
-    None { cleanup: bool },
+    Root { cleanup: bool },
 }
 
 /// State of a local variable including a memoized layout
@@ -333,6 +336,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOfHelpers<'tcx> for InterpC
     }
 }
 
+impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M> {
+    type FnAbiOfResult = InterpResult<'tcx, &'tcx FnAbi<'tcx, Ty<'tcx>>>;
+
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        _span: Span,
+        _fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> InterpErrorInfo<'tcx> {
+        match err {
+            FnAbiError::Layout(err) => err_inval!(Layout(err)).into(),
+            FnAbiError::AdjustForForeignAbi(err) => {
+                err_inval!(FnAbiAdjustForForeignAbi(err)).into()
+            }
+        }
+    }
+}
+
 /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value.
 /// This test should be symmetric, as it is primarily about layout compatibility.
 pub(super) fn mir_assign_valid_types<'tcx>(
@@ -828,7 +849,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // because this is CTFE and the final value will be thoroughly validated anyway.
         let cleanup = match return_to_block {
             StackPopCleanup::Goto { .. } => true,
-            StackPopCleanup::None { cleanup, .. } => cleanup,
+            StackPopCleanup::Root { cleanup, .. } => cleanup,
         };
 
         if !cleanup {
@@ -853,8 +874,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // Follow the unwind edge.
             let unwind = match return_to_block {
                 StackPopCleanup::Goto { unwind, .. } => unwind,
-                StackPopCleanup::None { .. } => {
-                    panic!("Encountered StackPopCleanup::None when unwinding!")
+                StackPopCleanup::Root { .. } => {
+                    panic!("encountered StackPopCleanup::Root when unwinding!")
                 }
             };
             self.unwind_to_block(unwind)
@@ -862,7 +883,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // Follow the normal return edge.
             match return_to_block {
                 StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
-                StackPopCleanup::None { .. } => Ok(()),
+                StackPopCleanup::Root { .. } => {
+                    assert!(
+                        self.stack().is_empty(),
+                        "only the topmost frame can have StackPopCleanup::Root"
+                    );
+                    Ok(())
+                }
             }
         }
     }
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 727099848a4..23ec3875cbc 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -167,7 +167,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         args: &[OpTy<'tcx, Self::PointerTag>],
         ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
         unwind: StackPopUnwind,
-    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;
+    ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>;
 
     /// Execute `fn_val`.  It is the hook's responsibility to advance the instruction
     /// pointer as appropriate.
@@ -212,12 +212,6 @@ pub trait Machine<'mir, 'tcx>: Sized {
         right: &ImmTy<'tcx, Self::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;
 
-    /// Heap allocations via the `box` keyword.
-    fn box_alloc(
-        ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        dest: &PlaceTy<'tcx, Self::PointerTag>,
-    ) -> InterpResult<'tcx>;
-
     /// Called to read the specified `local` from the `frame`.
     /// Since reading a ZST is not actually accessing memory or locals, this is never invoked
     /// for ZST reads.
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 992cef1cb6a..3daa1d3c2b3 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -199,9 +199,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Aggregate(ref kind, ref operands) => {
                 // active_field_index is for union initialization.
                 let (dest, active_field_index) = match **kind {
-                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
+                    mir::AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => {
                         self.write_discriminant(variant_index, &dest)?;
-                        if adt_def.is_enum() {
+                        if self.tcx.adt_def(adt_did).is_enum() {
                             assert!(active_field_index.is_none());
                             (self.place_downcast(&dest, variant_index)?, None)
                         } else {
@@ -271,10 +271,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_immediate(place.to_ref(self), &dest)?;
             }
 
-            NullaryOp(mir::NullOp::Box, _) => {
-                M::box_alloc(self, &dest)?;
-            }
-
             NullaryOp(null_op, ty) => {
                 let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
                 let layout = self.layout_of(ty)?;
@@ -289,7 +285,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let val = match null_op {
                     mir::NullOp::SizeOf => layout.size.bytes(),
                     mir::NullOp::AlignOf => layout.align.abi.bytes(),
-                    mir::NullOp::Box => unreachable!(),
                 };
                 self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?;
             }
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index df177fd9679..f3910c9765d 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -1,14 +1,14 @@
 use std::borrow::Cow;
 use std::convert::TryFrom;
 
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::ty::layout::{self, LayoutOf as _, TyAndLayout};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
 use rustc_middle::ty::Instance;
 use rustc_middle::{
     mir,
     ty::{self, Ty},
 };
 use rustc_target::abi;
+use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMode};
 use rustc_target::spec::abi::Abi;
 
 use super::{
@@ -17,10 +17,6 @@ use super::{
 };
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
-    fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
-        layout::fn_can_unwind(*self.tcx, attrs, abi)
-    }
-
     pub(super) fn eval_terminator(
         &mut self,
         terminator: &mir::Terminator<'tcx>,
@@ -64,25 +60,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let old_stack = self.frame_idx();
                 let old_loc = self.frame().loc;
                 let func = self.eval_operand(func, None)?;
-                let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() {
-                    ty::FnPtr(sig) => {
-                        let caller_abi = sig.abi();
+                let args = self.eval_operands(args)?;
+
+                let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
+                let fn_sig =
+                    self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
+                let extra_args = &args[fn_sig.inputs().len()..];
+                let extra_args = self.tcx.mk_type_list(extra_args.iter().map(|arg| arg.layout.ty));
+
+                let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
+                    ty::FnPtr(_sig) => {
                         let fn_ptr = self.read_pointer(&func)?;
                         let fn_val = self.memory.get_fn(fn_ptr)?;
-                        (
-                            fn_val,
-                            caller_abi,
-                            self.fn_can_unwind(CodegenFnAttrFlags::empty(), caller_abi),
-                        )
+                        (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false)
                     }
                     ty::FnDef(def_id, substs) => {
-                        let sig = func.layout.ty.fn_sig(*self.tcx);
+                        let instance =
+                            self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?;
                         (
-                            FnVal::Instance(
-                                self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?,
-                            ),
-                            sig.abi(),
-                            self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()),
+                            FnVal::Instance(instance),
+                            self.fn_abi_of_instance(instance, extra_args)?,
+                            instance.def.requires_caller_location(*self.tcx),
                         )
                     }
                     _ => span_bug!(
@@ -91,7 +89,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         func.layout.ty
                     ),
                 };
-                let args = self.eval_operands(args)?;
+
                 let dest_place;
                 let ret = match destination {
                     Some((dest, ret)) => {
@@ -102,10 +100,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 };
                 self.eval_fn_call(
                     fn_val,
-                    abi,
+                    (fn_sig.abi, fn_abi),
                     &args,
+                    with_caller_location,
                     ret,
-                    match (cleanup, caller_can_unwind) {
+                    match (cleanup, fn_abi.can_unwind) {
                         (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
                         (None, true) => StackPopUnwind::Skip,
                         (_, false) => StackPopUnwind::NotAllowed,
@@ -174,68 +173,128 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     fn check_argument_compat(
-        rust_abi: bool,
-        caller: TyAndLayout<'tcx>,
-        callee: TyAndLayout<'tcx>,
+        caller_abi: &ArgAbi<'tcx, Ty<'tcx>>,
+        callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
     ) -> bool {
-        if caller.ty == callee.ty {
-            // No question
+        // Heuristic for type comparison.
+        let layout_compat = || {
+            if caller_abi.layout.ty == callee_abi.layout.ty {
+                // No question
+                return true;
+            }
+            // Compare layout
+            match (caller_abi.layout.abi, callee_abi.layout.abi) {
+                // Different valid ranges are okay (once we enforce validity,
+                // that will take care to make it UB to leave the range, just
+                // like for transmute).
+                (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => {
+                    caller.value == callee.value
+                }
+                (
+                    abi::Abi::ScalarPair(caller1, caller2),
+                    abi::Abi::ScalarPair(callee1, callee2),
+                ) => caller1.value == callee1.value && caller2.value == callee2.value,
+                // Be conservative
+                _ => false,
+            }
+        };
+        // Padding must be fully equal.
+        let pad_compat = || caller_abi.pad == callee_abi.pad;
+        // When comparing the PassMode, we have to be smart about comparing the attributes.
+        let arg_attr_compat = |a1: ArgAttributes, a2: ArgAttributes| {
+            // There's only one regular attribute that matters for the call ABI: InReg.
+            // Everything else is things like noalias, dereferencable, nonnull, ...
+            // (This also applies to pointee_size, pointee_align.)
+            if a1.regular.contains(ArgAttribute::InReg) != a2.regular.contains(ArgAttribute::InReg)
+            {
+                return false;
+            }
+            // We also compare the sign extension mode -- this could let the callee make assumptions
+            // about bits that conceptually were not even passed.
+            if a1.arg_ext != a2.arg_ext {
+                return false;
+            }
             return true;
-        }
-        if !rust_abi {
-            // Don't risk anything
-            return false;
-        }
-        // Compare layout
-        match (caller.abi, callee.abi) {
-            // Different valid ranges are okay (once we enforce validity,
-            // that will take care to make it UB to leave the range, just
-            // like for transmute).
-            (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => caller.value == callee.value,
-            (abi::Abi::ScalarPair(caller1, caller2), abi::Abi::ScalarPair(callee1, callee2)) => {
-                caller1.value == callee1.value && caller2.value == callee2.value
+        };
+        let mode_compat = || match (caller_abi.mode, callee_abi.mode) {
+            (PassMode::Ignore, PassMode::Ignore) => true,
+            (PassMode::Direct(a1), PassMode::Direct(a2)) => arg_attr_compat(a1, a2),
+            (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => {
+                arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2)
             }
-            // Be conservative
+            (PassMode::Cast(c1), PassMode::Cast(c2)) => c1 == c2,
+            (
+                PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 },
+                PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 },
+            ) => arg_attr_compat(a1, a2) && s1 == s2,
+            (
+                PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 },
+                PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 },
+            ) => arg_attr_compat(a1, a2) && arg_attr_compat(e1, e2) && s1 == s2,
             _ => false,
+        };
+
+        if layout_compat() && pad_compat() && mode_compat() {
+            return true;
         }
+        trace!(
+            "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}",
+            caller_abi,
+            callee_abi
+        );
+        return false;
     }
 
-    /// Pass a single argument, checking the types for compatibility.
-    fn pass_argument(
+    /// Initialize a single callee argument, checking the types for compatibility.
+    fn pass_argument<'x, 'y>(
         &mut self,
-        rust_abi: bool,
-        caller_arg: &mut impl Iterator<Item = OpTy<'tcx, M::PointerTag>>,
+        caller_args: &mut impl Iterator<
+            Item = (&'x OpTy<'tcx, M::PointerTag>, &'y ArgAbi<'tcx, Ty<'tcx>>),
+        >,
+        callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
         callee_arg: &PlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx> {
-        if rust_abi && callee_arg.layout.is_zst() {
-            // Nothing to do.
-            trace!("Skipping callee ZST");
+    ) -> InterpResult<'tcx>
+    where
+        'tcx: 'x,
+        'tcx: 'y,
+    {
+        if matches!(callee_abi.mode, PassMode::Ignore) {
+            // This one is skipped.
             return Ok(());
         }
-        let caller_arg = caller_arg.next().ok_or_else(|| {
+        // Find next caller arg.
+        let (caller_arg, caller_abi) = caller_args.next().ok_or_else(|| {
             err_ub_format!("calling a function with fewer arguments than it requires")
         })?;
-        if rust_abi {
-            assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
-        }
         // Now, check
-        if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) {
+        if !Self::check_argument_compat(caller_abi, callee_abi) {
             throw_ub_format!(
                 "calling a function with argument of type {:?} passing data of type {:?}",
                 callee_arg.layout.ty,
                 caller_arg.layout.ty
             )
         }
-        // We allow some transmutes here
+        // We allow some transmutes here.
+        // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This
+        // is true for all `copy_op`, but there are a lot of special cases for argument passing
+        // specifically.)
         self.copy_op_transmute(&caller_arg, callee_arg)
     }
 
     /// Call this function -- pushing the stack frame and initializing the arguments.
+    ///
+    /// `caller_fn_abi` is used to determine if all the arguments are passed the proper way.
+    /// However, we also need `caller_abi` to determine if we need to do untupling of arguments.
+    ///
+    /// `with_caller_location` indicates whether the caller passed a caller location. Miri
+    /// implements caller locations without argument passing, but to match `FnAbi` we need to know
+    /// when those arguments are present.
     pub(crate) fn eval_fn_call(
         &mut self,
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
-        caller_abi: Abi,
+        (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
         args: &[OpTy<'tcx, M::PointerTag>],
+        with_caller_location: bool,
         ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
         mut unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
@@ -248,39 +307,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         };
 
-        let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() {
-            ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
-            ty::Closure(..) => Abi::RustCall,
-            ty::Generator(..) => Abi::Rust,
-            _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
-        };
-
-        // ABI check
-        let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> {
-            let normalize_abi = |abi| match abi {
-                Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
-                // These are all the same ABI, really.
-                {
-                    Abi::Rust
-                }
-                abi => abi,
-            };
-            if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
-                throw_ub_format!(
-                    "calling a function with ABI {} using caller ABI {}",
-                    callee_abi.name(),
-                    caller_abi.name()
-                )
-            }
-            Ok(())
-        };
-
         match instance.def {
             ty::InstanceDef::Intrinsic(..) => {
-                if M::enforce_abi(self) {
-                    check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?;
-                }
                 assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
+                // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic.
                 M::call_intrinsic(self, instance, args, ret, unwind)
             }
             ty::InstanceDef::VtableShim(..)
@@ -291,26 +321,37 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | ty::InstanceDef::CloneShim(..)
             | ty::InstanceDef::Item(_) => {
                 // We need MIR for this fn
-                let body =
+                let (body, instance) =
                     match M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? {
                         Some(body) => body,
                         None => return Ok(()),
                     };
 
-                // Check against the ABI of the MIR body we are calling (not the ABI of `instance`;
-                // these can differ when `find_mir_or_eval_fn` does something clever like resolve
-                // exported symbol names).
-                let callee_def_id = body.source.def_id();
-                let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id));
+                // Compute callee information using the `instance` returned by
+                // `find_mir_or_eval_fn`.
+                // FIXME: for variadic support, do we have to somehow determine calle's extra_args?
+                let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
+
+                if callee_fn_abi.c_variadic != caller_fn_abi.c_variadic {
+                    throw_ub_format!(
+                        "calling a c-variadic function via a non-variadic call site, or vice versa"
+                    );
+                }
+                if callee_fn_abi.c_variadic {
+                    throw_unsup_format!("calling a c-variadic function is not supported");
+                }
 
                 if M::enforce_abi(self) {
-                    check_abi(callee_abi)?;
+                    if caller_fn_abi.conv != callee_fn_abi.conv {
+                        throw_ub_format!(
+                            "calling a function with calling convention {:?} using calling convention {:?}",
+                            callee_fn_abi.conv,
+                            caller_fn_abi.conv
+                        )
+                    }
                 }
 
-                if !matches!(unwind, StackPopUnwind::NotAllowed)
-                    && !self
-                        .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi)
-                {
+                if !matches!(unwind, StackPopUnwind::NotAllowed) && !callee_fn_abi.can_unwind {
                     // The callee cannot unwind.
                     unwind = StackPopUnwind::NotAllowed;
                 }
@@ -343,12 +384,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             .collect::<Vec<_>>()
                     );
 
-                    // Figure out how to pass which arguments.
-                    // The Rust ABI is special: ZST get skipped.
-                    let rust_abi = matches!(caller_abi, Abi::Rust | Abi::RustCall);
-
-                    // We have two iterators: Where the arguments come from,
-                    // and where they go to.
+                    // In principle, we have two iterators: Where the arguments come from, and where
+                    // they go to.
 
                     // For where they come from: If the ABI is RustCall, we untuple the
                     // last incoming argument.  These two iterators do not have the same type,
@@ -373,53 +410,59 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             // Plain arg passing
                             Cow::from(args)
                         };
-                    // Skip ZSTs
-                    let mut caller_iter =
-                        caller_args.iter().filter(|op| !rust_abi || !op.layout.is_zst()).copied();
+                    // If `with_caller_location` is set we pretend there is an extra argument (that
+                    // we will not pass).
+                    assert_eq!(
+                        caller_args.len() + if with_caller_location { 1 } else { 0 },
+                        caller_fn_abi.args.len(),
+                        "mismatch between caller ABI and caller arguments",
+                    );
+                    let mut caller_args = caller_args
+                        .iter()
+                        .zip(caller_fn_abi.args.iter())
+                        .filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore));
 
                     // Now we have to spread them out across the callee's locals,
                     // taking into account the `spread_arg`.  If we could write
                     // this is a single iterator (that handles `spread_arg`), then
                     // `pass_argument` would be the loop body. It takes care to
                     // not advance `caller_iter` for ZSTs.
+                    let mut callee_args_abis = callee_fn_abi.args.iter();
                     for local in body.args_iter() {
                         let dest = self.eval_place(mir::Place::from(local))?;
                         if Some(local) == body.spread_arg {
                             // Must be a tuple
                             for i in 0..dest.layout.fields.count() {
                                 let dest = self.place_field(&dest, i)?;
-                                self.pass_argument(rust_abi, &mut caller_iter, &dest)?;
+                                let callee_abi = callee_args_abis.next().unwrap();
+                                self.pass_argument(&mut caller_args, callee_abi, &dest)?;
                             }
                         } else {
                             // Normal argument
-                            self.pass_argument(rust_abi, &mut caller_iter, &dest)?;
+                            let callee_abi = callee_args_abis.next().unwrap();
+                            self.pass_argument(&mut caller_args, callee_abi, &dest)?;
                         }
                     }
-                    // Now we should have no more caller args
-                    if caller_iter.next().is_some() {
+                    // If the callee needs a caller location, pretend we consume one more argument from the ABI.
+                    if instance.def.requires_caller_location(*self.tcx) {
+                        callee_args_abis.next().unwrap();
+                    }
+                    // Now we should have no more caller args or callee arg ABIs
+                    assert!(
+                        callee_args_abis.next().is_none(),
+                        "mismatch between callee ABI and callee body arguments"
+                    );
+                    if caller_args.next().is_some() {
                         throw_ub_format!("calling a function with more arguments than it expected")
                     }
                     // Don't forget to check the return type!
-                    if let Some((caller_ret, _)) = ret {
-                        let callee_ret = self.eval_place(mir::Place::return_place())?;
-                        if !Self::check_argument_compat(
-                            rust_abi,
-                            caller_ret.layout,
-                            callee_ret.layout,
-                        ) {
-                            throw_ub_format!(
-                                "calling a function with return type {:?} passing \
-                                     return place of type {:?}",
-                                callee_ret.layout.ty,
-                                caller_ret.layout.ty
-                            )
-                        }
-                    } else {
-                        let local = mir::RETURN_PLACE;
-                        let callee_layout = self.layout_of_local(self.frame(), local, None)?;
-                        if !callee_layout.abi.is_uninhabited() {
-                            throw_ub_format!("calling a returning function without a return place")
-                        }
+                    if !Self::check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret) {
+                        throw_ub_format!(
+                            "calling a function with return type {:?} passing \
+                                    return place of type {:?}",
+                            callee_fn_abi.ret.layout.ty,
+                            caller_fn_abi.ret.layout.ty,
+                        )
                     }
                 };
                 match res {
@@ -464,7 +507,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 ));
                 trace!("Patched self operand to {:#?}", args[0]);
                 // recurse with concrete function
-                self.eval_fn_call(fn_val, caller_abi, &args, ret, unwind)
+                self.eval_fn_call(
+                    fn_val,
+                    (caller_abi, caller_fn_abi),
+                    &args,
+                    with_caller_location,
+                    ret,
+                    unwind,
+                )
             }
         }
     }
@@ -489,6 +539,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             _ => (instance, place),
         };
+        let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
 
         let arg = ImmTy::from_immediate(
             place.to_ref(self),
@@ -500,8 +551,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         self.eval_fn_call(
             FnVal::Instance(instance),
-            Abi::Rust,
+            (Abi::Rust, fn_abi),
             &[arg.into()],
+            false,
             Some((&dest.into(), target)),
             match unwind {
                 Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 6be3e19a833..5a398c2f45a 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -14,6 +14,7 @@ use rustc_middle::mir::interpret::InterpError;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_span::symbol::{sym, Symbol};
+use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange};
 
 use std::hash::Hash;
@@ -736,9 +737,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     #[inline(always)]
     fn visit_union(
         &mut self,
-        _op: &OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         _fields: NonZeroUsize,
     ) -> InterpResult<'tcx> {
+        // Special check preventing `UnsafeCell` inside unions in the inner part of constants.
+        if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) {
+            if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env) {
+                throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
+            }
+        }
         Ok(())
     }
 
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 1d5f4630152..dd749c03934 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -632,7 +632,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             }
 
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
-            Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation),
             Rvalue::ShallowInitBox(_, _) => {}
 
             Rvalue::UnaryOp(_, ref operand) => {
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 a8077b258bb..27f2da34262 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -270,7 +270,8 @@ where
         Rvalue::Aggregate(kind, operands) => {
             // Return early if we know that the struct or enum being constructed is always
             // qualified.
-            if let AggregateKind::Adt(def, _, substs, ..) = **kind {
+            if let AggregateKind::Adt(adt_did, _, substs, ..) = **kind {
+                let def = cx.tcx.adt_def(adt_did);
                 if Q::in_adt_inherently(cx, def, substs) {
                     return true;
                 }
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 1537de993d1..55fba5d7ddf 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -508,7 +508,6 @@ impl<'tcx> Validator<'_, 'tcx> {
             }
 
             Rvalue::NullaryOp(op, _) => match op {
-                NullOp::Box => return Err(Unpromotable),
                 NullOp::SizeOf => {}
                 NullOp::AlignOf => {}
             },
diff --git a/compiler/rustc_const_eval/src/util/aggregate.rs b/compiler/rustc_const_eval/src/util/aggregate.rs
index 4bc0357cab8..e5f5e7072d5 100644
--- a/compiler/rustc_const_eval/src/util/aggregate.rs
+++ b/compiler/rustc_const_eval/src/util/aggregate.rs
@@ -22,7 +22,8 @@ pub fn expand_aggregate<'tcx>(
 ) -> impl Iterator<Item = Statement<'tcx>> + TrustedLen {
     let mut set_discriminant = None;
     let active_field_index = match kind {
-        AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
+        AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => {
+            let adt_def = tcx.adt_def(adt_did);
             if adt_def.is_enum() {
                 set_discriminant = Some(Statement {
                     kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index },
diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs
index 53062b9c20d..872b0eb7854 100644
--- a/compiler/rustc_data_structures/src/sip128.rs
+++ b/compiler/rustc_data_structures/src/sip128.rs
@@ -409,6 +409,20 @@ impl SipHasher128 {
     }
 }
 
+macro_rules! dispatch_value {
+    ($target: expr, $value:expr) => {
+        let value = $value;
+        #[allow(unreachable_patterns)]
+        #[allow(overflowing_literals)]
+        match value {
+            0..=0xFF => $target.short_write(value as u8),
+            0x100..=0xFFFF => $target.short_write(value as u16),
+            0x10000..=0xFFFFFFFF => $target.short_write(value as u32),
+            _ => $target.short_write(value as u64),
+        }
+    };
+}
+
 impl Hasher for SipHasher128 {
     #[inline]
     fn write_u8(&mut self, i: u8) {
@@ -422,7 +436,7 @@ impl Hasher for SipHasher128 {
 
     #[inline]
     fn write_u32(&mut self, i: u32) {
-        self.short_write(i);
+        dispatch_value!(self, i);
     }
 
     #[inline]
@@ -452,7 +466,7 @@ impl Hasher for SipHasher128 {
 
     #[inline]
     fn write_i64(&mut self, i: i64) {
-        self.short_write(i as u64);
+        dispatch_value!(self, i as u64);
     }
 
     #[inline]
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index d87aa5ed0d5..3da35178957 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -379,9 +379,8 @@ impl<T: ?Sized + HashStable<CTX>, CTX> HashStable<CTX> for ::std::sync::Arc<T> {
 
 impl<CTX> HashStable<CTX> for str {
     #[inline]
-    fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
-        self.len().hash(hasher);
-        self.as_bytes().hash(hasher);
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        self.as_bytes().hash_stable(ctx, hasher);
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/thin_vec.rs b/compiler/rustc_data_structures/src/thin_vec.rs
index b5d2d24736c..716259142d1 100644
--- a/compiler/rustc_data_structures/src/thin_vec.rs
+++ b/compiler/rustc_data_structures/src/thin_vec.rs
@@ -5,7 +5,7 @@ use std::iter::FromIterator;
 /// A vector type optimized for cases where this size is usually 0 (cf. `SmallVec`).
 /// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
 /// which uses only a single (null) pointer.
-#[derive(Clone, Encodable, Decodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq)]
 pub struct ThinVec<T>(Option<Box<Vec<T>>>);
 
 impl<T> ThinVec<T> {
@@ -20,6 +20,13 @@ impl<T> ThinVec<T> {
     pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
         self.into_iter()
     }
+
+    pub fn push(&mut self, item: T) {
+        match *self {
+            ThinVec(Some(ref mut vec)) => vec.push(item),
+            ThinVec(None) => *self = vec![item].into(),
+        }
+    }
 }
 
 impl<T> From<Vec<T>> for ThinVec<T> {
@@ -101,10 +108,7 @@ impl<T> Extend<T> for ThinVec<T> {
     }
 
     fn extend_one(&mut self, item: T) {
-        match *self {
-            ThinVec(Some(ref mut vec)) => vec.push(item),
-            ThinVec(None) => *self = vec![item].into(),
-        }
+        self.push(item)
     }
 
     fn extend_reserve(&mut self, additional: usize) {
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index 2383a000687..872f946bf7d 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -8,10 +8,8 @@ crate-type = ["dylib"]
 
 [dependencies]
 libc = "0.2"
-atty = "0.2"
 tracing = { version = "0.1.28" }
-tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
-tracing-tree = "0.2.0"
+rustc_log = { path = "../rustc_log" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_target = { path = "../rustc_target" }
@@ -40,4 +38,4 @@ winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"]
 
 [features]
 llvm = ['rustc_interface/llvm']
-max_level_info = ['tracing/max_level_info']
+max_level_info = ['rustc_log/max_level_info']
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 12e0b7a4977..694c679c158 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -24,6 +24,7 @@ use rustc_feature::find_gated_cfg;
 use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
 use rustc_interface::{interface, Queries};
 use rustc_lint::LintStore;
+use rustc_log::stdout_isatty;
 use rustc_metadata::locator;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
@@ -514,14 +515,6 @@ impl Compilation {
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
 
-fn stdout_isatty() -> bool {
-    atty::is(atty::Stream::Stdout)
-}
-
-fn stderr_isatty() -> bool {
-    atty::is(atty::Stream::Stderr)
-}
-
 fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
     let upper_cased_code = code.to_ascii_uppercase();
     let normalised = if upper_cased_code.starts_with('E') {
@@ -1047,7 +1040,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     let wall = matches.opt_strs("W");
     if wall.iter().any(|x| *x == "all") {
         print_wall_help();
-        return None;
+        rustc_errors::FatalError.raise();
     }
 
     // Don't handle -W help here, because we might first load plugins.
@@ -1254,54 +1247,18 @@ pub fn install_ice_hook() {
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
 pub fn init_rustc_env_logger() {
-    init_env_logger("RUSTC_LOG")
+    if let Err(error) = rustc_log::init_rustc_env_logger() {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
 }
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
 /// other than `RUSTC_LOG`.
 pub fn init_env_logger(env: &str) {
-    use tracing_subscriber::{
-        filter::{self, EnvFilter, LevelFilter},
-        layer::SubscriberExt,
-    };
-
-    let filter = match std::env::var(env) {
-        Ok(env) => EnvFilter::new(env),
-        _ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)),
-    };
-
-    let color_logs = match std::env::var(String::from(env) + "_COLOR") {
-        Ok(value) => match value.as_ref() {
-            "always" => true,
-            "never" => false,
-            "auto" => stderr_isatty(),
-            _ => early_error(
-                ErrorOutputType::default(),
-                &format!(
-                    "invalid log color value '{}': expected one of always, never, or auto",
-                    value
-                ),
-            ),
-        },
-        Err(std::env::VarError::NotPresent) => stderr_isatty(),
-        Err(std::env::VarError::NotUnicode(_value)) => early_error(
-            ErrorOutputType::default(),
-            "non-Unicode log color value: expected one of always, never, or auto",
-        ),
-    };
-
-    let layer = tracing_tree::HierarchicalLayer::default()
-        .with_writer(io::stderr)
-        .with_indent_lines(true)
-        .with_ansi(color_logs)
-        .with_targets(true)
-        .with_indent_amount(2);
-    #[cfg(parallel_compiler)]
-    let layer = layer.with_thread_ids(true).with_thread_names(true);
-
-    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
-    tracing::subscriber::set_global_default(subscriber).unwrap();
+    if let Err(error) = rustc_log::init_env_logger(env) {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
 }
 
 #[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index ce26ff62235..79d9c55b547 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -120,6 +120,7 @@ E0223: include_str!("./error_codes/E0223.md"),
 E0224: include_str!("./error_codes/E0224.md"),
 E0225: include_str!("./error_codes/E0225.md"),
 E0226: include_str!("./error_codes/E0226.md"),
+E0227: include_str!("./error_codes/E0227.md"),
 E0228: include_str!("./error_codes/E0228.md"),
 E0229: include_str!("./error_codes/E0229.md"),
 E0230: include_str!("./error_codes/E0230.md"),
@@ -530,7 +531,6 @@ E0786: include_str!("./error_codes/E0786.md"),
 //  E0217, // ambiguous associated type, defined in multiple supertraits
 //  E0218, // no associated type defined
 //  E0219, // associated type defined in higher-ranked supertrait
-    E0227, // ambiguous lifetime bound, explicit lifetime bound required
 //  E0233,
 //  E0234,
 //  E0235, // structure constructor specifies a structure of type but
diff --git a/compiler/rustc_error_codes/src/error_codes/E0227.md b/compiler/rustc_error_codes/src/error_codes/E0227.md
new file mode 100644
index 00000000000..f68614723d4
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0227.md
@@ -0,0 +1,33 @@
+This error indicates that the compiler is unable to determine whether there is
+exactly one unique region in the set of derived region bounds.
+
+Example of erroneous code:
+
+```compile_fail,E0227
+trait Foo<'foo>: 'foo {}
+trait Bar<'bar>: 'bar {}
+
+trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {}
+
+struct Baz<'foo, 'bar> {
+    baz: dyn FooBar<'foo, 'bar>,
+}
+```
+
+Here, `baz` can have either `'foo` or `'bar` lifetimes.
+
+To resolve this error, provide an explicit lifetime:
+
+```rust
+trait Foo<'foo>: 'foo {}
+trait Bar<'bar>: 'bar {}
+
+trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {}
+
+struct Baz<'foo, 'bar, 'baz>
+where
+    'baz: 'foo + 'bar,
+{
+    obj: dyn FooBar<'foo, 'bar> + 'baz,
+}
+```
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index ba675daac41..7f49f80a843 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -377,6 +377,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             dir_path,
         });
         let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate();
+        assert_eq!(krate.id, ast::CRATE_NODE_ID);
         self.cx.trace_macros_diag();
         krate
     }
@@ -1160,13 +1161,19 @@ macro_rules! assign_id {
 
 impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn visit_crate(&mut self, krate: &mut ast::Crate) {
-        let span = krate.span;
-        let empty_crate =
-            || ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None };
-        let mut fold_crate = |krate: ast::Crate| {
+        visit_clobber(krate, |krate| {
+            let span = krate.span;
             let mut krate = match self.configure(krate) {
                 Some(krate) => krate,
-                None => return empty_crate(),
+                None => {
+                    return ast::Crate {
+                        attrs: Vec::new(),
+                        items: Vec::new(),
+                        span,
+                        id: self.cx.resolver.next_node_id(),
+                        is_placeholder: false,
+                    };
+                }
             };
 
             if let Some(attr) = self.take_first_attr(&mut krate) {
@@ -1175,12 +1182,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     .make_crate();
             }
 
-            noop_visit_crate(&mut krate, self);
+            assign_id!(self, &mut krate.id, || noop_visit_crate(&mut krate, self));
             krate
-        };
-
-        // Cannot use `visit_clobber` here, see the FIXME on it.
-        *krate = fold_crate(mem::replace(krate, empty_crate()));
+        })
     }
 
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 25b3a5820e6..825af9a7b2b 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -50,7 +50,8 @@ pub fn placeholder(
             attrs: Default::default(),
             items: Default::default(),
             span,
-            is_placeholder: Some(id),
+            id,
+            is_placeholder: true,
         }),
         AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
         AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
@@ -362,8 +363,8 @@ impl MutVisitor for PlaceholderExpander {
     }
 
     fn visit_crate(&mut self, krate: &mut ast::Crate) {
-        if let Some(id) = krate.is_placeholder {
-            *krate = self.remove(id).make_crate();
+        if krate.is_placeholder {
+            *krate = self.remove(krate.id).make_crate();
         } else {
             noop_visit_crate(krate, self)
         }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 69572807e7c..d59756239d9 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1407,6 +1407,20 @@ impl fmt::Display for ConstContext {
 /// A literal.
 pub type Lit = Spanned<LitKind>;
 
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+pub enum ArrayLen {
+    Infer(HirId, Span),
+    Body(AnonConst),
+}
+
+impl ArrayLen {
+    pub fn hir_id(&self) -> HirId {
+        match self {
+            &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, body: _ }) => hir_id,
+        }
+    }
+}
+
 /// A constant (expression) that's not an item or associated item,
 /// but needs its own `DefId` for type-checking, const-eval, etc.
 /// These are usually found nested inside types (e.g., array lengths)
@@ -1756,7 +1770,7 @@ pub enum ExprKind<'hir> {
     ///
     /// E.g., `[1; 5]`. The first expression is the element
     /// to be repeated; the second is the number of times to repeat it.
-    Repeat(&'hir Expr<'hir>, AnonConst),
+    Repeat(&'hir Expr<'hir>, ArrayLen),
 
     /// A suspension point for generators (i.e., `yield <expr>`).
     Yield(&'hir Expr<'hir>, YieldSource),
@@ -2266,7 +2280,7 @@ pub enum TyKind<'hir> {
     /// A variable length slice (i.e., `[T]`).
     Slice(&'hir Ty<'hir>),
     /// A fixed length array (i.e., `[T; n]`).
-    Array(&'hir Ty<'hir>, AnonConst),
+    Array(&'hir Ty<'hir>, ArrayLen),
     /// A raw pointer (i.e., `*const T` or `*mut T`).
     Ptr(MutTy<'hir>),
     /// A reference (i.e., `&'a T` or `&'a mut T`).
@@ -2484,7 +2498,7 @@ impl FnRetTy<'_> {
     }
 }
 
-#[derive(Encodable, Debug)]
+#[derive(Encodable, Debug, HashStable_Generic)]
 pub struct Mod<'hir> {
     /// A span from the first token past `{` to the last token until `}`.
     /// For `mod foo;`, the inner span ranges from the first token
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 0fab7cbfeea..d0eee422202 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -383,6 +383,9 @@ pub trait Visitor<'v>: Sized {
     fn visit_pat(&mut self, p: &'v Pat<'v>) {
         walk_pat(self, p)
     }
+    fn visit_array_length(&mut self, len: &'v ArrayLen) {
+        walk_array_len(self, len)
+    }
     fn visit_anon_const(&mut self, c: &'v AnonConst) {
         walk_anon_const(self, c)
     }
@@ -753,7 +756,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
         }
         TyKind::Array(ref ty, ref length) => {
             visitor.visit_ty(ty);
-            visitor.visit_anon_const(length)
+            visitor.visit_array_length(length)
         }
         TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
             for bound in bounds {
@@ -1124,6 +1127,13 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
     }
 }
 
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
+    match len {
+        &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
+        ArrayLen::Body(c) => visitor.visit_anon_const(c),
+    }
+}
+
 pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
     visitor.visit_id(constant.hir_id);
     visitor.visit_nested_body(constant.body);
@@ -1147,7 +1157,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
         ExprKind::Repeat(ref element, ref count) => {
             visitor.visit_expr(element);
-            visitor.visit_anon_const(count)
+            visitor.visit_array_length(count)
         }
         ExprKind::Struct(ref qpath, fields, ref optional_base) => {
             visitor.visit_qpath(qpath, expression.hir_id, expression.span);
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index c8d729a999e..a43c1f9d9ae 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -2,7 +2,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas
 
 use crate::hir::{
     AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item,
-    ItemId, Mod, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind,
+    ItemId, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind,
 };
 use crate::hir_id::{HirId, ItemLocalId};
 use rustc_span::def_id::DefPathHash;
@@ -16,7 +16,6 @@ pub trait HashStableContext:
     fn hash_hir_id(&mut self, _: HirId, hasher: &mut StableHasher);
     fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher);
     fn hash_reference_to_item(&mut self, _: HirId, hasher: &mut StableHasher);
-    fn hash_hir_mod(&mut self, _: &Mod<'_>, hasher: &mut StableHasher);
     fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher);
     fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
     fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
@@ -132,12 +131,6 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItemId {
     }
 }
 
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Mod<'_> {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_hir_mod(self, hasher)
-    }
-}
-
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Expr<'_> {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         hcx.hash_hir_expr(self, hasher)
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 2f5f158856f..4c9e2d7fe42 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -358,7 +358,7 @@ impl<'a> State<'a> {
                 self.word("[");
                 self.print_type(&ty);
                 self.word("; ");
-                self.print_anon_const(length);
+                self.print_array_length(length);
                 self.word("]");
             }
             hir::TyKind::Typeof(ref e) => {
@@ -1065,6 +1065,13 @@ impl<'a> State<'a> {
         self.print_else(elseopt)
     }
 
+    pub fn print_array_length(&mut self, len: &hir::ArrayLen) {
+        match len {
+            hir::ArrayLen::Infer(_, _) => self.word("_"),
+            hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
+        }
+    }
+
     pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
         self.ann.nested(self, Nested::Body(constant.body))
     }
@@ -1140,12 +1147,12 @@ impl<'a> State<'a> {
         self.end()
     }
 
-    fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
+    fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) {
         self.ibox(INDENT_UNIT);
         self.word("[");
         self.print_expr(element);
         self.word_space(";");
-        self.print_anon_const(count);
+        self.print_array_length(count);
         self.word("]");
         self.end()
     }
@@ -1874,7 +1881,11 @@ impl<'a> State<'a> {
             PatKind::Struct(ref qpath, ref fields, etc) => {
                 self.print_qpath(qpath, true);
                 self.nbsp();
-                self.word_space("{");
+                self.word("{");
+                let empty = fields.is_empty() && !etc;
+                if !empty {
+                    self.space();
+                }
                 self.commasep_cmnt(
                     Consistent,
                     &fields,
@@ -1895,7 +1906,9 @@ impl<'a> State<'a> {
                     }
                     self.word("..");
                 }
-                self.space();
+                if !empty {
+                    self.space();
+                }
                 self.word("}");
             }
             PatKind::Or(ref pats) => {
@@ -1948,7 +1961,6 @@ impl<'a> State<'a> {
             PatKind::Range(ref begin, ref end, ref end_kind) => {
                 if let Some(expr) = begin {
                     self.print_expr(expr);
-                    self.space();
                 }
                 match *end_kind {
                     RangeEnd::Included => self.word("..."),
@@ -2327,10 +2339,7 @@ impl<'a> State<'a> {
         arg_names: &[Ident],
     ) {
         self.ibox(INDENT_UNIT);
-        if !generic_params.is_empty() {
-            self.word("for");
-            self.print_generic_params(generic_params);
-        }
+        self.print_formal_generic_params(generic_params);
         let generics = hir::Generics {
             params: &[],
             where_clause: hir::WhereClause { predicates: &[], span: rustc_span::DUMMY_SP },
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 7ac00b4609a..88795679943 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -9,6 +9,13 @@
 //! - `#[rustc_clean(cfg="rev2")]` same as above, except that the
 //!   fingerprints must be the SAME (along with all other fingerprints).
 //!
+//! - `#[rustc_clean(cfg="rev2", loaded_from_disk='typeck")]` asserts that
+//!   the query result for `DepNode::typeck(X)` was actually
+//!   loaded from disk (not just marked green). This can be useful
+//!   to ensure that a test is actually exercising the deserialization
+//!   logic for a particular query result. This can be combined with
+//!   `except`
+//!
 //! Errors are reported if we are in the suitable configuration but
 //! the required condition is not met.
 
@@ -28,6 +35,7 @@ use rustc_span::Span;
 use std::iter::FromIterator;
 use std::vec::Vec;
 
+const LOADED_FROM_DISK: Symbol = sym::loaded_from_disk;
 const EXCEPT: Symbol = sym::except;
 const CFG: Symbol = sym::cfg;
 
@@ -124,6 +132,7 @@ type Labels = FxHashSet<String>;
 struct Assertion {
     clean: Labels,
     dirty: Labels,
+    loaded_from_disk: Labels,
 }
 
 pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
@@ -174,6 +183,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
     fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion {
         let (name, mut auto) = self.auto_labels(item_id, attr);
         let except = self.except(attr);
+        let loaded_from_disk = self.loaded_from_disk(attr);
         for e in except.iter() {
             if !auto.remove(e) {
                 let msg = format!(
@@ -183,7 +193,19 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
                 self.tcx.sess.span_fatal(attr.span, &msg);
             }
         }
-        Assertion { clean: auto, dirty: except }
+        Assertion { clean: auto, dirty: except, loaded_from_disk }
+    }
+
+    /// `loaded_from_disk=` attribute value
+    fn loaded_from_disk(&self, attr: &Attribute) -> Labels {
+        for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
+            if item.has_name(LOADED_FROM_DISK) {
+                let value = expect_associated_value(self.tcx, &item);
+                return self.resolve_labels(&item, value);
+            }
+        }
+        // If `loaded_from_disk=` is not specified, don't assert anything
+        Labels::default()
     }
 
     /// `except=` attribute value
@@ -332,6 +354,18 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
         }
     }
 
+    fn assert_loaded_from_disk(&self, item_span: Span, dep_node: DepNode) {
+        debug!("assert_loaded_from_disk({:?})", dep_node);
+
+        if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) {
+            let dep_node_str = self.dep_node_str(&dep_node);
+            self.tcx.sess.span_err(
+                item_span,
+                &format!("`{}` should have been loaded from disk but it was not", dep_node_str),
+            );
+        }
+    }
+
     fn check_item(&mut self, item_id: LocalDefId, item_span: Span) {
         let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
         for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() {
@@ -348,6 +382,10 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
                 let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
                 self.assert_dirty(item_span, dep_node);
             }
+            for label in assertion.loaded_from_disk {
+                let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
+                self.assert_loaded_from_disk(item_span, dep_node);
+            }
         }
     }
 }
@@ -382,7 +420,7 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
             let value = expect_associated_value(tcx, &item);
             debug!("check_config: searching for cfg {:?}", value);
             cfg = Some(config.contains(&(value, None)));
-        } else if !item.has_name(EXCEPT) {
+        } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) {
             tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty()));
         }
     }
diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml
index b984a1321e0..89419bfce6f 100644
--- a/compiler/rustc_index/Cargo.toml
+++ b/compiler/rustc_index/Cargo.toml
@@ -10,3 +10,4 @@ doctest = false
 arrayvec = { version = "0.7", default-features = false }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_macros = { path = "../rustc_macros" }
+smallvec = "1"
diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs
new file mode 100644
index 00000000000..6da95053b11
--- /dev/null
+++ b/compiler/rustc_index/src/interval.rs
@@ -0,0 +1,269 @@
+use std::iter::Step;
+use std::marker::PhantomData;
+use std::ops::Bound;
+use std::ops::RangeBounds;
+
+use crate::vec::Idx;
+use crate::vec::IndexVec;
+use smallvec::SmallVec;
+
+#[cfg(test)]
+mod tests;
+
+/// Stores a set of intervals on the indices.
+#[derive(Debug, Clone)]
+pub struct IntervalSet<I> {
+    // Start, end
+    map: SmallVec<[(u32, u32); 4]>,
+    domain: usize,
+    _data: PhantomData<I>,
+}
+
+#[inline]
+fn inclusive_start<T: Idx>(range: impl RangeBounds<T>) -> u32 {
+    match range.start_bound() {
+        Bound::Included(start) => start.index() as u32,
+        Bound::Excluded(start) => start.index() as u32 + 1,
+        Bound::Unbounded => 0,
+    }
+}
+
+#[inline]
+fn inclusive_end<T: Idx>(domain: usize, range: impl RangeBounds<T>) -> Option<u32> {
+    let end = match range.end_bound() {
+        Bound::Included(end) => end.index() as u32,
+        Bound::Excluded(end) => end.index().checked_sub(1)? as u32,
+        Bound::Unbounded => domain.checked_sub(1)? as u32,
+    };
+    Some(end)
+}
+
+impl<I: Idx> IntervalSet<I> {
+    pub fn new(domain: usize) -> IntervalSet<I> {
+        IntervalSet { map: SmallVec::new(), domain, _data: PhantomData }
+    }
+
+    pub fn clear(&mut self) {
+        self.map.clear();
+    }
+
+    pub fn iter(&self) -> impl Iterator<Item = I> + '_
+    where
+        I: Step,
+    {
+        self.iter_intervals().flatten()
+    }
+
+    /// Iterates through intervals stored in the set, in order.
+    pub fn iter_intervals(&self) -> impl Iterator<Item = std::ops::Range<I>> + '_
+    where
+        I: Step,
+    {
+        self.map.iter().map(|&(start, end)| I::new(start as usize)..I::new(end as usize + 1))
+    }
+
+    /// Returns true if we increased the number of elements present.
+    pub fn insert(&mut self, point: I) -> bool {
+        self.insert_range(point..=point)
+    }
+
+    /// Returns true if we increased the number of elements present.
+    pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
+        let start = inclusive_start(range.clone());
+        let Some(mut end) = inclusive_end(self.domain, range) else {
+            // empty range
+            return false;
+        };
+        if start > end {
+            return false;
+        }
+
+        loop {
+            // This condition looks a bit weird, but actually makes sense.
+            //
+            // if r.0 == end + 1, then we're actually adjacent, so we want to
+            // continue to the next range. We're looking here for the first
+            // range which starts *non-adjacently* to our end.
+            let next = self.map.partition_point(|r| r.0 <= end + 1);
+            if let Some(last) = next.checked_sub(1) {
+                let (prev_start, prev_end) = &mut self.map[last];
+                if *prev_end + 1 >= start {
+                    // If the start for the inserted range is adjacent to the
+                    // end of the previous, we can extend the previous range.
+                    if start < *prev_start {
+                        // Our range starts before the one we found. We'll need
+                        // to *remove* it, and then try again.
+                        //
+                        // FIXME: This is not so efficient; we may need to
+                        // recurse a bunch of times here. Instead, it's probably
+                        // better to do something like drain_filter(...) on the
+                        // map to be able to delete or modify all the ranges in
+                        // start..=end and then potentially re-insert a new
+                        // range.
+                        end = std::cmp::max(end, *prev_end);
+                        self.map.remove(last);
+                    } else {
+                        // We overlap with the previous range, increase it to
+                        // include us.
+                        //
+                        // Make sure we're actually going to *increase* it though --
+                        // it may be that end is just inside the previously existing
+                        // set.
+                        return if end > *prev_end {
+                            *prev_end = end;
+                            true
+                        } else {
+                            false
+                        };
+                    }
+                } else {
+                    // Otherwise, we don't overlap, so just insert
+                    self.map.insert(last + 1, (start, end));
+                    return true;
+                }
+            } else {
+                if self.map.is_empty() {
+                    // Quite common in practice, and expensive to call memcpy
+                    // with length zero.
+                    self.map.push((start, end));
+                } else {
+                    self.map.insert(next, (start, end));
+                }
+                return true;
+            }
+        }
+    }
+
+    pub fn contains(&self, needle: I) -> bool {
+        let needle = needle.index() as u32;
+        let last = match self.map.partition_point(|r| r.0 <= needle).checked_sub(1) {
+            Some(idx) => idx,
+            None => {
+                // All ranges in the map start after the new range's end
+                return false;
+            }
+        };
+        let (_, prev_end) = &self.map[last];
+        needle <= *prev_end
+    }
+
+    pub fn superset(&self, other: &IntervalSet<I>) -> bool
+    where
+        I: Step,
+    {
+        // FIXME: Performance here is probably not great. We will be doing a lot
+        // of pointless tree traversals.
+        other.iter().all(|elem| self.contains(elem))
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.map.is_empty()
+    }
+
+    /// Returns the maximum (last) element present in the set from `range`.
+    pub fn last_set_in(&self, range: impl RangeBounds<I> + Clone) -> Option<I> {
+        let start = inclusive_start(range.clone());
+        let Some(end) = inclusive_end(self.domain, range) else {
+            // empty range
+            return None;
+        };
+        if start > end {
+            return None;
+        }
+        let last = match self.map.partition_point(|r| r.0 <= end).checked_sub(1) {
+            Some(idx) => idx,
+            None => {
+                // All ranges in the map start after the new range's end
+                return None;
+            }
+        };
+        let (_, prev_end) = &self.map[last];
+        if start <= *prev_end { Some(I::new(std::cmp::min(*prev_end, end) as usize)) } else { None }
+    }
+
+    pub fn insert_all(&mut self) {
+        self.clear();
+        self.map.push((0, self.domain.try_into().unwrap()));
+    }
+
+    pub fn union(&mut self, other: &IntervalSet<I>) -> bool
+    where
+        I: Step,
+    {
+        assert_eq!(self.domain, other.domain);
+        let mut did_insert = false;
+        for range in other.iter_intervals() {
+            did_insert |= self.insert_range(range);
+        }
+        did_insert
+    }
+}
+
+/// This data structure optimizes for cases where the stored bits in each row
+/// are expected to be highly contiguous (long ranges of 1s or 0s), in contrast
+/// to BitMatrix and SparseBitMatrix which are optimized for
+/// "random"/non-contiguous bits and cheap(er) point queries at the expense of
+/// memory usage.
+#[derive(Clone)]
+pub struct SparseIntervalMatrix<R, C>
+where
+    R: Idx,
+    C: Idx,
+{
+    rows: IndexVec<R, IntervalSet<C>>,
+    column_size: usize,
+}
+
+impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> {
+    pub fn new(column_size: usize) -> SparseIntervalMatrix<R, C> {
+        SparseIntervalMatrix { rows: IndexVec::new(), column_size }
+    }
+
+    pub fn rows(&self) -> impl Iterator<Item = R> {
+        self.rows.indices()
+    }
+
+    pub fn row(&self, row: R) -> Option<&IntervalSet<C>> {
+        self.rows.get(row)
+    }
+
+    fn ensure_row(&mut self, row: R) -> &mut IntervalSet<C> {
+        self.rows.ensure_contains_elem(row, || IntervalSet::new(self.column_size));
+        &mut self.rows[row]
+    }
+
+    pub fn union_row(&mut self, row: R, from: &IntervalSet<C>) -> bool
+    where
+        C: Step,
+    {
+        self.ensure_row(row).union(from)
+    }
+
+    pub fn union_rows(&mut self, read: R, write: R) -> bool
+    where
+        C: Step,
+    {
+        if read == write || self.rows.get(read).is_none() {
+            return false;
+        }
+        self.ensure_row(write);
+        let (read_row, write_row) = self.rows.pick2_mut(read, write);
+        write_row.union(read_row)
+    }
+
+    pub fn insert_all_into_row(&mut self, row: R) {
+        self.ensure_row(row).insert_all();
+    }
+
+    pub fn insert_range(&mut self, row: R, range: impl RangeBounds<C> + Clone) {
+        self.ensure_row(row).insert_range(range);
+    }
+
+    pub fn insert(&mut self, row: R, point: C) -> bool {
+        self.ensure_row(row).insert(point)
+    }
+
+    pub fn contains(&self, row: R, point: C) -> bool {
+        self.row(row).map_or(false, |r| r.contains(point))
+    }
+}
diff --git a/compiler/rustc_index/src/interval/tests.rs b/compiler/rustc_index/src/interval/tests.rs
new file mode 100644
index 00000000000..d90b449f326
--- /dev/null
+++ b/compiler/rustc_index/src/interval/tests.rs
@@ -0,0 +1,199 @@
+use super::*;
+
+#[test]
+fn insert_collapses() {
+    let mut set = IntervalSet::<u32>::new(3000);
+    set.insert_range(9831..=9837);
+    set.insert_range(43..=9830);
+    assert_eq!(set.iter_intervals().collect::<Vec<_>>(), [43..9838]);
+}
+
+#[test]
+fn contains() {
+    let mut set = IntervalSet::new(300);
+    set.insert(0u32);
+    assert!(set.contains(0));
+    set.insert_range(0..10);
+    assert!(set.contains(9));
+    assert!(!set.contains(10));
+    set.insert_range(10..11);
+    assert!(set.contains(10));
+}
+
+#[test]
+fn insert() {
+    for i in 0..30usize {
+        let mut set = IntervalSet::new(300);
+        for j in i..30usize {
+            set.insert(j);
+            for k in i..j {
+                assert!(set.contains(k));
+            }
+        }
+    }
+
+    let mut set = IntervalSet::new(300);
+    set.insert_range(0..1u32);
+    assert!(set.contains(0), "{:?}", set.map);
+    assert!(!set.contains(1));
+    set.insert_range(1..1);
+    assert!(set.contains(0));
+    assert!(!set.contains(1));
+
+    let mut set = IntervalSet::new(300);
+    set.insert_range(4..5u32);
+    set.insert_range(5..10);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [4, 5, 6, 7, 8, 9]);
+    set.insert_range(3..7);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [3, 4, 5, 6, 7, 8, 9]);
+
+    let mut set = IntervalSet::new(300);
+    set.insert_range(0..10u32);
+    set.insert_range(3..5);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+
+    let mut set = IntervalSet::new(300);
+    set.insert_range(0..10u32);
+    set.insert_range(0..3);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+
+    let mut set = IntervalSet::new(300);
+    set.insert_range(0..10u32);
+    set.insert_range(0..10);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+
+    let mut set = IntervalSet::new(300);
+    set.insert_range(0..10u32);
+    set.insert_range(5..10);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+
+    let mut set = IntervalSet::new(300);
+    set.insert_range(0..10u32);
+    set.insert_range(5..13);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
+}
+
+#[test]
+fn insert_range() {
+    #[track_caller]
+    fn check<R>(range: R)
+    where
+        R: RangeBounds<usize> + Clone + IntoIterator<Item = usize> + std::fmt::Debug,
+    {
+        let mut set = IntervalSet::new(300);
+        set.insert_range(range.clone());
+        for i in set.iter() {
+            assert!(range.contains(&i));
+        }
+        for i in range.clone() {
+            assert!(set.contains(i), "A: {} in {:?}, inserted {:?}", i, set, range);
+        }
+        set.insert_range(range.clone());
+        for i in set.iter() {
+            assert!(range.contains(&i), "{} in {:?}", i, set);
+        }
+        for i in range.clone() {
+            assert!(set.contains(i), "B: {} in {:?}, inserted {:?}", i, set, range);
+        }
+    }
+    check(10..10);
+    check(10..100);
+    check(10..30);
+    check(0..5);
+    check(0..250);
+    check(200..250);
+
+    check(10..=10);
+    check(10..=100);
+    check(10..=30);
+    check(0..=5);
+    check(0..=250);
+    check(200..=250);
+
+    for i in 0..30 {
+        for j in i..30 {
+            check(i..j);
+            check(i..=j);
+        }
+    }
+}
+
+#[test]
+fn insert_range_dual() {
+    let mut set = IntervalSet::<u32>::new(300);
+    set.insert_range(0..3);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2]);
+    set.insert_range(5..7);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 5, 6]);
+    set.insert_range(3..4);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 5, 6]);
+    set.insert_range(3..5);
+    assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6]);
+}
+
+#[test]
+fn last_set_before_adjacent() {
+    let mut set = IntervalSet::<u32>::new(300);
+    set.insert_range(0..3);
+    set.insert_range(3..5);
+    assert_eq!(set.last_set_in(0..3), Some(2));
+    assert_eq!(set.last_set_in(0..5), Some(4));
+    assert_eq!(set.last_set_in(3..5), Some(4));
+    set.insert_range(2..5);
+    assert_eq!(set.last_set_in(0..3), Some(2));
+    assert_eq!(set.last_set_in(0..5), Some(4));
+    assert_eq!(set.last_set_in(3..5), Some(4));
+}
+
+#[test]
+fn last_set_in() {
+    fn easy(set: &IntervalSet<usize>, needle: impl RangeBounds<usize>) -> Option<usize> {
+        let mut last_leq = None;
+        for e in set.iter() {
+            if needle.contains(&e) {
+                last_leq = Some(e);
+            }
+        }
+        last_leq
+    }
+
+    #[track_caller]
+    fn cmp(set: &IntervalSet<usize>, needle: impl RangeBounds<usize> + Clone + std::fmt::Debug) {
+        assert_eq!(
+            set.last_set_in(needle.clone()),
+            easy(set, needle.clone()),
+            "{:?} in {:?}",
+            needle,
+            set
+        );
+    }
+    let mut set = IntervalSet::new(300);
+    cmp(&set, 50..=50);
+    set.insert(64);
+    cmp(&set, 64..=64);
+    set.insert(64 - 1);
+    cmp(&set, 0..=64 - 1);
+    cmp(&set, 0..=5);
+    cmp(&set, 10..100);
+    set.insert(100);
+    cmp(&set, 100..110);
+    cmp(&set, 99..100);
+    cmp(&set, 99..=100);
+
+    for i in 0..=30 {
+        for j in i..=30 {
+            for k in 0..30 {
+                let mut set = IntervalSet::new(100);
+                cmp(&set, ..j);
+                cmp(&set, i..);
+                cmp(&set, i..j);
+                cmp(&set, i..=j);
+                set.insert(k);
+                cmp(&set, ..j);
+                cmp(&set, i..);
+                cmp(&set, i..j);
+                cmp(&set, i..=j);
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index a9efd6bb8bc..359b1859c68 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -7,6 +7,7 @@
 #![feature(let_else)]
 
 pub mod bit_set;
+pub mod interval;
 pub mod vec;
 
 // FIXME(#56935): Work around ICEs during cross-compilation.
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 5e48fbf253d..da71edbd2d9 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -572,8 +572,9 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
             // (e.g., #41849).
             relate::relate_substs(self, None, a_subst, b_subst)
         } else {
-            let opt_variances = self.tcx().variances_of(item_def_id);
-            relate::relate_substs(self, Some(&opt_variances), a_subst, b_subst)
+            let tcx = self.tcx();
+            let opt_variances = tcx.variances_of(item_def_id);
+            relate::relate_substs(self, Some((item_def_id, &opt_variances)), a_subst, b_subst)
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 9a76c05e4f6..f0c73d0c2f3 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2041,11 +2041,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
                     trace.values
                 {
-                    // If a tuple of length one was expected and the found expression has
-                    // parentheses around it, perhaps the user meant to write `(expr,)` to
-                    // build a tuple (issue #86100)
                     match (expected.kind(), found.kind()) {
                         (ty::Tuple(_), ty::Tuple(_)) => {}
+                        // If a tuple of length one was expected and the found expression has
+                        // parentheses around it, perhaps the user meant to write `(expr,)` to
+                        // build a tuple (issue #86100)
                         (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
                             if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
                                 if let Some(code) =
@@ -2060,6 +2060,41 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                 }
                             }
                         }
+                        // If a character was expected and the found expression is a string literal
+                        // containing a single character, perhaps the user meant to write `'c'` to
+                        // specify a character literal (issue #92479)
+                        (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
+                            if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+                                if let Some(code) =
+                                    code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
+                                {
+                                    if code.chars().nth(1).is_none() {
+                                        err.span_suggestion(
+                                            span,
+                                            "if you meant to write a `char` literal, use single quotes",
+                                            format!("'{}'", code),
+                                            Applicability::MachineApplicable,
+                                        );
+                                    }
+                                }
+                            }
+                        }
+                        // If a string was expected and the found expression is a character literal,
+                        // perhaps the user meant to write `"s"` to specify a string literal.
+                        (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
+                            if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+                                if let Some(code) =
+                                    code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+                                {
+                                    err.span_suggestion(
+                                        span,
+                                        "if you meant to write a `str` literal, use double quotes",
+                                        format!("\"{}\"", code),
+                                        Applicability::MachineApplicable,
+                                    );
+                                }
+                            }
+                        }
                         _ => {}
                     }
                 }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 2904b3f5b70..3804e100307 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -11,7 +11,7 @@ use rustc_errors::registry::Registry;
 use rustc_errors::{ErrorReported, Handler};
 use rustc_lint::LintStore;
 use rustc_middle::ty;
-use rustc_parse::new_parser_from_source_str;
+use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_query_impl::QueryCtxt;
 use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
 use rustc_session::early_error;
@@ -91,7 +91,6 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
                     s
                 )));
                 let filename = FileName::cfg_spec_source_code(&s);
-                let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
 
                 macro_rules! error {
                     ($reason: expr) => {
@@ -102,26 +101,27 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
                     };
                 }
 
-                match &mut parser.parse_meta_item() {
-                    Ok(meta_item) if parser.token == token::Eof => {
-                        if meta_item.path.segments.len() != 1 {
-                            error!("argument key must be an identifier");
-                        }
-                        match &meta_item.kind {
-                            MetaItemKind::List(..) => {
-                                error!(r#"expected `key` or `key="value"`"#);
-                            }
-                            MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
-                                error!("argument value must be a string");
+                match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
+                    Ok(mut parser) => match &mut parser.parse_meta_item() {
+                        Ok(meta_item) if parser.token == token::Eof => {
+                            if meta_item.path.segments.len() != 1 {
+                                error!("argument key must be an identifier");
                             }
-                            MetaItemKind::NameValue(..) | MetaItemKind::Word => {
-                                let ident = meta_item.ident().expect("multi-segment cfg key");
-                                return (ident.name, meta_item.value_str());
+                            match &meta_item.kind {
+                                MetaItemKind::List(..) => {}
+                                MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
+                                    error!("argument value must be a string");
+                                }
+                                MetaItemKind::NameValue(..) | MetaItemKind::Word => {
+                                    let ident = meta_item.ident().expect("multi-segment cfg key");
+                                    return (ident.name, meta_item.value_str());
+                                }
                             }
                         }
-                    }
-                    Ok(..) => {}
-                    Err(err) => err.cancel(),
+                        Ok(..) => {}
+                        Err(err) => err.cancel(),
+                    },
+                    Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()),
                 }
 
                 error!(r#"expected `key` or `key="value"`"#);
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index d11cc52b508..33bf670f570 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -3,7 +3,7 @@ use crate::proc_macro_decls;
 use crate::util;
 
 use rustc_ast::mut_visit::MutVisitor;
-use rustc_ast::{self as ast, visit};
+use rustc_ast::{self as ast, visit, DUMMY_NODE_ID};
 use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -323,7 +323,7 @@ pub fn configure_and_expand(
 
         let crate_attrs = krate.attrs.clone();
         let extern_mod_loaded = |ident: Ident, attrs, items, span| {
-            let krate = ast::Crate { attrs, items, span, is_placeholder: None };
+            let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false };
             pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, ident.name.as_str());
             (krate.attrs, krate.items)
         };
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index c651feaaa66..816e770f012 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -8,10 +8,11 @@ use rustc_session::config::{build_configuration, build_session_options, to_crate
 use rustc_session::config::{
     rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
 };
-use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
 use rustc_session::config::{
-    Externs, OutputType, OutputTypes, SymbolManglingVersion, WasiExecModel,
+    BranchProtection, Externs, OutputType, OutputTypes, PAuthKey, PacRet, SymbolManglingVersion,
+    WasiExecModel,
 };
+use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
@@ -593,6 +594,7 @@ fn test_codegen_options_tracking_hash() {
     tracked!(relocation_model, Some(RelocModel::Pic));
     tracked!(soft_float, true);
     tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
+    tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
     tracked!(target_cpu, Some(String::from("abc")));
     tracked!(target_feature, String::from("all the features, all of them"));
 }
@@ -717,6 +719,10 @@ fn test_debugging_options_tracking_hash() {
     tracked!(asm_comments, true);
     tracked!(assume_incomplete_release, true);
     tracked!(binary_dep_depinfo, true);
+    tracked!(
+        branch_protection,
+        BranchProtection { bti: true, pac_ret: Some(PacRet { leaf: true, key: PAuthKey::B }) }
+    );
     tracked!(chalk, true);
     tracked!(codegen_backend, Some("abc".to_string()));
     tracked!(crate_attr, vec!["abc".to_string()]);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index b04f91634cc..cb51555f5ca 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -484,7 +484,7 @@ pub(crate) fn check_attr_crate_type(
                     return;
                 }
 
-                if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().kind {
+                if let ast::MetaItemKind::NameValue(spanned) = a.meta_kind().unwrap() {
                     let span = spanned.span;
                     let lev_candidate = find_best_match_for_name(
                         &CRATE_TYPES.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 4f77db8a24d..f06fc3edf58 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -17,6 +17,7 @@
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Object/IRObjectFile.h"
 #include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/PassPlugin.h"
 #include "llvm/Passes/StandardInstrumentations.h"
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/FileSystem.h"
@@ -753,7 +754,8 @@ LLVMRustOptimizeWithNewPassManager(
     void* LlvmSelfProfiler,
     LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
     LLVMRustSelfProfileAfterPassCallback AfterPassCallback,
-    const char *ExtraPasses, size_t ExtraPassesLen) {
+    const char *ExtraPasses, size_t ExtraPassesLen,
+    const char *LLVMPlugins, size_t LLVMPluginsLen) {
   Module *TheModule = unwrap(ModuleRef);
   TargetMachine *TM = unwrap(TMRef);
   OptimizationLevel OptLevel = fromRust(OptLevelRust);
@@ -924,6 +926,20 @@ LLVMRustOptimizeWithNewPassManager(
     }
   }
 
+  if (LLVMPluginsLen) {
+    auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen);
+    SmallVector<StringRef> Plugins;
+    PluginsStr.split(Plugins, ',', -1, false);
+    for (auto PluginPath: Plugins) {
+      auto Plugin = PassPlugin::Load(PluginPath.str());
+      if (!Plugin) {
+        LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str());
+        continue;
+      }
+      Plugin->registerPassBuilderCallbacks(PB);
+    }
+  }
+
 #if LLVM_VERSION_GE(13, 0)
   ModulePassManager MPM;
 #else
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 3fbf020c552..c21e4acbefe 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -341,14 +341,12 @@ extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn,
                                                  unsigned Index,
                                                  LLVMRustAttribute RustAttr) {
   Function *F = unwrap<Function>(Fn);
-  Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr));
-  AttrBuilder B(Attr);
-  auto PAL = F->getAttributes();
+  AttributeList PAL = F->getAttributes();
   AttributeList PALNew;
 #if LLVM_VERSION_LT(14, 0)
-  PALNew = PAL.removeAttributes(F->getContext(), Index, B);
+  PALNew = PAL.removeAttribute(F->getContext(), Index, fromRust(RustAttr));
 #else
-  PALNew = PAL.removeAttributesAtIndex(F->getContext(), Index, B);
+  PALNew = PAL.removeAttributeAtIndex(F->getContext(), Index, fromRust(RustAttr));
 #endif
   F->setAttributes(PALNew);
 }
@@ -716,6 +714,14 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; }
 
 extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; }
 
+extern "C" bool LLVMRustIsRustLLVM() {
+#ifdef LLVM_RUSTLLVM
+  return true;
+#else
+  return false;
+#endif
+}
+
 extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name,
                                       uint32_t Value) {
   unwrap(M)->addModuleFlag(Module::Warning, Name, Value);
@@ -971,11 +977,11 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder,
 
 extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd(
     LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo,
-    int64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
+    uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
     LLVMBasicBlockRef InsertAtEnd) {
   return wrap(Builder->insertDeclare(
       unwrap(V), unwrap<DILocalVariable>(VarInfo),
-      Builder->createExpression(llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
+      Builder->createExpression(llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
       DebugLoc(cast<MDNode>(unwrap(DL))),
       unwrap(InsertAtEnd)));
 }
@@ -1049,11 +1055,11 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
   return wrap(Loc);
 }
 
-extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() {
   return dwarf::DW_OP_deref;
 }
 
-extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() {
   return dwarf::DW_OP_plus_uconst;
 }
 
diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml
new file mode 100644
index 00000000000..1b2cde60555
--- /dev/null
+++ b/compiler/rustc_log/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "rustc_log"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+atty = "0.2"
+tracing = "0.1.28"
+tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
+tracing-tree = "0.2.0"
+
+[dev-dependencies]
+rustc_span = { path = "../rustc_span" }
+
+[features]
+max_level_info = ['tracing/max_level_info']
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
new file mode 100644
index 00000000000..f5e7435d36e
--- /dev/null
+++ b/compiler/rustc_log/src/lib.rs
@@ -0,0 +1,115 @@
+//! This crate allows tools to enable rust logging without having to magically
+//! match rustc's tracing crate version.
+//!
+//! For example if someone is working on rustc_ast and wants to write some
+//! minimal code against it to run in a debugger, with access to the `debug!`
+//! logs emitted by rustc_ast, that can be done by writing:
+//!
+//! ```toml
+//! [dependencies]
+//! rustc_ast = { path = "../rust/compiler/rustc_ast" }
+//! rustc_log = { path = "../rust/compiler/rustc_log" }
+//! rustc_span = { path = "../rust/compiler/rustc_span" }
+//! ```
+//!
+//! ```
+//! fn main() {
+//!     rustc_log::init_rustc_env_logger().unwrap();
+//!
+//!     let edition = rustc_span::edition::Edition::Edition2021;
+//!     rustc_span::create_session_globals_then(edition, || {
+//!         /* ... */
+//!     });
+//! }
+//! ```
+//!
+//! Now `RUSTC_LOG=debug cargo run` will run your minimal main.rs and show
+//! rustc's debug logging. In a workflow like this, one might also add
+//! `std::env::set_var("RUSTC_LOG", "debug")` to the top of main so that `cargo
+//! run` by itself is sufficient to get logs.
+//!
+//! The reason rustc_log is a tiny separate crate, as opposed to exposing the
+//! same things in rustc_driver only, is to enable the above workflow. If you
+//! had to depend on rustc_driver in order to turn on rustc's debug logs, that's
+//! an enormously bigger dependency tree; every change you make to rustc_ast (or
+//! whichever piece of the compiler you are interested in) would involve
+//! rebuilding all the rest of rustc up to rustc_driver in order to run your
+//! main.rs. Whereas by depending only on rustc_log and the few crates you are
+//! debugging, you can make changes inside those crates and quickly run main.rs
+//! to read the debug logs.
+
+use std::env::{self, VarError};
+use std::fmt::{self, Display};
+use std::io;
+use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
+use tracing_subscriber::layer::SubscriberExt;
+
+pub fn init_rustc_env_logger() -> Result<(), Error> {
+    init_env_logger("RUSTC_LOG")
+}
+
+/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
+/// other than `RUSTC_LOG`.
+pub fn init_env_logger(env: &str) -> Result<(), Error> {
+    let filter = match env::var(env) {
+        Ok(env) => EnvFilter::new(env),
+        _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
+    };
+
+    let color_logs = match env::var(String::from(env) + "_COLOR") {
+        Ok(value) => match value.as_ref() {
+            "always" => true,
+            "never" => false,
+            "auto" => stderr_isatty(),
+            _ => return Err(Error::InvalidColorValue(value)),
+        },
+        Err(VarError::NotPresent) => stderr_isatty(),
+        Err(VarError::NotUnicode(_value)) => return Err(Error::NonUnicodeColorValue),
+    };
+
+    let layer = tracing_tree::HierarchicalLayer::default()
+        .with_writer(io::stderr)
+        .with_indent_lines(true)
+        .with_ansi(color_logs)
+        .with_targets(true)
+        .with_indent_amount(2);
+    #[cfg(parallel_compiler)]
+    let layer = layer.with_thread_ids(true).with_thread_names(true);
+
+    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
+    tracing::subscriber::set_global_default(subscriber).unwrap();
+
+    Ok(())
+}
+
+pub fn stdout_isatty() -> bool {
+    atty::is(atty::Stream::Stdout)
+}
+
+pub fn stderr_isatty() -> bool {
+    atty::is(atty::Stream::Stderr)
+}
+
+#[derive(Debug)]
+pub enum Error {
+    InvalidColorValue(String),
+    NonUnicodeColorValue,
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::InvalidColorValue(value) => write!(
+                formatter,
+                "invalid log color value '{}': expected one of always, never, or auto",
+                value,
+            ),
+            Error::NonUnicodeColorValue => write!(
+                formatter,
+                "non-Unicode log color value: expected one of always, never, or auto",
+            ),
+        }
+    }
+}
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 66e6b571beb..3351564299c 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -1,6 +1,7 @@
 use proc_macro2::TokenStream;
-use quote::quote;
+use quote::{quote, quote_spanned};
 use syn::parse_quote;
+use syn::spanned::Spanned;
 
 pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
     let decoder_ty = quote! { __D };
@@ -104,6 +105,8 @@ fn decodable_body(
 }
 
 fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro2::TokenStream {
+    let field_span = field.ident.as_ref().map_or(field.ty.span(), |ident| ident.span());
+
     let decode_inner_method = if let syn::Type::Reference(_) = field.ty {
         quote! { ::rustc_middle::ty::codec::RefDecodable::decode }
     } else {
@@ -111,20 +114,21 @@ fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro
     };
     let (decode_method, opt_field_name) = if is_struct {
         let field_name = field.ident.as_ref().map_or_else(|| index.to_string(), |i| i.to_string());
-        (
-            proc_macro2::Ident::new("read_struct_field", proc_macro2::Span::call_site()),
-            quote! { #field_name, },
-        )
+        (proc_macro2::Ident::new("read_struct_field", field_span), quote! { #field_name, })
     } else {
-        (
-            proc_macro2::Ident::new("read_enum_variant_arg", proc_macro2::Span::call_site()),
-            quote! {},
-        )
+        (proc_macro2::Ident::new("read_enum_variant_arg", field_span), quote! {})
+    };
+
+    let __decoder = quote! { __decoder };
+    // Use the span of the field for the method call, so
+    // that backtraces will point to the field.
+    let decode_call = quote_spanned! {field_span=>
+        ::rustc_serialize::Decoder::#decode_method(
+                #__decoder, #opt_field_name #decode_inner_method)
     };
 
     quote! {
-        match ::rustc_serialize::Decoder::#decode_method(
-            __decoder, #opt_field_name #decode_inner_method) {
+        match #decode_call  {
             ::std::result::Result::Ok(__res) => __res,
             ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err),
         }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index c0da386edfd..36a1798cd6a 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -102,30 +102,23 @@ struct CrateDump<'a>(&'a CStore);
 impl<'a> std::fmt::Debug for CrateDump<'a> {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         writeln!(fmt, "resolved crates:")?;
-        // `iter_crate_data` does not allow returning values. Thus we use a mutable variable here
-        // that aggregates the value (and any errors that could happen).
-        let mut res = Ok(());
-        self.0.iter_crate_data(|cnum, data| {
-            res = res.and(
-                try {
-                    writeln!(fmt, "  name: {}", data.name())?;
-                    writeln!(fmt, "  cnum: {}", cnum)?;
-                    writeln!(fmt, "  hash: {}", data.hash())?;
-                    writeln!(fmt, "  reqd: {:?}", data.dep_kind())?;
-                    let CrateSource { dylib, rlib, rmeta } = data.source();
-                    if let Some(dylib) = dylib {
-                        writeln!(fmt, "  dylib: {}", dylib.0.display())?;
-                    }
-                    if let Some(rlib) = rlib {
-                        writeln!(fmt, "   rlib: {}", rlib.0.display())?;
-                    }
-                    if let Some(rmeta) = rmeta {
-                        writeln!(fmt, "   rmeta: {}", rmeta.0.display())?;
-                    }
-                },
-            );
-        });
-        res
+        for (cnum, data) in self.0.iter_crate_data() {
+            writeln!(fmt, "  name: {}", data.name())?;
+            writeln!(fmt, "  cnum: {}", cnum)?;
+            writeln!(fmt, "  hash: {}", data.hash())?;
+            writeln!(fmt, "  reqd: {:?}", data.dep_kind())?;
+            let CrateSource { dylib, rlib, rmeta } = data.source();
+            if let Some(dylib) = dylib {
+                writeln!(fmt, "  dylib: {}", dylib.0.display())?;
+            }
+            if let Some(rlib) = rlib {
+                writeln!(fmt, "   rlib: {}", rlib.0.display())?;
+            }
+            if let Some(rmeta) = rmeta {
+                writeln!(fmt, "   rmeta: {}", rmeta.0.display())?;
+            }
+        }
+        Ok(())
     }
 }
 
@@ -154,12 +147,10 @@ impl CStore {
         self.metas[cnum] = Some(Lrc::new(data));
     }
 
-    crate fn iter_crate_data(&self, mut f: impl FnMut(CrateNum, &CrateMetadata)) {
-        for (cnum, data) in self.metas.iter_enumerated() {
-            if let Some(data) = data {
-                f(cnum, data);
-            }
-        }
+    crate fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
+        self.metas
+            .iter_enumerated()
+            .filter_map(|(cnum, data)| data.as_ref().map(|data| (cnum, &**data)))
     }
 
     fn push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum) {
@@ -178,7 +169,9 @@ impl CStore {
     crate fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> {
         let mut deps = Vec::new();
         if cnum == LOCAL_CRATE {
-            self.iter_crate_data(|cnum, _| self.push_dependencies_in_postorder(&mut deps, cnum));
+            for (cnum, _) in self.iter_crate_data() {
+                self.push_dependencies_in_postorder(&mut deps, cnum);
+            }
         } else {
             self.push_dependencies_in_postorder(&mut deps, cnum);
         }
@@ -263,21 +256,17 @@ impl<'a> CrateLoader<'a> {
     }
 
     fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> {
-        let mut ret = None;
-        self.cstore.iter_crate_data(|cnum, data| {
+        for (cnum, data) in self.cstore.iter_crate_data() {
             if data.name() != name {
                 tracing::trace!("{} did not match {}", data.name(), name);
-                return;
+                continue;
             }
 
             match hash {
-                Some(hash) if hash == data.hash() => {
-                    ret = Some(cnum);
-                    return;
-                }
+                Some(hash) if hash == data.hash() => return Some(cnum),
                 Some(hash) => {
                     debug!("actual hash {} did not match expected {}", hash, data.hash());
-                    return;
+                    continue;
                 }
                 None => {}
             }
@@ -301,10 +290,10 @@ impl<'a> CrateLoader<'a> {
                             || source.rlib.as_ref().map(|(p, _)| p) == Some(l)
                             || source.rmeta.as_ref().map(|(p, _)| p) == Some(l)
                     }) {
-                        ret = Some(cnum);
+                        return Some(cnum);
                     }
                 }
-                return;
+                continue;
             }
 
             // Alright, so we've gotten this far which means that `data` has the
@@ -321,15 +310,16 @@ impl<'a> CrateLoader<'a> {
                 .expect("No sources for crate")
                 .1;
             if kind.matches(prev_kind) {
-                ret = Some(cnum);
+                return Some(cnum);
             } else {
                 debug!(
                     "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}",
                     name, kind, prev_kind
                 );
             }
-        });
-        ret
+        }
+
+        None
     }
 
     fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> {
@@ -339,17 +329,14 @@ impl<'a> CrateLoader<'a> {
         }
 
         // Check for conflicts with any crate loaded so far
-        let mut res = Ok(());
-        self.cstore.iter_crate_data(|_, other| {
-            if other.stable_crate_id() == root.stable_crate_id() && // same stable crate id
-               other.hash() != root.hash()
-            {
-                // but different SVH
-                res = Err(CrateError::SymbolConflictsOthers(root.name()));
+        for (_, other) in self.cstore.iter_crate_data() {
+            // Same stable crate id but different SVH
+            if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() {
+                return Err(CrateError::SymbolConflictsOthers(root.name()));
             }
-        });
+        }
 
-        res
+        Ok(())
     }
 
     fn verify_no_stable_crate_id_hash_conflicts(
@@ -607,13 +594,14 @@ impl<'a> CrateLoader<'a> {
             locator.triple == self.sess.opts.target_triple || locator.is_proc_macro;
         Ok(Some(if can_reuse_cratenum {
             let mut result = LoadResult::Loaded(library);
-            self.cstore.iter_crate_data(|cnum, data| {
+            for (cnum, data) in self.cstore.iter_crate_data() {
                 if data.name() == root.name() && root.hash() == data.hash() {
                     assert!(locator.hash.is_none());
                     info!("load success, going to previous cnum: {}", cnum);
                     result = LoadResult::Previous(cnum);
+                    break;
                 }
-            });
+            }
             result
         } else {
             LoadResult::Loaded(library)
@@ -711,7 +699,7 @@ impl<'a> CrateLoader<'a> {
         let mut needs_panic_runtime =
             self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime);
 
-        self.cstore.iter_crate_data(|cnum, data| {
+        for (cnum, data) in self.cstore.iter_crate_data() {
             needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
             if data.is_panic_runtime() {
                 // Inject a dependency from all #![needs_panic_runtime] to this
@@ -721,7 +709,7 @@ impl<'a> CrateLoader<'a> {
                 });
                 runtime_found = runtime_found || data.dep_kind() == CrateDepKind::Explicit;
             }
-        });
+        }
 
         // If an explicitly linked and matching panic runtime was found, or if
         // we just don't need one at all, then we're done here and there's
@@ -813,11 +801,9 @@ impl<'a> CrateLoader<'a> {
         // Check to see if we actually need an allocator. This desire comes
         // about through the `#![needs_allocator]` attribute and is typically
         // written down in liballoc.
-        let mut needs_allocator = self.sess.contains_name(&krate.attrs, sym::needs_allocator);
-        self.cstore.iter_crate_data(|_, data| {
-            needs_allocator = needs_allocator || data.needs_allocator();
-        });
-        if !needs_allocator {
+        if !self.sess.contains_name(&krate.attrs, sym::needs_allocator)
+            && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator())
+        {
             return;
         }
 
@@ -838,23 +824,19 @@ impl<'a> CrateLoader<'a> {
         // global allocator.
         let mut global_allocator =
             self.cstore.has_global_allocator.then(|| Symbol::intern("this crate"));
-        self.cstore.iter_crate_data(|_, data| {
-            if !data.has_global_allocator() {
-                return;
-            }
-            match global_allocator {
-                Some(other_crate) => {
-                    self.sess.err(&format!(
-                        "the `#[global_allocator]` in {} \
-                                            conflicts with global \
-                                            allocator in: {}",
+        for (_, data) in self.cstore.iter_crate_data() {
+            if data.has_global_allocator() {
+                match global_allocator {
+                    Some(other_crate) => self.sess.err(&format!(
+                        "the `#[global_allocator]` in {} conflicts with global allocator in: {}",
                         other_crate,
                         data.name()
-                    ));
+                    )),
+                    None => global_allocator = Some(data.name()),
                 }
-                None => global_allocator = Some(data.name()),
             }
-        });
+        }
+
         if global_allocator.is_some() {
             self.cstore.allocator_kind = Some(AllocatorKind::Global);
             return;
@@ -864,19 +846,12 @@ impl<'a> CrateLoader<'a> {
         // allocator. At this point our allocator request is typically fulfilled
         // by the standard library, denoted by the `#![default_lib_allocator]`
         // attribute.
-        let mut has_default = self.sess.contains_name(&krate.attrs, sym::default_lib_allocator);
-        self.cstore.iter_crate_data(|_, data| {
-            if data.has_default_lib_allocator() {
-                has_default = true;
-            }
-        });
-
-        if !has_default {
+        if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
+            && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
+        {
             self.sess.err(
-                "no global memory allocator found but one is \
-                           required; link to std or \
-                           add `#[global_allocator]` to a static item \
-                           that implements the GlobalAlloc trait",
+                "no global memory allocator found but one is required; link to std or add \
+                 `#[global_allocator]` to a static item that implements the GlobalAlloc trait",
             );
         }
         self.cstore.allocator_kind = Some(AllocatorKind::Default);
@@ -916,14 +891,12 @@ impl<'a> CrateLoader<'a> {
         // crate provided for this compile, but in order for this compilation to
         // be successfully linked we need to inject a dependency (to order the
         // crates on the command line correctly).
-        self.cstore.iter_crate_data(|cnum, data| {
-            if !needs_dep(data) {
-                return;
+        for (cnum, data) in self.cstore.iter_crate_data() {
+            if needs_dep(data) {
+                info!("injecting a dep from {} to {}", cnum, krate);
+                data.add_dependency(krate);
             }
-
-            info!("injecting a dep from {} to {}", cnum, krate);
-            data.add_dependency(krate);
-        });
+        }
     }
 
     fn report_unused_deps(&mut self, krate: &ast::Crate) {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 09c6cb010b0..5c275279579 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -27,6 +27,7 @@ use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, Body, Promoted};
 use rustc_middle::thir;
 use rustc_middle::ty::codec::TyDecoder;
+use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
 use rustc_serialize::{opaque, Decodable, Decoder};
 use rustc_session::cstore::{
@@ -45,7 +46,8 @@ use std::num::NonZeroUsize;
 use std::path::Path;
 use tracing::debug;
 
-pub use cstore_impl::{provide, provide_extern};
+pub(super) use cstore_impl::provide;
+pub use cstore_impl::provide_extern;
 use rustc_span::hygiene::HygieneDecodeContext;
 
 mod cstore_impl;
@@ -91,8 +93,7 @@ crate struct CrateMetadata {
     /// Trait impl data.
     /// FIXME: Used only from queries and can use query cache,
     /// so pre-decoding can probably be avoided.
-    trait_impls:
-        FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>>,
+    trait_impls: FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<SimplifiedType>)]>>,
     /// Proc macro descriptions for this crate, if it's a proc macro crate.
     raw_proc_macros: Option<&'static [ProcMacro]>,
     /// Source maps for code from the crate.
@@ -721,25 +722,24 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         &self.raw_proc_macros.unwrap()[pos]
     }
 
-    fn try_item_ident(&self, item_index: DefIndex, sess: &Session) -> Result<Ident, String> {
-        let name = self
-            .def_key(item_index)
-            .disambiguated_data
-            .data
-            .get_opt_name()
-            .ok_or_else(|| format!("Missing opt name for {:?}", item_index))?;
-        let span = self
-            .root
-            .tables
-            .ident_span
-            .get(self, item_index)
-            .ok_or_else(|| format!("Missing ident span for {:?} ({:?})", name, item_index))?
-            .decode((self, sess));
-        Ok(Ident::new(name, span))
+    fn opt_item_ident(&self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
+        let name = self.def_key(item_index).disambiguated_data.data.get_opt_name()?;
+        let span = match self.root.tables.ident_span.get(self, item_index) {
+            Some(lazy_span) => lazy_span.decode((self, sess)),
+            None => {
+                // FIXME: this weird case of a name with no span is specific to `extern crate`
+                // items, which are supposed to be treated like `use` items and only be encoded
+                // to metadata as `Export`s, return `None` because that's what all the callers
+                // expect in this case.
+                assert_eq!(self.def_kind(item_index), DefKind::ExternCrate);
+                return None;
+            }
+        };
+        Some(Ident::new(name, span))
     }
 
     fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident {
-        self.try_item_ident(item_index, sess).unwrap()
+        self.opt_item_ident(item_index, sess).expect("no encoded ident for item")
     }
 
     fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> {
@@ -1008,6 +1008,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.get_impl_data(id).constness
     }
 
+    fn get_trait_item_def_id(&self, id: DefIndex) -> Option<DefId> {
+        self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self))
+    }
+
     fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
         self.get_impl_data(id).coerce_unsized_info
     }
@@ -1099,70 +1103,29 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         };
 
         // Iterate over all children.
-        let macros_only = self.dep_kind.lock().macros_only();
-        if !macros_only {
-            let children = self.root.tables.children.get(self, id).unwrap_or_else(Lazy::empty);
-
+        if let Some(children) = self.root.tables.children.get(self, id) {
             for child_index in children.decode((self, sess)) {
-                // Get the item.
-                let child_kind = match self.maybe_kind(child_index) {
-                    Some(child_kind) => child_kind,
-                    None => continue,
-                };
-
-                // Hand off the item to the callback.
-                match child_kind {
-                    // FIXME(eddyb) Don't encode these in children.
-                    EntryKind::ForeignMod => {
-                        let child_children = self
-                            .root
-                            .tables
-                            .children
-                            .get(self, child_index)
-                            .unwrap_or_else(Lazy::empty);
-                        for child_index in child_children.decode((self, sess)) {
-                            let kind = self.def_kind(child_index);
-                            callback(Export {
-                                res: Res::Def(kind, self.local_def_id(child_index)),
-                                ident: self.item_ident(child_index, sess),
-                                vis: self.get_visibility(child_index),
-                                span: self
-                                    .root
-                                    .tables
-                                    .span
-                                    .get(self, child_index)
-                                    .unwrap()
-                                    .decode((self, sess)),
-                            });
-                        }
+                if let Some(ident) = self.opt_item_ident(child_index, sess) {
+                    let kind = self.def_kind(child_index);
+                    if matches!(kind, DefKind::Macro(..)) {
+                        // FIXME: Macros are currently encoded twice, once as items and once as
+                        // reexports. We ignore the items here and only use the reexports.
                         continue;
                     }
-                    EntryKind::Impl(_) => continue,
-
-                    _ => {}
-                }
-
-                let def_key = self.def_key(child_index);
-                if def_key.disambiguated_data.data.get_opt_name().is_some() {
-                    let span = self.get_span(child_index, sess);
-                    let kind = self.def_kind(child_index);
-                    let ident = self.item_ident(child_index, sess);
-                    let vis = self.get_visibility(child_index);
                     let def_id = self.local_def_id(child_index);
                     let res = Res::Def(kind, def_id);
+                    let vis = self.get_visibility(child_index);
+                    let span = self.get_span(child_index, sess);
 
-                    // FIXME: Macros are currently encoded twice, once as items and once as
-                    // reexports. We ignore the items here and only use the reexports.
-                    if !matches!(kind, DefKind::Macro(..)) {
-                        callback(Export { res, ident, vis, span });
-                    }
+                    callback(Export { ident, res, vis, span });
 
                     // For non-re-export structs and variants add their constructors to children.
                     // Re-export lists automatically contain constructors when necessary.
                     match kind {
                         DefKind::Struct => {
-                            if let Some(ctor_def_id) = self.get_ctor_def_id(child_index) {
-                                let ctor_kind = self.get_ctor_kind(child_index);
+                            if let Some((ctor_def_id, ctor_kind)) =
+                                self.get_ctor_def_id_and_kind(child_index)
+                            {
                                 let ctor_res =
                                     Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
                                 let vis = self.get_visibility(ctor_def_id.index);
@@ -1174,8 +1137,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                             // value namespace, they are reserved for possible future use.
                             // It's ok to use the variant's id as a ctor id since an
                             // error will be reported on any use of such resolution anyway.
-                            let ctor_def_id = self.get_ctor_def_id(child_index).unwrap_or(def_id);
-                            let ctor_kind = self.get_ctor_kind(child_index);
+                            let (ctor_def_id, ctor_kind) = self
+                                .get_ctor_def_id_and_kind(child_index)
+                                .unwrap_or((def_id, CtorKind::Fictive));
                             let ctor_res =
                                 Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
                             let mut vis = self.get_visibility(ctor_def_id.index);
@@ -1200,11 +1164,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 
         if let EntryKind::Mod(exports) = kind {
             for exp in exports.decode((self, sess)) {
-                match exp.res {
-                    Res::Def(DefKind::Macro(..), _) => {}
-                    _ if macros_only => continue,
-                    _ => {}
-                }
                 callback(exp);
             }
         }
@@ -1296,6 +1255,23 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         }
     }
 
+    fn get_fn_has_self_parameter(&self, id: DefIndex) -> bool {
+        match self.kind(id) {
+            EntryKind::AssocFn(data) => data.decode(self).has_self,
+            _ => false,
+        }
+    }
+
+    fn get_associated_item_def_ids(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] {
+        if let Some(children) = self.root.tables.children.get(self, id) {
+            tcx.arena.alloc_from_iter(
+                children.decode((self, tcx.sess)).map(|child_index| self.local_def_id(child_index)),
+            )
+        } else {
+            &[]
+        }
+    }
+
     fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem {
         let def_key = self.def_key(id);
         let parent = self.local_def_id(def_key.parent.unwrap());
@@ -1317,6 +1293,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             vis: self.get_visibility(id),
             defaultness: container.defaultness(),
             def_id: self.local_def_id(id),
+            trait_item_def_id: self.get_trait_item_def_id(id),
             container: container.with_def_id(parent),
             fn_has_self_parameter: has_self,
         }
@@ -1326,22 +1303,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self)
     }
 
-    fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind {
+    fn get_ctor_def_id_and_kind(&self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
         match self.kind(node_id) {
-            EntryKind::Struct(data, _) | EntryKind::Union(data, _) | EntryKind::Variant(data) => {
-                data.decode(self).ctor_kind
-            }
-            _ => CtorKind::Fictive,
-        }
-    }
-
-    fn get_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
-        match self.kind(node_id) {
-            EntryKind::Struct(data, _) => {
-                data.decode(self).ctor.map(|index| self.local_def_id(index))
-            }
-            EntryKind::Variant(data) => {
-                data.decode(self).ctor.map(|index| self.local_def_id(index))
+            EntryKind::Struct(data, _) | EntryKind::Variant(data) => {
+                let vdata = data.decode(self);
+                vdata.ctor.map(|index| (self.local_def_id(index), vdata.ctor_kind))
             }
             _ => None,
         }
@@ -1349,24 +1315,26 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 
     fn get_item_attrs(
         &'a self,
-        node_id: DefIndex,
+        id: DefIndex,
         sess: &'a Session,
     ) -> impl Iterator<Item = ast::Attribute> + 'a {
-        // The attributes for a tuple struct/variant are attached to the definition, not the ctor;
-        // we assume that someone passing in a tuple struct ctor is actually wanting to
-        // look at the definition
-        let def_key = self.def_key(node_id);
-        let item_id = if def_key.disambiguated_data.data == DefPathData::Ctor {
-            def_key.parent.unwrap()
-        } else {
-            node_id
-        };
-
         self.root
             .tables
             .attributes
-            .get(self, item_id)
-            .unwrap_or_else(Lazy::empty)
+            .get(self, id)
+            .unwrap_or_else(|| {
+                // Structure and variant constructors don't have any attributes encoded for them,
+                // but we assume that someone passing a constructor ID actually wants to look at
+                // the attributes on the corresponding struct or variant.
+                let def_key = self.def_key(id);
+                assert_eq!(def_key.disambiguated_data.data, DefPathData::Ctor);
+                let parent_id = def_key.parent.expect("no parent for a constructor");
+                self.root
+                    .tables
+                    .attributes
+                    .get(self, parent_id)
+                    .expect("no encoded attributes for a structure or variant")
+            })
             .decode((self, sess))
     }
 
@@ -1408,39 +1376,43 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         )
     }
 
-    fn get_implementations_for_trait(
+    fn get_traits(&'a self) -> impl Iterator<Item = DefId> + 'a {
+        self.root.traits.decode(self).map(|index| self.local_def_id(index))
+    }
+
+    fn get_trait_impls(&'a self) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + 'a {
+        self.trait_impls.values().flat_map(move |impls| {
+            impls
+                .decode(self)
+                .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
+        })
+    }
+
+    fn get_implementations_of_trait(
         &self,
         tcx: TyCtxt<'tcx>,
-        filter: Option<DefId>,
-    ) -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
+        trait_def_id: DefId,
+    ) -> &'tcx [(DefId, Option<SimplifiedType>)] {
         if self.root.is_proc_macro_crate() {
             // proc-macro crates export no trait impls.
             return &[];
         }
 
-        if let Some(def_id) = filter {
-            // Do a reverse lookup beforehand to avoid touching the crate_num
-            // hash map in the loop below.
-            let filter = match self.reverse_translate_def_id(def_id) {
-                Some(def_id) => (def_id.krate.as_u32(), def_id.index),
-                None => return &[],
-            };
+        // Do a reverse lookup beforehand to avoid touching the crate_num
+        // hash map in the loop below.
+        let key = match self.reverse_translate_def_id(trait_def_id) {
+            Some(def_id) => (def_id.krate.as_u32(), def_id.index),
+            None => return &[],
+        };
 
-            if let Some(impls) = self.trait_impls.get(&filter) {
-                tcx.arena.alloc_from_iter(
-                    impls.decode(self).map(|(idx, simplified_self_ty)| {
-                        (self.local_def_id(idx), simplified_self_ty)
-                    }),
-                )
-            } else {
-                &[]
-            }
-        } else {
-            tcx.arena.alloc_from_iter(self.trait_impls.values().flat_map(|impls| {
+        if let Some(impls) = self.trait_impls.get(&key) {
+            tcx.arena.alloc_from_iter(
                 impls
                     .decode(self)
-                    .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
-            }))
+                    .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)),
+            )
+        } else {
+            &[]
         }
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 4e5d21049a0..804f277e26e 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -103,12 +103,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
         tcx.calculate_dtor(def_id, |_,_| Ok(()))
     }
     variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
-    associated_item_def_ids => {
-        let mut result = SmallVec::<[_; 8]>::new();
-        cdata.each_child_of_item(def_id.index,
-          |child| result.push(child.res.def_id()), tcx.sess);
-        tcx.arena.alloc_slice(&result)
-    }
+    associated_item_def_ids => { cdata.get_associated_item_def_ids(tcx, def_id.index) }
     associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
     impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
     impl_polarity => { cdata.get_impl_polarity(def_id.index) }
@@ -133,9 +128,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     generator_kind => { cdata.generator_kind(def_id.index) }
     opt_def_kind => { Some(cdata.def_kind(def_id.index)) }
     def_span => { cdata.get_span(def_id.index, &tcx.sess) }
-    def_ident_span => {
-        cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span)
-    }
+    def_ident_span => { cdata.opt_item_ident(def_id.index, &tcx.sess).map(|ident| ident.span) }
     lookup_stability => {
         cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
     }
@@ -145,9 +138,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     lookup_deprecation_entry => {
         cdata.get_deprecation(def_id.index).map(DeprecationEntry::external)
     }
-    item_attrs => { tcx.arena.alloc_from_iter(
-        cdata.get_item_attrs(def_id.index, tcx.sess)
-    ) }
+    item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
     fn_arg_names => { cdata.get_fn_param_names(tcx, def_id.index) }
     rendered_const => { cdata.get_rendered_const(def_id.index) }
     impl_parent => { cdata.get_parent_impl(def_id.index) }
@@ -195,13 +186,10 @@ provide! { <'tcx> tcx, def_id, other, cdata,
 
     extra_filename => { cdata.root.extra_filename.clone() }
 
-    implementations_of_trait => {
-        cdata.get_implementations_for_trait(tcx, Some(other))
-    }
+    traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
+    all_trait_implementations => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) }
 
-    all_trait_implementations => {
-        cdata.get_implementations_for_trait(tcx, None)
-    }
+    implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
 
     visibility => { cdata.get_visibility(def_id.index) }
     dep_kind => {
@@ -239,7 +227,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
 }
 
-pub fn provide(providers: &mut Providers) {
+pub(in crate::rmeta) fn provide(providers: &mut Providers) {
     // FIXME(#44234) - almost all of these queries have no sub-queries and
     // therefore no actual inputs, they're just reading tables calculated in
     // resolve! Does this work? Unsure! That's what the issue is about
@@ -372,7 +360,7 @@ pub fn provide(providers: &mut Providers) {
             tcx.arena
                 .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
         },
-        crates: |tcx, ()| tcx.arena.alloc_slice(&CStore::from_tcx(tcx).crates_untracked()),
+        crates: |tcx, ()| tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).crates_untracked()),
 
         ..*providers
     };
@@ -388,9 +376,7 @@ impl CStore {
     }
 
     pub fn ctor_def_id_and_kind_untracked(&self, def: DefId) -> Option<(DefId, CtorKind)> {
-        self.get_crate_data(def.krate).get_ctor_def_id(def.index).map(|ctor_def_id| {
-            (ctor_def_id, self.get_crate_data(def.krate).get_ctor_kind(def.index))
-        })
+        self.get_crate_data(def.krate).get_ctor_def_id_and_kind(def.index)
     }
 
     pub fn visibility_untracked(&self, def: DefId) -> Visibility {
@@ -417,16 +403,12 @@ impl CStore {
 
         let span = data.get_span(id.index, sess);
 
-        let attrs = data.get_item_attrs(id.index, sess).collect();
-
-        let ident = data.item_ident(id.index, sess);
-
         LoadedMacro::MacroDef(
             ast::Item {
-                ident,
+                ident: data.item_ident(id.index, sess),
                 id: ast::DUMMY_NODE_ID,
                 span,
-                attrs,
+                attrs: data.get_item_attrs(id.index, sess).collect(),
                 kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)),
                 vis: ast::Visibility {
                     span: span.shrink_to_lo(),
@@ -439,8 +421,8 @@ impl CStore {
         )
     }
 
-    pub fn associated_item_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::AssocItem {
-        self.get_crate_data(def.krate).get_associated_item(def.index, sess)
+    pub fn fn_has_self_parameter_untracked(&self, def: DefId) -> bool {
+        self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index)
     }
 
     pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource {
@@ -455,10 +437,8 @@ impl CStore {
         self.get_crate_data(def.krate).def_kind(def.index)
     }
 
-    pub fn crates_untracked(&self) -> Vec<CrateNum> {
-        let mut result = vec![];
-        self.iter_crate_data(|cnum, _| result.push(cnum));
-        result
+    pub fn crates_untracked(&self) -> impl Iterator<Item = CrateNum> + '_ {
+        self.iter_crate_data().map(|(cnum, _)| cnum)
     }
 
     pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
@@ -476,7 +456,7 @@ impl CStore {
         self.get_crate_data(cnum).num_def_ids()
     }
 
-    pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
+    pub fn item_attrs_untracked(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
     }
 
@@ -536,4 +516,8 @@ impl CrateStore for CStore {
     ) -> ExpnId {
         self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash)
     }
+
+    fn import_source_files(&self, sess: &Session, cnum: CrateNum) {
+        self.get_crate_data(cnum).imported_source_files(sess);
+    }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index eeb907d0114..11a986f0a7c 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -26,7 +26,8 @@ use rustc_middle::mir::interpret;
 use rustc_middle::thir;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_serialize::{opaque, Encodable, Encoder};
 use rustc_session::config::CrateType;
@@ -612,10 +613,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.encode_def_path_table();
         let def_path_table_bytes = self.position() - i;
 
+        // Encode the def IDs of traits, for rustdoc and diagnostics.
+        i = self.position();
+        let traits = self.encode_traits();
+        let traits_bytes = self.position() - i;
+
         // Encode the def IDs of impls, for coherence checking.
         i = self.position();
         let impls = self.encode_impls();
-        let impl_bytes = self.position() - i;
+        let impls_bytes = self.position() - i;
 
         let tcx = self.tcx;
 
@@ -715,7 +721,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
             panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
             profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
-            symbol_mangling_version: tcx.sess.opts.debugging_opts.get_symbol_mangling_version(),
+            symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
 
             crate_deps,
             dylib_dependency_formats,
@@ -726,6 +732,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             native_libraries,
             foreign_modules,
             source_map,
+            traits,
             impls,
             exported_symbols,
             interpret_alloc_index,
@@ -753,7 +760,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes);
             eprintln!("          native bytes: {}", native_lib_bytes);
             eprintln!("      source_map bytes: {}", source_map_bytes);
-            eprintln!("            impl bytes: {}", impl_bytes);
+            eprintln!("          traits bytes: {}", traits_bytes);
+            eprintln!("           impls bytes: {}", impls_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);
@@ -1100,9 +1108,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             // Encode this here because we don't do it in encode_def_ids.
             record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
         } else {
-            record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| {
-                item_id.def_id.local_def_index
-            }));
+            let direct_children = md.item_ids.iter().map(|item_id| item_id.def_id.local_def_index);
+            // Foreign items are planted into their parent modules from name resolution point of view.
+            let tcx = self.tcx;
+            let foreign_item_children = md
+                .item_ids
+                .iter()
+                .filter_map(|item_id| match tcx.hir().item(*item_id).kind {
+                    hir::ItemKind::ForeignMod { items, .. } => {
+                        Some(items.iter().map(|fi_ref| fi_ref.id.def_id.local_def_index))
+                    }
+                    _ => None,
+                })
+                .flatten();
+
+            record!(self.tables.children[def_id] <- direct_children.chain(foreign_item_children));
         }
     }
 
@@ -1274,6 +1294,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
         self.encode_ident_span(def_id, impl_item.ident);
         self.encode_item_type(def_id);
+        if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
+            record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id);
+        }
         if impl_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
         }
@@ -1503,11 +1526,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         record!(self.tables.kind[def_id] <- entry_kind);
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
-            hir::ItemKind::ForeignMod { items, .. } => record!(self.tables.children[def_id] <-
-                items
-                    .iter()
-                    .map(|foreign_item| foreign_item.id.def_id.local_def_index)
-            ),
             hir::ItemKind::Enum(..) => record!(self.tables.children[def_id] <-
                 self.tcx.adt_def(def_id).variants.iter().map(|v| {
                     assert!(v.def_id.is_local());
@@ -1783,12 +1801,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy(&tcx.lang_items().missing)
     }
 
+    fn encode_traits(&mut self) -> Lazy<[DefIndex]> {
+        empty_proc_macro!(self);
+        self.lazy(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index))
+    }
+
     /// Encodes an index, mapping each trait to its (local) implementations.
     fn encode_impls(&mut self) -> Lazy<[TraitImpls]> {
+        debug!("EncodeContext::encode_traits_and_impls()");
         empty_proc_macro!(self);
-        debug!("EncodeContext::encode_impls()");
         let tcx = self.tcx;
-        let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() };
+        let mut visitor = ImplsVisitor { tcx, impls: FxHashMap::default() };
         tcx.hir().visit_all_item_likes(&mut visitor);
 
         let mut all_impls: Vec<_> = visitor.impls.into_iter().collect();
@@ -2033,27 +2056,30 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 }
 
-struct ImplVisitor<'tcx> {
+struct ImplsVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    impls: FxHashMap<DefId, Vec<(DefIndex, Option<fast_reject::SimplifiedType>)>>,
+    impls: FxHashMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>>,
 }
 
-impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
+impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplsVisitor<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        if let hir::ItemKind::Impl { .. } = item.kind {
-            if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) {
-                let simplified_self_ty = fast_reject::simplify_type(
-                    self.tcx,
-                    trait_ref.self_ty(),
-                    SimplifyParams::No,
-                    StripReferences::No,
-                );
+        match item.kind {
+            hir::ItemKind::Impl(..) => {
+                if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) {
+                    let simplified_self_ty = fast_reject::simplify_type(
+                        self.tcx,
+                        trait_ref.self_ty(),
+                        SimplifyParams::No,
+                        StripReferences::No,
+                    );
 
-                self.impls
-                    .entry(trait_ref.def_id)
-                    .or_default()
-                    .push((item.def_id.local_def_index, simplified_self_ty));
+                    self.impls
+                        .entry(trait_ref.def_id)
+                        .or_default()
+                        .push((item.def_id.local_def_index, simplified_self_ty));
+                }
             }
+            _ => {}
         }
     }
 
@@ -2202,3 +2228,34 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
 
     EncodedMetadata { raw_data: result }
 }
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        traits_in_crate: |tcx, cnum| {
+            assert_eq!(cnum, LOCAL_CRATE);
+
+            #[derive(Default)]
+            struct TraitsVisitor {
+                traits: Vec<DefId>,
+            }
+            impl ItemLikeVisitor<'_> for TraitsVisitor {
+                fn visit_item(&mut self, item: &hir::Item<'_>) {
+                    if let hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) = item.kind {
+                        self.traits.push(item.def_id.to_def_id());
+                    }
+                }
+                fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
+                fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
+                fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
+            }
+
+            let mut visitor = TraitsVisitor::default();
+            tcx.hir().visit_all_item_likes(&mut visitor);
+            // Bring everything into deterministic order.
+            visitor.traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
+            tcx.arena.alloc_slice(&visitor.traits)
+        },
+
+        ..*providers
+    };
+}
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 5ce239ac704..fa44cbc2d55 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -16,6 +16,8 @@ use rustc_middle::hir::exports::Export;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir;
 use rustc_middle::thir;
+use rustc_middle::ty::fast_reject::SimplifiedType;
+use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
@@ -29,8 +31,8 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
 use std::marker::PhantomData;
 use std::num::NonZeroUsize;
 
+pub use decoder::provide_extern;
 use decoder::DecodeContext;
-pub use decoder::{provide, provide_extern};
 crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
 use encoder::EncodeContext;
 pub use encoder::{encode_metadata, EncodedMetadata};
@@ -222,6 +224,7 @@ crate struct CrateRoot<'tcx> {
     diagnostic_items: Lazy<[(Symbol, DefIndex)]>,
     native_libraries: Lazy<[NativeLib]>,
     foreign_modules: Lazy<[ForeignModule]>,
+    traits: Lazy<[DefIndex]>,
     impls: Lazy<[TraitImpls]>,
     interpret_alloc_index: Lazy<[u32]>,
     proc_macro_data: Option<ProcMacroData>,
@@ -259,7 +262,7 @@ crate struct CrateDep {
 #[derive(MetadataEncodable, MetadataDecodable)]
 crate struct TraitImpls {
     trait_id: (u32, DefIndex),
-    impls: Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>,
+    impls: Lazy<[(DefIndex, Option<SimplifiedType>)]>,
 }
 
 /// Define `LazyTables` and `TableBuilders` at the same time.
@@ -299,6 +302,7 @@ define_tables! {
     ty: Table<DefIndex, Lazy!(Ty<'tcx>)>,
     fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
     impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
+    trait_item_def_id: Table<DefIndex, Lazy<DefId>>,
     inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
     variances: Table<DefIndex, Lazy<[ty::Variance]>>,
     generics: Table<DefIndex, Lazy<ty::Generics>>,
@@ -453,3 +457,8 @@ struct GeneratorData<'tcx> {
 const TAG_VALID_SPAN_LOCAL: u8 = 0;
 const TAG_VALID_SPAN_FOREIGN: u8 = 1;
 const TAG_PARTIAL_SPAN: u8 = 2;
+
+pub fn provide(providers: &mut Providers) {
+    encoder::provide(providers);
+    decoder::provide(providers);
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 37ec2006172..e9a857d0912 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -8,7 +8,7 @@ use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported}
 use rustc_macros::HashStable;
 use rustc_session::CtfeBacktrace;
 use rustc_span::def_id::DefId;
-use rustc_target::abi::{Align, Size};
+use rustc_target::abi::{call, Align, Size};
 use std::{any::Any, backtrace::Backtrace, fmt};
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
@@ -141,6 +141,10 @@ pub enum InvalidProgramInfo<'tcx> {
     AlreadyReported(ErrorReported),
     /// An error occurred during layout computation.
     Layout(layout::LayoutError<'tcx>),
+    /// An error occurred during FnAbi computation: the passed --target lacks FFI support
+    /// (which unfortunately typeck does not reject).
+    /// Not using `FnAbiError` as that contains a nested `LayoutError`.
+    FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
     /// An invalid transmute happened.
     TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>),
     /// SizeOf of unsized type was requested.
@@ -157,6 +161,7 @@ impl fmt::Display for InvalidProgramInfo<'_> {
                 write!(f, "encountered constants with type errors, stopping evaluation")
             }
             Layout(ref err) => write!(f, "{}", err),
+            FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err),
             TransmuteSizeDiff(from_ty, to_ty) => write!(
                 f,
                 "transmuting `{}` to `{}` is not possible, because these types do not have the same size",
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index d2dd15aad12..52ef380001c 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2268,7 +2268,7 @@ pub enum AggregateKind<'tcx> {
     /// active field number and is present only for union expressions
     /// -- e.g., for a union expression `SomeUnion { c: .. }`, the
     /// active field index would identity the field `c`
-    Adt(&'tcx AdtDef, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>),
+    Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>),
 
     Closure(DefId, SubstsRef<'tcx>),
     Generator(DefId, SubstsRef<'tcx>, hir::Movability),
@@ -2336,8 +2336,6 @@ pub enum NullOp {
     SizeOf,
     /// Returns the minimum alignment of a type
     AlignOf,
-    /// Creates a new uninitialized box for a value of that type
-    Box,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
@@ -2427,28 +2425,26 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                         }
                     }
 
-                    AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => {
-                        let variant_def = &adt_def.variants[variant];
-
-                        let name = ty::tls::with(|tcx| {
+                    AggregateKind::Adt(adt_did, variant, substs, _user_ty, _) => {
+                        ty::tls::with(|tcx| {
                             let mut name = String::new();
+                            let variant_def = &tcx.adt_def(adt_did).variants[variant];
                             let substs = tcx.lift(substs).expect("could not lift for printing");
                             FmtPrinter::new(tcx, &mut name, Namespace::ValueNS)
                                 .print_def_path(variant_def.def_id, substs)?;
-                            Ok(name)
-                        })?;
-
-                        match variant_def.ctor_kind {
-                            CtorKind::Const => fmt.write_str(&name),
-                            CtorKind::Fn => fmt_tuple(fmt, &name),
-                            CtorKind::Fictive => {
-                                let mut struct_fmt = fmt.debug_struct(&name);
-                                for (field, place) in iter::zip(&variant_def.fields, places) {
-                                    struct_fmt.field(field.ident.as_str(), place);
+
+                            match variant_def.ctor_kind {
+                                CtorKind::Const => fmt.write_str(&name),
+                                CtorKind::Fn => fmt_tuple(fmt, &name),
+                                CtorKind::Fictive => {
+                                    let mut struct_fmt = fmt.debug_struct(&name);
+                                    for (field, place) in iter::zip(&variant_def.fields, places) {
+                                        struct_fmt.field(field.ident.as_str(), place);
+                                    }
+                                    struct_fmt.finish()
                                 }
-                                struct_fmt.finish()
                             }
-                        }
+                        })
                     }
 
                     AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| {
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index c3c5ebe705e..dc53dc8de9d 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -195,12 +195,11 @@ impl<'tcx> Rvalue<'tcx> {
             }
             Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
-            Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize,
             Rvalue::Aggregate(ref ak, ref ops) => match **ak {
                 AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64),
                 AggregateKind::Tuple => tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))),
-                AggregateKind::Adt(def, _, substs, _, _) => tcx.type_of(def.did).subst(tcx, substs),
+                AggregateKind::Adt(did, _, substs, _, _) => tcx.type_of(did).subst(tcx, substs),
                 AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs),
                 AggregateKind::Generator(did, substs, movability) => {
                     tcx.mk_generator(did, substs, movability)
@@ -215,9 +214,7 @@ impl<'tcx> Rvalue<'tcx> {
     /// whether its only shallowly initialized (`Rvalue::Box`).
     pub fn initialization_state(&self) -> RvalueInitializationState {
         match *self {
-            Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => {
-                RvalueInitializationState::Shallow
-            }
+            Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow,
             _ => RvalueInitializationState::Deep,
         }
     }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index ad3f61d0784..f1c2be660bc 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -630,6 +630,32 @@ rustc_queries! {
         desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
     }
 
+    /// Maps from associated items on a trait to the corresponding associated
+    /// item on the impl specified by `impl_id`.
+    ///
+    /// For example, with the following code
+    ///
+    /// ```
+    /// struct Type {}
+    ///                         // DefId
+    /// trait Trait {           // trait_id
+    ///     fn f();             // trait_f
+    ///     fn g() {}           // trait_g
+    /// }
+    ///
+    /// impl Trait for Type {   // impl_id
+    ///     fn f() {}           // impl_f
+    ///     fn g() {}           // impl_g
+    /// }
+    /// ```
+    ///
+    /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
+    ///`{ trait_f: impl_f, trait_g: impl_g }`
+    query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
+        desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
+        storage(ArenaCacheSelector<'tcx>)
+    }
+
     /// Given an `impl_id`, return the trait it implements.
     /// Return `None` if this is an inherent impl.
     query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
@@ -1411,16 +1437,14 @@ rustc_queries! {
 
     /// Given a crate and a trait, look up all impls of that trait in the crate.
     /// Return `(impl_id, self_ty)`.
-    query implementations_of_trait(_: (CrateNum, DefId))
-        -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
+    query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [(DefId, Option<SimplifiedType>)] {
         desc { "looking up implementations of a trait in a crate" }
         separate_provide_extern
     }
 
     /// Given a crate, look up all trait impls in that crate.
     /// Return `(impl_id, self_ty)`.
-    query all_trait_implementations(_: CrateNum)
-        -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
+    query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option<SimplifiedType>)] {
         desc { "looking up all (?) trait implementations" }
         separate_provide_extern
     }
@@ -1609,11 +1633,11 @@ rustc_queries! {
         desc { "fetching all foreign CrateNum instances" }
     }
 
-    /// A vector of every trait accessible in the whole crate
-    /// (i.e., including those from subcrates). This is used only for
-    /// error reporting.
-    query all_traits(_: ()) -> &'tcx [DefId] {
-        desc { "fetching all foreign and local traits" }
+    /// A list of all traits in a crate, used by rustdoc and error reporting.
+    /// NOTE: Not named just `traits` due to a naming conflict.
+    query traits_in_crate(_: CrateNum) -> &'tcx [DefId] {
+        desc { "fetching all traits in a crate" }
+        separate_provide_extern
     }
 
     /// The list of symbols exported from the given crate.
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 3e9cd6b46b2..087be313b26 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -4,7 +4,6 @@ use crate::ty::{self, TyCtxt};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::{DefId, DefIdMap};
-use rustc_span::symbol::Ident;
 
 /// A per-trait graph of impls in specialization order. At the moment, this
 /// graph forms a tree rooted with the trait itself, with all other nodes
@@ -75,34 +74,28 @@ pub enum Node {
     Trait(DefId),
 }
 
-impl<'tcx> Node {
+impl Node {
     pub fn is_from_trait(&self) -> bool {
         matches!(self, Node::Trait(..))
     }
 
-    /// Iterate over the items defined directly by the given (impl or trait) node.
-    pub fn items(&self, tcx: TyCtxt<'tcx>) -> impl 'tcx + Iterator<Item = &'tcx ty::AssocItem> {
-        tcx.associated_items(self.def_id()).in_definition_order()
-    }
-
-    /// Finds an associated item defined in this node.
+    /// Trys to find the associated item that implements `trait_item_def_id`
+    /// defined in this node.
     ///
     /// If this returns `None`, the item can potentially still be found in
     /// parents of this node.
-    pub fn item(
+    pub fn item<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        trait_item_name: Ident,
-        trait_item_kind: ty::AssocKind,
-        trait_def_id: DefId,
-    ) -> Option<ty::AssocItem> {
-        tcx.associated_items(self.def_id())
-            .filter_by_name_unhygienic(trait_item_name.name)
-            .find(move |impl_item| {
-                trait_item_kind == impl_item.kind
-                    && tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id)
-            })
-            .copied()
+        trait_item_def_id: DefId,
+    ) -> Option<&'tcx ty::AssocItem> {
+        match *self {
+            Node::Trait(_) => Some(tcx.associated_item(trait_item_def_id)),
+            Node::Impl(impl_def_id) => {
+                let id = tcx.impl_item_implementor_ids(impl_def_id).get(&trait_item_def_id)?;
+                Some(tcx.associated_item(*id))
+            }
+        }
     }
 
     pub fn def_id(&self) -> DefId {
@@ -181,17 +174,11 @@ impl LeafDef {
 impl<'tcx> Ancestors<'tcx> {
     /// Finds the bottom-most (ie. most specialized) definition of an associated
     /// item.
-    pub fn leaf_def(
-        mut self,
-        tcx: TyCtxt<'tcx>,
-        trait_item_name: Ident,
-        trait_item_kind: ty::AssocKind,
-    ) -> Option<LeafDef> {
-        let trait_def_id = self.trait_def_id;
+    pub fn leaf_def(mut self, tcx: TyCtxt<'tcx>, trait_item_def_id: DefId) -> Option<LeafDef> {
         let mut finalizing_node = None;
 
         self.find_map(|node| {
-            if let Some(item) = node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) {
+            if let Some(item) = node.item(tcx, trait_item_def_id) {
                 if finalizing_node.is_none() {
                     let is_specializable = item.defaultness.is_default()
                         || tcx.impl_defaultness(node.def_id()).is_default();
@@ -201,7 +188,7 @@ impl<'tcx> Ancestors<'tcx> {
                     }
                 }
 
-                Some(LeafDef { item, defining_node: node, finalizing_node })
+                Some(LeafDef { item: *item, defining_node: node, finalizing_node })
             } else {
                 // Item not mentioned. This "finalizes" any defaulted item provided by an ancestor.
                 finalizing_node = Some(node);
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index bf5a3e68250..5af4eef40d4 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -40,6 +40,7 @@ impl AssocItemContainer {
     }
 }
 
+/// Information about an associated item
 #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
 pub struct AssocItem {
     pub def_id: DefId,
@@ -50,6 +51,10 @@ pub struct AssocItem {
     pub defaultness: hir::Defaultness,
     pub container: AssocItemContainer,
 
+    /// If this is an item in an impl of a trait then this is the `DefId` of
+    /// the associated item on the trait that this implements.
+    pub trait_item_def_id: Option<DefId>,
+
     /// Whether this is a method with an explicit self
     /// as its first parameter, allowing method calls.
     pub fn_has_self_parameter: bool,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index caa7008f108..dd571e29bf6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1577,6 +1577,12 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn const_eval_limit(self) -> Limit {
         self.limits(()).const_eval_limit
     }
+
+    pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
+        iter::once(LOCAL_CRATE)
+            .chain(self.crates(()).iter().copied())
+            .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied())
+    }
 }
 
 /// A trait implemented for all `X<'a>` types that can be safely and
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 04011552e31..daf9156a15f 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -143,6 +143,18 @@ pub fn simplify_type(
 }
 
 impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> {
+    pub fn def(self) -> Option<D> {
+        match self {
+            AdtSimplifiedType(d)
+            | ForeignSimplifiedType(d)
+            | TraitSimplifiedType(d)
+            | ClosureSimplifiedType(d)
+            | GeneratorSimplifiedType(d)
+            | OpaqueSimplifiedType(d) => Some(d),
+            _ => None,
+        }
+    }
+
     pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U>
     where
         F: Fn(D) -> U,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 7ec6d3f3b2b..196fe7ce1b6 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2581,9 +2581,12 @@ impl<'tcx> ty::Instance<'tcx> {
     // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
     // or should go through `FnAbi` instead, to avoid losing any
     // 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());
+    fn fn_sig_for_fn_abi(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> ty::PolyFnSig<'tcx> {
+        let ty = self.ty(tcx, param_env);
         match *ty.kind() {
             ty::FnDef(..) => {
                 // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
@@ -2965,7 +2968,7 @@ fn fn_abi_of_instance<'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 sig = instance.fn_sig_for_fn_abi(tcx, param_env);
 
     let caller_location = if instance.def.requires_caller_location(tcx) {
         Some(tcx.caller_location_ty())
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 37d99766da9..78ccfbd5e8c 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -77,7 +77,7 @@ pub use self::sty::{
     GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
     ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
     PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
-    UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
+    UpvarSubsts, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 2f91503afdf..3af1b3a0440 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -28,6 +28,7 @@ use crate::traits::query::{
 };
 use crate::traits::specialization_graph;
 use crate::traits::{self, ImplSource};
+use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 905a5c47d2b..63ed318cadb 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -6,7 +6,7 @@
 
 use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
 use crate::ty::error::{ExpectedFound, TypeError};
-use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
+use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as ast;
 use rustc_hir::def_id::DefId;
@@ -59,8 +59,9 @@ pub trait TypeRelation<'tcx>: Sized {
             item_def_id, a_subst, b_subst
         );
 
-        let opt_variances = self.tcx().variances_of(item_def_id);
-        relate_substs(self, Some(opt_variances), a_subst, b_subst)
+        let tcx = self.tcx();
+        let opt_variances = tcx.variances_of(item_def_id);
+        relate_substs(self, Some((item_def_id, opt_variances)), a_subst, b_subst)
     }
 
     /// Switch variance for the purpose of relating `a` and `b`.
@@ -116,7 +117,7 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
     a: ty::TypeAndMut<'tcx>,
     b: ty::TypeAndMut<'tcx>,
-    kind: ty::VarianceDiagMutKind,
+    base_ty: Ty<'tcx>,
 ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
     debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
     if a.mutbl != b.mutbl {
@@ -125,7 +126,9 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
         let mutbl = a.mutbl;
         let (variance, info) = match mutbl {
             ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
-            ast::Mutability::Mut => (ty::Invariant, ty::VarianceDiagInfo::Mut { kind, ty: a.ty }),
+            ast::Mutability::Mut => {
+                (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: base_ty, param_index: 0 })
+            }
         };
         let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?;
         Ok(ty::TypeAndMut { ty, mutbl })
@@ -134,15 +137,29 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
 
 pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
-    variances: Option<&[ty::Variance]>,
+    variances: Option<(DefId, &[ty::Variance])>,
     a_subst: SubstsRef<'tcx>,
     b_subst: SubstsRef<'tcx>,
 ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
     let tcx = relation.tcx();
+    let mut cached_ty = None;
 
     let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
-        let variance = variances.map_or(ty::Invariant, |v| v[i]);
-        relation.relate_with_variance(variance, ty::VarianceDiagInfo::default(), a, b)
+        let (variance, variance_info) = match variances {
+            Some((ty_def_id, variances)) => {
+                let variance = variances[i];
+                let variance_info = if variance == ty::Invariant {
+                    let ty =
+                        cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
+                    ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
+                } else {
+                    ty::VarianceDiagInfo::default()
+                };
+                (variance, variance_info)
+            }
+            None => (ty::Invariant, ty::VarianceDiagInfo::default()),
+        };
+        relation.relate_with_variance(variance, variance_info, a, b)
     });
 
     tcx.mk_substs(params)
@@ -436,7 +453,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         }
 
         (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
-            let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::RawPtr)?;
+            let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
             Ok(tcx.mk_ptr(mt))
         }
 
@@ -449,7 +466,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             )?;
             let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
             let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
-            let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::Ref)?;
+            let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
             Ok(tcx.mk_ref(r, mt))
         }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 8706661b250..c24a1d8eb52 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2282,36 +2282,26 @@ pub enum VarianceDiagInfo<'tcx> {
     /// We will not add any additional information to error messages.
     #[default]
     None,
-    /// We switched our variance because a type occurs inside
-    /// the generic argument of a mutable reference or pointer
-    /// (`*mut T` or `&mut T`). In either case, our variance
-    /// will always be `Invariant`.
-    Mut {
-        /// Tracks whether we had a mutable pointer or reference,
-        /// for better error messages
-        kind: VarianceDiagMutKind,
-        /// The type parameter of the mutable pointer/reference
-        /// (the `T` in `&mut T` or `*mut T`).
+    /// We switched our variance because a generic argument occurs inside
+    /// the invariant generic argument of another type.
+    Invariant {
+        /// The generic type containing the generic parameter
+        /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`)
         ty: Ty<'tcx>,
+        /// The index of the generic parameter being used
+        /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`)
+        param_index: u32,
     },
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-pub enum VarianceDiagMutKind {
-    /// A mutable raw pointer (`*mut T`)
-    RawPtr,
-    /// A mutable reference (`&mut T`)
-    Ref,
-}
-
 impl<'tcx> VarianceDiagInfo<'tcx> {
     /// Mirrors `Variance::xform` - used to 'combine' the existing
     /// and new `VarianceDiagInfo`s when our variance changes.
     pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> {
-        // For now, just use the first `VarianceDiagInfo::Mut` that we see
+        // For now, just use the first `VarianceDiagInfo::Invariant` that we see
         match self {
             VarianceDiagInfo::None => other,
-            VarianceDiagInfo::Mut { .. } => self,
+            VarianceDiagInfo::Invariant { .. } => self,
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index cbb88def7e2..34d059f4ec8 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,5 +1,5 @@
 use crate::traits::specialization_graph;
-use crate::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
 use crate::ty::fold::TypeFoldable;
 use crate::ty::{Ty, TyCtxt};
 use rustc_hir as hir;
@@ -68,7 +68,7 @@ pub enum TraitSpecializationKind {
 pub struct TraitImpls {
     blanket_impls: Vec<DefId>,
     /// Impls indexed by their simplified self type, for fast lookup.
-    non_blanket_impls: FxIndexMap<fast_reject::SimplifiedType, Vec<DefId>>,
+    non_blanket_impls: FxIndexMap<SimplifiedType, Vec<DefId>>,
 }
 
 impl TraitImpls {
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index abec67af08b..d9896ff5ac9 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -377,7 +377,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     })
                 });
                 let adt = Box::new(AggregateKind::Adt(
-                    adt_def,
+                    adt_def.did,
                     variant_index,
                     substs,
                     user_ty,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 092fe131174..bdde6b4a356 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -583,9 +583,12 @@ impl<'tcx> Cx<'tcx> {
                 ExprKind::ConstBlock { value }
             }
             // Now comes the rote stuff:
-            hir::ExprKind::Repeat(ref v, ref count) => {
-                let count_def_id = self.tcx.hir().local_def_id(count.hir_id);
-                let count = ty::Const::from_anon_const(self.tcx, count_def_id);
+            hir::ExprKind::Repeat(ref v, _) => {
+                let ty = self.typeck_results().expr_ty(expr);
+                let count = match ty.kind() {
+                    ty::Array(_, ct) => ct,
+                    _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty),
+                };
 
                 ExprKind::Repeat { value: self.mirror_expr(v), count }
             }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index feb85d4ffdf..2e00b4f9a5e 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -343,19 +343,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             | Rvalue::AddressOf(..)
             | Rvalue::Discriminant(..)
             | Rvalue::Len(..)
-            | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _)
-            | Rvalue::NullaryOp(NullOp::Box, _) => {
-                // This returns an rvalue with uninitialized contents. We can't
-                // move out of it here because it is an rvalue - assignments always
-                // completely initialize their place.
-                //
-                // However, this does not matter - MIR building is careful to
-                // only emit a shallow free for the partially-initialized
-                // temporary.
-                //
-                // In any case, if we want to fix this, we have to register a
-                // special move and change the `statement_effect` functions.
-            }
+            | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
         }
     }
 
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 2dda19badd7..a40c4d1c366 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -117,8 +117,8 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
         match rvalue {
             Rvalue::Aggregate(box ref aggregate, _) => match aggregate {
                 &AggregateKind::Array(..) | &AggregateKind::Tuple => {}
-                &AggregateKind::Adt(ref def, ..) => {
-                    match self.tcx.layout_scalar_valid_range(def.did) {
+                &AggregateKind::Adt(adt_did, ..) => {
+                    match self.tcx.layout_scalar_valid_range(adt_did) {
                         (Bound::Unbounded, Bound::Unbounded) => {}
                         _ => self.require_unsafe(
                             UnsafetyViolationKind::General,
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 84bdb8eece6..e3ff6ad4549 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -207,7 +207,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         _args: &[OpTy<'tcx>],
         _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
         _unwind: StackPopUnwind,
-    ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
+    ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
         Ok(None)
     }
 
@@ -239,13 +239,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
     }
 
-    fn box_alloc(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _dest: &PlaceTy<'tcx>,
-    ) -> InterpResult<'tcx> {
-        throw_machine_stop_str!("can't const prop heap allocations")
-    }
-
     fn access_local(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
         frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
@@ -413,7 +406,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             Instance::new(def_id, substs),
             dummy_body,
             ret.as_ref(),
-            StackPopCleanup::None { cleanup: false },
+            StackPopCleanup::Root { cleanup: false },
         )
         .expect("failed to push initial stack frame");
 
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index d346dfb1772..7320b2738a7 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -316,12 +316,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 LookupResult::Parent(Some(parent)) => {
                     let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent);
                     if maybe_dead {
-                        span_bug!(
+                        self.tcx.sess.delay_span_bug(
                             terminator.source_info.span,
-                            "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
-                            bb,
-                            place,
-                            path
+                            &format!(
+                                "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
+                                bb, place, path,
+                            ),
                         );
                     }
                     continue;
@@ -368,10 +368,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                             bb,
                         ),
                         LookupResult::Parent(..) => {
-                            span_bug!(
+                            self.tcx.sess.delay_span_bug(
                                 terminator.source_info.span,
-                                "drop of untracked value {:?}",
-                                bb
+                                &format!("drop of untracked value {:?}", bb),
                             );
                         }
                     }
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 6220cee8d21..bc9a104e849 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -243,7 +243,7 @@ impl<'tcx> TransformVisitor<'tcx> {
         val: Operand<'tcx>,
         source_info: SourceInfo,
     ) -> impl Iterator<Item = Statement<'tcx>> {
-        let kind = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None);
+        let kind = AggregateKind::Adt(self.state_adt_ref.did, idx, self.state_substs, None, None);
         assert_eq!(self.state_adt_ref.variants[idx].fields.len(), 1);
         let ty = self
             .tcx
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index d0039380361..58996dcd673 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -777,7 +777,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
         adt_def.variants[variant_index].fields.iter().enumerate().map(|(idx, field_def)| {
             (Operand::Move(Place::from(Local::new(idx + 1))), field_def.ty(tcx, substs))
         }),
-        AggregateKind::Adt(adt_def, variant_index, substs, None, None),
+        AggregateKind::Adt(adt_def.did, variant_index, substs, None, None),
         source_info,
         tcx,
     )
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index b1fa9041342..3e06e7f36d4 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -688,15 +688,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                     _ => bug!(),
                 }
             }
-            mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => {
-                let tcx = self.tcx;
-                let exchange_malloc_fn_def_id =
-                    tcx.require_lang_item(LangItem::ExchangeMalloc, None);
-                let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
-                if should_codegen_locally(tcx, &instance) {
-                    self.output.push(create_fn_mono_item(self.tcx, instance, span));
-                }
-            }
             mir::Rvalue::ThreadLocalRef(def_id) => {
                 assert!(self.tcx.is_thread_local_static(def_id));
                 let instance = Instance::mono(self.tcx, def_id);
@@ -1319,10 +1310,9 @@ fn create_mono_items_for_default_impls<'tcx>(
             if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
                 let param_env = ty::ParamEnv::reveal_all();
                 let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
-                let overridden_methods: FxHashSet<_> =
-                    impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect();
+                let overridden_methods = tcx.impl_item_implementor_ids(item.def_id);
                 for method in tcx.provided_trait_methods(trait_ref.def_id) {
-                    if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) {
+                    if overridden_methods.contains_key(&method.def_id) {
                         continue;
                     }
 
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 618aa3fd002..ade441b0e7d 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -27,7 +27,7 @@ impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main entry point for the parser.
     pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
         let (attrs, items, span) = self.parse_mod(&token::Eof)?;
-        Ok(ast::Crate { attrs, items, span, is_placeholder: None })
+        Ok(ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false })
     }
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
@@ -794,6 +794,44 @@ impl<'a> Parser<'a> {
         ))
     }
 
+    /// Emits an error that the where clause at the end of a type alias is not
+    /// allowed and suggests moving it.
+    fn error_ty_alias_where(
+        &self,
+        before_where_clause_present: bool,
+        before_where_clause_span: Span,
+        after_predicates: &[WherePredicate],
+        after_where_clause_span: Span,
+    ) {
+        let mut err =
+            self.struct_span_err(after_where_clause_span, "where clause not allowed here");
+        if !after_predicates.is_empty() {
+            let mut state = crate::pprust::State::new();
+            if !before_where_clause_present {
+                state.space();
+                state.word_space("where");
+            } else {
+                state.word_space(",");
+            }
+            let mut first = true;
+            for p in after_predicates.iter() {
+                if !first {
+                    state.word_space(",");
+                }
+                first = false;
+                state.print_where_predicate(p);
+            }
+            let suggestion = state.s.eof();
+            err.span_suggestion(
+                before_where_clause_span.shrink_to_hi(),
+                "move it here",
+                suggestion,
+                Applicability::MachineApplicable,
+            );
+        }
+        err.emit()
+    }
+
     /// Parses a `type` alias with the following grammar:
     /// ```
     /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
@@ -806,9 +844,24 @@ impl<'a> Parser<'a> {
         // Parse optional colon and param bounds.
         let bounds =
             if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
+
         generics.where_clause = self.parse_where_clause()?;
 
         let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
+
+        if self.token.is_keyword(kw::Where) {
+            let after_where_clause = self.parse_where_clause()?;
+
+            self.error_ty_alias_where(
+                generics.where_clause.has_where_token,
+                generics.where_clause.span,
+                &after_where_clause.predicates,
+                after_where_clause.span,
+            );
+
+            generics.where_clause.predicates.extend(after_where_clause.predicates.into_iter());
+        }
+
         self.expect_semi()?;
 
         Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty }))))
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index a5a65740707..b755f686f6a 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -93,26 +93,29 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
                     for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
                     {
                         if let ty::AssocItem {
-                            kind: ty::AssocKind::Fn, ident, defaultness, ..
-                        } = trait_item
+                            kind: ty::AssocKind::Fn,
+                            defaultness,
+                            def_id: trait_item_id,
+                            ..
+                        } = *trait_item
                         {
                             // we can ignore functions that do not have default bodies:
                             // if those are unimplemented it will be catched by typeck.
                             if !defaultness.has_value()
                                 || self
                                     .tcx
-                                    .has_attr(trait_item.def_id, sym::default_method_body_is_const)
+                                    .has_attr(trait_item_id, sym::default_method_body_is_const)
                             {
                                 continue;
                             }
 
                             let is_implemented = ancestors
-                                .leaf_def(self.tcx, trait_item.ident, trait_item.kind)
+                                .leaf_def(self.tcx, trait_item_id)
                                 .map(|node_item| !node_item.defining_node.is_from_trait())
                                 .unwrap_or(false);
 
                             if !is_implemented {
-                                to_implement.push(ident.to_string());
+                                to_implement.push(self.tcx.item_name(trait_item_id).to_string());
                             }
                         }
                     }
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 55ae808dc30..40d12c4a22d 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -4,7 +4,7 @@
 // and `#[unstable (..)]`), but are not declared in one single location
 // (unlike lang features), which means we need to collect them instead.
 
-use rustc_ast::{Attribute, MetaItem, MetaItemKind};
+use rustc_ast::{Attribute, MetaItemKind};
 use rustc_errors::struct_span_err;
 use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 use rustc_middle::hir::map::Map;
@@ -34,8 +34,8 @@ impl<'tcx> LibFeatureCollector<'tcx> {
         // Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`,
         // `#[rustc_const_unstable (..)]`).
         if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
-            let meta_item = attr.meta();
-            if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item {
+            let meta_kind = attr.meta_kind();
+            if let Some(MetaItemKind::List(ref metas)) = meta_kind {
                 let mut feature = None;
                 let mut since = None;
                 for meta in metas {
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 5f19991f9c7..c136411df27 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -794,19 +794,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     }
                 }
 
-                if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
-                    for impl_item_ref in items {
-                        let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
-                        let trait_item_def_id = self
-                            .tcx
-                            .associated_items(trait_did)
-                            .filter_by_name_unhygienic(impl_item.ident.name)
-                            .next()
-                            .map(|item| item.def_id);
-                        if let Some(def_id) = trait_item_def_id {
-                            // Pass `None` to skip deprecation warnings.
-                            self.tcx.check_stability(def_id, None, impl_item.span, None);
-                        }
+                for impl_item_ref in items {
+                    let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
+
+                    if let Some(def_id) = impl_item.trait_item_def_id {
+                        // Pass `None` to skip deprecation warnings.
+                        self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
                     }
                 }
             }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 10f6f6b1a9f..183a5a205ec 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -2064,7 +2064,11 @@ impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
             // Subitems of trait impls have inherited publicity.
             hir::ItemKind::Impl(ref impl_) => {
                 let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
-                self.check(item.def_id, impl_vis).generics().predicates();
+                // check that private components do not appear in the generics or predicates of inherent impls
+                // this check is intentionally NOT performed for impls of traits, per #90586
+                if impl_.of_trait.is_none() {
+                    self.check(item.def_id, impl_vis).generics().predicates();
+                }
                 for impl_item_ref in impl_.items {
                     let impl_item_vis = if impl_.of_trait.is_none() {
                         min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 11f54ea66fa..6a88e123537 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -495,6 +495,20 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
             .entry(index)
             .or_insert_with(|| {
                 let stable_id = file_index_to_stable_id[&index].translate(tcx);
+
+                // If this `SourceFile` is from a foreign crate, then make sure
+                // that we've imported all of the source files from that crate.
+                // This has usually already been done during macro invocation.
+                // However, when encoding query results like `TypeckResults`,
+                // we might encode an `AdtDef` for a foreign type (because it
+                // was referenced in the body of the function). There is no guarantee
+                // that we will load the source files from that crate during macro
+                // expansion, so we use `import_source_files` to ensure that the foreign
+                // source files are actually imported before we call `source_file_by_stable_id`.
+                if stable_id.cnum != LOCAL_CRATE {
+                    self.tcx.cstore_untracked().import_source_files(self.tcx.sess, stable_id.cnum);
+                }
+
                 source_map
                     .source_file_by_stable_id(stable_id)
                     .expect("failed to lookup `SourceFile` in new context")
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 19788a979ad..7c96f68ffb3 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -88,6 +88,11 @@ struct DepGraphData<K: DepKind> {
     previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
 
     dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
+
+    /// Used by incremental compilation tests to assert that
+    /// a particular query result was decoded from disk
+    /// (not just marked green)
+    debug_loaded_from_disk: Lock<FxHashSet<DepNode<K>>>,
 }
 
 pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint
@@ -135,6 +140,7 @@ impl<K: DepKind> DepGraph<K> {
                 processed_side_effects: Default::default(),
                 previous: prev_graph,
                 colors: DepNodeColorMap::new(prev_graph_node_count),
+                debug_loaded_from_disk: Default::default(),
             })),
             virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
         }
@@ -500,6 +506,14 @@ impl<K: DepKind> DepGraph<K> {
         &self.data.as_ref().unwrap().previous_work_products
     }
 
+    pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode<K>) {
+        self.data.as_ref().unwrap().debug_loaded_from_disk.lock().insert(dep_node);
+    }
+
+    pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode<K>) -> bool {
+        self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node)
+    }
+
     #[inline(always)]
     pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen: F)
     where
diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs
index 3a0aab81fdb..3117140a5b6 100644
--- a/compiler/rustc_query_system/src/ich/impls_hir.rs
+++ b/compiler/rustc_query_system/src/ich/impls_hir.rs
@@ -3,8 +3,7 @@
 
 use crate::ich::hcx::BodyResolver;
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
 use std::mem;
 
@@ -47,28 +46,6 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
         })
     }
 
-    #[inline]
-    fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) {
-        let hcx = self;
-        let hir::Mod { inner: ref inner_span, ref item_ids } = *module;
-
-        inner_span.hash_stable(hcx, hasher);
-
-        // Combining the `DefPathHash`s directly is faster than feeding them
-        // into the hasher. Because we use a commutative combine, we also don't
-        // have to sort the array.
-        let item_ids_hash = item_ids
-            .iter()
-            .map(|id| {
-                let def_path_hash = id.to_stable_hash_key(hcx);
-                def_path_hash.0
-            })
-            .fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b));
-
-        item_ids.len().hash_stable(hcx, hasher);
-        item_ids_hash.hash_stable(hcx, hasher);
-    }
-
     fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) {
         self.while_hashing_hir_bodies(true, |hcx| {
             let hir::Expr { hir_id: _, ref span, ref kind } = *expr;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 192da6735fc..da1f3617647 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -524,6 +524,10 @@ where
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
         if let Some(result) = result {
+            if unlikely!(tcx.dep_context().sess().opts.debugging_opts.query_dep_graph) {
+                dep_graph.mark_debug_loaded_from_disk(*dep_node)
+            }
+
             let prev_fingerprint = tcx
                 .dep_context()
                 .dep_graph()
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 74edc3a2d5e..39074f811a5 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1016,10 +1016,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 self.insert_field_names(def_id, field_names);
             }
             Res::Def(DefKind::AssocFn, def_id) => {
-                if cstore
-                    .associated_item_cloned_untracked(def_id, self.r.session)
-                    .fn_has_self_parameter
-                {
+                if cstore.fn_has_self_parameter_untracked(def_id) {
                     self.r.has_self.insert(def_id);
                 }
             }
@@ -1515,8 +1512,8 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
     }
 
     fn visit_crate(&mut self, krate: &'b ast::Crate) {
-        if let Some(id) = krate.is_placeholder {
-            self.visit_invoc_in_module(id);
+        if krate.is_placeholder {
+            self.visit_invoc_in_module(krate.id);
         } else {
             visit::walk_crate(self, krate);
             self.contains_macro_use(&krate.attrs);
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 688b7b1a8c6..8ea5dca6f10 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -344,8 +344,8 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
     }
 
     fn visit_crate(&mut self, krate: &'a Crate) {
-        if let Some(id) = krate.is_placeholder {
-            self.visit_macro_invoc(id)
+        if krate.is_placeholder {
+            self.visit_macro_invoc(krate.id)
         } else {
             visit::walk_crate(self, krate)
         }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index babfa8015af..4feeae5cab1 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -895,8 +895,11 @@ impl<'a> Resolver<'a> {
                             // a note about editions
                             let note = if let Some(did) = did {
                                 let requires_note = !did.is_local()
-                                    && this.cstore().item_attrs(did, this.session).iter().any(
-                                        |attr| {
+                                    && this
+                                        .cstore()
+                                        .item_attrs_untracked(did, this.session)
+                                        .iter()
+                                        .any(|attr| {
                                             if attr.has_name(sym::rustc_diagnostic_item) {
                                                 [sym::TryInto, sym::TryFrom, sym::FromIterator]
                                                     .map(|x| Some(x))
@@ -904,8 +907,7 @@ impl<'a> Resolver<'a> {
                                             } else {
                                                 false
                                             }
-                                        },
-                                    );
+                                        });
 
                                 requires_note.then(|| {
                                     format!(
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 12123c946cc..57305023138 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1603,10 +1603,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         pat_src: PatternSource,
         bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
     ) {
+        // We walk the pattern before declaring the pattern's inner bindings,
+        // so that we avoid resolving a literal expression to a binding defined
+        // by the pattern.
+        visit::walk_pat(self, pat);
         self.resolve_pattern_inner(pat, pat_src, bindings);
         // This has to happen *after* we determine which pat_idents are variants:
         self.check_consistent_bindings_top(pat);
-        visit::walk_pat(self, pat);
     }
 
     /// Resolve bindings in a pattern. This is a helper to `resolve_pattern`.
@@ -2376,7 +2379,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             ExprKind::While(ref cond, ref block, label) => {
                 self.with_resolved_label(label, expr.id, |this| {
                     this.with_rib(ValueNS, NormalRibKind, |this| {
+                        let old = this.diagnostic_metadata.in_if_condition.replace(cond);
                         this.visit_expr(cond);
+                        this.diagnostic_metadata.in_if_condition = old;
                         this.visit_block(block);
                     })
                 });
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index e74a7a95650..4cd1b34bedc 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2115,10 +2115,13 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                 let spans_suggs: Vec<_> = formatters
                     .into_iter()
                     .zip(spans_with_counts.iter())
-                    .filter_map(|(fmt, (span, _))| {
-                        if let Some(formatter) = fmt { Some((formatter, span)) } else { None }
+                    .filter_map(|(formatter, (span, _))| {
+                        if let Some(formatter) = formatter {
+                            Some((*span, formatter(name)))
+                        } else {
+                            None
+                        }
                     })
-                    .map(|(formatter, span)| (*span, formatter(name)))
                     .collect();
                 if spans_suggs.is_empty() {
                     // If all the spans come from macros, we cannot extract snippets and then
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 84ce492ba72..b46a93c0673 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -68,7 +68,7 @@ use smallvec::{smallvec, SmallVec};
 use std::cell::{Cell, RefCell};
 use std::collections::{BTreeMap, BTreeSet};
 use std::ops::ControlFlow;
-use std::{cmp, fmt, iter, ptr};
+use std::{cmp, fmt, iter, mem, ptr};
 use tracing::debug;
 
 use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding};
@@ -1394,7 +1394,7 @@ impl<'a> Resolver<'a> {
                 .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
                 .collect(),
             lint_buffer: LintBuffer::default(),
-            next_node_id: NodeId::from_u32(1),
+            next_node_id: CRATE_NODE_ID,
             node_id_to_def_id,
             def_id_to_node_id,
             placeholder_field_indices: Default::default(),
@@ -1430,8 +1430,7 @@ impl<'a> Resolver<'a> {
     pub fn next_node_id(&mut self) -> NodeId {
         let next =
             self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
-        self.next_node_id = ast::NodeId::from_u32(next);
-        self.next_node_id
+        mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next))
     }
 
     pub fn lint_buffer(&mut self) -> &mut LintBuffer {
@@ -3419,27 +3418,21 @@ impl<'a> Resolver<'a> {
                     return v.clone();
                 }
 
-                let parse_attrs = || {
-                    let attrs = self.cstore().item_attrs(def_id, self.session);
-                    let attr =
-                        attrs.iter().find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
-                    let mut ret = vec![];
-                    for meta in attr.meta_item_list()? {
-                        match meta.literal()?.kind {
-                            LitKind::Int(a, _) => {
-                                ret.push(a as usize);
-                            }
-                            _ => panic!("invalid arg index"),
-                        }
+                let attr = self
+                    .cstore()
+                    .item_attrs_untracked(def_id, self.session)
+                    .into_iter()
+                    .find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
+                let mut ret = Vec::new();
+                for meta in attr.meta_item_list()? {
+                    match meta.literal()?.kind {
+                        LitKind::Int(a, _) => ret.push(a as usize),
+                        _ => panic!("invalid arg index"),
                     }
-                    Some(ret)
-                };
-
-                // Cache the lookup to avoid parsing attributes for an iterm
-                // multiple times.
-                let ret = parse_attrs();
-                self.legacy_const_generic_args.insert(def_id, ret.clone());
-                return ret;
+                }
+                // Cache the lookup to avoid parsing attributes for an iterm multiple times.
+                self.legacy_const_generic_args.insert(def_id, Some(ret.clone()));
+                return Some(ret);
             }
         }
         None
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index f1a5282b088..23f5b17fa78 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -1326,12 +1326,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 }
                 intravisit::walk_qpath(self, path, t.hir_id, t.span);
             }
-            hir::TyKind::Array(ref ty, ref anon_const) => {
+            hir::TyKind::Array(ref ty, ref length) => {
                 self.visit_ty(ty);
                 let map = self.tcx.hir();
-                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
-                    v.visit_expr(&map.body(anon_const.body).value)
-                });
+                match length {
+                    // FIXME(generic_arg_infer): We probably want to
+                    // output the inferred type here? :shrug:
+                    hir::ArrayLen::Infer(..) => {}
+                    hir::ArrayLen::Body(anon_const) => self
+                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                            v.visit_expr(&map.body(anon_const.body).value)
+                        }),
+                }
             }
             hir::TyKind::OpaqueDef(item_id, _) => {
                 let item = self.tcx.hir().item(item_id);
@@ -1390,12 +1396,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                     v.visit_expr(&body.value)
                 });
             }
-            hir::ExprKind::Repeat(ref expr, ref anon_const) => {
+            hir::ExprKind::Repeat(ref expr, ref length) => {
                 self.visit_expr(expr);
                 let map = self.tcx.hir();
-                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
-                    v.visit_expr(&map.body(anon_const.body).value)
-                });
+                match length {
+                    // FIXME(generic_arg_infer): We probably want to
+                    // output the inferred type here? :shrug:
+                    hir::ArrayLen::Infer(..) => {}
+                    hir::ArrayLen::Body(anon_const) => self
+                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                            v.visit_expr(&map.body(anon_const.body).value)
+                        }),
+                }
             }
             // In particular, we take this branch for call and path expressions,
             // where we'll index the idents involved just by continuing to walk.
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 7ec619e07ff..a83f0230814 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -710,13 +710,11 @@ impl<'tcx> SaveContext<'tcx> {
             }
             Res::Def(HirDefKind::AssocFn, decl_id) => {
                 let def_id = if decl_id.is_local() {
-                    let ti = self.tcx.associated_item(decl_id);
-
-                    self.tcx
-                        .associated_items(ti.container.id())
-                        .filter_by_name_unhygienic(ti.ident.name)
-                        .find(|item| item.defaultness.has_value())
-                        .map(|item| item.def_id)
+                    if self.tcx.associated_item(decl_id).defaultness.has_value() {
+                        Some(decl_id)
+                    } else {
+                        None
+                    }
                 } else {
                     None
                 };
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index e43344ad6d9..4971bb6d1aa 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -310,9 +310,9 @@ impl<'hir> Sig for hir::Ty<'hir> {
                 let nested = bounds_to_string(&bounds);
                 Ok(text_sig(nested))
             }
-            hir::TyKind::Array(ref ty, ref anon_const) => {
+            hir::TyKind::Array(ref ty, ref length) => {
                 let nested_ty = ty.make(offset + 1, id, scx)?;
-                let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " ");
+                let expr = id_to_string(&scx.tcx.hir(), length.hir_id()).replace('\n', " ");
                 let text = format!("[{}; {}]", nested_ty.text, expr);
                 Ok(replace_text(nested_ty, text))
             }
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index cc1216418ae..f2ef1481681 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -92,7 +92,8 @@ impl serialize::Encoder for Encoder {
 
     #[inline]
     fn emit_u16(&mut self, v: u16) -> EncodeResult {
-        write_leb128!(self, v, u16, write_u16_leb128)
+        self.data.extend_from_slice(&v.to_le_bytes());
+        Ok(())
     }
 
     #[inline]
@@ -123,7 +124,8 @@ impl serialize::Encoder for Encoder {
 
     #[inline]
     fn emit_i16(&mut self, v: i16) -> EncodeResult {
-        write_leb128!(self, v, i16, write_i16_leb128)
+        self.data.extend_from_slice(&v.to_le_bytes());
+        Ok(())
     }
 
     #[inline]
@@ -446,7 +448,7 @@ impl serialize::Encoder for FileEncoder {
 
     #[inline]
     fn emit_u16(&mut self, v: u16) -> FileEncodeResult {
-        file_encoder_write_leb128!(self, v, u16, write_u16_leb128)
+        self.write_all(&v.to_le_bytes())
     }
 
     #[inline]
@@ -476,13 +478,12 @@ impl serialize::Encoder for FileEncoder {
 
     #[inline]
     fn emit_i16(&mut self, v: i16) -> FileEncodeResult {
-        file_encoder_write_leb128!(self, v, i16, write_i16_leb128)
+        self.write_all(&v.to_le_bytes())
     }
 
     #[inline]
     fn emit_i8(&mut self, v: i8) -> FileEncodeResult {
-        let as_u8: u8 = unsafe { std::mem::transmute(v) };
-        self.emit_u8(as_u8)
+        self.emit_u8(v as u8)
     }
 
     #[inline]
@@ -591,7 +592,10 @@ impl<'a> serialize::Decoder for Decoder<'a> {
 
     #[inline]
     fn read_u16(&mut self) -> Result<u16, Self::Error> {
-        read_leb128!(self, read_u16_leb128)
+        let bytes = [self.data[self.position], self.data[self.position + 1]];
+        let value = u16::from_le_bytes(bytes);
+        self.position += 2;
+        Ok(value)
     }
 
     #[inline]
@@ -623,7 +627,10 @@ impl<'a> serialize::Decoder for Decoder<'a> {
 
     #[inline]
     fn read_i16(&mut self) -> Result<i16, Self::Error> {
-        read_leb128!(self, read_i16_leb128)
+        let bytes = [self.data[self.position], self.data[self.position + 1]];
+        let value = i16::from_le_bytes(bytes);
+        self.position += 2;
+        Ok(value)
     }
 
     #[inline]
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index de5ff231d61..62b351f5e02 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -231,6 +231,37 @@ pub enum DebugInfo {
     Full,
 }
 
+/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
+/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
+/// uses DWARF for debug-information.
+///
+/// Some debug-information requires link-time relocation and some does not. LLVM can partition
+/// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
+/// DWARF provides a mechanism which allows the linker to skip the sections which don't require
+/// link-time relocation - either by putting those sections in DWARF object files, or by keeping
+/// them in the object file in such a way that the linker will skip them.
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+pub enum SplitDwarfKind {
+    /// Sections which do not require relocation are written into object file but ignored by the
+    /// linker.
+    Single,
+    /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
+    /// which is ignored by the linker.
+    Split,
+}
+
+impl FromStr for SplitDwarfKind {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, ()> {
+        Ok(match s {
+            "single" => SplitDwarfKind::Single,
+            "split" => SplitDwarfKind::Split,
+            _ => return Err(()),
+        })
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
 #[derive(Encodable, Decodable)]
 pub enum OutputType {
@@ -378,7 +409,7 @@ impl OutputTypes {
         self.0.len()
     }
 
-    // Returns `true` if any of the output types require codegen or linking.
+    /// Returns `true` if any of the output types require codegen or linking.
     pub fn should_codegen(&self) -> bool {
         self.0.keys().any(|k| match *k {
             OutputType::Bitcode
@@ -391,7 +422,7 @@ impl OutputTypes {
         })
     }
 
-    // Returns `true` if any of the output types require linking.
+    /// Returns `true` if any of the output types require linking.
     pub fn should_link(&self) -> bool {
         self.0.keys().any(|k| match *k {
             OutputType::Bitcode
@@ -681,18 +712,23 @@ impl OutputFilenames {
     pub fn split_dwarf_path(
         &self,
         split_debuginfo_kind: SplitDebuginfo,
+        split_dwarf_kind: SplitDwarfKind,
         cgu_name: Option<&str>,
     ) -> Option<PathBuf> {
         let obj_out = self.temp_path(OutputType::Object, cgu_name);
         let dwo_out = self.temp_path_dwo(cgu_name);
-        match split_debuginfo_kind {
-            SplitDebuginfo::Off => None,
+        match (split_debuginfo_kind, split_dwarf_kind) {
+            (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
             // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
             // (pointing at the path which is being determined here). Use the path to the current
             // object file.
-            SplitDebuginfo::Packed => Some(obj_out),
+            (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
+                Some(obj_out)
+            }
             // Split mode emits the DWARF into a different file, use that path.
-            SplitDebuginfo::Unpacked => Some(dwo_out),
+            (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
+                Some(dwo_out)
+            }
         }
     }
 }
@@ -781,6 +817,10 @@ impl Options {
             },
         }
     }
+
+    pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
+        self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
+    }
 }
 
 impl DebuggingOptions {
@@ -794,10 +834,6 @@ impl DebuggingOptions {
             deduplicate_diagnostics: self.deduplicate_diagnostics,
         }
     }
-
-    pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
-        self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
-    }
 }
 
 // The type of entry function, so users can have their own entry functions
@@ -821,6 +857,18 @@ pub enum CrateType {
 
 impl_stable_hash_via_hash!(CrateType);
 
+impl CrateType {
+    /// When generated, is this crate type an archive?
+    pub fn is_archive(&self) -> bool {
+        match *self {
+            CrateType::Rlib | CrateType::Staticlib => true,
+            CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
+                false
+            }
+        }
+    }
+}
+
 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum Passes {
     Some(Vec<String>),
@@ -843,6 +891,30 @@ impl Passes {
     }
 }
 
+#[derive(Clone, Copy, Hash, Debug, PartialEq)]
+pub enum PAuthKey {
+    A,
+    B,
+}
+
+#[derive(Clone, Copy, Hash, Debug, PartialEq)]
+pub struct PacRet {
+    pub leaf: bool,
+    pub key: PAuthKey,
+}
+
+#[derive(Clone, Copy, Hash, Debug, PartialEq)]
+pub struct BranchProtection {
+    pub bti: bool,
+    pub pac_ret: Option<PacRet>,
+}
+
+impl Default for BranchProtection {
+    fn default() -> Self {
+        BranchProtection { bti: false, pac_ret: None }
+    }
+}
+
 pub const fn default_lib_output() -> CrateType {
     CrateType::Rlib
 }
@@ -2092,6 +2164,34 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         );
     }
 
+    // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
+    // precedence.
+    match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) {
+        (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
+            early_error(
+                error_format,
+                "incompatible values passed for `-C symbol-mangling-version` \
+                and `-Z symbol-mangling-version`",
+            );
+        }
+        (Some(SymbolManglingVersion::V0), _) => {}
+        (Some(_), _) if !debugging_opts.unstable_options => {
+            early_error(
+                error_format,
+                "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
+            );
+        }
+        (None, None) => {}
+        (None, smv) => {
+            early_warn(
+                error_format,
+                "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
+            );
+            cg.symbol_mangling_version = smv;
+        }
+        _ => {}
+    }
+
     if debugging_opts.instrument_coverage.is_some()
         && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
     {
@@ -2103,19 +2203,17 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
             );
         }
 
-        // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
+        // `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
         // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
         // multiple runs, including some changes to source code; so mangled names must be consistent
         // across compilations.
-        match debugging_opts.symbol_mangling_version {
-            None => {
-                debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
-            }
+        match cg.symbol_mangling_version {
+            None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
             Some(SymbolManglingVersion::Legacy) => {
                 early_warn(
                     error_format,
                     "-Z instrument-coverage requires symbol mangling version `v0`, \
-                    but `-Z symbol-mangling-version=legacy` was specified",
+                    but `-C symbol-mangling-version=legacy` was specified",
                 );
             }
             Some(SymbolManglingVersion::V0) => {}
@@ -2497,9 +2595,9 @@ impl PpMode {
 crate mod dep_tracking {
     use super::LdImpl;
     use super::{
-        CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
-        LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
-        SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
+        BranchProtection, CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage,
+        LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes,
+        SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
     };
     use crate::lint;
     use crate::options::WasiExecModel;
@@ -2593,6 +2691,7 @@ crate mod dep_tracking {
         OutputType,
         RealFileName,
         LocationDetail,
+        BranchProtection,
     );
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index 59e7abc2ea3..281fc887633 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -201,6 +201,12 @@ pub trait CrateStore: std::fmt::Debug {
         index_guess: u32,
         hash: ExpnHash,
     ) -> ExpnId;
+
+    /// Imports all `SourceFile`s from the given crate into the current session.
+    /// This normally happens automatically when we decode a `Span` from
+    /// that crate's metadata - however, the incr comp cache needs
+    /// to trigger this manually when decoding a foreign `Span`
+    fn import_source_files(&self, sess: &Session, cnum: CrateNum);
 }
 
 pub type CrateStoreDyn = dyn CrateStore + sync::Sync;
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 9090524c933..0b9623d1c7d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -412,9 +412,13 @@ mod desc {
     pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
     pub const parse_split_debuginfo: &str =
         "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
+    pub const parse_split_dwarf_kind: &str =
+        "one of supported split dwarf modes (`split` or `single`)";
     pub const parse_gcc_ld: &str = "one of: no value, `lld`";
     pub const parse_stack_protector: &str =
         "one of (`none` (default), `basic`, `strong`, or `all`)";
+    pub const parse_branch_protection: &str =
+        "a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`";
 }
 
 mod parse {
@@ -939,6 +943,14 @@ mod parse {
         true
     }
 
+    crate fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
+        match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) {
+            Some(e) => *slot = e,
+            _ => return false,
+        }
+        true
+    }
+
     crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
         match v {
             None => *slot = None,
@@ -955,6 +967,32 @@ mod parse {
         }
         true
     }
+
+    crate fn parse_branch_protection(slot: &mut BranchProtection, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                for opt in s.split(',') {
+                    match opt {
+                        "bti" => slot.bti = true,
+                        "pac-ret" if slot.pac_ret.is_none() => {
+                            slot.pac_ret = Some(PacRet { leaf: false, key: PAuthKey::A })
+                        }
+                        "leaf" => match slot.pac_ret.as_mut() {
+                            Some(pac) => pac.leaf = true,
+                            _ => return false,
+                        },
+                        "b-key" => match slot.pac_ret.as_mut() {
+                            Some(pac) => pac.key = PAuthKey::B,
+                            _ => return false,
+                        },
+                        _ => return false,
+                    };
+                }
+            }
+            _ => return false,
+        }
+        true
+    }
 }
 
 options! {
@@ -1055,6 +1093,9 @@ options! {
         "how to handle split-debuginfo, a platform-specific option"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
+    symbol_mangling_version: Option<SymbolManglingVersion> = (None,
+        parse_symbol_mangling_version, [TRACKED],
+        "which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
     target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
         "select target processor (`rustc --print target-cpus` for details)"),
     target_feature: String = (String::new(), parse_target_feature, [TRACKED],
@@ -1096,6 +1137,8 @@ options! {
         (default: no)"),
     borrowck: String = ("migrate".to_string(), parse_string, [UNTRACKED],
         "select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"),
+    branch_protection: BranchProtection = (BranchProtection::default(), parse_branch_protection, [TRACKED],
+        "set options for branch target identification and pointer authentication on AArch64"),
     cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED],
         "the codegen unit partitioning strategy to use"),
     chalk: bool = (false, parse_bool, [TRACKED],
@@ -1197,7 +1240,7 @@ options! {
     instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
         "instrument the generated code to support LLVM source-based code coverage \
         reports (note, the compiler build config must include `profiler = true`); \
-        implies `-Z symbol-mangling-version=v0`. Optional values are:
+        implies `-C symbol-mangling-version=v0`. Optional values are:
         `=all` (implicit value)
         `=except-unused-generics`
         `=except-unused-functions`
@@ -1370,6 +1413,14 @@ options! {
         "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
+    split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED],
+        "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
+        (default: `split`)
+
+        `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
+                 file which is ignored by the linker
+        `single`: sections which do not require relocation are written into object file but ignored
+                  by the linker"),
     split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
         "provide minimal debug info in the object/executable to facilitate online \
          symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index d15befbf287..24d2a8ac073 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -136,8 +136,8 @@ impl Borrow<Fingerprint> for DefPathHash {
 /// collisions when loading crates and abort compilation in order to avoid
 /// further trouble.
 ///
-/// See the discussion in [`DefId`] for more information
-/// on the possibility of hash collisions in rustc,
+/// For more information on the possibility of hash collisions in rustc,
+/// see the discussion in [`DefId`].
 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub struct StableCrateId(pub(crate) u64);
@@ -316,17 +316,23 @@ impl fmt::Debug for DefId {
 
 rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId);
 
-/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
+/// A `LocalDefId` is equivalent to a `DefId` with `krate == LOCAL_CRATE`. Since
 /// we encode this information in the type, we can ensure at compile time that
-/// no DefIds from upstream crates get thrown into the mix. There are quite a
-/// few cases where we know that only DefIds from the local crate are expected
-/// and a DefId from a different crate would signify a bug somewhere. This
-/// is when LocalDefId comes in handy.
+/// no `DefId`s from upstream crates get thrown into the mix. There are quite a
+/// few cases where we know that only `DefId`s from the local crate are expected;
+/// a `DefId` from a different crate would signify a bug somewhere. This
+/// is when `LocalDefId` comes in handy.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct LocalDefId {
     pub local_def_index: DefIndex,
 }
 
+// To ensure correctness of incremental compilation,
+// `LocalDefId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for LocalDefId {}
+impl !PartialOrd for LocalDefId {}
+
 pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX };
 
 impl Idx for LocalDefId {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 51a7a2644f6..84cf8878af8 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -788,6 +788,7 @@ symbols! {
         literal,
         llvm_asm,
         load,
+        loaded_from_disk,
         local,
         local_inner_macros,
         log10f32,
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 65b5852bc39..1f38240ee41 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -237,7 +237,7 @@ fn compute_symbol_name<'tcx>(
 
     // Pick the crate responsible for the symbol mangling version, which has to:
     // 1. be stable for each instance, whether it's being defined or imported
-    // 2. obey each crate's own `-Z symbol-mangling-version`, as much as possible
+    // 2. obey each crate's own `-C symbol-mangling-version`, as much as possible
     // We solve these as follows:
     // 1. because symbol names depend on both `def_id` and `instantiating_crate`,
     // both their `CrateNum`s are stable for any given instance, so we can pick
@@ -245,7 +245,7 @@ fn compute_symbol_name<'tcx>(
     // 2. we favor `instantiating_crate` where possible (i.e. when `Some`)
     let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate);
     let mangling_version = if mangling_version_crate == LOCAL_CRATE {
-        tcx.sess.opts.debugging_opts.get_symbol_mangling_version()
+        tcx.sess.opts.get_symbol_mangling_version()
     } else {
         tcx.symbol_mangling_version(mangling_version_crate)
     };
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 43913183694..ca1949b9f75 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -479,7 +479,7 @@ pub enum SplitDebuginfo {
     ///
     /// * Windows - not supported
     /// * macOS - supported, scattered object files
-    /// * ELF - supported, scattered `*.dwo` files
+    /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`)
     Unpacked,
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 53ff911ea0c..05d2a373dc6 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -839,7 +839,17 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                         _ => return false,
                     }
                 }
-                _ => panic!("Unexpected predicate {:?} {:?}", ty, predicate),
+                // There's not really much we can do with these predicates -
+                // we start out with a `ParamEnv` with no inference variables,
+                // and these don't correspond to adding any new bounds to
+                // the `ParamEnv`.
+                ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
             };
         }
         true
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index b5c5724f56e..a9ae0ec53c7 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1567,14 +1567,14 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
             self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some)
         };
         let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
-        let all_traits = self.tcx.all_traits(());
-        let traits_with_same_path: std::collections::BTreeSet<_> = all_traits
-            .iter()
-            .filter(|trait_def_id| **trait_def_id != trait_ref.def_id())
-            .filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path)
+        let traits_with_same_path: std::collections::BTreeSet<_> = self
+            .tcx
+            .all_traits()
+            .filter(|trait_def_id| *trait_def_id != trait_ref.def_id())
+            .filter(|trait_def_id| self.tcx.def_path_str(*trait_def_id) == required_trait_path)
             .collect();
         for trait_with_same_path in traits_with_same_path {
-            if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) {
+            if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) {
                 let impl_span = self.tcx.def_span(impl_def_id);
                 err.span_help(impl_span, "trait impl with same name found");
                 let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 23f615a9618..51bd505366c 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1883,7 +1883,6 @@ fn assoc_ty_def(
     assoc_ty_def_id: DefId,
 ) -> Result<specialization_graph::LeafDef, ErrorReported> {
     let tcx = selcx.tcx();
-    let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident;
     let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
     let trait_def = tcx.trait_def(trait_def_id);
 
@@ -1893,21 +1892,18 @@ fn assoc_ty_def(
     // for the associated item at the given impl.
     // If there is no such item in that impl, this function will fail with a
     // cycle error if the specialization graph is currently being built.
-    let impl_node = specialization_graph::Node::Impl(impl_def_id);
-    for item in impl_node.items(tcx) {
-        if matches!(item.kind, ty::AssocKind::Type)
-            && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
-        {
-            return Ok(specialization_graph::LeafDef {
-                item: *item,
-                defining_node: impl_node,
-                finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
-            });
-        }
+    if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_ty_def_id) {
+        let item = tcx.associated_item(impl_item_id);
+        let impl_node = specialization_graph::Node::Impl(impl_def_id);
+        return Ok(specialization_graph::LeafDef {
+            item: *item,
+            defining_node: impl_node,
+            finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
+        });
     }
 
     let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
-    if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) {
+    if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_def_id) {
         Ok(assoc_item)
     } else {
         // This is saying that neither the trait nor
@@ -1916,7 +1912,11 @@ fn assoc_ty_def(
         // could only arise through a compiler bug --
         // if the user wrote a bad item name, it
         // should have failed in astconv.
-        bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id))
+        bug!(
+            "No associated type `{}` for {}",
+            tcx.item_name(assoc_ty_def_id),
+            tcx.def_path_str(impl_def_id)
+        )
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index e9b368f683e..b7fc578ea3b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -8,6 +8,7 @@
 //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::Constness;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
@@ -51,6 +52,38 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         candidate: SelectionCandidate<'tcx>,
     ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
+        let mut obligation = obligation;
+        let new_obligation;
+
+        // HACK(const_trait_impl): the surrounding environment is remapped to a non-const context
+        // because nested obligations might be actually `~const` then (incorrectly) requiring
+        // const impls. for example:
+        // ```
+        // pub trait Super {}
+        // pub trait Sub: Super {}
+        //
+        // impl<A> const Super for &A where A: ~const Super {}
+        // impl<A> const Sub for &A where A: ~const Sub {}
+        // ```
+        //
+        // The procedure to check the code above without the remapping code is as follows:
+        // ```
+        // CheckWf(impl const Sub for &A where A: ~const Sub) // <- const env
+        // CheckPredicate(&A: Super)
+        // CheckPredicate(A: ~const Super) // <- still const env, failure
+        // ```
+        if obligation.param_env.constness() == Constness::Const
+            && obligation.predicate.skip_binder().constness == ty::BoundConstness::NotConst
+        {
+            new_obligation = TraitObligation {
+                cause: obligation.cause.clone(),
+                param_env: obligation.param_env.without_const(),
+                ..*obligation
+            };
+
+            obligation = &new_obligation;
+        }
+
         match candidate {
             BuiltinCandidate { has_nested } => {
                 let data = self.confirm_builtin_candidate(obligation, has_nested);
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 4bd73ef68aa..72ffe9085cb 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -197,14 +197,13 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
     item: Option<&hir::Item<'tcx>>,
     cause: &mut traits::ObligationCause<'tcx>,
     pred: &ty::Predicate<'tcx>,
-    mut trait_assoc_items: impl Iterator<Item = &'tcx ty::AssocItem>,
 ) {
     debug!(
         "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}",
         trait_ref, item, cause, pred
     );
-    let items = match item {
-        Some(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.items,
+    let (items, impl_def_id) = match item {
+        Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id),
         _ => return,
     };
     let fix_span =
@@ -222,11 +221,16 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
             // `traits-assoc-type-in-supertrait-bad.rs`.
             if let ty::Projection(projection_ty) = proj.ty.kind() {
-                let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id);
-                if let Some(impl_item_span) =
-                    items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span)
+                if let Some(&impl_item_id) =
+                    tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
                 {
-                    cause.span = impl_item_span;
+                    if let Some(impl_item_span) = items
+                        .iter()
+                        .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+                        .map(fix_span)
+                    {
+                        cause.span = impl_item_span;
+                    }
                 }
             }
         }
@@ -235,13 +239,16 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
             debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
             if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind() {
-                if let Some(impl_item_span) = trait_assoc_items
-                    .find(|i| i.def_id == item_def_id)
-                    .and_then(|trait_assoc_item| {
-                        items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span)
-                    })
+                if let Some(&impl_item_id) =
+                    tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id)
                 {
-                    cause.span = impl_item_span;
+                    if let Some(impl_item_span) = items
+                        .iter()
+                        .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+                        .map(fix_span)
+                    {
+                        cause.span = impl_item_span;
+                    }
                 }
             }
         }
@@ -312,7 +319,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                 item,
                 &mut cause,
                 &obligation.predicate,
-                tcx.associated_items(trait_ref.def_id).in_definition_order(),
             );
             traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate)
         };
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 1b79e537634..3f51442277f 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -436,23 +436,13 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
     ) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
         let def_id = associated_ty_id.0;
         let assoc_item = self.interner.tcx.associated_item(def_id);
-        let (impl_id, trait_id) = match assoc_item.container {
-            AssocItemContainer::TraitContainer(def_id) => (def_id, def_id),
-            AssocItemContainer::ImplContainer(def_id) => {
-                (def_id, self.interner.tcx.impl_trait_ref(def_id).unwrap().def_id)
-            }
-        };
+        let impl_id = assoc_item.container.id();
         match assoc_item.kind {
             AssocKind::Type => {}
             _ => unimplemented!("Not possible??"),
         }
 
-        let trait_item = self
-            .interner
-            .tcx
-            .associated_items(trait_id)
-            .find_by_name_and_kind(self.interner.tcx, assoc_item.ident, assoc_item.kind, trait_id)
-            .unwrap();
+        let trait_item_id = assoc_item.trait_item_def_id.expect("assoc_ty with no trait version");
         let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
         let binders = binders_for(self.interner, bound_vars);
         let ty = self
@@ -464,7 +454,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
 
         Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
             impl_id: chalk_ir::ImplId(impl_id),
-            associated_ty_id: chalk_ir::AssocTypeId(trait_item.def_id),
+            associated_ty_id: chalk_ir::AssocTypeId(trait_item_id),
             value: chalk_ir::Binders::new(
                 binders,
                 chalk_solve::rust_ir::AssociatedTyValueBound { ty },
@@ -724,7 +714,7 @@ impl<'tcx> chalk_ir::UnificationDatabase<RustInterner<'tcx>> for RustIrDatabase<
 /// var bound at index `0`. For types, we use a `BoundVar` index equal to
 /// the type parameter index. For regions, we use the `BoundRegionKind::BrNamed`
 /// variant (which has a `DefId`).
-fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
+fn bound_vars_for_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
     InternalSubsts::for_item(tcx, def_id, |param, substs| match param.kind {
         ty::GenericParamDefKind::Type { .. } => tcx
             .mk_ty(ty::Bound(
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 92f2760e62c..90c698db8fb 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -138,7 +138,7 @@ fn compute_implied_outlives_bounds<'tcx>(
 /// this down to determine what relationships would have to hold for
 /// `T: 'a` to hold. We get to assume that the caller has validated
 /// those relationships.
-fn implied_bounds_from_components(
+fn implied_bounds_from_components<'tcx>(
     sub_region: ty::Region<'tcx>,
     sup_components: SmallVec<[Component<'tcx>; 4]>,
 ) -> Vec<OutlivesBound<'tcx>> {
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 8612499623b..b814b984dae 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -2,7 +2,6 @@
 //! the guts are broken up into modules; see the comments in those modules.
 
 #![feature(crate_visibility_modifier)]
-#![feature(in_band_lifetimes)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 87530cf9961..46c2f7e4cf2 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -57,7 +57,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq +
     })
 }
 
-fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
+fn not_outlives_predicate<'tcx>(p: &ty::Predicate<'tcx>) -> bool {
     match p.kind().skip_binder() {
         ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
         ty::PredicateKind::Trait(..)
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index cc0b7d5817b..6fcac9fcdc6 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -70,7 +70,7 @@ struct AscribeUserTypeCx<'me, 'tcx> {
     fulfill_cx: &'me mut dyn TraitEngine<'tcx>,
 }
 
-impl AscribeUserTypeCx<'me, 'tcx> {
+impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
     fn normalize<T>(&mut self, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
@@ -195,7 +195,7 @@ fn type_op_eq<'tcx>(
     })
 }
 
-fn type_op_normalize<T>(
+fn type_op_normalize<'tcx, T>(
     infcx: &InferCtxt<'_, 'tcx>,
     fulfill_cx: &mut dyn TraitEngine<'tcx>,
     key: ParamEnvAnd<'tcx, Normalize<T>>,
@@ -210,28 +210,28 @@ where
     Ok(value)
 }
 
-fn type_op_normalize_ty(
+fn type_op_normalize_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Ty<'tcx>>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, NoSolution> {
     tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
 
-fn type_op_normalize_predicate(
+fn type_op_normalize_predicate<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Predicate<'tcx>>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Predicate<'tcx>>>, NoSolution> {
     tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
 
-fn type_op_normalize_fn_sig(
+fn type_op_normalize_fn_sig<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<FnSig<'tcx>>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, FnSig<'tcx>>>, NoSolution> {
     tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
 
-fn type_op_normalize_poly_fn_sig(
+fn type_op_normalize_poly_fn_sig<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<PolyFnSig<'tcx>>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, PolyFnSig<'tcx>>>, NoSolution> {
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
new file mode 100644
index 00000000000..b1d47f6c29a
--- /dev/null
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -0,0 +1,239 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+
+pub fn provide(providers: &mut ty::query::Providers) {
+    *providers = ty::query::Providers {
+        associated_item,
+        associated_item_def_ids,
+        associated_items,
+        impl_item_implementor_ids,
+        trait_of_item,
+        ..*providers
+    };
+}
+
+fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
+    let item = tcx.hir().expect_item(def_id.expect_local());
+    match item.kind {
+        hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
+            trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
+        ),
+        hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
+            impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
+        ),
+        hir::ItemKind::TraitAlias(..) => &[],
+        _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
+    }
+}
+
+fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
+    let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
+    ty::AssocItems::new(items)
+}
+
+fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> {
+    tcx.associated_items(impl_id)
+        .in_definition_order()
+        .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
+        .collect()
+}
+
+/// If the given `DefId` describes an item belonging to a trait,
+/// returns the `DefId` of the trait that the trait item belongs to;
+/// otherwise, returns `None`.
+fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
+    tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
+        ty::TraitContainer(def_id) => Some(def_id),
+        ty::ImplContainer(_) => None,
+    })
+}
+
+fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
+    let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    let parent_id = tcx.hir().get_parent_item(id);
+    let parent_def_id = tcx.hir().local_def_id(parent_id);
+    let parent_item = tcx.hir().expect_item(parent_def_id);
+    match parent_item.kind {
+        hir::ItemKind::Impl(ref impl_) => {
+            if let Some(impl_item_ref) =
+                impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+            {
+                let assoc_item =
+                    associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
+                debug_assert_eq!(assoc_item.def_id, def_id);
+                return assoc_item;
+            }
+        }
+
+        hir::ItemKind::Trait(.., ref trait_item_refs) => {
+            if let Some(trait_item_ref) =
+                trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+            {
+                let assoc_item =
+                    associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
+                debug_assert_eq!(assoc_item.def_id, def_id);
+                return assoc_item;
+            }
+        }
+
+        _ => {}
+    }
+
+    span_bug!(
+        parent_item.span,
+        "unexpected parent of trait or impl item or item not found: {:?}",
+        parent_item.kind
+    )
+}
+
+fn associated_item_from_trait_item_ref(
+    tcx: TyCtxt<'_>,
+    parent_def_id: LocalDefId,
+    trait_item_ref: &hir::TraitItemRef,
+) -> ty::AssocItem {
+    let def_id = trait_item_ref.id.def_id;
+    let (kind, has_self) = match trait_item_ref.kind {
+        hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+        hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+        hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+    };
+
+    ty::AssocItem {
+        ident: trait_item_ref.ident,
+        kind,
+        vis: tcx.visibility(def_id),
+        defaultness: trait_item_ref.defaultness,
+        def_id: def_id.to_def_id(),
+        trait_item_def_id: Some(def_id.to_def_id()),
+        container: ty::TraitContainer(parent_def_id.to_def_id()),
+        fn_has_self_parameter: has_self,
+    }
+}
+
+fn associated_item_from_impl_item_ref(
+    tcx: TyCtxt<'_>,
+    parent_def_id: LocalDefId,
+    impl_item_ref: &hir::ImplItemRef,
+) -> ty::AssocItem {
+    let def_id = impl_item_ref.id.def_id;
+    let (kind, has_self) = match impl_item_ref.kind {
+        hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+        hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+        hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+    };
+
+    let trait_item_def_id = impl_item_base_id(tcx, parent_def_id, impl_item_ref);
+
+    ty::AssocItem {
+        ident: impl_item_ref.ident,
+        kind,
+        vis: tcx.visibility(def_id),
+        defaultness: impl_item_ref.defaultness,
+        def_id: def_id.to_def_id(),
+        trait_item_def_id,
+        container: ty::ImplContainer(parent_def_id.to_def_id()),
+        fn_has_self_parameter: has_self,
+    }
+}
+
+fn impl_item_base_id<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    parent_def_id: LocalDefId,
+    impl_item: &hir::ImplItemRef,
+) -> Option<DefId> {
+    let impl_trait_ref = tcx.impl_trait_ref(parent_def_id)?;
+
+    // If the trait reference itself is erroneous (so the compilation is going
+    // to fail), skip checking the items here -- the `impl_item` table in `tcx`
+    // isn't populated for such impls.
+    if impl_trait_ref.references_error() {
+        return None;
+    }
+
+    // Locate trait items
+    let associated_items = tcx.associated_items(impl_trait_ref.def_id);
+
+    // Match item against trait
+    let mut items = associated_items.filter_by_name(tcx, impl_item.ident, impl_trait_ref.def_id);
+
+    let mut trait_item = items.next()?;
+
+    let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
+        (ty::AssocKind::Const, hir::AssocItemKind::Const) => true,
+        (ty::AssocKind::Fn, hir::AssocItemKind::Fn { .. }) => true,
+        (ty::AssocKind::Type, hir::AssocItemKind::Type) => true,
+        _ => false,
+    };
+
+    // If we don't have a compatible item, we'll use the first one whose name matches
+    // to report an error.
+    let mut compatible_kind = is_compatible(&trait_item);
+
+    if !compatible_kind {
+        if let Some(ty_trait_item) = items.find(is_compatible) {
+            compatible_kind = true;
+            trait_item = ty_trait_item;
+        }
+    }
+
+    if compatible_kind {
+        Some(trait_item.def_id)
+    } else {
+        report_mismatch_error(tcx, trait_item.def_id, impl_trait_ref, impl_item);
+        None
+    }
+}
+
+#[inline(never)]
+#[cold]
+fn report_mismatch_error<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_item_def_id: DefId,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+    impl_item: &hir::ImplItemRef,
+) {
+    let mut err = match impl_item.kind {
+        hir::AssocItemKind::Const => {
+            // Find associated const definition.
+            struct_span_err!(
+                tcx.sess,
+                impl_item.span,
+                E0323,
+                "item `{}` is an associated const, which doesn't match its trait `{}`",
+                impl_item.ident,
+                impl_trait_ref.print_only_trait_path()
+            )
+        }
+
+        hir::AssocItemKind::Fn { .. } => {
+            struct_span_err!(
+                tcx.sess,
+                impl_item.span,
+                E0324,
+                "item `{}` is an associated method, which doesn't match its trait `{}`",
+                impl_item.ident,
+                impl_trait_ref.print_only_trait_path()
+            )
+        }
+
+        hir::AssocItemKind::Type => {
+            struct_span_err!(
+                tcx.sess,
+                impl_item.span,
+                E0325,
+                "item `{}` is an associated type, which doesn't match its trait `{}`",
+                impl_item.ident,
+                impl_trait_ref.print_only_trait_path()
+            )
+        }
+    };
+
+    err.span_label(impl_item.span, "does not match trait");
+    if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
+        err.span_label(trait_span, "item in trait");
+    }
+    err.emit();
+}
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 13ffb2a5adc..e0aea786b83 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -152,8 +152,7 @@ fn inner_resolve_instance<'tcx>(
 
     let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
         debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
-        let item = tcx.associated_item(def.did);
-        resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
+        resolve_associated_item(tcx, def.did, param_env, trait_def_id, substs)
     } else {
         let ty = tcx.type_of(def.def_id_for_type_of());
         let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
@@ -204,19 +203,12 @@ fn inner_resolve_instance<'tcx>(
 
 fn resolve_associated_item<'tcx>(
     tcx: TyCtxt<'tcx>,
-    trait_item: &ty::AssocItem,
+    trait_item_id: DefId,
     param_env: ty::ParamEnv<'tcx>,
     trait_id: DefId,
     rcvr_substs: SubstsRef<'tcx>,
 ) -> Result<Option<Instance<'tcx>>, ErrorReported> {
-    let def_id = trait_item.def_id;
-    debug!(
-        "resolve_associated_item(trait_item={:?}, \
-            param_env={:?}, \
-            trait_id={:?}, \
-            rcvr_substs={:?})",
-        def_id, param_env, trait_id, rcvr_substs
-    );
+    debug!(?trait_item_id, ?param_env, ?trait_id, ?rcvr_substs, "resolve_associated_item");
 
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
 
@@ -232,7 +224,7 @@ fn resolve_associated_item<'tcx>(
         traits::ImplSource::UserDefined(impl_data) => {
             debug!(
                 "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
-                param_env, trait_item, rcvr_substs, impl_data
+                param_env, trait_item_id, rcvr_substs, impl_data
             );
             assert!(!rcvr_substs.needs_infer());
             assert!(!trait_ref.needs_infer());
@@ -241,9 +233,9 @@ fn resolve_associated_item<'tcx>(
             let trait_def = tcx.trait_def(trait_def_id);
             let leaf_def = trait_def
                 .ancestors(tcx, impl_data.impl_def_id)?
-                .leaf_def(tcx, trait_item.ident, trait_item.kind)
+                .leaf_def(tcx, trait_item_id)
                 .unwrap_or_else(|| {
-                    bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id);
+                    bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
                 });
 
             let substs = tcx.infer_ctxt().enter(|infcx| {
@@ -297,22 +289,22 @@ fn resolve_associated_item<'tcx>(
             // performs (i.e. that the definition's type in the `impl` matches
             // the declaration in the `trait`), so that we can cheaply check
             // here if it failed, instead of approximating it.
-            if trait_item.kind == ty::AssocKind::Const
-                && trait_item.def_id != leaf_def.item.def_id
+            if leaf_def.item.kind == ty::AssocKind::Const
+                && trait_item_id != leaf_def.item.def_id
                 && leaf_def.item.def_id.is_local()
             {
                 let normalized_type_of = |def_id, substs| {
                     tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
                 };
 
-                let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs);
+                let original_ty = normalized_type_of(trait_item_id, rcvr_substs);
                 let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
 
                 if original_ty != resolved_ty {
                     let msg = format!(
                         "Instance::resolve: inconsistent associated `const` type: \
                          was `{}: {}` but resolved to `{}: {}`",
-                        tcx.def_path_str_with_substs(trait_item.def_id, rcvr_substs),
+                        tcx.def_path_str_with_substs(trait_item_id, rcvr_substs),
                         original_ty,
                         tcx.def_path_str_with_substs(leaf_def.item.def_id, substs),
                         resolved_ty,
@@ -343,19 +335,22 @@ fn resolve_associated_item<'tcx>(
         }
         traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
             ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
-                def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
+                def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
                 substs: rcvr_substs,
             }),
             _ => None,
         },
         traits::ImplSource::Object(ref data) => {
-            let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
-            Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
+            let index = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id);
+            Some(Instance {
+                def: ty::InstanceDef::Virtual(trait_item_id, index),
+                substs: rcvr_substs,
+            })
         }
         traits::ImplSource::Builtin(..) => {
             if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
                 // FIXME(eddyb) use lang items for methods instead of names.
-                let name = tcx.item_name(def_id);
+                let name = tcx.item_name(trait_item_id);
                 if name == sym::clone {
                     let self_ty = trait_ref.self_ty();
 
@@ -367,7 +362,7 @@ fn resolve_associated_item<'tcx>(
                     };
 
                     Some(Instance {
-                        def: ty::InstanceDef::CloneShim(def_id, self_ty),
+                        def: ty::InstanceDef::CloneShim(trait_item_id, self_ty),
                         substs: rcvr_substs,
                     })
                 } else {
@@ -375,7 +370,7 @@ fn resolve_associated_item<'tcx>(
 
                     // Use the default `fn clone_from` from `trait Clone`.
                     let substs = tcx.erase_regions(rcvr_substs);
-                    Some(ty::Instance::new(def_id, substs))
+                    Some(ty::Instance::new(trait_item_id, substs))
                 }
             } else {
                 None
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 60f8e196bcb..55e19990761 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -16,6 +16,7 @@ extern crate tracing;
 
 use rustc_middle::ty::query::Providers;
 
+mod assoc;
 mod common_traits;
 pub mod instance;
 mod needs_drop;
@@ -23,6 +24,7 @@ pub mod representability;
 mod ty;
 
 pub fn provide(providers: &mut Providers) {
+    assoc::provide(providers);
     common_traits::provide(providers);
     needs_drop::provide(providers);
     ty::provide(providers);
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 6c2657bd64b..8f50e3e0fe1 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
 use rustc_span::{sym, Span};
@@ -71,90 +71,6 @@ fn sized_constraint_for_ty<'tcx>(
     result
 }
 
-fn associated_item_from_trait_item_ref(
-    tcx: TyCtxt<'_>,
-    parent_def_id: LocalDefId,
-    trait_item_ref: &hir::TraitItemRef,
-) -> ty::AssocItem {
-    let def_id = trait_item_ref.id.def_id;
-    let (kind, has_self) = match trait_item_ref.kind {
-        hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
-        hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
-        hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
-    };
-
-    ty::AssocItem {
-        ident: trait_item_ref.ident,
-        kind,
-        vis: tcx.visibility(def_id),
-        defaultness: trait_item_ref.defaultness,
-        def_id: def_id.to_def_id(),
-        container: ty::TraitContainer(parent_def_id.to_def_id()),
-        fn_has_self_parameter: has_self,
-    }
-}
-
-fn associated_item_from_impl_item_ref(
-    tcx: TyCtxt<'_>,
-    parent_def_id: LocalDefId,
-    impl_item_ref: &hir::ImplItemRef,
-) -> ty::AssocItem {
-    let def_id = impl_item_ref.id.def_id;
-    let (kind, has_self) = match impl_item_ref.kind {
-        hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
-        hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
-        hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
-    };
-
-    ty::AssocItem {
-        ident: impl_item_ref.ident,
-        kind,
-        vis: tcx.visibility(def_id),
-        defaultness: impl_item_ref.defaultness,
-        def_id: def_id.to_def_id(),
-        container: ty::ImplContainer(parent_def_id.to_def_id()),
-        fn_has_self_parameter: has_self,
-    }
-}
-
-fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
-    let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    let parent_id = tcx.hir().get_parent_item(id);
-    let parent_def_id = tcx.hir().local_def_id(parent_id);
-    let parent_item = tcx.hir().expect_item(parent_def_id);
-    match parent_item.kind {
-        hir::ItemKind::Impl(ref impl_) => {
-            if let Some(impl_item_ref) =
-                impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
-            {
-                let assoc_item =
-                    associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
-                debug_assert_eq!(assoc_item.def_id, def_id);
-                return assoc_item;
-            }
-        }
-
-        hir::ItemKind::Trait(.., ref trait_item_refs) => {
-            if let Some(trait_item_ref) =
-                trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
-            {
-                let assoc_item =
-                    associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
-                debug_assert_eq!(assoc_item.def_id, def_id);
-                return assoc_item;
-            }
-        }
-
-        _ => {}
-    }
-
-    span_bug!(
-        parent_item.span,
-        "unexpected parent of trait or impl item or item not found: {:?}",
-        parent_item.kind
-    )
-}
-
 fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
     let item = tcx.hir().expect_item(def_id.expect_local());
     if let hir::ItemKind::Impl(impl_) = &item.kind {
@@ -197,25 +113,6 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
     ty::AdtSizedConstraint(result)
 }
 
-fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
-    let item = tcx.hir().expect_item(def_id.expect_local());
-    match item.kind {
-        hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
-            trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
-        ),
-        hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
-            impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
-        ),
-        hir::ItemKind::TraitAlias(..) => &[],
-        _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
-    }
-}
-
-fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
-    let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
-    ty::AssocItems::new(items)
-}
-
 fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
     tcx.hir()
         .get_if_local(def_id)
@@ -231,16 +128,6 @@ fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         .map(|ident| ident.span)
 }
 
-/// If the given `DefId` describes an item belonging to a trait,
-/// returns the `DefId` of the trait that the trait item belongs to;
-/// otherwise, returns `None`.
-fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
-    tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
-        ty::TraitContainer(def_id) => Some(def_id),
-        ty::ImplContainer(_) => None,
-    })
-}
-
 /// See `ParamEnv` struct definition for details.
 #[instrument(level = "debug", skip(tcx))]
 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
@@ -620,14 +507,10 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>(
 pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         asyncness,
-        associated_item,
-        associated_item_def_ids,
-        associated_items,
         adt_sized_constraint,
         def_ident_span,
         param_env,
         param_env_reveal_all_normalized,
-        trait_of_item,
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index caa5c71e21c..956696546da 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -104,7 +104,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
                 GenericParamDefKind::Const { .. },
             ) if tcx.type_of(param.def_id) == tcx.types.usize => {
-                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id));
+                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
                 if let Ok(snippet) = snippet {
                     err.span_suggestion(
                         arg.span(),
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 8db706c3709..8226ffbccc4 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2363,8 +2363,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
             }
             hir::TyKind::Array(ref ty, ref length) => {
-                let length_def_id = tcx.hir().local_def_id(length.hir_id);
-                let length = ty::Const::from_anon_const(tcx, length_def_id);
+                let length = match length {
+                    &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
+                    hir::ArrayLen::Body(constant) => {
+                        let length_def_id = tcx.hir().local_def_id(constant.hir_id);
+                        ty::Const::from_anon_const(tcx, length_def_id)
+                    }
+                };
+
                 let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index e67ee1cab3d..eea8f40635d 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -496,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             call_expr.span,
             call_expr,
             fn_sig.inputs(),
-            &expected_arg_tys,
+            expected_arg_tys,
             arg_exprs,
             fn_sig.c_variadic,
             TupleArgumentsFlag::DontTupleArguments,
@@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             call_expr.span,
             call_expr,
             fn_sig.inputs(),
-            &expected_arg_tys,
+            expected_arg_tys,
             arg_exprs,
             fn_sig.c_variadic,
             TupleArgumentsFlag::TupleArguments,
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index fd7b3a55dfb..dcf42e1aefe 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -841,14 +841,8 @@ pub(super) fn check_specialization_validity<'tcx>(
     trait_def: &ty::TraitDef,
     trait_item: &ty::AssocItem,
     impl_id: DefId,
-    impl_item: &hir::ImplItem<'_>,
+    impl_item: &hir::ImplItemRef,
 ) {
-    let kind = match impl_item.kind {
-        hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
-        hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
-        hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
-    };
-
     let ancestors = match trait_def.ancestors(tcx, impl_id) {
         Ok(ancestors) => ancestors,
         Err(_) => return,
@@ -857,7 +851,7 @@ pub(super) fn check_specialization_validity<'tcx>(
         if parent.is_from_trait() {
             None
         } else {
-            Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+            Some((parent, parent.item(tcx, trait_item.def_id)))
         }
     });
 
@@ -894,7 +888,7 @@ pub(super) fn check_specialization_validity<'tcx>(
     }
 }
 
-pub(super) fn check_impl_items_against_trait<'tcx>(
+fn check_impl_items_against_trait<'tcx>(
     tcx: TyCtxt<'tcx>,
     full_impl_span: Span,
     impl_id: LocalDefId,
@@ -926,174 +920,82 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
         }
     }
 
-    // Locate trait definition and items
     let trait_def = tcx.trait_def(impl_trait_ref.def_id);
-    let impl_items = impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
-    let associated_items = tcx.associated_items(impl_trait_ref.def_id);
-
-    // Check existing impl methods to see if they are both present in trait
-    // and compatible with trait signature
-    for impl_item in impl_items {
-        let ty_impl_item = tcx.associated_item(impl_item.def_id);
-
-        let mut items =
-            associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id);
-
-        let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() {
-            let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
-                (ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true,
-                (ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true,
-                (ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true,
-                _ => false,
-            };
-
-            // If we don't have a compatible item, we'll use the first one whose name matches
-            // to report an error.
-            let mut compatible_kind = is_compatible(&ty_trait_item);
-            let mut trait_item = ty_trait_item;
-
-            if !compatible_kind {
-                if let Some(ty_trait_item) = items.find(is_compatible) {
-                    compatible_kind = true;
-                    trait_item = ty_trait_item;
-                }
-            }
 
-            (compatible_kind, trait_item)
+    for impl_item in impl_item_refs {
+        let ty_impl_item = tcx.associated_item(impl_item.id.def_id);
+        let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
+            tcx.associated_item(trait_item_id)
         } else {
+            // Checked in `associated_item`.
+            tcx.sess.delay_span_bug(impl_item.span, "missing associated item in trait");
             continue;
         };
-
-        if compatible_kind {
-            match impl_item.kind {
-                hir::ImplItemKind::Const(..) => {
-                    // Find associated const definition.
-                    compare_const_impl(
-                        tcx,
-                        &ty_impl_item,
-                        impl_item.span,
-                        &ty_trait_item,
-                        impl_trait_ref,
-                    );
-                }
-                hir::ImplItemKind::Fn(..) => {
-                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    compare_impl_method(
-                        tcx,
-                        &ty_impl_item,
-                        impl_item.span,
-                        &ty_trait_item,
-                        impl_trait_ref,
-                        opt_trait_span,
-                    );
-                }
-                hir::ImplItemKind::TyAlias(impl_ty) => {
-                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    compare_ty_impl(
-                        tcx,
-                        &ty_impl_item,
-                        impl_ty.span,
-                        &ty_trait_item,
-                        impl_trait_ref,
-                        opt_trait_span,
-                    );
-                }
+        let impl_item_full = tcx.hir().impl_item(impl_item.id);
+        match impl_item_full.kind {
+            hir::ImplItemKind::Const(..) => {
+                // Find associated const definition.
+                compare_const_impl(
+                    tcx,
+                    &ty_impl_item,
+                    impl_item.span,
+                    &ty_trait_item,
+                    impl_trait_ref,
+                );
+            }
+            hir::ImplItemKind::Fn(..) => {
+                let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+                compare_impl_method(
+                    tcx,
+                    &ty_impl_item,
+                    impl_item.span,
+                    &ty_trait_item,
+                    impl_trait_ref,
+                    opt_trait_span,
+                );
+            }
+            hir::ImplItemKind::TyAlias(impl_ty) => {
+                let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+                compare_ty_impl(
+                    tcx,
+                    &ty_impl_item,
+                    impl_ty.span,
+                    &ty_trait_item,
+                    impl_trait_ref,
+                    opt_trait_span,
+                );
             }
-
-            check_specialization_validity(
-                tcx,
-                trait_def,
-                &ty_trait_item,
-                impl_id.to_def_id(),
-                impl_item,
-            );
-        } else {
-            report_mismatch_error(
-                tcx,
-                ty_trait_item.def_id,
-                impl_trait_ref,
-                impl_item,
-                &ty_impl_item,
-            );
         }
+
+        check_specialization_validity(
+            tcx,
+            trait_def,
+            &ty_trait_item,
+            impl_id.to_def_id(),
+            impl_item,
+        );
     }
 
     if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
-        let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
-
         // Check for missing items from trait
         let mut missing_items = Vec::new();
-        for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
+        for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
             let is_implemented = ancestors
-                .leaf_def(tcx, trait_item.ident, trait_item.kind)
-                .map(|node_item| !node_item.defining_node.is_from_trait())
-                .unwrap_or(false);
+                .leaf_def(tcx, trait_item_id)
+                .map_or(false, |node_item| node_item.item.defaultness.has_value());
 
             if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
-                if !trait_item.defaultness.has_value() {
-                    missing_items.push(*trait_item);
-                }
+                missing_items.push(tcx.associated_item(trait_item_id));
             }
         }
 
         if !missing_items.is_empty() {
+            let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
             missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
         }
     }
 }
 
-#[inline(never)]
-#[cold]
-fn report_mismatch_error<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_item_def_id: DefId,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-    impl_item: &hir::ImplItem<'_>,
-    ty_impl_item: &ty::AssocItem,
-) {
-    let mut err = match impl_item.kind {
-        hir::ImplItemKind::Const(..) => {
-            // Find associated const definition.
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0323,
-                "item `{}` is an associated const, which doesn't match its trait `{}`",
-                ty_impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-
-        hir::ImplItemKind::Fn(..) => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0324,
-                "item `{}` is an associated method, which doesn't match its trait `{}`",
-                ty_impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-
-        hir::ImplItemKind::TyAlias(_) => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0325,
-                "item `{}` is an associated type, which doesn't match its trait `{}`",
-                ty_impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-    };
-
-    err.span_label(impl_item.span, "does not match trait");
-    if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
-        err.span_label(trait_span, "item in trait");
-    }
-    err.emit();
-}
-
 /// Checks whether a type can be represented in memory. In particular, it
 /// identifies types that contain themselves without indirection through a
 /// pointer, which would mean their size is unbounded.
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 096c4fcf472..621938c9b78 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1238,12 +1238,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn check_expr_repeat(
         &self,
         element: &'tcx hir::Expr<'tcx>,
-        count: &'tcx hir::AnonConst,
+        count: &'tcx hir::ArrayLen,
         expected: Expectation<'tcx>,
         _expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let count = self.to_const(count);
+        let count = self.array_length_to_const(count);
 
         let uty = match expected {
             ExpectHasType(uty) => match *uty.kind() {
@@ -1508,7 +1508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             } else {
                 self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
-                    let base_ty = self.check_expr(base_expr);
+                    let base_ty = self.typeck_results.borrow().node_type(base_expr.hir_id);
                     let same_adt = match (adt_ty.kind(), base_ty.kind()) {
                         (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
                         _ => false,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 67630fd4e58..1aca2911533 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -498,6 +498,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
+    pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> {
+        match length {
+            &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
+            hir::ArrayLen::Body(anon_const) => self.to_const(anon_const),
+        }
+    }
+
     pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
         let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
         let c = ty::Const::from_anon_const(self.tcx, const_def_id);
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 11b63a99043..e796fe58170 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 sp,
                 expr,
                 &err_inputs,
-                &[],
+                vec![],
                 args_no_rcvr,
                 false,
                 tuple_arguments,
@@ -73,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let method = method.unwrap();
         // HACK(eddyb) ignore self in the definition (see above).
-        let expected_arg_tys = self.expected_inputs_for_expected_output(
+        let expected_input_tys = self.expected_inputs_for_expected_output(
             sp,
             expected,
             method.sig.output(),
@@ -83,7 +83,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             sp,
             expr,
             &method.sig.inputs()[1..],
-            &expected_arg_tys[..],
+            expected_input_tys,
             args_no_rcvr,
             method.sig.c_variadic,
             tuple_arguments,
@@ -96,34 +96,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// method calls and overloaded operators.
     pub(in super::super) fn check_argument_types(
         &self,
-        sp: Span,
-        expr: &'tcx hir::Expr<'tcx>,
-        fn_inputs: &[Ty<'tcx>],
-        expected_arg_tys: &[Ty<'tcx>],
-        args: &'tcx [hir::Expr<'tcx>],
+        // Span enclosing the call site
+        call_span: Span,
+        // Expression of the call site
+        call_expr: &'tcx hir::Expr<'tcx>,
+        // Types (as defined in the *signature* of the target function)
+        formal_input_tys: &[Ty<'tcx>],
+        // More specific expected types, after unifying with caller output types
+        expected_input_tys: Vec<Ty<'tcx>>,
+        // The expressions for each provided argument
+        provided_args: &'tcx [hir::Expr<'tcx>],
+        // Whether the function is variadic, for example when imported from C
         c_variadic: bool,
+        // Whether the arguments have been bundled in a tuple (ex: closures)
         tuple_arguments: TupleArgumentsFlag,
-        def_id: Option<DefId>,
+        // The DefId for the function being called, for better error messages
+        fn_def_id: Option<DefId>,
     ) {
         let tcx = self.tcx;
         // Grab the argument types, supplying fresh type variables
         // if the wrong number of arguments were supplied
-        let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
+        let supplied_arg_count =
+            if tuple_arguments == DontTupleArguments { provided_args.len() } else { 1 };
 
         // All the input types from the fn signature must outlive the call
         // so as to validate implied bounds.
-        for (&fn_input_ty, arg_expr) in iter::zip(fn_inputs, args) {
+        for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) {
             self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
         }
 
-        let expected_arg_count = fn_inputs.len();
+        let expected_arg_count = formal_input_tys.len();
 
         let param_count_error = |expected_count: usize,
                                  arg_count: usize,
                                  error_code: &str,
                                  c_variadic: bool,
                                  sugg_unit: bool| {
-            let (span, start_span, args, ctor_of) = match &expr.kind {
+            let (span, start_span, args, ctor_of) = match &call_expr.kind {
                 hir::ExprKind::Call(
                     hir::Expr {
                         span,
@@ -156,14 +165,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     &args[1..], // Skip the receiver.
                     None,       // methods are never ctors
                 ),
-                k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
+                k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
             };
-            let arg_spans = if args.is_empty() {
+            let arg_spans = if provided_args.is_empty() {
                 // foo()
                 // ^^^-- supplied 0 arguments
                 // |
                 // expected 2 arguments
-                vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
+                vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
             } else {
                 // foo(1, 2, 3)
                 // ^^^ -  -  - supplied 3 arguments
@@ -196,7 +205,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
             }
 
-            if let Some(def_id) = def_id {
+            if let Some(def_id) = fn_def_id {
                 if let Some(def_span) = tcx.def_ident_span(def_id) {
                     let mut spans: MultiSpan = def_span.into();
 
@@ -218,7 +227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
 
             if sugg_unit {
-                let sugg_span = tcx.sess.source_map().end_point(expr.span);
+                let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
                 // remove closing `)` from the span
                 let sugg_span = sugg_span.shrink_to_lo();
                 err.span_suggestion(
@@ -240,110 +249,148 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             err.emit();
         };
 
-        let mut expected_arg_tys = expected_arg_tys.to_vec();
-
-        let formal_tys = if tuple_arguments == TupleArguments {
-            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
+        let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
+            let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]);
             match tuple_type.kind() {
-                ty::Tuple(arg_types) if arg_types.len() != args.len() => {
-                    param_count_error(arg_types.len(), args.len(), "E0057", false, false);
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
+                ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => {
+                    param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false);
+                    (self.err_args(provided_args.len()), vec![])
                 }
                 ty::Tuple(arg_types) => {
-                    expected_arg_tys = match expected_arg_tys.get(0) {
+                    let expected_input_tys = match expected_input_tys.get(0) {
                         Some(&ty) => match ty.kind() {
                             ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
                             _ => vec![],
                         },
                         None => vec![],
                     };
-                    arg_types.iter().map(|k| k.expect_ty()).collect()
+                    (arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys)
                 }
                 _ => {
                     struct_span_err!(
                         tcx.sess,
-                        sp,
+                        call_span,
                         E0059,
                         "cannot use call notation; the first type parameter \
                          for the function trait is neither a tuple nor unit"
                     )
                     .emit();
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
+                    (self.err_args(provided_args.len()), vec![])
                 }
             }
         } else if expected_arg_count == supplied_arg_count {
-            fn_inputs.to_vec()
+            (formal_input_tys.to_vec(), expected_input_tys)
         } else if c_variadic {
             if supplied_arg_count >= expected_arg_count {
-                fn_inputs.to_vec()
+                (formal_input_tys.to_vec(), expected_input_tys)
             } else {
                 param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
-                expected_arg_tys = vec![];
-                self.err_args(supplied_arg_count)
+                (self.err_args(supplied_arg_count), vec![])
             }
         } else {
             // is the missing argument of type `()`?
-            let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit()
-            } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(fn_inputs[0]).is_unit()
+            let sugg_unit = if expected_input_tys.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(expected_input_tys[0]).is_unit()
+            } else if formal_input_tys.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(formal_input_tys[0]).is_unit()
             } else {
                 false
             };
             param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
 
-            expected_arg_tys = vec![];
-            self.err_args(supplied_arg_count)
+            (self.err_args(supplied_arg_count), vec![])
         };
 
         debug!(
-            "check_argument_types: formal_tys={:?}",
-            formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
+            "check_argument_types: formal_input_tys={:?}",
+            formal_input_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
         );
 
-        // If there is no expectation, expect formal_tys.
-        let expected_arg_tys =
-            if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
+        // If there is no expectation, expect formal_input_tys.
+        let expected_input_tys = if !expected_input_tys.is_empty() {
+            expected_input_tys
+        } else {
+            formal_input_tys.clone()
+        };
+
+        assert_eq!(expected_input_tys.len(), formal_input_tys.len());
 
+        // Keep track of the fully coerced argument types
         let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
 
+        // We introduce a helper function to demand that a given argument satisfy a given input
+        // This is more complicated than just checking type equality, as arguments could be coerced
+        // This version writes those types back so further type checking uses the narrowed types
+        let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| {
+            let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
+            let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
+            let provided_arg = &provided_args[idx];
+
+            debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty);
+
+            // The special-cased logic below has three functions:
+            // 1. Provide as good of an expected type as possible.
+            let expectation = Expectation::rvalue_hint(self, expected_input_ty);
+
+            let checked_ty = self.check_expr_with_expectation(provided_arg, expectation);
+
+            // 2. Coerce to the most detailed type that could be coerced
+            //    to, which is `expected_ty` if `rvalue_hint` returns an
+            //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+            let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
+
+            // Keep track of these for below
+            final_arg_types.push((idx, checked_ty, coerced_ty));
+
+            // Cause selection errors caused by resolving a single argument to point at the
+            // argument and not the call. This is otherwise redundant with the `demand_coerce`
+            // call immediately after, but it lets us customize the span pointed to in the
+            // fulfillment error to be more accurate.
+            let _ =
+                self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| {
+                    self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
+                    self.point_at_arg_instead_of_call_if_possible(
+                        errors,
+                        &final_arg_types,
+                        call_expr,
+                        call_span,
+                        provided_args,
+                    );
+                });
+
+            // We're processing function arguments so we definitely want to use
+            // two-phase borrows.
+            self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes);
+
+            // 3. Relate the expected type and the formal one,
+            //    if the expected type was used for the coercion.
+            self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
+        };
+
         // Check the arguments.
         // We do this in a pretty awful way: first we type-check any arguments
         // that are not closures, then we type-check the closures. This is so
         // that we have more information about the types of arguments when we
         // type-check the functions. This isn't really the right way to do this.
         for check_closures in [false, true] {
-            debug!("check_closures={}", check_closures);
-
             // More awful hacks: before we check argument types, try to do
             // an "opportunistic" trait resolution of any trait bounds on
             // the call. This helps coercions.
             if check_closures {
                 self.select_obligations_where_possible(false, |errors| {
-                    self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+                    self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
                     self.point_at_arg_instead_of_call_if_possible(
                         errors,
                         &final_arg_types,
-                        expr,
-                        sp,
-                        &args,
+                        call_expr,
+                        call_span,
+                        &provided_args,
                     );
                 })
             }
 
-            // For C-variadic functions, we don't have a declared type for all of
-            // the arguments hence we only do our usual type checking with
-            // the arguments who's types we do know.
-            let t = if c_variadic {
-                expected_arg_count
-            } else if tuple_arguments == TupleArguments {
-                args.len()
-            } else {
-                supplied_arg_count
-            };
-            for (i, arg) in args.iter().take(t).enumerate() {
+            let minimum_input_count = formal_input_tys.len();
+            for (idx, arg) in provided_args.iter().enumerate() {
                 // Warn only for the first loop (the "no closures" one).
                 // Closure arguments themselves can't be diverging, but
                 // a previous argument can, e.g., `foo(panic!(), || {})`.
@@ -351,53 +398,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
                 }
 
-                let is_closure = matches!(arg.kind, ExprKind::Closure(..));
+                // For C-variadic functions, we don't have a declared type for all of
+                // the arguments hence we only do our usual type checking with
+                // the arguments who's types we do know. However, we *can* check
+                // for unreachable expressions (see above).
+                // FIXME: unreachable warning current isn't emitted
+                if idx >= minimum_input_count {
+                    continue;
+                }
 
+                let is_closure = matches!(arg.kind, ExprKind::Closure(..));
                 if is_closure != check_closures {
                     continue;
                 }
 
-                let formal_ty = formal_tys[i];
-                debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty);
-
-                // The special-cased logic below has three functions:
-                // 1. Provide as good of an expected type as possible.
-                let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
-
-                let checked_ty = self.check_expr_with_expectation(&arg, expected);
-
-                // 2. Coerce to the most detailed type that could be coerced
-                //    to, which is `expected_ty` if `rvalue_hint` returns an
-                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
-                let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
-
-                final_arg_types.push((i, checked_ty, coerce_ty));
-
-                // Cause selection errors caused by resolving a single argument to point at the
-                // argument and not the call. This is otherwise redundant with the `demand_coerce`
-                // call immediately after, but it lets us customize the span pointed to in the
-                // fulfillment error to be more accurate.
-                let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
-                    coerce_ty,
-                    |errors| {
-                        self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
-                        self.point_at_arg_instead_of_call_if_possible(
-                            errors,
-                            &final_arg_types,
-                            expr,
-                            sp,
-                            args,
-                        );
-                    },
-                );
-
-                // We're processing function arguments so we definitely want to use
-                // two-phase borrows.
-                self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
-
-                // 3. Relate the expected type and the formal one,
-                //    if the expected type was used for the coercion.
-                self.demand_suptype(arg.span, formal_ty, coerce_ty);
+                demand_compatible(idx, &mut final_arg_types);
             }
         }
 
@@ -410,7 +425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit()
             }
 
-            for arg in args.iter().skip(expected_arg_count) {
+            for arg in provided_args.iter().skip(expected_arg_count) {
                 let arg_ty = self.check_expr(&arg);
 
                 // There are a few types which get autopromoted when passed via varargs
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 03518dc8d12..f7f4c52c2a1 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -7,7 +7,7 @@ mod prelude2021;
 pub mod probe;
 mod suggest;
 
-pub use self::suggest::{SelfSource, TraitInfo};
+pub use self::suggest::SelfSource;
 pub use self::CandidateSource::*;
 pub use self::MethodError::*;
 
@@ -31,7 +31,6 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use self::probe::{IsSuggestion, ProbeScope};
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    suggest::provide(providers);
     probe::provide(providers);
 }
 
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index f3a5fbbb444..7f9c75c7fee 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -5,8 +5,8 @@ use crate::check::FnCtxt;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def::Namespace;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -1922,76 +1922,10 @@ impl Ord for TraitInfo {
     }
 }
 
-/// Retrieves all traits in this crate and any dependent crates.
+/// Retrieves all traits in this crate and any dependent crates,
+/// and wraps them into `TraitInfo` for custom sorting.
 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
-    tcx.all_traits(()).iter().map(|&def_id| TraitInfo { def_id }).collect()
-}
-
-/// Computes all traits in this crate and any dependent crates.
-fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] {
-    use hir::itemlikevisit;
-
-    let mut traits = vec![];
-
-    // Crate-local:
-
-    struct Visitor<'a> {
-        traits: &'a mut Vec<DefId>,
-    }
-
-    impl<'v, 'a> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a> {
-        fn visit_item(&mut self, i: &'v hir::Item<'v>) {
-            match i.kind {
-                hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
-                    self.traits.push(i.def_id.to_def_id());
-                }
-                _ => (),
-            }
-        }
-
-        fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
-
-        fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
-
-        fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
-    }
-
-    tcx.hir().visit_all_item_likes(&mut Visitor { traits: &mut traits });
-
-    // Cross-crate:
-
-    let mut external_mods = FxHashSet::default();
-    fn handle_external_res(
-        tcx: TyCtxt<'_>,
-        traits: &mut Vec<DefId>,
-        external_mods: &mut FxHashSet<DefId>,
-        res: Res<!>,
-    ) {
-        match res {
-            Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
-                traits.push(def_id);
-            }
-            Res::Def(DefKind::Mod, def_id) => {
-                if !external_mods.insert(def_id) {
-                    return;
-                }
-                for child in tcx.item_children(def_id).iter() {
-                    handle_external_res(tcx, traits, external_mods, child.res)
-                }
-            }
-            _ => {}
-        }
-    }
-    for &cnum in tcx.crates(()).iter() {
-        let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
-        handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
-    }
-
-    tcx.arena.alloc_from_iter(traits)
-}
-
-pub fn provide(providers: &mut ty::query::Providers) {
-    providers.all_traits = compute_all_traits;
+    tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect()
 }
 
 fn find_use_placement<'tcx>(tcx: TyCtxt<'tcx>, target_module: LocalDefId) -> (Option<Span>, bool) {
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index a9e6b1caff0..d576154ff90 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -566,7 +566,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S
 
 fn report_forbidden_specialization(
     tcx: TyCtxt<'_>,
-    impl_item: &hir::ImplItem<'_>,
+    impl_item: &hir::ImplItemRef,
     parent_impl: DefId,
 ) {
     let mut err = struct_span_err!(
@@ -598,7 +598,7 @@ fn report_forbidden_specialization(
 fn missing_items_err(
     tcx: TyCtxt<'_>,
     impl_span: Span,
-    missing_items: &[ty::AssocItem],
+    missing_items: &[&ty::AssocItem],
     full_impl_span: Span,
 ) {
     let missing_items_msg = missing_items
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index e7b728d491b..d4d4baa3f71 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -182,7 +182,7 @@ crate fn placeholder_type_error<'tcx>(
         sugg.push((span, format!(", {}", type_name)));
     }
 
-    let mut err = bad_placeholder_type(tcx, placeholder_types, kind);
+    let mut err = bad_placeholder(tcx, "type", placeholder_types, kind);
 
     // Suggest, but only if it is not a function in const or static
     if suggest {
@@ -295,7 +295,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
         if let hir::ExprKind::Closure(..) = expr.kind {
             let def_id = self.tcx.hir().local_def_id(expr.hir_id);
             self.tcx.ensure().generics_of(def_id);
-            self.tcx.ensure().type_of(def_id);
+            // We do not call `type_of` for closures here as that
+            // depends on typecheck and would therefore hide
+            // any further errors in case one typeck fails.
         }
         intravisit::walk_expr(self, expr);
     }
@@ -314,8 +316,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Utility types and common code for the above passes.
 
-fn bad_placeholder_type<'tcx>(
+fn bad_placeholder<'tcx>(
     tcx: TyCtxt<'tcx>,
+    placeholder_kind: &'static str,
     mut spans: Vec<Span>,
     kind: &'static str,
 ) -> rustc_errors::DiagnosticBuilder<'tcx> {
@@ -326,7 +329,8 @@ fn bad_placeholder_type<'tcx>(
         tcx.sess,
         spans.clone(),
         E0121,
-        "the type placeholder `_` is not allowed within types on item signatures for {}",
+        "the {} placeholder `_` is not allowed within types on item signatures for {}",
+        placeholder_kind,
         kind
     );
     for span in spans {
@@ -393,7 +397,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         _: Option<&ty::GenericParamDef>,
         span: Span,
     ) -> &'tcx Const<'tcx> {
-        bad_placeholder_type(self.tcx(), vec![span], "generic").emit();
+        bad_placeholder(self.tcx(), "const", vec![span], "generic").emit();
         // Typeck doesn't expect erased regions to be returned from `type_of`.
         let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r {
             ty::ReErased => self.tcx.lifetimes.re_static,
@@ -1482,7 +1486,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
                     // as they shouldn't be able to cause query cycle errors.
                     Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                    | Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+                        if constant.hir_id() == hir_id =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    Node::Variant(Variant { disr_expr: Some(ref constant), .. })
                         if constant.hir_id == hir_id =>
                     {
                         Some(parent_def_id.to_def_id())
@@ -1788,7 +1796,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
 
                     let mut visitor = PlaceholderHirTyCollector::default();
                     visitor.visit_ty(ty);
-                    let mut diag = bad_placeholder_type(tcx, visitor.0, "return type");
+                    let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type");
                     let ret_ty = fn_sig.skip_binder().output();
                     if !ret_ty.references_error() {
                         if !ret_ty.is_closure() {
@@ -2894,7 +2902,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 }
             }
         } else if attr.has_name(sym::instruction_set) {
-            codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) {
+            codegen_fn_attrs.instruction_set = match attr.meta_kind() {
                 Some(MetaItemKind::List(ref items)) => match items.as_slice() {
                     [NestedMetaItem::MetaItem(set)] => {
                         let segments =
@@ -2999,7 +3007,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         if !attr.has_name(sym::inline) {
             return ia;
         }
-        match attr.meta().map(|i| i.kind) {
+        match attr.meta_kind() {
             Some(MetaItemKind::Word) => InlineAttr::Hint,
             Some(MetaItemKind::List(ref items)) => {
                 inline_span = Some(attr.span);
@@ -3038,7 +3046,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             return ia;
         }
         let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
-        match attr.meta().map(|i| i.kind) {
+        match attr.meta_kind() {
             Some(MetaItemKind::Word) => {
                 err(attr.span, "expected one argument");
                 ia
@@ -3142,21 +3150,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
 /// applied to the method prototype.
 fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     if let Some(impl_item) = tcx.opt_associated_item(def_id) {
-        if let ty::AssocItemContainer::ImplContainer(impl_def_id) = impl_item.container {
-            if let Some(trait_def_id) = tcx.trait_id_of_impl(impl_def_id) {
-                if let Some(trait_item) = tcx
-                    .associated_items(trait_def_id)
-                    .filter_by_name_unhygienic(impl_item.ident.name)
-                    .find(move |trait_item| {
-                        trait_item.kind == ty::AssocKind::Fn
-                            && tcx.hygienic_eq(impl_item.ident, trait_item.ident, trait_def_id)
-                    })
-                {
-                    return tcx
-                        .codegen_fn_attrs(trait_item.def_id)
-                        .flags
-                        .intersects(CodegenFnAttrFlags::TRACK_CALLER);
-                }
+        if let ty::AssocItemContainer::ImplContainer(_) = impl_item.container {
+            if let Some(trait_item) = impl_item.trait_item_def_id {
+                return tcx
+                    .codegen_fn_attrs(trait_item)
+                    .flags
+                    .intersects(CodegenFnAttrFlags::TRACK_CALLER);
             }
         }
     }
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 99fddcb00ce..ae8d262fcf1 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -13,7 +13,7 @@ use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
 use super::ItemCtxt;
-use super::{bad_placeholder_type, is_suggestable_infer_ty};
+use super::{bad_placeholder, is_suggestable_infer_ty};
 
 /// Computes the relevant generic parameter for a potential generic const argument.
 ///
@@ -470,14 +470,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 
         Node::Field(field) => icx.to_ty(field.ty),
 
-        Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => {
-            let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
-            if let Some(movability) = gen {
-                tcx.mk_generator(def_id.to_def_id(), substs, movability)
-            } else {
-                tcx.mk_closure(def_id.to_def_id(), substs)
-            }
-        }
+        Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => tcx.typeck(def_id).node_type(hir_id),
 
         Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
             // We defer to `type_of` of the corresponding parameter
@@ -490,7 +483,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             match parent_node {
                 Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
                 | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                    if constant.hir_id == hir_id =>
+                    if constant.hir_id() == hir_id =>
                 {
                     tcx.types.usize
                 }
@@ -788,7 +781,7 @@ fn infer_placeholder_type<'a>(
             err.emit();
         }
         None => {
-            let mut diag = bad_placeholder_type(tcx, vec![span], kind);
+            let mut diag = bad_placeholder(tcx, "type", vec![span], kind);
 
             if !ty.references_error() {
                 let mut mk_nameable = MakeNameable::new(tcx);
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 32b4018f626..1ae0ff30364 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -715,13 +715,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
 
         debug!("walk_captures({:?})", closure_expr);
 
-        let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
-        let upvars = self.tcx().upvars_mentioned(self.body_owner);
+        let tcx = self.tcx();
+        let closure_def_id = tcx.hir().local_def_id(closure_expr.hir_id).to_def_id();
+        let upvars = tcx.upvars_mentioned(self.body_owner);
 
         // For purposes of this function, generator and closures are equivalent.
         let body_owner_is_closure = matches!(
-            self.tcx().type_of(self.body_owner.to_def_id()).kind(),
-            ty::Closure(..) | ty::Generator(..)
+            tcx.hir().body_owner_kind(tcx.hir().local_def_id_to_hir_id(self.body_owner)),
+            hir::BodyOwnerKind::Closure,
         );
 
         // If we have a nested closure, we want to include the fake reads present in the nested closure.