about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs17
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs21
-rw-r--r--compiler/rustc_ast/src/visit.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs12
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs174
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs19
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs55
-rw-r--r--compiler/rustc_driver/src/lib.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0212.md35
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0390.md5
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0546.md27
-rw-r--r--compiler/rustc_expand/src/base.rs10
-rw-r--r--compiler/rustc_expand/src/expand.rs8
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_hir/src/arena.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs4
-rw-r--r--compiler/rustc_hir/src/intravisit.rs2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs4
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs6
-rw-r--r--compiler/rustc_infer/src/traits/util.rs34
-rw-r--r--compiler/rustc_interface/src/interface.rs3
-rw-r--r--compiler/rustc_interface/src/queries.rs12
-rw-r--r--compiler/rustc_lexer/src/lib.rs10
-rw-r--r--compiler/rustc_lint/src/internal.rs46
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs6
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs45
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs28
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs12
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs2
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs2
-rw-r--r--compiler/rustc_middle/src/hir/place.rs43
-rw-r--r--compiler/rustc_middle/src/middle/cstore.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs30
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs6
-rw-r--r--compiler/rustc_middle/src/ty/context.rs51
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs76
-rw-r--r--compiler/rustc_middle/src/ty/query/keys.rs24
-rw-r--r--compiler/rustc_middle/src/ty/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/query/on_disk_cache.rs24
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs9
-rw-r--r--compiler/rustc_middle/src/ty/util.rs10
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/mod.rs16
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs6
-rw-r--r--compiler/rustc_mir/src/const_eval/error.rs2
-rw-r--r--compiler/rustc_mir/src/const_eval/machine.rs55
-rw-r--r--compiler/rustc_mir/src/interpret/eval_context.rs55
-rw-r--r--compiler/rustc_mir/src/interpret/intern.rs30
-rw-r--r--compiler/rustc_mir/src/interpret/intrinsics.rs18
-rw-r--r--compiler/rustc_mir/src/interpret/machine.rs10
-rw-r--r--compiler/rustc_mir/src/interpret/step.rs6
-rw-r--r--compiler/rustc_mir/src/interpret/terminator.rs2
-rw-r--r--compiler/rustc_mir/src/interpret/util.rs9
-rw-r--r--compiler/rustc_mir/src/lib.rs1
-rw-r--r--compiler/rustc_mir/src/transform/const_prop.rs2
-rw-r--r--compiler/rustc_mir/src/transform/coverage/debug.rs62
-rw-r--r--compiler/rustc_mir/src/transform/coverage/graph.rs28
-rw-r--r--compiler/rustc_mir/src/transform/coverage/mod.rs93
-rw-r--r--compiler/rustc_mir/src/transform/coverage/query.rs37
-rw-r--r--compiler/rustc_mir/src/transform/coverage/spans.rs154
-rw-r--r--compiler/rustc_mir/src/transform/promote_consts.rs58
-rw-r--r--compiler/rustc_mir/src/util/generic_graphviz.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs399
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs105
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs105
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/into.rs11
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs97
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs56
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs252
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs62
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs2
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs29
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs33
-rw-r--r--compiler/rustc_passes/Cargo.toml1
-rw-r--r--compiler/rustc_passes/src/check_attr.rs316
-rw-r--r--compiler/rustc_passes/src/dead.rs36
-rw-r--r--compiler/rustc_passes/src/intrinsicck.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs254
-rw-r--r--compiler/rustc_passes/src/liveness/rwu_table.rs144
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs239
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs13
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs27
-rw-r--r--compiler/rustc_query_system/src/dep_graph/prev.rs41
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs2
-rw-r--r--compiler/rustc_serialize/src/json.rs2
-rw-r--r--compiler/rustc_session/src/config.rs109
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/options.rs10
-rw-r--r--compiler/rustc_session/src/session.rs30
-rw-r--r--compiler/rustc_span/src/analyze_source_file.rs4
-rw-r--r--compiler/rustc_span/src/lib.rs5
-rw-r--r--compiler/rustc_span/src/source_map.rs6
-rw-r--r--compiler/rustc_span/src/symbol.rs39
-rw-r--r--compiler/rustc_target/src/asm/mod.rs51
-rw-r--r--compiler/rustc_target/src/lib.rs1
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs7
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs68
-rw-r--r--compiler/rustc_typeck/src/bounds.rs24
-rw-r--r--compiler/rustc_typeck/src/check/check.rs68
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs58
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/mod.rs8
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs4
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs13
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs11
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs41
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs34
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls.rs57
-rw-r--r--compiler/rustc_typeck/src/collect.rs188
-rw-r--r--compiler/rustc_typeck/src/collect/item_bounds.rs4
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs60
129 files changed, 2847 insertions, 1882 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 9d6ee65049a..220bbed7e78 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -24,7 +24,7 @@ pub use UnsafeSource::*;
 
 use crate::ptr::P;
 use crate::token::{self, CommentKind, DelimToken};
-use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
+use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -39,7 +39,6 @@ use rustc_span::{Span, DUMMY_SP};
 use std::cmp::Ordering;
 use std::convert::TryFrom;
 use std::fmt;
-use std::iter;
 
 #[cfg(test)]
 mod tests;
@@ -1514,20 +1513,6 @@ impl MacArgs {
         }
     }
 
-    /// Tokens together with the delimiters or `=`.
-    /// Use of this method generally means that something suboptimal or hacky is happening.
-    pub fn outer_tokens(&self) -> TokenStream {
-        match *self {
-            MacArgs::Empty => TokenStream::default(),
-            MacArgs::Delimited(dspan, delim, ref tokens) => {
-                TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into()
-            }
-            MacArgs::Eq(eq_span, ref tokens) => {
-                iter::once(TokenTree::token(token::Eq, eq_span)).chain(tokens.trees()).collect()
-            }
-        }
-    }
-
     /// Whether a macro with these arguments needs a semicolon
     /// when used as a standalone item or statement.
     pub fn need_semicolon(&self) -> bool {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index c4e92a9f6d1..3889ede7f4c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -371,20 +371,15 @@ pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) {
             // The value in `#[key = VALUE]` must be visited as an expression for backward
             // compatibility, so that macros can be expanded in that position.
             if !vis.token_visiting_enabled() {
-                if let Some(TokenTree::Token(token)) = tokens.trees_ref().next() {
-                    if let token::Interpolated(..) = token.kind {
-                        // ^^ Do not `make_mut` unless we have to.
-                        match Lrc::make_mut(&mut tokens.0).get_mut(0) {
-                            Some((TokenTree::Token(token), _spacing)) => match &mut token.kind {
-                                token::Interpolated(nt) => match Lrc::make_mut(nt) {
-                                    token::NtExpr(expr) => vis.visit_expr(expr),
-                                    t => panic!("unexpected token in key-value attribute: {:?}", t),
-                                },
-                                t => panic!("unexpected token in key-value attribute: {:?}", t),
-                            },
+                match Lrc::make_mut(&mut tokens.0).get_mut(0) {
+                    Some((TokenTree::Token(token), _spacing)) => match &mut token.kind {
+                        token::Interpolated(nt) => match Lrc::make_mut(nt) {
+                            token::NtExpr(expr) => vis.visit_expr(expr),
                             t => panic!("unexpected token in key-value attribute: {:?}", t),
-                        }
-                    }
+                        },
+                        t => panic!("unexpected token in key-value attribute: {:?}", t),
+                    },
+                    t => panic!("unexpected token in key-value attribute: {:?}", t),
                 }
             }
         }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 61426a838de..a420bb56350 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -906,7 +906,6 @@ pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) {
                     token::NtExpr(expr) => visitor.visit_expr(expr),
                     t => panic!("unexpected token in key-value attribute: {:?}", t),
                 },
-                token::Literal(..) | token::Ident(..) => {}
                 t => panic!("unexpected token in key-value attribute: {:?}", t),
             },
             t => panic!("unexpected token in key-value attribute: {:?}", t),
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 314e5103cc2..6ad6e664316 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -347,7 +347,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `_ => else_block` where `else_block` is `{}` if there's `None`:
         let else_pat = self.pat_wild(span);
         let (else_expr, contains_else_clause) = match else_opt {
-            None => (self.expr_block_empty(span), false),
+            None => (self.expr_block_empty(span.shrink_to_hi()), false),
             Some(els) => (self.lower_expr(els), true),
         };
         let else_arm = self.arm(else_pat, else_expr);
@@ -1307,7 +1307,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
                     }
                 };
-                Some(op)
+                Some((op, *op_sp))
             })
             .collect();
 
@@ -1326,7 +1326,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             } = *p
             {
                 let op_sp = asm.operands[operand_idx].1;
-                match &operands[operand_idx] {
+                match &operands[operand_idx].0 {
                     hir::InlineAsmOperand::In { reg, .. }
                     | hir::InlineAsmOperand::Out { reg, .. }
                     | hir::InlineAsmOperand::InOut { reg, .. }
@@ -1385,8 +1385,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let mut used_input_regs = FxHashMap::default();
         let mut used_output_regs = FxHashMap::default();
         let mut required_features: Vec<&str> = vec![];
-        for (idx, op) in operands.iter().enumerate() {
-            let op_sp = asm.operands[idx].1;
+        for (idx, &(ref op, op_sp)) in operands.iter().enumerate() {
             if let Some(reg) = op.reg() {
                 // Make sure we don't accidentally carry features from the
                 // previous iteration.
@@ -1458,8 +1457,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                                     skip = true;
 
                                     let idx2 = *o.get();
-                                    let op2 = &operands[idx2];
-                                    let op_sp2 = asm.operands[idx2].1;
+                                    let &(ref op2, op_sp2) = &operands[idx2];
                                     let reg2 = match op2.reg() {
                                         Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r,
                                         _ => unreachable!(),
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 4ec3e39facc..bf6d3322176 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -400,7 +400,7 @@ impl<'a> AstValidator<'a> {
         if let Defaultness::Default(def_span) = defaultness {
             let span = self.session.source_map().guess_head_span(span);
             self.err_handler()
-                .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
+                .struct_span_err(span, "`default` is only allowed on items in trait impls")
                 .span_label(def_span, "`default` because of this")
                 .emit();
         }
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 5b75fbf339b..9d54d89e080 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -630,6 +630,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
     gate_all!(const_trait_impl, "const trait impls are experimental");
     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
     gate_all!(inline_const, "inline-const is experimental");
+    gate_all!(
+        extended_key_value_attributes,
+        "arbitrary expressions in key-value attributes are unstable"
+    );
     if sess.parse_sess.span_diagnostic.err_count() == 0 {
         // Errors for `destructuring_assignment` can get quite noisy, especially where `_` is
         // involved, so we only emit errors where there are no other parsing errors.
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 3563aa250a9..df8aa1b3e69 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -146,12 +146,12 @@ macro atomic_minmax($fx:expr, $cc:expr, <$T:ident> ($ptr:ident, $src:ident) -> $
 
 macro validate_atomic_type($fx:ident, $intrinsic:ident, $span:ident, $ty:expr) {
     match $ty.kind() {
-        ty::Uint(_) | ty::Int(_) => {}
+        ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
         _ => {
             $fx.tcx.sess.span_err(
                 $span,
                 &format!(
-                    "`{}` intrinsic: expected basic integer type, found `{:?}`",
+                    "`{}` intrinsic: expected basic integer or raw pointer type, found `{:?}`",
                     $intrinsic, $ty
                 ),
             );
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 62a7986c194..97c38e04bc1 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -127,9 +127,6 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
         return;
     }
 
-    // FIXME(richkadel): Make sure probestack plays nice with `-Z instrument-coverage`
-    // or disable it if not, similar to above early exits.
-
     // Flag our internal `__rust_probestack` function as the stack probe symbol.
     // This is defined in the `compiler-builtins` crate for each architecture.
     llvm::AddFunctionAttrStringValue(
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 85aaa7e8893..72ba5bbd5f2 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -3,11 +3,14 @@ use crate::coverageinfo;
 use crate::llvm;
 
 use llvm::coverageinfo::CounterMappingRegion;
-use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression};
+use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression, FunctionCoverage};
 use rustc_codegen_ssa::traits::ConstMethods;
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE};
 use rustc_llvm::RustString;
 use rustc_middle::mir::coverage::CodeRegion;
+use rustc_middle::ty::{Instance, TyCtxt};
+use rustc_span::Symbol;
 
 use std::ffi::CString;
 
@@ -26,14 +29,17 @@ use tracing::debug;
 /// undocumented details in Clang's implementation (that may or may not be important) were also
 /// replicated for Rust's Coverage Map.
 pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
+    let tcx = cx.tcx;
     // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3).
     // If not, the LLVM Version must be less than 11.
     let version = coverageinfo::mapping_version();
     if version != 3 {
-        cx.tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher.");
+        tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher.");
     }
 
-    let function_coverage_map = match cx.coverage_context() {
+    debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
+
+    let mut function_coverage_map = match cx.coverage_context() {
         Some(ctx) => ctx.take_function_coverage_map(),
         None => return,
     };
@@ -42,14 +48,15 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
         return;
     }
 
+    add_unreachable_coverage(tcx, &mut function_coverage_map);
+
     let mut mapgen = CoverageMapGenerator::new();
 
     // Encode coverage mappings and generate function records
     let mut function_data = Vec::new();
     for (instance, function_coverage) in function_coverage_map {
-        debug!("Generate coverage map for: {:?}", instance);
-
-        let mangled_function_name = cx.tcx.symbol_name(instance).to_string();
+        debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
+        let mangled_function_name = tcx.symbol_name(instance).to_string();
         let function_source_hash = function_coverage.source_hash();
         let (expressions, counter_regions) =
             function_coverage.get_expressions_and_counter_regions();
@@ -228,3 +235,156 @@ fn save_function_record(
     let is_used = true;
     coverageinfo::save_func_record_to_mod(cx, func_name_hash, func_record_val, is_used);
 }
+
+/// When finalizing the coverage map, `FunctionCoverage` only has the `CodeRegion`s and counters for
+/// the functions that went through codegen; such as public functions and "used" functions
+/// (functions referenced by other "used" or public items). Any other functions considered unused,
+/// or "Unreachable" were still parsed and processed through the MIR stage.
+///
+/// We can find the unreachable functions by the set difference of all MIR `DefId`s (`tcx` query
+/// `mir_keys`) minus the codegenned `DefId`s (`tcx` query `collect_and_partition_mono_items`).
+///
+/// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and
+/// this function is processing a `function_coverage_map` for the functions (`Instance`/`DefId`)
+/// allocated to only one of those CGUs. We must NOT inject any "Unreachable" functions's
+/// `CodeRegion`s more than once, so we have to pick which CGU's `function_coverage_map` to add
+/// each "Unreachable" function to.
+///
+/// Some constraints:
+///
+/// 1. The file name of an "Unreachable" function must match the file name of the existing
+///    codegenned (covered) function to which the unreachable code regions will be added.
+/// 2. The function to which the unreachable code regions will be added must not be a genaric
+///    function (must not have type parameters) because the coverage tools will get confused
+///    if the codegenned function has more than one instantiation and additional `CodeRegion`s
+///    attached to only one of those instantiations.
+fn add_unreachable_coverage<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    function_coverage_map: &mut FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>>,
+) {
+    // FIXME(#79622): Can this solution be simplified and/or improved? Are there other sources
+    // of compiler state data that might help (or better sources that could be exposed, but
+    // aren't yet)?
+
+    // Note: If the crate *only* defines generic functions, there are no codegenerated non-generic
+    // functions to add any unreachable code to. In this case, the unreachable code regions will
+    // have no coverage, instead of having coverage with zero executions.
+    //
+    // This is probably still an improvement over Clang, which does not generate any coverage
+    // for uninstantiated template functions.
+
+    let has_non_generic_def_ids =
+        function_coverage_map.keys().any(|instance| instance.def.attrs(tcx).len() == 0);
+
+    if !has_non_generic_def_ids {
+        // There are no non-generic functions to add unreachable `CodeRegion`s to
+        return;
+    }
+
+    let all_def_ids: DefIdSet =
+        tcx.mir_keys(LOCAL_CRATE).iter().map(|local_def_id| local_def_id.to_def_id()).collect();
+
+    let (codegenned_def_ids, _) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
+
+    let mut unreachable_def_ids_by_file: FxHashMap<Symbol, Vec<DefId>> = FxHashMap::default();
+    for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) {
+        // Make sure the non-codegenned (unreachable) function has a file_name
+        if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) {
+            let def_ids = unreachable_def_ids_by_file
+                .entry(*non_codegenned_file_name)
+                .or_insert_with(|| Vec::new());
+            def_ids.push(non_codegenned_def_id);
+        }
+    }
+
+    if unreachable_def_ids_by_file.is_empty() {
+        // There are no unreachable functions with file names to add (in any CGU)
+        return;
+    }
+
+    // Since there may be multiple `CodegenUnit`s, some codegenned_def_ids may be codegenned in a
+    // different CGU, and will be added to the function_coverage_map for each CGU. Determine which
+    // function_coverage_map has the responsibility for publishing unreachable coverage
+    // based on file name:
+    //
+    // For each covered file name, sort ONLY the non-generic codegenned_def_ids, and if
+    // covered_def_ids.contains(the first def_id) for a given file_name, add the unreachable code
+    // region in this function_coverage_map. Otherwise, ignore it and assume another CGU's
+    // function_coverage_map will be adding it (because it will be first for one, and only one,
+    // of them).
+    let mut sorted_codegenned_def_ids: Vec<DefId> =
+        codegenned_def_ids.iter().map(|def_id| *def_id).collect();
+    sorted_codegenned_def_ids.sort_unstable();
+
+    let mut first_covered_def_id_by_file: FxHashMap<Symbol, DefId> = FxHashMap::default();
+    for &def_id in sorted_codegenned_def_ids.iter() {
+        // Only consider non-generic functions, to potentially add unreachable code regions
+        if tcx.generics_of(def_id).count() == 0 {
+            if let Some(covered_file_name) = tcx.covered_file_name(def_id) {
+                // Only add files known to have unreachable functions
+                if unreachable_def_ids_by_file.contains_key(covered_file_name) {
+                    first_covered_def_id_by_file.entry(*covered_file_name).or_insert(def_id);
+                }
+            }
+        }
+    }
+
+    // Get the set of def_ids with coverage regions, known by *this* CoverageContext.
+    let cgu_covered_def_ids: DefIdSet =
+        function_coverage_map.keys().map(|instance| instance.def.def_id()).collect();
+
+    let mut cgu_covered_files: FxHashSet<Symbol> = first_covered_def_id_by_file
+        .iter()
+        .filter_map(
+            |(&file_name, def_id)| {
+                if cgu_covered_def_ids.contains(def_id) { Some(file_name) } else { None }
+            },
+        )
+        .collect();
+
+    // Find the first covered, non-generic function (instance) for each cgu_covered_file. Take the
+    // unreachable code regions for that file, and add them to the function.
+    //
+    // There are three `for` loops here, but (a) the lists have already been reduced to the minimum
+    // required values, the lists are further reduced (by `remove()` calls) when elements are no
+    // longer needed, and there are several opportunities to branch out of loops early.
+    for (instance, function_coverage) in function_coverage_map.iter_mut() {
+        if instance.def.attrs(tcx).len() > 0 {
+            continue;
+        }
+        // The covered function is not generic...
+        let covered_def_id = instance.def.def_id();
+        if let Some(covered_file_name) = tcx.covered_file_name(covered_def_id) {
+            if !cgu_covered_files.remove(&covered_file_name) {
+                continue;
+            }
+            // The covered function's file is one of the files with unreachable code regions, so
+            // all of the unreachable code regions for this file will be added to this function.
+            for def_id in
+                unreachable_def_ids_by_file.remove(&covered_file_name).into_iter().flatten()
+            {
+                // Note, this loop adds an unreachable code regions for each MIR-derived region.
+                // Alternatively, we could add a single code region for the maximum span of all
+                // code regions here.
+                //
+                // Observed downsides of this approach are:
+                //
+                // 1. The coverage results will appear inconsistent compared with the same (or
+                //    similar) code in a function that is reached.
+                // 2. If the function is unreachable from one crate but reachable when compiling
+                //    another referencing crate (such as a cross-crate reference to a
+                //    generic function or inlined function), actual coverage regions overlaid
+                //    on a single larger code span of `Zero` coverage can appear confusing or
+                //    wrong. Chaning the unreachable coverage from a `code_region` to a
+                //    `gap_region` can help, but still can look odd with `0` line counts for
+                //    lines between executed (> 0) lines (such as for blank lines or comments).
+                for &region in tcx.covered_code_regions(def_id) {
+                    function_coverage.add_unreachable_region(region.clone());
+                }
+            }
+            if cgu_covered_files.is_empty() {
+                break;
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 70b92b234e9..8ec1eed4404 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -2,6 +2,7 @@
 #![feature(bool_to_option)]
 #![feature(option_expect_none)]
 #![feature(box_patterns)]
+#![feature(drain_filter)]
 #![feature(try_blocks)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index e59832a8eed..ce56f163549 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1395,6 +1395,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         dst: PlaceRef<'tcx, Bx::Value>,
     ) {
         let src = self.codegen_operand(bx, src);
+
+        // Special-case transmutes between scalars as simple bitcasts.
+        match (&src.layout.abi, &dst.layout.abi) {
+            (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
+                // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
+                if (src_scalar.value == abi::Pointer) == (dst_scalar.value == abi::Pointer) {
+                    assert_eq!(src.layout.size, dst.layout.size);
+
+                    // NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
+                    // conversions allow handling `bool`s the same as `u8`s.
+                    let src = bx.from_immediate(src.immediate());
+                    let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout));
+                    Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
+                    return;
+                }
+            }
+            _ => {}
+        }
+
         let llty = bx.backend_type(src.layout);
         let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
         let align = src.layout.align.abi.min(dst.align);
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 94340e92048..72a64a8c510 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -437,16 +437,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 match split[1] {
                     "cxchg" | "cxchgweak" => {
                         let ty = substs.type_at(0);
-                        if int_type_width_signed(ty, bx.tcx()).is_some() {
+                        if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
                             let weak = split[1] == "cxchgweak";
-                            let pair = bx.atomic_cmpxchg(
-                                args[0].immediate(),
-                                args[1].immediate(),
-                                args[2].immediate(),
-                                order,
-                                failorder,
-                                weak,
-                            );
+                            let mut dst = args[0].immediate();
+                            let mut cmp = args[1].immediate();
+                            let mut src = args[2].immediate();
+                            if ty.is_unsafe_ptr() {
+                                // Some platforms do not support atomic operations on pointers,
+                                // so we cast to integer first.
+                                let ptr_llty = bx.type_ptr_to(bx.type_isize());
+                                dst = bx.pointercast(dst, ptr_llty);
+                                cmp = bx.ptrtoint(cmp, bx.type_isize());
+                                src = bx.ptrtoint(src, bx.type_isize());
+                            }
+                            let pair = bx.atomic_cmpxchg(dst, cmp, src, order, failorder, weak);
                             let val = bx.extract_value(pair, 0);
                             let success = bx.extract_value(pair, 1);
                             let val = bx.from_immediate(val);
@@ -464,9 +468,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
                     "load" => {
                         let ty = substs.type_at(0);
-                        if int_type_width_signed(ty, bx.tcx()).is_some() {
-                            let size = bx.layout_of(ty).size;
-                            bx.atomic_load(args[0].immediate(), order, size)
+                        if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
+                            let layout = bx.layout_of(ty);
+                            let size = layout.size;
+                            let mut source = args[0].immediate();
+                            if ty.is_unsafe_ptr() {
+                                // Some platforms do not support atomic operations on pointers,
+                                // so we cast to integer first...
+                                let ptr_llty = bx.type_ptr_to(bx.type_isize());
+                                source = bx.pointercast(source, ptr_llty);
+                            }
+                            let result = bx.atomic_load(source, order, size);
+                            if ty.is_unsafe_ptr() {
+                                // ... and then cast the result back to a pointer
+                                bx.inttoptr(result, bx.backend_type(layout))
+                            } else {
+                                result
+                            }
                         } else {
                             return invalid_monomorphization(ty);
                         }
@@ -474,9 +492,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
                     "store" => {
                         let ty = substs.type_at(0);
-                        if int_type_width_signed(ty, bx.tcx()).is_some() {
+                        if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
                             let size = bx.layout_of(ty).size;
-                            bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size);
+                            let mut val = args[1].immediate();
+                            let mut ptr = args[0].immediate();
+                            if ty.is_unsafe_ptr() {
+                                // Some platforms do not support atomic operations on pointers,
+                                // so we cast to integer first.
+                                let ptr_llty = bx.type_ptr_to(bx.type_isize());
+                                ptr = bx.pointercast(ptr, ptr_llty);
+                                val = bx.ptrtoint(val, bx.type_isize());
+                            }
+                            bx.atomic_store(val, ptr, order, size);
                             return;
                         } else {
                             return invalid_monomorphization(ty);
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index c1741bfaaba..b3466f49b9f 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -223,7 +223,6 @@ fn run_compiler(
             file_loader: None,
             diagnostic_output,
             stderr: None,
-            crate_name: None,
             lint_caps: Default::default(),
             register_lints: None,
             override_queries: None,
@@ -307,7 +306,6 @@ fn run_compiler(
         file_loader,
         diagnostic_output,
         stderr: None,
-        crate_name: None,
         lint_caps: Default::default(),
         register_lints: None,
         override_queries: None,
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 0a88759f84c..fef6602b9cc 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -111,6 +111,7 @@ E0206: include_str!("./error_codes/E0206.md"),
 E0207: include_str!("./error_codes/E0207.md"),
 E0210: include_str!("./error_codes/E0210.md"),
 E0211: include_str!("./error_codes/E0211.md"),
+E0212: include_str!("./error_codes/E0212.md"),
 E0214: include_str!("./error_codes/E0214.md"),
 E0220: include_str!("./error_codes/E0220.md"),
 E0221: include_str!("./error_codes/E0221.md"),
@@ -283,6 +284,7 @@ E0537: include_str!("./error_codes/E0537.md"),
 E0538: include_str!("./error_codes/E0538.md"),
 E0539: include_str!("./error_codes/E0539.md"),
 E0541: include_str!("./error_codes/E0541.md"),
+E0546: include_str!("./error_codes/E0546.md"),
 E0550: include_str!("./error_codes/E0550.md"),
 E0551: include_str!("./error_codes/E0551.md"),
 E0552: include_str!("./error_codes/E0552.md"),
@@ -502,7 +504,6 @@ E0779: include_str!("./error_codes/E0779.md"),
 //  E0196, // cannot determine a type for this closure
     E0208,
 //  E0209, // builtin traits can only be implemented on structs or enums
-    E0212, // cannot extract an associated type from a higher-ranked trait bound
 //  E0213, // associated types are not accepted in this context
 //  E0215, // angle-bracket notation is not stable with `Fn`
 //  E0216, // parenthetical notation is only stable with `Fn`
@@ -603,7 +604,6 @@ E0779: include_str!("./error_codes/E0779.md"),
     E0543, // missing 'reason'
     E0544, // multiple stability levels
     E0545, // incorrect 'issue'
-    E0546, // missing 'feature'
     E0547, // missing 'issue'
 //  E0548, // replaced with a generic attribute input check
     // rustc_deprecated attribute must be paired with either stable or unstable
diff --git a/compiler/rustc_error_codes/src/error_codes/E0212.md b/compiler/rustc_error_codes/src/error_codes/E0212.md
new file mode 100644
index 00000000000..17465414650
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0212.md
@@ -0,0 +1,35 @@
+Cannot use the associated type of
+a trait with uninferred generic parameters.
+
+Erroneous code example:
+
+```compile_fail,E0212
+pub trait Foo<T> {
+    type A;
+
+    fn get(&self, t: T) -> Self::A;
+}
+
+fn foo2<I : for<'x> Foo<&'x isize>>(
+    field: I::A) {} // error!
+```
+
+In this example, we have to instantiate `'x`, and
+we don't know what lifetime to instantiate it with.
+To fix this, spell out the precise lifetimes involved.
+Example:
+
+```
+pub trait Foo<T> {
+    type A;
+
+    fn get(&self, t: T) -> Self::A;
+}
+
+fn foo3<I : for<'x> Foo<&'x isize>>(
+    x: <I as Foo<&isize>>::A) {} // ok!
+
+
+fn foo4<'a, I : for<'x> Foo<&'x isize>>(
+    x: <I as Foo<&'a isize>>::A) {} // ok!
+```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0390.md b/compiler/rustc_error_codes/src/error_codes/E0390.md
index ecc5b5568ad..7a13160d098 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0390.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0390.md
@@ -1,4 +1,4 @@
-A method was implemented on a primitive type.
+A method or constant was implemented on a primitive type.
 
 Erroneous code example:
 
@@ -12,7 +12,8 @@ impl *mut Foo {}
 //        `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive
 ```
 
-This isn't allowed, but using a trait to implement a method is a good solution.
+This isn't allowed, but using a trait to implement a method or constant
+is a good solution.
 Example:
 
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0546.md b/compiler/rustc_error_codes/src/error_codes/E0546.md
new file mode 100644
index 00000000000..b2df22c0f8f
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0546.md
@@ -0,0 +1,27 @@
+A feature name is missing.
+
+Erroneous code example:
+
+```compile_fail,E0546
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[unstable(issue = "none")] // invalid
+fn unstable_fn() {}
+
+#[stable(since = "1.0.0")] // invalid
+fn stable_fn() {}
+```
+
+To fix the issue you need to provide a feature name.
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[unstable(feature = "unstable_fn", issue = "none")] // ok!
+fn unstable_fn() {}
+
+#[stable(feature = "stable_fn", since = "1.0.0")] // ok!
+fn stable_fn() {}
+```
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index b1071bf4308..335f3b7a9a0 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -235,12 +235,10 @@ impl Annotatable {
     pub fn derive_allowed(&self) -> bool {
         match *self {
             Annotatable::Stmt(ref stmt) => match stmt.kind {
-                ast::StmtKind::Item(ref item) => match item.kind {
-                    ast::ItemKind::Struct(..)
-                    | ast::ItemKind::Enum(..)
-                    | ast::ItemKind::Union(..) => true,
-                    _ => false,
-                },
+                ast::StmtKind::Item(ref item) => matches!(
+                    item.kind,
+                    ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..)
+                ),
                 _ => false,
             },
             Annotatable::Item(ref item) => match item.kind {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 37ff6b9b368..2da5bde028f 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1134,7 +1134,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
             if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
                 // Collect the invoc regardless of whether or not attributes are permitted here
                 // expansion will eat the attribute so it won't error later.
-                attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr));
+                if let Some(attr) = attr.0.as_ref() {
+                    self.cfg.maybe_emit_expr_attr_err(attr)
+                }
 
                 // AstFragmentKind::Expr requires the macro to emit an expression.
                 return self
@@ -1231,7 +1233,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
             self.cfg.configure_expr_kind(&mut expr.kind);
 
             if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
-                attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr));
+                if let Some(attr) = attr.0.as_ref() {
+                    self.cfg.maybe_emit_expr_attr_err(attr)
+                }
 
                 return self
                     .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 75337634d3f..845e03150d7 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -620,6 +620,9 @@ declare_features! (
     /// Allows capturing disjoint fields in a closure/generator (RFC 2229).
     (active, capture_disjoint_fields, "1.49.0", Some(53488), None),
 
+    /// Allows arbitrary expressions in key-value attributes at parse time.
+    (active, extended_key_value_attributes, "1.50.0", Some(78835), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index 44dfdcfccab..c7dc66b70fe 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -14,7 +14,7 @@ macro_rules! arena_types {
             // HIR types
             [few] hir_krate: rustc_hir::Crate<$tcx>,
             [] arm: rustc_hir::Arm<$tcx>,
-            [] asm_operand: rustc_hir::InlineAsmOperand<$tcx>,
+            [] asm_operand: (rustc_hir::InlineAsmOperand<$tcx>, Span),
             [] asm_template: rustc_ast::InlineAsmTemplatePiece,
             [] attribute: rustc_ast::Attribute,
             [] block: rustc_hir::Block<$tcx>,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index f01d4417105..280e863d474 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2143,7 +2143,7 @@ impl<'hir> InlineAsmOperand<'hir> {
 #[derive(Debug, HashStable_Generic)]
 pub struct InlineAsm<'hir> {
     pub template: &'hir [InlineAsmTemplatePiece],
-    pub operands: &'hir [InlineAsmOperand<'hir>],
+    pub operands: &'hir [(InlineAsmOperand<'hir>, Span)],
     pub options: InlineAsmOptions,
     pub line_spans: &'hir [Span],
 }
@@ -2401,7 +2401,7 @@ impl StructField<'_> {
     // Still necessary in couple of places
     pub fn is_positional(&self) -> bool {
         let first = self.ident.as_str().as_bytes()[0];
-        first >= b'0' && first <= b'9'
+        (b'0'..=b'9').contains(&first)
     }
 }
 
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 3e8fc689acf..3c330c5d6c5 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -1191,7 +1191,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             walk_list!(visitor, visit_expr, optional_expression);
         }
         ExprKind::InlineAsm(ref asm) => {
-            for op in asm.operands {
+            for (op, _op_sp) in asm.operands {
                 match op {
                     InlineAsmOperand::In { expr, .. }
                     | InlineAsmOperand::InOut { expr, .. }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 25b09d76295..597c55b4bd7 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1462,7 +1462,7 @@ impl<'a> State<'a> {
 
                 let mut args = vec![];
                 args.push(AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(&a.template)));
-                args.extend(a.operands.iter().map(|o| AsmArg::Operand(o)));
+                args.extend(a.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
                 if !a.options.is_empty() {
                     args.push(AsmArg::Options(a.options));
                 }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 6781fbc95c0..8a60b196e5e 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -505,7 +505,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             let canon_value = Canonical {
                 max_universe: ty::UniverseIndex::ROOT,
                 variables: List::empty(),
-                value: value.clone(),
+                value,
             };
             return canon_value;
         }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 59786059fae..cdd68d83f22 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -121,7 +121,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 
                 (Some(ret_span), _) => {
                     let sup_future = self.future_return_type(scope_def_id_sup);
-                    let (return_type, action) = if let Some(_) = sup_future {
+                    let (return_type, action) = if sup_future.is_some() {
                         ("returned future", "held across an await point")
                     } else {
                         ("return type", "returned")
@@ -140,7 +140,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 }
                 (_, Some(ret_span)) => {
                     let sub_future = self.future_return_type(scope_def_id_sub);
-                    let (return_type, action) = if let Some(_) = sub_future {
+                    let (return_type, action) = if sub_future.is_some() {
                         ("returned future", "held across an await point")
                     } else {
                         ("return type", "returned")
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index 9d9ecf5b384..39043980dc4 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -24,9 +24,9 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
         // as-is, we need to do some extra work here in order to make sure
         // that function subtyping works correctly with respect to regions
         //
-        // Note: this is a subtle algorithm.  For a full explanation,
-        // please see the large comment at the end of the file in the (inlined) module
-        // `doc`.
+        // Note: this is a subtle algorithm.  For a full explanation, please see
+        // the rustc dev guide:
+        // <https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html>
 
         let span = self.trace.cause.span;
 
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 93863ef1d50..8273c2d291d 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -1,10 +1,9 @@
 use smallvec::smallvec;
 
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::ty::outlives::Component;
 use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
-use rustc_span::symbol::Ident;
 
 pub fn anonymize_predicate<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -288,37 +287,6 @@ pub fn transitive_bounds<'tcx>(
     elaborate_trait_refs(tcx, bounds).filter_to_traits()
 }
 
-/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may
-/// define the given associated type `assoc_name`. It uses the
-/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that
-/// aren't related to `assoc_item`.  This is used when resolving types like `Self::Item` or
-/// `T::Item` and helps to avoid cycle errors (see e.g. #35237).
-pub fn transitive_bounds_that_define_assoc_type<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
-    assoc_name: Ident,
-) -> FxIndexSet<ty::PolyTraitRef<'tcx>> {
-    let mut stack: Vec<_> = bounds.collect();
-    let mut trait_refs = FxIndexSet::default();
-
-    while let Some(trait_ref) = stack.pop() {
-        if trait_refs.insert(trait_ref) {
-            let super_predicates =
-                tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), Some(assoc_name)));
-            for (super_predicate, _) in super_predicates.predicates {
-                let bound_predicate = super_predicate.bound_atom();
-                let subst_predicate = super_predicate
-                    .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder()));
-                if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() {
-                    stack.push(binder.value);
-                }
-            }
-        }
-    }
-
-    trait_refs
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Other
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 11dd6ec32c0..acd49d86c2c 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -34,7 +34,6 @@ pub struct Compiler {
     pub(crate) input_path: Option<PathBuf>,
     pub(crate) output_dir: Option<PathBuf>,
     pub(crate) output_file: Option<PathBuf>,
-    pub(crate) crate_name: Option<String>,
     pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
     pub(crate) override_queries:
         Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
@@ -140,7 +139,6 @@ pub struct Config {
     /// Set to capture stderr output during compiler execution
     pub stderr: Option<Arc<Mutex<Vec<u8>>>>,
 
-    pub crate_name: Option<String>,
     pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
 
     /// This is a callback from the driver that is called when we're registering lints;
@@ -185,7 +183,6 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
         input_path: config.input_path,
         output_dir: config.output_dir,
         output_file: config.output_file,
-        crate_name: config.crate_name,
         register_lints: config.register_lints,
         override_queries: config.override_queries,
     };
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index a2704c3adbf..4c340b3fc1f 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -156,13 +156,11 @@ impl<'tcx> Queries<'tcx> {
 
     pub fn crate_name(&self) -> Result<&Query<String>> {
         self.crate_name.compute(|| {
-            Ok(match self.compiler.crate_name {
-                Some(ref crate_name) => crate_name.clone(),
-                None => {
-                    let parse_result = self.parse()?;
-                    let krate = parse_result.peek();
-                    find_crate_name(self.session(), &krate.attrs, &self.compiler.input)
-                }
+            Ok({
+                let parse_result = self.parse()?;
+                let krate = parse_result.peek();
+                // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
+                find_crate_name(self.session(), &krate.attrs, &self.compiler.input)
             })
         })
     }
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 6539419aefb..44fc4db7dc1 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -267,8 +267,8 @@ pub fn is_whitespace(c: char) -> bool {
 pub fn is_id_start(c: char) -> bool {
     // This is XID_Start OR '_' (which formally is not a XID_Start).
     // We also add fast-path for ascii idents
-    ('a' <= c && c <= 'z')
-        || ('A' <= c && c <= 'Z')
+    ('a'..='z').contains(&c)
+        || ('A'..='Z').contains(&c)
         || c == '_'
         || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_start(c))
 }
@@ -279,9 +279,9 @@ pub fn is_id_start(c: char) -> bool {
 pub fn is_id_continue(c: char) -> bool {
     // This is exactly XID_Continue.
     // We also add fast-path for ascii idents
-    ('a' <= c && c <= 'z')
-        || ('A' <= c && c <= 'Z')
-        || ('0' <= c && c <= '9')
+    ('a'..='z').contains(&c)
+        || ('A'..='Z').contains(&c)
+        || ('0'..='9').contains(&c)
         || c == '_'
         || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c))
 }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index c2d98b8e4ad..af5972c6c81 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -10,7 +10,7 @@ use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath,
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 
 declare_tool_lint! {
     pub rustc::DEFAULT_HASH_TYPES,
@@ -267,3 +267,47 @@ impl EarlyLintPass for LintPassImpl {
         }
     }
 }
+
+declare_tool_lint! {
+    pub rustc::EXISTING_DOC_KEYWORD,
+    Allow,
+    "Check that documented keywords in std and core actually exist",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(ExistingDocKeyword => [EXISTING_DOC_KEYWORD]);
+
+fn is_doc_keyword(s: Symbol) -> bool {
+    s <= kw::Union
+}
+
+impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
+        for attr in item.attrs {
+            if !attr.has_name(sym::doc) {
+                continue;
+            }
+            if let Some(list) = attr.meta_item_list() {
+                for nested in list {
+                    if nested.has_name(sym::keyword) {
+                        let v = nested
+                            .value_str()
+                            .expect("#[doc(keyword = \"...\")] expected a value!");
+                        if is_doc_keyword(v) {
+                            return;
+                        }
+                        cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
+                            lint.build(&format!(
+                                "Found non-existing keyword `{}` used in \
+                                     `#[doc(keyword = \"...\")]`",
+                                v,
+                            ))
+                            .help("only existing keywords are allowed in core/std")
+                            .emit();
+                        });
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 81549be4b09..80ef855c385 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -463,6 +463,8 @@ fn register_internals(store: &mut LintStore) {
     store.register_early_pass(|| box DefaultHashTypes::new());
     store.register_lints(&LintPassImpl::get_lints());
     store.register_early_pass(|| box LintPassImpl);
+    store.register_lints(&ExistingDocKeyword::get_lints());
+    store.register_late_pass(|| box ExistingDocKeyword);
     store.register_lints(&TyTyKind::get_lints());
     store.register_late_pass(|| box TyTyKind);
     store.register_group(
@@ -475,6 +477,7 @@ fn register_internals(store: &mut LintStore) {
             LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),
             LintId::of(TY_PASS_BY_REFERENCE),
             LintId::of(USAGE_OF_QUALIFIED_TY),
+            LintId::of(EXISTING_DOC_KEYWORD),
         ],
     );
 }
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 2720c376774..6d61b86f32e 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -131,7 +131,7 @@ impl NonCamelCaseTypes {
                 let cc = to_camel_case(name);
                 // We cannot provide meaningful suggestions
                 // if the characters are in the category of "Lowercase Letter".
-                if name.to_string() != cc {
+                if *name != cc {
                     err.span_suggestion(
                         ident.span,
                         "convert the identifier to upper camel case",
@@ -271,7 +271,7 @@ impl NonSnakeCase {
                 let mut err = lint.build(&msg);
                 // We cannot provide meaningful suggestions
                 // if the characters are in the category of "Uppercase Letter".
-                if name.to_string() != sc {
+                if *name != sc {
                     // We have a valid span in almost all cases, but we don't have one when linting a crate
                     // name provided via the command line.
                     if !ident.span.is_dummy() {
@@ -455,7 +455,7 @@ impl NonUpperCaseGlobals {
                     lint.build(&format!("{} `{}` should have an upper case name", sort, name));
                 // We cannot provide meaningful suggestions
                 // if the characters are in the category of "Lowercase Letter".
-                if name.to_string() != uc {
+                if *name != uc {
                     err.span_suggestion(
                         ident.span,
                         "convert the identifier to upper case",
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index fa82dce0ae2..a9358c9610a 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2742,6 +2742,50 @@ declare_lint! {
     "detects deprecation attributes with no effect",
 }
 
+declare_lint! {
+    /// The `unsupported_naked_functions` lint detects naked function
+    /// definitions that are unsupported but were previously accepted.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(naked_functions)]
+    ///
+    /// #[naked]
+    /// pub fn f() -> u32 {
+    ///     42
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The naked functions must be defined using a single inline assembly
+    /// block.
+    ///
+    /// The execution must never fall through past the end of the assembly
+    /// code so the block must use `noreturn` option. The asm block can also
+    /// use `att_syntax` option, but other options are not allowed.
+    ///
+    /// The asm block must not contain any operands other than `const` and
+    /// `sym`. Additionally, naked function should specify a non-Rust ABI.
+    ///
+    /// While other definitions of naked functions were previously accepted,
+    /// they are unsupported and might not work reliably. This is a
+    /// [future-incompatible] lint that will transition into hard error in
+    /// the future.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub UNSUPPORTED_NAKED_FUNCTIONS,
+    Warn,
+    "unsupported naked function definitions",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #32408 <https://github.com/rust-lang/rust/issues/32408>",
+        edition: None,
+    };
+}
+
 declare_tool_lint! {
     pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
     Deny,
@@ -2832,6 +2876,7 @@ declare_lint_pass! {
         UNINHABITED_STATIC,
         FUNCTION_ITEM_REFERENCES,
         USELESS_DEPRECATED,
+        UNSUPPORTED_NAKED_FUNCTIONS,
     ]
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index f53a4027806..43f7b2a9928 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1553,6 +1553,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             return Some(DefId { krate, index: def_index_guess });
         }
 
+        let is_proc_macro = self.is_proc_macro_crate();
+
         // Slow path: We need to find out the new `DefIndex` of the provided
         // `DefPathHash`, if its still exists. This requires decoding every `DefPathHash`
         // stored in this crate.
@@ -1561,9 +1563,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             let mut map = FxHashMap::with_capacity_and_hasher(end_id as usize, Default::default());
             for i in 0..end_id {
                 let def_index = DefIndex::from_u32(i);
-                let hash =
-                    self.root.tables.def_path_hashes.get(self, def_index).unwrap().decode(self);
-                map.insert(hash, def_index);
+                // There may be gaps in the encoded table if we're decoding a proc-macro crate
+                if let Some(hash) = self.root.tables.def_path_hashes.get(self, def_index) {
+                    map.insert(hash.decode(self), def_index);
+                } else if !is_proc_macro {
+                    panic!("Missing def_path_hashes entry for {:?}", def_index);
+                }
             }
             map
         });
@@ -1592,23 +1597,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.def_path_hash_unlocked(index, &mut def_path_hashes)
     }
 
-    fn all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> {
-        let mut def_path_hashes = self.def_path_hash_cache.lock();
-        let mut def_index_to_data = |index| {
-            (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index))
-        };
-        if let Some(data) = &self.root.proc_macro_data {
-            std::iter::once(CRATE_DEF_INDEX)
-                .chain(data.macros.decode(self))
-                .map(def_index_to_data)
-                .collect()
-        } else {
-            (0..self.num_def_ids())
-                .map(|index| def_index_to_data(DefIndex::from_usize(index)))
-                .collect()
-        }
-    }
-
     /// Get the `DepNodeIndex` corresponding this crate. The result of this
     /// method is cached in the `dep_node_index` field.
     fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 2ffd239b2f0..b7f22885217 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -456,6 +456,10 @@ impl CStore {
     pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId {
         self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
     }
+
+    pub fn num_def_ids(&self, cnum: CrateNum) -> usize {
+        self.get_crate_data(cnum).num_def_ids()
+    }
 }
 
 impl CrateStore for CStore {
@@ -498,14 +502,6 @@ impl CrateStore for CStore {
         self.get_crate_data(def.krate).def_path_hash(def.index)
     }
 
-    fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)> {
-        self.get_crate_data(cnum).all_def_path_hashes_and_def_ids()
-    }
-
-    fn num_def_ids(&self, cnum: CrateNum) -> usize {
-        self.get_crate_data(cnum).num_def_ids()
-    }
-
     // See `CrateMetadataRef::def_path_hash_to_def_id` for more details
     fn def_path_hash_to_def_id(
         &self,
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 672073b1d34..9a42bbe7bac 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -32,6 +32,7 @@ macro_rules! arena_types {
             [decode] borrowck_result:
                 rustc_middle::mir::BorrowCheckResult<$tcx>,
             [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
+            [decode] code_region: rustc_middle::mir::coverage::CodeRegion,
             [] const_allocs: rustc_middle::mir::interpret::Allocation,
             // Required for the incremental on-disk cache
             [few] mir_keys: rustc_hir::def_id::DefIdSet,
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index a94f6d25fc7..e641c1cd77b 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -93,7 +93,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
 
     fn register_reused_dep_path_hash(&self, hash: DefPathHash) {
         if let Some(cache) = self.queries.on_disk_cache.as_ref() {
-            cache.register_reused_dep_path_hash(hash)
+            cache.register_reused_dep_path_hash(*self, hash)
         }
     }
 
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 5e36362ec59..598e28c1a3a 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -47,7 +47,7 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
     }
 }
 
-fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> {
+pub fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> {
     match &node {
         Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
         | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. })
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
index 5da4be4e982..143b3867d9f 100644
--- a/compiler/rustc_middle/src/hir/place.rs
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -4,7 +4,18 @@ use crate::ty::Ty;
 use rustc_hir::HirId;
 use rustc_target::abi::VariantIdx;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    PartialEq,
+    Eq,
+    Hash,
+    TyEncodable,
+    TyDecodable,
+    TypeFoldable,
+    HashStable
+)]
 pub enum PlaceBase {
     /// A temporary variable
     Rvalue,
@@ -16,7 +27,18 @@ pub enum PlaceBase {
     Upvar(ty::UpvarId),
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    PartialEq,
+    Eq,
+    Hash,
+    TyEncodable,
+    TyDecodable,
+    TypeFoldable,
+    HashStable
+)]
 pub enum ProjectionKind {
     /// A dereference of a pointer, reference or `Box<T>` of the given type
     Deref,
@@ -36,7 +58,18 @@ pub enum ProjectionKind {
     Subslice,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    PartialEq,
+    Eq,
+    Hash,
+    TyEncodable,
+    TyDecodable,
+    TypeFoldable,
+    HashStable
+)]
 pub struct Projection<'tcx> {
     /// Type after the projection is being applied.
     pub ty: Ty<'tcx>,
@@ -48,7 +81,7 @@ pub struct Projection<'tcx> {
 /// A `Place` represents how a value is located in memory.
 ///
 /// This is an HIR version of `mir::Place`
-#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
 pub struct Place<'tcx> {
     /// The type of the `PlaceBase`
     pub base_ty: Ty<'tcx>,
@@ -61,7 +94,7 @@ pub struct Place<'tcx> {
 /// A `PlaceWithHirId` represents how a value is located in memory.
 ///
 /// This is an HIR version of `mir::Place`
-#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
 pub struct PlaceWithHirId<'tcx> {
     /// `HirId` of the expression or pattern producing this value.
     pub hir_id: HirId,
diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs
index bd7121ca1d7..6d2c43874bc 100644
--- a/compiler/rustc_middle/src/middle/cstore.rs
+++ b/compiler/rustc_middle/src/middle/cstore.rs
@@ -189,8 +189,6 @@ pub trait CrateStore {
     fn def_kind(&self, def: DefId) -> DefKind;
     fn def_path(&self, def: DefId) -> DefPath;
     fn def_path_hash(&self, def: DefId) -> DefPathHash;
-    fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>;
-    fn num_def_ids(&self, cnum: CrateNum) -> usize;
     fn def_path_hash_to_def_id(
         &self,
         cnum: CrateNum,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index b516810205f..1b5f7a2c12e 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -346,6 +346,21 @@ rustc_queries! {
             cache_on_disk_if { key.is_local() }
         }
 
+        /// Returns the name of the file that contains the function body, if instrumented for coverage.
+        query covered_file_name(key: DefId) -> Option<Symbol> {
+            desc { |tcx| "retrieving the covered file name, if instrumented, for `{}`", tcx.def_path_str(key) }
+            storage(ArenaCacheSelector<'tcx>)
+            cache_on_disk_if { key.is_local() }
+        }
+
+        /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
+        /// function was optimized out before codegen, and before being added to the Coverage Map.
+        query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
+            desc { |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", tcx.def_path_str(key) }
+            storage(ArenaCacheSelector<'tcx>)
+            cache_on_disk_if { key.is_local() }
+        }
+
         /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own
         /// `DefId`. This function returns all promoteds in the specified body. The body references
         /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because
@@ -433,23 +448,12 @@ rustc_queries! {
         /// full predicates are available (note that supertraits have
         /// additional acyclicity requirements).
         query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
-            desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) }
-        }
-
-        /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query
-        /// returns the full set of predicates. If `Some<Ident>`, then the query returns only the
-        /// subset of super-predicates that reference traits that define the given associated type.
-        /// This is used to avoid cycles in resolving types like `T::Item`.
-        query super_predicates_that_define_assoc_type(key: (DefId, Option<rustc_span::symbol::Ident>)) -> ty::GenericPredicates<'tcx> {
-            desc { |tcx| "computing the super traits of `{}`{}",
-                tcx.def_path_str(key.0),
-                if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() },
-            }
+            desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) }
         }
 
         /// To avoid cycles within the predicates of a single item we compute
         /// per-type-parameter predicates for resolving `T::AssocTy`.
-        query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
+        query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> {
             desc { |tcx| "computing the bounds for type parameter `{}`", {
                 let id = tcx.hir().local_def_id_to_hir_id(key.1);
                 tcx.hir().ty_param_name(id)
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 1def4936860..b2fc3710cd6 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -162,7 +162,8 @@ encodable_via_deref! {
     ty::Region<'tcx>,
     &'tcx mir::Body<'tcx>,
     &'tcx mir::UnsafetyCheckResult,
-    &'tcx mir::BorrowCheckResult<'tcx>
+    &'tcx mir::BorrowCheckResult<'tcx>,
+    &'tcx mir::coverage::CodeRegion
 }
 
 pub trait TyDecoder<'tcx>: Decoder {
@@ -376,7 +377,8 @@ impl_decodable_via_ref! {
     &'tcx Allocation,
     &'tcx mir::Body<'tcx>,
     &'tcx mir::UnsafetyCheckResult,
-    &'tcx mir::BorrowCheckResult<'tcx>
+    &'tcx mir::BorrowCheckResult<'tcx>,
+    &'tcx mir::coverage::CodeRegion
 }
 
 #[macro_export]
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index f078bbacfe9..a8d007c0be2 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -51,7 +51,7 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
 use rustc_session::lint::{Level, Lint};
 use rustc_session::Session;
 use rustc_span::source_map::MultiSpan;
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
@@ -624,6 +624,19 @@ impl<'tcx> TypeckResults<'tcx> {
         LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
     }
 
+    /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
+    /// by the closure.
+    pub fn closure_min_captures_flattened(
+        &self,
+        closure_def_id: DefId,
+    ) -> impl Iterator<Item = &ty::CapturedPlace<'tcx>> {
+        self.closure_min_captures
+            .get(&closure_def_id)
+            .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter()))
+            .into_iter()
+            .flatten()
+    }
+
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
         self.upvar_capture_map[&upvar_id]
     }
@@ -2066,42 +2079,6 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }))
     }
 
-    /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
-    /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`.
-    pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
-        self.super_traits_of(trait_def_id).any(|trait_did| {
-            self.associated_items(trait_did)
-                .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did)
-                .is_some()
-        })
-    }
-
-    /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally)
-    /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
-    /// to identify which traits may define a given associated type to help avoid cycle errors.
-    /// Returns a `DefId` iterator.
-    fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
-        let mut set = FxHashSet::default();
-        let mut stack = vec![trait_def_id];
-
-        set.insert(trait_def_id);
-
-        iter::from_fn(move || -> Option<DefId> {
-            let trait_did = stack.pop()?;
-            let generic_predicates = self.super_predicates_of(trait_did);
-
-            for (predicate, _) in generic_predicates.predicates {
-                if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() {
-                    if set.insert(data.def_id()) {
-                        stack.push(data.def_id());
-                    }
-                }
-            }
-
-            Some(trait_did)
-        })
-    }
-
     /// Given a closure signature, returns an equivalent fn signature. Detuples
     /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
     /// you would get a `fn(u32, i32)`.
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 1883c89a151..13c8d6b2bcc 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -581,7 +581,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let mut const_map = FxHashMap::default();
 
         if !value.has_escaping_bound_vars() {
-            (value.clone(), region_map)
+            (value, region_map)
         } else {
             let mut real_fld_r = |br| *region_map.entry(br).or_insert_with(|| fld_r(br));
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 038de42a6f1..7428f34153c 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -588,7 +588,18 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
 #[rustc_diagnostic_item = "Ty"]
 pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    PartialEq,
+    Eq,
+    Hash,
+    TyEncodable,
+    TyDecodable,
+    TypeFoldable,
+    HashStable
+)]
 pub struct UpvarPath {
     pub hir_id: hir::HirId,
 }
@@ -596,7 +607,7 @@ pub struct UpvarPath {
 /// Upvars do not get their own `NodeId`. Instead, we use the pair of
 /// the original var ID (that is, the root variable that is referenced
 /// by the upvar) and the ID of the closure expression.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
 pub struct UpvarId {
     pub var_path: UpvarPath,
     pub closure_expr_id: LocalDefId,
@@ -608,7 +619,7 @@ impl UpvarId {
     }
 }
 
-#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
+#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
     ImmBorrow,
@@ -662,7 +673,7 @@ pub enum BorrowKind {
 
 /// Information describing the capture of an upvar. This is computed
 /// during `typeck`, specifically by `regionck`.
-#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
 pub enum UpvarCapture<'tcx> {
     /// Upvar is captured by value. This is always true when the
     /// closure is labeled `move`, but can also be true in other cases
@@ -679,7 +690,7 @@ pub enum UpvarCapture<'tcx> {
     ByRef(UpvarBorrow<'tcx>),
 }
 
-#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
 pub struct UpvarBorrow<'tcx> {
     /// The kind of borrow: by-ref upvars have access to shared
     /// immutable borrows, which are not part of the normal language
@@ -706,7 +717,7 @@ pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureLis
 pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
 
 /// A `Place` and the corresponding `CaptureInfo`.
-#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
 pub struct CapturedPlace<'tcx> {
     pub place: HirPlace<'tcx>,
     pub info: CaptureInfo<'tcx>,
@@ -715,7 +726,7 @@ pub struct CapturedPlace<'tcx> {
 /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
 /// for a particular capture as well as identifying the part of the source code
 /// that triggered this capture to occur.
-#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
 pub struct CaptureInfo<'tcx> {
     /// Expr Id pointing to use that resulted in selecting the current capture kind
     ///
@@ -1599,34 +1610,59 @@ pub struct BoundConst<'tcx> {
 
 pub type PlaceholderConst<'tcx> = Placeholder<BoundConst<'tcx>>;
 
-/// A `DefId` which is potentially bundled with its corresponding generic parameter
-/// in case `did` is a const argument.
+/// A `DefId` which, in case it is a const argument, is potentially bundled with
+/// the `DefId` of the generic parameter it instantiates.
 ///
-/// This is used to prevent cycle errors during typeck
-/// as `type_of(const_arg)` depends on `typeck(owning_body)`
-/// which once again requires the type of its generic arguments.
-///
-/// Luckily we only need to deal with const arguments once we
-/// know their corresponding parameters. We (ab)use this by
-/// calling `type_of(param_did)` for these arguments.
+/// This is used to avoid calls to `type_of` for const arguments during typeck
+/// which cause cycle errors.
 ///
 /// ```rust
 /// #![feature(const_generics)]
 ///
 /// struct A;
 /// impl A {
-///     fn foo<const N: usize>(&self) -> usize { N }
+///     fn foo<const N: usize>(&self) -> [u8; N] { [0; N] }
+///     //           ^ const parameter
 /// }
 /// struct B;
 /// impl B {
-///     fn foo<const N: u8>(&self) -> usize { 42 }
+///     fn foo<const M: u8>(&self) -> usize { 42 }
+///     //           ^ const parameter
 /// }
 ///
 /// fn main() {
 ///     let a = A;
-///     a.foo::<7>();
+///     let _b = a.foo::<{ 3 + 7 }>();
+///     //               ^^^^^^^^^ const argument
 /// }
 /// ```
+///
+/// Let's look at the call `a.foo::<{ 3 + 7 }>()` here. We do not know
+/// which `foo` is used until we know the type of `a`.
+///
+/// We only know the type of `a` once we are inside of `typeck(main)`.
+/// We also end up normalizing the type of `_b` during `typeck(main)` which
+/// requires us to evaluate the const argument.
+///
+/// To evaluate that const argument we need to know its type,
+/// which we would get using `type_of(const_arg)`. This requires us to
+/// resolve `foo` as it can be either `usize` or `u8` in this example.
+/// However, resolving `foo` once again requires `typeck(main)` to get the type of `a`,
+/// which results in a cycle.
+///
+/// In short we must not call `type_of(const_arg)` during `typeck(main)`.
+///
+/// When first creating the `ty::Const` of the const argument inside of `typeck` we have
+/// already resolved `foo` so we know which const parameter this argument instantiates.
+/// This means that we also know the expected result of `type_of(const_arg)` even if we
+/// aren't allowed to call that query: it is equal to `type_of(const_param)` which is
+/// trivial to compute.
+///
+/// If we now want to use that constant in a place which potentionally needs its type
+/// we also pass the type of its `const_param`. This is the point of `WithOptConstParam`,
+/// except that instead of a `Ty` we bundle the `DefId` of the const parameter.
+/// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some`
+/// to get the type of `did`.
 #[derive(Copy, Clone, Debug, TypeFoldable, Lift, TyEncodable, TyDecodable)]
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
 #[derive(Hash, HashStable)]
@@ -1637,7 +1673,7 @@ pub struct WithOptConstParam<T> {
     ///
     /// Note that even if `did` is a const argument, this may still be `None`.
     /// All queries taking `WithOptConstParam` start by calling `tcx.opt_const_param_of(def.did)`
-    /// to potentially update `param_did` in case it `None`.
+    /// to potentially update `param_did` in the case it is `None`.
     pub const_param_did: Option<DefId>,
 }
 
diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs
index 3949c303f72..a005990264c 100644
--- a/compiler/rustc_middle/src/ty/query/keys.rs
+++ b/compiler/rustc_middle/src/ty/query/keys.rs
@@ -7,7 +7,7 @@ use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_query_system::query::DefaultCacheSelector;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
 
 /// The `Key` trait controls what types can legally be used as the key
@@ -149,28 +149,6 @@ impl Key for (LocalDefId, DefId) {
     }
 }
 
-impl Key for (DefId, Option<Ident>) {
-    type CacheSelector = DefaultCacheSelector;
-
-    fn query_crate(&self) -> CrateNum {
-        self.0.krate
-    }
-    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
-        tcx.def_span(self.0)
-    }
-}
-
-impl Key for (DefId, LocalDefId, Ident) {
-    type CacheSelector = DefaultCacheSelector;
-
-    fn query_crate(&self) -> CrateNum {
-        self.0.krate
-    }
-    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
-        self.1.default_span(tcx)
-    }
-}
-
 impl Key for (CrateNum, DefId) {
     type CacheSelector = DefaultCacheSelector;
 
diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs
index 187f86a52f4..b269dd09b72 100644
--- a/compiler/rustc_middle/src/ty/query/mod.rs
+++ b/compiler/rustc_middle/src/ty/query/mod.rs
@@ -220,7 +220,7 @@ pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &De
                                          .map(|c| c.is_green())
                                          .unwrap_or(false));
 
-                        let key = <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node).unwrap();
+                        let key = <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
                         if queries::$name::cache_on_disk(tcx, &key, None) {
                             let _ = tcx.$name(key);
                         }
diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
index 898cc24992b..3eed94b1ffb 100644
--- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
@@ -454,6 +454,7 @@ impl<'sess> OnDiskCache<'sess> {
     fn try_remap_cnum(&self, tcx: TyCtxt<'_>, cnum: u32) -> Option<CrateNum> {
         let cnum_map =
             self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
+        debug!("try_remap_cnum({}): cnum_map={:?}", cnum, cnum_map);
 
         cnum_map[CrateNum::from_u32(cnum)]
     }
@@ -466,9 +467,22 @@ impl<'sess> OnDiskCache<'sess> {
             .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() });
     }
 
-    pub fn register_reused_dep_path_hash(&self, hash: DefPathHash) {
-        if let Some(old_id) = self.foreign_def_path_hashes.get(&hash) {
-            self.latest_foreign_def_path_hashes.lock().insert(hash, *old_id);
+    /// If the given `hash` still exists in the current compilation,
+    /// calls `store_foreign_def_id` with its current `DefId`.
+    ///
+    /// Normally, `store_foreign_def_id_hash` can be called directly by
+    /// the dependency graph when we construct a `DepNode`. However,
+    /// when we re-use a deserialized `DepNode` from the previous compilation
+    /// session, we only have the `DefPathHash` available. This method is used
+    /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written
+    /// out for usage in the next compilation session.
+    pub fn register_reused_dep_path_hash(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) {
+        // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to
+        // `latest_foreign_def_path_hashes`, since the `RawDefId` might have
+        // changed in the current compilation session (e.g. we've added/removed crates,
+        // or added/removed definitions before/after the target definition).
+        if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) {
+            self.store_foreign_def_id_hash(def_id, hash);
         }
     }
 
@@ -592,6 +606,7 @@ impl<'sess> OnDiskCache<'sess> {
         match cache.entry(hash) {
             Entry::Occupied(e) => *e.get(),
             Entry::Vacant(e) => {
+                debug!("def_path_hash_to_def_id({:?})", hash);
                 // Check if the `DefPathHash` corresponds to a definition in the current
                 // crate
                 if let Some(def_id) = self.local_def_path_hash_to_def_id.get(&hash).cloned() {
@@ -605,9 +620,11 @@ impl<'sess> OnDiskCache<'sess> {
                 // current compilation session, the crate is guaranteed to be the same
                 // (otherwise, we would compute a different `DefPathHash`).
                 let raw_def_id = self.get_raw_def_id(&hash)?;
+                debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id);
                 // If the owning crate no longer exists, the corresponding definition definitely
                 // no longer exists.
                 let krate = self.try_remap_cnum(tcx, raw_def_id.krate)?;
+                debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate);
                 // If our `DefPathHash` corresponded to a definition in the local crate,
                 // we should have either found it in `local_def_path_hash_to_def_id`, or
                 // never attempted to load it in the first place. Any query result or `DepNode`
@@ -621,6 +638,7 @@ impl<'sess> OnDiskCache<'sess> {
                 // Try to find a definition in the current session, using the previous `DefIndex`
                 // as an initial guess.
                 let opt_def_id = tcx.cstore.def_path_hash_to_def_id(krate, raw_def_id.index, hash);
+                debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id);
                 e.insert(opt_def_id);
                 opt_def_id
             }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 72c97dfcf5d..5b787f9841c 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2068,6 +2068,15 @@ impl<'tcx> TyS<'tcx> {
         }
     }
 
+    /// Get the `i`-th element of a tuple.
+    /// Panics when called on anything but a tuple.
+    pub fn tuple_element_ty(&self, i: usize) -> Option<Ty<'tcx>> {
+        match self.kind() {
+            Tuple(substs) => substs.iter().nth(i).map(|field| field.expect_ty()),
+            _ => bug!("tuple_fields called on non-tuple"),
+        }
+    }
+
     /// If the type contains variants, returns the valid range of variant indices.
     //
     // FIXME: This requires the optimized MIR in the case of generators.
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index e23c3f51967..25787f005aa 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -18,7 +18,7 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Integer, Size, TargetDataLayout};
 use smallvec::SmallVec;
 use std::{cmp, fmt};
@@ -221,7 +221,13 @@ impl<'tcx> TyCtxt<'tcx> {
         mut ty: Ty<'tcx>,
         normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>,
     ) -> Ty<'tcx> {
-        loop {
+        for iteration in 0.. {
+            if !self.sess.recursion_limit().value_within_limit(iteration) {
+                return self.ty_error_with_message(
+                    DUMMY_SP,
+                    &format!("reached the recursion limit finding the struct tail for {}", ty),
+                );
+            }
             match *ty.kind() {
                 ty::Adt(def, substs) => {
                     if !def.is_struct() {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
index 2a90fb042dd..6211cf8a9da 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
@@ -445,7 +445,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
             type_name, needle_fr
         );
-        if type_name.find(&format!("'{}", counter)).is_some() {
+        if type_name.contains(&format!("'{}", counter)) {
             // Only add a label if we can confirm that a region was labelled.
             RegionNameHighlight::CannotMatchHirTy(span, type_name)
         } else {
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index de54c5582e0..80eabdd9af8 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -9,6 +9,7 @@ use rustc_hir::{HirId, Node};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::mir::{
     traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
     PlaceRef,
@@ -75,6 +76,7 @@ crate use region_infer::RegionInferenceContext;
 crate struct Upvar {
     name: Symbol,
 
+    // FIXME(project-rfc-2229#8): This should use Place or something similar
     var_hir_id: HirId,
 
     /// If true, the capture is behind a reference.
@@ -155,13 +157,13 @@ fn do_mir_borrowck<'a, 'tcx>(
         infcx.set_tainted_by_errors();
     }
     let upvars: Vec<_> = tables
-        .closure_captures
-        .get(&def.did.to_def_id())
-        .into_iter()
-        .flat_map(|v| v.values())
-        .map(|upvar_id| {
-            let var_hir_id = upvar_id.var_path.hir_id;
-            let capture = tables.upvar_capture(*upvar_id);
+        .closure_min_captures_flattened(def.did.to_def_id())
+        .map(|captured_place| {
+            let var_hir_id = match captured_place.place.base {
+                HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+                _ => bug!("Expected upvar"),
+            };
+            let capture = captured_place.info.capture_kind;
             let by_ref = match capture {
                 ty::UpvarCapture::ByValue(_) => false,
                 ty::UpvarCapture::ByRef(..) => true,
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index a5c45452dec..543b7e7ebaa 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -749,7 +749,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                     (&adt_def.variants[VariantIdx::new(0)], substs)
                 }
                 ty::Closure(_, substs) => {
-                    return match substs.as_closure().upvar_tys().nth(field.index()) {
+                    return match substs
+                        .as_closure()
+                        .tupled_upvars_ty()
+                        .tuple_element_ty(field.index())
+                    {
                         Some(ty) => Ok(ty),
                         None => Err(FieldAccessError::OutOfRange {
                             field_count: substs.as_closure().upvar_tys().count(),
diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs
index 39358e03e75..0e610e37552 100644
--- a/compiler/rustc_mir/src/const_eval/error.rs
+++ b/compiler/rustc_mir/src/const_eval/error.rs
@@ -20,6 +20,7 @@ pub enum ConstEvalErrKind {
     ModifiedGlobal,
     AssertFailure(AssertKind<ConstInt>),
     Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
+    Abort(String),
 }
 
 // The errors become `MachineStop` with plain strings when being raised.
@@ -46,6 +47,7 @@ impl fmt::Display for ConstEvalErrKind {
             Panic { msg, line, col, file } => {
                 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col)
             }
+            Abort(ref msg) => write!(f, "{}", msg),
         }
     }
 }
diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs
index c72089ec55a..740c965e591 100644
--- a/compiler/rustc_mir/src/const_eval/machine.rs
+++ b/compiler/rustc_mir/src/const_eval/machine.rs
@@ -1,17 +1,20 @@
 use rustc_middle::mir;
 use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::InstanceDef;
 use rustc_middle::ty::{self, Ty};
 use std::borrow::Borrow;
 use std::collections::hash_map::Entry;
 use std::hash::Hash;
 
 use rustc_data_structures::fx::FxHashMap;
+use std::fmt;
 
 use rustc_ast::Mutability;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::AssertMessage;
 use rustc_session::Limit;
 use rustc_span::symbol::{sym, Symbol};
+use rustc_target::abi::{Align, Size};
 
 use crate::interpret::{
     self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx,
@@ -37,6 +40,14 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
         if instance.def.requires_caller_location(self.tcx()) {
             return Ok(false);
         }
+        // Only memoize instrinsics. This was added in #79594 while adding the `const_allocate` intrinsic.
+        // We only memoize intrinsics because it would be unsound to memoize functions
+        // which might interact with the heap.
+        // Additionally, const_allocate intrinsic is impure and thus should not be memoized;
+        // it will not be memoized because it has non-ZST args
+        if !matches!(instance.def, InstanceDef::Intrinsic(_)) {
+            return Ok(false);
+        }
         // For the moment we only do this for functions which take no arguments
         // (or all arguments are ZSTs) so that we don't memoize too much.
         if args.iter().any(|a| !a.layout.is_zst()) {
@@ -169,6 +180,28 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
 crate type CompileTimeEvalContext<'mir, 'tcx> =
     InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>;
 
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+pub enum MemoryKind {
+    Heap,
+}
+
+impl fmt::Display for MemoryKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            MemoryKind::Heap => write!(f, "heap allocation"),
+        }
+    }
+}
+
+impl interpret::MayLeak for MemoryKind {
+    #[inline(always)]
+    fn may_leak(self) -> bool {
+        match self {
+            MemoryKind::Heap => false,
+        }
+    }
+}
+
 impl interpret::MayLeak for ! {
     #[inline(always)]
     fn may_leak(self) -> bool {
@@ -212,6 +245,8 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
 impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> {
     compile_time_machine!(<'mir, 'tcx>);
 
+    type MemoryKind = MemoryKind;
+
     type MemoryExtra = MemoryExtra;
 
     fn find_mir_or_eval_fn(
@@ -295,6 +330,22 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 };
                 ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
             }
+            sym::const_allocate => {
+                let size = ecx.read_scalar(args[0])?.to_machine_usize(ecx)?;
+                let align = ecx.read_scalar(args[1])?.to_machine_usize(ecx)?;
+
+                let align = match Align::from_bytes(align) {
+                    Ok(a) => a,
+                    Err(err) => throw_ub_format!("align has to be a power of 2, {}", err),
+                };
+
+                let ptr = ecx.memory.allocate(
+                    Size::from_bytes(size as u64),
+                    align,
+                    interpret::MemoryKind::Machine(MemoryKind::Heap),
+                );
+                ecx.write_scalar(Scalar::Ptr(ptr), dest)?;
+            }
             _ => {
                 return Err(ConstEvalErrKind::NeedsRfc(format!(
                     "calling intrinsic `{}`",
@@ -333,6 +384,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         Err(ConstEvalErrKind::AssertFailure(err).into())
     }
 
+    fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> {
+        Err(ConstEvalErrKind::Abort(msg).into())
+    }
+
     fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> {
         Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into())
     }
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index 05b4d1c410d..3d955576f0f 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -4,7 +4,7 @@ use std::mem;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir::{self as hir, def::DefKind, def_id::DefId, definitions::DefPathData};
+use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use rustc_middle::ich::StableHashingContext;
@@ -700,21 +700,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
 
         // Now mark those locals as dead that we do not want to initialize
-        match self.tcx.def_kind(instance.def_id()) {
-            // statics and constants don't have `Storage*` statements, no need to look for them
-            //
-            // FIXME: The above is likely untrue. See
-            // <https://github.com/rust-lang/rust/pull/70004#issuecomment-602022110>. Is it
-            // okay to ignore `StorageDead`/`StorageLive` annotations during CTFE?
-            DefKind::Static | DefKind::Const | DefKind::AssocConst => {}
-            _ => {
-                // Mark locals that use `Storage*` annotations as dead on function entry.
-                let always_live = AlwaysLiveLocals::new(self.body());
-                for local in locals.indices() {
-                    if !always_live.contains(local) {
-                        locals[local].value = LocalValue::Dead;
-                    }
-                }
+        // Mark locals that use `Storage*` annotations as dead on function entry.
+        let always_live = AlwaysLiveLocals::new(self.body());
+        for local in locals.indices() {
+            if !always_live.contains(local) {
+                locals[local].value = LocalValue::Dead;
             }
         }
         // done
@@ -850,36 +840,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(())
     }
 
-    /// Mark a storage as live, killing the previous content and returning it.
-    /// Remember to deallocate that!
-    pub fn storage_live(
-        &mut self,
-        local: mir::Local,
-    ) -> InterpResult<'tcx, LocalValue<M::PointerTag>> {
+    /// Mark a storage as live, killing the previous content.
+    pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
         assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
         trace!("{:?} is now live", local);
 
         let local_val = LocalValue::Uninitialized;
-        // StorageLive *always* kills the value that's currently stored.
-        // However, we do not error if the variable already is live;
-        // see <https://github.com/rust-lang/rust/issues/42371>.
-        Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val))
+        // StorageLive expects the local to be dead, and marks it live.
+        let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
+        if !matches!(old, LocalValue::Dead) {
+            throw_ub_format!("StorageLive on a local that was already live");
+        }
+        Ok(())
     }
 
-    /// Returns the old value of the local.
-    /// Remember to deallocate that!
-    pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue<M::PointerTag> {
+    pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
         assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
         trace!("{:?} is now dead", local);
 
-        mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead)
+        // It is entirely okay for this local to be already dead (at least that's how we currently generate MIR)
+        let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
+        self.deallocate_local(old)?;
+        Ok(())
     }
 
-    pub(super) fn deallocate_local(
-        &mut self,
-        local: LocalValue<M::PointerTag>,
-    ) -> InterpResult<'tcx> {
-        // FIXME: should we tell the user that there was a local which was never written to?
+    fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
             // All locals have a backing allocation, even if the allocation is empty
             // due to the local having ZST type.
diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs
index 413be427339..01d58c47e3a 100644
--- a/compiler/rustc_mir/src/interpret/intern.rs
+++ b/compiler/rustc_mir/src/interpret/intern.rs
@@ -25,19 +25,20 @@ use rustc_target::abi::Size;
 use rustc_ast::Mutability;
 
 use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, Scalar, ValueVisitor};
+use crate::const_eval;
 
-pub trait CompileTimeMachine<'mir, 'tcx> = Machine<
+pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
     'mir,
     'tcx,
-    MemoryKind = !,
+    MemoryKind = T,
     PointerTag = (),
     ExtraFnVal = !,
     FrameExtra = (),
     AllocExtra = (),
-    MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>,
+    MemoryMap = FxHashMap<AllocId, (MemoryKind<T>, Allocation)>,
 >;
 
-struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> {
+struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> {
     /// The ectx from which we intern.
     ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
     /// Previously encountered safe references.
@@ -74,7 +75,7 @@ struct IsStaticOrFn;
 /// `immutable` things might become mutable if `ty` is not frozen.
 /// `ty` can be `None` if there is no potential interior mutability
 /// to account for (e.g. for vtables).
-fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
+fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>(
     ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
     leftover_allocations: &'rt mut FxHashSet<AllocId>,
     alloc_id: AllocId,
@@ -104,7 +105,10 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
     // This match is just a canary for future changes to `MemoryKind`, which most likely need
     // changes in this function.
     match kind {
-        MemoryKind::Stack | MemoryKind::Vtable | MemoryKind::CallerLocation => {}
+        MemoryKind::Stack
+        | MemoryKind::Machine(const_eval::MemoryKind::Heap)
+        | MemoryKind::Vtable
+        | MemoryKind::CallerLocation => {}
     }
     // Set allocation mutability as appropriate. This is used by LLVM to put things into
     // read-only memory, and also by Miri when evaluating other globals that
@@ -138,7 +142,9 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
     None
 }
 
-impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir, 'tcx, M> {
+impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>
+    InternVisitor<'rt, 'mir, 'tcx, M>
+{
     fn intern_shallow(
         &mut self,
         alloc_id: AllocId,
@@ -149,8 +155,8 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir
     }
 }
 
-impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
-    for InternVisitor<'rt, 'mir, 'tcx, M>
+impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>
+    ValueVisitor<'mir, 'tcx, M> for InternVisitor<'rt, 'mir, 'tcx, M>
 {
     type V = MPlaceTy<'tcx>;
 
@@ -287,7 +293,7 @@ pub enum InternKind {
 /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures
 /// are hard errors.
 #[tracing::instrument(skip(ecx))]
-pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
+pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>(
     ecx: &mut InterpCx<'mir, 'tcx, M>,
     intern_kind: InternKind,
     ret: MPlaceTy<'tcx>,
@@ -418,7 +424,9 @@ where
     Ok(())
 }
 
-impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
+    InterpCx<'mir, 'tcx, M>
+{
     /// A helper function that allocates memory for the layout given and gives you access to mutate
     /// it. Once your own mutation code is done, the backing `Allocation` is removed from the
     /// current `Memory` and returned.
diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs
index f666a89ca56..dfd77a8fca9 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics.rs
@@ -126,7 +126,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             None => match intrinsic_name {
                 sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
                 sym::unreachable => throw_ub!(Unreachable),
-                sym::abort => M::abort(self)?,
+                sym::abort => M::abort(self, "the program aborted execution".to_owned())?,
                 // Unsupported diverging intrinsic.
                 _ => return Ok(false),
             },
@@ -407,6 +407,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             sym::transmute => {
                 self.copy_op_transmute(args[0], dest)?;
             }
+            sym::assert_inhabited => {
+                let ty = instance.substs.type_at(0);
+                let layout = self.layout_of(ty)?;
+
+                if layout.abi.is_uninhabited() {
+                    // The run-time intrinsic panics just to get a good backtrace; here we abort
+                    // since there is no problem showing a backtrace even for aborts.
+                    M::abort(
+                        self,
+                        format!(
+                            "aborted execution: attempted to instantiate uninhabited type `{}`",
+                            ty
+                        ),
+                    )?;
+                }
+            }
             sym::simd_insert => {
                 let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
                 let elem = args[2];
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs
index 66dbacb2f9d..74625569432 100644
--- a/compiler/rustc_mir/src/interpret/machine.rs
+++ b/compiler/rustc_mir/src/interpret/machine.rs
@@ -176,7 +176,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     ) -> InterpResult<'tcx>;
 
     /// Called to evaluate `Abort` MIR terminator.
-    fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> {
+    fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> {
         throw_unsup_format!("aborting execution is not supported")
     }
 
@@ -366,9 +366,9 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     type PointerTag = ();
     type ExtraFnVal = !;
 
-    type MemoryKind = !;
-    type MemoryMap = rustc_data_structures::fx::FxHashMap<AllocId, (MemoryKind<!>, Allocation)>;
-    const GLOBAL_KIND: Option<!> = None; // no copying of globals from `tcx` to machine memory
+    type MemoryMap =
+        rustc_data_structures::fx::FxHashMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>;
+    const GLOBAL_KIND: Option<Self::MemoryKind> = None; // no copying of globals from `tcx` to machine memory
 
     type AllocExtra = ();
     type FrameExtra = ();
@@ -407,7 +407,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
         _memory_extra: &Self::MemoryExtra,
         _id: AllocId,
         alloc: Cow<'b, Allocation>,
-        _kind: Option<MemoryKind<!>>,
+        _kind: Option<MemoryKind<Self::MemoryKind>>,
     ) -> (Cow<'b, Allocation<Self::PointerTag>>, Self::PointerTag) {
         // We do not use a tag so we can just cheaply forward the allocation
         (alloc, ())
diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs
index 156da84f291..95738db1f55 100644
--- a/compiler/rustc_mir/src/interpret/step.rs
+++ b/compiler/rustc_mir/src/interpret/step.rs
@@ -95,14 +95,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             // Mark locals as alive
             StorageLive(local) => {
-                let old_val = self.storage_live(*local)?;
-                self.deallocate_local(old_val)?;
+                self.storage_live(*local)?;
             }
 
             // Mark locals as dead
             StorageDead(local) => {
-                let old_val = self.storage_dead(*local);
-                self.deallocate_local(old_val)?;
+                self.storage_dead(*local)?;
             }
 
             // No dynamic semantics attached to `FakeRead`; MIR
diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs
index bb11c2a23bd..a2931325a28 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_mir/src/interpret/terminator.rs
@@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             Abort => {
-                M::abort(self)?;
+                M::abort(self, "the program aborted execution".to_owned())?;
             }
 
             // When we encounter Resume, we've finished unwinding
diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs
index ec90f063a55..c2165db278f 100644
--- a/compiler/rustc_mir/src/interpret/util.rs
+++ b/compiler/rustc_mir/src/interpret/util.rs
@@ -13,12 +13,13 @@ where
         return Ok(());
     }
 
+    struct FoundParam;
     struct UsedParamsNeedSubstVisitor<'tcx> {
         tcx: TyCtxt<'tcx>,
     }
 
     impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
-        type BreakTy = ();
+        type BreakTy = FoundParam;
 
         fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             if !c.needs_subst() {
@@ -26,7 +27,7 @@ where
             }
 
             match c.val {
-                ty::ConstKind::Param(..) => ControlFlow::BREAK,
+                ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
                 _ => c.super_visit_with(self),
             }
         }
@@ -37,7 +38,7 @@ where
             }
 
             match *ty.kind() {
-                ty::Param(_) => ControlFlow::BREAK,
+                ty::Param(_) => ControlFlow::Break(FoundParam),
                 ty::Closure(def_id, substs)
                 | ty::Generator(def_id, substs, ..)
                 | ty::FnDef(def_id, substs) => {
@@ -76,7 +77,7 @@ where
     }
 
     let mut vis = UsedParamsNeedSubstVisitor { tcx };
-    if ty.visit_with(&mut vis).is_break() {
+    if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
         throw_inval!(TooGeneric);
     } else {
         Ok(())
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index 2ed115b1297..e6d822086f5 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -28,6 +28,7 @@ Rust MIR: a lowered representation of Rust.
 #![feature(or_patterns)]
 #![feature(once_cell)]
 #![feature(control_flow_enum)]
+#![feature(str_split_once)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index abcf1862fd8..1d949e020ed 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -180,6 +180,8 @@ impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> {
 impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> {
     compile_time_machine!(<'mir, 'tcx>);
 
+    type MemoryKind = !;
+
     type MemoryExtra = ();
 
     fn find_mir_or_eval_fn(
diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs
index e9528557b33..af81d9af0e2 100644
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ b/compiler/rustc_mir/src/transform/coverage/debug.rs
@@ -148,40 +148,46 @@ impl DebugOptions {
 
         if let Ok(env_debug_options) = std::env::var(RUSTC_COVERAGE_DEBUG_OPTIONS) {
             for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(',') {
-                let mut setting = setting_str.splitn(2, '=');
-                match setting.next() {
-                    Some(option) if option == "allow_unused_expressions" => {
-                        allow_unused_expressions = bool_option_val(option, setting.next());
+                let (option, value) = match setting_str.split_once('=') {
+                    None => (setting_str, None),
+                    Some((k, v)) => (k, Some(v)),
+                };
+                match option {
+                    "allow_unused_expressions" => {
+                        allow_unused_expressions = bool_option_val(option, value);
                         debug!(
                             "{} env option `allow_unused_expressions` is set to {}",
                             RUSTC_COVERAGE_DEBUG_OPTIONS, allow_unused_expressions
                         );
                     }
-                    Some(option) if option == "counter_format" => {
-                        if let Some(strval) = setting.next() {
-                            counter_format = counter_format_option_val(strval);
-                            debug!(
-                                "{} env option `counter_format` is set to {:?}",
-                                RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format
-                            );
-                        } else {
-                            bug!(
-                                "`{}` option in environment variable {} requires one or more \
-                                plus-separated choices (a non-empty subset of \
-                                `id+block+operation`)",
-                                option,
-                                RUSTC_COVERAGE_DEBUG_OPTIONS
-                            );
-                        }
+                    "counter_format" => {
+                        match value {
+                            None => {
+                                bug!(
+                                    "`{}` option in environment variable {} requires one or more \
+                                    plus-separated choices (a non-empty subset of \
+                                    `id+block+operation`)",
+                                    option,
+                                    RUSTC_COVERAGE_DEBUG_OPTIONS
+                                );
+                            }
+                            Some(val) => {
+                                counter_format = counter_format_option_val(val);
+                                debug!(
+                                    "{} env option `counter_format` is set to {:?}",
+                                    RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format
+                                );
+                            }
+                        };
                     }
-                    Some("") => {}
-                    Some(invalid) => bug!(
-                        "Unsupported setting `{}` in environment variable {}",
-                        invalid,
-                        RUSTC_COVERAGE_DEBUG_OPTIONS
-                    ),
-                    None => {}
-                }
+                    _ => {
+                        bug!(
+                            "Unsupported setting `{}` in environment variable {}",
+                            option,
+                            RUSTC_COVERAGE_DEBUG_OPTIONS
+                        )
+                    }
+                };
             }
         }
 
diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs
index 9d375633dcf..2408a999c05 100644
--- a/compiler/rustc_mir/src/transform/coverage/graph.rs
+++ b/compiler/rustc_mir/src/transform/coverage/graph.rs
@@ -33,7 +33,7 @@ impl CoverageGraph {
         // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock
         // equivalents. Note that since the BasicCoverageBlock graph has been fully simplified, the
         // each predecessor of a BCB leader_bb should be in a unique BCB, and each successor of a
-        // BCB last_bb should bin in its own unique BCB. Therefore, collecting the BCBs using
+        // BCB last_bb should be in its own unique BCB. Therefore, collecting the BCBs using
         // `bb_to_bcb` should work without requiring a deduplication step.
 
         let successors = IndexVec::from_fn_n(
@@ -118,18 +118,8 @@ impl CoverageGraph {
 
             match term.kind {
                 TerminatorKind::Return { .. }
-                // FIXME(richkadel): Add test(s) for `Abort` coverage.
                 | TerminatorKind::Abort
-                // FIXME(richkadel): Add test(s) for `Assert` coverage.
-                // Should `Assert` be handled like `FalseUnwind` instead? Since we filter out unwind
-                // branches when creating the BCB CFG, aren't `Assert`s (without unwinds) just like
-                // `FalseUnwinds` (which are kind of like `Goto`s)?
-                | TerminatorKind::Assert { .. }
-                // FIXME(richkadel): Add test(s) for `Yield` coverage, and confirm coverage is
-                // sensible for code using the `yield` keyword.
                 | TerminatorKind::Yield { .. }
-                // FIXME(richkadel): Also add coverage tests using async/await, and threading.
-
                 | TerminatorKind::SwitchInt { .. } => {
                     // The `bb` has more than one _outgoing_ edge, or exits the function. Save the
                     // current sequence of `basic_blocks` gathered to this point, as a new
@@ -147,6 +137,16 @@ impl CoverageGraph {
                     // `Terminator`s `successors()` list) checking the number of successors won't
                     // work.
                 }
+
+                // The following `TerminatorKind`s are either not expected outside an unwind branch,
+                // or they should not (under normal circumstances) branch. Coverage graphs are
+                // simplified by assuring coverage results are accurate for program executions that
+                // don't panic.
+                //
+                // Programs that panic and unwind may record slightly inaccurate coverage results
+                // for a coverage region containing the `Terminator` that began the panic. This
+                // is as intended. (See Issue #78544 for a possible future option to support
+                // coverage in test programs that panic.)
                 TerminatorKind::Goto { .. }
                 | TerminatorKind::Resume
                 | TerminatorKind::Unreachable
@@ -154,6 +154,7 @@ impl CoverageGraph {
                 | TerminatorKind::DropAndReplace { .. }
                 | TerminatorKind::Call { .. }
                 | TerminatorKind::GeneratorDrop
+                | TerminatorKind::Assert { .. }
                 | TerminatorKind::FalseEdge { .. }
                 | TerminatorKind::FalseUnwind { .. }
                 | TerminatorKind::InlineAsm { .. } => {}
@@ -278,10 +279,13 @@ rustc_index::newtype_index! {
     /// A node in the [control-flow graph][CFG] of CoverageGraph.
     pub(super) struct BasicCoverageBlock {
         DEBUG_FORMAT = "bcb{}",
+        const START_BCB = 0,
     }
 }
 
-/// A BasicCoverageBlockData (BCB) represents the maximal-length sequence of MIR BasicBlocks without
+/// `BasicCoverageBlockData` holds the data indexed by a `BasicCoverageBlock`.
+///
+/// A `BasicCoverageBlock` (BCB) represents the maximal-length sequence of MIR `BasicBlock`s without
 /// conditional branches, and form a new, simplified, coverage-specific Control Flow Graph, without
 /// altering the original MIR CFG.
 ///
diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs
index 192bb6680e4..f69748db238 100644
--- a/compiler/rustc_mir/src/transform/coverage/mod.rs
+++ b/compiler/rustc_mir/src/transform/coverage/mod.rs
@@ -88,6 +88,8 @@ struct Instrumentor<'a, 'tcx> {
     pass_name: &'a str,
     tcx: TyCtxt<'tcx>,
     mir_body: &'a mut mir::Body<'tcx>,
+    source_file: Lrc<SourceFile>,
+    fn_sig_span: Span,
     body_span: Span,
     basic_coverage_blocks: CoverageGraph,
     coverage_counters: CoverageCounters,
@@ -95,14 +97,24 @@ struct Instrumentor<'a, 'tcx> {
 
 impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
     fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
-        let hir_body = hir_body(tcx, mir_body.source.def_id());
+        let source_map = tcx.sess.source_map();
+        let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, mir_body.source.def_id());
         let body_span = hir_body.value.span;
+        let source_file = source_map.lookup_source_file(body_span.lo());
+        let fn_sig_span = match some_fn_sig.filter(|fn_sig| {
+            Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.hi()))
+        }) {
+            Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()),
+            None => body_span.shrink_to_lo(),
+        };
         let function_source_hash = hash_mir_source(tcx, hir_body);
         let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
         Self {
             pass_name,
             tcx,
             mir_body,
+            source_file,
+            fn_sig_span,
             body_span,
             basic_coverage_blocks,
             coverage_counters: CoverageCounters::new(function_source_hash),
@@ -114,9 +126,15 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         let source_map = tcx.sess.source_map();
         let mir_source = self.mir_body.source;
         let def_id = mir_source.def_id();
+        let fn_sig_span = self.fn_sig_span;
         let body_span = self.body_span;
 
-        debug!("instrumenting {:?}, span: {}", def_id, source_map.span_to_string(body_span));
+        debug!(
+            "instrumenting {:?}, fn sig span: {}, body span: {}",
+            def_id,
+            source_map.span_to_string(fn_sig_span),
+            source_map.span_to_string(body_span)
+        );
 
         let mut graphviz_data = debug::GraphvizData::new();
         let mut debug_used_expressions = debug::UsedExpressions::new();
@@ -138,6 +156,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         // Compute `CoverageSpan`s from the `CoverageGraph`.
         let coverage_spans = CoverageSpans::generate_coverage_spans(
             &self.mir_body,
+            fn_sig_span,
             body_span,
             &self.basic_coverage_blocks,
         );
@@ -255,8 +274,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         let tcx = self.tcx;
         let source_map = tcx.sess.source_map();
         let body_span = self.body_span;
-        let source_file = source_map.lookup_source_file(body_span.lo());
-        let file_name = Symbol::intern(&source_file.name.to_string());
+        let file_name = Symbol::intern(&self.source_file.name.to_string());
 
         let mut bcb_counters = IndexVec::from_elem_n(None, self.basic_coverage_blocks.num_nodes());
         for covspan in coverage_spans {
@@ -272,47 +290,22 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
                 bug!("Every BasicCoverageBlock should have a Counter or Expression");
             };
             graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind);
-            // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special
-            // cases?
-            let some_code_region = if self.is_code_region_redundant(bcb, span, body_span) {
-                None
-            } else {
-                Some(make_code_region(file_name, &source_file, span, body_span))
-            };
-            inject_statement(self.mir_body, counter_kind, self.bcb_last_bb(bcb), some_code_region);
-        }
-    }
 
-    /// Returns true if the type of `BasicCoverageBlock` (specifically, it's `BasicBlock`s
-    /// `TerminatorKind`) with the given `Span` (relative to the `body_span`) is known to produce
-    /// a redundant coverage count.
-    ///
-    /// There is at least one case for this, and if it's not handled, the last line in a function
-    /// will be double-counted.
-    ///
-    /// If this method returns `true`, the counter (which other `Expressions` may depend on) is
-    /// still injected, but without an associated code region.
-    // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special cases?
-    fn is_code_region_redundant(
-        &self,
-        bcb: BasicCoverageBlock,
-        span: Span,
-        body_span: Span,
-    ) -> bool {
-        if span.hi() == body_span.hi() {
-            // All functions execute a `Return`-terminated `BasicBlock`, regardless of how the
-            // function returns; but only some functions also _can_ return after a `Goto` block
-            // that ends on the closing brace of the function (with the `Return`). When this
-            // happens, the last character is counted 2 (or possibly more) times, when we know
-            // the function returned only once (of course). By giving all `Goto` terminators at
-            // the end of a function a `non-reportable` code region, they are still counted
-            // if appropriate, but they don't increment the line counter, as long as their is
-            // also a `Return` on that last line.
-            if let TerminatorKind::Goto { .. } = self.bcb_terminator(bcb).kind {
-                return true;
-            }
+            debug!(
+                "Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})",
+                file_name,
+                self.source_file,
+                source_map.span_to_string(span),
+                source_map.span_to_string(body_span)
+            );
+
+            inject_statement(
+                self.mir_body,
+                counter_kind,
+                self.bcb_last_bb(bcb),
+                Some(make_code_region(file_name, &self.source_file, span, body_span)),
+            );
         }
-        false
     }
 
     /// `inject_coverage_span_counters()` looped through the `CoverageSpan`s and injected the
@@ -412,11 +405,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
     }
 
     #[inline]
-    fn bcb_terminator(&self, bcb: BasicCoverageBlock) -> &Terminator<'tcx> {
-        self.bcb_data(bcb).terminator(self.mir_body)
-    }
-
-    #[inline]
     fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData {
         &self.basic_coverage_blocks[bcb]
     }
@@ -521,10 +509,15 @@ fn make_code_region(
     }
 }
 
-fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
+fn fn_sig_and_body<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) {
+    // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
+    // to HIR for it.
     let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
     let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
-    tcx.hir().body(fn_body_id)
+    (hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id))
 }
 
 fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir/src/transform/coverage/query.rs
index e86bb96d29c..aa34ae70ef1 100644
--- a/compiler/rustc_mir/src/transform/coverage/query.rs
+++ b/compiler/rustc_mir/src/transform/coverage/query.rs
@@ -1,6 +1,8 @@
+use super::*;
+
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{Coverage, CoverageInfo, Location};
+use rustc_middle::mir::{self, Coverage, CoverageInfo, Location};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
@@ -9,6 +11,8 @@ use rustc_span::def_id::DefId;
 /// counter) and `FunctionCoverage::new()` (to extract the coverage map metadata from the MIR).
 pub(crate) fn provide(providers: &mut Providers) {
     providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id);
+    providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id);
+    providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id);
 }
 
 /// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in
@@ -123,3 +127,34 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo
 
     coverage_visitor.info
 }
+
+fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Symbol> {
+    let mir_body = tcx.optimized_mir(def_id);
+    for bb_data in mir_body.basic_blocks().iter() {
+        for statement in bb_data.statements.iter() {
+            if let StatementKind::Coverage(box ref coverage) = statement.kind {
+                if let Some(code_region) = coverage.code_region.as_ref() {
+                    return Some(code_region.file_name);
+                }
+            }
+        }
+    }
+    None
+}
+
+fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
+    let mir_body: &'tcx mir::Body<'tcx> = tcx.optimized_mir(def_id);
+    mir_body
+        .basic_blocks()
+        .iter()
+        .map(|data| {
+            data.statements.iter().filter_map(|statement| match statement.kind {
+                StatementKind::Coverage(box ref coverage) => {
+                    coverage.code_region.as_ref() // may be None
+                }
+                _ => None,
+            })
+        })
+        .flatten()
+        .collect()
+}
diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs
index 95c49922262..fd3e782f6df 100644
--- a/compiler/rustc_mir/src/transform/coverage/spans.rs
+++ b/compiler/rustc_mir/src/transform/coverage/spans.rs
@@ -1,10 +1,9 @@
 use super::debug::term_type;
-use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
+use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
 
 use crate::util::spanview::source_range_no_file;
 
 use rustc_data_structures::graph::WithNumNodes;
-use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{
     self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
     TerminatorKind,
@@ -74,6 +73,10 @@ pub(super) struct CoverageSpan {
 }
 
 impl CoverageSpan {
+    pub fn for_fn_sig(fn_sig_span: Span) -> Self {
+        Self { span: fn_sig_span, bcb: START_BCB, coverage_statements: vec![], is_closure: false }
+    }
+
     pub fn for_statement(
         statement: &Statement<'tcx>,
         span: Span,
@@ -82,10 +85,10 @@ impl CoverageSpan {
         stmt_index: usize,
     ) -> Self {
         let is_closure = match statement.kind {
-            StatementKind::Assign(box (
-                _,
-                Rvalue::Aggregate(box AggregateKind::Closure(_, _), _),
-            )) => true,
+            StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind {
+                AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true,
+                _ => false,
+            },
             _ => false,
         };
 
@@ -109,9 +112,6 @@ impl CoverageSpan {
     pub fn merge_from(&mut self, mut other: CoverageSpan) {
         debug_assert!(self.is_mergeable(&other));
         self.span = self.span.to(other.span);
-        if other.is_closure {
-            self.is_closure = true;
-        }
         self.coverage_statements.append(&mut other.coverage_statements);
     }
 
@@ -171,6 +171,9 @@ pub struct CoverageSpans<'a, 'tcx> {
     /// The MIR, used to look up `BasicBlockData`.
     mir_body: &'a mir::Body<'tcx>,
 
+    /// A `Span` covering the signature of function for the MIR.
+    fn_sig_span: Span,
+
     /// A `Span` covering the function body of the MIR (typically from left curly brace to right
     /// curly brace).
     body_span: Span,
@@ -214,13 +217,36 @@ pub struct CoverageSpans<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
+    /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
+    /// counted.
+    ///
+    /// The basic steps are:
+    ///
+    /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each
+    ///    `BasicCoverageBlockData`.
+    /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position
+    ///    are sorted with longer spans before shorter spans; and equal spans are sorted
+    ///    (deterministically) based on "dominator" relationship (if any).
+    /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance,
+    ///    if another span or spans are already counting the same code region), or should be merged
+    ///    into a broader combined span (because it represents a contiguous, non-branching, and
+    ///    uninterrupted region of source code).
+    ///
+    ///    Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since
+    ///    closures have their own MIR, their `Span` in their enclosing function should be left
+    ///    "uncovered".
+    ///
+    /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
+    /// to be).
     pub(super) fn generate_coverage_spans(
         mir_body: &'a mir::Body<'tcx>,
+        fn_sig_span: Span,
         body_span: Span,
         basic_coverage_blocks: &'a CoverageGraph,
     ) -> Vec<CoverageSpan> {
         let mut coverage_spans = CoverageSpans {
             mir_body,
+            fn_sig_span,
             body_span,
             basic_coverage_blocks,
             sorted_spans_iter: None,
@@ -242,27 +268,6 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
         coverage_spans.to_refined_spans()
     }
 
-    /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
-    /// counted.
-    ///
-    /// The basic steps are:
-    ///
-    /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each
-    ///    `BasicCoverageBlockData`.
-    /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position
-    ///    are sorted with longer spans before shorter spans; and equal spans are sorted
-    ///    (deterministically) based on "dominator" relationship (if any).
-    /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance,
-    ///    if another span or spans are already counting the same code region), or should be merged
-    ///    into a broader combined span (because it represents a contiguous, non-branching, and
-    ///    uninterrupted region of source code).
-    ///
-    ///    Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since
-    ///    closures have their own MIR, their `Span` in their enclosing function should be left
-    ///    "uncovered".
-    ///
-    /// Note the resulting vector of `CoverageSpan`s does may not be fully sorted (and does not need
-    /// to be).
     fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
         let mut initial_spans = Vec::<CoverageSpan>::with_capacity(self.mir_body.num_nodes() * 2);
         for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() {
@@ -277,6 +282,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
             return initial_spans;
         }
 
+        initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span));
+
         initial_spans.sort_unstable_by(|a, b| {
             if a.span.lo() == b.span.lo() {
                 if a.span.hi() == b.span.hi() {
@@ -331,7 +338,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
                     prev={:?}",
                     self.prev()
                 );
-                self.discard_curr();
+                self.take_curr();
             } else if self.curr().is_closure {
                 self.carve_out_span_for_closure();
             } else if self.prev_original_span == self.curr().span {
@@ -345,28 +352,28 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
 
         debug!("    AT END, adding last prev={:?}", self.prev());
         let prev = self.take_prev();
-        let CoverageSpans {
-            mir_body, basic_coverage_blocks, pending_dups, mut refined_spans, ..
-        } = self;
+        let CoverageSpans { pending_dups, mut refined_spans, .. } = self;
         for dup in pending_dups {
             debug!("    ...adding at least one pending dup={:?}", dup);
             refined_spans.push(dup);
         }
-        refined_spans.push(prev);
-
-        // Remove `CoverageSpan`s with empty spans ONLY if the empty `CoverageSpan`s BCB also has at
-        // least one other non-empty `CoverageSpan`.
-        let mut has_coverage = BitSet::new_empty(basic_coverage_blocks.num_nodes());
-        for covspan in &refined_spans {
-            if !covspan.span.is_empty() {
-                has_coverage.insert(covspan.bcb);
-            }
+
+        // Async functions wrap a closure that implements the body to be executed. The enclosing
+        // function is called and returns an `impl Future` without initially executing any of the
+        // body. To avoid showing the return from the enclosing function as a "covered" return from
+        // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is
+        // excluded. The closure's `Return` is the only one that will be counted. This provides
+        // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
+        // of the function body.)
+        let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() {
+            last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi()
+        } else {
+            false
+        };
+
+        if !body_ends_with_closure {
+            refined_spans.push(prev);
         }
-        refined_spans.retain(|covspan| {
-            !(covspan.span.is_empty()
-                && is_goto(&basic_coverage_blocks[covspan.bcb].terminator(mir_body).kind)
-                && has_coverage.contains(covspan.bcb))
-        });
 
         // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
         // regions for the current function leave room for the closure's own coverage regions
@@ -491,8 +498,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
 
     /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
     /// `curr` coverage span.
-    fn discard_curr(&mut self) {
-        self.some_curr = None;
+    fn take_curr(&mut self) -> CoverageSpan {
+        self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
     }
 
     /// Returns true if the curr span should be skipped because prev has already advanced beyond the
@@ -508,11 +515,11 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
         self.prev().span.hi() <= self.curr().span.lo()
     }
 
-    /// If `prev`s span extends left of the closure (`curr`), carve out the closure's
-    /// span from `prev`'s span. (The closure's coverage counters will be injected when
-    /// processing the closure's own MIR.) Add the portion of the span to the left of the
-    /// closure; and if the span extends to the right of the closure, update `prev` to
-    /// that portion of the span. For any `pending_dups`, repeat the same process.
+    /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from
+    /// `prev`'s span. (The closure's coverage counters will be injected when processing the
+    /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span
+    /// extends to the right of the closure, update `prev` to that portion of the span. For any
+    /// `pending_dups`, repeat the same process.
     fn carve_out_span_for_closure(&mut self) {
         let curr_span = self.curr().span;
         let left_cutoff = curr_span.lo();
@@ -541,7 +548,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
                 dup.span = dup.span.with_lo(right_cutoff);
             }
             self.pending_dups.append(&mut pending_dups);
-            self.discard_curr(); // since self.prev() was already updated
+            let closure_covspan = self.take_curr();
+            self.refined_spans.push(closure_covspan); // since self.prev() was already updated
         } else {
             pending_dups.clear();
         }
@@ -705,30 +713,8 @@ pub(super) fn filtered_terminator_span(
         | TerminatorKind::DropAndReplace { .. }
         | TerminatorKind::SwitchInt { .. }
         // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
-        // FIXME(richkadel): Note that `Goto` was moved to it's own match arm, for the reasons
-        // described below. Add tests to confirm whether or not similar cases also apply to
-        // `FalseEdge`.
-        | TerminatorKind::FalseEdge { .. } => None,
-
-        // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special cases?
-        //
-        // `Goto`s are often the targets of `SwitchInt` branches, and certain important
-        // optimizations to replace some `Counter`s with `Expression`s require a separate
-        // `BasicCoverageBlock` for each branch, to support the `Counter`, when needed.
-        //
-        // Also, some test cases showed that `Goto` terminators, and to some degree their `Span`s,
-        // provided useful context for coverage, such as to count and show when `if` blocks
-        // _without_ `else` blocks execute the `false` case (counting when the body of the `if`
-        // was _not_ taken). In these cases, the `Goto` span is ultimately given a `CoverageSpan`
-        // of 1 character, at the end of it's original `Span`.
-        //
-        // However, in other cases, a visible `CoverageSpan` is not wanted, but the `Goto`
-        // block must still be counted (for example, to contribute its count to an `Expression`
-        // that reports the execution count for some other block). In these cases, the code region
-        // is set to `None`. (See `Instrumentor::is_code_region_redundant()`.)
-        TerminatorKind::Goto { .. } => {
-            Some(function_source_span(terminator.source_info.span.shrink_to_hi(), body_span))
-        }
+        | TerminatorKind::FalseEdge { .. }
+        | TerminatorKind::Goto { .. } => None,
 
         // Retain spans from all other terminators
         TerminatorKind::Resume
@@ -749,11 +735,3 @@ fn function_source_span(span: Span, body_span: Span) -> Span {
     let span = original_sp(span, body_span).with_ctxt(SyntaxContext::root());
     if body_span.contains(span) { span } else { body_span }
 }
-
-#[inline(always)]
-fn is_goto(term_kind: &TerminatorKind<'tcx>) -> bool {
-    match term_kind {
-        TerminatorKind::Goto { .. } => true,
-        _ => false,
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index 927aae82a36..8d5ed747c3f 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -22,7 +22,7 @@ use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
 use rustc_span::symbol::sym;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_target::spec::abi::Abi;
@@ -326,41 +326,16 @@ impl<'tcx> Validator<'_, 'tcx> {
                         if place.projection.contains(&ProjectionElem::Deref) {
                             return Err(Unpromotable);
                         }
-
-                        let mut has_mut_interior =
-                            self.qualif_local::<qualifs::HasMutInterior>(place.local);
-                        // HACK(eddyb) this should compute the same thing as
-                        // `<HasMutInterior as Qualif>::in_projection` from
-                        // `check_consts::qualifs` but without recursion.
-                        if has_mut_interior {
-                            // This allows borrowing fields which don't have
-                            // `HasMutInterior`, from a type that does, e.g.:
-                            // `let _: &'static _ = &(Cell::new(1), 2).1;`
-                            let mut place_projection = &place.projection[..];
-                            // FIXME(eddyb) use a forward loop instead of a reverse one.
-                            while let &[ref proj_base @ .., elem] = place_projection {
-                                // FIXME(eddyb) this is probably excessive, with
-                                // the exception of `union` member accesses.
-                                let ty =
-                                    Place::ty_from(place.local, proj_base, self.body, self.tcx)
-                                        .projection_ty(self.tcx, elem)
-                                        .ty;
-                                if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
-                                    has_mut_interior = false;
-                                    break;
-                                }
-
-                                place_projection = proj_base;
-                            }
+                        if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
+                            return Err(Unpromotable);
                         }
 
                         // FIXME(eddyb) this duplicates part of `validate_rvalue`.
+                        let has_mut_interior =
+                            self.qualif_local::<qualifs::HasMutInterior>(place.local);
                         if has_mut_interior {
                             return Err(Unpromotable);
                         }
-                        if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
-                            return Err(Unpromotable);
-                        }
 
                         if let BorrowKind::Mut { .. } = kind {
                             let ty = place.ty(self.body, self.tcx).ty;
@@ -692,28 +667,7 @@ impl<'tcx> Validator<'_, 'tcx> {
 
                 self.validate_place(place)?;
 
-                // HACK(eddyb) this should compute the same thing as
-                // `<HasMutInterior as Qualif>::in_projection` from
-                // `check_consts::qualifs` but without recursion.
-                let mut has_mut_interior =
-                    self.qualif_local::<qualifs::HasMutInterior>(place.local);
-                if has_mut_interior {
-                    let mut place_projection = place.projection;
-                    // FIXME(eddyb) use a forward loop instead of a reverse one.
-                    while let &[ref proj_base @ .., elem] = place_projection {
-                        // FIXME(eddyb) this is probably excessive, with
-                        // the exception of `union` member accesses.
-                        let ty = Place::ty_from(place.local, proj_base, self.body, self.tcx)
-                            .projection_ty(self.tcx, elem)
-                            .ty;
-                        if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
-                            has_mut_interior = false;
-                            break;
-                        }
-
-                        place_projection = proj_base;
-                    }
-                }
+                let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
                 if has_mut_interior {
                     return Err(Unpromotable);
                 }
diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_mir/src/util/generic_graphviz.rs
index 8bd4a512bbb..fd55a4dfc4c 100644
--- a/compiler/rustc_mir/src/util/generic_graphviz.rs
+++ b/compiler/rustc_mir/src/util/generic_graphviz.rs
@@ -116,9 +116,13 @@ impl<
 
         write!(w, r#"<table border="0" cellborder="1" cellspacing="0">"#)?;
 
-        // FIXME(richkadel): Need generic way to know if node header should have a different color
+        // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation,
+        // we need generic way to know if node header should have a different color. For example,
+        // for MIR:
+        //
         // let (blk, bgcolor) = if data.is_cleanup {
-        //    (format!("{:?} (cleanup)", node), "lightblue")
+        //     let color = if dark_mode { "royalblue" } else { "lightblue" };
+        //     (format!("{:?} (cleanup)", node), color)
         // } else {
         //     let color = if dark_mode { "dimgray" } else { "gray" };
         //     (format!("{:?}", node), color)
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index d5f72e6f22d..82f38ac0e76 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -3,6 +3,7 @@ use crate::build::ForGuard::OutsideGuard;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use crate::thir::*;
 use rustc_hir as hir;
+use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
 use rustc_session::lint::Level;
@@ -12,6 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn ast_block(
         &mut self,
         destination: Place<'tcx>,
+        scope: Option<region::Scope>,
         block: BasicBlock,
         ast_block: &'tcx hir::Block<'tcx>,
         source_info: SourceInfo,
@@ -28,9 +30,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
             this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
                 if targeted_by_break {
-                    this.in_breakable_scope(None, destination, span, |this| {
+                    this.in_breakable_scope(None, destination, scope, span, |this| {
                         Some(this.ast_block_stmts(
                             destination,
+                            scope,
                             block,
                             span,
                             stmts,
@@ -39,7 +42,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         ))
                     })
                 } else {
-                    this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
+                    this.ast_block_stmts(destination, scope, block, span, stmts, expr, safety_mode)
                 }
             })
         })
@@ -48,6 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn ast_block_stmts(
         &mut self,
         destination: Place<'tcx>,
+        scope: Option<region::Scope>,
         mut block: BasicBlock,
         span: Span,
         stmts: Vec<StmtRef<'tcx>>,
@@ -182,7 +186,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             };
             this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span });
 
-            unpack!(block = this.into(destination, block, expr));
+            unpack!(block = this.into(destination, scope, block, expr));
             let popped = this.block_context.pop();
 
             assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index cf075abc94b..60f8d8c8a9f 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -19,7 +19,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let local_scope = self.local_scope();
-        self.as_operand(block, local_scope, expr)
+        self.as_operand(block, Some(local_scope), expr)
     }
 
     /// Returns an operand suitable for use until the end of the current scope expression and
@@ -79,7 +79,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let local_scope = self.local_scope();
-        self.as_call_operand(block, local_scope, expr)
+        self.as_call_operand(block, Some(local_scope), expr)
     }
 
     /// Compile `expr` into a value that can be used as an operand.
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index e6263e5d6cf..e1a3dc87c8c 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -4,14 +4,62 @@ use crate::build::expr::category::Category;
 use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
 use crate::thir::*;
+use rustc_hir::def_id::DefId;
+use rustc_hir::HirId;
 use rustc_middle::middle::region;
+use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::mir::AssertKind::BoundsCheck;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
 use rustc_span::Span;
+use rustc_target::abi::VariantIdx;
 
 use rustc_index::vec::Idx;
 
+/// The "outermost" place that holds this value.
+#[derive(Copy, Clone)]
+crate enum PlaceBase {
+    /// Denotes the start of a `Place`.
+    Local(Local),
+
+    /// When building place for an expression within a closure, the place might start off a
+    /// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture
+    /// index (within the desugared closure) of the captured path until most of the projections
+    /// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the
+    /// captured path starts, the closure the capture belongs to and the trait the closure
+    /// implements.
+    ///
+    /// Once we have figured out the capture index, we can convert the place builder to start from
+    /// `PlaceBase::Local`.
+    ///
+    /// Consider the following example
+    /// ```rust
+    /// let t = (10, (10, (10, 10)));
+    ///
+    /// let c = || {
+    ///     println!("{}", t.0.0.0);
+    /// };
+    /// ```
+    /// Here the THIR expression for `t.0.0.0` will be something like
+    ///
+    /// ```
+    /// * Field(0)
+    ///     * Field(0)
+    ///         * Field(0)
+    ///             * UpvarRef(t)
+    /// ```
+    ///
+    /// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to
+    /// figure out that it is captured until all the `Field` projections are applied.
+    Upvar {
+        /// HirId of the upvar
+        var_hir_id: HirId,
+        /// DefId of the closure
+        closure_def_id: DefId,
+        /// The trait closure implements, `Fn`, `FnMut`, `FnOnce`
+        closure_kind: ty::ClosureKind },
+}
+
 /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
 /// place by pushing more and more projections onto the end, and then convert the final set into a
 /// place using the `into_place` method.
@@ -19,14 +67,240 @@ use rustc_index::vec::Idx;
 /// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
 /// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
 #[derive(Clone)]
-struct PlaceBuilder<'tcx> {
-    local: Local,
+crate struct PlaceBuilder<'tcx> {
+    base: PlaceBase,
     projection: Vec<PlaceElem<'tcx>>,
 }
 
+/// Given a list of MIR projections, convert them to list of HIR ProjectionKind.
+/// The projections are truncated to represent a path that might be captured by a
+/// closure/generator. This implies the vector returned from this function doesn't contain
+/// ProjectionElems `Downcast`, `ConstantIndex`, `Index`, or `Subslice` because those will never be
+/// part of a path that is captued by a closure. We stop applying projections once we see the first
+/// projection that isn't captured by a closure.
+fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
+    mir_projections: &Vec<PlaceElem<'tcx>>,
+) -> Vec<HirProjectionKind> {
+
+    let mut hir_projections  = Vec::new();
+
+    for mir_projection in mir_projections {
+        let hir_projection = match mir_projection {
+            ProjectionElem::Deref => HirProjectionKind::Deref,
+            ProjectionElem::Field(field, _) => {
+                // We will never encouter this for multivariant enums,
+                // read the comment for `Downcast`.
+                HirProjectionKind::Field(field.index() as u32, VariantIdx::new(0))
+            },
+            ProjectionElem::Downcast(..) => {
+                // This projections exist only for enums that have
+                // multiple variants. Since such enums that are captured
+                // completely, we can stop here.
+                break
+            },
+            ProjectionElem::Index(..)
+            | ProjectionElem::ConstantIndex { .. }
+            | ProjectionElem::Subslice { .. } => {
+                // We don't capture array-access projections.
+                // We can stop here as arrays are captured completely.
+                break
+            },
+        };
+
+        hir_projections.push(hir_projection);
+    }
+
+    hir_projections
+}
+
+/// Return true if the `proj_possible_ancestor` represents an ancestor path
+/// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`,
+/// assuming they both start off of the same root variable.
+///
+/// **Note:** It's the caller's responsibility to ensure that both lists of projections
+///           start off of the same root variable.
+///
+/// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of
+///        `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`.
+///        Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`.
+///     2. Since we only look at the projections here function will return `bar.x` as an a valid
+///        ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
+///        list are being applied to the same root variable.
+fn is_ancestor_or_same_capture(
+    proj_possible_ancestor: &Vec<HirProjectionKind>,
+    proj_capture: &Vec<HirProjectionKind>,
+) -> bool {
+    // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
+    // Therefore we can't just check if all projections are same in the zipped iterator below.
+    if proj_possible_ancestor.len() > proj_capture.len() {
+        return false;
+    }
+
+    proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b)
+}
+
+/// Computes the index of a capture within the desugared closure provided the closure's
+/// `closure_min_captures` and the capture's index of the capture in the
+/// `ty::MinCaptureList` of the root variable `var_hir_id`.
+fn compute_capture_idx<'tcx>(
+    closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>,
+    var_hir_id: HirId,
+    root_var_idx: usize,
+) -> usize {
+    let mut res = 0;
+    for (var_id, capture_list) in closure_min_captures {
+        if *var_id == var_hir_id {
+            res += root_var_idx;
+            break;
+        } else {
+            res += capture_list.len();
+        }
+    }
+
+    res
+}
+
+/// Given a closure, returns the index of a capture within the desugared closure struct and the
+/// `ty::CapturedPlace` which is the ancestor of the Place represented using the `var_hir_id`
+/// and `projection`.
+///
+/// Note there will be at most one ancestor for any given Place.
+///
+/// Returns None, when the ancestor is not found.
+fn find_capture_matching_projections<'a, 'tcx>(
+    typeck_results: &'a ty::TypeckResults<'tcx>,
+    var_hir_id: HirId,
+    closure_def_id: DefId,
+    projections: &Vec<PlaceElem<'tcx>>,
+) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> {
+    let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?;
+    let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?;
+
+    let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections);
+
+    // If an ancestor is found, `idx` is the index within the list of captured places
+    // for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself.
+    let (idx, capture) = root_variable_min_captures.iter().enumerate().find(|(_, capture)| {
+            let possible_ancestor_proj_kinds =
+                capture.place.projections.iter().map(|proj| proj.kind).collect();
+            is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections)
+    })?;
+
+    // Convert index to be from the presepective of the entire closure_min_captures map
+    // instead of just the root variable capture list
+    Some((compute_capture_idx(closure_min_captures, var_hir_id, idx), capture))
+}
+
+/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the
+/// `PlaceBuilder` now starts from `PlaceBase::Local`.
+///
+/// Returns a Result with the error being the HirId of the Upvar that was not found.
+fn to_upvars_resolved_place_builder<'a, 'tcx>(
+    from_builder: PlaceBuilder<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    typeck_results: &'a ty::TypeckResults<'tcx>,
+) -> Result<PlaceBuilder<'tcx>, HirId> {
+    match from_builder.base {
+        PlaceBase::Local(_) => Ok(from_builder),
+        PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
+            // Captures are represented using fields inside a structure.
+            // This represents accessing self in the closure structure
+            let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1));
+            match closure_kind {
+                ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
+                    upvar_resolved_place_builder = upvar_resolved_place_builder.deref();
+                }
+                ty::ClosureKind::FnOnce => {}
+            }
+
+            let (capture_index, capture) =
+                if let Some(capture_details) = find_capture_matching_projections(
+                    typeck_results,
+                    var_hir_id,
+                    closure_def_id,
+                    &from_builder.projection,
+                ) {
+                    capture_details
+                } else {
+                    if !tcx.features().capture_disjoint_fields {
+                        bug!(
+                            "No associated capture found for {:?}[{:#?}] even though \
+                            capture_disjoint_fields isn't enabled",
+                            var_hir_id,
+                            from_builder.projection
+                        )
+                    } else {
+                        // FIXME(project-rfc-2229#24): Handle this case properly
+                        debug!(
+                            "No associated capture found for {:?}[{:#?}]",
+                            var_hir_id,
+                            from_builder.projection,
+                        );
+                    }
+                    return Err(var_hir_id);
+                };
+
+            let closure_ty =
+                typeck_results.node_type(tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()));
+
+            let substs = match closure_ty.kind() {
+                ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
+                ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
+                _ => bug!("Lowering capture for non-closure type {:?}", closure_ty),
+            };
+
+            // Access the capture by accessing the field within the Closure struct.
+            //
+            // We must have inferred the capture types since we are building MIR, therefore
+            // it's safe to call `tuple_element_ty` and we can unwrap here because
+            // we know that the capture exists and is the `capture_index`-th capture.
+            let var_ty = substs.tupled_upvars_ty().tuple_element_ty(capture_index).unwrap();
+
+            upvar_resolved_place_builder = upvar_resolved_place_builder.field(Field::new(capture_index), var_ty);
+
+            // If the variable is captured via ByRef(Immutable/Mutable) Borrow,
+            // we need to deref it
+            upvar_resolved_place_builder = match capture.info.capture_kind {
+                ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(),
+                ty::UpvarCapture::ByValue(_) => upvar_resolved_place_builder,
+            };
+
+            let next_projection = capture.place.projections.len();
+            let mut curr_projections = from_builder.projection;
+
+            // We used some of the projections to build the capture itself,
+            // now we apply the remaining to the upvar resolved place.
+            upvar_resolved_place_builder.projection.extend(
+                curr_projections.drain(next_projection..));
+
+            Ok(upvar_resolved_place_builder)
+        }
+    }
+}
+
 impl<'tcx> PlaceBuilder<'tcx> {
-    fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
-        Place { local: self.local, projection: tcx.intern_place_elems(&self.projection) }
+    crate fn into_place<'a>(
+        self,
+        tcx: TyCtxt<'tcx>,
+        typeck_results: &'a ty::TypeckResults<'tcx>,
+    ) -> Place<'tcx> {
+        if let PlaceBase::Local(local) = self.base {
+            Place { local, projection: tcx.intern_place_elems(&self.projection) }
+        } else {
+            self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
+        }
+    }
+
+    fn expect_upvars_resolved<'a>(
+        self,
+        tcx: TyCtxt<'tcx>,
+        typeck_results: &'a ty::TypeckResults<'tcx>,
+    ) -> PlaceBuilder<'tcx> {
+        to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
+    }
+
+    crate fn base(&self) -> PlaceBase {
+        self.base
     }
 
     fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
@@ -49,7 +323,13 @@ impl<'tcx> PlaceBuilder<'tcx> {
 
 impl<'tcx> From<Local> for PlaceBuilder<'tcx> {
     fn from(local: Local) -> Self {
-        Self { local, projection: Vec::new() }
+        Self { base: PlaceBase::Local(local), projection: Vec::new() }
+    }
+}
+
+impl<'tcx> From<PlaceBase> for PlaceBuilder<'tcx> {
+    fn from(base: PlaceBase) -> Self {
+        Self { base, projection: Vec::new() }
     }
 }
 
@@ -71,12 +351,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let place_builder = unpack!(block = self.as_place_builder(block, expr));
-        block.and(place_builder.into_place(self.hir.tcx()))
+        block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
     /// intermediate `Place` values until we know the full set of projections.
-    fn as_place_builder<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<PlaceBuilder<'tcx>>
+    crate fn as_place_builder<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<PlaceBuilder<'tcx>>
     where
         M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
@@ -98,7 +378,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
-        block.and(place_builder.into_place(self.hir.tcx()))
+        block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -161,27 +441,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 source_info,
             ),
             ExprKind::UpvarRef { closure_def_id, var_hir_id } => {
-                let capture = this
-                    .hir
-                    .typeck_results
-                    .closure_captures
-                    .get(&closure_def_id)
-                    .and_then(|captures| captures.get_full(&var_hir_id));
-
-                if capture.is_none() {
-                    if !this.hir.tcx().features().capture_disjoint_fields {
-                        bug!(
-                            "No associated capture found for {:?} even though \
-                            capture_disjoint_fields isn't enabled",
-                            expr.kind
-                        )
-                    }
-                    // FIXME(project-rfc-2229#24): Handle this case properly
-                }
-
-                // Unwrap until the FIXME has been resolved
-                let (capture_index, _, upvar_id) = capture.unwrap();
-                this.lower_closure_capture(block, capture_index, *upvar_id)
+                let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local());
+                this.lower_captured_upvar(block, upvar_id)
             }
 
             ExprKind::VarRef { id } => {
@@ -208,7 +469,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             inferred_ty: expr.ty,
                         });
 
-                    let place = place_builder.clone().into_place(this.hir.tcx());
+                    let place =
+                        place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results());
                     this.cfg.push(
                         block,
                         Statement {
@@ -293,59 +555,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
-    /// Lower a closure/generator capture by representing it as a field
-    /// access within the desugared closure/generator.
-    ///
-    /// `capture_index` is the index of the capture within the desugared
-    /// closure/generator.
-    fn lower_closure_capture(
+    /// Lower a captured upvar. Note we might not know the actual capture index,
+    /// so we create a place starting from `PlaceBase::Upvar`, which will be resolved
+    /// once all projections that allow us to indentify a capture have been applied.
+    fn lower_captured_upvar(
         &mut self,
         block: BasicBlock,
-        capture_index: usize,
         upvar_id: ty::UpvarId,
-    )  -> BlockAnd<PlaceBuilder<'tcx>> {
+    ) -> BlockAnd<PlaceBuilder<'tcx>> {
         let closure_ty = self
             .hir
             .typeck_results()
             .node_type(self.hir.tcx().hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
 
-        // Captures are represented using fields inside a structure.
-        // This represents accessing self in the closure structure
-        let mut place_builder = PlaceBuilder::from(Local::new(1));
-
-        // In case of Fn/FnMut closures we must deref to access the fields
-        // Generators are considered FnOnce, so we ignore this step for them.
-        if let ty::Closure(_, closure_substs) = closure_ty.kind() {
-            match self.hir.infcx().closure_kind(closure_substs).unwrap() {
-                ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
-                    place_builder = place_builder.deref();
-                }
-                ty::ClosureKind::FnOnce => {}
-            }
-        }
-
-        let substs = match closure_ty.kind() {
-            ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
-            ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
-            _ => bug!("Lowering capture for non-closure type {:?}", closure_ty)
+        let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
+            self.hir.infcx().closure_kind(closure_substs).unwrap()
+        } else {
+            // Generators are considered FnOnce.
+            ty::ClosureKind::FnOnce
         };
 
-        // Access the capture by accessing the field within the Closure struct.
-        //
-        // We must have inferred the capture types since we are building MIR, therefore
-        // it's safe to call `upvar_tys` and we can unwrap here because
-        // we know that the capture exists and is the `capture_index`-th capture.
-        let var_ty = substs.upvar_tys().nth(capture_index).unwrap();
-        place_builder = place_builder.field(Field::new(capture_index), var_ty);
-
-        // If the variable is captured via ByRef(Immutable/Mutable) Borrow,
-        // we need to deref it
-        match self.hir.typeck_results.upvar_capture(upvar_id) {
-            ty::UpvarCapture::ByRef(_) => {
-                block.and(place_builder.deref())
-            }
-            ty::UpvarCapture::ByValue(_) => block.and(place_builder),
-        }
+        block.and(PlaceBuilder::from(PlaceBase::Upvar {
+            var_hir_id: upvar_id.var_path.hir_id,
+            closure_def_id: upvar_id.closure_expr_id.to_def_id(),
+            closure_kind,
+        }))
     }
 
     /// Lower an index expression
@@ -373,7 +607,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let is_outermost_index = fake_borrow_temps.is_none();
         let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps);
 
-        let base_place =
+        let mut base_place =
             unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),));
 
         // Making this a *fresh* temporary means we do not have to worry about
@@ -383,7 +617,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         block = self.bounds_check(
             block,
-            base_place.clone().into_place(self.hir.tcx()),
+            base_place.clone().into_place(self.hir.tcx(), self.hir.typeck_results()),
             idx,
             expr_span,
             source_info,
@@ -392,6 +626,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         if is_outermost_index {
             self.read_fake_borrows(block, fake_borrow_temps, source_info)
         } else {
+            base_place = base_place.expect_upvars_resolved(self.hir.tcx(), self.hir.typeck_results());
             self.add_fake_borrows_of_base(
                 &base_place,
                 block,
@@ -441,8 +676,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         source_info: SourceInfo,
     ) {
         let tcx = self.hir.tcx();
-        let place_ty =
-            Place::ty_from(base_place.local, &base_place.projection, &self.local_decls, tcx);
+        let local = match base_place.base {
+            PlaceBase::Local(local) => local,
+            PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar")
+        };
+
+        let place_ty = Place::ty_from(local, &base_place.projection, &self.local_decls, tcx);
         if let ty::Slice(_) = place_ty.ty.kind() {
             // We need to create fake borrows to ensure that the bounds
             // check that we just did stays valid. Since we can't assign to
@@ -452,7 +691,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 match elem {
                     ProjectionElem::Deref => {
                         let fake_borrow_deref_ty = Place::ty_from(
-                            base_place.local,
+                            local,
                             &base_place.projection[..idx],
                             &self.local_decls,
                             tcx,
@@ -470,14 +709,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             Rvalue::Ref(
                                 tcx.lifetimes.re_erased,
                                 BorrowKind::Shallow,
-                                Place { local: base_place.local, projection },
+                                Place { local, projection },
                             ),
                         );
                         fake_borrow_temps.push(fake_borrow_temp);
                     }
                     ProjectionElem::Index(_) => {
                         let index_ty = Place::ty_from(
-                            base_place.local,
+                            local,
                             &base_place.projection[..idx],
                             &self.local_decls,
                             tcx,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 7c34b996055..3f381f3f15e 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -4,6 +4,7 @@ use rustc_index::vec::Idx;
 
 use crate::build::expr::category::{Category, RvalueFunc};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::build::expr::as_place::PlaceBase;
 use crate::thir::*;
 use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind;
@@ -11,6 +12,8 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, UpvarSubsts};
 use rustc_span::Span;
 
+use std::slice;
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Returns an rvalue suitable for use until the end of the current
     /// scope expression.
@@ -23,7 +26,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let local_scope = self.local_scope();
-        self.as_rvalue(block, local_scope, expr)
+        self.as_rvalue(block, Some(local_scope), expr)
     }
 
     /// Compile `expr`, yielding an rvalue.
@@ -112,12 +115,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
                 this.cfg.push_assign(block, source_info, Place::from(result), box_);
 
-                // initialize the box contents:
+                // Initialize the box contents. No scope is needed since the
+                // `Box` is already scheduled to be dropped.
                 unpack!(
-                    block =
-                        this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value)
+                    block = this.into(
+                        this.hir.tcx().mk_place_deref(Place::from(result)),
+                        None,
+                        block,
+                        value,
+                    )
                 );
-                block.and(Rvalue::Use(Operand::Move(Place::from(result))))
+                let result_operand = Operand::Move(Place::from(result));
+                this.record_operands_moved(slice::from_ref(&result_operand));
+                block.and(Rvalue::Use(result_operand))
             }
             ExprKind::Cast { source } => {
                 let source = unpack!(block = this.as_operand(block, scope, source));
@@ -161,6 +171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                     .collect();
 
+                this.record_operands_moved(&fields);
                 block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
             }
             ExprKind::Tuple { fields } => {
@@ -171,6 +182,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                     .collect();
 
+                this.record_operands_moved(&fields);
                 block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
             }
             ExprKind::Closure { closure_id, substs, upvars, movability } => {
@@ -222,6 +234,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     }
                     UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
                 };
+                this.record_operands_moved(&operands);
                 block.and(Rvalue::Aggregate(result, operands))
             }
             ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
@@ -381,44 +394,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
 
-        let arg_place = unpack!(block = this.as_place(block, arg));
-
-        let mutability = match arg_place.as_ref() {
-            PlaceRef { local, projection: &[] } => this.local_decls[local].mutability,
-            PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
-                debug_assert!(
-                    this.local_decls[local].is_ref_for_guard(),
-                    "Unexpected capture place",
-                );
-                this.local_decls[local].mutability
-            }
-            PlaceRef {
-                local,
-                projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
-            }
-            | PlaceRef {
-                local,
-                projection:
-                    &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref],
-            } => {
-                let place = PlaceRef { local, projection: proj_base };
-
-                // Not projected from the implicit `self` in a closure.
-                debug_assert!(
-                    match place.local_or_deref_local() {
-                        Some(local) => local == Local::new(1),
-                        None => false,
-                    },
-                    "Unexpected capture place"
-                );
-                // Not in a closure
-                debug_assert!(
-                    this.upvar_mutbls.len() > upvar_index.index(),
-                    "Unexpected capture place"
-                );
-                this.upvar_mutbls[upvar_index.index()]
+        let arg_place_builder = unpack!(block = this.as_place_builder(block, arg));
+
+        let mutability = match arg_place_builder.base() {
+            // We are capturing a path that starts off a local variable in the parent.
+            // The mutability of the current capture is same as the mutability
+            // of the local declaration in the parent.
+            PlaceBase::Local(local) =>  this.local_decls[local].mutability,
+            // Parent is a closure and we are capturing a path that is captured
+            // by the parent itself. The mutability of the current capture
+            // is same as that of the capture in the parent closure.
+            PlaceBase::Upvar { .. } => {
+                let enclosing_upvars_resolved = arg_place_builder.clone().into_place(
+                    this.hir.tcx(),
+                    this.hir.typeck_results());
+
+                match enclosing_upvars_resolved.as_ref() {
+                    PlaceRef { local, projection: &[ProjectionElem::Field(upvar_index, _), ..] }
+                    | PlaceRef {
+                        local,
+                        projection: &[ProjectionElem::Deref, ProjectionElem::Field(upvar_index, _), ..] } => {
+                            // Not in a closure
+                            debug_assert!(
+                                local == Local::new(1),
+                                "Expected local to be Local(1), found {:?}",
+                                local
+                            );
+                            // Not in a closure
+                            debug_assert!(
+                                this.upvar_mutbls.len() > upvar_index.index(),
+                                "Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}",
+                                this.upvar_mutbls, upvar_index
+                            );
+                            this.upvar_mutbls[upvar_index.index()]
+                        }
+                    _ => bug!("Unexpected capture place"),
+                }
             }
-            _ => bug!("Unexpected capture place"),
         };
 
         let borrow_kind = match mutability {
@@ -426,6 +438,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
         };
 
+        let arg_place = arg_place_builder.into_place(
+                    this.hir.tcx(),
+                    this.hir.typeck_results());
+
         this.cfg.push_assign(
             block,
             source_info,
@@ -433,9 +449,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place),
         );
 
-        // In constants, temp_lifetime is None. We should not need to drop
-        // anything because no values with a destructor can be created in
-        // a constant at this time, even if the type may need dropping.
+        // See the comment in `expr_as_temp` and on the `rvalue_scopes` field for why
+        // this can be `None`.
         if let Some(temp_lifetime) = temp_lifetime {
             this.schedule_drop_storage_and_value(upvar_span, temp_lifetime, temp);
         }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index 9984b527ffd..241330d96e7 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -114,11 +114,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
-        unpack!(block = this.into(temp_place, block, expr));
-
-        if let Some(temp_lifetime) = temp_lifetime {
-            this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
-        }
+        unpack!(block = this.into(temp_place, temp_lifetime, block, expr));
 
         block.and(temp)
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 50001c38dc7..1f70fdb5ae3 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -1,28 +1,37 @@
 //! See docs in build/expr/mod.rs
 
 use crate::build::expr::category::{Category, RvalueFunc};
+use crate::build::scope::DropKind;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use crate::thir::*;
 use rustc_ast::InlineAsmOptions;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
+use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
 use rustc_span::symbol::sym;
-
 use rustc_target::spec::abi::Abi;
 
+use std::slice;
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, storing the result into `destination`, which
     /// is assumed to be uninitialized.
+    /// If a `drop_scope` is provided, `destination` is scheduled to be dropped
+    /// in `scope` once it has been initialized.
     crate fn into_expr(
         &mut self,
         destination: Place<'tcx>,
+        scope: Option<region::Scope>,
         mut block: BasicBlock,
         expr: Expr<'tcx>,
     ) -> BlockAnd<()> {
-        debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
+        debug!(
+            "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})",
+            destination, scope, block, expr
+        );
 
         // since we frequently have to reference `self` from within a
         // closure, where `self` would be shadowed, it's easier to
@@ -37,6 +46,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             _ => false,
         };
 
+        let schedule_drop = move |this: &mut Self| {
+            if let Some(drop_scope) = scope {
+                let local =
+                    destination.as_local().expect("cannot schedule drop of non-Local place");
+                this.schedule_drop(expr_span, drop_scope, local, DropKind::Value);
+            }
+        };
+
         if !expr_is_block_or_scope {
             this.block_context.push(BlockFrame::SubExpr);
         }
@@ -46,15 +63,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let region_scope = (region_scope, source_info);
                 ensure_sufficient_stack(|| {
                     this.in_scope(region_scope, lint_level, |this| {
-                        this.into(destination, block, value)
+                        this.into(destination, scope, block, value)
                     })
                 })
             }
             ExprKind::Block { body: ast_block } => {
-                this.ast_block(destination, block, ast_block, source_info)
+                this.ast_block(destination, scope, block, ast_block, source_info)
             }
             ExprKind::Match { scrutinee, arms } => {
-                this.match_expr(destination, expr_span, block, scrutinee, arms)
+                this.match_expr(destination, scope, expr_span, block, scrutinee, arms)
             }
             ExprKind::NeverToAny { source } => {
                 let source = this.hir.mirror(source);
@@ -62,10 +79,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 // (#66975) Source could be a const of type `!`, so has to
                 // exist in the generated MIR.
-                unpack!(block = this.as_temp(block, this.local_scope(), source, Mutability::Mut,));
+                unpack!(block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,));
 
                 // This is an optimization. If the expression was a call then we already have an
                 // unreachable block. Don't bother to terminate it and create a new one.
+                schedule_drop(this);
                 if is_call {
                     block.unit()
                 } else {
@@ -141,26 +159,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // Start the loop.
                 this.cfg.goto(block, source_info, loop_block);
 
-                this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
-                    // conduct the test, if necessary
-                    let body_block = this.cfg.start_new_block();
-                    this.cfg.terminate(
-                        loop_block,
-                        source_info,
-                        TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
-                    );
-                    this.diverge_from(loop_block);
-
-                    // The “return” value of the loop body must always be an unit. We therefore
-                    // introduce a unit temporary as the destination for the loop body.
-                    let tmp = this.get_unit_temp();
-                    // Execute the body, branching back to the test.
-                    let body_block_end = unpack!(this.into(tmp, body_block, body));
-                    this.cfg.goto(body_block_end, source_info, loop_block);
-
-                    // Loops are only exited by `break` expressions.
-                    None
-                })
+                this.in_breakable_scope(
+                    Some(loop_block),
+                    destination,
+                    scope,
+                    expr_span,
+                    move |this| {
+                        // conduct the test, if necessary
+                        let body_block = this.cfg.start_new_block();
+                        this.cfg.terminate(
+                            loop_block,
+                            source_info,
+                            TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
+                        );
+                        this.diverge_from(loop_block);
+
+                        // The “return” value of the loop body must always be an unit. We therefore
+                        // introduce a unit temporary as the destination for the loop body.
+                        let tmp = this.get_unit_temp();
+                        // Execute the body, branching back to the test.
+                        // We don't need to provide a drop scope because `tmp`
+                        // has type `()`.
+                        let body_block_end = unpack!(this.into(tmp, None, body_block, body));
+                        this.cfg.goto(body_block_end, source_info, loop_block);
+                        schedule_drop(this);
+
+                        // Loops are only exited by `break` expressions.
+                        None
+                    },
+                )
             }
             ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => {
                 let intrinsic = match *ty.kind() {
@@ -192,8 +219,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         .local_decls
                         .push(LocalDecl::with_source_info(ptr_ty, source_info).internal());
                     let ptr_temp = Place::from(ptr_temp);
-                    let block = unpack!(this.into(ptr_temp, block, ptr));
-                    this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val)
+                    // No need for a scope, ptr_temp doesn't need drop
+                    let block = unpack!(this.into(ptr_temp, None, block, ptr));
+                    // Maybe we should provide a scope here so that
+                    // `move_val_init` wouldn't leak on panic even with an
+                    // arbitrary `val` expression, but `schedule_drop`,
+                    // borrowck and drop elaboration all prevent us from
+                    // dropping `ptr_temp.deref()`.
+                    this.into(this.hir.tcx().mk_place_deref(ptr_temp), None, block, val)
                 } else {
                     let args: Vec<_> = args
                         .into_iter()
@@ -226,10 +259,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         },
                     );
                     this.diverge_from(block);
+                    schedule_drop(this);
                     success.unit()
                 }
             }
-            ExprKind::Use { source } => this.into(destination, block, source),
+            ExprKind::Use { source } => this.into(destination, scope, block, source),
             ExprKind::Borrow { arg, borrow_kind } => {
                 // We don't do this in `as_rvalue` because we use `as_place`
                 // for borrow expressions, so we cannot create an `RValue` that
@@ -266,12 +300,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // (evaluating them in order given by user)
                 let fields_map: FxHashMap<_, _> = fields
                     .into_iter()
-                    .map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr))))
+                    .map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr))))
                     .collect();
 
                 let field_names = this.hir.all_fields(adt_def, variant_index);
 
-                let fields = if let Some(FruInfo { base, field_types }) = base {
+                let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
                     let base = unpack!(block = this.as_place(block, base));
 
                     // MIR does not natively support FRU, so for each
@@ -306,12 +340,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     user_ty,
                     active_field_index,
                 );
+                this.record_operands_moved(&fields);
                 this.cfg.push_assign(
                     block,
                     source_info,
                     destination,
                     Rvalue::Aggregate(adt, fields),
                 );
+                schedule_drop(this);
                 block.unit()
             }
             ExprKind::InlineAsm { template, operands, options, line_spans } => {
@@ -408,6 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let place = unpack!(block = this.as_place(block, expr));
                 let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
                 this.cfg.push_assign(block, source_info, destination, rvalue);
+                schedule_drop(this);
                 block.unit()
             }
             ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
@@ -425,19 +462,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let place = unpack!(block = this.as_place(block, expr));
                 let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
                 this.cfg.push_assign(block, source_info, destination, rvalue);
+                schedule_drop(this);
                 block.unit()
             }
 
             ExprKind::Yield { value } => {
                 let scope = this.local_scope();
-                let value = unpack!(block = this.as_operand(block, scope, value));
+                let value = unpack!(block = this.as_operand(block, Some(scope), value));
                 let resume = this.cfg.start_new_block();
+                this.record_operands_moved(slice::from_ref(&value));
                 this.cfg.terminate(
                     block,
                     source_info,
                     TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
                 );
                 this.generator_drop_cleanup(block);
+                schedule_drop(this);
                 resume.unit()
             }
 
@@ -469,6 +509,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
                 this.cfg.push_assign(block, source_info, destination, rvalue);
+                schedule_drop(this);
                 block.unit()
             }
         };
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index f117689d940..a974ea0db5f 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -3,6 +3,7 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use crate::thir::*;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
+use std::slice;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Builds a block of MIR statements to evaluate the THIR `expr`.
@@ -46,6 +47,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 if this.hir.needs_drop(lhs.ty) {
                     let rhs = unpack!(block = this.as_local_operand(block, rhs));
                     let lhs = unpack!(block = this.as_place(block, lhs));
+                    this.record_operands_moved(slice::from_ref(&rhs));
                     unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
                 } else {
                     let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
diff --git a/compiler/rustc_mir_build/src/build/into.rs b/compiler/rustc_mir_build/src/build/into.rs
index 7264e495b84..ee1838ddea6 100644
--- a/compiler/rustc_mir_build/src/build/into.rs
+++ b/compiler/rustc_mir_build/src/build/into.rs
@@ -6,6 +6,7 @@
 
 use crate::build::{BlockAnd, Builder};
 use crate::thir::*;
+use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 
 pub(in crate::build) trait EvalInto<'tcx> {
@@ -13,6 +14,7 @@ pub(in crate::build) trait EvalInto<'tcx> {
         self,
         builder: &mut Builder<'_, 'tcx>,
         destination: Place<'tcx>,
+        scope: Option<region::Scope>,
         block: BasicBlock,
     ) -> BlockAnd<()>;
 }
@@ -21,13 +23,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn into<E>(
         &mut self,
         destination: Place<'tcx>,
+        scope: Option<region::Scope>,
         block: BasicBlock,
         expr: E,
     ) -> BlockAnd<()>
     where
         E: EvalInto<'tcx>,
     {
-        expr.eval_into(self, destination, block)
+        expr.eval_into(self, destination, scope, block)
     }
 }
 
@@ -36,10 +39,11 @@ impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
         self,
         builder: &mut Builder<'_, 'tcx>,
         destination: Place<'tcx>,
+        scope: Option<region::Scope>,
         block: BasicBlock,
     ) -> BlockAnd<()> {
         let expr = builder.hir.mirror(self);
-        builder.into_expr(destination, block, expr)
+        builder.into_expr(destination, scope, block, expr)
     }
 }
 
@@ -48,8 +52,9 @@ impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
         self,
         builder: &mut Builder<'_, 'tcx>,
         destination: Place<'tcx>,
+        scope: Option<region::Scope>,
         block: BasicBlock,
     ) -> BlockAnd<()> {
-        builder.into_expr(destination, block, self)
+        builder.into_expr(destination, scope, block, self)
     }
 }
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 3ee15248ae2..7ffdb7e33fb 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -87,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn match_expr(
         &mut self,
         destination: Place<'tcx>,
+        destination_scope: Option<region::Scope>,
         span: Span,
         mut block: BasicBlock,
         scrutinee: ExprRef<'tcx>,
@@ -107,6 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         self.lower_match_arms(
             destination,
+            destination_scope,
             scrutinee_place,
             scrutinee_span,
             arm_candidates,
@@ -213,75 +215,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
-    /// Lower the bindings, guards and arm bodies of a `match` expression.
-    ///
-    /// The decision tree should have already been created
-    /// (by [Builder::lower_match_tree]).
-    ///
-    /// `outer_source_info` is the SourceInfo for the whole match.
-    fn lower_match_arms(
-        &mut self,
-        destination: Place<'tcx>,
-        scrutinee_place: Place<'tcx>,
-        scrutinee_span: Span,
-        arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
-        outer_source_info: SourceInfo,
-        fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
-    ) -> BlockAnd<()> {
-        let arm_end_blocks: Vec<_> = arm_candidates
-            .into_iter()
-            .map(|(arm, candidate)| {
-                debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate);
-
-                let arm_source_info = self.source_info(arm.span);
-                let arm_scope = (arm.scope, arm_source_info);
-                self.in_scope(arm_scope, arm.lint_level, |this| {
-                    let body = this.hir.mirror(arm.body.clone());
-                    let scope = this.declare_bindings(
-                        None,
-                        arm.span,
-                        &arm.pattern,
-                        ArmHasGuard(arm.guard.is_some()),
-                        Some((Some(&scrutinee_place), scrutinee_span)),
-                    );
-
-                    let arm_block = this.bind_pattern(
-                        outer_source_info,
-                        candidate,
-                        arm.guard.as_ref(),
-                        &fake_borrow_temps,
-                        scrutinee_span,
-                        Some(arm.scope),
-                    );
-
-                    if let Some(source_scope) = scope {
-                        this.source_scope = source_scope;
-                    }
-
-                    this.into(destination, arm_block, body)
-                })
-            })
-            .collect();
-
-        // all the arm blocks will rejoin here
-        let end_block = self.cfg.start_new_block();
-
-        for arm_block in arm_end_blocks {
-            self.cfg.goto(unpack!(arm_block), outer_source_info, end_block);
-        }
-
-        self.source_scope = outer_source_info.scope;
-
-        end_block.unit()
-    }
-
     /// Binds the variables and ascribes types for a given `match` arm or
     /// `let` binding.
     ///
     /// Also check if the guard matches, if it's provided.
     /// `arm_scope` should be `Some` if and only if this is called for a
     /// `match` arm.
-    fn bind_pattern(
+    crate fn bind_pattern(
         &mut self,
         outer_source_info: SourceInfo,
         candidate: Candidate<'_, 'tcx>,
@@ -365,13 +305,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
                 let place =
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
-                unpack!(block = self.into(place, block, initializer));
+                let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
+
+                unpack!(block = self.into(place, Some(region_scope), block, initializer));
 
                 // Inject a fake read, see comments on `FakeReadCause::ForLet`.
                 let source_info = self.source_info(irrefutable_pat.span);
                 self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place);
 
-                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
                 block.unit()
             }
 
@@ -398,9 +339,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ascription:
                     thir::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
             } => {
+                let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
                 let place =
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
-                unpack!(block = self.into(place, block, initializer));
+                unpack!(block = self.into(place, Some(region_scope), block, initializer));
 
                 // Inject a fake read, see comments on `FakeReadCause::ForLet`.
                 let pattern_source_info = self.source_info(irrefutable_pat.span);
@@ -438,7 +380,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     },
                 );
 
-                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
                 block.unit()
             }
 
@@ -684,7 +625,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 }
 
 #[derive(Debug)]
-struct Candidate<'pat, 'tcx> {
+pub(super) struct Candidate<'pat, 'tcx> {
     /// `Span` of the original pattern that gave rise to this candidate
     span: Span,
 
@@ -1394,12 +1335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match test.kind {
             TestKind::SwitchInt { switch_ty, ref mut options } => {
                 for candidate in candidates.iter() {
-                    if !self.add_cases_to_switch(
-                        &match_place,
-                        candidate,
-                        switch_ty,
-                        options,
-                    ) {
+                    if !self.add_cases_to_switch(&match_place, candidate, switch_ty, options) {
                         break;
                     }
                 }
@@ -1780,14 +1716,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // ```
             //
             // and that is clearly not correct.
-            let by_value_bindings =
-                parent_bindings
-                    .iter()
-                    .flat_map(|(bindings, _)| bindings)
-                    .chain(&candidate.bindings)
-                    .filter(|binding| {
-                        matches!(binding.binding_mode, BindingMode::ByValue )
-                    });
+            let by_value_bindings = parent_bindings
+                .iter()
+                .flat_map(|(bindings, _)| bindings)
+                .chain(&candidate.bindings)
+                .filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue));
             // Read all of the by reference bindings to ensure that the
             // place they refer to can't be modified by the guard.
             for binding in by_value_bindings.clone() {
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index c50389a850e..d7fce15d996 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{GeneratorKind, HirIdMap, Node};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::Subst;
@@ -75,7 +76,9 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
             kind: hir::TraitItemKind::Const(ty, Some(body_id)),
             ..
         }) => (*body_id, ty.span, None),
-        Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => (*body, tcx.hir().span(*hir_id), None),
+        Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => {
+            (*body, tcx.hir().span(*hir_id), None)
+        }
 
         _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def.did),
     };
@@ -183,7 +186,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
                 return_ty,
                 return_ty_span,
                 body,
-                span_with_body
+                span_with_body,
             );
             mir.yield_ty = yield_ty;
             mir
@@ -581,7 +584,7 @@ fn construct_fn<'a, 'tcx, A>(
     return_ty: Ty<'tcx>,
     return_ty_span: Span,
     body: &'tcx hir::Body<'tcx>,
-    span_with_body: Span
+    span_with_body: Span,
 ) -> Body<'tcx>
 where
     A: Iterator<Item = ArgInfo<'tcx>>,
@@ -615,8 +618,12 @@ where
         let arg_scope_s = (arg_scope, source_info);
         // Attribute epilogue to function's closing brace
         let fn_end = span_with_body.shrink_to_hi();
-        let return_block =
-            unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
+        let return_block = unpack!(builder.in_breakable_scope(
+            None,
+            Place::return_place(),
+            Some(call_site_scope),
+            fn_end,
+            |builder| {
                 Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
                     builder.args_and_body(
                         START_BLOCK,
@@ -626,11 +633,13 @@ where
                         &body.value,
                     )
                 }))
-            }));
+            },
+        ));
         let source_info = builder.source_info(fn_end);
         builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
         let should_abort = should_abort_on_panic(tcx, fn_def_id, abi);
         builder.build_drop_trees(should_abort);
+        builder.unschedule_return_place_drop();
         return_block.unit()
     }));
 
@@ -657,12 +666,15 @@ fn construct_const<'a, 'tcx>(
     let owner_id = tcx.hir().body_owner(body_id);
     let def_id = tcx.hir().local_def_id(owner_id);
     let span = tcx.hir().span(owner_id);
-    let mut builder = Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None);
+    let mut builder =
+        Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None);
 
     let mut block = START_BLOCK;
     let ast_expr = &tcx.hir().body(body_id).value;
     let expr = builder.hir.mirror(ast_expr);
-    unpack!(block = builder.into_expr(Place::return_place(), block, expr));
+    // We don't provide a scope because we can't unwind in constants, so won't
+    // need to drop the return place.
+    unpack!(block = builder.into_expr(Place::return_place(), None, block, expr));
 
     let source_info = builder.source_info(span);
     builder.cfg.terminate(block, source_info, TerminatorKind::Return);
@@ -697,7 +709,8 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t
         hir::BodyOwnerKind::Const => 0,
         hir::BodyOwnerKind::Static(_) => 0,
     };
-    let mut builder = Builder::new(hir, def_id.to_def_id(), span, num_params, Safety::Safe, ty, span, None);
+    let mut builder =
+        Builder::new(hir, def_id.to_def_id(), span, num_params, Safety::Safe, ty, span, None);
     let source_info = builder.source_info(span);
     // Some MIR passes will expect the number of parameters to match the
     // function declaration.
@@ -811,7 +824,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // with the closure's DefId. Here, we run through that vec of UpvarIds for
         // the given closure and use the necessary information to create upvar
         // debuginfo and to fill `self.upvar_mutbls`.
-        if let Some(upvars) = hir_typeck_results.closure_captures.get(&fn_def_id) {
+        if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() {
             let closure_env_arg = Local::new(1);
             let mut closure_env_projs = vec![];
             let mut closure_ty = self.local_decls[closure_env_arg].ty;
@@ -824,14 +837,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
                 _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty),
             };
-            let upvar_tys = upvar_substs.upvar_tys();
-            let upvars_with_tys = upvars.iter().zip(upvar_tys);
-            self.upvar_mutbls = upvars_with_tys
+            let capture_tys = upvar_substs.upvar_tys();
+            let captures_with_tys = hir_typeck_results
+                .closure_min_captures_flattened(fn_def_id)
+                .zip(capture_tys);
+
+            self.upvar_mutbls = captures_with_tys
                 .enumerate()
-                .map(|(i, ((&var_id, &upvar_id), ty))| {
-                    let capture = hir_typeck_results.upvar_capture(upvar_id);
+                .map(|(i, (captured_place, ty))| {
+                    let capture = captured_place.info.capture_kind;
+                    let var_id = match captured_place.place.base {
+                        HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+                        _ => bug!("Expected an upvar")
+                    };
 
                     let mut mutability = Mutability::Not;
+
+                    // FIXME(project-rfc-2229#8): Store more precise information
                     let mut name = kw::Invalid;
                     if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) {
                         if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
@@ -941,7 +963,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
 
         let body = self.hir.mirror(ast_body);
-        self.into(Place::return_place(), block, body)
+        let call_site =
+            region::Scope { id: ast_body.hir_id.local_id, data: region::ScopeData::CallSite };
+        self.into(Place::return_place(), Some(call_site), block, body)
     }
 
     fn set_correct_source_scope_for_arg(
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index e91227d8357..e137f77ffbb 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -81,10 +81,10 @@ that contains only loops and breakable blocks. It tracks where a `break`,
 
 */
 
+use crate::build::matches::{ArmHasGuard, Candidate};
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
-use crate::thir::{Expr, ExprRef, LintLevel};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
+use crate::thir::{Arm, Expr, ExprRef, LintLevel};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::vec::IndexVec;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
@@ -121,8 +121,6 @@ struct Scope {
     /// end of the vector (top of the stack) first.
     drops: Vec<DropData>,
 
-    moved_locals: Vec<Local>,
-
     /// The drop index that will drop everything in and below this scope on an
     /// unwind path.
     cached_unwind_block: Option<DropIdx>,
@@ -158,6 +156,8 @@ struct BreakableScope<'tcx> {
     /// The destination of the loop/block expression itself (i.e., where to put
     /// the result of a `break` or `return` expression)
     break_destination: Place<'tcx>,
+    /// The scope that the destination should have its drop scheduled in.
+    destination_scope: Option<region::Scope>,
     /// Drops that happen on the `break`/`return` path.
     break_drops: DropTree,
     /// Drops that happen on the `continue` path.
@@ -406,7 +406,6 @@ impl<'tcx> Scopes<'tcx> {
             region_scope: region_scope.0,
             region_scope_span: region_scope.1.span,
             drops: vec![],
-            moved_locals: vec![],
             cached_unwind_block: None,
             cached_generator_drop_block: None,
         });
@@ -441,6 +440,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         loop_block: Option<BasicBlock>,
         break_destination: Place<'tcx>,
+        destination_scope: Option<region::Scope>,
         span: Span,
         f: F,
     ) -> BlockAnd<()>
@@ -451,15 +451,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let scope = BreakableScope {
             region_scope,
             break_destination,
+            destination_scope,
             break_drops: DropTree::new(),
             continue_drops: loop_block.map(|_| DropTree::new()),
         };
+        let continue_block = loop_block.map(|block| (block, self.diverge_cleanup()));
         self.scopes.breakable_scopes.push(scope);
         let normal_exit_block = f(self);
         let breakable_scope = self.scopes.breakable_scopes.pop().unwrap();
         assert!(breakable_scope.region_scope == region_scope);
+        if let Some(drops) = breakable_scope.continue_drops {
+            self.build_exit_tree(drops, continue_block);
+        }
         let break_block = self.build_exit_tree(breakable_scope.break_drops, None);
-        if let Some(drops) = breakable_scope.continue_drops { self.build_exit_tree(drops, loop_block); }
         match (normal_exit_block, break_block) {
             (Some(block), None) | (None, Some(block)) => block,
             (None, None) => self.cfg.start_new_block().unit(),
@@ -588,22 +592,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 .rposition(|breakable_scope| breakable_scope.region_scope == scope)
                 .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
         };
-        let (break_index, destination) = match target {
+        let (break_index, destination, dest_scope) = match target {
             BreakableTarget::Return => {
                 let scope = &self.scopes.breakable_scopes[0];
                 if scope.break_destination != Place::return_place() {
                     span_bug!(span, "`return` in item with no return scope");
                 }
-                (0, Some(scope.break_destination))
+                (0, Some(scope.break_destination), scope.destination_scope)
             }
             BreakableTarget::Break(scope) => {
                 let break_index = get_scope_index(scope);
                 let scope = &self.scopes.breakable_scopes[break_index];
-                (break_index, Some(scope.break_destination))
+                (break_index, Some(scope.break_destination), scope.destination_scope)
             }
             BreakableTarget::Continue(scope) => {
                 let break_index = get_scope_index(scope);
-                (break_index, None)
+                (break_index, None, None)
             }
         };
 
@@ -611,7 +615,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             if let Some(value) = value {
                 debug!("stmt_expr Break val block_context.push(SubExpr)");
                 self.block_context.push(BlockFrame::SubExpr);
-                unpack!(block = self.into(destination, block, value));
+                unpack!(block = self.into(destination, dest_scope, block, value));
+                dest_scope
+                    .map(|scope| self.unschedule_drop(scope, destination.as_local().unwrap()));
                 self.block_context.pop();
             } else {
                 self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx())
@@ -733,18 +739,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// We would allocate the box but then free it on the unwinding
     /// path; we would also emit a free on the 'success' path from
     /// panic, but that will turn out to be removed as dead-code.
-    ///
-    /// When building statics/constants, returns `None` since
-    /// intermediate values do not have to be dropped in that case.
-    crate fn local_scope(&self) -> Option<region::Scope> {
-        match self.hir.body_owner_kind {
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) =>
-            // No need to free storage in this context.
-            {
-                None
-            }
-            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => Some(self.scopes.topmost()),
-        }
+    crate fn local_scope(&self) -> region::Scope {
+        self.scopes.topmost()
     }
 
     // Scheduling drops
@@ -861,14 +857,47 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
     }
 
-    /// Indicates that the "local operand" stored in `local` is
+    /// Unschedule a drop. Used for `break`, `return` and `match` expressions,
+    /// where `record_operands_moved` is not powerful enough.
+    ///
+    /// The given local is expected to have a value drop scheduled in the given
+    /// scope and for that drop to be the most recent thing scheduled in that
+    /// scope.
+    fn unschedule_drop(&mut self, region_scope: region::Scope, local: Local) {
+        if !self.hir.needs_drop(self.local_decls[local].ty) {
+            return;
+        }
+        for scope in self.scopes.scopes.iter_mut().rev() {
+            scope.invalidate_cache();
+
+            if scope.region_scope == region_scope {
+                let drop = scope.drops.pop();
+
+                match drop {
+                    Some(DropData { local: removed_local, kind: DropKind::Value, .. })
+                        if removed_local == local =>
+                    {
+                        return;
+                    }
+                    _ => bug!(
+                        "found wrong drop, expected value drop of {:?}, found {:?}",
+                        local,
+                        drop,
+                    ),
+                }
+            }
+        }
+
+        bug!("region scope {:?} not in scope to unschedule drop of {:?}", region_scope, local);
+    }
+
+    /// Indicates that the "local operands" stored in `local` is
     /// *moved* at some point during execution (see `local_scope` for
     /// more information about what a "local operand" is -- in short,
     /// it's an intermediate operand created as part of preparing some
     /// MIR instruction). We use this information to suppress
-    /// redundant drops on the non-unwind paths. This results in less
-    /// MIR, but also avoids spurious borrow check errors
-    /// (c.f. #64391).
+    /// redundant drops. This results in less MIR, but also avoids spurious
+    /// borrow check errors (c.f. #64391).
     ///
     /// Example: when compiling the call to `foo` here:
     ///
@@ -898,35 +927,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// not the `DROP(_X)` itself, but the (spurious) unwind pathways
     /// that it creates. See #64391 for an example.
     crate fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) {
-        let scope = match self.local_scope() {
-            None => {
-                // if there is no local scope, operands won't be dropped anyway
-                return;
-            }
+        let local_scope = self.local_scope();
+        let scope = self.scopes.scopes.last_mut().unwrap();
 
-            Some(local_scope) => self
-                .scopes
-                .scopes
-                .iter_mut()
-                .rfind(|scope| scope.region_scope == local_scope)
-                .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)),
-        };
+        assert_eq!(
+            scope.region_scope, local_scope,
+            "local scope is not the topmost scope!",
+        );
 
         // look for moves of a local variable, like `MOVE(_X)`
-        let locals_moved = operands.iter().flat_map(|operand| match operand {
-            Operand::Copy(_) | Operand::Constant(_) => None,
-            Operand::Move(place) => place.as_local(),
-        });
+        let locals_moved = operands
+            .iter()
+            .filter_map(|operand| match operand {
+                Operand::Copy(_) | Operand::Constant(_) => None,
+                Operand::Move(place) => place.as_local(),
+            })
+            .collect::<FxHashSet<_>>();
 
-        for local in locals_moved {
-            // check if we have a Drop for this operand and -- if so
-            // -- add it to the list of moved operands. Note that this
-            // local might not have been an operand created for this
-            // call, it could come from other places too.
-            if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) {
-                scope.moved_locals.push(local);
-            }
-        }
+        // Remove the drops for the moved operands.
+        scope
+            .drops
+            .retain(|drop| drop.kind == DropKind::Storage || !locals_moved.contains(&drop.local));
+        scope.invalidate_cache();
     }
 
     // Other
@@ -950,9 +972,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match cond {
             // Don't try to drop a constant
             Operand::Constant(_) => (),
-            // If constants and statics, we don't generate StorageLive for this
-            // temporary, so don't try to generate StorageDead for it either.
-            _ if self.local_scope().is_none() => (),
             Operand::Copy(place) | Operand::Move(place) => {
                 if let Some(cond_temp) = place.as_local() {
                     // Manually drop the condition on both branches.
@@ -1116,11 +1135,96 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         success_block
     }
 
+    /// Lower the arms and guards of a match.
+    ///
+    /// The decision tree should have already been created (by
+    /// [Builder::lower_match_tree]).
+    ///
+    /// This is this module, and not in `build::matches` because we have to do
+    /// some careful scope manipulation to have the drop of the destination be
+    /// scheduled at the end of each arm and then cleared for the next arm.
+    crate fn lower_match_arms(
+        &mut self,
+        destination: Place<'tcx>,
+        destination_scope: Option<region::Scope>,
+        scrutinee_place: Place<'tcx>,
+        scrutinee_span: Span,
+        arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
+        outer_source_info: SourceInfo,
+        fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
+    ) -> BlockAnd<()> {
+        if arm_candidates.is_empty() {
+            // If there are no arms to schedule drops, then we have to do it
+            // manually.
+            if let Some(scope) = destination_scope {
+                self.schedule_drop(
+                    outer_source_info.span,
+                    scope,
+                    destination.as_local().unwrap(),
+                    DropKind::Value,
+                );
+            }
+            return self.cfg.start_new_block().unit();
+        }
+        let mut first_arm = true;
+        let arm_end_blocks: Vec<_> = arm_candidates
+            .into_iter()
+            .map(|(arm, candidate)| {
+                debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate);
+
+                if first_arm {
+                    first_arm = false;
+                } else if let Some(scope) = destination_scope {
+                    self.unschedule_drop(scope, destination.as_local().unwrap());
+                }
+
+                let arm_source_info = self.source_info(arm.span);
+                let arm_scope = (arm.scope, arm_source_info);
+                self.in_scope(arm_scope, arm.lint_level, |this| {
+                    let body = this.hir.mirror(arm.body.clone());
+                    let scope = this.declare_bindings(
+                        None,
+                        arm.span,
+                        &arm.pattern,
+                        ArmHasGuard(arm.guard.is_some()),
+                        Some((Some(&scrutinee_place), scrutinee_span)),
+                    );
+
+                    let arm_block = this.bind_pattern(
+                        outer_source_info,
+                        candidate,
+                        arm.guard.as_ref(),
+                        &fake_borrow_temps,
+                        scrutinee_span,
+                        Some(arm.scope),
+                    );
+
+                    if let Some(source_scope) = scope {
+                        this.source_scope = source_scope;
+                    }
+
+                    this.into(destination, destination_scope, arm_block, body)
+                })
+            })
+            .collect();
+
+        // all the arm blocks will rejoin here
+        let end_block = self.cfg.start_new_block();
+
+        for arm_block in arm_end_blocks {
+            self.cfg.goto(unpack!(arm_block), outer_source_info, end_block);
+        }
+
+        self.source_scope = outer_source_info.scope;
+
+        end_block.unit()
+    }
+
     /// Unschedules any drops in the top scope.
     ///
     /// This is only needed for `match` arm scopes, because they have one
     /// entrance per pattern, but only one exit.
-    crate fn clear_top_scope(&mut self, region_scope: region::Scope) {
+    pub(super) fn clear_top_scope(&mut self, region_scope: region::Scope) {
         let top_scope = self.scopes.scopes.last_mut().unwrap();
 
         assert_eq!(top_scope.region_scope, region_scope);
@@ -1128,6 +1232,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         top_scope.drops.clear();
         top_scope.invalidate_cache();
     }
+
+    /// Unschedules the drop of the return place.
+    ///
+    /// If the return type of a function requires drop, then we schedule it
+    /// in the outermost scope so that it's dropped if there's a panic while
+    /// we drop any local variables. But we don't want to drop it if we
+    /// return normally.
+    crate fn unschedule_return_place_drop(&mut self) {
+        assert_eq!(self.scopes.scopes.len(), 1);
+        assert!(self.scopes.scopes[0].drops.len() <= 1);
+        self.scopes.scopes[0].drops.clear();
+    }
 }
 
 /// Builds drops for `pop_scope` and `leave_top_scope`.
@@ -1174,14 +1290,6 @@ fn build_scope_drops<'tcx>(
                 debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind);
                 unwind_to = unwind_drops.drops[unwind_to].1;
 
-                // If the operand has been moved, and we are not on an unwind
-                // path, then don't generate the drop. (We only take this into
-                // account for non-unwind paths so as not to disturb the
-                // caching mechanism.)
-                if scope.moved_locals.iter().any(|&o| o == local) {
-                    continue;
-                }
-
                 unwind_drops.add_entry(block, unwind_to);
 
                 let next = cfg.start_new_block();
@@ -1211,20 +1319,24 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
     /// Build a drop tree for a breakable scope.
     ///
     /// If `continue_block` is `Some`, then the tree is for `continue` inside a
-    /// loop. Otherwise this is for `break` or `return`.
+    /// loop. Otherwise this is for `break` or `return`. The `DropIdx` is the
+    /// next drop in the case that the drop tree unwinds. This is needed
+    /// because the drop of the break destination has already been scheduled
+    /// but it hasn't been initialized on the `continue` paths.
     fn build_exit_tree(
         &mut self,
         mut drops: DropTree,
-        continue_block: Option<BasicBlock>,
+        continue_block: Option<(BasicBlock, DropIdx)>,
     ) -> Option<BlockAnd<()>> {
         let mut blocks = IndexVec::from_elem(None, &drops.drops);
-        blocks[ROOT_NODE] = continue_block;
+        blocks[ROOT_NODE] = continue_block.map(|(block, _)| block);
 
         drops.build_mir::<ExitScopes>(&mut self.cfg, &mut blocks);
 
         // Link the exit drop tree to unwind drop tree.
         if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) {
-            let unwind_target = self.diverge_cleanup();
+            let unwind_target = continue_block
+                .map_or_else(|| self.diverge_cleanup(), |(_, unwind_target)| unwind_target);
             let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
             for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) {
                 match drop_data.0.kind {
@@ -1387,7 +1499,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
             | TerminatorKind::Yield { .. }
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::InlineAsm {.. } => {
+            | TerminatorKind::InlineAsm { .. } => {
                 span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind)
             }
         }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index e404afeb698..fbdadc67b43 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -6,6 +6,8 @@ use crate::thir::*;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_index::vec::Idx;
+use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
+use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::ty::adjustment::{
@@ -386,14 +388,12 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                     span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
                 }
             };
+
             let upvars = cx
                 .typeck_results()
-                .closure_captures
-                .get(&def_id)
-                .iter()
-                .flat_map(|upvars| upvars.iter())
+                .closure_min_captures_flattened(def_id)
                 .zip(substs.upvar_tys())
-                .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty))
+                .map(|(captured_place, ty)| capture_upvar(cx, expr, captured_place, ty))
                 .collect();
             ExprKind::Closure { closure_id: def_id, substs, upvars, movability }
         }
@@ -408,7 +408,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             operands: asm
                 .operands
                 .iter()
-                .map(|op| {
+                .map(|(op, _op_sp)| {
                     match *op {
                         hir::InlineAsmOperand::In { reg, ref expr } => {
                             InlineAsmOperand::In { reg, expr: expr.to_ref() }
@@ -981,27 +981,55 @@ fn overloaded_place<'a, 'tcx>(
     ExprKind::Deref { arg: ref_expr.to_ref() }
 }
 
-fn capture_upvar<'tcx>(
+fn capture_upvar<'a, 'tcx>(
     cx: &mut Cx<'_, 'tcx>,
     closure_expr: &'tcx hir::Expr<'tcx>,
-    var_hir_id: hir::HirId,
+    captured_place: &'a ty::CapturedPlace<'tcx>,
     upvar_ty: Ty<'tcx>,
 ) -> ExprRef<'tcx> {
-    let upvar_id = ty::UpvarId {
-        var_path: ty::UpvarPath { hir_id: var_hir_id },
-        closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id),
-    };
-    let upvar_capture = cx.typeck_results().upvar_capture(upvar_id);
+    let upvar_capture = captured_place.info.capture_kind;
     let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
-    let var_ty = cx.typeck_results().node_type(var_hir_id);
-    let captured_var = Expr {
+    let var_ty = captured_place.place.base_ty;
+
+    // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
+    // as it's seen for use within the closure and not at the time of closure creation.
+    //
+    // That is we see expect to see it start from a captured upvar and not something that is local
+    // to the closure's parent.
+    let var_hir_id = match captured_place.place.base {
+        HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+        base => bug!("Expected an upvar, found {:?}", base),
+    };
+
+    let mut captured_place_expr = Expr {
         temp_lifetime,
         ty: var_ty,
         span: closure_expr.span,
         kind: convert_var(cx, var_hir_id),
     };
+
+    for proj in captured_place.place.projections.iter() {
+        let kind = match proj.kind {
+            HirProjectionKind::Deref => ExprKind::Deref { arg: captured_place_expr.to_ref() },
+            HirProjectionKind::Field(field, ..) => {
+                // Variant index will always be 0, because for multi-variant
+                // enums, we capture the enum entirely.
+                ExprKind::Field {
+                    lhs: captured_place_expr.to_ref(),
+                    name: Field::new(field as usize),
+                }
+            }
+            HirProjectionKind::Index | HirProjectionKind::Subslice => {
+                // We don't capture these projections, so we can ignore them here
+                continue;
+            }
+        };
+
+        captured_place_expr = Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind };
+    }
+
     match upvar_capture {
-        ty::UpvarCapture::ByValue(_) => captured_var.to_ref(),
+        ty::UpvarCapture::ByValue(_) => captured_place_expr.to_ref(),
         ty::UpvarCapture::ByRef(upvar_borrow) => {
             let borrow_kind = match upvar_borrow.kind {
                 ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
@@ -1012,7 +1040,7 @@ fn capture_upvar<'tcx>(
                 temp_lifetime,
                 ty: upvar_ty,
                 span: closure_expr.span,
-                kind: ExprKind::Borrow { borrow_kind, arg: captured_var.to_ref() },
+                kind: ExprKind::Borrow { borrow_kind, arg: captured_place_expr.to_ref() },
             }
             .to_ref()
         }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 3b2eef5a905..8b21a9b24e6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -697,6 +697,8 @@ impl<'tcx> Constructor<'tcx> {
     /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
     /// For the simple cases, this is simply checking for equality. For the "grouped" constructors,
     /// this checks for inclusion.
+    // We inline because this has a single call site in `Matrix::specialize_constructor`.
+    #[inline]
     pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
         // This must be kept in sync with `is_covered_by_any`.
         match (self, other) {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index b746256f5fe..df4695b18e7 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -23,6 +23,7 @@ use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, E
 use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit};
 use rustc_ast::{Visibility, VisibilityKind};
 use rustc_ast_pretty::pprust;
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::PResult;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError};
 use rustc_session::parse::ParseSess;
@@ -264,7 +265,7 @@ impl TokenType {
             TokenType::Ident => "identifier".to_string(),
             TokenType::Path => "path".to_string(),
             TokenType::Type => "type".to_string(),
-            TokenType::Const => "const".to_string(),
+            TokenType::Const => "a const expression".to_string(),
         }
     }
 }
@@ -935,16 +936,24 @@ impl<'a> Parser<'a> {
                             is_interpolated_expr = true;
                         }
                     }
-                    let token_tree = if is_interpolated_expr {
-                        // We need to accept arbitrary interpolated expressions to continue
-                        // supporting things like `doc = $expr` that work on stable.
-                        // Non-literal interpolated expressions are rejected after expansion.
-                        self.parse_token_tree()
-                    } else {
-                        self.parse_unsuffixed_lit()?.token_tree()
-                    };
 
-                    MacArgs::Eq(eq_span, token_tree.into())
+                    // The value here is never passed to macros as tokens by itself (not as a part
+                    // of the whole attribute), so we don't collect tokens here. If this changes,
+                    // then token will need to be collected. One catch here is that we are using
+                    // a nonterminal for keeping the expression, but this nonterminal should not
+                    // be wrapped into a group when converting to token stream.
+                    let expr = self.parse_expr()?;
+                    let span = expr.span;
+
+                    match &expr.kind {
+                        // Not gated to supporte things like `doc = $expr` that work on stable.
+                        _ if is_interpolated_expr => {}
+                        ExprKind::Lit(lit) if lit.kind.is_unsuffixed() => {}
+                        _ => self.sess.gated_spans.gate(sym::extended_key_value_attributes, span),
+                    }
+
+                    let token = token::Interpolated(Lrc::new(token::NtExpr(expr)));
+                    MacArgs::Eq(eq_span, TokenTree::token(token, span).into())
                 } else {
                     MacArgs::Empty
                 }
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index ee9a6dca5ad..b62c7373800 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -18,7 +18,7 @@ pub(super) const PARAM_EXPECTED: Expected = Some("parameter name");
 const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here";
 
 /// Whether or not an or-pattern should be gated when occurring in the current context.
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
 pub(super) enum GateOr {
     Yes,
     No,
@@ -94,7 +94,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, P<Pat>> {
         // Parse the first pattern (`p_0`).
         let first_pat = self.parse_pat(expected)?;
-        self.maybe_recover_unexpected_comma(first_pat.span, rc)?;
+        self.maybe_recover_unexpected_comma(first_pat.span, rc, gate_or)?;
 
         // If the next token is not a `|`,
         // this is not an or-pattern and we should exit here.
@@ -110,7 +110,7 @@ impl<'a> Parser<'a> {
                 err.span_label(lo, WHILE_PARSING_OR_MSG);
                 err
             })?;
-            self.maybe_recover_unexpected_comma(pat.span, rc)?;
+            self.maybe_recover_unexpected_comma(pat.span, rc, gate_or)?;
             pats.push(pat);
         }
         let or_pattern_span = lo.to(self.prev_token.span);
@@ -190,7 +190,12 @@ impl<'a> Parser<'a> {
 
     /// Some special error handling for the "top-level" patterns in a match arm,
     /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
-    fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> {
+    fn maybe_recover_unexpected_comma(
+        &mut self,
+        lo: Span,
+        rc: RecoverComma,
+        gate_or: GateOr,
+    ) -> PResult<'a, ()> {
         if rc == RecoverComma::No || self.token != token::Comma {
             return Ok(());
         }
@@ -209,18 +214,24 @@ impl<'a> Parser<'a> {
         let seq_span = lo.to(self.prev_token.span);
         let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
         if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
+            const MSG: &str = "try adding parentheses to match on a tuple...";
+
+            let or_suggestion =
+                gate_or == GateOr::No || !self.sess.gated_spans.is_ungated(sym::or_patterns);
             err.span_suggestion(
                 seq_span,
-                "try adding parentheses to match on a tuple...",
+                if or_suggestion { MSG } else { MSG.trim_end_matches('.') },
                 format!("({})", seq_snippet),
                 Applicability::MachineApplicable,
-            )
-            .span_suggestion(
-                seq_span,
-                "...or a vertical bar to match on multiple alternatives",
-                seq_snippet.replace(",", " |"),
-                Applicability::MachineApplicable,
             );
+            if or_suggestion {
+                err.span_suggestion(
+                    seq_span,
+                    "...or a vertical bar to match on multiple alternatives",
+                    seq_snippet.replace(",", " |"),
+                    Applicability::MachineApplicable,
+                );
+            }
         }
         Err(err)
     }
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index df6667a29d5..c87799f1c2a 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -18,3 +18,4 @@ rustc_ast = { path = "../rustc_ast" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_lexer = { path = "../rustc_lexer" }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c9e02d56f4b..73fb28e5c9a 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -78,7 +78,7 @@ impl CheckAttrVisitor<'tcx> {
             } else if self.tcx.sess.check_name(attr, sym::track_caller) {
                 self.check_track_caller(&attr.span, attrs, span, target)
             } else if self.tcx.sess.check_name(attr, sym::doc) {
-                self.check_doc_alias(attr, hir_id, target)
+                self.check_doc_attrs(attr, hir_id, target)
             } else if self.tcx.sess.check_name(attr, sym::no_link) {
                 self.check_no_link(&attr, span, target)
             } else if self.tcx.sess.check_name(attr, sym::export_name) {
@@ -287,99 +287,159 @@ impl CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn doc_alias_str_error(&self, meta: &NestedMetaItem) {
+    fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) {
         self.tcx
             .sess
             .struct_span_err(
                 meta.span(),
-                "doc alias attribute expects a string: #[doc(alias = \"0\")]",
+                &format!("doc {0} attribute expects a string: #[doc({0} = \"a\")]", attr_name),
             )
             .emit();
     }
 
-    fn check_doc_alias(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool {
+    fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool {
+        let doc_alias = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
+        if doc_alias.is_empty() {
+            self.doc_attr_str_error(meta, "alias");
+            return false;
+        }
+        if let Some(c) =
+            doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
+        {
+            self.tcx
+                .sess
+                .struct_span_err(
+                    meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
+                    &format!("{:?} character isn't allowed in `#[doc(alias = \"...\")]`", c,),
+                )
+                .emit();
+            return false;
+        }
+        if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') {
+            self.tcx
+                .sess
+                .struct_span_err(
+                    meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
+                    "`#[doc(alias = \"...\")]` cannot start or end with ' '",
+                )
+                .emit();
+            return false;
+        }
+        if let Some(err) = match target {
+            Target::Impl => Some("implementation block"),
+            Target::ForeignMod => Some("extern block"),
+            Target::AssocTy => {
+                let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+                let containing_item = self.tcx.hir().expect_item(parent_hir_id);
+                if Target::from_item(containing_item) == Target::Impl {
+                    Some("type alias in implementation block")
+                } else {
+                    None
+                }
+            }
+            Target::AssocConst => {
+                let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+                let containing_item = self.tcx.hir().expect_item(parent_hir_id);
+                // We can't link to trait impl's consts.
+                let err = "associated constant in trait implementation block";
+                match containing_item.kind {
+                    ItemKind::Impl { of_trait: Some(_), .. } => Some(err),
+                    _ => None,
+                }
+            }
+            _ => None,
+        } {
+            self.tcx
+                .sess
+                .struct_span_err(
+                    meta.span(),
+                    &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err),
+                )
+                .emit();
+            return false;
+        }
+        true
+    }
+
+    fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
+        let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
+        if doc_keyword.is_empty() {
+            self.doc_attr_str_error(meta, "keyword");
+            return false;
+        }
+        match self.tcx.hir().expect_item(hir_id).kind {
+            ItemKind::Mod(ref module) => {
+                if !module.item_ids.is_empty() {
+                    self.tcx
+                        .sess
+                        .struct_span_err(
+                            meta.span(),
+                            "`#[doc(keyword = \"...\")]` can only be used on empty modules",
+                        )
+                        .emit();
+                    return false;
+                }
+            }
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(
+                        meta.span(),
+                        "`#[doc(keyword = \"...\")]` can only be used on modules",
+                    )
+                    .emit();
+                return false;
+            }
+        }
+        if !rustc_lexer::is_ident(&doc_keyword) {
+            self.tcx
+                .sess
+                .struct_span_err(
+                    meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
+                    &format!("`{}` is not a valid identifier", doc_keyword),
+                )
+                .emit();
+            return false;
+        }
+        true
+    }
+
+    fn check_attr_crate_level(
+        &self,
+        meta: &NestedMetaItem,
+        hir_id: HirId,
+        attr_name: &str,
+    ) -> bool {
+        if CRATE_HIR_ID == hir_id {
+            self.tcx
+                .sess
+                .struct_span_err(
+                    meta.span(),
+                    &format!(
+                        "`#![doc({} = \"...\")]` isn't allowed as a crate level attribute",
+                        attr_name,
+                    ),
+                )
+                .emit();
+            return false;
+        }
+        true
+    }
+
+    fn check_doc_attrs(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool {
         if let Some(mi) = attr.meta() {
             if let Some(list) = mi.meta_item_list() {
                 for meta in list {
                     if meta.has_name(sym::alias) {
-                        if !meta.is_value_str() {
-                            self.doc_alias_str_error(meta);
-                            return false;
-                        }
-                        let doc_alias =
-                            meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
-                        if doc_alias.is_empty() {
-                            self.doc_alias_str_error(meta);
-                            return false;
-                        }
-                        if let Some(c) = doc_alias
-                            .chars()
-                            .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
+                        if !self.check_attr_crate_level(meta, hir_id, "alias")
+                            || !self.check_doc_alias(meta, hir_id, target)
                         {
-                            self.tcx
-                                .sess
-                                .struct_span_err(
-                                    meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
-                                    &format!(
-                                        "{:?} character isn't allowed in `#[doc(alias = \"...\")]`",
-                                        c,
-                                    ),
-                                )
-                                .emit();
-                            return false;
-                        }
-                        if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') {
-                            self.tcx
-                                .sess
-                                .struct_span_err(
-                                    meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
-                                    "`#[doc(alias = \"...\")]` cannot start or end with ' '",
-                                )
-                                .emit();
                             return false;
                         }
-                        if let Some(err) = match target {
-                            Target::Impl => Some("implementation block"),
-                            Target::ForeignMod => Some("extern block"),
-                            Target::AssocTy => {
-                                let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
-                                let containing_item = self.tcx.hir().expect_item(parent_hir_id);
-                                if Target::from_item(containing_item) == Target::Impl {
-                                    Some("type alias in implementation block")
-                                } else {
-                                    None
-                                }
-                            }
-                            Target::AssocConst => {
-                                let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
-                                let containing_item = self.tcx.hir().expect_item(parent_hir_id);
-                                // We can't link to trait impl's consts.
-                                let err = "associated constant in trait implementation block";
-                                match containing_item.kind {
-                                    ItemKind::Impl { of_trait: Some(_), .. } => Some(err),
-                                    _ => None,
-                                }
-                            }
-                            _ => None,
-                        } {
-                            self.tcx
-                                .sess
-                                .struct_span_err(
-                                    meta.span(),
-                                    &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err),
-                                )
-                                .emit();
-                            return false;
-                        }
-                        if CRATE_HIR_ID == hir_id {
-                            self.tcx
-                                .sess
-                                .struct_span_err(
-                                    meta.span(),
-                                    "`#![doc(alias = \"...\")]` isn't allowed as a crate \
-                                     level attribute",
-                                )
-                                .emit();
+                    } else if meta.has_name(sym::keyword) {
+                        if !self.check_attr_crate_level(meta, hir_id, "keyword")
+                            || !self.check_doc_keyword(meta, hir_id)
+                        {
                             return false;
                         }
                     }
@@ -485,60 +545,68 @@ impl CheckAttrVisitor<'tcx> {
         target: Target,
         item: Option<ItemLike<'_>>,
     ) -> bool {
-        if let Target::Fn | Target::Method(..) | Target::ForeignFn = target {
-            let mut invalid_args = vec![];
-            for meta in attr.meta_item_list().expect("no meta item list") {
-                if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) {
-                    if let Some(ItemLike::Item(Item {
-                        kind: ItemKind::Fn(FnSig { decl, .. }, ..),
-                        ..
-                    }))
-                    | Some(ItemLike::ForeignItem(ForeignItem {
-                        kind: ForeignItemKind::Fn(decl, ..),
-                        ..
-                    })) = item
-                    {
-                        let arg_count = decl.inputs.len() as u128;
-                        if *val >= arg_count {
-                            let span = meta.span();
-                            self.tcx
-                                .sess
-                                .struct_span_err(span, "index exceeds number of arguments")
-                                .span_label(
-                                    span,
-                                    format!(
-                                        "there {} only {} argument{}",
-                                        if arg_count != 1 { "are" } else { "is" },
-                                        arg_count,
-                                        pluralize!(arg_count)
-                                    ),
-                                )
-                                .emit();
-                            return false;
-                        }
-                    } else {
-                        bug!("should be a function item");
+        let is_function = matches!(target, Target::Fn | Target::Method(..) | Target::ForeignFn);
+        if !is_function {
+            self.tcx
+                .sess
+                .struct_span_err(attr.span, "attribute should be applied to a function")
+                .span_label(*span, "not a function")
+                .emit();
+            return false;
+        }
+
+        let list = match attr.meta_item_list() {
+            // The attribute form is validated on AST.
+            None => return false,
+            Some(it) => it,
+        };
+
+        let mut invalid_args = vec![];
+        for meta in list {
+            if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) {
+                if let Some(ItemLike::Item(Item {
+                    kind: ItemKind::Fn(FnSig { decl, .. }, ..),
+                    ..
+                }))
+                | Some(ItemLike::ForeignItem(ForeignItem {
+                    kind: ForeignItemKind::Fn(decl, ..),
+                    ..
+                })) = item
+                {
+                    let arg_count = decl.inputs.len() as u128;
+                    if *val >= arg_count {
+                        let span = meta.span();
+                        self.tcx
+                            .sess
+                            .struct_span_err(span, "index exceeds number of arguments")
+                            .span_label(
+                                span,
+                                format!(
+                                    "there {} only {} argument{}",
+                                    if arg_count != 1 { "are" } else { "is" },
+                                    arg_count,
+                                    pluralize!(arg_count)
+                                ),
+                            )
+                            .emit();
+                        return false;
                     }
                 } else {
-                    invalid_args.push(meta.span());
+                    bug!("should be a function item");
                 }
-            }
-            if !invalid_args.is_empty() {
-                self.tcx
-                    .sess
-                    .struct_span_err(invalid_args, "arguments should be non-negative integers")
-                    .emit();
-                false
             } else {
-                true
+                invalid_args.push(meta.span());
             }
-        } else {
+        }
+
+        if !invalid_args.is_empty() {
             self.tcx
                 .sess
-                .struct_span_err(attr.span, "attribute should be applied to a function")
-                .span_label(*span, "not a function")
+                .struct_span_err(invalid_args, "arguments should be non-negative integers")
                 .emit();
             false
+        } else {
+            true
         }
     }
 
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index b87b13cff80..00152878d6d 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -396,24 +396,6 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
                     }
                 }
             }
-            hir::ItemKind::Trait(.., trait_item_refs) => {
-                for trait_item_ref in trait_item_refs {
-                    let trait_item = self.krate.trait_item(trait_item_ref.id);
-                    match trait_item.kind {
-                        hir::TraitItemKind::Const(_, Some(_))
-                        | hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => {
-                            if has_allow_dead_code_or_lang_attr(
-                                self.tcx,
-                                trait_item.hir_id,
-                                &trait_item.attrs,
-                            ) {
-                                self.worklist.push(trait_item.hir_id);
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-            }
             hir::ItemKind::Impl { ref of_trait, items, .. } => {
                 if of_trait.is_some() {
                     self.worklist.push(item.hir_id);
@@ -440,15 +422,27 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
         }
     }
 
-    fn visit_trait_item(&mut self, _item: &hir::TraitItem<'_>) {
-        // ignore: we are handling this in `visit_item` above
+    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
+        use hir::TraitItemKind::{Const, Fn};
+        if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
+            && has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id, &trait_item.attrs)
+        {
+            self.worklist.push(trait_item.hir_id);
+        }
     }
 
     fn visit_impl_item(&mut self, _item: &hir::ImplItem<'_>) {
         // ignore: we are handling this in `visit_item` above
     }
 
-    fn visit_foreign_item(&mut self, _item: &'v hir::ForeignItem<'v>) {}
+    fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
+        use hir::ForeignItemKind::{Fn, Static};
+        if matches!(foreign_item.kind, Static(..) | Fn(..))
+            && has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id, &foreign_item.attrs)
+        {
+            self.worklist.push(foreign_item.hir_id);
+        }
+    }
 }
 
 fn create_and_seed_worklist<'tcx>(
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index 956be925be8..711e8e87c6c 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -347,7 +347,7 @@ impl ExprVisitor<'tcx> {
     }
 
     fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
-        for (idx, op) in asm.operands.iter().enumerate() {
+        for (idx, (op, _op_sp)) in asm.operands.iter().enumerate() {
             match *op {
                 hir::InlineAsmOperand::In { reg, ref expr } => {
                     self.check_asm_operand_type(idx, reg, expr, asm.template, None);
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index debb873beb9..a161ad16b8c 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -105,6 +105,8 @@ use std::io;
 use std::io::prelude::*;
 use std::rc::Rc;
 
+mod rwu_table;
+
 rustc_index::newtype_index! {
     pub struct Variable {
         DEBUG_FORMAT = "v({})",
@@ -468,101 +470,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
 // Actually we compute just a bit more than just liveness, but we use
 // the same basic propagation framework in all cases.
 
-#[derive(Clone, Copy)]
-struct RWU {
-    reader: Option<LiveNode>,
-    writer: Option<LiveNode>,
-    used: bool,
-}
-
-/// Conceptually, this is like a `Vec<RWU>`. But the number of `RWU`s can get
-/// very large, so it uses a more compact representation that takes advantage
-/// of the fact that when the number of `RWU`s is large, most of them have an
-/// invalid reader and an invalid writer.
-struct RWUTable {
-    /// Each entry in `packed_rwus` is either INV_INV_FALSE, INV_INV_TRUE, or
-    /// an index into `unpacked_rwus`. In the common cases, this compacts the
-    /// 65 bits of data into 32; in the uncommon cases, it expands the 65 bits
-    /// in 96.
-    ///
-    /// More compact representations are possible -- e.g., use only 2 bits per
-    /// packed `RWU` and make the secondary table a HashMap that maps from
-    /// indices to `RWU`s -- but this one strikes a good balance between size
-    /// and speed.
-    packed_rwus: Vec<u32>,
-    unpacked_rwus: Vec<RWU>,
-}
-
-// A constant representing `RWU { reader: None; writer: None; used: false }`.
-const INV_INV_FALSE: u32 = u32::MAX;
-
-// A constant representing `RWU { reader: None; writer: None; used: true }`.
-const INV_INV_TRUE: u32 = u32::MAX - 1;
-
-impl RWUTable {
-    fn new(num_rwus: usize) -> RWUTable {
-        Self { packed_rwus: vec![INV_INV_FALSE; num_rwus], unpacked_rwus: vec![] }
-    }
-
-    fn get(&self, idx: usize) -> RWU {
-        let packed_rwu = self.packed_rwus[idx];
-        match packed_rwu {
-            INV_INV_FALSE => RWU { reader: None, writer: None, used: false },
-            INV_INV_TRUE => RWU { reader: None, writer: None, used: true },
-            _ => self.unpacked_rwus[packed_rwu as usize],
-        }
-    }
-
-    fn get_reader(&self, idx: usize) -> Option<LiveNode> {
-        let packed_rwu = self.packed_rwus[idx];
-        match packed_rwu {
-            INV_INV_FALSE | INV_INV_TRUE => None,
-            _ => self.unpacked_rwus[packed_rwu as usize].reader,
-        }
-    }
-
-    fn get_writer(&self, idx: usize) -> Option<LiveNode> {
-        let packed_rwu = self.packed_rwus[idx];
-        match packed_rwu {
-            INV_INV_FALSE | INV_INV_TRUE => None,
-            _ => self.unpacked_rwus[packed_rwu as usize].writer,
-        }
-    }
-
-    fn get_used(&self, idx: usize) -> bool {
-        let packed_rwu = self.packed_rwus[idx];
-        match packed_rwu {
-            INV_INV_FALSE => false,
-            INV_INV_TRUE => true,
-            _ => self.unpacked_rwus[packed_rwu as usize].used,
-        }
-    }
-
-    #[inline]
-    fn copy_packed(&mut self, dst_idx: usize, src_idx: usize) {
-        self.packed_rwus[dst_idx] = self.packed_rwus[src_idx];
-    }
-
-    fn assign_unpacked(&mut self, idx: usize, rwu: RWU) {
-        if rwu.reader == None && rwu.writer == None {
-            // When we overwrite an indexing entry in `self.packed_rwus` with
-            // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry
-            // from `self.unpacked_rwus`; it's not worth the effort, and we
-            // can't have entries shifting around anyway.
-            self.packed_rwus[idx] = if rwu.used { INV_INV_TRUE } else { INV_INV_FALSE }
-        } else {
-            // Add a new RWU to `unpacked_rwus` and make `packed_rwus[idx]`
-            // point to it.
-            self.packed_rwus[idx] = self.unpacked_rwus.len() as u32;
-            self.unpacked_rwus.push(rwu);
-        }
-    }
-
-    fn assign_inv_inv(&mut self, idx: usize) {
-        self.packed_rwus[idx] = if self.get_used(idx) { INV_INV_TRUE } else { INV_INV_FALSE };
-    }
-}
-
 const ACC_READ: u32 = 1;
 const ACC_WRITE: u32 = 2;
 const ACC_USE: u32 = 4;
@@ -575,7 +482,7 @@ struct Liveness<'a, 'tcx> {
     upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
     closure_captures: Option<&'tcx FxIndexMap<hir::HirId, ty::UpvarId>>,
     successors: IndexVec<LiveNode, Option<LiveNode>>,
-    rwu_table: RWUTable,
+    rwu_table: rwu_table::RWUTable,
 
     /// A live node representing a point of execution before closure entry &
     /// after closure exit. Used to calculate liveness of captured variables
@@ -613,7 +520,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             upvars,
             closure_captures,
             successors: IndexVec::from_elem_n(None, num_live_nodes),
-            rwu_table: RWUTable::new(num_live_nodes * num_vars),
+            rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars),
             closure_ln,
             exit_ln,
             break_ln: Default::default(),
@@ -652,61 +559,37 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         succ
     }
 
-    fn idx(&self, ln: LiveNode, var: Variable) -> usize {
-        ln.index() * self.ir.var_kinds.len() + var.index()
-    }
-
-    fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
-        if let Some(reader) = self.rwu_table.get_reader(self.idx(ln, var)) {
-            Some(self.ir.lnks[reader])
-        } else {
-            None
-        }
+    fn live_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
+        self.rwu_table.get_reader(ln, var)
     }
 
     // Is this variable live on entry to any of its successor nodes?
-    fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
+    fn live_on_exit(&self, ln: LiveNode, var: Variable) -> bool {
         let successor = self.successors[ln].unwrap();
         self.live_on_entry(successor, var)
     }
 
     fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
-        self.rwu_table.get_used(self.idx(ln, var))
+        self.rwu_table.get_used(ln, var)
     }
 
-    fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
-        if let Some(writer) = self.rwu_table.get_writer(self.idx(ln, var)) {
-            Some(self.ir.lnks[writer])
-        } else {
-            None
-        }
+    fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
+        self.rwu_table.get_writer(ln, var)
     }
 
-    fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
+    fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> bool {
         let successor = self.successors[ln].unwrap();
         self.assigned_on_entry(successor, var)
     }
 
-    fn indices2<F>(&mut self, ln: LiveNode, succ_ln: LiveNode, mut op: F)
-    where
-        F: FnMut(&mut Liveness<'a, 'tcx>, usize, usize),
-    {
-        let node_base_idx = self.idx(ln, Variable::from(0u32));
-        let succ_base_idx = self.idx(succ_ln, Variable::from(0u32));
-        for var_idx in 0..self.ir.var_kinds.len() {
-            op(self, node_base_idx + var_idx, succ_base_idx + var_idx);
-        }
-    }
-
-    fn write_vars<F>(&self, wr: &mut dyn Write, ln: LiveNode, mut test: F) -> io::Result<()>
+    fn write_vars<F>(&self, wr: &mut dyn Write, mut test: F) -> io::Result<()>
     where
-        F: FnMut(usize) -> bool,
+        F: FnMut(Variable) -> bool,
     {
-        let node_base_idx = self.idx(ln, Variable::from(0u32));
         for var_idx in 0..self.ir.var_kinds.len() {
-            let idx = node_base_idx + var_idx;
-            if test(idx) {
-                write!(wr, " {:?}", Variable::from(var_idx))?;
+            let var = Variable::from(var_idx);
+            if test(var) {
+                write!(wr, " {:?}", var)?;
             }
         }
         Ok(())
@@ -718,11 +601,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         {
             let wr = &mut wr as &mut dyn Write;
             write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]);
-            self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_some());
+            self.write_vars(wr, |var| self.rwu_table.get_reader(ln, var));
             write!(wr, "  writes");
-            self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_some());
+            self.write_vars(wr, |var| self.rwu_table.get_writer(ln, var));
             write!(wr, "  uses");
-            self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx));
+            self.write_vars(wr, |var| self.rwu_table.get_used(ln, var));
 
             write!(wr, "  precedes {:?}]", self.successors[ln]);
         }
@@ -747,100 +630,57 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         self.successors[ln] = Some(succ_ln);
 
         // It is not necessary to initialize the RWUs here because they are all
-        // set to INV_INV_FALSE when they are created, and the sets only grow
-        // during iterations.
+        // empty when created, and the sets only grow during iterations.
     }
 
     fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) {
         // more efficient version of init_empty() / merge_from_succ()
         self.successors[ln] = Some(succ_ln);
-
-        self.indices2(ln, succ_ln, |this, idx, succ_idx| {
-            this.rwu_table.copy_packed(idx, succ_idx);
-        });
+        self.rwu_table.copy(ln, succ_ln);
         debug!("init_from_succ(ln={}, succ={})", self.ln_str(ln), self.ln_str(succ_ln));
     }
 
-    fn merge_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode, first_merge: bool) -> bool {
+    fn merge_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) -> bool {
         if ln == succ_ln {
             return false;
         }
 
-        let mut any_changed = false;
-        self.indices2(ln, succ_ln, |this, idx, succ_idx| {
-            // This is a special case, pulled out from the code below, where we
-            // don't have to do anything. It occurs about 60-70% of the time.
-            if this.rwu_table.packed_rwus[succ_idx] == INV_INV_FALSE {
-                return;
-            }
-
-            let mut changed = false;
-            let mut rwu = this.rwu_table.get(idx);
-            let succ_rwu = this.rwu_table.get(succ_idx);
-            if succ_rwu.reader.is_some() && rwu.reader.is_none() {
-                rwu.reader = succ_rwu.reader;
-                changed = true
-            }
-
-            if succ_rwu.writer.is_some() && rwu.writer.is_none() {
-                rwu.writer = succ_rwu.writer;
-                changed = true
-            }
-
-            if succ_rwu.used && !rwu.used {
-                rwu.used = true;
-                changed = true;
-            }
-
-            if changed {
-                this.rwu_table.assign_unpacked(idx, rwu);
-                any_changed = true;
-            }
-        });
-
-        debug!(
-            "merge_from_succ(ln={:?}, succ={}, first_merge={}, changed={})",
-            ln,
-            self.ln_str(succ_ln),
-            first_merge,
-            any_changed
-        );
-        any_changed
+        let changed = self.rwu_table.union(ln, succ_ln);
+        debug!("merge_from_succ(ln={:?}, succ={}, changed={})", ln, self.ln_str(succ_ln), changed);
+        changed
     }
 
     // Indicates that a local variable was *defined*; we know that no
     // uses of the variable can precede the definition (resolve checks
     // this) so we just clear out all the data.
     fn define(&mut self, writer: LiveNode, var: Variable) {
-        let idx = self.idx(writer, var);
-        self.rwu_table.assign_inv_inv(idx);
-
-        debug!("{:?} defines {:?} (idx={}): {}", writer, var, idx, self.ln_str(writer));
+        let used = self.rwu_table.get_used(writer, var);
+        self.rwu_table.set(writer, var, rwu_table::RWU { reader: false, writer: false, used });
+        debug!("{:?} defines {:?}: {}", writer, var, self.ln_str(writer));
     }
 
     // Either read, write, or both depending on the acc bitset
     fn acc(&mut self, ln: LiveNode, var: Variable, acc: u32) {
         debug!("{:?} accesses[{:x}] {:?}: {}", ln, acc, var, self.ln_str(ln));
 
-        let idx = self.idx(ln, var);
-        let mut rwu = self.rwu_table.get(idx);
+        let mut rwu = self.rwu_table.get(ln, var);
 
         if (acc & ACC_WRITE) != 0 {
-            rwu.reader = None;
-            rwu.writer = Some(ln);
+            rwu.reader = false;
+            rwu.writer = true;
         }
 
         // Important: if we both read/write, must do read second
         // or else the write will override.
         if (acc & ACC_READ) != 0 {
-            rwu.reader = Some(ln);
+            rwu.reader = true;
         }
 
         if (acc & ACC_USE) != 0 {
             rwu.used = true;
         }
 
-        self.rwu_table.assign_unpacked(idx, rwu);
+        self.rwu_table.set(ln, var, rwu);
     }
 
     fn compute(&mut self, body: &hir::Body<'_>, hir_id: HirId) -> LiveNode {
@@ -906,7 +746,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         };
 
         // Propagate through calls to the closure.
-        let mut first_merge = true;
         loop {
             self.init_from_succ(self.closure_ln, succ);
             for param in body.params {
@@ -916,10 +755,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 })
             }
 
-            if !self.merge_from_succ(self.exit_ln, self.closure_ln, first_merge) {
+            if !self.merge_from_succ(self.exit_ln, self.closure_ln) {
                 break;
             }
-            first_merge = false;
             assert_eq!(succ, self.propagate_through_expr(&body.value, self.exit_ln));
         }
 
@@ -1025,7 +863,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 //
                 let ln = self.live_node(expr.hir_id, expr.span);
                 self.init_empty(ln, succ);
-                let mut first_merge = true;
                 for arm in arms {
                     let body_succ = self.propagate_through_expr(&arm.body, succ);
 
@@ -1034,8 +871,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                         body_succ,
                     );
                     let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ);
-                    self.merge_from_succ(ln, arm_succ, first_merge);
-                    first_merge = false;
+                    self.merge_from_succ(ln, arm_succ);
                 }
                 self.propagate_through_expr(&e, ln)
             }
@@ -1146,7 +982,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
                 let ln = self.live_node(expr.hir_id, expr.span);
                 self.init_from_succ(ln, succ);
-                self.merge_from_succ(ln, r_succ, false);
+                self.merge_from_succ(ln, r_succ);
 
                 self.propagate_through_expr(&l, ln)
             }
@@ -1174,7 +1010,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 };
 
                 // Do a first pass for writing outputs only
-                for op in asm.operands.iter().rev() {
+                for (op, _op_sp) in asm.operands.iter().rev() {
                     match op {
                         hir::InlineAsmOperand::In { .. }
                         | hir::InlineAsmOperand::Const { .. }
@@ -1197,7 +1033,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
                 // Then do a second pass for inputs
                 let mut succ = succ;
-                for op in asm.operands.iter().rev() {
+                for (op, _op_sp) in asm.operands.iter().rev() {
                     match op {
                         hir::InlineAsmOperand::In { expr, .. }
                         | hir::InlineAsmOperand::Const { expr, .. }
@@ -1390,7 +1226,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         */
 
         // first iteration:
-        let mut first_merge = true;
         let ln = self.live_node(expr.hir_id, expr.span);
         self.init_empty(ln, succ);
         debug!("propagate_through_loop: using id for loop body {} {:?}", expr.hir_id, body);
@@ -1402,8 +1237,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         let body_ln = self.propagate_through_block(body, ln);
 
         // repeat until fixed point is reached:
-        while self.merge_from_succ(ln, body_ln, first_merge) {
-            first_merge = false;
+        while self.merge_from_succ(ln, body_ln) {
             assert_eq!(body_ln, self.propagate_through_block(body, ln));
         }
 
@@ -1454,7 +1288,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
         }
 
         hir::ExprKind::InlineAsm(ref asm) => {
-            for op in asm.operands {
+            for (op, _op_sp) in asm.operands {
                 match op {
                     hir::InlineAsmOperand::Out { expr, .. } => {
                         if let Some(expr) = expr {
@@ -1575,7 +1409,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
                 ty::UpvarCapture::ByRef(..) => continue,
             };
             if self.used_on_entry(entry_ln, var) {
-                if self.live_on_entry(entry_ln, var).is_none() {
+                if !self.live_on_entry(entry_ln, var) {
                     if let Some(name) = self.should_warn(var) {
                         self.ir.tcx.struct_span_lint_hir(
                             lint::builtin::UNUSED_ASSIGNMENTS,
@@ -1609,7 +1443,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
     fn warn_about_unused_args(&self, body: &hir::Body<'_>, entry_ln: LiveNode) {
         for p in body.params {
             self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| {
-                if self.live_on_entry(ln, var).is_none() {
+                if !self.live_on_entry(ln, var) {
                     self.report_unsed_assign(hir_id, spans, var, |name| {
                         format!("value passed to `{}` is never read", name)
                     });
@@ -1658,7 +1492,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
             // {ret}`, there is only one node, so asking about
             // assigned_on_exit() is not meaningful.
             let is_assigned =
-                if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() };
+                if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) };
 
             if is_assigned {
                 self.ir.tcx.struct_span_lint_hir(
@@ -1725,7 +1559,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
     }
 
     fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
-        if self.live_on_exit(ln, var).is_none() {
+        if !self.live_on_exit(ln, var) {
             self.report_unsed_assign(hir_id, spans, var, |name| {
                 format!("value assigned to `{}` is never read", name)
             });
diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs
new file mode 100644
index 00000000000..a1a6f27398e
--- /dev/null
+++ b/compiler/rustc_passes/src/liveness/rwu_table.rs
@@ -0,0 +1,144 @@
+use crate::liveness::{LiveNode, Variable};
+
+#[derive(Clone, Copy)]
+pub(super) struct RWU {
+    pub(super) reader: bool,
+    pub(super) writer: bool,
+    pub(super) used: bool,
+}
+
+/// Conceptually, this is like a `Vec<Vec<RWU>>`. But the number of
+/// RWU`s can get very large, so it uses a more compact representation.
+pub(super) struct RWUTable {
+    /// Total number of live nodes.
+    live_nodes: usize,
+    /// Total number of variables.
+    vars: usize,
+
+    /// A compressed representation of `RWU`s.
+    ///
+    /// Each word represents 2 different `RWU`s packed together. Each packed RWU
+    /// is stored in 4 bits: a reader bit, a writer bit, a used bit and a
+    /// padding bit.
+    ///
+    /// The data for each live node is contiguous and starts at a word boundary,
+    /// so there might be an unused space left.
+    words: Vec<u8>,
+    /// Number of words per each live node.
+    live_node_words: usize,
+}
+
+impl RWUTable {
+    const RWU_READER: u8 = 0b0001;
+    const RWU_WRITER: u8 = 0b0010;
+    const RWU_USED: u8 = 0b0100;
+    const RWU_MASK: u8 = 0b1111;
+
+    /// Size of packed RWU in bits.
+    const RWU_BITS: usize = 4;
+    /// Size of a word in bits.
+    const WORD_BITS: usize = std::mem::size_of::<u8>() * 8;
+    /// Number of packed RWUs that fit into a single word.
+    const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS;
+
+    pub(super) fn new(live_nodes: usize, vars: usize) -> RWUTable {
+        let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT;
+        Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] }
+    }
+
+    fn word_and_shift(&self, ln: LiveNode, var: Variable) -> (usize, u32) {
+        assert!(ln.index() < self.live_nodes);
+        assert!(var.index() < self.vars);
+
+        let var = var.index();
+        let word = var / Self::WORD_RWU_COUNT;
+        let shift = Self::RWU_BITS * (var % Self::WORD_RWU_COUNT);
+        (ln.index() * self.live_node_words + word, shift as u32)
+    }
+
+    fn pick2_rows_mut(&mut self, a: LiveNode, b: LiveNode) -> (&mut [u8], &mut [u8]) {
+        assert!(a.index() < self.live_nodes);
+        assert!(b.index() < self.live_nodes);
+        assert!(a != b);
+
+        let a_start = a.index() * self.live_node_words;
+        let b_start = b.index() * self.live_node_words;
+
+        unsafe {
+            let ptr = self.words.as_mut_ptr();
+            (
+                std::slice::from_raw_parts_mut(ptr.add(a_start), self.live_node_words),
+                std::slice::from_raw_parts_mut(ptr.add(b_start), self.live_node_words),
+            )
+        }
+    }
+
+    pub(super) fn copy(&mut self, dst: LiveNode, src: LiveNode) {
+        if dst == src {
+            return;
+        }
+
+        let (dst_row, src_row) = self.pick2_rows_mut(dst, src);
+        dst_row.copy_from_slice(src_row);
+    }
+
+    /// Sets `dst` to the union of `dst` and `src`, returns true if `dst` was
+    /// changed.
+    pub(super) fn union(&mut self, dst: LiveNode, src: LiveNode) -> bool {
+        if dst == src {
+            return false;
+        }
+
+        let mut changed = false;
+        let (dst_row, src_row) = self.pick2_rows_mut(dst, src);
+        for (dst_word, src_word) in dst_row.iter_mut().zip(src_row.iter()) {
+            let old = *dst_word;
+            let new = *dst_word | src_word;
+            *dst_word = new;
+            changed |= old != new;
+        }
+        changed
+    }
+
+    pub(super) fn get_reader(&self, ln: LiveNode, var: Variable) -> bool {
+        let (word, shift) = self.word_and_shift(ln, var);
+        (self.words[word] >> shift) & Self::RWU_READER != 0
+    }
+
+    pub(super) fn get_writer(&self, ln: LiveNode, var: Variable) -> bool {
+        let (word, shift) = self.word_and_shift(ln, var);
+        (self.words[word] >> shift) & Self::RWU_WRITER != 0
+    }
+
+    pub(super) fn get_used(&self, ln: LiveNode, var: Variable) -> bool {
+        let (word, shift) = self.word_and_shift(ln, var);
+        (self.words[word] >> shift) & Self::RWU_USED != 0
+    }
+
+    pub(super) fn get(&self, ln: LiveNode, var: Variable) -> RWU {
+        let (word, shift) = self.word_and_shift(ln, var);
+        let rwu_packed = self.words[word] >> shift;
+        RWU {
+            reader: rwu_packed & Self::RWU_READER != 0,
+            writer: rwu_packed & Self::RWU_WRITER != 0,
+            used: rwu_packed & Self::RWU_USED != 0,
+        }
+    }
+
+    pub(super) fn set(&mut self, ln: LiveNode, var: Variable, rwu: RWU) {
+        let mut packed = 0;
+        if rwu.reader {
+            packed |= Self::RWU_READER;
+        }
+        if rwu.writer {
+            packed |= Self::RWU_WRITER;
+        }
+        if rwu.used {
+            packed |= Self::RWU_USED;
+        }
+
+        let (word, shift) = self.word_and_shift(ln, var);
+        let word = &mut self.words[word];
+        *word = (*word & !(Self::RWU_MASK << shift)) | (packed << shift)
+    }
+}
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 6ef45cdd391..5b50ef8627b 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,10 +1,16 @@
+//! Checks validity of naked functions.
+
+use rustc_ast::InlineAsmOptions;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
 
 fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(
@@ -33,27 +39,52 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
         fk: FnKind<'v>,
         _fd: &'tcx hir::FnDecl<'tcx>,
         body_id: hir::BodyId,
-        _span: Span,
-        _hir_id: hir::HirId,
+        span: Span,
+        hir_id: HirId,
     ) {
+        let ident_span;
+        let fn_header;
+
         match fk {
-            // Rejected during attribute check. Do not validate further.
-            FnKind::Closure(..) => return,
-            FnKind::ItemFn(..) | FnKind::Method(..) => {}
+            FnKind::Closure(..) => {
+                // Closures with a naked attribute are rejected during attribute
+                // check. Don't validate them any further.
+                return;
+            }
+            FnKind::ItemFn(ident, _, ref header, ..) => {
+                ident_span = ident.span;
+                fn_header = header;
+            }
+
+            FnKind::Method(ident, ref sig, ..) => {
+                ident_span = ident.span;
+                fn_header = &sig.header;
+            }
         }
 
         let naked = fk.attrs().iter().any(|attr| attr.has_name(sym::naked));
         if naked {
             let body = self.tcx.hir().body(body_id);
-            check_params(self.tcx, body);
-            check_body(self.tcx, body);
+            check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
+            check_no_patterns(self.tcx, body.params);
+            check_no_parameters_use(self.tcx, body);
+            check_asm(self.tcx, hir_id, body, span);
         }
     }
 }
 
+/// Checks that function uses non-Rust ABI.
+fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
+    if abi == Abi::Rust {
+        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_ident_span, |lint| {
+            lint.build("Rust ABI is unsupported in naked functions").emit();
+        });
+    }
+}
+
 /// Checks that parameters don't use patterns. Mirrors the checks for function declarations.
-fn check_params(tcx: TyCtxt<'_>, body: &hir::Body<'_>) {
-    for param in body.params {
+fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
+    for param in params {
         match param.pat.kind {
             hir::PatKind::Wild
             | hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, None) => {}
@@ -69,23 +100,23 @@ fn check_params(tcx: TyCtxt<'_>, body: &hir::Body<'_>) {
     }
 }
 
-/// Checks that function parameters aren't referenced in the function body.
-fn check_body<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) {
+/// Checks that function parameters aren't used in the function body.
+fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) {
     let mut params = hir::HirIdSet::default();
     for param in body.params {
         param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| {
             params.insert(hir_id);
         });
     }
-    CheckBody { tcx, params }.visit_body(body);
+    CheckParameters { tcx, params }.visit_body(body);
 }
 
-struct CheckBody<'tcx> {
+struct CheckParameters<'tcx> {
     tcx: TyCtxt<'tcx>,
     params: hir::HirIdSet,
 }
 
-impl<'tcx> Visitor<'tcx> for CheckBody<'tcx> {
+impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
     type Map = ErasedMap<'tcx>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -103,11 +134,189 @@ impl<'tcx> Visitor<'tcx> for CheckBody<'tcx> {
                     .sess
                     .struct_span_err(
                         expr.span,
-                        "use of parameters not allowed inside naked functions",
+                        "referencing function parameters is not allowed in naked functions",
                     )
+                    .help("follow the calling convention in asm block to use parameters")
                     .emit();
+                return;
             }
         }
         hir::intravisit::walk_expr(self, expr);
     }
 }
+
+/// Checks that function body contains a single inline assembly block.
+fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
+    let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
+    this.visit_body(body);
+    if let &[(ItemKind::Asm, _)] = &this.items[..] {
+        // Ok.
+    } else {
+        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| {
+            let mut diag = lint.build("naked functions must contain a single asm block");
+            let mut has_asm = false;
+            for &(kind, span) in &this.items {
+                match kind {
+                    ItemKind::Asm if has_asm => {
+                        diag.span_label(
+                            span,
+                            "multiple asm blocks are unsupported in naked functions",
+                        );
+                    }
+                    ItemKind::Asm => has_asm = true,
+                    ItemKind::NonAsm => {
+                        diag.span_label(span, "non-asm is unsupported in naked functions");
+                    }
+                }
+            }
+            diag.emit();
+        });
+    }
+}
+
+struct CheckInlineAssembly<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    items: Vec<(ItemKind, Span)>,
+}
+
+#[derive(Copy, Clone)]
+enum ItemKind {
+    Asm,
+    NonAsm,
+}
+
+impl<'tcx> CheckInlineAssembly<'tcx> {
+    fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
+        match expr.kind {
+            ExprKind::Box(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::Array(..)
+            | ExprKind::Call(..)
+            | ExprKind::MethodCall(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Binary(..)
+            | ExprKind::Unary(..)
+            | ExprKind::Lit(..)
+            | ExprKind::Cast(..)
+            | ExprKind::Type(..)
+            | ExprKind::Loop(..)
+            | ExprKind::Match(..)
+            | ExprKind::Closure(..)
+            | ExprKind::Assign(..)
+            | ExprKind::AssignOp(..)
+            | ExprKind::Field(..)
+            | ExprKind::Index(..)
+            | ExprKind::Path(..)
+            | ExprKind::AddrOf(..)
+            | ExprKind::Break(..)
+            | ExprKind::Continue(..)
+            | ExprKind::Ret(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Repeat(..)
+            | ExprKind::Yield(..) => {
+                self.items.push((ItemKind::NonAsm, span));
+            }
+
+            ExprKind::InlineAsm(ref asm) => {
+                self.items.push((ItemKind::Asm, span));
+                self.check_inline_asm(expr.hir_id, asm, span);
+            }
+
+            ExprKind::LlvmInlineAsm(..) => {
+                self.items.push((ItemKind::Asm, span));
+                self.tcx.struct_span_lint_hir(
+                    UNSUPPORTED_NAKED_FUNCTIONS,
+                    expr.hir_id,
+                    span,
+                    |lint| {
+                        lint.build(
+                            "the LLVM-style inline assembly is unsupported in naked functions",
+                        )
+                        .help("use the new asm! syntax specified in RFC 2873")
+                        .emit();
+                    },
+                );
+            }
+
+            ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
+                hir::intravisit::walk_expr(self, expr);
+            }
+        }
+    }
+
+    fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
+        let unsupported_operands: Vec<Span> = asm
+            .operands
+            .iter()
+            .filter_map(|&(ref op, op_sp)| match op {
+                InlineAsmOperand::Const { .. } | InlineAsmOperand::Sym { .. } => None,
+                InlineAsmOperand::In { .. }
+                | InlineAsmOperand::Out { .. }
+                | InlineAsmOperand::InOut { .. }
+                | InlineAsmOperand::SplitInOut { .. } => Some(op_sp),
+            })
+            .collect();
+        if !unsupported_operands.is_empty() {
+            self.tcx.struct_span_lint_hir(
+                UNSUPPORTED_NAKED_FUNCTIONS,
+                hir_id,
+                unsupported_operands,
+                |lint| {
+                    lint.build("only `const` and `sym` operands are supported in naked functions")
+                        .emit();
+                },
+            );
+        }
+
+        let unsupported_options: Vec<&'static str> = [
+            (InlineAsmOptions::NOMEM, "`nomem`"),
+            (InlineAsmOptions::NOSTACK, "`nostack`"),
+            (InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"),
+            (InlineAsmOptions::PURE, "`pure`"),
+            (InlineAsmOptions::READONLY, "`readonly`"),
+        ]
+        .iter()
+        .filter_map(|&(option, name)| if asm.options.contains(option) { Some(name) } else { None })
+        .collect();
+
+        if !unsupported_options.is_empty() {
+            self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
+                lint.build(&format!(
+                    "asm options unsupported in naked functions: {}",
+                    unsupported_options.join(", ")
+                ))
+                .emit();
+            });
+        }
+
+        if !asm.options.contains(InlineAsmOptions::NORETURN) {
+            self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
+                lint.build("asm in naked functions must use `noreturn` option").emit();
+            });
+        }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> {
+    type Map = ErasedMap<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
+        match stmt.kind {
+            StmtKind::Item(..) => {}
+            StmtKind::Local(..) => {
+                self.items.push((ItemKind::NonAsm, stmt.span));
+            }
+            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
+                self.check_expr(expr, stmt.span);
+            }
+        }
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+        self.check_expr(&expr, expr.span);
+    }
+}
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index 3d9e739cd28..09e5dc857a7 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -53,6 +53,19 @@ use std::hash::Hash;
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub struct DepNode<K> {
     pub kind: K,
+    // Important - whenever a `DepNode` is constructed, we need to make
+    // sure to register a `DefPathHash -> DefId` mapping if needed.
+    // This is currently done in two places:
+    //
+    // * When a `DepNode::construct` is called, `arg.to_fingerprint()`
+    //   is responsible for calling `OnDiskCache::store_foreign_def_id_hash`
+    //   if needed
+    // * When a `DepNode` is loaded from the `PreviousDepGraph`,
+    //   then `PreviousDepGraph::index_to_node` is responsible for calling
+    //   `tcx.register_reused_dep_path_hash`
+    //
+    // FIXME: Enforce this by preventing manual construction of `DefNode`
+    // (e.g. add a `_priv: ()` field)
     pub hash: PackedFingerprint,
 }
 
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index ac37b296b53..956d476d973 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -7,7 +7,6 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
 use rustc_data_structures::unlikely;
 use rustc_errors::Diagnostic;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_span::def_id::DefPathHash;
 
 use parking_lot::{Condvar, Mutex};
 use smallvec::{smallvec, SmallVec};
@@ -555,7 +554,7 @@ impl<K: DepKind> DepGraph<K> {
         // We never try to mark eval_always nodes as green
         debug_assert!(!dep_node.kind.is_eval_always());
 
-        debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
+        data.previous.debug_assert_eq(prev_dep_node_index, *dep_node);
 
         let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
 
@@ -573,7 +572,7 @@ impl<K: DepKind> DepGraph<K> {
                         "try_mark_previous_green({:?}) --- found dependency {:?} to \
                             be immediately green",
                         dep_node,
-                        data.previous.index_to_node(dep_dep_node_index)
+                        data.previous.debug_dep_node(dep_dep_node_index),
                     );
                     current_deps.push(node_index);
                 }
@@ -586,20 +585,20 @@ impl<K: DepKind> DepGraph<K> {
                         "try_mark_previous_green({:?}) - END - dependency {:?} was \
                             immediately red",
                         dep_node,
-                        data.previous.index_to_node(dep_dep_node_index)
+                        data.previous.debug_dep_node(dep_dep_node_index)
                     );
                     return None;
                 }
                 None => {
-                    let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
+                    let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index, tcx);
 
                     // We don't know the state of this dependency. If it isn't
                     // an eval_always node, let's try to mark it green recursively.
                     if !dep_dep_node.kind.is_eval_always() {
                         debug!(
-                            "try_mark_previous_green({:?}) --- state of dependency {:?} \
+                            "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
                                  is unknown, trying to mark it green",
-                            dep_node, dep_dep_node
+                            dep_node, dep_dep_node, dep_dep_node.hash,
                         );
 
                         let node_index = self.try_mark_previous_green(
@@ -700,18 +699,6 @@ impl<K: DepKind> DepGraph<K> {
             data.current.intern_node(*dep_node, current_deps, fingerprint)
         };
 
-        // We have just loaded a deserialized `DepNode` from the previous
-        // compilation session into the current one. If this was a foreign `DefId`,
-        // then we stored additional information in the incr comp cache when we
-        // initially created its fingerprint (see `DepNodeParams::to_fingerprint`)
-        // We won't be calling `to_fingerprint` again for this `DepNode` (we no longer
-        // have the original value), so we need to copy over this additional information
-        // from the old incremental cache into the new cache that we serialize
-        // and the end of this compilation session.
-        if dep_node.kind.can_reconstruct_query_key() {
-            tcx.register_reused_dep_path_hash(DefPathHash(dep_node.hash.into()));
-        }
-
         // ... emitting any stored diagnostic ...
 
         // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere
@@ -814,7 +801,7 @@ impl<K: DepKind> DepGraph<K> {
         for prev_index in data.colors.values.indices() {
             match data.colors.get(prev_index) {
                 Some(DepNodeColor::Green(_)) => {
-                    let dep_node = data.previous.index_to_node(prev_index);
+                    let dep_node = data.previous.index_to_node(prev_index, tcx);
                     tcx.try_load_from_on_disk_cache(&dep_node);
                 }
                 None | Some(DepNodeColor::Red) => {
diff --git a/compiler/rustc_query_system/src/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs
index 29357ce9449..9298b652da2 100644
--- a/compiler/rustc_query_system/src/dep_graph/prev.rs
+++ b/compiler/rustc_query_system/src/dep_graph/prev.rs
@@ -1,7 +1,9 @@
 use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 use super::{DepKind, DepNode};
+use crate::dep_graph::DepContext;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_span::def_id::DefPathHash;
 
 #[derive(Debug, Encodable, Decodable)]
 pub struct PreviousDepGraph<K: DepKind> {
@@ -31,7 +33,44 @@ impl<K: DepKind> PreviousDepGraph<K> {
     }
 
     #[inline]
-    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
+    pub fn index_to_node<CTX: DepContext<DepKind = K>>(
+        &self,
+        dep_node_index: SerializedDepNodeIndex,
+        tcx: CTX,
+    ) -> DepNode<K> {
+        let dep_node = self.data.nodes[dep_node_index];
+        // We have just loaded a deserialized `DepNode` from the previous
+        // compilation session into the current one. If this was a foreign `DefId`,
+        // then we stored additional information in the incr comp cache when we
+        // initially created its fingerprint (see `DepNodeParams::to_fingerprint`)
+        // We won't be calling `to_fingerprint` again for this `DepNode` (we no longer
+        // have the original value), so we need to copy over this additional information
+        // from the old incremental cache into the new cache that we serialize
+        // and the end of this compilation session.
+        if dep_node.kind.can_reconstruct_query_key() {
+            tcx.register_reused_dep_path_hash(DefPathHash(dep_node.hash.into()));
+        }
+        dep_node
+    }
+
+    /// When debug assertions are enabled, asserts that the dep node at `dep_node_index` is equal to `dep_node`.
+    /// This method should be preferred over manually calling `index_to_node`.
+    /// Calls to `index_to_node` may affect global state, so gating a call
+    /// to `index_to_node` on debug assertions could cause behavior changes when debug assertions
+    /// are enabled.
+    #[inline]
+    pub fn debug_assert_eq(&self, dep_node_index: SerializedDepNodeIndex, dep_node: DepNode<K>) {
+        debug_assert_eq!(self.data.nodes[dep_node_index], dep_node);
+    }
+
+    /// Obtains a debug-printable version of the `DepNode`.
+    /// See `debug_assert_eq` for why this should be preferred over manually
+    /// calling `dep_node_index`
+    pub fn debug_dep_node(&self, dep_node_index: SerializedDepNodeIndex) -> impl std::fmt::Debug {
+        // We're returning the `DepNode` without calling `register_reused_dep_path_hash`,
+        // but `impl Debug` return type means that it can only be used for debug printing.
+        // So, there's no risk of calls trying to create new dep nodes that have this
+        // node as a dependency
         self.data.nodes[dep_node_index]
     }
 
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 91edbebc05f..69f28045bb5 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -1098,7 +1098,7 @@ fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shado
         )
     };
     err.span_label(orig.span, "first declared here");
-    err.span_label(shadower.span, format!("lifetime {} already in scope", name));
+    err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name));
     err.emit();
 }
 
diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs
index 6c8965aa2e3..bbbe568f17a 100644
--- a/compiler/rustc_serialize/src/json.rs
+++ b/compiler/rustc_serialize/src/json.rs
@@ -1859,7 +1859,7 @@ impl<T: Iterator<Item = char>> Parser<T> {
                             }
 
                             let n2 = self.decode_hex_escape()?;
-                            if n2 < 0xDC00 || n2 > 0xDFFF {
+                            if !(0xDC00..=0xDFFF).contains(&n2) {
                                 return self.error(LoneLeadingSurrogateInHexEscape);
                             }
                             let c =
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index b648e14360c..54abb65dc38 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1296,8 +1296,10 @@ fn parse_output_types(
     if !debugging_opts.parse_only {
         for list in matches.opt_strs("emit") {
             for output_type in list.split(',') {
-                let mut parts = output_type.splitn(2, '=');
-                let shorthand = parts.next().unwrap();
+                let (shorthand, path) = match output_type.split_once('=') {
+                    None => (output_type, None),
+                    Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
+                };
                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
                     early_error(
                         error_format,
@@ -1308,7 +1310,6 @@ fn parse_output_types(
                         ),
                     )
                 });
-                let path = parts.next().map(PathBuf::from);
                 output_types.insert(output_type, path);
             }
         }
@@ -1452,11 +1453,10 @@ fn parse_opt_level(
     let max_c = matches
         .opt_strs_pos("C")
         .into_iter()
-        .flat_map(
-            |(i, s)| {
-                if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
-            },
-        )
+        .flat_map(|(i, s)| {
+            // NB: This can match a string without `=`.
+            if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
+        })
         .max();
     if max_o > max_c {
         OptLevel::Default
@@ -1491,11 +1491,10 @@ fn select_debuginfo(
     let max_c = matches
         .opt_strs_pos("C")
         .into_iter()
-        .flat_map(
-            |(i, s)| {
-                if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
-            },
-        )
+        .flat_map(|(i, s)| {
+            // NB: This can match a string without `=`.
+            if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
+        })
         .max();
     if max_g > max_c {
         DebugInfo::Full
@@ -1528,23 +1527,26 @@ fn parse_libs(
         .map(|s| {
             // Parse string of the form "[KIND=]lib[:new_name]",
             // where KIND is one of "dylib", "framework", "static".
-            let mut parts = s.splitn(2, '=');
-            let kind = parts.next().unwrap();
-            let (name, kind) = match (parts.next(), kind) {
-                (None, name) => (name, NativeLibKind::Unspecified),
-                (Some(name), "dylib") => (name, NativeLibKind::Dylib),
-                (Some(name), "framework") => (name, NativeLibKind::Framework),
-                (Some(name), "static") => (name, NativeLibKind::StaticBundle),
-                (Some(name), "static-nobundle") => (name, NativeLibKind::StaticNoBundle),
-                (_, s) => {
-                    early_error(
-                        error_format,
-                        &format!(
-                            "unknown library kind `{}`, expected \
-                             one of dylib, framework, or static",
-                            s
-                        ),
-                    );
+            let (name, kind) = match s.split_once('=') {
+                None => (s, NativeLibKind::Unspecified),
+                Some((kind, name)) => {
+                    let kind = match kind {
+                        "dylib" => NativeLibKind::Dylib,
+                        "framework" => NativeLibKind::Framework,
+                        "static" => NativeLibKind::StaticBundle,
+                        "static-nobundle" => NativeLibKind::StaticNoBundle,
+                        s => {
+                            early_error(
+                                error_format,
+                                &format!(
+                                    "unknown library kind `{}`, expected \
+                                     one of dylib, framework, or static",
+                                    s
+                                ),
+                            );
+                        }
+                    };
+                    (name.to_string(), kind)
                 }
             };
             if kind == NativeLibKind::StaticNoBundle
@@ -1556,10 +1558,11 @@ fn parse_libs(
                      accepted on the nightly compiler",
                 );
             }
-            let mut name_parts = name.splitn(2, ':');
-            let name = name_parts.next().unwrap();
-            let new_name = name_parts.next();
-            (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
+            let (name, new_name) = match name.split_once(':') {
+                None => (name, None),
+                Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
+            };
+            (name, new_name, kind)
         })
         .collect()
 }
@@ -1580,20 +1583,13 @@ pub fn parse_externs(
     let is_unstable_enabled = debugging_opts.unstable_options;
     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
     for arg in matches.opt_strs("extern") {
-        let mut parts = arg.splitn(2, '=');
-        let name = parts
-            .next()
-            .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
-        let path = parts.next().map(|s| s.to_string());
-
-        let mut name_parts = name.splitn(2, ':');
-        let first_part = name_parts.next();
-        let second_part = name_parts.next();
-        let (options, name) = match (first_part, second_part) {
-            (Some(opts), Some(name)) => (Some(opts), name),
-            (Some(name), None) => (None, name),
-            (None, None) => early_error(error_format, "--extern name must not be empty"),
-            _ => unreachable!(),
+        let (name, path) = match arg.split_once('=') {
+            None => (arg, None),
+            Some((name, path)) => (name.to_string(), Some(path.to_string())),
+        };
+        let (options, name) = match name.split_once(':') {
+            None => (None, name),
+            Some((opts, name)) => (Some(opts), name.to_string()),
         };
 
         let entry = externs.entry(name.to_owned());
@@ -1682,17 +1678,12 @@ fn parse_remap_path_prefix(
     matches
         .opt_strs("remap-path-prefix")
         .into_iter()
-        .map(|remap| {
-            let mut parts = remap.rsplitn(2, '='); // reverse iterator
-            let to = parts.next();
-            let from = parts.next();
-            match (from, to) {
-                (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
-                _ => early_error(
-                    error_format,
-                    "--remap-path-prefix must contain '=' between FROM and TO",
-                ),
-            }
+        .map(|remap| match remap.rsplit_once('=') {
+            None => early_error(
+                error_format,
+                "--remap-path-prefix must contain '=' between FROM and TO",
+            ),
+            Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
         })
         .collect()
 }
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index d002f597391..36bf8634c6e 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,6 +1,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(once_cell)]
 #![feature(or_patterns)]
+#![feature(str_split_once)]
 
 #[macro_use]
 extern crate bitflags;
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 66c709b4080..74578f2dc17 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -179,9 +179,10 @@ macro_rules! options {
     {
         let mut op = $defaultfn();
         for option in matches.opt_strs($prefix) {
-            let mut iter = option.splitn(2, '=');
-            let key = iter.next().unwrap();
-            let value = iter.next();
+            let (key, value) = match option.split_once('=') {
+                None => (option, None),
+                Some((k, v)) => (k.to_string(), Some(v)),
+            };
             let option_to_lookup = key.replace("-", "_");
             let mut found = false;
             for &(candidate, setter, type_desc, _) in $stat {
@@ -945,8 +946,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "instrument the generated code to support LLVM source-based code coverage \
         reports (note, the compiler build config must include `profiler = true`, \
         and is mutually exclusive with `-C profile-generate`/`-C profile-use`); \
-        implies `-C link-dead-code` (unless targeting MSVC, or explicitly disabled) \
-        and `-Z symbol-mangling-version=v0`; disables/overrides some Rust \
+        implies `-Z symbol-mangling-version=v0`; disables/overrides some Rust \
         optimizations (default: no)"),
     instrument_mcount: bool = (false, parse_bool, [TRACKED],
         "insert function instrument code for mcount-based tracing (default: no)"),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 5dddf0eb72e..4e269f3172c 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1111,33 +1111,7 @@ impl Session {
     pub fn link_dead_code(&self) -> bool {
         match self.opts.cg.link_dead_code {
             Some(explicitly_set) => explicitly_set,
-            None => {
-                self.opts.debugging_opts.instrument_coverage && !self.target.is_like_msvc
-                // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid
-                // binaries when LLVM InstrProf counters are enabled). As described by this issue,
-                // the "link dead code" option produces incorrect binaries when compiled and linked
-                // under MSVC. The resulting Rust programs typically crash with a segmentation
-                // fault, or produce an empty "*.profraw" file (profiling counter results normally
-                // generated during program exit).
-                //
-                // If not targeting MSVC, `-Z instrument-coverage` implies `-C link-dead-code`, so
-                // unexecuted code is still counted as zero, rather than be optimized out. Note that
-                // instrumenting dead code can be explicitly disabled with:
-                //
-                //     `-Z instrument-coverage -C link-dead-code=no`.
-                //
-                // FIXME(richkadel): Investigate if `instrument-coverage` implementation can inject
-                // [zero counters](https://llvm.org/docs/CoverageMappingFormat.html#counter) in the
-                // coverage map when "dead code" is removed, rather than forcing `link-dead-code`.
-                // This may not be possible, however, if (as it seems to appear) the "dead code"
-                // that would otherwise not be linked is only identified as "dead" by the native
-                // linker. If that's the case, I believe it is too late for the Rust compiler to
-                // leverage any information it might be able to get from the linker regarding what
-                // code is dead, to be able to add those counters.
-                //
-                // On the other hand, if any Rust compiler passes are optimizing out dead code blocks
-                // we should inject "zero" counters for those code regions.
-            }
+            None => false,
         }
     }
 
@@ -1338,7 +1312,7 @@ pub fn build_session(
 
         let profiler = SelfProfiler::new(
             directory,
-            sopts.crate_name.as_ref().map(|s| &s[..]),
+            sopts.crate_name.as_deref(),
             &sopts.debugging_opts.self_profile_events,
         );
         match profiler {
diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs
index b4beb3dc376..5987fb2a198 100644
--- a/compiler/rustc_span/src/analyze_source_file.rs
+++ b/compiler/rustc_span/src/analyze_source_file.rs
@@ -97,7 +97,7 @@ cfg_if::cfg_if! {
                 let ptr = src_bytes.as_ptr() as *const __m128i;
                 // We don't know if the pointer is aligned to 16 bytes, so we
                 // use `loadu`, which supports unaligned loading.
-                let chunk = _mm_loadu_si128(ptr.offset(chunk_index as isize));
+                let chunk = _mm_loadu_si128(ptr.add(chunk_index));
 
                 // For character in the chunk, see if its byte value is < 0, which
                 // indicates that it's part of a UTF-8 char.
@@ -253,7 +253,7 @@ fn analyze_source_file_generic(
             let pos = BytePos::from_usize(i) + output_offset;
 
             if char_len > 1 {
-                assert!(char_len >= 2 && char_len <= 4);
+                assert!((2..=4).contains(&char_len));
                 let mbc = MultiByteChar { pos, bytes: char_len as u8 };
                 multi_byte_chars.push(mbc);
             }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 11a49d1ab88..f63a73acbf4 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -1015,10 +1015,7 @@ pub enum ExternalSourceKind {
 
 impl ExternalSource {
     pub fn is_absent(&self) -> bool {
-        match self {
-            ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. } => false,
-            _ => true,
-        }
+        !matches!(self, ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. })
     }
 
     pub fn get_source(&self) -> Option<&Lrc<String>> {
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index f067cdb7308..e9b4eb6e4ab 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -623,7 +623,7 @@ impl SourceMap {
         self.span_to_source(sp, |src, start_index, end_index| {
             src.get(start_index..end_index)
                 .map(|s| s.to_string())
-                .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp))
+                .ok_or(SpanSnippetError::IllFormedSpan(sp))
         })
     }
 
@@ -640,9 +640,7 @@ impl SourceMap {
     /// Returns the source snippet as `String` before the given `Span`.
     pub fn span_to_prev_source(&self, sp: Span) -> Result<String, SpanSnippetError> {
         self.span_to_source(sp, |src, start_index, _| {
-            src.get(..start_index)
-                .map(|s| s.to_string())
-                .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp))
+            src.get(..start_index).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp))
         })
     }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 523628b7058..b60d466c3a7 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -356,6 +356,7 @@ symbols! {
         concat_idents,
         conservative_impl_trait,
         console,
+        const_allocate,
         const_compare_raw_pointers,
         const_constructor,
         const_eval_limit,
@@ -459,6 +460,9 @@ symbols! {
         document_private_items,
         dotdot_in_tuple_patterns,
         dotdoteq_in_patterns,
+        dreg,
+        dreg_low16,
+        dreg_low8,
         drop,
         drop_in_place,
         drop_types_in_const,
@@ -495,6 +499,7 @@ symbols! {
         expf64,
         export_name,
         expr,
+        extended_key_value_attributes,
         extern_absolute_paths,
         extern_crate_item_prelude,
         extern_crate_self,
@@ -542,6 +547,7 @@ symbols! {
         format_args_capture,
         format_args_nl,
         freeze,
+        freg,
         frem_fast,
         from,
         from_desugaring,
@@ -625,6 +631,7 @@ symbols! {
         iter,
         keyword,
         kind,
+        kreg,
         label,
         label_break_value,
         lang,
@@ -650,6 +657,7 @@ symbols! {
         lint_reasons,
         literal,
         llvm_asm,
+        local,
         local_inner_macros,
         log10f32,
         log10f64,
@@ -852,6 +860,9 @@ symbols! {
         pub_restricted,
         pure,
         pushpop_unsafe,
+        qreg,
+        qreg_low4,
+        qreg_low8,
         quad_precision_float,
         question_mark,
         quote,
@@ -873,6 +884,13 @@ symbols! {
         reexport_test_harness_main,
         reference,
         reflect,
+        reg,
+        reg16,
+        reg32,
+        reg64,
+        reg_abcd,
+        reg_byte,
+        reg_thumb,
         register_attr,
         register_tool,
         relaxed_adts,
@@ -1058,6 +1076,8 @@ symbols! {
         spotlight,
         sqrtf32,
         sqrtf64,
+        sreg,
+        sreg_low16,
         sse4a_target_feature,
         stable,
         staged_api,
@@ -1213,6 +1233,8 @@ symbols! {
         volatile_load,
         volatile_set_memory,
         volatile_store,
+        vreg,
+        vreg_low16,
         warn,
         wasm_import_module,
         wasm_target_feature,
@@ -1224,6 +1246,9 @@ symbols! {
         wrapping_mul,
         wrapping_sub,
         write_bytes,
+        xmm_reg,
+        ymm_reg,
+        zmm_reg,
     }
 }
 
@@ -1362,15 +1387,13 @@ impl fmt::Display for IdentPrinter {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if self.is_raw {
             f.write_str("r#")?;
-        } else {
-            if self.symbol == kw::DollarCrate {
-                if let Some(span) = self.convert_dollar_crate {
-                    let converted = span.ctxt().dollar_crate_name();
-                    if !converted.is_path_segment_keyword() {
-                        f.write_str("::")?;
-                    }
-                    return fmt::Display::fmt(&converted, f);
+        } else if self.symbol == kw::DollarCrate {
+            if let Some(span) = self.convert_dollar_crate {
+                let converted = span.ctxt().dollar_crate_name();
+                if !converted.is_path_segment_keyword() {
+                    f.write_str("::")?;
                 }
+                return fmt::Display::fmt(&converted, f);
             }
         }
         fmt::Display::fmt(&self.symbol, f)
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index aff1ff92d31..3c65c84b0de 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -20,16 +20,16 @@ macro_rules! def_reg_class {
         }
 
         impl $arch_regclass {
-            pub fn name(self) -> &'static str {
+            pub fn name(self) -> rustc_span::Symbol {
                 match self {
-                    $(Self::$class => stringify!($class),)*
+                    $(Self::$class => rustc_span::symbol::sym::$class,)*
                 }
             }
 
-            pub fn parse(_arch: super::InlineAsmArch, name: &str) -> Result<Self, &'static str> {
+            pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result<Self, &'static str> {
                 match name {
                     $(
-                        stringify!($class) => Ok(Self::$class),
+                        rustc_span::sym::$class => Ok(Self::$class),
                     )*
                     _ => Err("unknown register class"),
                 }
@@ -327,7 +327,7 @@ pub enum InlineAsmRegClass {
 }
 
 impl InlineAsmRegClass {
-    pub fn name(self) -> &'static str {
+    pub fn name(self) -> Symbol {
         match self {
             Self::X86(r) => r.name(),
             Self::Arm(r) => r.name(),
@@ -422,29 +422,22 @@ impl InlineAsmRegClass {
     }
 
     pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
-        // FIXME: use direct symbol comparison for register class names
-        name.with(|name| {
-            Ok(match arch {
-                InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
-                    Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
-                }
-                InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
-                InlineAsmArch::AArch64 => {
-                    Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?)
-                }
-                InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
-                    Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
-                }
-                InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
-                InlineAsmArch::Hexagon => {
-                    Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
-                }
-                InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
-                    Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
-                }
-                InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
-                InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
-            })
+        Ok(match arch {
+            InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
+                Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
+            }
+            InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
+            InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
+            InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
+                Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
+            }
+            InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
+            InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
+            InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
+                Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
+            }
+            InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
+            InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
         })
     }
 
@@ -484,7 +477,7 @@ impl fmt::Display for InlineAsmRegOrRegClass {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Self::Reg(r) => write!(f, "\"{}\"", r.name()),
-            Self::RegClass(r) => f.write_str(r.name()),
+            Self::RegClass(r) => write!(f, "{}", r.name()),
         }
     }
 }
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index fb747dfcbd3..1ad57582eba 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -15,6 +15,7 @@
 #![feature(never_type)]
 #![feature(associated_type_bounds)]
 #![feature(exhaustive_patterns)]
+#![feature(str_split_once)]
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index e271a6dec40..88422395216 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -54,10 +54,7 @@ fn macos_deployment_target() -> (u32, u32) {
     let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok();
     let version = deployment_target
         .as_ref()
-        .and_then(|s| {
-            let mut i = s.splitn(2, '.');
-            i.next().and_then(|a| i.next().map(|b| (a, b)))
-        })
+        .and_then(|s| s.split_once('.'))
         .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok());
 
     version.unwrap_or((10, 7))
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index d6048d092b1..2fb9b3cd5d3 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -65,8 +65,7 @@ pub use self::util::{
     get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
 };
 pub use self::util::{
-    supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
-    SupertraitDefIds, Supertraits,
+    supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
 };
 
 pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 54743ef9ce9..33cd509cbb8 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -49,7 +49,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
             self.param_env,
         );
         if !value.has_projections() {
-            return Ok(Normalized { value: value.clone(), obligations: vec![] });
+            return Ok(Normalized { value, obligations: vec![] });
         }
 
         let mut normalizer = QueryNormalizer {
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 0db5fda272a..b7e77f389f8 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -44,6 +44,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             // the match is non-exhaustive.
             _ => bug!("invalid generic parameter kind {}", kind),
         };
+
+        if let ParamKindOrd::Const { .. } = kind_ord {
+            if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg {
+                err.help("const arguments cannot yet be inferred with `_`");
+            }
+        }
+
         let arg_ord = match arg {
             GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
             GenericArg::Type(_) => ParamKindOrd::Type,
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 915a15fd245..7888cb1b9f5 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -49,10 +49,9 @@ pub trait AstConv<'tcx> {
 
     fn default_constness_for_trait_bounds(&self) -> Constness;
 
-    /// Returns predicates in scope of the form `X: Foo<T>`, where `X`
-    /// is a type parameter `X` with the given id `def_id` and T
-    /// matches `assoc_name`. This is a subset of the full set of
-    /// predicates.
+    /// Returns predicates in scope of the form `X: Foo`, where `X` is
+    /// a type parameter `X` with the given id `def_id`. This is a
+    /// subset of the full set of predicates.
     ///
     /// This is used for one specific purpose: resolving "short-hand"
     /// associated type references like `T::Item`. In principle, we
@@ -61,12 +60,7 @@ pub trait AstConv<'tcx> {
     /// but this can lead to cycle errors. The problem is that we have
     /// to do this resolution *in order to create the predicates in
     /// the first place*. Hence, we have this "special pass".
-    fn get_type_parameter_bounds(
-        &self,
-        span: Span,
-        def_id: DefId,
-        assoc_name: Ident,
-    ) -> ty::GenericPredicates<'tcx>;
+    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>;
 
     /// Returns the lifetime to use when a lifetime is omitted (and not elided).
     fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
@@ -768,7 +762,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     }
 
     // Returns `true` if a bounds list includes `?Sized`.
-    pub fn is_unsized(&self, ast_bounds: &[&hir::GenericBound<'_>], span: Span) -> bool {
+    pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool {
         let tcx = self.tcx();
 
         // Try to find an unbound in bounds.
@@ -826,7 +820,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     fn add_bounds(
         &self,
         param_ty: Ty<'tcx>,
-        ast_bounds: &[&hir::GenericBound<'_>],
+        ast_bounds: &[hir::GenericBound<'_>],
         bounds: &mut Bounds<'tcx>,
     ) {
         let constness = self.default_constness_for_trait_bounds();
@@ -841,7 +835,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
                 hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
                     .instantiate_lang_item_trait_ref(
-                        *lang_item, *span, *hir_id, args, param_ty, bounds,
+                        lang_item, span, hir_id, args, param_ty, bounds,
                     ),
                 hir::GenericBound::Outlives(ref l) => {
                     bounds.region_bounds.push((self.ast_region_to_region(l, None), l.span))
@@ -873,42 +867,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         sized_by_default: SizedByDefault,
         span: Span,
     ) -> Bounds<'tcx> {
-        let ast_bounds: Vec<_> = ast_bounds.iter().collect();
-        self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span)
-    }
-
-    /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
-    /// named `assoc_name` into ty::Bounds. Ignore the rest.
-    pub fn compute_bounds_that_match_assoc_type(
-        &self,
-        param_ty: Ty<'tcx>,
-        ast_bounds: &[hir::GenericBound<'_>],
-        sized_by_default: SizedByDefault,
-        span: Span,
-        assoc_name: Ident,
-    ) -> Bounds<'tcx> {
-        let mut result = Vec::new();
-
-        for ast_bound in ast_bounds {
-            if let Some(trait_ref) = ast_bound.trait_ref() {
-                if let Some(trait_did) = trait_ref.trait_def_id() {
-                    if self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) {
-                        result.push(ast_bound);
-                    }
-                }
-            }
-        }
-
-        self.compute_bounds_inner(param_ty, &result, sized_by_default, span)
-    }
-
-    fn compute_bounds_inner(
-        &self,
-        param_ty: Ty<'tcx>,
-        ast_bounds: &[&hir::GenericBound<'_>],
-        sized_by_default: SizedByDefault,
-        span: Span,
-    ) -> Bounds<'tcx> {
         let mut bounds = Bounds::default();
 
         self.add_bounds(param_ty, ast_bounds, &mut bounds);
@@ -1077,8 +1035,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
                 // parameter to have a skipped binder.
                 let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
-                let ast_bounds: Vec<_> = ast_bounds.iter().collect();
-                self.add_bounds(param_ty, &ast_bounds, bounds);
+                self.add_bounds(param_ty, ast_bounds, bounds);
             }
         }
         Ok(())
@@ -1395,9 +1352,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             ty_param_def_id, assoc_name, span,
         );
 
-        let predicates = &self
-            .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name)
-            .predicates;
+        let predicates =
+            &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates;
 
         debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
 
@@ -1405,14 +1361,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let param_name = tcx.hir().ty_param_name(param_hir_id);
         self.one_bound_for_assoc_type(
             || {
-                traits::transitive_bounds_that_define_assoc_type(
+                traits::transitive_bounds(
                     tcx,
                     predicates.iter().filter_map(|(p, _)| {
                         p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value)
                     }),
-                    assoc_name,
                 )
-                .into_iter()
             },
             || param_name.to_string(),
             assoc_name,
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs
index 683707470f4..497754f20e4 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_typeck/src/bounds.rs
@@ -67,22 +67,18 @@ impl<'tcx> Bounds<'tcx> {
 
         sized_predicate
             .into_iter()
+            .chain(self.region_bounds.iter().map(|&(region_bound, span)| {
+                let outlives = ty::OutlivesPredicate(param_ty, region_bound);
+                (ty::Binder::bind(outlives).to_predicate(tcx), span)
+            }))
+            .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
+                let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
+                (predicate, span)
+            }))
             .chain(
-                self.region_bounds
+                self.projection_bounds
                     .iter()
-                    .map(|&(region_bound, span)| {
-                        let outlives = ty::OutlivesPredicate(param_ty, region_bound);
-                        (ty::Binder::bind(outlives).to_predicate(tcx), span)
-                    })
-                    .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
-                        let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
-                        (predicate, span)
-                    }))
-                    .chain(
-                        self.projection_bounds
-                            .iter()
-                            .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
-                    ),
+                    .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
             )
             .collect()
     }
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 489d836298f..ec7369fd3e8 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -462,39 +462,25 @@ pub(super) fn check_opaque<'tcx>(
 
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
 /// in "inheriting lifetimes".
+#[instrument(skip(tcx, span))]
 pub(super) fn check_opaque_for_inheriting_lifetimes(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
     span: Span,
 ) {
     let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id));
-    debug!(
-        "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}",
-        def_id, span, item
-    );
-
-    #[derive(Debug)]
-    struct ProhibitOpaqueVisitor<'tcx> {
-        opaque_identity_ty: Ty<'tcx>,
-        generics: &'tcx ty::Generics,
-    }
+    debug!(?item, ?span);
 
-    impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
-        type BreakTy = Option<Ty<'tcx>>;
-
-        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-            debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
-            if t != self.opaque_identity_ty && t.super_visit_with(self).is_break() {
-                return ControlFlow::Break(Some(t));
-            }
-            ControlFlow::CONTINUE
-        }
+    struct FoundParentLifetime;
+    struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
+    impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
+        type BreakTy = FoundParentLifetime;
 
         fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-            debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
+            debug!("FindParentLifetimeVisitor: r={:?}", r);
             if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
-                if *index < self.generics.parent_count as u32 {
-                    return ControlFlow::Break(None);
+                if *index < self.0.parent_count as u32 {
+                    return ControlFlow::Break(FoundParentLifetime);
                 } else {
                     return ControlFlow::CONTINUE;
                 }
@@ -505,7 +491,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
 
         fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             if let ty::ConstKind::Unevaluated(..) = c.val {
-                // FIXME(#72219) We currenctly don't detect lifetimes within substs
+                // FIXME(#72219) We currently don't detect lifetimes within substs
                 // which would violate this check. Even though the particular substitution is not used
                 // within the const, this should still be fixed.
                 return ControlFlow::CONTINUE;
@@ -514,6 +500,26 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
         }
     }
 
+    #[derive(Debug)]
+    struct ProhibitOpaqueVisitor<'tcx> {
+        opaque_identity_ty: Ty<'tcx>,
+        generics: &'tcx ty::Generics,
+    }
+
+    impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
+        type BreakTy = Ty<'tcx>;
+
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+            debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
+            if t == self.opaque_identity_ty {
+                ControlFlow::CONTINUE
+            } else {
+                t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
+                    .map_break(|FoundParentLifetime| t)
+            }
+        }
+    }
+
     if let ItemKind::OpaqueTy(hir::OpaqueTy {
         origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
         ..
@@ -555,14 +561,12 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
 
             if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
                 if snippet == "Self" {
-                    if let Some(ty) = ty {
-                        err.span_suggestion(
-                            span,
-                            "consider spelling out the type instead",
-                            format!("{:?}", ty),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
+                    err.span_suggestion(
+                        span,
+                        "consider spelling out the type instead",
+                        format!("{:?}", ty),
+                        Applicability::MaybeIncorrect,
+                    );
                 }
             }
             err.emit();
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index d12d2cb59a5..aa4d57f7e1d 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -361,11 +361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     fn replace_prefix(&self, s: &str, old: &str, new: &str) -> Option<String> {
-        if let Some(stripped) = s.strip_prefix(old) {
-            Some(new.to_string() + stripped)
-        } else {
-            None
-        }
+        s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
     }
 
     /// This function is used to determine potential "simple" improvements or users' errors and
@@ -552,11 +548,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // we may want to suggest removing a `&`.
                 if sm.is_imported(expr.span) {
                     if let Ok(src) = sm.span_to_snippet(sp) {
-                        if let Some(src) = self.replace_prefix(&src, "&", "") {
+                        if let Some(src) = src.strip_prefix('&') {
                             return Some((
                                 sp,
                                 "consider removing the borrow",
-                                src,
+                                src.to_string(),
                                 Applicability::MachineApplicable,
                             ));
                         }
@@ -587,47 +583,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 hir::Mutability::Mut => {
                                     let new_prefix = "&mut ".to_owned() + derefs;
                                     match mutbl_a {
-                                        hir::Mutability::Mut => {
-                                            if let Some(s) =
-                                                self.replace_prefix(&src, "&mut ", &new_prefix)
-                                            {
-                                                Some((s, Applicability::MachineApplicable))
-                                            } else {
-                                                None
-                                            }
-                                        }
-                                        hir::Mutability::Not => {
-                                            if let Some(s) =
-                                                self.replace_prefix(&src, "&", &new_prefix)
-                                            {
-                                                Some((s, Applicability::Unspecified))
-                                            } else {
-                                                None
-                                            }
-                                        }
+                                        hir::Mutability::Mut => self
+                                            .replace_prefix(&src, "&mut ", &new_prefix)
+                                            .map(|s| (s, Applicability::MachineApplicable)),
+                                        hir::Mutability::Not => self
+                                            .replace_prefix(&src, "&", &new_prefix)
+                                            .map(|s| (s, Applicability::Unspecified)),
                                     }
                                 }
                                 hir::Mutability::Not => {
                                     let new_prefix = "&".to_owned() + derefs;
                                     match mutbl_a {
-                                        hir::Mutability::Mut => {
-                                            if let Some(s) =
-                                                self.replace_prefix(&src, "&mut ", &new_prefix)
-                                            {
-                                                Some((s, Applicability::MachineApplicable))
-                                            } else {
-                                                None
-                                            }
-                                        }
-                                        hir::Mutability::Not => {
-                                            if let Some(s) =
-                                                self.replace_prefix(&src, "&", &new_prefix)
-                                            {
-                                                Some((s, Applicability::MachineApplicable))
-                                            } else {
-                                                None
-                                            }
-                                        }
+                                        hir::Mutability::Mut => self
+                                            .replace_prefix(&src, "&mut ", &new_prefix)
+                                            .map(|s| (s, Applicability::MachineApplicable)),
+                                        hir::Mutability::Not => self
+                                            .replace_prefix(&src, "&", &new_prefix)
+                                            .map(|s| (s, Applicability::MachineApplicable)),
                                     }
                                 }
                             } {
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 26962d2222d..b8a2a4779d9 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1929,7 +1929,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
-        for op in asm.operands {
+        for (op, _op_sp) in asm.operands {
             match op {
                 hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::Const { expr } => {
                     self.check_expr_asm_operand(expr, true);
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index 20c639a0031..f635e0b6f93 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -20,7 +20,6 @@ use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Const, Ty, TyCtxt};
 use rustc_session::Session;
-use rustc_span::symbol::Ident;
 use rustc_span::{self, Span};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 
@@ -184,12 +183,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn get_type_parameter_bounds(
-        &self,
-        _: Span,
-        def_id: DefId,
-        _: Ident,
-    ) -> ty::GenericPredicates<'tcx> {
+    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
         let tcx = self.tcx;
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
         let item_id = tcx.hir().ty_param_owner(hir_id);
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index f40a250200e..e2712a30339 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -286,6 +286,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
             }
 
+            sym::const_allocate => {
+                (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8))
+            }
+
             sym::ptr_offset_from => {
                 (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
             }
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 39a79893b64..891dd8b2f02 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -765,13 +765,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             )
         });
 
-        // It is illegal to invoke a method on a trait instance that
-        // refers to the `Self` type. An error will be reported by
-        // `enforce_object_limitations()` if the method refers to the
-        // `Self` type anywhere other than the receiver. Here, we use
-        // a substitution that replaces `Self` with the object type
-        // itself. Hence, a `&self` method will wind up with an
-        // argument type like `&Trait`.
+        // It is illegal to invoke a method on a trait instance that refers to
+        // the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error
+        // will be reported by `object_safety.rs` if the method refers to the
+        // `Self` type anywhere other than the receiver. Here, we use a
+        // substitution that replaces `Self` with the object type itself. Hence,
+        // a `&self` method will wind up with an argument type like `&Trait`.
         let trait_ref = principal.with_self_ty(self.tcx, self_ty);
         self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
             let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index bcb73e1b4e7..5fc573a57ad 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1174,7 +1174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let mut unmentioned_err = None;
-        // Report an error if incorrect number of the fields were specified.
+        // Report an error if an incorrect number of fields was specified.
         if adt.is_union() {
             if fields.len() != 1 {
                 tcx.sess
@@ -1185,12 +1185,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
             }
         } else if !etc && !unmentioned_fields.is_empty() {
-            let no_accessible_unmentioned_fields = unmentioned_fields
-                .iter()
-                .find(|(field, _)| {
-                    field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
-                })
-                .is_none();
+            let no_accessible_unmentioned_fields = !unmentioned_fields.iter().any(|(field, _)| {
+                field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+            });
 
             if no_accessible_unmentioned_fields {
                 unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 019fa78fb1e..30b4682296c 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -202,7 +202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // inference algorithm will reject it).
 
         // Equate the type variables for the upvars with the actual types.
-        let final_upvar_tys = self.final_upvar_tys(closure_hir_id);
+        let final_upvar_tys = self.final_upvar_tys(closure_def_id);
         debug!(
             "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}",
             closure_hir_id, substs, final_upvar_tys
@@ -222,36 +222,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     // Returns a list of `Ty`s for each upvar.
-    fn final_upvar_tys(&self, closure_id: hir::HirId) -> Vec<Ty<'tcx>> {
+    fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> {
         // Presently an unboxed closure type cannot "escape" out of a
         // function, so we will only encounter ones that originated in the
         // local crate or were inlined into it along with some function.
         // This may change if abstract return types of some sort are
         // implemented.
         let tcx = self.tcx;
-        let closure_def_id = tcx.hir().local_def_id(closure_id);
 
         self.typeck_results
             .borrow()
-            .closure_captures
-            .get(&closure_def_id.to_def_id())
-            .iter()
-            .flat_map(|upvars| {
-                upvars.iter().map(|(&var_hir_id, _)| {
-                    let upvar_ty = self.node_ty(var_hir_id);
-                    let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id);
-                    let capture = self.typeck_results.borrow().upvar_capture(upvar_id);
-
-                    debug!("var_id={:?} upvar_ty={:?} capture={:?}", var_hir_id, upvar_ty, capture);
-
-                    match capture {
-                        ty::UpvarCapture::ByValue(_) => upvar_ty,
-                        ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref(
-                            borrow.region,
-                            ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() },
-                        ),
-                    }
-                })
+            .closure_min_captures_flattened(closure_id)
+            .map(|captured_place| {
+                let upvar_ty = captured_place.place.ty();
+                let capture = captured_place.info.capture_kind;
+
+                debug!(
+                    "place={:?} upvar_ty={:?} capture={:?}",
+                    captured_place.place, upvar_ty, capture
+                );
+
+                match capture {
+                    ty::UpvarCapture::ByValue(_) => upvar_ty,
+                    ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref(
+                        borrow.region,
+                        ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() },
+                    ),
+                }
             })
             .collect()
     }
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index d1ada123c0d..7c9cfe69fc9 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -55,6 +55,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (),
         }
         wbcx.visit_body(body);
+        wbcx.visit_min_capture_map();
         wbcx.visit_upvar_capture_map();
         wbcx.visit_closures();
         wbcx.visit_liberated_fn_sigs();
@@ -88,7 +89,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// The Writeback context. This visitor walks the AST, checking the
+// The Writeback context. This visitor walks the HIR, checking the
 // fn-specific typeck results to find references to types or regions. It
 // resolves those regions to remove inference variables and writes the
 // final result back into the master typeck results in the tcx. Here and
@@ -331,6 +332,37 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
 }
 
 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
+    fn visit_min_capture_map(&mut self) {
+        let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher(
+            self.fcx.typeck_results.borrow().closure_min_captures.len(),
+            Default::default(),
+        );
+        for (closure_def_id, root_min_captures) in
+            self.fcx.typeck_results.borrow().closure_min_captures.iter()
+        {
+            let mut root_var_map_wb = ty::RootVariableMinCaptureList::with_capacity_and_hasher(
+                root_min_captures.len(),
+                Default::default(),
+            );
+            for (var_hir_id, min_list) in root_min_captures.iter() {
+                let min_list_wb = min_list
+                    .iter()
+                    .map(|captured_place| {
+                        let locatable = captured_place.info.expr_id.unwrap_or(
+                            self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local()),
+                        );
+
+                        self.resolve(captured_place.clone(), &locatable)
+                    })
+                    .collect();
+                root_var_map_wb.insert(*var_hir_id, min_list_wb);
+            }
+            min_captures_wb.insert(*closure_def_id, root_var_map_wb);
+        }
+
+        self.typeck_results.closure_min_captures = min_captures_wb;
+    }
+
     fn visit_upvar_capture_map(&mut self) {
         for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() {
             let new_upvar_capture = match *upvar_capture {
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 483ab2f58f2..0c1578498b8 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -44,8 +44,8 @@ struct InherentCollect<'tcx> {
 
 impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        let ty = match item.kind {
-            hir::ItemKind::Impl { of_trait: None, ref self_ty, .. } => self_ty,
+        let (ty, assoc_items) = match item.kind {
+            hir::ItemKind::Impl { of_trait: None, ref self_ty, items, .. } => (self_ty, items),
             _ => return,
         };
 
@@ -70,6 +70,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "bool",
                     "bool",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Char => {
@@ -80,6 +81,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "char",
                     "char",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Str => {
@@ -90,6 +92,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "str",
                     "str",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
@@ -100,6 +103,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "slice_u8",
                     "[u8]",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Slice(_) => {
@@ -110,6 +114,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "slice",
                     "[T]",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Array(_, _) => {
@@ -120,6 +125,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "array",
                     "[T; N]",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not })
@@ -132,6 +138,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "const_slice_ptr",
                     "*const [T]",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut })
@@ -144,6 +151,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "mut_slice_ptr",
                     "*mut [T]",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => {
@@ -154,6 +162,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "const_ptr",
                     "*const T",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Mut }) => {
@@ -164,6 +173,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "mut_ptr",
                     "*mut T",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Int(ast::IntTy::I8) => {
@@ -174,6 +184,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "i8",
                     "i8",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Int(ast::IntTy::I16) => {
@@ -184,6 +195,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "i16",
                     "i16",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Int(ast::IntTy::I32) => {
@@ -194,6 +206,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "i32",
                     "i32",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Int(ast::IntTy::I64) => {
@@ -204,6 +217,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "i64",
                     "i64",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Int(ast::IntTy::I128) => {
@@ -214,6 +228,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "i128",
                     "i128",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Int(ast::IntTy::Isize) => {
@@ -224,6 +239,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "isize",
                     "isize",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Uint(ast::UintTy::U8) => {
@@ -234,6 +250,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "u8",
                     "u8",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Uint(ast::UintTy::U16) => {
@@ -244,6 +261,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "u16",
                     "u16",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Uint(ast::UintTy::U32) => {
@@ -254,6 +272,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "u32",
                     "u32",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Uint(ast::UintTy::U64) => {
@@ -264,6 +283,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "u64",
                     "u64",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Uint(ast::UintTy::U128) => {
@@ -274,6 +294,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "u128",
                     "u128",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Uint(ast::UintTy::Usize) => {
@@ -284,6 +305,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "usize",
                     "usize",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Float(ast::FloatTy::F32) => {
@@ -294,6 +316,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "f32",
                     "f32",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Float(ast::FloatTy::F64) => {
@@ -304,6 +327,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "f64",
                     "f64",
                     item.span,
+                    assoc_items,
                 );
             }
             ty::Error(_) => {}
@@ -369,6 +393,7 @@ impl InherentCollect<'tcx> {
         lang: &str,
         ty: &str,
         span: Span,
+        assoc_items: &[hir::ImplItemRef<'_>],
     ) {
         match (lang_def_id, lang_def_id2) {
             (Some(lang_def_id), _) if lang_def_id == impl_def_id.to_def_id() => {
@@ -378,6 +403,32 @@ impl InherentCollect<'tcx> {
                 // OK
             }
             _ => {
+                let to_implement = if assoc_items.len() == 0 {
+                    String::new()
+                } else {
+                    let plural = assoc_items.len() > 1;
+                    let assoc_items_kind = {
+                        let item_types = assoc_items.iter().map(|x| x.kind);
+                        if item_types.clone().all(|x| x == hir::AssocItemKind::Const) {
+                            "constant"
+                        } else if item_types
+                            .clone()
+                            .all(|x| matches! {x, hir::AssocItemKind::Fn{ .. } })
+                        {
+                            "method"
+                        } else {
+                            "associated item"
+                        }
+                    };
+
+                    format!(
+                        " to implement {} {}{}",
+                        if plural { "these" } else { "this" },
+                        assoc_items_kind,
+                        if plural { "s" } else { "" }
+                    )
+                };
+
                 struct_span_err!(
                     self.tcx.sess,
                     span,
@@ -387,7 +438,7 @@ impl InherentCollect<'tcx> {
                     lang,
                     ty
                 )
-                .span_help(span, "consider using a trait to implement these methods")
+                .help(&format!("consider using a trait{}", to_implement))
                 .emit();
             }
         }
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index f8b7ccb2cd6..38da1e5ea03 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1,4 +1,3 @@
-// ignore-tidy-filelength
 //! "Collection" is the process of determining the type and other external
 //! details of each item in Rust. Collection is specifically concerned
 //! with *inter-procedural* things -- for example, for a function
@@ -80,7 +79,6 @@ pub fn provide(providers: &mut Providers) {
         projection_ty_from_predicates,
         explicit_predicates_of,
         super_predicates_of,
-        super_predicates_that_define_assoc_type,
         trait_explicit_predicates_and_bounds,
         type_param_predicates,
         trait_def,
@@ -312,17 +310,8 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
         }
     }
 
-    fn get_type_parameter_bounds(
-        &self,
-        span: Span,
-        def_id: DefId,
-        assoc_name: Ident,
-    ) -> ty::GenericPredicates<'tcx> {
-        self.tcx.at(span).type_param_predicates((
-            self.item_def_id,
-            def_id.expect_local(),
-            assoc_name,
-        ))
+    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
+        self.tcx.at(span).type_param_predicates((self.item_def_id, def_id.expect_local()))
     }
 
     fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> {
@@ -370,8 +359,8 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
                 self.tcx().sess,
                 span,
                 E0212,
-                "cannot extract an associated type from a higher-ranked trait bound \
-                 in this context"
+                "cannot use the associated type of a trait \
+                 with uninferred generic parameters"
             );
 
             match self.node() {
@@ -503,7 +492,7 @@ fn get_new_lifetime_name<'tcx>(
 /// `X: Foo` where `X` is the type parameter `def_id`.
 fn type_param_predicates(
     tcx: TyCtxt<'_>,
-    (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
+    (item_def_id, def_id): (DefId, LocalDefId),
 ) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
 
@@ -528,7 +517,7 @@ fn type_param_predicates(
     let mut result = parent
         .map(|parent| {
             let icx = ItemCtxt::new(tcx, parent);
-            icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
+            icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id())
         })
         .unwrap_or_default();
     let mut extend = None;
@@ -571,18 +560,12 @@ fn type_param_predicates(
 
     let icx = ItemCtxt::new(tcx, item_def_id);
     let extra_predicates = extend.into_iter().chain(
-        icx.type_parameter_bounds_in_generics(
-            ast_generics,
-            param_id,
-            ty,
-            OnlySelfBounds(true),
-            Some(assoc_name),
-        )
-        .into_iter()
-        .filter(|(predicate, _)| match predicate.skip_binders() {
-            ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index),
-            _ => false,
-        }),
+        icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))
+            .into_iter()
+            .filter(|(predicate, _)| match predicate.skip_binders() {
+                ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index),
+                _ => false,
+            }),
     );
     result.predicates =
         tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
@@ -600,7 +583,6 @@ impl ItemCtxt<'tcx> {
         param_id: hir::HirId,
         ty: Ty<'tcx>,
         only_self_bounds: OnlySelfBounds,
-        assoc_name: Option<Ident>,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
         let constness = self.default_constness_for_trait_bounds();
         let from_ty_params = ast_generics
@@ -611,10 +593,6 @@ impl ItemCtxt<'tcx> {
                 _ => None,
             })
             .flat_map(|bounds| bounds.iter())
-            .filter(|b| match assoc_name {
-                Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
-                None => true,
-            })
             .flat_map(|b| predicates_from_bound(self, ty, b, constness));
 
         let from_where_clauses = ast_generics
@@ -633,34 +611,12 @@ impl ItemCtxt<'tcx> {
                 } else {
                     None
                 };
-                bp.bounds
-                    .iter()
-                    .filter(|b| match assoc_name {
-                        Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
-                        None => true,
-                    })
-                    .filter_map(move |b| bt.map(|bt| (bt, b)))
+                bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b)))
             })
             .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness));
 
         from_ty_params.chain(from_where_clauses).collect()
     }
-
-    fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
-        debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name);
-
-        match b {
-            hir::GenericBound::Trait(poly_trait_ref, _) => {
-                let trait_ref = &poly_trait_ref.trait_ref;
-                if let Some(trait_did) = trait_ref.trait_def_id() {
-                    self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
-                } else {
-                    false
-                }
-            }
-            _ => false,
-        }
-    }
 }
 
 /// Tests whether this is the AST for a reference to the type
@@ -1029,90 +985,54 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef {
 /// the transitive super-predicates are converted.
 fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> {
     debug!("super_predicates(trait_def_id={:?})", trait_def_id);
-    tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
-}
-
-/// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
-fn super_predicates_that_define_assoc_type(
-    tcx: TyCtxt<'_>,
-    (trait_def_id, assoc_name): (DefId, Option<Ident>),
-) -> ty::GenericPredicates<'_> {
-    debug!(
-        "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})",
-        trait_def_id, assoc_name
-    );
-    if trait_def_id.is_local() {
-        debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id);
-        let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
-
-        let item = match tcx.hir().get(trait_hir_id) {
-            Node::Item(item) => item,
-            _ => bug!("trait_node_id {} is not an item", trait_hir_id),
-        };
+    let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
 
-        let (generics, bounds) = match item.kind {
-            hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
-            hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
-            _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
-        };
-
-        let icx = ItemCtxt::new(tcx, trait_def_id);
+    let item = match tcx.hir().get(trait_hir_id) {
+        Node::Item(item) => item,
+        _ => bug!("trait_node_id {} is not an item", trait_hir_id),
+    };
 
-        // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
-        let self_param_ty = tcx.types.self_param;
-        let superbounds1 = if let Some(assoc_name) = assoc_name {
-            AstConv::compute_bounds_that_match_assoc_type(
-                &icx,
-                self_param_ty,
-                &bounds,
-                SizedByDefault::No,
-                item.span,
-                assoc_name,
-            )
-        } else {
-            AstConv::compute_bounds(&icx, self_param_ty, &bounds, SizedByDefault::No, item.span)
-        };
+    let (generics, bounds) = match item.kind {
+        hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
+        hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
+        _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
+    };
 
-        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+    let icx = ItemCtxt::new(tcx, trait_def_id);
+
+    // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
+    let self_param_ty = tcx.types.self_param;
+    let superbounds1 =
+        AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
+
+    let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+
+    // Convert any explicit superbounds in the where-clause,
+    // e.g., `trait Foo where Self: Bar`.
+    // In the case of trait aliases, however, we include all bounds in the where-clause,
+    // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
+    // as one of its "superpredicates".
+    let is_trait_alias = tcx.is_trait_alias(trait_def_id);
+    let superbounds2 = icx.type_parameter_bounds_in_generics(
+        generics,
+        item.hir_id,
+        self_param_ty,
+        OnlySelfBounds(!is_trait_alias),
+    );
 
-        // Convert any explicit superbounds in the where-clause,
-        // e.g., `trait Foo where Self: Bar`.
-        // In the case of trait aliases, however, we include all bounds in the where-clause,
-        // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
-        // as one of its "superpredicates".
-        let is_trait_alias = tcx.is_trait_alias(trait_def_id);
-        let superbounds2 = icx.type_parameter_bounds_in_generics(
-            generics,
-            item.hir_id,
-            self_param_ty,
-            OnlySelfBounds(!is_trait_alias),
-            assoc_name,
-        );
+    // Combine the two lists to form the complete set of superbounds:
+    let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
 
-        // Combine the two lists to form the complete set of superbounds:
-        let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
-
-        // Now require that immediate supertraits are converted,
-        // which will, in turn, reach indirect supertraits.
-        if assoc_name.is_none() {
-            // FIXME: move this into the `super_predicates_of` query
-            for &(pred, span) in superbounds {
-                debug!("superbound: {:?}", pred);
-                if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() {
-                    tcx.at(span).super_predicates_of(bound.def_id());
-                }
-            }
+    // Now require that immediate supertraits are converted,
+    // which will, in turn, reach indirect supertraits.
+    for &(pred, span) in superbounds {
+        debug!("superbound: {:?}", pred);
+        if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() {
+            tcx.at(span).super_predicates_of(bound.def_id());
         }
-
-        ty::GenericPredicates { parent: None, predicates: superbounds }
-    } else {
-        // if `assoc_name` is None, then the query should've been redirected to an
-        // external provider
-        assert!(assoc_name.is_some());
-        tcx.super_predicates_of(trait_def_id)
     }
+
+    ty::GenericPredicates { parent: None, predicates: superbounds }
 }
 
 fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index dd1da7d9cff..e596dd1a396 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -28,7 +28,7 @@ fn associated_type_bounds<'tcx>(
     let bounds = AstConv::compute_bounds(
         &ItemCtxt::new(tcx, assoc_item_def_id),
         item_ty,
-        &bounds,
+        bounds,
         SizedByDefault::Yes,
         span,
     );
@@ -68,7 +68,7 @@ fn opaque_type_bounds<'tcx>(
         let bounds = AstConv::compute_bounds(
             &ItemCtxt::new(tcx, opaque_def_id),
             item_ty,
-            &bounds,
+            bounds,
             SizedByDefault::Yes,
             span,
         )
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 1b51d5e0182..ce9fd5575cf 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -15,7 +15,6 @@ use rustc_index::vec::Idx;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::hir::place::ProjectionKind;
 use rustc_middle::ty::{self, adjustment, TyCtxt};
-use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
 
 use crate::mem_categorization as mc;
@@ -243,7 +242,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
             }
 
             hir::ExprKind::InlineAsm(ref asm) => {
-                for op in asm.operands {
+                for (op, _op_sp) in asm.operands {
                     match op {
                         hir::InlineAsmOperand::In { expr, .. }
                         | hir::InlineAsmOperand::Const { expr, .. }
@@ -571,38 +570,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         }));
     }
 
-    /// Walk closure captures but using `closure_caputes` instead
-    /// of `closure_min_captures`.
-    ///
-    /// This is needed because clippy uses `ExprUseVisitor` after TypeckResults
-    /// are written back. We don't currently writeback min_captures to
-    /// TypeckResults.
-    fn walk_captures_closure_captures(&mut self, closure_expr: &hir::Expr<'_>) {
-        // FIXME(arora-aman): Remove this function once rust-lang/project-rfc-2229#18
-        // is completed.
-        debug!("walk_captures_closure_captures({:?}), ", closure_expr);
-
-        let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
-        let cl_span = self.tcx().hir().span(closure_expr.hir_id);
-
-        let captures = &self.mc.typeck_results.closure_captures[&closure_def_id];
-
-        for (&var_id, &upvar_id) in captures {
-            let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id);
-            let captured_place =
-                return_if_err!(self.cat_captured_var(closure_expr.hir_id, cl_span, var_id));
-            match upvar_capture {
-                ty::UpvarCapture::ByValue(_) => {
-                    let mode = copy_or_move(&self.mc, &captured_place);
-                    self.delegate.consume(&captured_place, captured_place.hir_id, mode);
-                }
-                ty::UpvarCapture::ByRef(upvar_borrow) => {
-                    self.delegate.borrow(&captured_place, captured_place.hir_id, upvar_borrow.kind);
-                }
-            }
-        }
-    }
-
     /// Handle the case where the current body contains a closure.
     ///
     /// When the current body being handled is a closure, then we must make sure that
@@ -646,16 +613,18 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                     let place = &captured_place.place;
                     let capture_info = captured_place.info;
 
-                    let upvar_id = if body_owner_is_closure {
+                    let place_base = if body_owner_is_closure {
                         // Mark the place to be captured by the enclosing closure
-                        ty::UpvarId::new(*var_hir_id, self.body_owner)
+                        PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.body_owner))
                     } else {
-                        ty::UpvarId::new(*var_hir_id, closure_def_id.expect_local())
+                        // If the body owner isn't a closure then the variable must
+                        // be a local variable
+                        PlaceBase::Local(*var_hir_id)
                     };
                     let place_with_id = PlaceWithHirId::new(
                         capture_info.expr_id.unwrap_or(closure_expr.hir_id),
                         place.base_ty,
-                        PlaceBase::Upvar(upvar_id),
+                        place_base,
                         place.projections.clone(),
                     );
 
@@ -674,23 +643,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                     }
                 }
             }
-        } else if self.mc.typeck_results.closure_captures.contains_key(&closure_def_id) {
-            // Handle the case where clippy calls ExprUseVisitor after
-            self.walk_captures_closure_captures(closure_expr)
         }
     }
-
-    fn cat_captured_var(
-        &mut self,
-        closure_hir_id: hir::HirId,
-        closure_span: Span,
-        var_id: hir::HirId,
-    ) -> mc::McResult<PlaceWithHirId<'tcx>> {
-        // Create the place for the variable being borrowed, from the
-        // perspective of the creator (parent) of the closure.
-        let var_ty = self.mc.node_ty(var_id)?;
-        self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id))
-    }
 }
 
 fn copy_or_move<'a, 'tcx>(