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.rs3
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs1
-rw-r--r--compiler/rustc_ast/src/visit.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs19
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs4
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs6
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/analyze.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs55
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs23
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs13
-rw-r--r--compiler/rustc_data_structures/src/functor.rs82
-rw-r--r--compiler/rustc_data_structures/src/lib.rs15
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs22
-rw-r--r--compiler/rustc_data_structures/src/steal.rs (renamed from compiler/rustc_middle/src/ty/steal.rs)11
-rw-r--r--compiler/rustc_driver/src/lib.rs21
-rw-r--r--compiler/rustc_driver/src/pretty.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0744.md19
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs18
-rw-r--r--compiler/rustc_errors/src/emitter.rs17
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_feature/src/lib.rs42
-rw-r--r--compiler/rustc_hir/src/hir.rs8
-rw-r--r--compiler/rustc_incremental/src/persist/file_format.rs12
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs19
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs12
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs18
-rw-r--r--compiler/rustc_infer/src/infer/canonical/substitute.rs12
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs36
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs9
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs2
-rw-r--r--compiler/rustc_infer/src/infer/fudge.rs2
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs9
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs26
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs7
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs4
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs4
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs13
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs6
-rw-r--r--compiler/rustc_infer/src/traits/util.rs2
-rw-r--r--compiler/rustc_interface/src/lib.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs10
-rw-r--r--compiler/rustc_interface/src/queries.rs2
-rw-r--r--compiler/rustc_interface/src/util.rs25
-rw-r--r--compiler/rustc_lint/src/types.rs22
-rw-r--r--compiler/rustc_macros/src/type_foldable.rs18
-rw-r--r--compiler/rustc_middle/src/arena.rs4
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs43
-rw-r--r--compiler/rustc_middle/src/ich/impls_ty.rs9
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs4
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/macros.rs18
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs5
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs38
-rw-r--r--compiler/rustc_middle/src/mir/predecessors.rs2
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs126
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs124
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs2
-rw-r--r--compiler/rustc_middle/src/ty/binding.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs20
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs10
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs150
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs12
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs62
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs6
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs206
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs20
-rw-r--r--compiler/rustc_middle/src/ty/util.rs33
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs27
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/mod.rs6
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs6
-rw-r--r--compiler/rustc_mir/src/borrow_check/renumber.rs8
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/input_output.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs12
-rw-r--r--compiler/rustc_mir/src/borrow_check/universal_regions.rs20
-rw-r--r--compiler/rustc_mir/src/dataflow/drop_flag_effects.rs2
-rw-r--r--compiler/rustc_mir/src/interpret/eval_context.rs2
-rw-r--r--compiler/rustc_mir/src/interpret/traits.rs6
-rw-r--r--compiler/rustc_mir/src/interpret/util.rs6
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs4
-rw-r--r--compiler/rustc_mir/src/monomorphize/partitioning/default.rs2
-rw-r--r--compiler/rustc_mir/src/monomorphize/polymorphize.rs10
-rw-r--r--compiler/rustc_mir/src/shim.rs10
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/ops.rs3
-rw-r--r--compiler/rustc_mir/src/transform/generator.rs6
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs41
-rw-r--r--compiler/rustc_mir/src/transform/mod.rs2
-rw-r--r--compiler/rustc_mir/src/transform/validate.rs7
-rw-r--r--compiler/rustc_mir/src/util/pretty.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/_match.rs115
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs140
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs44
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs3
-rw-r--r--compiler/rustc_passes/src/check_const.rs3
-rw-r--r--compiler/rustc_passes/src/liveness.rs69
-rw-r--r--compiler/rustc_privacy/src/lib.rs35
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs4
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs5
-rw-r--r--compiler/rustc_resolve/src/lib.rs27
-rw-r--r--compiler/rustc_resolve/src/macros.rs27
-rw-r--r--compiler/rustc_session/src/config.rs22
-rw-r--r--compiler/rustc_session/src/parse.rs6
-rw-r--r--compiler/rustc_session/src/session.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs2
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs6
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs8
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs48
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs61
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs37
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs53
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs2
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs4
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs36
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs2
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs6
-rw-r--r--compiler/rustc_traits/src/type_op.rs4
-rw-r--r--compiler/rustc_ty/src/instance.rs10
-rw-r--r--compiler/rustc_ty/src/needs_drop.rs2
-rw-r--r--compiler/rustc_ty/src/ty.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs207
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs224
-rw-r--r--compiler/rustc_typeck/src/check/_match.rs2
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs6
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs14
-rw-r--r--compiler/rustc_typeck/src/check/check.rs27
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs18
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs10
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs22
-rw-r--r--compiler/rustc_typeck/src/check/dropck.rs4
-rw-r--r--compiler/rustc_typeck/src/check/expectation.rs6
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs12
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs187
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs10
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs4
-rw-r--r--compiler/rustc_typeck/src/check/gather_locals.rs9
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs8
-rw-r--r--compiler/rustc_typeck/src/check/inherited.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/confirm.rs89
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs8
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs41
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs4
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs12
-rw-r--r--compiler/rustc_typeck/src/check/op.rs4
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs10
-rw-r--r--compiler/rustc_typeck/src/check/regionck.rs2
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs723
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs58
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs39
-rw-r--r--compiler/rustc_typeck/src/collect.rs6
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs2
-rw-r--r--compiler/rustc_typeck/src/constrained_generic_params.rs6
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs136
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs2
-rw-r--r--compiler/rustc_typeck/src/lib.rs1
-rw-r--r--compiler/rustc_typeck/src/mem_categorization.rs6
224 files changed, 2964 insertions, 1902 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 3e953729aab..328086af183 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1192,6 +1192,7 @@ impl Expr {
             ExprKind::Field(..) => ExprPrecedence::Field,
             ExprKind::Index(..) => ExprPrecedence::Index,
             ExprKind::Range(..) => ExprPrecedence::Range,
+            ExprKind::Underscore => ExprPrecedence::Path,
             ExprKind::Path(..) => ExprPrecedence::Path,
             ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
             ExprKind::Break(..) => ExprPrecedence::Break,
@@ -1324,6 +1325,8 @@ pub enum ExprKind {
     Index(P<Expr>, P<Expr>),
     /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment).
     Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
+    /// An underscore, used in destructuring assignment to ignore a value.
+    Underscore,
 
     /// Variable reference, possibly containing `::` and/or type
     /// parameters (e.g., `foo::bar::<baz>`).
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 26097980e8b..ddae0ab03e4 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1232,6 +1232,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             visit_opt(e1, |e1| vis.visit_expr(e1));
             visit_opt(e2, |e2| vis.visit_expr(e2));
         }
+        ExprKind::Underscore => {}
         ExprKind::Path(qself, path) => {
             vis.visit_qself(qself);
             vis.visit_path(path);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 49b521afcdc..560064182e1 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -806,6 +806,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             walk_list!(visitor, visit_expr, start);
             walk_list!(visitor, visit_expr, end);
         }
+        ExprKind::Underscore => {}
         ExprKind::Path(ref maybe_qself, ref path) => {
             if let Some(ref qself) = *maybe_qself {
                 visitor.visit_ty(&qself.ty);
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index b94fb1d8437..f83fc29577b 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -164,6 +164,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ExprKind::Range(ref e1, ref e2, lims) => {
                     self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
                 }
+                ExprKind::Underscore => {
+                    self.sess
+                        .struct_span_err(
+                            e.span,
+                            "in expressions, `_` can only be used on the left-hand side of an assignment",
+                        )
+                        .span_label(e.span, "`_` not allowed here")
+                        .emit();
+                    hir::ExprKind::Err
+                }
                 ExprKind::Path(ref qself, ref path) => {
                     let qpath = self.lower_qpath(
                         e.id,
@@ -863,7 +873,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // Return early in case of an ordinary assignment.
         fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
             match &lhs.kind {
-                ExprKind::Array(..) | ExprKind::Struct(..) | ExprKind::Tup(..) => false,
+                ExprKind::Array(..)
+                | ExprKind::Struct(..)
+                | ExprKind::Tup(..)
+                | ExprKind::Underscore => false,
                 // Check for tuple struct constructor.
                 ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),
                 ExprKind::Paren(e) => {
@@ -943,6 +956,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
         assignments: &mut Vec<hir::Stmt<'hir>>,
     ) -> &'hir hir::Pat<'hir> {
         match &lhs.kind {
+            // Underscore pattern.
+            ExprKind::Underscore => {
+                return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);
+            }
             // Slice patterns.
             ExprKind::Array(elements) => {
                 let (pats, rest) =
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 88ad2706eac..d93655e5905 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -53,7 +53,6 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
 use rustc_hir::intravisit;
 use rustc_hir::{ConstArg, GenericArg, ParamName};
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_session::config::nightly_options;
 use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::parse::ParseSess;
 use rustc_session::Session;
@@ -1398,8 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             "`impl Trait` not allowed outside of {}",
                             allowed_in,
                         );
-                        if pos == ImplTraitPosition::Binding && nightly_options::is_nightly_build()
-                        {
+                        if pos == ImplTraitPosition::Binding && self.sess.is_nightly_build() {
                             err.help(
                                 "add `#![feature(impl_trait_in_bindings)]` to the crate \
                                    attributes to enable",
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 2831675cb36..181783441f3 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -630,7 +630,11 @@ 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!(destructuring_assignment, "destructuring assignments 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.
+        gate_all!(destructuring_assignment, "destructuring assignments are unstable");
+    }
 
     // All uses of `gate_all!` below this point were added in #65742,
     // and subsequently disabled (with the non-early gating readded).
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 958219cbebf..fdb129d9e2a 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -109,7 +109,6 @@ pub fn print_crate<'a>(
     ann: &'a dyn PpAnn,
     is_expanded: bool,
     edition: Edition,
-    has_injected_crate: bool,
 ) -> String {
     let mut s = State {
         s: pp::mk_printer(),
@@ -119,7 +118,7 @@ pub fn print_crate<'a>(
         insert_extra_parens: true,
     };
 
-    if is_expanded && has_injected_crate {
+    if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
         // We need to print `#![no_std]` (and its feature gate) so that
         // compiling pretty-printed source won't inject libstd again.
         // However, we don't want these attributes in the AST because
@@ -2068,6 +2067,7 @@ impl<'a> State<'a> {
                     self.print_expr_maybe_paren(e, fake_prec);
                 }
             }
+            ast::ExprKind::Underscore => self.s.word("_"),
             ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
             ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
             ast::ExprKind::Break(opt_label, ref opt_expr) => {
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index e801b5c7b0c..91566ec1ef2 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -13,12 +13,12 @@ pub fn inject(
     resolver: &mut dyn ResolverExpand,
     sess: &Session,
     alt_std_name: Option<Symbol>,
-) -> (ast::Crate, Option<Symbol>) {
+) -> ast::Crate {
     let rust_2018 = sess.parse_sess.edition >= Edition::Edition2018;
 
     // the first name in this list is the crate name of the crate with the prelude
     let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) {
-        return (krate, None);
+        return krate;
     } else if sess.contains_name(&krate.attrs, sym::no_std) {
         if sess.contains_name(&krate.attrs, sym::compiler_builtins) {
             &[sym::core]
@@ -81,5 +81,5 @@ pub fn inject(
 
     krate.module.items.insert(0, use_item);
 
-    (krate, Some(name))
+    krate
 }
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 81091728692..ac076789f2e 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -216,7 +216,7 @@ pub(crate) fn get_function_name_and_sig<'tcx>(
     assert!(!inst.substs.needs_infer());
     let fn_sig = tcx.normalize_erasing_late_bound_regions(
         ParamEnv::reveal_all(),
-        &fn_sig_for_fn_abi(tcx, inst),
+        fn_sig_for_fn_abi(tcx, inst),
     );
     if fn_sig.c_variadic && !support_vararg {
         tcx.sess.span_fatal(
@@ -372,7 +372,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>(
         .mir
         .args_iter()
         .map(|local| {
-            let arg_ty = fx.monomorphize(&fx.mir.local_decls[local].ty);
+            let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty);
 
             // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
             if Some(local) == fx.mir.spread_arg {
@@ -470,7 +470,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>(
     }
 
     for local in fx.mir.vars_and_temps_iter() {
-        let ty = fx.monomorphize(&fx.mir.local_decls[local].ty);
+        let ty = fx.monomorphize(fx.mir.local_decls[local].ty);
         let layout = fx.layout_of(ty);
 
         let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa;
@@ -492,10 +492,10 @@ pub(crate) fn codegen_terminator_call<'tcx>(
     args: &[Operand<'tcx>],
     destination: Option<(Place<'tcx>, BasicBlock)>,
 ) {
-    let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx));
+    let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
     let fn_sig = fx
         .tcx
-        .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx));
+        .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
 
     let destination = destination.map(|(place, bb)| (codegen_place(fx, place), bb));
 
@@ -711,7 +711,7 @@ pub(crate) fn codegen_drop<'tcx>(
         let drop_fn_ty = drop_fn.ty(fx.tcx, ParamEnv::reveal_all());
         let fn_sig = fx.tcx.normalize_erasing_late_bound_regions(
             ParamEnv::reveal_all(),
-            &drop_fn_ty.fn_sig(fx.tcx),
+            drop_fn_ty.fn_sig(fx.tcx),
         );
         assert_eq!(fn_sig.output(), fx.tcx.mk_unit());
 
diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs
index fd25b19a583..adf5c7ac4fe 100644
--- a/compiler/rustc_codegen_cranelift/src/analyze.rs
+++ b/compiler/rustc_codegen_cranelift/src/analyze.rs
@@ -17,7 +17,7 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, impl Module>) -> IndexVec<Local, S
         .local_decls
         .iter()
         .map(|local_decl| {
-            let ty = fx.monomorphize(&local_decl.ty);
+            let ty = fx.monomorphize(local_decl.ty);
             if fx.clif_type(ty).is_some() || fx.clif_pair_type(ty).is_some() {
                 SsaKind::Ssa
             } else {
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index bfe5514b6d3..a4df371c88a 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -445,43 +445,43 @@ fn codegen_stmt<'tcx>(
         StatementKind::Assign(to_place_and_rval) => {
             let lval = codegen_place(fx, to_place_and_rval.0);
             let dest_layout = lval.layout();
-            match &to_place_and_rval.1 {
-                Rvalue::Use(operand) => {
+            match to_place_and_rval.1 {
+                Rvalue::Use(ref operand) => {
                     let val = codegen_operand(fx, operand);
                     lval.write_cvalue(fx, val);
                 }
                 Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
-                    let place = codegen_place(fx, *place);
+                    let place = codegen_place(fx, place);
                     let ref_ = place.place_ref(fx, lval.layout());
                     lval.write_cvalue(fx, ref_);
                 }
                 Rvalue::ThreadLocalRef(def_id) => {
-                    let val = crate::constant::codegen_tls_ref(fx, *def_id, lval.layout());
+                    let val = crate::constant::codegen_tls_ref(fx, def_id, lval.layout());
                     lval.write_cvalue(fx, val);
                 }
-                Rvalue::BinaryOp(bin_op, lhs, rhs) => {
+                Rvalue::BinaryOp(bin_op, ref lhs, ref rhs) => {
                     let lhs = codegen_operand(fx, lhs);
                     let rhs = codegen_operand(fx, rhs);
 
-                    let res = crate::num::codegen_binop(fx, *bin_op, lhs, rhs);
+                    let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs);
                     lval.write_cvalue(fx, res);
                 }
-                Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => {
+                Rvalue::CheckedBinaryOp(bin_op, ref lhs, ref rhs) => {
                     let lhs = codegen_operand(fx, lhs);
                     let rhs = codegen_operand(fx, rhs);
 
                     let res = if !fx.tcx.sess.overflow_checks() {
                         let val =
-                            crate::num::codegen_int_binop(fx, *bin_op, lhs, rhs).load_scalar(fx);
+                            crate::num::codegen_int_binop(fx, bin_op, lhs, rhs).load_scalar(fx);
                         let is_overflow = fx.bcx.ins().iconst(types::I8, 0);
                         CValue::by_val_pair(val, is_overflow, lval.layout())
                     } else {
-                        crate::num::codegen_checked_int_binop(fx, *bin_op, lhs, rhs)
+                        crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs)
                     };
 
                     lval.write_cvalue(fx, res);
                 }
-                Rvalue::UnaryOp(un_op, operand) => {
+                Rvalue::UnaryOp(un_op, ref operand) => {
                     let operand = codegen_operand(fx, operand);
                     let layout = operand.layout();
                     let val = operand.load_scalar(fx);
@@ -509,8 +509,8 @@ fn codegen_stmt<'tcx>(
                     };
                     lval.write_cvalue(fx, res);
                 }
-                Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), operand, to_ty) => {
-                    let from_ty = fx.monomorphize(&operand.ty(&fx.mir.local_decls, fx.tcx));
+                Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), ref operand, to_ty) => {
+                    let from_ty = fx.monomorphize(operand.ty(&fx.mir.local_decls, fx.tcx));
                     let to_layout = fx.layout_of(fx.monomorphize(to_ty));
                     match *from_ty.kind() {
                         ty::FnDef(def_id, substs) => {
@@ -530,14 +530,14 @@ fn codegen_stmt<'tcx>(
                         _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", from_ty),
                     }
                 }
-                Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), operand, to_ty)
-                | Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, to_ty)
-                | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, to_ty) => {
+                Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), ref operand, to_ty)
+                | Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), ref operand, to_ty)
+                | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), ref operand, to_ty) => {
                     let to_layout = fx.layout_of(fx.monomorphize(to_ty));
                     let operand = codegen_operand(fx, operand);
                     lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
                 }
-                Rvalue::Cast(CastKind::Misc, operand, to_ty) => {
+                Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => {
                     let operand = codegen_operand(fx, operand);
                     let from_ty = operand.layout().ty;
                     let to_ty = fx.monomorphize(to_ty);
@@ -577,12 +577,12 @@ fn codegen_stmt<'tcx>(
 
                         use rustc_target::abi::{Int, TagEncoding, Variants};
 
-                        match &operand.layout().variants {
+                        match operand.layout().variants {
                             Variants::Single { index } => {
                                 let discr = operand
                                     .layout()
                                     .ty
-                                    .discriminant_for_variant(fx.tcx, *index)
+                                    .discriminant_for_variant(fx.tcx, index)
                                     .unwrap();
                                 let discr = if discr.ty.is_signed() {
                                     fx.layout_of(discr.ty).size.sign_extend(discr.val)
@@ -595,7 +595,7 @@ fn codegen_stmt<'tcx>(
                                 lval.write_cvalue(fx, discr);
                             }
                             Variants::Multiple {
-                                tag,
+                                ref tag,
                                 tag_field,
                                 tag_encoding: TagEncoding::Direct,
                                 variants: _,
@@ -604,7 +604,7 @@ fn codegen_stmt<'tcx>(
 
                                 // Read the tag/niche-encoded discriminant from memory.
                                 let encoded_discr =
-                                    operand.value_field(fx, mir::Field::new(*tag_field));
+                                    operand.value_field(fx, mir::Field::new(tag_field));
                                 let encoded_discr = encoded_discr.load_scalar(fx);
 
                                 // Decode the discriminant (specifically if it's niche-encoded).
@@ -634,7 +634,7 @@ fn codegen_stmt<'tcx>(
                 }
                 Rvalue::Cast(
                     CastKind::Pointer(PointerCast::ClosureFnPointer(_)),
-                    operand,
+                    ref operand,
                     _to_ty,
                 ) => {
                     let operand = codegen_operand(fx, operand);
@@ -654,18 +654,18 @@ fn codegen_stmt<'tcx>(
                         _ => bug!("{} cannot be cast to a fn ptr", operand.layout().ty),
                     }
                 }
-                Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, _to_ty) => {
+                Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref operand, _to_ty) => {
                     let operand = codegen_operand(fx, operand);
                     operand.unsize_value(fx, lval);
                 }
                 Rvalue::Discriminant(place) => {
-                    let place = codegen_place(fx, *place);
+                    let place = codegen_place(fx, place);
                     let value = place.to_cvalue(fx);
                     let discr =
                         crate::discriminant::codegen_get_discriminant(fx, value, dest_layout);
                     lval.write_cvalue(fx, discr);
                 }
-                Rvalue::Repeat(operand, times) => {
+                Rvalue::Repeat(ref operand, times) => {
                     let operand = codegen_operand(fx, operand);
                     let times = fx
                         .monomorphize(times)
@@ -704,7 +704,7 @@ fn codegen_stmt<'tcx>(
                     }
                 }
                 Rvalue::Len(place) => {
-                    let place = codegen_place(fx, *place);
+                    let place = codegen_place(fx, place);
                     let usize_layout = fx.layout_of(fx.tcx.types.usize);
                     let len = codegen_array_len(fx, place);
                     lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
@@ -749,7 +749,7 @@ fn codegen_stmt<'tcx>(
                         CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), ty_size.into());
                     lval.write_cvalue(fx, val);
                 }
-                Rvalue::Aggregate(kind, operands) => match **kind {
+                Rvalue::Aggregate(ref kind, ref operands) => match kind.as_ref() {
                     AggregateKind::Array(_ty) => {
                         for (i, operand) in operands.iter().enumerate() {
                             let operand = codegen_operand(fx, operand);
@@ -877,8 +877,7 @@ fn codegen_array_len<'tcx>(
     match *place.layout().ty.kind() {
         ty::Array(_elem_ty, len) => {
             let len = fx
-                .monomorphize(&len)
-                .eval(fx.tcx, ParamEnv::reveal_all())
+                .monomorphize(len)
                 .eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
             fx.bcx.ins().iconst(fx.pointer_type, len)
         }
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 466758f2f86..d7d6c3e1677 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -357,7 +357,7 @@ impl<'tcx, M: Module> HasTargetSpec for FunctionCx<'_, 'tcx, M> {
 }
 
 impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> {
-    pub(crate) fn monomorphize<T>(&self, value: &T) -> T
+    pub(crate) fn monomorphize<T>(&self, value: T) -> T
     where
         T: TypeFoldable<'tcx> + Copy,
     {
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 41cfae4ca6e..351bb6ecd23 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -38,7 +38,7 @@ impl ConstantCx {
 
 pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, impl Module>) {
     for constant in &fx.mir.required_consts {
-        let const_ = fx.monomorphize(&constant.literal);
+        let const_ = fx.monomorphize(constant.literal);
         match const_.val {
             ConstKind::Value(_) => {}
             ConstKind::Unevaluated(def, ref substs, promoted) => {
@@ -110,7 +110,7 @@ pub(crate) fn codegen_constant<'tcx>(
     fx: &mut FunctionCx<'_, 'tcx, impl Module>,
     constant: &Constant<'tcx>,
 ) -> CValue<'tcx> {
-    let const_ = fx.monomorphize(&constant.literal);
+    let const_ = fx.monomorphize(constant.literal);
     let const_val = match const_.val {
         ConstKind::Value(const_val) => const_val,
         ConstKind::Unevaluated(def, ref substs, promoted) if fx.tcx.is_static(def.did) => {
@@ -466,7 +466,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
     match operand {
         Operand::Copy(_) | Operand::Move(_) => None,
         Operand::Constant(const_) => Some(
-            fx.monomorphize(&const_.literal)
+            fx.monomorphize(const_.literal)
                 .eval(fx.tcx, ParamEnv::reveal_all()),
         ),
     }
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index 85e8158af27..a6f4ded41b6 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -365,7 +365,7 @@ impl<'tcx> DebugContext<'tcx> {
                 let ty = self.tcx.subst_and_normalize_erasing_regions(
                     instance.substs,
                     ty::ParamEnv::reveal_all(),
-                    &mir.local_decls[local].ty,
+                    mir.local_decls[local].ty,
                 );
                 let var_id = self.define_local(entry_id, format!("{:?}", local), ty);
 
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 10f515e38ea..6c472e6774f 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -50,7 +50,7 @@ pub(crate) fn maybe_create_entry_wrapper(
         // late-bound regions, since late-bound
         // regions must appear in the argument
         // listing.
-        let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());
+        let main_ret_ty = tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap());
 
         let cmain_sig = Signature {
             params: vec![
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index ff878af7f5e..a9f060e51d8 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -80,7 +80,7 @@ impl CommentWriter {
                     "sig {:?}",
                     tcx.normalize_erasing_late_bound_regions(
                         ParamEnv::reveal_all(),
-                        &crate::abi::fn_sig_for_fn_abi(tcx, instance)
+                        crate::abi::fn_sig_for_fn_abi(tcx, instance)
                     )
                 ),
                 String::new(),
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 0000866c4f6..cb40d4ed9a6 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -455,7 +455,7 @@ impl<'tcx> CPlace<'tcx> {
             from_ty: Ty<'tcx>,
             to_ty: Ty<'tcx>,
         ) {
-            match (&from_ty.kind(), &to_ty.kind()) {
+            match (from_ty.kind(), to_ty.kind()) {
                 (ty::Ref(_, a, _), ty::Ref(_, b, _))
                 | (
                     ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }),
@@ -466,11 +466,11 @@ impl<'tcx> CPlace<'tcx> {
                 (ty::FnPtr(_), ty::FnPtr(_)) => {
                     let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
                         ParamEnv::reveal_all(),
-                        &from_ty.fn_sig(fx.tcx),
+                        from_ty.fn_sig(fx.tcx),
                     );
                     let to_sig = fx.tcx.normalize_erasing_late_bound_regions(
                         ParamEnv::reveal_all(),
-                        &to_ty.fn_sig(fx.tcx),
+                        to_ty.fn_sig(fx.tcx),
                     );
                     assert_eq!(
                         from_sig, to_sig,
@@ -479,7 +479,7 @@ impl<'tcx> CPlace<'tcx> {
                     );
                     // fn(&T) -> for<'l> fn(&'l T) is allowed
                 }
-                (ty::Dynamic(from_traits, _), ty::Dynamic(to_traits, _)) => {
+                (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => {
                     let from_traits = fx
                         .tcx
                         .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from_traits);
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index e06e2d45665..9a2fbf359ea 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -25,7 +25,7 @@ use crate::value::Value;
 
 /// Mark LLVM function to use provided inline heuristic.
 #[inline]
-fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
+fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr, requires_inline: bool) {
     use self::InlineAttr::*;
     match inline {
         Hint => Attribute::InlineHint.apply_llfn(Function, val),
@@ -35,11 +35,8 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
                 Attribute::NoInline.apply_llfn(Function, val);
             }
         }
-        None => {
-            Attribute::InlineHint.unapply_llfn(Function, val);
-            Attribute::AlwaysInline.unapply_llfn(Function, val);
-            Attribute::NoInline.unapply_llfn(Function, val);
-        }
+        None if requires_inline => Attribute::InlineHint.apply_llfn(Function, val),
+        None => {}
     };
 }
 
@@ -229,12 +226,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
         }
     }
 
-    // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites).
-    if instance.def.requires_inline(cx.tcx) {
-        inline(cx, llfn, attributes::InlineAttr::Hint);
-    }
-
-    inline(cx, llfn, codegen_fn_attrs.inline.clone());
+    inline(cx, llfn, codegen_fn_attrs.inline.clone(), instance.def.requires_inline(cx.tcx));
 
     // The `uwtable` attribute according to LLVM is:
     //
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 1090d4a25c7..7d01f6a5499 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -97,14 +97,12 @@ pub fn compile_codegen_unit(
     tcx: TyCtxt<'tcx>,
     cgu_name: Symbol,
 ) -> (ModuleCodegen<ModuleLlvm>, u64) {
-    let prof_timer = tcx.prof.generic_activity_with_arg("codegen_module", cgu_name.to_string());
     let start_time = Instant::now();
 
     let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
     let (module, _) =
         tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
     let time_to_codegen = start_time.elapsed();
-    drop(prof_timer);
 
     // We assume that the cost to run LLVM on a CGU is proportional to
     // the time we needed for codegenning it.
@@ -112,6 +110,10 @@ pub fn compile_codegen_unit(
 
     fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> {
         let cgu = tcx.codegen_unit(cgu_name);
+        let _prof_timer = tcx.prof.generic_activity_with_args(
+            "codegen_module",
+            &[cgu_name.to_string(), cgu.size_estimate().to_string()],
+        );
         // Instantiate monomorphizations without filling out definitions yet...
         let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
         {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index 6737872f203..7673dfb744c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -92,7 +92,7 @@ fn make_mir_scope(
             let callee = cx.tcx.subst_and_normalize_erasing_regions(
                 instance.substs,
                 ty::ParamEnv::reveal_all(),
-                &callee,
+                callee,
             );
             let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]);
             cx.dbg_scope_fn(callee, &callee_fn_abi, None)
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 27b81ebcff6..5e8ff14f0aa 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -189,7 +189,7 @@ impl TypeMap<'ll, 'tcx> {
         // something that provides more than the 64 bits of the DefaultHasher.
         let mut hasher = StableHasher::new();
         let mut hcx = cx.tcx.create_stable_hashing_context();
-        let type_ = cx.tcx.erase_regions(&type_);
+        let type_ = cx.tcx.erase_regions(type_);
         hcx.while_hashing_spans(false, |hcx| {
             hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
                 type_.hash_stable(hcx, &mut hasher);
@@ -427,7 +427,7 @@ fn subroutine_type_metadata(
     span: Span,
 ) -> MetadataCreationResult<'ll> {
     let signature =
-        cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &signature);
+        cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), signature);
 
     let signature_metadata: Vec<_> = iter::once(
         // return type
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 5065ff01aed..ccbe7325cc6 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -501,7 +501,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
                         instance.substs,
                         ty::ParamEnv::reveal_all(),
-                        &cx.tcx.type_of(impl_def_id),
+                        cx.tcx.type_of(impl_def_id),
                     );
 
                     // Only "class" methods are generally understood by LLVM,
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index d52b3be8cd3..ac423d01bf1 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -91,7 +91,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
         };
 
         let sig = callee_ty.fn_sig(tcx);
-        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
         let arg_tys = sig.inputs();
         let ret_ty = sig.output();
         let name = tcx.item_name(def_id);
@@ -777,8 +777,8 @@ fn generic_simd_intrinsic(
     }
 
     let tcx = bx.tcx();
-    let sig = tcx
-        .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &callee_ty.fn_sig(tcx));
+    let sig =
+        tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
     let arg_tys = sig.inputs();
     let name_str = &*name.as_str();
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index cc71b6289fa..a3139ce5a34 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -3,7 +3,6 @@ use crate::llvm;
 use libc::c_int;
 use rustc_codegen_ssa::target_features::supported_target_features;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_feature::UnstableFeatures;
 use rustc_middle::bug;
 use rustc_session::config::PrintRequest;
 use rustc_session::Session;
@@ -130,6 +129,13 @@ pub fn time_trace_profiler_finish(file_name: &str) {
 // WARNING: the features after applying `to_llvm_feature` must be known
 // to LLVM or the feature detection code will walk past the end of the feature
 // array, leading to crashes.
+// To find a list of LLVM's names, check llvm-project/llvm/include/llvm/Support/*TargetParser.def
+// where the * matches the architecture's name
+// Beware to not use the llvm github project for this, but check the git submodule
+// found in src/llvm-project
+// Though note that Rust can also be build with an external precompiled version of LLVM
+// which might lead to failures if the oldest tested / supported LLVM version
+// doesn't yet support the relevant intrinsics
 pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
     let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
     match (arch, s) {
@@ -137,6 +143,9 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
         ("x86", "rdrand") => "rdrnd",
         ("x86", "bmi1") => "bmi",
         ("x86", "cmpxchg16b") => "cx16",
+        ("x86", "avx512vaes") => "vaes",
+        ("x86", "avx512gfni") => "gfni",
+        ("x86", "avx512vpclmulqdq") => "vpclmulqdq",
         ("aarch64", "fp") => "fp-armv8",
         ("aarch64", "fp16") => "fullfp16",
         (_, s) => s,
@@ -147,13 +156,11 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
     let target_machine = create_informational_target_machine(sess);
     supported_target_features(sess)
         .iter()
-        .filter_map(|&(feature, gate)| {
-            if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
-                Some(feature)
-            } else {
-                None
-            }
-        })
+        .filter_map(
+            |&(feature, gate)| {
+                if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
+            },
+        )
         .filter(|feature| {
             let llvm_feature = to_llvm_feature(sess, feature);
             let cstr = CString::new(llvm_feature).unwrap();
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index e0754d21df1..8ea4768f77d 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -252,7 +252,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
 
         // Make sure lifetimes are erased, to avoid generating distinct LLVM
         // types for Rust types that only differ in the choice of lifetimes.
-        let normal_ty = cx.tcx.erase_regions(&self.ty);
+        let normal_ty = cx.tcx.erase_regions(self.ty);
 
         let mut defer = None;
         let llty = if self.ty != normal_ty {
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 5fe26dbf914..21138f967a2 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -399,7 +399,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         // late-bound regions, since late-bound
         // regions must appear in the argument
         // listing.
-        let main_ret_ty = cx.tcx().erase_regions(&main_ret_ty.no_bound_vars().unwrap());
+        let main_ret_ty = cx.tcx().erase_regions(main_ret_ty.no_bound_vars().unwrap());
 
         let llfn = match cx.declare_c_main(llfty) {
             Some(llfn) => llfn,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 0b49a379070..896af8a9191 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -120,8 +120,8 @@ pub fn push_debuginfo_type_name<'tcx>(
         }
         ty::Dynamic(ref trait_data, ..) => {
             if let Some(principal) = trait_data.principal() {
-                let principal = tcx
-                    .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &principal);
+                let principal =
+                    tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal);
                 push_item_name(tcx, principal.def_id, false, output);
                 push_type_params(tcx, principal.substs, output, visited);
             } else {
@@ -159,7 +159,7 @@ pub fn push_debuginfo_type_name<'tcx>(
 
             output.push_str("fn(");
 
-            let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+            let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
             if !sig.inputs().is_empty() {
                 for &parameter_type in sig.inputs() {
                     push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index bdde07d3fa9..44bb0deeae9 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -24,7 +24,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     analyzer.visit_body(&mir);
 
     for (local, decl) in mir.local_decls.iter_enumerated() {
-        let ty = fx.monomorphize(&decl.ty);
+        let ty = fx.monomorphize(decl.ty);
         debug!("local {:?} has type `{}`", local, ty);
         let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
         if fx.cx.is_backend_immediate(layout) {
@@ -121,10 +121,10 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
             if is_consume {
                 let base_ty =
                     mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx());
-                let base_ty = self.fx.monomorphize(&base_ty);
+                let base_ty = self.fx.monomorphize(base_ty);
 
                 // ZSTs don't require any actual memory access.
-                let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(&elem)).ty;
+                let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(elem)).ty;
                 let span = self.fx.mir.local_decls[place_ref.local].source_info.span;
                 if cx.spanned_layout_of(elem_ty, span).is_zst() {
                     return;
@@ -313,7 +313,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
 
             PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
                 let ty = self.fx.mir.local_decls[local].ty;
-                let ty = self.fx.monomorphize(&ty);
+                let ty = self.fx.monomorphize(ty);
 
                 // Only need the place if we're actually dropping it.
                 if self.fx.cx.type_needs_drop(ty) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index da4637b1afc..ee40095883d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -306,7 +306,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         unwind: Option<mir::BasicBlock>,
     ) {
         let ty = location.ty(self.mir, bx.tcx()).ty;
-        let ty = self.monomorphize(&ty);
+        let ty = self.monomorphize(ty);
         let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
 
         if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
@@ -576,7 +576,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             .iter()
             .map(|op_arg| {
                 let op_ty = op_arg.ty(self.mir, bx.tcx());
-                self.monomorphize(&op_ty)
+                self.monomorphize(op_ty)
             })
             .collect::<Vec<_>>();
 
@@ -900,7 +900,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     }
                 }
                 mir::InlineAsmOperand::SymFn { ref value } => {
-                    let literal = self.monomorphize(&value.literal);
+                    let literal = self.monomorphize(value.literal);
                     if let ty::FnDef(def_id, substs) = *literal.ty.kind() {
                         let instance = ty::Instance::resolve_for_fn_ptr(
                             bx.tcx(),
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 4943e279c7e..c8001b8daf0 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -16,7 +16,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         constant: &mir::Constant<'tcx>,
     ) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
         let val = self.eval_mir_constant(constant)?;
-        let ty = self.monomorphize(&constant.literal.ty);
+        let ty = self.monomorphize(constant.literal.ty);
         Ok(OperandRef::from_const(bx, val, ty))
     }
 
@@ -24,7 +24,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         &mut self,
         constant: &mir::Constant<'tcx>,
     ) -> Result<ConstValue<'tcx>, ErrorHandled> {
-        match self.monomorphize(&constant.literal).val {
+        match self.monomorphize(constant.literal).val {
             ty::ConstKind::Unevaluated(def, substs, promoted) => self
                 .cx
                 .tcx()
@@ -83,7 +83,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             .unwrap_or_else(|_| {
                 bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
                 // We've errored, so we don't have to produce working code.
-                let ty = self.monomorphize(&ty);
+                let ty = self.monomorphize(ty);
                 let llty = bx.backend_type(bx.layout_of(ty));
                 (bx.const_undef(llty), ty)
             })
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 4e0396a15a6..c4191a4e23d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -160,7 +160,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             // FIXME(eddyb) is this `+ 1` needed at all?
                             let kind = VariableKind::ArgumentVariable(arg_index + 1);
 
-                            let arg_ty = self.monomorphize(&decl.ty);
+                            let arg_ty = self.monomorphize(decl.ty);
 
                             self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span)
                         },
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 2bf1ee43c73..94340e92048 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -64,7 +64,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         };
 
         let sig = callee_ty.fn_sig(bx.tcx());
-        let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+        let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
         let arg_tys = sig.inputs();
         let ret_ty = sig.output();
         let name = bx.tcx().item_name(def_id);
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 01fd1681593..640f805d5e8 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -87,7 +87,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 }
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
-    pub fn monomorphize<T>(&self, value: &T) -> T
+    pub fn monomorphize<T>(&self, value: T) -> T
     where
         T: Copy + TypeFoldable<'tcx>,
     {
@@ -208,7 +208,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
         let mut allocate_local = |local| {
             let decl = &mir.local_decls[local];
-            let layout = bx.layout_of(fx.monomorphize(&decl.ty));
+            let layout = bx.layout_of(fx.monomorphize(decl.ty));
             assert!(!layout.ty.has_erasable_regions());
 
             if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
@@ -364,7 +364,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 // to reconstruct it into a tuple local variable, from multiple
                 // individual LLVM function arguments.
 
-                let arg_ty = fx.monomorphize(&arg_decl.ty);
+                let arg_ty = fx.monomorphize(arg_decl.ty);
                 let tupled_arg_tys = match arg_ty.kind() {
                     ty::Tuple(tys) => tys,
                     _ => bug!("spread argument isn't a tuple?!"),
@@ -385,7 +385,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             }
 
             if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
-                let arg_ty = fx.monomorphize(&arg_decl.ty);
+                let arg_ty = fx.monomorphize(arg_decl.ty);
 
                 let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
                 bx.va_start(va_list.llval);
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index bbd004be875..08a4ae3962b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -452,7 +452,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     bx.abort();
                     // We still have to return an operand but it doesn't matter,
                     // this code is unreachable.
-                    let ty = self.monomorphize(&constant.literal.ty);
+                    let ty = self.monomorphize(constant.literal.ty);
                     let layout = bx.cx().layout_of(ty);
                     bx.load_operand(PlaceRef::new_sized(
                         bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))),
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index e1cc0268723..e4f4c884470 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -485,7 +485,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             cg_base.project_index(bx, bx.cx().const_usize(from as u64));
                         let projected_ty =
                             PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem).ty;
-                        subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
+                        subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty));
 
                         if subslice.layout.is_unsized() {
                             assert!(from_end, "slice subslices should be `from_end`");
@@ -515,6 +515,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> {
         let tcx = self.cx.tcx();
         let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, self.mir, tcx);
-        self.monomorphize(&place_ty.ty)
+        self.monomorphize(place_ty.ty)
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 40ae0a13c72..2ad470c2693 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -106,7 +106,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
 
                 let count =
-                    self.monomorphize(&count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
+                    self.monomorphize(count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
 
                 bx.write_operand_repeatedly(cg_elem, count, dest)
             }
@@ -181,7 +181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => {
                 let operand = self.codegen_operand(&mut bx, source);
                 debug!("cast operand is {:?}", operand);
-                let cast = bx.cx().layout_of(self.monomorphize(&mir_cast_ty));
+                let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
 
                 let val = match *kind {
                     mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => {
@@ -502,7 +502,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
 
             mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
-                let ty = self.monomorphize(&ty);
+                let ty = self.monomorphize(ty);
                 assert!(bx.cx().type_is_sized(ty));
                 let val = bx.cx().const_usize(bx.cx().layout_of(ty).size.bytes());
                 let tcx = self.cx.tcx();
@@ -516,7 +516,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
 
             mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => {
-                let content_ty = self.monomorphize(&content_ty);
+                let content_ty = self.monomorphize(content_ty);
                 let content_layout = bx.cx().layout_of(content_ty);
                 let llsize = bx.cx().const_usize(content_layout.size.bytes());
                 let llalign = bx.cx().const_usize(content_layout.align.abi.bytes());
@@ -554,7 +554,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 // aggregate rvalues are allowed to be operands.
                 let ty = rvalue.ty(self.mir, self.cx.tcx());
                 let operand =
-                    OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(&ty)));
+                    OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty)));
                 (bx, operand)
             }
         }
@@ -774,7 +774,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Rvalue::Repeat(..) |
             mir::Rvalue::Aggregate(..) => {
                 let ty = rvalue.ty(self.mir, self.cx.tcx());
-                let ty = self.monomorphize(&ty);
+                let ty = self.monomorphize(ty);
                 self.cx.spanned_layout_of(ty, span).is_zst()
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 000ddf42604..fd18f42f2dd 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -4,6 +4,11 @@ use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::symbol::Symbol;
 
+// When adding features to the below lists
+// check whether they're named already elsewhere in rust
+// e.g. in stdarch and whether the given name matches LLVM's
+// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted
+
 const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("aclass", Some(sym::arm_target_feature)),
     ("mclass", Some(sym::arm_target_feature)),
@@ -50,15 +55,23 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("aes", None),
     ("avx", None),
     ("avx2", None),
+    ("avx512bf16", Some(sym::avx512_target_feature)),
+    ("avx512bitalg", Some(sym::avx512_target_feature)),
     ("avx512bw", Some(sym::avx512_target_feature)),
     ("avx512cd", Some(sym::avx512_target_feature)),
     ("avx512dq", Some(sym::avx512_target_feature)),
     ("avx512er", Some(sym::avx512_target_feature)),
     ("avx512f", Some(sym::avx512_target_feature)),
+    ("avx512gfni", Some(sym::avx512_target_feature)),
     ("avx512ifma", Some(sym::avx512_target_feature)),
     ("avx512pf", Some(sym::avx512_target_feature)),
+    ("avx512vaes", Some(sym::avx512_target_feature)),
     ("avx512vbmi", Some(sym::avx512_target_feature)),
+    ("avx512vbmi2", Some(sym::avx512_target_feature)),
     ("avx512vl", Some(sym::avx512_target_feature)),
+    ("avx512vnni", Some(sym::avx512_target_feature)),
+    ("avx512vp2intersect", Some(sym::avx512_target_feature)),
+    ("avx512vpclmulqdq", Some(sym::avx512_target_feature)),
     ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
     ("bmi1", None),
     ("bmi2", None),
diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs
new file mode 100644
index 00000000000..fe7a256d210
--- /dev/null
+++ b/compiler/rustc_data_structures/src/functor.rs
@@ -0,0 +1,82 @@
+use rustc_index::vec::{Idx, IndexVec};
+use std::mem;
+use std::ptr;
+
+pub trait IdFunctor {
+    type Inner;
+
+    fn map_id<F>(self, f: F) -> Self
+    where
+        F: FnMut(Self::Inner) -> Self::Inner;
+}
+
+impl<T> IdFunctor for Box<T> {
+    type Inner = T;
+
+    #[inline]
+    fn map_id<F>(self, mut f: F) -> Self
+    where
+        F: FnMut(Self::Inner) -> Self::Inner,
+    {
+        let raw = Box::into_raw(self);
+        unsafe {
+            // SAFETY: The raw pointer points to a valid value of type `T`.
+            let value = ptr::read(raw);
+            // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
+            // inverse of `Box::assume_init()` and should be safe.
+            let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
+            // SAFETY: Write the mapped value back into the `Box`.
+            ptr::write(raw.as_mut_ptr(), f(value));
+            // SAFETY: We just initialized `raw`.
+            raw.assume_init()
+        }
+    }
+}
+
+impl<T> IdFunctor for Vec<T> {
+    type Inner = T;
+
+    #[inline]
+    fn map_id<F>(mut self, mut f: F) -> Self
+    where
+        F: FnMut(Self::Inner) -> Self::Inner,
+    {
+        // FIXME: We don't really care about panics here and leak
+        // far more than we should, but that should be fine for now.
+        let len = self.len();
+        unsafe {
+            self.set_len(0);
+            let start = self.as_mut_ptr();
+            for i in 0..len {
+                let p = start.add(i);
+                ptr::write(p, f(ptr::read(p)));
+            }
+            self.set_len(len);
+        }
+        self
+    }
+}
+
+impl<T> IdFunctor for Box<[T]> {
+    type Inner = T;
+
+    #[inline]
+    fn map_id<F>(self, f: F) -> Self
+    where
+        F: FnMut(Self::Inner) -> Self::Inner,
+    {
+        Vec::from(self).map_id(f).into()
+    }
+}
+
+impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
+    type Inner = T;
+
+    #[inline]
+    fn map_id<F>(self, f: F) -> Self
+    where
+        F: FnMut(Self::Inner) -> Self::Inner,
+    {
+        IndexVec::from_raw(self.raw.map_id(f))
+    }
+}
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 7669b78834c..6b952f20dd1 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -27,6 +27,7 @@
 #![feature(extend_one)]
 #![feature(const_panic)]
 #![feature(min_const_generics)]
+#![feature(new_uninit)]
 #![feature(once_cell)]
 #![feature(maybe_uninit_uninit_array)]
 #![allow(rustc::default_hash_types)]
@@ -47,9 +48,9 @@ pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
 #[macro_export]
 macro_rules! likely {
     ($e:expr) => {
-        #[allow(unused_unsafe)]
-        {
-            unsafe { std::intrinsics::likely($e) }
+        match $e {
+            #[allow(unused_unsafe)]
+            e => unsafe { std::intrinsics::likely(e) },
         }
     };
 }
@@ -57,9 +58,9 @@ macro_rules! likely {
 #[macro_export]
 macro_rules! unlikely {
     ($e:expr) => {
-        #[allow(unused_unsafe)]
-        {
-            unsafe { std::intrinsics::unlikely($e) }
+        match $e {
+            #[allow(unused_unsafe)]
+            e => unsafe { std::intrinsics::unlikely(e) },
         }
     };
 }
@@ -70,6 +71,7 @@ pub mod box_region;
 pub mod captures;
 pub mod const_cstr;
 pub mod flock;
+pub mod functor;
 pub mod fx;
 pub mod graph;
 pub mod jobserver;
@@ -102,6 +104,7 @@ pub mod work_queue;
 pub use atomic_ref::AtomicRef;
 pub mod frozen;
 pub mod sso;
+pub mod steal;
 pub mod tagged_ptr;
 pub mod temp_dir;
 pub mod unhash;
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index e598d7a683d..5d13b7f27c7 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -272,6 +272,28 @@ impl SelfProfilerRef {
         })
     }
 
+    #[inline(always)]
+    pub fn generic_activity_with_args(
+        &self,
+        event_label: &'static str,
+        event_args: &[String],
+    ) -> TimingGuard<'_> {
+        self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
+            let builder = EventIdBuilder::new(&profiler.profiler);
+            let event_label = profiler.get_or_alloc_cached_string(event_label);
+            let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) {
+                let event_args: Vec<_> = event_args
+                    .iter()
+                    .map(|s| profiler.get_or_alloc_cached_string(&s[..]))
+                    .collect();
+                builder.from_label_and_args(event_label, &event_args)
+            } else {
+                builder.from_label(event_label)
+            };
+            TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id)
+        })
+    }
+
     /// Start profiling a query provider. Profiling continues until the
     /// TimingGuard returned from this call is dropped.
     #[inline(always)]
diff --git a/compiler/rustc_middle/src/ty/steal.rs b/compiler/rustc_data_structures/src/steal.rs
index 224e76845d7..e532a84cea3 100644
--- a/compiler/rustc_middle/src/ty/steal.rs
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -1,4 +1,5 @@
-use rustc_data_structures::sync::{MappedReadGuard, ReadGuard, RwLock};
+use crate::stable_hasher::{HashStable, StableHasher};
+use crate::sync::{MappedReadGuard, ReadGuard, RwLock};
 
 /// The `Steal` struct is intended to used as the value for a query.
 /// Specifically, we sometimes have queries (*cough* MIR *cough*)
@@ -31,7 +32,7 @@ impl<T> Steal<T> {
 
     pub fn borrow(&self) -> MappedReadGuard<'_, T> {
         ReadGuard::map(self.value.borrow(), |opt| match *opt {
-            None => bug!("attempted to read from stolen value"),
+            None => panic!("attempted to read from stolen value"),
             Some(ref v) => v,
         })
     }
@@ -42,3 +43,9 @@ impl<T> Steal<T> {
         value.expect("attempt to read from stolen value")
     }
 }
+
+impl<CTX, T: HashStable<CTX>> HashStable<CTX> for Steal<T> {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.borrow().hash_stable(hcx, hasher);
+    }
+}
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index a192c2eb94e..c5447612555 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -20,7 +20,7 @@ use rustc_data_structures::profiling::print_time_passes_entry;
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::registry::{InvalidErrorCode, Registry};
 use rustc_errors::{ErrorReported, PResult};
-use rustc_feature::{find_gated_cfg, UnstableFeatures};
+use rustc_feature::find_gated_cfg;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
 use rustc_interface::{interface, Queries};
@@ -746,9 +746,6 @@ impl RustcDefaultCalls {
                     }
                 }
                 Cfg => {
-                    let allow_unstable_cfg =
-                        UnstableFeatures::from_environment().is_nightly_build();
-
                     let mut cfgs = sess
                         .parse_sess
                         .config
@@ -763,7 +760,7 @@ impl RustcDefaultCalls {
                             // it, this is intended to get into Cargo and then go
                             // through to build scripts.
                             if (name != sym::target_feature || value != Some(sym::crt_dash_static))
-                                && !allow_unstable_cfg
+                                && !sess.is_nightly_build()
                                 && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
                             {
                                 return None;
@@ -814,14 +811,14 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
     }
 }
 
-fn usage(verbose: bool, include_unstable_options: bool) {
+fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
     let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
     let mut options = getopts::Options::new();
     for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
         (option.apply)(&mut options);
     }
     let message = "Usage: rustc [OPTIONS] INPUT";
-    let nightly_help = if nightly_options::is_nightly_build() {
+    let nightly_help = if nightly_build {
         "\n    -Z help             Print unstable compiler options"
     } else {
         ""
@@ -831,7 +828,7 @@ fn usage(verbose: bool, include_unstable_options: bool) {
     } else {
         "\n    --help -v           Print the full set of options rustc accepts"
     };
-    let at_path = if verbose && nightly_options::is_nightly_build() {
+    let at_path = if verbose && nightly_build {
         "    @path               Read newline separated options from `path`\n"
     } else {
         ""
@@ -1034,7 +1031,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     if args.is_empty() {
         // user did not write `-v` nor `-Z unstable-options`, so do not
         // include that extra information.
-        usage(false, false);
+        let nightly_build =
+            rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build();
+        usage(false, false, nightly_build);
         return None;
     }
 
@@ -1063,7 +1062,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
 
     if matches.opt_present("h") || matches.opt_present("help") {
         // Only show unstable options in --help if we accept unstable options.
-        usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches));
+        let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
+        let nightly_build = nightly_options::match_is_nightly_build(&matches);
+        usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
         return None;
     }
 
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index f74e1fe61e7..305fa838afa 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -404,7 +404,6 @@ pub fn print_after_parsing(
                 annotation.pp_ann(),
                 false,
                 parse.edition,
-                parse.injected_crate_name.get().is_some(),
             )
         })
     } else {
@@ -446,7 +445,6 @@ pub fn print_after_hir_lowering<'tcx>(
                     annotation.pp_ann(),
                     true,
                     parse.edition,
-                    parse.injected_crate_name.get().is_some(),
                 )
             })
         }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0744.md b/compiler/rustc_error_codes/src/error_codes/E0744.md
index 14cff3613e0..45804ab266e 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0744.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0744.md
@@ -1,4 +1,4 @@
-A control-flow expression was used inside a const context.
+An unsupported expression was used inside a const context.
 
 Erroneous code example:
 
@@ -12,12 +12,15 @@ const _: i32 = {
 };
 ```
 
-At the moment, `if` and `match`, as well as the looping constructs `for`,
-`while`, and `loop`, are forbidden inside a `const`, `static`, or `const fn`.
+At the moment, `for` loops, `.await`, and the `Try` operator (`?`) are forbidden
+inside a `const`, `static`, or `const fn`.
 
-This will be allowed at some point in the future, but the implementation is not
-yet complete. See the tracking issue for [conditionals] or [loops] in a const
-context for the current status.
+This may be allowed at some point in the future, but the implementation is not
+yet complete. See the tracking issues for [`async`] and [`?`] in `const fn`, and
+(to support `for` loops in `const fn`) the tracking issues for [`impl const
+Trait for Ty`] and [`&mut T`] in `const fn`.
 
-[conditionals]: https://github.com/rust-lang/rust/issues/49146
-[loops]: https://github.com/rust-lang/rust/issues/52000
+[`async`]: https://github.com/rust-lang/rust/issues/69431
+[`?`]: https://github.com/rust-lang/rust/issues/74935
+[`impl const Trait for Ty`]: https://github.com/rust-lang/rust/issues/67792
+[`&mut T`]: https://github.com/rust-lang/rust/issues/57349
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 56acdf699ef..c9259a1502c 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -184,16 +184,18 @@ impl<'a> DiagnosticBuilder<'a> {
         self.cancel();
     }
 
-    /// Adds a span/label to be included in the resulting snippet.
+    /// Appends a labeled span to the diagnostic.
     ///
-    /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic
-    /// was first built. That means it will be shown together with the original
-    /// span/label, *not* a span added by one of the `span_{note,warn,help,suggestions}` methods.
+    /// Labels are used to convey additional context for the diagnostic's primary span. They will
+    /// be shown together with the original diagnostic's span, *not* with spans added by
+    /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because
+    /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed
+    /// either.
     ///
-    /// This span is *not* considered a ["primary span"][`MultiSpan`]; only
-    /// the `Span` supplied when creating the diagnostic is primary.
-    ///
-    /// [`MultiSpan`]: ../rustc_span/struct.MultiSpan.html
+    /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when
+    /// the diagnostic was constructed. However, the label span is *not* considered a
+    /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
+    /// primary.
     pub fn span_label(&mut self, span: Span, label: impl Into<String>) -> &mut Self {
         self.0.diagnostic.span_label(span, label);
         self
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 302713a21db..32104e6f00d 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -200,6 +200,11 @@ pub trait Emitter {
         true
     }
 
+    /// Checks if we can use colors in the current output stream.
+    fn supports_color(&self) -> bool {
+        false
+    }
+
     fn source_map(&self) -> Option<&Lrc<SourceMap>>;
 
     /// Formats the substitutions of the primary_span
@@ -504,6 +509,10 @@ impl Emitter for EmitterWriter {
     fn should_show_explain(&self) -> bool {
         !self.short_message
     }
+
+    fn supports_color(&self) -> bool {
+        self.dst.supports_color()
+    }
 }
 
 /// An emitter that does nothing when emitting a diagnostic.
@@ -2057,6 +2066,14 @@ impl Destination {
             Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)),
         }
     }
+
+    fn supports_color(&self) -> bool {
+        match *self {
+            Self::Terminal(ref stream) => stream.supports_color(),
+            Self::Buffered(ref buffer) => buffer.buffer().supports_color(),
+            Self::Raw(_, supports_color) => supports_color,
+        }
+    }
 }
 
 impl<'a> WritableDst<'a> {
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 0df67b63eba..a0355079247 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -616,6 +616,9 @@ declare_features! (
     /// Enables `#[cfg(panic = "...")]` config key.
     (active, cfg_panic, "1.49.0", Some(77443), None),
 
+    /// Allows capturing disjoint fields in a closure/generator (RFC 2229).
+    (active, capture_disjoint_fields, "1.49.0", Some(53488), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -639,6 +642,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
     sym::inline_const,
     sym::repr128,
     sym::unsized_locals,
+    sym::capture_disjoint_fields,
 ];
 
 /// Some features are not allowed to be used together at the same time, if
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 5c5cf609ac3..fa8edba629e 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -547,6 +547,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ==========================================================================
 
     rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
+    rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
     rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
     rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
     rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 68ac2841fed..f965f7fdefe 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -59,7 +59,7 @@ pub enum Stability {
     Deprecated(&'static str, Option<&'static str>),
 }
 
-#[derive(Clone, Copy, Hash)]
+#[derive(Clone, Copy, Debug, Hash)]
 pub enum UnstableFeatures {
     /// Hard errors for unstable features are active, as on beta/stable channels.
     Disallow,
@@ -73,11 +73,20 @@ pub enum UnstableFeatures {
 }
 
 impl UnstableFeatures {
-    pub fn from_environment() -> UnstableFeatures {
+    /// This takes into account `RUSTC_BOOTSTRAP`.
+    ///
+    /// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly features.
+    /// Otherwise, only `RUSTC_BOOTSTRAP=1` will work.
+    pub fn from_environment(krate: Option<&str>) -> Self {
         // `true` if this is a feature-staged build, i.e., on the beta or stable channel.
         let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
+        // Returns whether `krate` should be counted as unstable
+        let is_unstable_crate = |var: &str| {
+            krate.map_or(false, |name| var.split(',').any(|new_krate| new_krate == name))
+        };
         // `true` if we should enable unstable features for bootstrapping.
-        let bootstrap = std::env::var("RUSTC_BOOTSTRAP").is_ok();
+        let bootstrap = std::env::var("RUSTC_BOOTSTRAP")
+            .map_or(false, |var| var == "1" || is_unstable_crate(&var));
         match (disable_unstable_features, bootstrap) {
             (_, true) => UnstableFeatures::Cheat,
             (true, _) => UnstableFeatures::Disallow,
@@ -140,3 +149,30 @@ pub use builtin_attrs::{
     AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
 };
 pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
+
+#[cfg(test)]
+mod test {
+    use super::UnstableFeatures;
+
+    #[test]
+    fn rustc_bootstrap_parsing() {
+        let is_bootstrap = |env, krate| {
+            std::env::set_var("RUSTC_BOOTSTRAP", env);
+            matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Cheat)
+        };
+        assert!(is_bootstrap("1", None));
+        assert!(is_bootstrap("1", Some("x")));
+        // RUSTC_BOOTSTRAP allows specifying a specific crate
+        assert!(is_bootstrap("x", Some("x")));
+        // RUSTC_BOOTSTRAP allows multiple comma-delimited crates
+        assert!(is_bootstrap("x,y,z", Some("x")));
+        assert!(is_bootstrap("x,y,z", Some("y")));
+        // Crate that aren't specified do not get unstable features
+        assert!(!is_bootstrap("x", Some("a")));
+        assert!(!is_bootstrap("x,y,z", Some("a")));
+        assert!(!is_bootstrap("x,y,z", None));
+
+        // this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP
+        assert!(!is_bootstrap("0", None));
+    }
+}
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 3c28b48795f..4497c8c0eaa 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -282,6 +282,14 @@ impl GenericArg<'_> {
             GenericArg::Const(_) => "constant",
         }
     }
+
+    pub fn short_descr(&self) -> &'static str {
+        match self {
+            GenericArg::Lifetime(_) => "lifetime",
+            GenericArg::Type(_) => "type",
+            GenericArg::Const(_) => "const",
+        }
+    }
 }
 
 #[derive(Debug, HashStable_Generic)]
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index 048a81b81ba..e185ee24d17 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -15,7 +15,6 @@ use std::io::{self, Read};
 use std::path::Path;
 
 use rustc_serialize::opaque::Encoder;
-use rustc_session::config::nightly_options;
 
 /// The first few bytes of files generated by incremental compilation.
 const FILE_MAGIC: &[u8] = b"RSIC";
@@ -28,12 +27,12 @@ const HEADER_FORMAT_VERSION: u16 = 0;
 /// the Git commit hash.
 const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
 
-pub fn write_file_header(stream: &mut Encoder) {
+pub fn write_file_header(stream: &mut Encoder, nightly_build: bool) {
     stream.emit_raw_bytes(FILE_MAGIC);
     stream
         .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]);
 
-    let rustc_version = rustc_version();
+    let rustc_version = rustc_version(nightly_build);
     assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize);
     stream.emit_raw_bytes(&[rustc_version.len() as u8]);
     stream.emit_raw_bytes(rustc_version.as_bytes());
@@ -51,6 +50,7 @@ pub fn write_file_header(stream: &mut Encoder) {
 pub fn read_file(
     report_incremental_info: bool,
     path: &Path,
+    nightly_build: bool,
 ) -> io::Result<Option<(Vec<u8>, usize)>> {
     if !path.exists() {
         return Ok(None);
@@ -93,7 +93,7 @@ pub fn read_file(
         let mut buffer = vec![0; rustc_version_str_len];
         file.read_exact(&mut buffer)?;
 
-        if buffer != rustc_version().as_bytes() {
+        if buffer != rustc_version(nightly_build).as_bytes() {
             report_format_mismatch(report_incremental_info, path, "Different compiler version");
             return Ok(None);
         }
@@ -115,8 +115,8 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
     }
 }
 
-fn rustc_version() -> String {
-    if nightly_options::is_nightly_build() {
+fn rustc_version(nightly_build: bool) -> String {
+    if nightly_build {
         if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
             return val.to_string_lossy().into_owned();
         }
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 966faa9639d..578c045a2b4 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -53,8 +53,12 @@ impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
     }
 }
 
-fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec<u8>, usize)> {
-    match file_format::read_file(report_incremental_info, path) {
+fn load_data(
+    report_incremental_info: bool,
+    path: &Path,
+    nightly_build: bool,
+) -> LoadResult<(Vec<u8>, usize)> {
+    match file_format::read_file(report_incremental_info, path, nightly_build) {
         Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
         Ok(None) => {
             // The file either didn't exist or was produced by an incompatible
@@ -111,13 +115,14 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
     let expected_hash = sess.opts.dep_tracking_hash();
 
     let mut prev_work_products = FxHashMap::default();
+    let nightly_build = sess.is_nightly_build();
 
     // If we are only building with -Zquery-dep-graph but without an actual
     // incr. comp. session directory, we skip this. Otherwise we'd fail
     // when trying to load work products.
     if sess.incr_comp_session_dir_opt().is_some() {
         let work_products_path = work_products_path(sess);
-        let load_result = load_data(report_incremental_info, &work_products_path);
+        let load_result = load_data(report_incremental_info, &work_products_path, nightly_build);
 
         if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
             // Decode the list of work_products
@@ -163,7 +168,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
     MaybeAsync::Async(std::thread::spawn(move || {
         let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
 
-        match load_data(report_incremental_info, &path) {
+        match load_data(report_incremental_info, &path, nightly_build) {
             LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
             LoadResult::Error { message } => LoadResult::Error { message },
             LoadResult::Ok { data: (bytes, start_pos) } => {
@@ -201,7 +206,11 @@ pub fn load_query_result_cache(sess: &Session) -> OnDiskCache<'_> {
 
     let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
 
-    match load_data(sess.opts.debugging_opts.incremental_info, &query_cache_path(sess)) {
+    match load_data(
+        sess.opts.debugging_opts.incremental_info,
+        &query_cache_path(sess),
+        sess.is_nightly_build(),
+    ) {
         LoadResult::Ok { data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos),
         _ => OnDiskCache::new_empty(sess.source_map()),
     }
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 45cef479a4f..102a77e8e79 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -119,7 +119,7 @@ where
 
     // generate the data in a memory buffer
     let mut encoder = Encoder::new(Vec::new());
-    file_format::write_file_header(&mut encoder);
+    file_format::write_file_header(&mut encoder, sess.is_nightly_build());
     encode(&mut encoder);
 
     // write the data out
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index f554b51800a..6781fbc95c0 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -38,7 +38,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query
     pub fn canonicalize_query<V>(
         &self,
-        value: &V,
+        value: V,
         query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'tcx, V>
     where
@@ -80,7 +80,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     /// out the [chapter in the rustc dev guide][c].
     ///
     /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
-    pub fn canonicalize_response<V>(&self, value: &V) -> Canonicalized<'tcx, V>
+    pub fn canonicalize_response<V>(&self, value: V) -> Canonicalized<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -94,7 +94,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         )
     }
 
-    pub fn canonicalize_user_type_annotation<V>(&self, value: &V) -> Canonicalized<'tcx, V>
+    pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonicalized<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -123,7 +123,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     // and just use `canonicalize_query`.
     pub fn canonicalize_hr_query_hack<V>(
         &self,
-        value: &V,
+        value: V,
         query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'tcx, V>
     where
@@ -293,7 +293,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+    fn fold_binder<T>(&mut self, t: ty::Binder<T>) -> ty::Binder<T>
     where
         T: TypeFoldable<'tcx>,
     {
@@ -479,7 +479,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
     /// The main `canonicalize` method, shared impl of
     /// `canonicalize_query` and `canonicalize_response`.
     fn canonicalize<V>(
-        value: &V,
+        value: V,
         infcx: Option<&InferCtxt<'_, 'tcx>>,
         tcx: TyCtxt<'tcx>,
         canonicalize_region_mode: &dyn CanonicalizeRegionMode,
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 93e19521893..c8d66cbb695 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -59,7 +59,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
     {
         let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?;
-        let canonical_result = self.canonicalize_response(&query_response);
+        let canonical_result = self.canonicalize_response(query_response);
 
         debug!("make_canonicalized_query_response: canonical_result = {:#?}", canonical_result);
 
@@ -83,7 +83,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     where
         T: Debug + TypeFoldable<'tcx>,
     {
-        self.canonicalize_response(&QueryResponse {
+        self.canonicalize_response(QueryResponse {
             var_values: inference_vars,
             region_constraints: QueryRegionConstraints::default(),
             certainty: Certainty::Proven, // Ambiguities are OK!
@@ -176,7 +176,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         ));
 
         let user_result: R =
-            query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
+            query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone());
 
         Ok(InferOk { value: user_result, obligations })
     }
@@ -238,7 +238,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         for (index, original_value) in original_values.var_values.iter().enumerate() {
             // ...with the value `v_r` of that variable from the query.
             let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
-                &v.var_values[BoundVar::new(index)]
+                v.var_values[BoundVar::new(index)]
             });
             match (original_value.unpack(), result_value.unpack()) {
                 (
@@ -296,7 +296,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
 
         // ...also include the other query region constraints from the query.
         output_query_region_constraints.outlives.extend(
-            query_response.value.region_constraints.outlives.iter().filter_map(|r_c| {
+            query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
                 let r_c = substitute_value(self.tcx, &result_subst, r_c);
 
                 // Screen out `'a: 'a` cases -- we skip the binder here but
@@ -314,11 +314,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                 .region_constraints
                 .member_constraints
                 .iter()
-                .map(|p_c| substitute_value(self.tcx, &result_subst, p_c)),
+                .map(|p_c| substitute_value(self.tcx, &result_subst, p_c.clone())),
         );
 
         let user_result: R =
-            query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
+            query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone());
 
         Ok(InferOk { value: user_result, obligations })
     }
@@ -502,7 +502,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         // `query_response.var_values` after applying the substitution
         // `result_subst`.
         let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> {
-            query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index])
+            query_response.substitute_projected(self.tcx, &result_subst, |v| v.var_values[index])
         };
 
         // Unify the original value for each variable with the value
@@ -524,7 +524,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>],
         result_subst: &'a CanonicalVarValues<'tcx>,
     ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
-        unsubstituted_region_constraints.iter().map(move |constraint| {
+        unsubstituted_region_constraints.iter().map(move |&constraint| {
             let ty::OutlivesPredicate(k1, r2) =
                 substitute_value(self.tcx, result_subst, constraint).skip_binder();
 
diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs
index 65791f6fc65..cd4f1fa3bc3 100644
--- a/compiler/rustc_infer/src/infer/canonical/substitute.rs
+++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs
@@ -28,7 +28,7 @@ pub(super) trait CanonicalExt<'tcx, V> {
         &self,
         tcx: TyCtxt<'tcx>,
         var_values: &CanonicalVarValues<'tcx>,
-        projection_fn: impl FnOnce(&V) -> &T,
+        projection_fn: impl FnOnce(&V) -> T,
     ) -> T
     where
         T: TypeFoldable<'tcx>;
@@ -39,14 +39,14 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
     where
         V: TypeFoldable<'tcx>,
     {
-        self.substitute_projected(tcx, var_values, |value| value)
+        self.substitute_projected(tcx, var_values, |value| value.clone())
     }
 
     fn substitute_projected<T>(
         &self,
         tcx: TyCtxt<'tcx>,
         var_values: &CanonicalVarValues<'tcx>,
-        projection_fn: impl FnOnce(&V) -> &T,
+        projection_fn: impl FnOnce(&V) -> T,
     ) -> T
     where
         T: TypeFoldable<'tcx>,
@@ -60,16 +60,16 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
 /// Substitute the values from `var_values` into `value`. `var_values`
 /// must be values for the set of canonical variables that appear in
 /// `value`.
-pub(super) fn substitute_value<'a, 'tcx, T>(
+pub(super) fn substitute_value<'tcx, T>(
     tcx: TyCtxt<'tcx>,
     var_values: &CanonicalVarValues<'tcx>,
-    value: &'a T,
+    value: T,
 ) -> T
 where
     T: TypeFoldable<'tcx>,
 {
     if var_values.var_values.is_empty() {
-        value.clone()
+        value
     } else {
         let fld_r =
             |br: ty::BoundRegion| match var_values.var_values[br.assert_bound_var()].unpack() {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 524efd04cfc..183fb314a00 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -389,7 +389,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         member_region,
                         span,
                     } => {
-                        let hidden_ty = self.resolve_vars_if_possible(&hidden_ty);
+                        let hidden_ty = self.resolve_vars_if_possible(hidden_ty);
                         unexpected_hidden_region_diagnostic(
                             self.tcx,
                             span,
@@ -590,7 +590,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     ) {
         match cause.code {
             ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
-                let ty = self.resolve_vars_if_possible(&root_ty);
+                let ty = self.resolve_vars_if_possible(root_ty);
                 if ty.is_suggestable() {
                     // don't show type `_`
                     err.span_label(span, format!("this expression has type `{}`", ty));
@@ -661,7 +661,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 }
                 _ => {
                     // `last_ty` can be `!`, `expected` will have better info when present.
-                    let t = self.resolve_vars_if_possible(&match exp_found {
+                    let t = self.resolve_vars_if_possible(match exp_found {
                         Some(ty::error::ExpectedFound { expected, .. }) => expected,
                         _ => last_ty,
                     });
@@ -1498,7 +1498,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
 
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
-            fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+            fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if let Some((kind, def_id)) = TyCategory::from_ty(t) {
                     let span = self.tcx.def_span(def_id);
                     // Avoid cluttering the output when the "found" and error span overlap:
@@ -1547,7 +1547,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
                     _ => (false, Mismatch::Fixed("type")),
                 };
-                let vals = match self.values_str(&values) {
+                let vals = match self.values_str(values) {
                     Some((expected, found)) => Some((expected, found)),
                     None => {
                         // Derived error. Cancel the emitter.
@@ -1893,32 +1893,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
     fn values_str(
         &self,
-        values: &ValuePairs<'tcx>,
+        values: ValuePairs<'tcx>,
     ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
-        match *values {
-            infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found),
-            infer::Regions(ref exp_found) => self.expected_found_str(exp_found),
-            infer::Consts(ref exp_found) => self.expected_found_str(exp_found),
-            infer::TraitRefs(ref exp_found) => {
+        match values {
+            infer::Types(exp_found) => self.expected_found_str_ty(exp_found),
+            infer::Regions(exp_found) => self.expected_found_str(exp_found),
+            infer::Consts(exp_found) => self.expected_found_str(exp_found),
+            infer::TraitRefs(exp_found) => {
                 let pretty_exp_found = ty::error::ExpectedFound {
                     expected: exp_found.expected.print_only_trait_path(),
                     found: exp_found.found.print_only_trait_path(),
                 };
-                self.expected_found_str(&pretty_exp_found)
+                self.expected_found_str(pretty_exp_found)
             }
-            infer::PolyTraitRefs(ref exp_found) => {
+            infer::PolyTraitRefs(exp_found) => {
                 let pretty_exp_found = ty::error::ExpectedFound {
                     expected: exp_found.expected.print_only_trait_path(),
                     found: exp_found.found.print_only_trait_path(),
                 };
-                self.expected_found_str(&pretty_exp_found)
+                self.expected_found_str(pretty_exp_found)
             }
         }
     }
 
     fn expected_found_str_ty(
         &self,
-        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        exp_found: ty::error::ExpectedFound<Ty<'tcx>>,
     ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
         let exp_found = self.resolve_vars_if_possible(exp_found);
         if exp_found.references_error() {
@@ -1931,7 +1931,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// Returns a string of the form "expected `{}`, found `{}`".
     fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
         &self,
-        exp_found: &ty::error::ExpectedFound<T>,
+        exp_found: ty::error::ExpectedFound<T>,
     ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
         let exp_found = self.resolve_vars_if_possible(exp_found);
         if exp_found.references_error() {
@@ -2180,7 +2180,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "...",
                 );
                 if let Some(infer::RelateParamBound(_, t)) = origin {
-                    let t = self.resolve_vars_if_possible(&t);
+                    let t = self.resolve_vars_if_possible(t);
                     match t.kind() {
                         // We've got:
                         // fn get_later<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
@@ -2237,7 +2237,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values);
 
             if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) =
-                (self.values_str(&sup_trace.values), self.values_str(&sub_trace.values))
+                (self.values_str(sup_trace.values), self.values_str(sub_trace.values))
             {
                 if sub_expected == sup_expected && sub_found == sup_found {
                     note_and_explain_region(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 868989539d4..fd8f46a6926 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -49,7 +49,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
             .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id));
         match ty_opt {
             Some(ty) => {
-                let ty = self.infcx.resolve_vars_if_possible(&ty);
+                let ty = self.infcx.resolve_vars_if_possible(ty);
                 if ty.walk().any(|inner| {
                     inner == self.target
                         || match (inner.unpack(), self.target.unpack()) {
@@ -343,7 +343,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         arg: GenericArg<'tcx>,
         error_code: TypeAnnotationNeeded,
     ) -> DiagnosticBuilder<'tcx> {
-        let arg = self.resolve_vars_if_possible(&arg);
+        let arg = self.resolve_vars_if_possible(arg);
         let arg_data = self.extract_inference_diagnostics_data(arg, None);
         let kind_str = match arg.unpack() {
             GenericArgKind::Type(_) => "type",
@@ -686,7 +686,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         span: Span,
         ty: Ty<'tcx>,
     ) -> DiagnosticBuilder<'tcx> {
-        let ty = self.resolve_vars_if_possible(&ty);
+        let ty = self.resolve_vars_if_possible(ty);
         let data = self.extract_inference_diagnostics_data(ty.into(), None);
 
         let mut err = struct_span_err!(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index 2187064ec5e..e8e0326d978 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -234,14 +234,13 @@ impl NiceRegionError<'me, 'tcx> {
             false
         };
 
-        let expected_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef {
+        let expected_trait_ref = self.infcx.resolve_vars_if_possible(ty::TraitRef {
             def_id: trait_def_id,
             substs: expected_substs,
         });
-        let actual_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef {
-            def_id: trait_def_id,
-            substs: actual_substs,
-        });
+        let actual_trait_ref = self
+            .infcx
+            .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
 
         // Search the expected and actual trait references to see (a)
         // whether the sub/sup placeholders appear in them (sometimes
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index df3dbfca01d..5264854d8eb 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -414,7 +414,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             tcx,
             ctxt.param_env,
             ctxt.assoc_item.def_id,
-            self.infcx.resolve_vars_if_possible(&ctxt.substs),
+            self.infcx.resolve_vars_if_possible(ctxt.substs),
         ) {
             Ok(Some(instance)) => instance,
             _ => return false,
@@ -474,7 +474,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 struct TraitObjectVisitor(Vec<DefId>);
 
 impl TypeVisitor<'_> for TraitObjectVisitor {
-    fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
             ty::Dynamic(preds, RegionKind::ReStatic) => {
                 if let Some(def_id) = preds.principal_def_id() {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index c061f485c1c..4d3217a9c0b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -86,7 +86,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         }
 
         if let Some((expected, found)) =
-            self.infcx.expected_found_str_ty(&ExpectedFound { expected, found })
+            self.infcx.expected_found_str_ty(ExpectedFound { expected, found })
         {
             // Highlighted the differences when showing the "expected/found" note.
             err.note_expected_found(&"", expected, &"", found);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index ca93b2777ab..8d0100440a8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -55,12 +55,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let owner_id = hir.body_owner(body_id);
         let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
         let poly_fn_sig = self.tcx().fn_sig(id);
-        let fn_sig = self.tcx().liberate_late_bound_regions(id, &poly_fn_sig);
+        let fn_sig = self.tcx().liberate_late_bound_regions(id, poly_fn_sig);
         body.params.iter().enumerate().find_map(|(index, param)| {
             // May return None; sometimes the tables are not yet populated.
             let ty = fn_sig.inputs()[index];
             let mut found_anon_region = false;
-            let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| {
+            let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
                 if *r == *anon_region {
                     found_anon_region = true;
                     replace_region
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 9ac27030ade..7fb94332cad 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -24,7 +24,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         };
         match *origin {
             infer::Subtype(ref trace) => {
-                if let Some((expected, found)) = self.values_str(&trace.values) {
+                if let Some((expected, found)) = self.values_str(trace.values) {
                     label_or_note(
                         trace.cause.span,
                         &format!("...so that the {}", trace.cause.as_requirement_str()),
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index d7bc636db8f..c292b2bdb30 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -105,7 +105,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let (mut fudger, value) = self.probe(|_| {
             match f() {
                 Ok(value) => {
-                    let value = self.resolve_vars_if_possible(&value);
+                    let value = self.resolve_vars_if_possible(value);
 
                     // At this point, `value` could in principle refer
                     // to inference variables that have been created during
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index 4a5fd4b2aa5..9d9ecf5b384 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -33,14 +33,14 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
         self.infcx.commit_if_ok(|_| {
             // First, we instantiate each bound region in the supertype with a
             // fresh placeholder region.
-            let b_prime = self.infcx.replace_bound_vars_with_placeholders(&b);
+            let b_prime = self.infcx.replace_bound_vars_with_placeholders(b);
 
             // Next, we instantiate each bound region in the subtype
             // with a fresh region variable. These region variables --
             // but no other pre-existing region variables -- can name
             // the placeholders.
             let (a_prime, _) =
-                self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, &a);
+                self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
 
             debug!("a_prime={:?}", a_prime);
             debug!("b_prime={:?}", b_prime);
@@ -66,7 +66,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// the [rustc dev guide].
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
-    pub fn replace_bound_vars_with_placeholders<T>(&self, binder: &ty::Binder<T>) -> T
+    pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<T>) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -113,10 +113,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         debug!(
             "replace_bound_vars_with_placeholders(\
              next_universe={:?}, \
-             binder={:?}, \
              result={:?}, \
              map={:?})",
-            next_universe, binder, result, map,
+            next_universe, result, map,
         );
 
         result
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index fcf1949933b..d7b2ce7ee20 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -1001,7 +1001,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        tcx.fold_regions(&value, &mut false, |r, _db| match r {
+        tcx.fold_regions(value, &mut false, |r, _db| match r {
             ty::ReVar(rid) => self.resolve_var(*rid),
             _ => r,
         })
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index acded5351f8..6affe0e5463 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1,5 +1,3 @@
-//! See the Book for more information.
-
 pub use self::freshen::TypeFreshener;
 pub use self::LateBoundRegionConversionTime::*;
 pub use self::RegionVariableOrigin::*;
@@ -345,7 +343,7 @@ pub struct InferCtxt<'a, 'tcx> {
 }
 
 /// See the `error_reporting` module for more details.
-#[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
 pub enum ValuePairs<'tcx> {
     Types(ExpectedFound<Ty<'tcx>>),
     Regions(ExpectedFound<ty::Region<'tcx>>),
@@ -955,7 +953,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         Some(self.commit_if_ok(|_snapshot| {
             let ty::SubtypePredicate { a_is_expected, a, b } =
-                self.replace_bound_vars_with_placeholders(&predicate);
+                self.replace_bound_vars_with_placeholders(predicate);
 
             let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
 
@@ -970,7 +968,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     ) -> UnitResult<'tcx> {
         self.commit_if_ok(|_snapshot| {
             let ty::OutlivesPredicate(r_a, r_b) =
-                self.replace_bound_vars_with_placeholders(&predicate);
+                self.replace_bound_vars_with_placeholders(predicate);
             let origin = SubregionOrigin::from_obligation_cause(cause, || {
                 RelateRegionParamBound(cause.span)
             });
@@ -1266,7 +1264,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
-        self.resolve_vars_if_possible(&t).to_string()
+        self.resolve_vars_if_possible(t).to_string()
     }
 
     pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String {
@@ -1274,7 +1272,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         format!("({})", tstrs.join(", "))
     }
 
-    pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String {
+    pub fn trait_ref_to_string(&self, t: ty::TraitRef<'tcx>) -> String {
         self.resolve_vars_if_possible(t).print_only_trait_path().to_string()
     }
 
@@ -1314,7 +1312,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// is left as is. This is an idempotent operation that does
     /// not affect inference state in any way and so you can do it
     /// at will.
-    pub fn resolve_vars_if_possible<T>(&self, value: &T) -> T
+    pub fn resolve_vars_if_possible<T>(&self, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -1334,9 +1332,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        let mut r = resolve::UnresolvedTypeFinder::new(self);
-        value.visit_with(&mut r);
-        r.first_unresolved
+        value.visit_with(&mut resolve::UnresolvedTypeFinder::new(self)).break_value()
     }
 
     pub fn probe_const_var(
@@ -1349,7 +1345,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<'tcx, T> {
+    pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: T) -> FixupResult<'tcx, T> {
         /*!
          * Attempts to resolve all type/region/const variables in
          * `value`. Region inference must have been run already (e.g.,
@@ -1383,7 +1379,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     where
         M: FnOnce(String) -> DiagnosticBuilder<'tcx>,
     {
-        let actual_ty = self.resolve_vars_if_possible(&actual_ty);
+        let actual_ty = self.resolve_vars_if_possible(actual_ty);
         debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
 
         // Don't report an error if actual type is `Error`.
@@ -1420,7 +1416,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         &self,
         span: Span,
         lbrct: LateBoundRegionConversionTime,
-        value: &ty::Binder<T>,
+        value: ty::Binder<T>,
     ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
     where
         T: TypeFoldable<'tcx>,
@@ -1508,7 +1504,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         span: Option<Span>,
     ) -> EvalToConstValueResult<'tcx> {
         let mut original_values = OriginalQueryValues::default();
-        let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values);
+        let canonical = self.canonicalize_query((param_env, substs), &mut original_values);
 
         let (param_env, substs) = canonical.value;
         // The return value is the evaluated value which doesn't contain any reference to inference
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 9b2ffc7a920..0b2847658f7 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -741,7 +741,10 @@ struct ScopeInstantiator<'me, 'tcx> {
 }
 
 impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<()> {
+    fn visit_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: &ty::Binder<T>,
+    ) -> ControlFlow<Self::BreakTy> {
         self.target_index.shift_in(1);
         t.super_visit_with(self);
         self.target_index.shift_out(1);
@@ -749,7 +752,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
         ControlFlow::CONTINUE
     }
 
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         let ScopeInstantiator { bound_region_scope, next_region, .. } = self;
 
         match r {
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index eb1a7806256..16d86e6243d 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -167,7 +167,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                 sup_type, sub_region, origin
             );
 
-            let sup_type = self.resolve_vars_if_possible(&sup_type);
+            let sup_type = self.resolve_vars_if_possible(sup_type);
 
             if let Some(region_bound_pairs) = region_bound_pairs_map.get(&body_id) {
                 let outlives = &mut TypeOutlives::new(
@@ -205,7 +205,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
             implicit_region_bound,
             param_env,
         );
-        let ty = self.resolve_vars_if_possible(&ty);
+        let ty = self.resolve_vars_if_possible(ty);
         outlives.type_must_outlive(origin, ty, region);
     }
 }
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 2b827f4f4ed..f69212c599b 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -124,10 +124,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         projection_ty: ty::ProjectionTy<'tcx>,
     ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
         let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
-        let erased_projection_ty = self.tcx.erase_regions(&projection_ty);
+        let erased_projection_ty = self.tcx.erase_regions(projection_ty);
         self.declared_generic_bounds_from_env_with_compare_fn(|ty| {
             if let ty::Projection(..) = ty.kind() {
-                let erased_ty = self.tcx.erase_regions(&ty);
+                let erased_ty = self.tcx.erase_regions(ty);
                 erased_ty == erased_projection_ty
             } else {
                 false
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index fe4ba5aa4e8..d72be0134fb 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -111,19 +111,17 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
 /// involve some hashing and so forth).
 pub struct UnresolvedTypeFinder<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
-
-    /// Used to find the type parameter name and location for error reporting.
-    pub first_unresolved: Option<(Ty<'tcx>, Option<Span>)>,
 }
 
 impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> {
     pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
-        UnresolvedTypeFinder { infcx, first_unresolved: None }
+        UnresolvedTypeFinder { infcx }
     }
 }
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+    type BreakTy = (Ty<'tcx>, Option<Span>);
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         let t = self.infcx.shallow_resolve(t);
         if t.has_infer_types() {
             if let ty::Infer(infer_ty) = *t.kind() {
@@ -144,8 +142,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
                 } else {
                     None
                 };
-                self.first_unresolved = Some((t, ty_var_span));
-                ControlFlow::BREAK
+                ControlFlow::Break((t, ty_var_span))
             } else {
                 // Otherwise, visit its contents.
                 t.super_visit_with(self)
@@ -164,7 +161,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
 /// Full type resolution replaces all type and region variables with
 /// their concrete results. If any variable cannot be replaced (never unified, etc)
 /// then an `Err` result is returned.
-pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: &T) -> FixupResult<'tcx, T>
+pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> FixupResult<'tcx, T>
 where
     T: TypeFoldable<'tcx>,
 {
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 1a1c2637a6f..c4a2ecee096 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -60,16 +60,16 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
 // TypeFoldable implementations.
 
 impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         traits::Obligation {
-            cause: self.cause.clone(),
+            cause: self.cause,
             recursion_depth: self.recursion_depth,
             predicate: self.predicate.fold_with(folder),
             param_env: self.param_env.fold_with(folder),
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.predicate.visit_with(visitor)
     }
 }
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index f6ef9840788..b0b0e4372b8 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -9,7 +9,7 @@ pub fn anonymize_predicate<'tcx>(
     tcx: TyCtxt<'tcx>,
     pred: ty::Predicate<'tcx>,
 ) -> ty::Predicate<'tcx> {
-    match pred.kind() {
+    match *pred.kind() {
         ty::PredicateKind::ForAll(binder) => {
             let new = ty::PredicateKind::ForAll(tcx.anonymize_late_bound_regions(binder));
             tcx.reuse_or_mk_predicate(pred, new)
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 88d2efe96d1..0935eb2bd71 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,6 +1,6 @@
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
-#![feature(set_stdio)]
+#![feature(internal_output_capture)]
 #![feature(nll)]
 #![feature(generator_trait)]
 #![feature(generators)]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 548b6c03daa..82cf4ab7f5c 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -6,6 +6,7 @@ use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::{self as ast, visit};
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
+use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
@@ -20,7 +21,6 @@ use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::middle;
 use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::steal::Steal;
 use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
 use rustc_mir as mir;
 use rustc_mir_build as mir_build;
@@ -239,16 +239,12 @@ fn configure_and_expand_inner<'a>(
 
     krate = sess.time("crate_injection", || {
         let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
-        let (krate, name) = rustc_builtin_macros::standard_library_imports::inject(
+        rustc_builtin_macros::standard_library_imports::inject(
             krate,
             &mut resolver,
             &sess,
             alt_std_name,
-        );
-        if let Some(name) = name {
-            sess.parse_sess.injected_crate_name.set(name).expect("not yet initialized");
-        }
-        krate
+        )
     });
 
     util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer());
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 1de7350a3e2..a2704c3adbf 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -3,6 +3,7 @@ use crate::passes::{self, BoxedResolver, QueryContext};
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
+use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::ErrorReported;
@@ -12,7 +13,6 @@ use rustc_incremental::DepGraphFuture;
 use rustc_lint::LintStore;
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
-use rustc_middle::ty::steal::Steal;
 use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt};
 use rustc_serialize::json;
 use rustc_session::config::{self, OutputFilenames, OutputType};
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index d9ec6d51cdf..20a7b47313e 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -25,7 +25,7 @@ use rustc_span::symbol::{sym, Symbol};
 use smallvec::SmallVec;
 use std::env;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
-use std::io::{self, Write};
+use std::io;
 use std::lazy::SyncOnceCell;
 use std::mem;
 use std::ops::DerefMut;
@@ -106,21 +106,6 @@ fn get_stack_size() -> Option<usize> {
     env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
 }
 
-struct Sink(Arc<Mutex<Vec<u8>>>);
-impl Write for Sink {
-    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-        Write::write(&mut *self.0.lock().unwrap(), data)
-    }
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-impl io::LocalOutput for Sink {
-    fn clone_box(&self) -> Box<dyn io::LocalOutput> {
-        Box::new(Self(self.0.clone()))
-    }
-}
-
 /// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
 /// for `'static` bounds.
 #[cfg(not(parallel_compiler))]
@@ -163,9 +148,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
 
     let main_handler = move || {
         rustc_span::with_session_globals(edition, || {
-            if let Some(stderr) = stderr {
-                io::set_panic(Some(box Sink(stderr.clone())));
-            }
+            io::set_output_capture(stderr.clone());
             f()
         })
     };
@@ -203,9 +186,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
             // on the new threads.
             let main_handler = move |thread: rayon::ThreadBuilder| {
                 rustc_span::SESSION_GLOBALS.set(session_globals, || {
-                    if let Some(stderr) = stderr {
-                        io::set_panic(Some(box Sink(stderr.clone())));
-                    }
+                    io::set_output_capture(stderr.clone());
                     thread.run()
                 })
             };
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 467a3a42590..38c71e6e925 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -880,7 +880,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             return FfiSafe;
         }
 
-        match ty.kind() {
+        match *ty.kind() {
             ty::Adt(def, _) if def.is_box() && matches!(self.mode, CItemKind::Definition) => {
                 FfiSafe
             }
@@ -1044,7 +1044,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     };
                 }
 
-                let sig = tcx.erase_late_bound_regions(&sig);
+                let sig = tcx.erase_late_bound_regions(sig);
                 if !sig.output().is_unit() {
                     let r = self.check_type_for_ffi(cache, sig.output());
                     match r {
@@ -1131,16 +1131,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
         struct ProhibitOpaqueTypes<'a, 'tcx> {
             cx: &'a LateContext<'tcx>,
-            ty: Option<Ty<'tcx>>,
         };
 
         impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
-            fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+            type BreakTy = Ty<'tcx>;
+
+            fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 match ty.kind() {
-                    ty::Opaque(..) => {
-                        self.ty = Some(ty);
-                        ControlFlow::BREAK
-                    }
+                    ty::Opaque(..) => ControlFlow::Break(ty),
                     // Consider opaque types within projections FFI-safe if they do not normalize
                     // to more opaque types.
                     ty::Projection(..) => {
@@ -1159,9 +1157,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             }
         }
 
-        let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None };
-        ty.visit_with(&mut visitor);
-        if let Some(ty) = visitor.ty {
+        if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() {
             self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None);
             true
         } else {
@@ -1218,7 +1214,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) {
         let def_id = self.cx.tcx.hir().local_def_id(id);
         let sig = self.cx.tcx.fn_sig(def_id);
-        let sig = self.cx.tcx.erase_late_bound_regions(&sig);
+        let sig = self.cx.tcx.erase_late_bound_regions(sig);
 
         for (input_ty, input_hir) in sig.inputs().iter().zip(decl.inputs) {
             self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false);
@@ -1295,7 +1291,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
         if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind {
             let item_def_id = cx.tcx.hir().local_def_id(it.hir_id);
             let t = cx.tcx.type_of(item_def_id);
-            let ty = cx.tcx.erase_regions(&t);
+            let ty = cx.tcx.erase_regions(t);
             let layout = match cx.layout_of(ty) {
                 Ok(layout) => layout,
                 Err(
diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs
index 8fa6e6a7101..082af087bf4 100644
--- a/compiler/rustc_macros/src/type_foldable.rs
+++ b/compiler/rustc_macros/src/type_foldable.rs
@@ -6,6 +6,12 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
     }
 
     s.add_bounds(synstructure::AddBounds::Generics);
+    let body_visit = s.each(|bind| {
+        quote! {
+            ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?;
+        }
+    });
+    s.bind_with(|_| synstructure::BindStyle::Move);
     let body_fold = s.each_variant(|vi| {
         let bindings = vi.bindings();
         vi.construct(|_, index| {
@@ -16,26 +22,20 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
         })
     });
 
-    let body_visit = s.each(|bind| {
-        quote! {
-            ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?;
-        }
-    });
-
     s.bound_impl(
         quote!(::rustc_middle::ty::fold::TypeFoldable<'tcx>),
         quote! {
             fn super_fold_with<__F: ::rustc_middle::ty::fold::TypeFolder<'tcx>>(
-                &self,
+                self,
                 __folder: &mut __F
             ) -> Self {
-                match *self { #body_fold }
+                match self { #body_fold }
             }
 
             fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(
                 &self,
                 __folder: &mut __F
-            ) -> ::std::ops::ControlFlow<()> {
+            ) -> ::std::ops::ControlFlow<__F::BreakTy> {
                 match *self { #body_visit }
                 ::std::ops::ControlFlow::CONTINUE
             }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index f6570cc95d2..672073b1d34 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -14,10 +14,10 @@ macro_rules! arena_types {
             [] layouts: rustc_target::abi::Layout,
             // AdtDef are interned and compared by address
             [] adt_def: rustc_middle::ty::AdtDef,
-            [] steal_mir: rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>,
+            [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<$tcx>>,
             [decode] mir: rustc_middle::mir::Body<$tcx>,
             [] steal_promoted:
-                rustc_middle::ty::steal::Steal<
+                rustc_data_structures::steal::Steal<
                     rustc_index::vec::IndexVec<
                         rustc_middle::mir::Promoted,
                         rustc_middle::mir::Body<$tcx>
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index d86e8987195..37ec3d3d1ca 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -806,25 +806,34 @@ impl<'hir> Map<'hir> {
     /// Given a node ID, gets a list of attributes associated with the AST
     /// corresponding to the node-ID.
     pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] {
-        let attrs = match self.find_entry(id).map(|entry| entry.node) {
-            Some(Node::Param(a)) => Some(&a.attrs[..]),
-            Some(Node::Local(l)) => Some(&l.attrs[..]),
-            Some(Node::Item(i)) => Some(&i.attrs[..]),
-            Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]),
-            Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]),
-            Some(Node::ImplItem(ref ii)) => Some(&ii.attrs[..]),
-            Some(Node::Variant(ref v)) => Some(&v.attrs[..]),
-            Some(Node::Field(ref f)) => Some(&f.attrs[..]),
-            Some(Node::Expr(ref e)) => Some(&*e.attrs),
-            Some(Node::Stmt(ref s)) => Some(s.kind.attrs(|id| self.item(id.id))),
-            Some(Node::Arm(ref a)) => Some(&*a.attrs),
-            Some(Node::GenericParam(param)) => Some(&param.attrs[..]),
+        let attrs = self.find_entry(id).map(|entry| match entry.node {
+            Node::Param(a) => &a.attrs[..],
+            Node::Local(l) => &l.attrs[..],
+            Node::Item(i) => &i.attrs[..],
+            Node::ForeignItem(fi) => &fi.attrs[..],
+            Node::TraitItem(ref ti) => &ti.attrs[..],
+            Node::ImplItem(ref ii) => &ii.attrs[..],
+            Node::Variant(ref v) => &v.attrs[..],
+            Node::Field(ref f) => &f.attrs[..],
+            Node::Expr(ref e) => &*e.attrs,
+            Node::Stmt(ref s) => s.kind.attrs(|id| self.item(id.id)),
+            Node::Arm(ref a) => &*a.attrs,
+            Node::GenericParam(param) => &param.attrs[..],
             // Unit/tuple structs/variants take the attributes straight from
             // the struct/variant definition.
-            Some(Node::Ctor(..)) => return self.attrs(self.get_parent_item(id)),
-            Some(Node::Crate(item)) => Some(&item.attrs[..]),
-            _ => None,
-        };
+            Node::Ctor(..) => self.attrs(self.get_parent_item(id)),
+            Node::Crate(item) => &item.attrs[..],
+            Node::MacroDef(def) => def.attrs,
+            Node::AnonConst(..)
+            | Node::PathSegment(..)
+            | Node::Ty(..)
+            | Node::Pat(..)
+            | Node::Binding(..)
+            | Node::TraitRef(..)
+            | Node::Block(..)
+            | Node::Lifetime(..)
+            | Node::Visibility(..) => &[],
+        });
         attrs.unwrap_or(&[])
     }
 
diff --git a/compiler/rustc_middle/src/ich/impls_ty.rs b/compiler/rustc_middle/src/ich/impls_ty.rs
index 8f15c99f951..69bb4e23c4c 100644
--- a/compiler/rustc_middle/src/ich/impls_ty.rs
+++ b/compiler/rustc_middle/src/ich/impls_ty.rs
@@ -184,15 +184,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::FloatVid {
     }
 }
 
-impl<'a, T> HashStable<StableHashingContext<'a>> for ty::steal::Steal<T>
-where
-    T: HashStable<StableHashingContext<'a>>,
-{
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        self.borrow().hash_stable(hcx, hasher);
-    }
-}
-
 impl<'a> HashStable<StableHashingContext<'a>> for crate::middle::privacy::AccessLevels {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 947b016a1fc..6e5f95c4527 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -286,7 +286,7 @@ impl<'tcx, V> Canonical<'tcx, V> {
 pub type QueryOutlivesConstraint<'tcx> =
     ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>;
 
-CloneTypeFoldableAndLiftImpls! {
+TrivialTypeFoldableAndLiftImpls! {
     for <'tcx> {
         crate::infer::canonical::Certainty,
         crate::infer::canonical::CanonicalVarInfo<'tcx>,
@@ -294,7 +294,7 @@ CloneTypeFoldableAndLiftImpls! {
     }
 }
 
-CloneTypeFoldableImpls! {
+TrivialTypeFoldableImpls! {
     for <'tcx> {
         crate::infer::canonical::CanonicalVarInfos<'tcx>,
     }
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 4a1d5459d1e..cdc5940d9ba 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -51,6 +51,7 @@
 #![feature(half_open_range_patterns)]
 #![feature(exclusive_range_pattern)]
 #![feature(control_flow_enum)]
+#![feature(associated_type_defaults)]
 #![recursion_limit = "512"]
 
 #[macro_use]
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 921086366be..c0f2a76c19d 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -48,21 +48,21 @@ macro_rules! CloneLiftImpls {
 /// Used for types that are `Copy` and which **do not care arena
 /// allocated data** (i.e., don't need to be folded).
 #[macro_export]
-macro_rules! CloneTypeFoldableImpls {
+macro_rules! TrivialTypeFoldableImpls {
     (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
         $(
             impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
                 fn super_fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
-                    &self,
+                    self,
                     _: &mut F
                 ) -> $ty {
-                    Clone::clone(self)
+                    self
                 }
 
                 fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
                     &self,
                     _: &mut F)
-                    -> ::std::ops::ControlFlow<()>
+                    -> ::std::ops::ControlFlow<F::BreakTy>
                 {
                     ::std::ops::ControlFlow::CONTINUE
                 }
@@ -71,7 +71,7 @@ macro_rules! CloneTypeFoldableImpls {
     };
 
     ($($ty:ty,)+) => {
-        CloneTypeFoldableImpls! {
+        TrivialTypeFoldableImpls! {
             for <'tcx> {
                 $($ty,)+
             }
@@ -80,9 +80,9 @@ macro_rules! CloneTypeFoldableImpls {
 }
 
 #[macro_export]
-macro_rules! CloneTypeFoldableAndLiftImpls {
+macro_rules! TrivialTypeFoldableAndLiftImpls {
     ($($t:tt)*) => {
-        CloneTypeFoldableImpls! { $($t)* }
+        TrivialTypeFoldableImpls! { $($t)* }
         CloneLiftImpls! { $($t)* }
     }
 }
@@ -96,7 +96,7 @@ macro_rules! EnumTypeFoldableImpl {
             $(where $($wc)*)*
         {
             fn super_fold_with<V: $crate::ty::fold::TypeFolder<$tcx>>(
-                &self,
+                self,
                 folder: &mut V,
             ) -> Self {
                 EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
@@ -105,7 +105,7 @@ macro_rules! EnumTypeFoldableImpl {
             fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
                 &self,
                 visitor: &mut V,
-            ) -> ::std::ops::ControlFlow<()> {
+            ) -> ::std::ops::ControlFlow<V::BreakTy> {
                 EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
             }
         }
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 978f08927c6..47c140e0b18 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -4,7 +4,7 @@
 pub use self::StabilityLevel::*;
 
 use crate::ty::{self, TyCtxt};
-use rustc_ast::CRATE_NODE_ID;
+use rustc_ast::NodeId;
 use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -211,13 +211,14 @@ pub fn early_report_deprecation(
     suggestion: Option<Symbol>,
     lint: &'static Lint,
     span: Span,
+    node_id: NodeId,
 ) {
     if span.in_derive_expansion() {
         return;
     }
 
     let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span);
-    lint_buffer.buffer_lint_with_diagnostic(lint, CRATE_NODE_ID, span, message, diag);
+    lint_buffer.buffer_lint_with_diagnostic(lint, node_id, span, message, diag);
 }
 
 fn late_report_deprecation(
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index e35ff6b996e..397d2ffd565 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -29,7 +29,7 @@ impl From<ErrorReported> for ErrorHandled {
     }
 }
 
-CloneTypeFoldableAndLiftImpls! {
+TrivialTypeFoldableAndLiftImpls! {
     ErrorHandled,
 }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index f366681bc75..0517ec5bb1a 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -67,7 +67,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ) -> EvalToConstValueResult<'tcx> {
         // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
         // improve caching of queries.
-        let inputs = self.erase_regions(&param_env.and(cid));
+        let inputs = self.erase_regions(param_env.and(cid));
         if let Some(span) = span {
             self.at(span).eval_to_const_value_raw(inputs)
         } else {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 5fe7b0f647d..9289d4708de 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -420,7 +420,9 @@ impl<'tcx> Body<'tcx> {
     /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
     /// locals that are neither arguments nor the return place).
     #[inline]
-    pub fn vars_and_temps_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
+    pub fn vars_and_temps_iter(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = Local> + ExactSizeIterator {
         let arg_count = self.arg_count;
         let local_count = self.local_decls.len();
         (arg_count + 1..local_count).map(Local::new)
@@ -742,7 +744,7 @@ pub enum ImplicitSelfKind {
     None,
 }
 
-CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, }
+TrivialTypeFoldableAndLiftImpls! { BindingForm<'tcx>, }
 
 mod binding_form_impl {
     use crate::ich::StableHashingContext;
@@ -2452,32 +2454,20 @@ impl UserTypeProjection {
     }
 }
 
-CloneTypeFoldableAndLiftImpls! { ProjectionKind, }
+TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
 
 impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        use crate::mir::ProjectionElem::*;
-
-        let base = self.base.fold_with(folder);
-        let projs: Vec<_> = self
-            .projs
-            .iter()
-            .map(|&elem| match elem {
-                Deref => Deref,
-                Field(f, ()) => Field(f, ()),
-                Index(()) => Index(()),
-                Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
-                ConstantIndex { offset, min_length, from_end } => {
-                    ConstantIndex { offset, min_length, from_end }
-                }
-                Subslice { from, to, from_end } => Subslice { from, to, from_end },
-            })
-            .collect();
-
-        UserTypeProjection { base, projs }
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        UserTypeProjection {
+            base: self.base.fold_with(folder),
+            projs: self.projs.fold_with(folder),
+        }
     }
 
-    fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<()> {
+    fn super_visit_with<Vs: TypeVisitor<'tcx>>(
+        &self,
+        visitor: &mut Vs,
+    ) -> ControlFlow<Vs::BreakTy> {
         self.base.visit_with(visitor)
         // Note: there's nothing in `self.proj` to visit.
     }
diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs
index a8b74883355..fd6bb76dc43 100644
--- a/compiler/rustc_middle/src/mir/predecessors.rs
+++ b/compiler/rustc_middle/src/mir/predecessors.rs
@@ -75,6 +75,6 @@ impl<CTX> HashStable<CTX> for PredecessorCache {
     }
 }
 
-CloneTypeFoldableAndLiftImpls! {
+TrivialTypeFoldableAndLiftImpls! {
     PredecessorCache,
 }
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 0801188b278..da8e189ba9d 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -2,8 +2,9 @@
 
 use super::*;
 use crate::ty;
+use rustc_data_structures::functor::IdFunctor;
 
-CloneTypeFoldableAndLiftImpls! {
+TrivialTypeFoldableAndLiftImpls! {
     BlockTailInfo,
     MirPhase,
     SourceInfo,
@@ -15,34 +16,33 @@ CloneTypeFoldableAndLiftImpls! {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         use crate::mir::TerminatorKind::*;
 
         let kind = match self.kind {
             Goto { target } => Goto { target },
-            SwitchInt { ref discr, switch_ty, ref targets } => SwitchInt {
+            SwitchInt { discr, switch_ty, targets } => SwitchInt {
                 discr: discr.fold_with(folder),
                 switch_ty: switch_ty.fold_with(folder),
-                targets: targets.clone(),
+                targets,
             },
-            Drop { ref place, target, unwind } => {
+            Drop { place, target, unwind } => {
                 Drop { place: place.fold_with(folder), target, unwind }
             }
-            DropAndReplace { ref place, ref value, target, unwind } => DropAndReplace {
+            DropAndReplace { place, value, target, unwind } => DropAndReplace {
                 place: place.fold_with(folder),
                 value: value.fold_with(folder),
                 target,
                 unwind,
             },
-            Yield { ref value, resume, ref resume_arg, drop } => Yield {
+            Yield { value, resume, resume_arg, drop } => Yield {
                 value: value.fold_with(folder),
                 resume,
                 resume_arg: resume_arg.fold_with(folder),
                 drop,
             },
-            Call { ref func, ref args, ref destination, cleanup, from_hir_call, fn_span } => {
-                let dest =
-                    destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest));
+            Call { func, args, destination, cleanup, from_hir_call, fn_span } => {
+                let dest = destination.map(|(loc, dest)| (loc.fold_with(folder), dest));
 
                 Call {
                     func: func.fold_with(folder),
@@ -53,17 +53,17 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
                     fn_span,
                 }
             }
-            Assert { ref cond, expected, ref msg, target, cleanup } => {
+            Assert { cond, expected, msg, target, cleanup } => {
                 use AssertKind::*;
                 let msg = match msg {
                     BoundsCheck { len, index } => {
                         BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
                     }
-                    Overflow(op, l, r) => Overflow(*op, l.fold_with(folder), r.fold_with(folder)),
+                    Overflow(op, l, r) => Overflow(op, l.fold_with(folder), r.fold_with(folder)),
                     OverflowNeg(op) => OverflowNeg(op.fold_with(folder)),
                     DivisionByZero(op) => DivisionByZero(op.fold_with(folder)),
                     RemainderByZero(op) => RemainderByZero(op.fold_with(folder)),
-                    ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg.clone(),
+                    ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg,
                 };
                 Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
             }
@@ -76,7 +76,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
                 FalseEdge { real_target, imaginary_target }
             }
             FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
-            InlineAsm { template, ref operands, options, line_spans, destination } => InlineAsm {
+            InlineAsm { template, operands, options, line_spans, destination } => InlineAsm {
                 template,
                 operands: operands.fold_with(folder),
                 options,
@@ -87,7 +87,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
         Terminator { source_info: self.source_info, kind }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         use crate::mir::TerminatorKind::*;
 
         match self.kind {
@@ -140,61 +140,56 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
-        *self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
+        self
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.local.visit_with(visitor)?;
         self.projection.visit_with(visitor)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>();
-        folder.tcx().intern_place_elems(&v)
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         use crate::mir::Rvalue::*;
-        match *self {
-            Use(ref op) => Use(op.fold_with(folder)),
-            Repeat(ref op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)),
+        match self {
+            Use(op) => Use(op.fold_with(folder)),
+            Repeat(op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)),
             ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)),
-            Ref(region, bk, ref place) => {
-                Ref(region.fold_with(folder), bk, place.fold_with(folder))
-            }
-            AddressOf(mutability, ref place) => AddressOf(mutability, place.fold_with(folder)),
-            Len(ref place) => Len(place.fold_with(folder)),
-            Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
-            BinaryOp(op, ref rhs, ref lhs) => {
-                BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder))
-            }
-            CheckedBinaryOp(op, ref rhs, ref lhs) => {
+            Ref(region, bk, place) => Ref(region.fold_with(folder), bk, place.fold_with(folder)),
+            AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)),
+            Len(place) => Len(place.fold_with(folder)),
+            Cast(kind, op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
+            BinaryOp(op, rhs, lhs) => BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)),
+            CheckedBinaryOp(op, rhs, lhs) => {
                 CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder))
             }
-            UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)),
-            Discriminant(ref place) => Discriminant(place.fold_with(folder)),
+            UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)),
+            Discriminant(place) => Discriminant(place.fold_with(folder)),
             NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)),
-            Aggregate(ref kind, ref fields) => {
-                let kind = box match **kind {
+            Aggregate(kind, fields) => {
+                let kind = kind.map_id(|kind| match kind {
                     AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
                     AggregateKind::Tuple => AggregateKind::Tuple,
                     AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
@@ -210,13 +205,13 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
                     AggregateKind::Generator(id, substs, movablity) => {
                         AggregateKind::Generator(id, substs.fold_with(folder), movablity)
                     }
-                };
+                });
                 Aggregate(kind, fields.fold_with(folder))
             }
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         use crate::mir::Rvalue::*;
         match *self {
             Use(ref op) => op.visit_with(visitor),
@@ -263,15 +258,15 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)),
-            Operand::Move(ref place) => Operand::Move(place.fold_with(folder)),
-            Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        match self {
+            Operand::Copy(place) => Operand::Copy(place.fold_with(folder)),
+            Operand::Move(place) => Operand::Move(place.fold_with(folder)),
+            Operand::Constant(c) => Operand::Constant(c.fold_with(folder)),
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match *self {
             Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
             Operand::Constant(ref c) => c.visit_with(visitor),
@@ -280,10 +275,10 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         use crate::mir::ProjectionElem::*;
 
-        match *self {
+        match self {
             Deref => Deref,
             Field(f, ty) => Field(f, ty.fold_with(folder)),
             Index(v) => Index(v.fold_with(folder)),
@@ -295,7 +290,10 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
         }
     }
 
-    fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<()> {
+    fn super_visit_with<Vs: TypeVisitor<'tcx>>(
+        &self,
+        visitor: &mut Vs,
+    ) -> ControlFlow<Vs::BreakTy> {
         use crate::mir::ProjectionElem::*;
 
         match self {
@@ -307,41 +305,41 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Field {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
-        *self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
+        self
     }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
-        *self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
+        self
     }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
-        self.clone()
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
+        self
     }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         Constant {
             span: self.span,
             user_ty: self.user_ty.fold_with(folder),
             literal: self.literal.fold_with(folder),
         }
     }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.literal.visit_with(visitor)
     }
 }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index d8d639ab734..638dd8ce970 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1,70 +1,70 @@
+//! # The MIR Visitor
+//!
+//! ## Overview
+//!
+//! There are two visitors, one for immutable and one for mutable references,
+//! but both are generated by the following macro. The code is written according
+//! to the following conventions:
+//!
+//! - introduce a `visit_foo` and a `super_foo` method for every MIR type
+//! - `visit_foo`, by default, calls `super_foo`
+//! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
+//!
+//! This allows you as a user to override `visit_foo` for types are
+//! interested in, and invoke (within that method) call
+//! `self.super_foo` to get the default behavior. Just as in an OO
+//! language, you should never call `super` methods ordinarily except
+//! in that circumstance.
+//!
+//! For the most part, we do not destructure things external to the
+//! MIR, e.g., types, spans, etc, but simply visit them and stop. This
+//! avoids duplication with other visitors like `TypeFoldable`.
+//!
+//! ## Updating
+//!
+//! The code is written in a very deliberate style intended to minimize
+//! the chance of things being overlooked. You'll notice that we always
+//! use pattern matching to reference fields and we ensure that all
+//! matches are exhaustive.
+//!
+//! For example, the `super_basic_block_data` method begins like this:
+//!
+//! ```rust
+//! fn super_basic_block_data(&mut self,
+//!                           block: BasicBlock,
+//!                           data: & $($mutability)? BasicBlockData<'tcx>) {
+//!     let BasicBlockData {
+//!         statements,
+//!         terminator,
+//!         is_cleanup: _
+//!     } = *data;
+//!
+//!     for statement in statements {
+//!         self.visit_statement(block, statement);
+//!     }
+//!
+//!     ...
+//! }
+//! ```
+//!
+//! Here we used `let BasicBlockData { <fields> } = *data` deliberately,
+//! rather than writing `data.statements` in the body. This is because if one
+//! adds a new field to `BasicBlockData`, one will be forced to revise this code,
+//! and hence one will (hopefully) invoke the correct visit methods (if any).
+//!
+//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
+//! That means you never write `..` to skip over fields, nor do you write `_`
+//! to skip over variants in a `match`.
+//!
+//! The only place that `_` is acceptable is to match a field (or
+//! variant argument) that does not require visiting, as in
+//! `is_cleanup` above.
+
 use crate::mir::*;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{CanonicalUserTypeAnnotation, Ty};
 use rustc_span::Span;
 
-// # The MIR Visitor
-//
-// ## Overview
-//
-// There are two visitors, one for immutable and one for mutable references,
-// but both are generated by the following macro. The code is written according
-// to the following conventions:
-//
-// - introduce a `visit_foo` and a `super_foo` method for every MIR type
-// - `visit_foo`, by default, calls `super_foo`
-// - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
-//
-// This allows you as a user to override `visit_foo` for types are
-// interested in, and invoke (within that method) call
-// `self.super_foo` to get the default behavior. Just as in an OO
-// language, you should never call `super` methods ordinarily except
-// in that circumstance.
-//
-// For the most part, we do not destructure things external to the
-// MIR, e.g., types, spans, etc, but simply visit them and stop. This
-// avoids duplication with other visitors like `TypeFoldable`.
-//
-// ## Updating
-//
-// The code is written in a very deliberate style intended to minimize
-// the chance of things being overlooked. You'll notice that we always
-// use pattern matching to reference fields and we ensure that all
-// matches are exhaustive.
-//
-// For example, the `super_basic_block_data` method begins like this:
-//
-// ```rust
-// fn super_basic_block_data(&mut self,
-//                           block: BasicBlock,
-//                           data: & $($mutability)? BasicBlockData<'tcx>) {
-//     let BasicBlockData {
-//         statements,
-//         terminator,
-//         is_cleanup: _
-//     } = *data;
-//
-//     for statement in statements {
-//         self.visit_statement(block, statement);
-//     }
-//
-//     ...
-// }
-// ```
-//
-// Here we used `let BasicBlockData { <fields> } = *data` deliberately,
-// rather than writing `data.statements` in the body. This is because if one
-// adds a new field to `BasicBlockData`, one will be forced to revise this code,
-// and hence one will (hopefully) invoke the correct visit methods (if any).
-//
-// For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
-// That means you never write `..` to skip over fields, nor do you write `_`
-// to skip over variants in a `match`.
-//
-// The only place that `_` is acceptable is to match a field (or
-// variant argument) that does not require visiting, as in
-// `is_cleanup` above.
-
 macro_rules! make_mir_visitor {
     ($visitor_trait_name:ident, $($mutability:ident)?) => {
         pub trait $visitor_trait_name<'tcx> {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 72360e219ec..634d50368bd 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -367,7 +367,7 @@ rustc_queries! {
 
     TypeChecking {
         /// Erases regions from `ty` to yield a new type.
-        /// Normally you would just use `tcx.erase_regions(&value)`,
+        /// Normally you would just use `tcx.erase_regions(value)`,
         /// however, which uses this query as a kind of cache.
         query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
             // This query is not expected to have input -- as a result, it
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index b8f6675b8e2..194e275496e 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -105,7 +105,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
 ///////////////////////////////////////////////////////////////////////////
 // Lift implementations
 
-CloneTypeFoldableAndLiftImpls! {
+TrivialTypeFoldableAndLiftImpls! {
     super::IfExpressionCause,
     super::ImplSourceDiscriminantKindData,
 }
diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs
index 3237147c8ba..7ab192daf4b 100644
--- a/compiler/rustc_middle/src/ty/binding.rs
+++ b/compiler/rustc_middle/src/ty/binding.rs
@@ -8,7 +8,7 @@ pub enum BindingMode {
     BindByValue(Mutability),
 }
 
-CloneTypeFoldableAndLiftImpls! { BindingMode, }
+TrivialTypeFoldableAndLiftImpls! { BindingMode, }
 
 impl BindingMode {
     pub fn convert(ba: BindingAnnotation) -> BindingMode {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index ca51f2a9411..ecf2837b3e4 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -103,9 +103,9 @@ impl<'tcx> ConstKind<'tcx> {
             // so that we don't try to invoke this query with
             // any region variables.
             let param_env_and_substs = tcx
-                .erase_regions(&param_env)
+                .erase_regions(param_env)
                 .with_reveal_all_normalized(tcx)
-                .and(tcx.erase_regions(&substs));
+                .and(tcx.erase_regions(substs));
 
             // HACK(eddyb) when the query key would contain inference variables,
             // attempt using identity substs and `ParamEnv` instead, that will succeed
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 3838e1b006f..36cbd36a770 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -14,7 +14,6 @@ use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
 use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
 use crate::traits;
 use crate::ty::query::{self, TyCtxtAt};
-use crate::ty::steal::Steal;
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
 use crate::ty::TyKind::*;
 use crate::ty::{
@@ -33,6 +32,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
 use rustc_data_structures::stable_hasher::{
     hash_stable_hashmap, HashStable, StableHasher, StableVec,
 };
+use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::ErrorReported;
@@ -415,9 +415,19 @@ pub struct TypeckResults<'tcx> {
     /// entire variable.
     pub closure_captures: ty::UpvarListMap,
 
+    /// Tracks the minimum captures required for a closure;
+    /// see `MinCaptureInformationMap` for more details.
+    pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
+
     /// Stores the type, expression, span and optional scope span of all types
     /// that are live across the yield of this generator (if a generator).
     pub generator_interior_types: Vec<GeneratorInteriorTypeCause<'tcx>>,
+
+    /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
+    /// as `&[u8]`, depending on the pattern  in which they are used.
+    /// This hashset records all instances where we behave
+    /// like this to allow `const_to_pat` to reliably handle this situation.
+    pub treat_byte_string_as_slice: ItemLocalSet,
 }
 
 impl<'tcx> TypeckResults<'tcx> {
@@ -442,7 +452,9 @@ impl<'tcx> TypeckResults<'tcx> {
             tainted_by_errors: None,
             concrete_opaque_types: Default::default(),
             closure_captures: Default::default(),
+            closure_min_captures: Default::default(),
             generator_interior_types: Default::default(),
+            treat_byte_string_as_slice: Default::default(),
         }
     }
 
@@ -676,7 +688,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
             tainted_by_errors,
             ref concrete_opaque_types,
             ref closure_captures,
+            ref closure_min_captures,
             ref generator_interior_types,
+            ref treat_byte_string_as_slice,
         } = *self;
 
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
@@ -709,7 +723,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
             tainted_by_errors.hash_stable(hcx, hasher);
             concrete_opaque_types.hash_stable(hcx, hasher);
             closure_captures.hash_stable(hcx, hasher);
+            closure_min_captures.hash_stable(hcx, hasher);
             generator_interior_types.hash_stable(hcx, hasher);
+            treat_byte_string_as_slice.hash_stable(hcx, hasher);
         })
     }
 }
@@ -1495,7 +1511,7 @@ impl<'tcx> TyCtxt<'tcx> {
         match ret_ty.kind() {
             ty::FnDef(_, _) => {
                 let sig = ret_ty.fn_sig(self);
-                let output = self.erase_late_bound_regions(&sig.output());
+                let output = self.erase_late_bound_regions(sig.output());
                 if output.is_impl_trait() {
                     let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
                     Some((output, fn_decl.output.span()))
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 48d0fc1839e..4412ba9408c 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -15,17 +15,17 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Returns an equivalent value with all free regions removed (note
     /// that late-bound regions remain, because they are important for
     /// subtyping, but they are anonymized and normalized as well)..
-    pub fn erase_regions<T>(self, value: &T) -> T
+    pub fn erase_regions<T>(self, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
         // If there's nothing to erase avoid performing the query at all
         if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
-            return value.clone();
+            return value;
         }
-
+        debug!("erase_regions({:?})", value);
         let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
-        debug!("erase_regions({:?}) = {:?}", value, value1);
+        debug!("erase_regions = {:?}", value1);
         value1
     }
 }
@@ -43,7 +43,7 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
         if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) }
     }
 
-    fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+    fn fold_binder<T>(&mut self, t: ty::Binder<T>) -> ty::Binder<T>
     where
         T: TypeFoldable<'tcx>,
     {
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 70a8157c04a..1883c89a151 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -44,13 +44,13 @@ use std::ops::ControlFlow;
 ///
 /// To implement this conveniently, use the derive macro located in librustc_macros.
 pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self;
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         self.super_fold_with(folder)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()>;
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.super_visit_with(visitor)
     }
 
@@ -73,7 +73,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     }
 
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.visit_with(&mut HasTypeFlagsVisitor { flags }).is_break()
+        self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
     }
     fn has_projections(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_PROJECTION)
@@ -142,26 +142,13 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     fn still_further_specializable(&self) -> bool {
         self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
     }
-
-    /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`.
-    fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> ControlFlow<()>) -> ControlFlow<()> {
-        pub struct Visitor<F>(F);
-
-        impl<'tcx, F: FnMut(Ty<'tcx>) -> ControlFlow<()>> TypeVisitor<'tcx> for Visitor<F> {
-            fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
-                self.0(ty)
-            }
-        }
-
-        self.visit_with(&mut Visitor(visit))
-    }
 }
 
 impl TypeFoldable<'tcx> for hir::Constness {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
-        *self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
+        self
     }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
@@ -174,7 +161,7 @@ impl TypeFoldable<'tcx> for hir::Constness {
 pub trait TypeFolder<'tcx>: Sized {
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
 
-    fn fold_binder<T>(&mut self, t: &Binder<T>) -> Binder<T>
+    fn fold_binder<T>(&mut self, t: Binder<T>) -> Binder<T>
     where
         T: TypeFoldable<'tcx>,
     {
@@ -195,23 +182,25 @@ pub trait TypeFolder<'tcx>: Sized {
 }
 
 pub trait TypeVisitor<'tcx>: Sized {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> {
+    type BreakTy = !;
+
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> {
         t.super_visit_with(self)
     }
 
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         t.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         r.super_visit_with(self)
     }
 
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
+    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         c.super_visit_with(self)
     }
 
-    fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<()> {
+    fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         p.super_visit_with(self)
     }
 }
@@ -266,7 +255,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// and skipped.
     pub fn fold_regions<T>(
         self,
-        value: &T,
+        value: T,
         skipped_regions: &mut bool,
         mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
     ) -> T
@@ -329,14 +318,19 @@ impl<'tcx> TyCtxt<'tcx> {
         where
             F: FnMut(ty::Region<'tcx>) -> bool,
         {
-            fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> {
+            type BreakTy = ();
+
+            fn visit_binder<T: TypeFoldable<'tcx>>(
+                &mut self,
+                t: &Binder<T>,
+            ) -> ControlFlow<Self::BreakTy> {
                 self.outer_index.shift_in(1);
                 let result = t.as_ref().skip_binder().visit_with(self);
                 self.outer_index.shift_out(1);
                 result
             }
 
-            fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+            fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 match *r {
                     ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => {
                         ControlFlow::CONTINUE
@@ -351,7 +345,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 }
             }
 
-            fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+            fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 // We're only interested in types involving regions
                 if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
                     ty.super_visit_with(self)
@@ -406,7 +400,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
+    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> {
         self.current_index.shift_in(1);
         let t = t.super_fold_with(self);
         self.current_index.shift_out(1);
@@ -466,7 +460,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
+    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> {
         self.current_index.shift_in(1);
         let t = t.super_fold_with(self);
         self.current_index.shift_out(1);
@@ -549,7 +543,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// contain escaping bound types.
     pub fn replace_late_bound_regions<T, F>(
         self,
-        value: &Binder<T>,
+        value: Binder<T>,
         fld_r: F,
     ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
     where
@@ -561,7 +555,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let fld_c = |bound_ct, ty| {
             self.mk_const(ty::Const { val: ty::ConstKind::Bound(ty::INNERMOST, bound_ct), ty })
         };
-        self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c)
+        self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c)
     }
 
     /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping
@@ -569,7 +563,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// closure replaces escaping bound consts.
     pub fn replace_escaping_bound_vars<T, F, G, H>(
         self,
-        value: &T,
+        value: T,
         mut fld_r: F,
         mut fld_t: G,
         mut fld_c: H,
@@ -609,7 +603,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// types.
     pub fn replace_bound_vars<T, F, G, H>(
         self,
-        value: &Binder<T>,
+        value: Binder<T>,
         fld_r: F,
         fld_t: G,
         fld_c: H,
@@ -620,16 +614,12 @@ impl<'tcx> TyCtxt<'tcx> {
         H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>,
         T: TypeFoldable<'tcx>,
     {
-        self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c)
+        self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c)
     }
 
     /// Replaces any late-bound regions bound in `value` with
     /// free variants attached to `all_outlive_scope`.
-    pub fn liberate_late_bound_regions<T>(
-        self,
-        all_outlive_scope: DefId,
-        value: &ty::Binder<T>,
-    ) -> T
+    pub fn liberate_late_bound_regions<T>(self, all_outlive_scope: DefId, value: ty::Binder<T>) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -683,7 +673,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also
     /// method lookup and a few other places where precise region relationships are not required.
-    pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
+    pub fn erase_late_bound_regions<T>(self, value: Binder<T>) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -698,7 +688,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
     /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and
     /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization.
-    pub fn anonymize_late_bound_regions<T>(self, sig: &Binder<T>) -> Binder<T>
+    pub fn anonymize_late_bound_regions<T>(self, sig: Binder<T>) -> Binder<T>
     where
         T: TypeFoldable<'tcx>,
     {
@@ -740,7 +730,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
+    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> {
         self.current_index.shift_in(1);
         let t = t.super_fold_with(self);
         self.current_index.shift_out(1);
@@ -804,7 +794,7 @@ pub fn shift_region<'tcx>(
     }
 }
 
-pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: &T, amount: u32) -> T
+pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: T, amount: u32) -> T
 where
     T: TypeFoldable<'tcx>,
 {
@@ -813,6 +803,9 @@ where
     value.fold_with(&mut Shifter::new(tcx, amount))
 }
 
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+struct FoundEscapingVars;
+
 /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
 /// bound region or a bound type.
 ///
@@ -844,93 +837,114 @@ struct HasEscapingVarsVisitor {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> {
+    type BreakTy = FoundEscapingVars;
+
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> {
         self.outer_index.shift_in(1);
         let result = t.super_visit_with(self);
         self.outer_index.shift_out(1);
         result
     }
 
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // If the outer-exclusive-binder is *strictly greater* than
         // `outer_index`, that means that `t` contains some content
         // bound at `outer_index` or above (because
         // `outer_exclusive_binder` is always 1 higher than the
         // content in `t`). Therefore, `t` has some escaping vars.
         if t.outer_exclusive_binder > self.outer_index {
-            ControlFlow::BREAK
+            ControlFlow::Break(FoundEscapingVars)
         } else {
             ControlFlow::CONTINUE
         }
     }
 
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         // If the region is bound by `outer_index` or anything outside
         // of outer index, then it escapes the binders we have
         // visited.
         if r.bound_at_or_above_binder(self.outer_index) {
-            ControlFlow::BREAK
+            ControlFlow::Break(FoundEscapingVars)
         } else {
             ControlFlow::CONTINUE
         }
     }
 
-    fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
+    fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         // we don't have a `visit_infer_const` callback, so we have to
         // hook in here to catch this case (annoying...), but
         // otherwise we do want to remember to visit the rest of the
         // const, as it has types/regions embedded in a lot of other
         // places.
         match ct.val {
-            ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => ControlFlow::BREAK,
+            ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
+                ControlFlow::Break(FoundEscapingVars)
+            }
             _ => ct.super_visit_with(self),
         }
     }
 
-    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> {
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         if predicate.inner.outer_exclusive_binder > self.outer_index {
-            ControlFlow::BREAK
+            ControlFlow::Break(FoundEscapingVars)
         } else {
             ControlFlow::CONTINUE
         }
     }
 }
 
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+struct FoundFlags;
+
 // FIXME: Optimize for checking for infer flags
 struct HasTypeFlagsVisitor {
     flags: ty::TypeFlags,
 }
 
 impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
-    fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> {
+    type BreakTy = FoundFlags;
+
+    fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
         debug!(
             "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
             t,
             t.flags(),
             self.flags
         );
-        if t.flags().intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
+        if t.flags().intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::CONTINUE
+        }
     }
 
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = r.type_flags();
         debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags);
-        if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
+        if flags.intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::CONTINUE
+        }
     }
 
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
+    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = FlagComputation::for_const(c);
         debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags);
-        if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
+        if flags.intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::CONTINUE
+        }
     }
 
-    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> {
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!(
             "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
             predicate, predicate.inner.flags, self.flags
         );
         if predicate.inner.flags.intersects(self.flags) {
-            ControlFlow::BREAK
+            ControlFlow::Break(FoundFlags)
         } else {
             ControlFlow::CONTINUE
         }
@@ -964,14 +978,14 @@ impl LateBoundRegionsCollector {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> {
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> {
         self.current_index.shift_in(1);
         let result = t.super_visit_with(self);
         self.current_index.shift_out(1);
         result
     }
 
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // if we are only looking for "constrained" region, we have to
         // ignore the inputs to a projection, as they may not appear
         // in the normalized form
@@ -984,7 +998,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
         t.super_visit_with(self)
     }
 
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
+    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         // if we are only looking for "constrained" region, we have to
         // ignore the inputs of an unevaluated const, as they may not appear
         // in the normalized form
@@ -997,7 +1011,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
         c.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         if let ty::ReLateBound(debruijn, br) = *r {
             if debruijn == self.current_index {
                 self.regions.insert(br);
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 306cebd9cb7..f52466d85f8 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -359,15 +359,15 @@ impl<'tcx> Instance<'tcx> {
         // HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)`
         // below is more likely to ignore the bounds in scope (e.g. if the only
         // generic parameters mentioned by `substs` were lifetime ones).
-        let substs = tcx.erase_regions(&substs);
+        let substs = tcx.erase_regions(substs);
 
         // FIXME(eddyb) should this always use `param_env.with_reveal_all()`?
         if let Some((did, param_did)) = def.as_const_arg() {
             tcx.resolve_instance_of_const_arg(
-                tcx.erase_regions(&param_env.and((did, param_did, substs))),
+                tcx.erase_regions(param_env.and((did, param_did, substs))),
             )
         } else {
-            tcx.resolve_instance(tcx.erase_regions(&param_env.and((def.did, substs))))
+            tcx.resolve_instance(tcx.erase_regions(param_env.and((def.did, substs))))
         }
     }
 
@@ -452,7 +452,7 @@ impl<'tcx> Instance<'tcx> {
         let self_ty = tcx.mk_closure(closure_did, substs);
 
         let sig = substs.as_closure().sig();
-        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
         assert_eq!(sig.inputs().len(), 1);
         let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
 
@@ -485,7 +485,7 @@ impl<'tcx> Instance<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        v: &T,
+        v: T,
     ) -> T
     where
         T: TypeFoldable<'tcx> + Clone,
@@ -493,7 +493,7 @@ impl<'tcx> Instance<'tcx> {
         if let Some(substs) = self.substs_for_mir_body() {
             tcx.subst_and_normalize_erasing_regions(substs, param_env, v)
         } else {
-            tcx.normalize_erasing_regions(param_env, v.clone())
+            tcx.normalize_erasing_regions(param_env, v)
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 1e93c3650b8..5626c864fe1 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -176,7 +176,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
         match *self {
             LayoutError::Unknown(ty) => write!(f, "the type `{}` has an unknown layout", ty),
             LayoutError::SizeOverflow(ty) => {
-                write!(f, "the type `{}` is too big for the current architecture", ty)
+                write!(f, "values of the type `{}` are too big for the current architecture", ty)
             }
         }
     }
@@ -1756,7 +1756,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
                 match tail.kind() {
                     ty::Param(_) | ty::Projection(_) => {
                         debug_assert!(tail.has_param_types_or_consts());
-                        Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(&tail) })
+                        Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
                     }
                     _ => bug!(
                         "SizeSkeleton::compute({}): layout errored ({}), yet \
@@ -2545,7 +2545,7 @@ where
     ) -> Self {
         debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
 
-        let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+        let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
 
         use rustc_target::spec::abi::Abi::*;
         let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index db11746971d..6a67935cd98 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -6,6 +6,7 @@ pub use self::IntVarValue::*;
 pub use self::Variance::*;
 
 use crate::hir::exports::ExportMap;
+use crate::hir::place::Place as HirPlace;
 use crate::ich::StableHashingContext;
 use crate::middle::cstore::CrateStoreDyn;
 use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
@@ -106,7 +107,6 @@ pub mod outlives;
 pub mod print;
 pub mod query;
 pub mod relate;
-pub mod steal;
 pub mod subst;
 pub mod trait_def;
 pub mod util;
@@ -686,6 +686,12 @@ pub struct UpvarId {
     pub closure_expr_id: LocalDefId,
 }
 
+impl UpvarId {
+    pub fn new(var_hir_id: hir::HirId, closure_def_id: LocalDefId) -> UpvarId {
+        UpvarId { var_path: UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id }
+    }
+}
+
 #[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
@@ -768,6 +774,56 @@ pub struct UpvarBorrow<'tcx> {
     pub region: ty::Region<'tcx>,
 }
 
+/// Given the closure DefId this map provides a map of root variables to minimum
+/// set of `CapturedPlace`s that need to be tracked to support all captures of that closure.
+pub type MinCaptureInformationMap<'tcx> = FxHashMap<DefId, RootVariableMinCaptureList<'tcx>>;
+
+/// Part of `MinCaptureInformationMap`; Maps a root variable to the list of `CapturedPlace`.
+/// Used to track the minimum set of `Place`s that need to be captured to support all
+/// Places captured by the closure starting at a given root variable.
+///
+/// This provides a convenient and quick way of checking if a variable being used within
+/// a closure is a capture of a local variable.
+pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureList<'tcx>>;
+
+/// Part of `MinCaptureInformationMap`; List of `CapturePlace`s.
+pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
+
+/// A `Place` and the corresponding `CaptureInfo`.
+#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct CapturedPlace<'tcx> {
+    pub place: HirPlace<'tcx>,
+    pub info: CaptureInfo<'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)]
+pub struct CaptureInfo<'tcx> {
+    /// Expr Id pointing to use that resulted in selecting the current capture kind
+    ///
+    /// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is
+    /// possible that we don't see the use of a particular place resulting in expr_id being
+    /// None. In such case we fallback on uvpars_mentioned for span.
+    ///
+    /// Eg:
+    /// ```rust,no_run
+    /// let x = 5;
+    ///
+    /// let c = || {
+    ///     let _ = x
+    /// };
+    /// ```
+    ///
+    /// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured,
+    /// but we won't see it being used during capture analysis, since it's essentially a discard.
+    pub expr_id: Option<hir::HirId>,
+
+    /// Capture mode that was selected
+    pub capture_kind: UpvarCapture<'tcx>,
+}
+
 pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
 pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
 
@@ -1789,11 +1845,11 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
-    fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.caller_bounds().visit_with(visitor)?;
         self.reveal().visit_with(visitor)
     }
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index a594a8ad512..9d97815a5f1 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -30,7 +30,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         // Erase first before we do the real query -- this keeps the
         // cache from being too polluted.
-        let value = self.erase_regions(&value);
+        let value = self.erase_regions(value);
         if !value.has_projections() {
             value
         } else {
@@ -49,7 +49,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn normalize_erasing_late_bound_regions<T>(
         self,
         param_env: ty::ParamEnv<'tcx>,
-        value: &ty::Binder<T>,
+        value: ty::Binder<T>,
     ) -> T
     where
         T: TypeFoldable<'tcx>,
@@ -65,7 +65,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         param_substs: SubstsRef<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: &T,
+        value: T,
     ) -> T
     where
         T: TypeFoldable<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 1e4fd0921ee..38f8e779f6a 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1750,7 +1750,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
         define_scoped_cx!(self);
 
         let mut region_index = self.region_index;
-        let new_value = self.tcx.replace_late_bound_regions(value, |br| {
+        let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| {
             let _ = start_or_continue(&mut self, "for<", ", ");
             let br = match br {
                 ty::BrNamed(_, name) => {
@@ -1796,7 +1796,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
     {
         struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet<Symbol>);
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> {
-            fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+            fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if let ty::ReLateBound(_, ty::BrNamed(_, name)) = *r {
                     self.0.insert(name);
                 }
diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs
index 7ba4d5a14df..187f86a52f4 100644
--- a/compiler/rustc_middle/src/ty/query/mod.rs
+++ b/compiler/rustc_middle/src/ty/query/mod.rs
@@ -28,13 +28,13 @@ use crate::traits::query::{
 };
 use crate::traits::specialization_graph;
 use crate::traits::{self, ImplSource};
-use crate::ty::steal::Steal;
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::stable_hasher::StableVec;
+use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::ErrorReported;
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 89fd803fe51..94e69a93a6b 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -7,12 +7,12 @@ use crate::mir::ProjectionKind;
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
+use rustc_data_structures::functor::IdFunctor;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::CRATE_DEF_INDEX;
 use rustc_index::vec::{Idx, IndexVec};
 
-use smallvec::SmallVec;
 use std::fmt;
 use std::ops::ControlFlow;
 use std::rc::Rc;
@@ -274,7 +274,7 @@ impl fmt::Debug for ty::PredicateAtom<'tcx> {
 // For things that don't carry any arena-allocated data (and are
 // copy...), just add them to this list.
 
-CloneTypeFoldableAndLiftImpls! {
+TrivialTypeFoldableAndLiftImpls! {
     (),
     bool,
     usize,
@@ -725,21 +725,21 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
 
 /// AdtDefs are basically the same as a DefId.
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self {
-        *self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
+        self
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (T, U) {
         (self.0.fold_with(folder), self.1.fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.0.visit_with(visitor)?;
         self.1.visit_with(visitor)
     }
@@ -748,11 +748,11 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for
 impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx>
     for (A, B, C)
 {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> (A, B, C) {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (A, B, C) {
         (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.0.visit_with(visitor)?;
         self.1.visit_with(visitor)?;
         self.2.visit_with(visitor)
@@ -774,106 +774,107 @@ EnumTypeFoldableImpl! {
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Rc::new((**self).fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        // FIXME: Reuse the `Rc` here.
+        Rc::new((*self).clone().fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         (**self).visit_with(visitor)
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Arc::new((**self).fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        // FIXME: Reuse the `Arc` here.
+        Arc::new((*self).clone().fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         (**self).visit_with(visitor)
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let content: T = (**self).fold_with(folder);
-        box content
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        self.map_id(|value| value.fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         (**self).visit_with(visitor)
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        self.iter().map(|t| t.fold_with(folder)).collect()
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        self.map_id(|t| t.fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>().into_boxed_slice()
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        self.map_id(|t| t.fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        self.map_bound_ref(|ty| ty.fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        self.map_bound(|ty| ty.fold_with(folder))
     }
 
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         folder.fold_binder(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.as_ref().skip_binder().visit_with(visitor)
     }
 
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_binder(self)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_existential_predicates(v))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|p| p.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        fold_list(*self, folder, |tcx, v| tcx.intern_projs(v))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         use crate::ty::InstanceDef::*;
         Self {
             substs: self.substs.fold_with(folder),
@@ -893,7 +894,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         use crate::ty::InstanceDef::*;
         self.substs.visit_with(visitor)?;
         match self.def {
@@ -915,36 +916,36 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         Self { instance: self.instance.fold_with(folder), promoted: self.promoted }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.instance.visit_with(visitor)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let kind = match self.kind() {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        let kind = match *self.kind() {
             ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)),
             ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
             ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
-            ty::Adt(tid, substs) => ty::Adt(*tid, substs.fold_with(folder)),
-            ty::Dynamic(ref trait_ty, ref region) => {
+            ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)),
+            ty::Dynamic(trait_ty, region) => {
                 ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder))
             }
             ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)),
-            ty::FnDef(def_id, substs) => ty::FnDef(*def_id, substs.fold_with(folder)),
+            ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)),
             ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)),
-            ty::Ref(ref r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), *mutbl),
+            ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl),
             ty::Generator(did, substs, movability) => {
-                ty::Generator(*did, substs.fold_with(folder), *movability)
+                ty::Generator(did, substs.fold_with(folder), movability)
             }
             ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)),
-            ty::Closure(did, substs) => ty::Closure(*did, substs.fold_with(folder)),
-            ty::Projection(ref data) => ty::Projection(data.fold_with(folder)),
-            ty::Opaque(did, substs) => ty::Opaque(*did, substs.fold_with(folder)),
+            ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)),
+            ty::Projection(data) => ty::Projection(data.fold_with(folder)),
+            ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)),
 
             ty::Bool
             | ty::Char
@@ -964,11 +965,11 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
         if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) }
     }
 
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_ty(*self)
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        folder.fold_ty(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match self.kind() {
             ty::RawPtr(ref tm) => tm.visit_with(visitor),
             ty::Array(typ, sz) => {
@@ -1010,40 +1011,40 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
         }
     }
 
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_ty(self)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self {
-        *self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
+        self
     }
 
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_region(*self)
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        folder.fold_region(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_region(*self)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let new = ty::PredicateKind::super_fold_with(&self.inner.kind, folder);
-        folder.tcx().reuse_or_mk_predicate(*self, new)
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        let new = ty::PredicateKind::super_fold_with(self.inner.kind, folder);
+        folder.tcx().reuse_or_mk_predicate(self, new)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ty::PredicateKind::super_visit_with(&self.inner.kind, visitor)
     }
 
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_predicate(*self)
     }
 
@@ -1057,53 +1058,53 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|p| p.visit_with(visitor))
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        self.iter().map(|x| x.fold_with(folder)).collect()
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        self.map_id(|x| x.fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         let ty = self.ty.fold_with(folder);
         let val = self.val.fold_with(folder);
         if ty != self.ty || val != self.val {
             folder.tcx().mk_const(ty::Const { ty, val })
         } else {
-            *self
+            self
         }
     }
 
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_const(*self)
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        folder.fold_const(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.ty.visit_with(visitor)?;
         self.val.visit_with(visitor)
     }
 
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_const(self)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        match self {
             ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
             ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
             ty::ConstKind::Unevaluated(did, substs, promoted) => {
@@ -1112,11 +1113,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
             ty::ConstKind::Value(_)
             | ty::ConstKind::Bound(..)
             | ty::ConstKind::Placeholder(..)
-            | ty::ConstKind::Error(_) => *self,
+            | ty::ConstKind::Error(_) => self,
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match *self {
             ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
             ty::ConstKind::Param(p) => p.visit_with(visitor),
@@ -1130,42 +1131,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self {
-        *self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
+        self
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
-
-// Does the equivalent of
-// ```
-// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
-// folder.tcx().intern_*(&v)
-// ```
-fn fold_list<'tcx, F, T>(
-    list: &'tcx ty::List<T>,
-    folder: &mut F,
-    intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
-) -> &'tcx ty::List<T>
-where
-    F: TypeFolder<'tcx>,
-    T: TypeFoldable<'tcx> + PartialEq + Copy,
-{
-    let mut iter = list.iter();
-    // Look for the first element that changed
-    if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
-        let new_t = t.fold_with(folder);
-        if new_t == t { None } else { Some((i, new_t)) }
-    }) {
-        // An element changed, prepare to intern the resulting list
-        let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
-        new_list.extend_from_slice(&list[..i]);
-        new_list.push(new_t);
-        new_list.extend(iter.map(|t| t.fold_with(folder)));
-        intern(folder.tcx(), &new_list)
-    } else {
-        list
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 384d08f8348..4bf16436855 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1001,7 +1001,7 @@ impl<T> Binder<T> {
         T: TypeFoldable<'tcx>,
     {
         if value.has_escaping_bound_vars() {
-            Binder::bind(super::fold::shift_vars(tcx, &value, 1))
+            Binder::bind(super::fold::shift_vars(tcx, value, 1))
         } else {
             Binder::dummy(value)
         }
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 07f775cf8b1..5d1b976ae97 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -152,7 +152,7 @@ impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         match self.unpack() {
             GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(),
             GenericArgKind::Type(ty) => ty.fold_with(folder).into(),
@@ -160,7 +160,7 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match self.unpack() {
             GenericArgKind::Lifetime(lt) => lt.visit_with(visitor),
             GenericArgKind::Type(ty) => ty.visit_with(visitor),
@@ -363,7 +363,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         // This code is hot enough that it's worth specializing for the most
         // common length lists, to avoid the overhead of `SmallVec` creation.
         // The match arms are in order of frequency. The 1, 2, and 0 cases are
@@ -392,7 +392,7 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
@@ -405,12 +405,12 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
 // there is more information available (for better errors).
 
 pub trait Subst<'tcx>: Sized {
-    fn subst(&self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self {
+    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self {
         self.subst_spanned(tcx, substs, None)
     }
 
     fn subst_spanned(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         substs: &[GenericArg<'tcx>],
         span: Option<Span>,
@@ -419,13 +419,13 @@ pub trait Subst<'tcx>: Sized {
 
 impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T {
     fn subst_spanned(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         substs: &[GenericArg<'tcx>],
         span: Option<Span>,
     ) -> T {
         let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 };
-        (*self).fold_with(&mut folder)
+        self.fold_with(&mut folder)
     }
 }
 
@@ -448,7 +448,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
+    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> {
         self.binders_passed += 1;
         let t = t.super_fold_with(self);
         self.binders_passed -= 1;
@@ -634,7 +634,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
             return val;
         }
 
-        let result = ty::fold::shift_vars(self.tcx(), &val, self.binders_passed);
+        let result = ty::fold::shift_vars(self.tcx(), val, self.binders_passed);
         debug!("shift_vars: shifted result = {:?}", result);
 
         result
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 5f117e19eca..e23c3f51967 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -160,7 +160,7 @@ impl<'tcx> TyCtxt<'tcx> {
         // We want the type_id be independent of the types free regions, so we
         // erase them. The erase_regions() call will also anonymize bound
         // regions, which is desirable too.
-        let ty = self.erase_regions(&ty);
+        let ty = self.erase_regions(ty);
 
         hcx.while_hashing_spans(false, |hcx| {
             hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
@@ -1130,6 +1130,37 @@ pub fn needs_drop_components(
     }
 }
 
+// Does the equivalent of
+// ```
+// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
+// folder.tcx().intern_*(&v)
+// ```
+pub fn fold_list<'tcx, F, T>(
+    list: &'tcx ty::List<T>,
+    folder: &mut F,
+    intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
+) -> &'tcx ty::List<T>
+where
+    F: TypeFolder<'tcx>,
+    T: TypeFoldable<'tcx> + PartialEq + Copy,
+{
+    let mut iter = list.iter();
+    // Look for the first element that changed
+    if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
+        let new_t = t.fold_with(folder);
+        if new_t == t { None } else { Some((i, new_t)) }
+    }) {
+        // An element changed, prepare to intern the resulting list
+        let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
+        new_list.extend_from_slice(&list[..i]);
+        new_list.push(new_t);
+        new_list.extend(iter.map(|t| t.fold_with(folder)));
+        intern(folder.tcx(), &new_list)
+    } else {
+        list
+    }
+}
+
 #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
 pub struct AlwaysRequiresDrop;
 
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index 4256f6e39d5..41f3edaa413 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
@@ -383,16 +383,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     self.describe_field_from_ty(&ty, field, variant_index)
                 }
                 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
-                    // `tcx.upvars_mentioned(def_id)` returns an `Option`, which is `None` in case
-                    // the closure comes from another crate. But in that case we wouldn't
-                    // be borrowck'ing it, so we can just unwrap:
-                    let (&var_id, _) = self
-                        .infcx
-                        .tcx
-                        .upvars_mentioned(def_id)
-                        .unwrap()
-                        .get_index(field.index())
-                        .unwrap();
+                    // We won't be borrowck'ing here if the closure came from another crate,
+                    // so it's safe to call `expect_local`.
+                    //
+                    // We know the field exists so it's safe to call operator[] and `unwrap` here.
+                    let (&var_id, _) =
+                        self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id]
+                            .get_index(field.index())
+                            .unwrap();
 
                     self.infcx.tcx.hir().name(var_id).to_string()
                 }
@@ -967,9 +965,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
         debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
         if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
-            for ((upvar_hir_id, upvar), place) in
-                self.infcx.tcx.upvars_mentioned(def_id)?.iter().zip(places)
+            for (upvar_hir_id, place) in
+                self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id]
+                    .keys()
+                    .zip(places)
             {
+                let span = self.infcx.tcx.upvars_mentioned(local_did)?[upvar_hir_id].span;
                 match place {
                     Operand::Copy(place) | Operand::Move(place)
                         if target_place == place.as_ref() =>
@@ -991,7 +992,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         let usage_span =
                             match self.infcx.tcx.typeck(local_did).upvar_capture(upvar_id) {
                                 ty::UpvarCapture::ByValue(Some(span)) => span,
-                                _ => upvar.span,
+                                _ => span,
                             };
                         return Some((*args_span, generator_kind, usage_span));
                     }
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index a5a7012852d..3586be2804d 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -876,7 +876,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
 
             // Type-test failed. Report the error.
-            let erased_generic_kind = infcx.tcx.erase_regions(&type_test.generic_kind);
+            let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind);
 
             // Skip duplicate-ish errors.
             if deduplicate_errors.insert((
@@ -1006,7 +1006,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         debug!("try_promote_type_test_subject(ty = {:?})", ty);
 
-        let ty = tcx.fold_regions(&ty, &mut false, |r, _depth| {
+        let ty = tcx.fold_regions(ty, &mut false, |r, _depth| {
             let region_vid = self.to_region_vid(r);
 
             // The challenge if this. We have some region variable `r`
@@ -1248,7 +1248,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        tcx.fold_regions(&value, &mut false, |r, _db| {
+        tcx.fold_regions(value, &mut false, |r, _db| {
             let vid = self.to_region_vid(r);
             let scc = self.constraint_sccs.scc(vid);
             let repr = self.scc_representatives[scc];
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs
index 325dca8c8ca..f7c902355cb 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs
@@ -63,7 +63,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
                 let mut subst_regions = vec![self.universal_regions.fr_static];
                 let universal_substs =
-                    infcx.tcx.fold_regions(&substs, &mut false, |region, _| match *region {
+                    infcx.tcx.fold_regions(substs, &mut false, |region, _| match *region {
                         ty::ReVar(vid) => {
                             subst_regions.push(vid);
                             self.definitions[vid].external_name.unwrap_or_else(|| {
@@ -94,7 +94,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 subst_regions.dedup();
 
                 let universal_concrete_type =
-                    infcx.tcx.fold_regions(&concrete_type, &mut false, |region, _| match *region {
+                    infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
                         ty::ReVar(vid) => subst_regions
                             .iter()
                             .find(|ur_vid| self.eval_equal(vid, **ur_vid))
@@ -139,7 +139,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        tcx.fold_regions(&ty, &mut false, |region, _| match *region {
+        tcx.fold_regions(ty, &mut false, |region, _| match *region {
             ty::ReVar(vid) => {
                 // Find something that we can name
                 let upper_bound = self.approx_universal_upper_bound(vid);
diff --git a/compiler/rustc_mir/src/borrow_check/renumber.rs b/compiler/rustc_mir/src/borrow_check/renumber.rs
index 5df033b48c1..e563e37adc2 100644
--- a/compiler/rustc_mir/src/borrow_check/renumber.rs
+++ b/compiler/rustc_mir/src/borrow_check/renumber.rs
@@ -26,7 +26,7 @@ pub fn renumber_mir<'tcx>(
 
 /// Replaces all regions appearing in `value` with fresh inference
 /// variables.
-pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: &T) -> T
+pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T
 where
     T: TypeFoldable<'tcx>,
 {
@@ -43,7 +43,7 @@ struct NLLVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> NLLVisitor<'a, 'tcx> {
-    fn renumber_regions<T>(&mut self, value: &T) -> T
+    fn renumber_regions<T>(&mut self, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -70,7 +70,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
         _: Location,
     ) -> Option<PlaceElem<'tcx>> {
         if let PlaceElem::Field(field, ty) = elem {
-            let new_ty = self.renumber_regions(&ty);
+            let new_ty = self.renumber_regions(ty);
 
             if new_ty != ty {
                 return Some(PlaceElem::Field(field, new_ty));
@@ -83,7 +83,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
         debug!("visit_substs(substs={:?}, location={:?})", substs, location);
 
-        *substs = self.renumber_regions(&{ *substs });
+        *substs = self.renumber_regions(*substs);
 
         debug!("visit_substs: substs={:?}", substs);
     }
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
index 444f9fe8d0a..b7d22fab3dd 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
@@ -59,7 +59,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             .replace_bound_vars_with_fresh_vars(
                                 body.span,
                                 LateBoundRegionConversionTime::FnCall,
-                                &poly_sig,
+                                poly_sig,
                             )
                             .0,
                     )
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 409399094e8..a5c45452dec 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -784,7 +784,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         };
 
         if let Some(field) = variant.fields.get(field.index()) {
-            Ok(self.cx.normalize(&field.ty(tcx, substs), location))
+            Ok(self.cx.normalize(field.ty(tcx, substs), location))
         } else {
             Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
         }
@@ -1245,7 +1245,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             anon_owner_def_id,
                             dummy_body_id,
                             param_env,
-                            &anon_ty,
+                            anon_ty,
                             locations.span(body),
                         ));
                     debug!(
@@ -1271,7 +1271,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     );
 
                     for (&opaque_def_id, opaque_decl) in &opaque_type_map {
-                        let resolved_ty = infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty);
+                        let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty);
                         let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
                             *def_id == opaque_def_id
                         } else {
@@ -1296,7 +1296,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let subst_opaque_defn_ty =
                             opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs);
                         let renumbered_opaque_defn_ty =
-                            renumber::renumber_regions(infcx, &subst_opaque_defn_ty);
+                            renumber::renumber_regions(infcx, subst_opaque_defn_ty);
 
                         debug!(
                             "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
@@ -1601,7 +1601,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 let (sig, map) = self.infcx.replace_bound_vars_with_fresh_vars(
                     term.source_info.span,
                     LateBoundRegionConversionTime::FnCall,
-                    &sig,
+                    sig,
                 );
                 let sig = self.normalize(sig, term_location);
                 self.check_call_dest(body, term, &sig, destination, term_location);
@@ -1900,7 +1900,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         // Erase the regions from `ty` to get a global type.  The
         // `Sized` bound in no way depends on precise regions, so this
         // shouldn't affect `is_sized`.
-        let erased_ty = tcx.erase_regions(&ty);
+        let erased_ty = tcx.erase_regions(ty);
         if !erased_ty.is_sized(tcx.at(span), self.param_env) {
             // in current MIR construction, all non-control-flow rvalue
             // expressions evaluate through `as_temp` or `into` a return
diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
index 4742113b1a5..7ad38a1f82c 100644
--- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs
+++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
@@ -438,7 +438,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
             FR,
             self.mir_def.did,
-            &bound_inputs_and_output,
+            bound_inputs_and_output,
             &mut indices,
         );
         // Converse of above, if this is a function then the late-bound regions declared on its
@@ -522,7 +522,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 debug!("defining_ty (pre-replacement): {:?}", defining_ty);
 
                 let defining_ty =
-                    self.infcx.replace_free_regions_with_nll_infer_vars(FR, &defining_ty);
+                    self.infcx.replace_free_regions_with_nll_infer_vars(FR, defining_ty);
 
                 match *defining_ty.kind() {
                     ty::Closure(def_id, substs) => DefiningTy::Closure(def_id, substs),
@@ -543,7 +543,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
                 let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
                 let substs =
-                    self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs);
+                    self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
                 DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
             }
         }
@@ -628,7 +628,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
 
             DefiningTy::FnDef(def_id, _) => {
                 let sig = tcx.fn_sig(def_id);
-                let sig = indices.fold_to_region_vids(tcx, &sig);
+                let sig = indices.fold_to_region_vids(tcx, sig);
                 sig.inputs_and_output()
             }
 
@@ -637,7 +637,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 // "output" (the type of the constant).
                 assert_eq!(self.mir_def.did.to_def_id(), def_id);
                 let ty = tcx.type_of(self.mir_def.def_id_for_type_of());
-                let ty = indices.fold_to_region_vids(tcx, &ty);
+                let ty = indices.fold_to_region_vids(tcx, ty);
                 ty::Binder::dummy(tcx.intern_type_list(&[ty]))
             }
         }
@@ -648,7 +648,7 @@ trait InferCtxtExt<'tcx> {
     fn replace_free_regions_with_nll_infer_vars<T>(
         &self,
         origin: NLLRegionVariableOrigin,
-        value: &T,
+        value: T,
     ) -> T
     where
         T: TypeFoldable<'tcx>;
@@ -657,7 +657,7 @@ trait InferCtxtExt<'tcx> {
         &self,
         origin: NLLRegionVariableOrigin,
         all_outlive_scope: LocalDefId,
-        value: &ty::Binder<T>,
+        value: ty::Binder<T>,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) -> T
     where
@@ -674,7 +674,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
     fn replace_free_regions_with_nll_infer_vars<T>(
         &self,
         origin: NLLRegionVariableOrigin,
-        value: &T,
+        value: T,
     ) -> T
     where
         T: TypeFoldable<'tcx>,
@@ -686,7 +686,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         &self,
         origin: NLLRegionVariableOrigin,
         all_outlive_scope: LocalDefId,
-        value: &ty::Binder<T>,
+        value: ty::Binder<T>,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) -> T
     where
@@ -771,7 +771,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
 
     /// Replaces all free regions in `value` with region vids, as
     /// returned by `to_region_vid`.
-    pub fn fold_to_region_vids<T>(&self, tcx: TyCtxt<'tcx>, value: &T) -> T
+    pub fn fold_to_region_vids<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
diff --git a/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs
index d1d507e54ef..d16366fded9 100644
--- a/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs
+++ b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs
@@ -152,7 +152,7 @@ pub(crate) fn on_all_drop_children_bits<'tcx, F>(
         let ty = place.ty(body, tcx).ty;
         debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
 
-        let erased_ty = tcx.erase_regions(&ty);
+        let erased_ty = tcx.erase_regions(ty);
         if erased_ty.needs_drop(tcx, ctxt.param_env) {
             each_child(child);
         } else {
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index 0f86a181a55..05b4d1c410d 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -505,7 +505,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
         value: T,
     ) -> T {
-        frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, &value)
+        frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
     }
 
     /// The `substs` are assumed to already be in our interpreter "universe" (param_env).
diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs
index 77f4593fa16..fa7036f4e5b 100644
--- a/compiler/rustc_mir/src/interpret/traits.rs
+++ b/compiler/rustc_mir/src/interpret/traits.rs
@@ -21,7 +21,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
         trace!("get_vtable(trait_ref={:?})", poly_trait_ref);
 
-        let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));
+        let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref));
 
         // All vtables must be monomorphic, bail out otherwise.
         ensure_monomorphic_enough(*self.tcx, ty)?;
@@ -37,7 +37,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         let methods = if let Some(poly_trait_ref) = poly_trait_ref {
             let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
-            let trait_ref = self.tcx.erase_regions(&trait_ref);
+            let trait_ref = self.tcx.erase_regions(trait_ref);
 
             self.tcx.vtable_methods(trait_ref)
         } else {
@@ -143,7 +143,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?;
         trace!("Found drop fn: {:?}", drop_instance);
         let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx);
-        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
+        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig);
         // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
         let args = fn_sig.inputs();
         if args.len() != 1 {
diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs
index fce5553c993..e49b1c9f64d 100644
--- a/compiler/rustc_mir/src/interpret/util.rs
+++ b/compiler/rustc_mir/src/interpret/util.rs
@@ -18,7 +18,9 @@ where
     };
 
     impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
-        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
+        type BreakTy = ();
+
+        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             if !c.needs_subst() {
                 return ControlFlow::CONTINUE;
             }
@@ -29,7 +31,7 @@ where
             }
         }
 
-        fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+        fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             if !ty.needs_subst() {
                 return ControlFlow::CONTINUE;
             }
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index 938181abff2..a6f90992172 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -546,7 +546,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> {
         self.instance.subst_mir_and_normalize_erasing_regions(
             self.tcx,
             ty::ParamEnv::reveal_all(),
-            &value,
+            value,
         )
     }
 }
@@ -1118,7 +1118,7 @@ impl RootCollector<'_, 'v> {
         // late-bound regions, since late-bound
         // regions must appear in the argument
         // listing.
-        let main_ret_ty = self.tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());
+        let main_ret_ty = self.tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap());
 
         let start_instance = Instance::resolve(
             self.tcx,
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
index 037b80e4bf2..d5a845dd76f 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
@@ -304,7 +304,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
                 let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
                     instance.substs,
                     ty::ParamEnv::reveal_all(),
-                    &tcx.type_of(impl_def_id),
+                    tcx.type_of(impl_def_id),
                 );
                 if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
                     return Some(def_id);
diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
index c2ebc954a22..0ce1c5a0489 100644
--- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs
+++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
@@ -250,7 +250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
-    fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> {
+    fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!("visit_const: c={:?}", c);
         if !c.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
@@ -283,7 +283,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
         }
     }
 
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!("visit_ty: ty={:?}", ty);
         if !ty.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
@@ -318,7 +318,9 @@ struct HasUsedGenericParams<'a> {
 }
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
-    fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> {
+    type BreakTy = ();
+
+    fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!("visit_const: c={:?}", c);
         if !c.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
@@ -336,7 +338,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
         }
     }
 
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!("visit_ty: ty={:?}", ty);
         if !ty.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs
index b2fa4b11f36..3a1fa0018c1 100644
--- a/compiler/rustc_mir/src/shim.rs
+++ b/compiler/rustc_mir/src/shim.rs
@@ -135,7 +135,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
     // Check if this is a generator, if so, return the drop glue for it
     if let Some(&ty::Generator(gen_def_id, substs, _)) = ty.map(|ty| ty.kind()) {
         let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap();
-        return body.subst(tcx, substs);
+        return body.clone().subst(tcx, substs);
     }
 
     let substs = if let Some(ty) = ty {
@@ -144,7 +144,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
         InternalSubsts::identity_for_item(tcx, def_id)
     };
     let sig = tcx.fn_sig(def_id).subst(tcx, substs);
-    let sig = tcx.erase_late_bound_regions(&sig);
+    let sig = tcx.erase_late_bound_regions(sig);
     let span = tcx.def_span(def_id);
 
     let source_info = SourceInfo::outermost(span);
@@ -338,7 +338,7 @@ impl CloneShimBuilder<'tcx> {
         // or access fields of a Place of type TySelf.
         let substs = tcx.mk_substs_trait(self_ty, &[]);
         let sig = tcx.fn_sig(def_id).subst(tcx, substs);
-        let sig = tcx.erase_late_bound_regions(&sig);
+        let sig = tcx.erase_late_bound_regions(sig);
         let span = tcx.def_span(def_id);
 
         CloneShimBuilder {
@@ -656,7 +656,7 @@ fn build_call_shim<'tcx>(
     // to substitute into the signature of the shim. It is not necessary for users of this
     // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`).
     let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance {
-        let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
+        let sig = tcx.erase_late_bound_regions(ty.fn_sig(tcx));
 
         let untuple_args = sig.inputs();
 
@@ -671,7 +671,7 @@ fn build_call_shim<'tcx>(
 
     let def_id = instance.def_id();
     let sig = tcx.fn_sig(def_id);
-    let mut sig = tcx.erase_late_bound_regions(&sig);
+    let mut sig = tcx.erase_late_bound_regions(sig);
 
     assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
     if let Some(sig_substs) = sig_substs {
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index bd51136b8db..d2e65abfbc7 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -4,7 +4,6 @@ use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir;
-use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
@@ -104,7 +103,7 @@ impl NonConstOp for FnCallUnstable {
 
         if ccx.is_const_stable_const_fn() {
             err.help("Const-stable functions can only call other const-stable functions");
-        } else if nightly_options::is_nightly_build() {
+        } else if ccx.tcx.sess.is_nightly_build() {
             if let Some(feature) = feature {
                 err.help(&format!(
                     "add `#![feature({})]` to the crate attributes to enable",
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index 039d4753a8c..dc413f8dd2d 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -720,13 +720,13 @@ fn sanitize_witness<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     witness: Ty<'tcx>,
-    upvars: &Vec<Ty<'tcx>>,
+    upvars: Vec<Ty<'tcx>>,
     saved_locals: &GeneratorSavedLocals,
 ) {
     let did = body.source.def_id();
     let allowed_upvars = tcx.erase_regions(upvars);
     let allowed = match witness.kind() {
-        ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s),
+        &ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(s),
         _ => {
             tcx.sess.delay_span_bug(
                 body.span,
@@ -1303,7 +1303,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
         let liveness_info =
             locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
 
-        sanitize_witness(tcx, body, interior, &upvars, &liveness_info.saved_locals);
+        sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals);
 
         if tcx.sess.opts.debugging_opts.validate_mir {
             let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias {
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index aae98f5b6d8..094c1513118 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -122,7 +122,7 @@ impl Inliner<'tcx> {
             let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions(
                 self.tcx,
                 self.param_env,
-                callee_body,
+                callee_body.clone(),
             );
 
             let old_blocks = caller_body.basic_blocks().next_index();
@@ -459,6 +459,7 @@ impl Inliner<'tcx> {
                     tcx: self.tcx,
                     callsite_span: callsite.source_info.span,
                     body_span: callee_body.span,
+                    always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
                 };
 
                 // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
@@ -490,6 +491,34 @@ impl Inliner<'tcx> {
                     }
                 }
 
+                // If there are any locals without storage markers, give them storage only for the
+                // duration of the call.
+                for local in callee_body.vars_and_temps_iter() {
+                    if integrator.always_live_locals.contains(local) {
+                        let new_local = integrator.map_local(local);
+                        caller_body[callsite.block].statements.push(Statement {
+                            source_info: callsite.source_info,
+                            kind: StatementKind::StorageLive(new_local),
+                        });
+                    }
+                }
+                if let Some(block) = callsite.target {
+                    // To avoid repeated O(n) insert, push any new statements to the end and rotate
+                    // the slice once.
+                    let mut n = 0;
+                    for local in callee_body.vars_and_temps_iter().rev() {
+                        if integrator.always_live_locals.contains(local) {
+                            let new_local = integrator.map_local(local);
+                            caller_body[block].statements.push(Statement {
+                                source_info: callsite.source_info,
+                                kind: StatementKind::StorageDead(new_local),
+                            });
+                            n += 1;
+                        }
+                    }
+                    caller_body[block].statements.rotate_right(n);
+                }
+
                 // Insert all of the (mapped) parts of the callee body into the caller.
                 caller_body.local_decls.extend(
                     // FIXME(eddyb) make `Range<Local>` iterable so that we can use
@@ -670,6 +699,7 @@ struct Integrator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     callsite_span: Span,
     body_span: Span,
+    always_live_locals: BitSet<Local>,
 }
 
 impl<'a, 'tcx> Integrator<'a, 'tcx> {
@@ -759,6 +789,15 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
         }
     }
 
+    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
+        if let StatementKind::StorageLive(local) | StatementKind::StorageDead(local) =
+            statement.kind
+        {
+            self.always_live_locals.remove(local);
+        }
+        self.super_statement(statement, location);
+    }
+
     fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) {
         // Don't try to modify the implicit `_0` access on return (`return` terminators are
         // replaced down below anyways).
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index 2f81db8af2f..e86d11e248f 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -1,6 +1,7 @@
 use crate::{shim, util};
 use required_consts::RequiredConstsVisitor;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::steal::Steal;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
@@ -8,7 +9,6 @@ use rustc_index::vec::IndexVec;
 use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::steal::Steal;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs
index 876ecee80c6..75399e9c32c 100644
--- a/compiler/rustc_mir/src/transform/validate.rs
+++ b/compiler/rustc_mir/src/transform/validate.rs
@@ -181,6 +181,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
     fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) {
+        if self.body.local_decls.get(*local).is_none() {
+            self.fail(
+                location,
+                format!("local {:?} has no corresponding declaration in `body.local_decls`", local),
+            );
+        }
+
         if self.reachable_blocks.contains(location.block) && context.is_use() {
             // Uses of locals must occur while the local's storage is allocated.
             self.storage_liveness.seek_after_primary_effect(location);
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index 8bee8417c51..cd60602b088 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -640,7 +640,7 @@ pub fn write_allocations<'tcx>(
     }
     struct CollectAllocIds(BTreeSet<AllocId>);
     impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
-        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
+        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             if let ty::ConstKind::Value(val) = c.val {
                 self.0.extend(alloc_ids_from_const(val));
             }
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index f9995f43f5a..c50389a850e 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -24,7 +24,7 @@ use super::lints;
 crate fn mir_built<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx ty::steal::Steal<Body<'tcx>> {
+) -> &'tcx rustc_data_structures::steal::Steal<Body<'tcx>> {
     if let Some(def) = def.try_upgrade(tcx) {
         return tcx.mir_built(def);
     }
@@ -240,7 +240,7 @@ fn liberated_closure_env_ty(
     };
 
     let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap();
-    tcx.erase_late_bound_regions(&closure_env_ty)
+    tcx.erase_late_bound_regions(closure_env_ty)
 }
 
 #[derive(Debug, PartialEq, Eq)]
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 6ed7ed575fc..47c0400533b 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -387,8 +387,9 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                 }
             };
             let upvars = cx
-                .tcx
-                .upvars_mentioned(def_id)
+                .typeck_results()
+                .closure_captures
+                .get(&def_id)
                 .iter()
                 .flat_map(|upvars| upvars.iter())
                 .zip(substs.upvar_tys())
diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
index 5e7e81eba62..6bea2381862 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
@@ -364,14 +364,14 @@ impl<'tcx> Pat<'tcx> {
 /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
 /// works well.
 #[derive(Debug, Clone)]
-crate struct PatStack<'p, 'tcx> {
+struct PatStack<'p, 'tcx> {
     pats: SmallVec<[&'p Pat<'tcx>; 2]>,
     /// Cache for the constructor of the head
     head_ctor: OnceCell<Constructor<'tcx>>,
 }
 
 impl<'p, 'tcx> PatStack<'p, 'tcx> {
-    crate fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
+    fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
         Self::from_vec(smallvec![pat])
     }
 
@@ -455,17 +455,17 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
 
 /// A 2D matrix.
 #[derive(Clone, PartialEq)]
-crate struct Matrix<'p, 'tcx> {
+struct Matrix<'p, 'tcx> {
     patterns: Vec<PatStack<'p, 'tcx>>,
 }
 
 impl<'p, 'tcx> Matrix<'p, 'tcx> {
-    crate fn empty() -> Self {
+    fn empty() -> Self {
         Matrix { patterns: vec![] }
     }
 
     /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
-    crate fn push(&mut self, row: PatStack<'p, 'tcx>) {
+    fn push(&mut self, row: PatStack<'p, 'tcx>) {
         if let Some(rows) = row.expand_or_pat() {
             for row in rows {
                 // We recursively expand the or-patterns of the new rows.
@@ -588,7 +588,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
     }
 
     /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
-    crate fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
+    fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
         match ty.kind() {
             ty::Adt(def, ..) => {
                 def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
@@ -1392,13 +1392,12 @@ impl<'tcx> Usefulness<'tcx> {
         pcx: PatCtxt<'_, 'p, 'tcx>,
         ctor: &Constructor<'tcx>,
         ctor_wild_subpatterns: &Fields<'p, 'tcx>,
-        is_top_level: bool,
     ) -> Self {
         match self {
             UsefulWithWitness(witnesses) => {
                 let new_witnesses = if ctor.is_wildcard() {
                     let missing_ctors = MissingConstructors::new(pcx);
-                    let new_patterns = missing_ctors.report_patterns(pcx, is_top_level);
+                    let new_patterns = missing_ctors.report_patterns(pcx);
                     witnesses
                         .into_iter()
                         .flat_map(|witness| {
@@ -1440,7 +1439,7 @@ impl<'tcx> Usefulness<'tcx> {
 }
 
 #[derive(Copy, Clone, Debug)]
-crate enum WitnessPreference {
+enum WitnessPreference {
     ConstructWitness,
     LeaveOutWitness,
 }
@@ -1454,6 +1453,9 @@ struct PatCtxt<'a, 'p, 'tcx> {
     ty: Ty<'tcx>,
     /// Span of the current pattern under investigation.
     span: Span,
+    /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a
+    /// subpattern.
+    is_top_level: bool,
 }
 
 /// A witness of non-exhaustiveness for error reporting, represented
@@ -1493,7 +1495,8 @@ struct PatCtxt<'a, 'p, 'tcx> {
 crate struct Witness<'tcx>(Vec<Pat<'tcx>>);
 
 impl<'tcx> Witness<'tcx> {
-    crate fn single_pattern(self) -> Pat<'tcx> {
+    /// Asserts that the witness contains a single pattern, and returns it.
+    fn single_pattern(self) -> Pat<'tcx> {
         assert_eq!(self.0.len(), 1);
         self.0.into_iter().next().unwrap()
     }
@@ -1585,11 +1588,12 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
             let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
 
             // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
-            // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that
-            // an empty match will still be considered exhaustive because that case is handled
-            // separately in `check_match`.
-            let is_secretly_empty =
-                def.variants.is_empty() && !cx.tcx.features().exhaustive_patterns;
+            // as though it had an "unknown" constructor to avoid exposing its emptiness. The
+            // exception is if the pattern is at the top level, because we want empty matches to be
+            // considered exhaustive.
+            let is_secretly_empty = def.variants.is_empty()
+                && !cx.tcx.features().exhaustive_patterns
+                && !pcx.is_top_level;
 
             if is_secretly_empty || is_declared_nonexhaustive {
                 vec![NonExhaustive]
@@ -1635,6 +1639,13 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
             let max = size.truncate(u128::MAX);
             vec![make_range(0, max)]
         }
+        // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot
+        // expose its emptiness. The exception is if the pattern is at the top level, because we
+        // want empty matches to be considered exhaustive.
+        ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => {
+            vec![NonExhaustive]
+        }
+        ty::Never => vec![],
         _ if cx.is_uninhabited(pcx.ty) => vec![],
         ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => vec![Single],
         // This type is one for which we cannot list constructors, like `str` or `f64`.
@@ -2012,11 +2023,7 @@ impl<'tcx> MissingConstructors<'tcx> {
 
     /// List the patterns corresponding to the missing constructors. In some cases, instead of
     /// listing all constructors of a given type, we prefer to simply report a wildcard.
-    fn report_patterns<'p>(
-        &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
-        is_top_level: bool,
-    ) -> SmallVec<[Pat<'tcx>; 1]> {
+    fn report_patterns<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Pat<'tcx>; 1]> {
         // There are 2 ways we can report a witness here.
         // Commonly, we can report all the "free"
         // constructors as witnesses, e.g., if we have:
@@ -2044,7 +2051,7 @@ impl<'tcx> MissingConstructors<'tcx> {
         // `used_ctors` is empty.
         // The exception is: if we are at the top-level, for example in an empty match, we
         // sometimes prefer reporting the list of constructors instead of just `_`.
-        let report_when_all_missing = is_top_level && !IntRange::is_integral(pcx.ty);
+        let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
         if self.used_ctors.is_empty() && !report_when_all_missing {
             // All constructors are unused. Report only a wildcard
             // rather than each individual constructor.
@@ -2086,7 +2093,7 @@ impl<'tcx> MissingConstructors<'tcx> {
 /// `is_under_guard` is used to inform if the pattern has a guard. If it
 /// has one it must not be inserted into the matrix. This shouldn't be
 /// relied on for soundness.
-crate fn is_useful<'p, 'tcx>(
+fn is_useful<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     matrix: &Matrix<'p, 'tcx>,
     v: &PatStack<'p, 'tcx>,
@@ -2200,7 +2207,7 @@ crate fn is_useful<'p, 'tcx>(
 
     // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
     let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty);
-    let pcx = PatCtxt { cx, matrix, ty, span: v.head().span };
+    let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level };
 
     debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
 
@@ -2215,7 +2222,7 @@ crate fn is_useful<'p, 'tcx>(
             let v = v.pop_head_constructor(&ctor_wild_subpatterns);
             let usefulness =
                 is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
-            usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns, is_top_level)
+            usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
         })
         .find(|result| result.is_useful())
         .unwrap_or(NotUseful);
@@ -2283,3 +2290,63 @@ fn pat_constructor<'p, 'tcx>(
         PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
     }
 }
+
+/// The arm of a match expression.
+#[derive(Clone, Copy)]
+crate struct MatchArm<'p, 'tcx> {
+    /// The pattern must have been lowered through `MatchVisitor::lower_pattern`.
+    crate pat: &'p super::Pat<'tcx>,
+    crate hir_id: HirId,
+    crate has_guard: bool,
+}
+
+/// The output of checking a match for exhaustiveness and arm reachability.
+crate struct UsefulnessReport<'p, 'tcx> {
+    /// For each arm of the input, whether that arm is reachable after the arms above it.
+    crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Usefulness<'tcx>)>,
+    /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
+    /// exhaustiveness.
+    crate non_exhaustiveness_witnesses: Vec<super::Pat<'tcx>>,
+}
+
+/// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
+/// of its arms are reachable.
+///
+/// Note: the input patterns must have been lowered through `MatchVisitor::lower_pattern`.
+crate fn compute_match_usefulness<'p, 'tcx>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
+    arms: &[MatchArm<'p, 'tcx>],
+    scrut_hir_id: HirId,
+    scrut_ty: Ty<'tcx>,
+) -> UsefulnessReport<'p, 'tcx> {
+    let mut matrix = Matrix::empty();
+    let arm_usefulness: Vec<_> = arms
+        .iter()
+        .copied()
+        .map(|arm| {
+            let v = PatStack::from_pattern(arm.pat);
+            let usefulness =
+                is_useful(cx, &matrix, &v, LeaveOutWitness, arm.hir_id, arm.has_guard, true);
+            if !arm.has_guard {
+                matrix.push(v);
+            }
+            (arm, usefulness)
+        })
+        .collect();
+
+    let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(scrut_ty));
+    let v = PatStack::from_pattern(wild_pattern);
+    let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true);
+    let non_exhaustiveness_witnesses = match usefulness {
+        NotUseful => vec![], // Wildcard pattern isn't useful, so the match is exhaustive.
+        UsefulWithWitness(pats) => {
+            if pats.is_empty() {
+                bug!("Exhaustiveness check returned no witnesses")
+            } else {
+                pats.into_iter().map(|w| w.single_pattern()).collect()
+            }
+        }
+        Useful(_) => bug!(),
+    };
+    UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 14ed93f1127..f9fe261bcee 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,6 +1,7 @@
 use super::_match::Usefulness::*;
-use super::_match::WitnessPreference::*;
-use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack};
+use super::_match::{
+    compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, UsefulnessReport,
+};
 use super::{PatCtxt, PatKind, PatternError};
 
 use rustc_arena::TypedArena;
@@ -12,7 +13,6 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{HirId, Pat};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::config::nightly_options;
 use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
 use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
 use rustc_session::parse::feature_err;
@@ -170,39 +170,50 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
 
         let mut have_errors = false;
 
-        let inlined_arms: Vec<_> = arms
+        let arms: Vec<_> = arms
             .iter()
-            .map(|hir::Arm { pat, guard, .. }| {
-                (self.lower_pattern(&mut cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some())
+            .map(|hir::Arm { pat, guard, .. }| MatchArm {
+                pat: self.lower_pattern(&mut cx, pat, &mut have_errors).0,
+                hir_id: pat.hir_id,
+                has_guard: guard.is_some(),
             })
             .collect();
 
-        // Bail out early if inlining failed.
+        // Bail out early if lowering failed.
         if have_errors {
             return;
         }
 
-        // Fourth, check for unreachable arms.
-        let matrix = check_arms(&mut cx, &inlined_arms, source);
+        let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut);
+        let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty);
+
+        // Report unreachable arms.
+        report_arm_reachability(&cx, &report, source);
 
-        // Fifth, check if the match is exhaustive.
+        // Check if the match is exhaustive.
         // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
         // since an empty matrix can occur when there are arms, if those arms all have guards.
-        let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut);
-        let is_empty_match = inlined_arms.is_empty();
-        check_exhaustive(&mut cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
+        let is_empty_match = arms.is_empty();
+        let witnesses = report.non_exhaustiveness_witnesses;
+        if !witnesses.is_empty() {
+            non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+        }
     }
 
     fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
         let mut cx = self.new_cx(pat.hir_id);
 
         let (pattern, pattern_ty) = self.lower_pattern(&mut cx, pat, &mut false);
-        let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
-
-        let witnesses = match check_not_useful(&mut cx, pattern_ty, &pats, pat.hir_id) {
-            Ok(_) => return,
-            Err(err) => err,
-        };
+        let arms = vec![MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }];
+        let report = compute_match_usefulness(&cx, &arms, pat.hir_id, pattern_ty);
+
+        // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We
+        // only care about exhaustiveness here.
+        let witnesses = report.non_exhaustiveness_witnesses;
+        if witnesses.is_empty() {
+            // The pattern is irrefutable.
+            return;
+        }
 
         let joined_patterns = joined_uncovered_patterns(&witnesses);
         let mut err = struct_span_err!(
@@ -355,17 +366,15 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::
     });
 }
 
-/// Check for unreachable patterns.
-fn check_arms<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    arms: &[(&'p super::Pat<'tcx>, HirId, bool)],
+/// Report unreachable arms, if any.
+fn report_arm_reachability<'p, 'tcx>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
+    report: &UsefulnessReport<'p, 'tcx>,
     source: hir::MatchSource,
-) -> Matrix<'p, 'tcx> {
-    let mut seen = Matrix::empty();
+) {
     let mut catchall = None;
-    for (arm_index, (pat, id, has_guard)) in arms.iter().copied().enumerate() {
-        let v = PatStack::from_pattern(pat);
-        match is_useful(cx, &seen, &v, LeaveOutWitness, id, has_guard, true) {
+    for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() {
+        match is_useful {
             NotUseful => {
                 match source {
                     hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
@@ -374,15 +383,15 @@ fn check_arms<'p, 'tcx>(
                         // Check which arm we're on.
                         match arm_index {
                             // The arm with the user-specified pattern.
-                            0 => unreachable_pattern(cx.tcx, pat.span, id, None),
+                            0 => unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None),
                             // The arm with the wildcard pattern.
-                            1 => irrefutable_let_pattern(cx.tcx, pat.span, id, source),
+                            1 => irrefutable_let_pattern(cx.tcx, arm.pat.span, arm.hir_id, source),
                             _ => bug!(),
                         }
                     }
 
                     hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
-                        unreachable_pattern(cx.tcx, pat.span, id, catchall);
+                        unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall);
                     }
 
                     // Unreachable patterns in try and await expressions occur when one of
@@ -390,79 +399,32 @@ fn check_arms<'p, 'tcx>(
                     hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
                 }
             }
+            Useful(unreachables) if unreachables.is_empty() => {}
+            // The arm is reachable, but contains unreachable subpatterns (from or-patterns).
             Useful(unreachables) => {
-                let mut unreachables: Vec<_> = unreachables.into_iter().flatten().collect();
+                let mut unreachables: Vec<_> = unreachables.iter().flatten().copied().collect();
                 // Emit lints in the order in which they occur in the file.
                 unreachables.sort_unstable();
                 for span in unreachables {
-                    unreachable_pattern(cx.tcx, span, id, None);
+                    unreachable_pattern(cx.tcx, span, arm.hir_id, None);
                 }
             }
             UsefulWithWitness(_) => bug!(),
         }
-        if !has_guard {
-            seen.push(v);
-            if catchall.is_none() && pat_is_catchall(pat) {
-                catchall = Some(pat.span);
-            }
+        if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
+            catchall = Some(arm.pat.span);
         }
     }
-    seen
 }
 
-fn check_not_useful<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    ty: Ty<'tcx>,
-    matrix: &Matrix<'p, 'tcx>,
-    hir_id: HirId,
-) -> Result<(), Vec<super::Pat<'tcx>>> {
-    let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
-    let v = PatStack::from_pattern(wild_pattern);
-
-    // false is given for `is_under_guard` argument due to the wildcard
-    // pattern not having a guard
-    match is_useful(cx, matrix, &v, ConstructWitness, hir_id, false, true) {
-        NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
-        UsefulWithWitness(pats) => Err(if pats.is_empty() {
-            bug!("Exhaustiveness check returned no witnesses")
-        } else {
-            pats.into_iter().map(|w| w.single_pattern()).collect()
-        }),
-        Useful(_) => bug!(),
-    }
-}
-
-fn check_exhaustive<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
+/// Report that a match is not exhaustive.
+fn non_exhaustive_match<'p, 'tcx>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
     scrut_ty: Ty<'tcx>,
     sp: Span,
-    matrix: &Matrix<'p, 'tcx>,
-    hir_id: HirId,
+    witnesses: Vec<super::Pat<'tcx>>,
     is_empty_match: bool,
 ) {
-    // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by
-    // `is_useful` to exhaustively match uninhabited types, so we manually check here.
-    if is_empty_match && !cx.tcx.features().exhaustive_patterns {
-        let scrutinee_is_visibly_uninhabited = match scrut_ty.kind() {
-            ty::Never => true,
-            ty::Adt(def, _) => {
-                def.is_enum()
-                    && def.variants.is_empty()
-                    && !cx.is_foreign_non_exhaustive_enum(scrut_ty)
-            }
-            _ => false,
-        };
-        if scrutinee_is_visibly_uninhabited {
-            // If the type *is* uninhabited, an empty match is vacuously exhaustive.
-            return;
-        }
-    }
-
-    let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {
-        Ok(_) => return,
-        Err(err) => err,
-    };
-
     let non_empty_enum = match scrut_ty.kind() {
         ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
         _ => false,
@@ -502,7 +464,7 @@ fn check_exhaustive<'p, 'tcx>(
                 so a wildcard `_` is necessary to match exhaustively",
             scrut_ty,
         ));
-        if nightly_options::is_nightly_build() {
+        if cx.tcx.sess.is_nightly_build() {
             err.help(&format!(
                 "add `#![feature(precise_pointer_size_matching)]` \
                     to the crate attributes to enable precise `{}` matching",
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 6370f8c375b..32fc0f008e9 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -18,6 +18,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     /// Converts an evaluated constant to a pattern (if possible).
     /// This means aggregate values (like structs and enums) are converted
     /// to a pattern that matches the value (as if you'd compared via structural equality).
+    #[instrument(skip(self))]
     pub(super) fn const_to_pat(
         &self,
         cv: &'tcx ty::Const<'tcx>,
@@ -25,15 +26,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         span: Span,
         mir_structural_match_violation: bool,
     ) -> Pat<'tcx> {
-        debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
-        debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
-
         let pat = self.tcx.infer_ctxt().enter(|infcx| {
             let mut convert = ConstToPat::new(self, id, span, infcx);
             convert.to_pat(cv, mir_structural_match_violation)
         });
 
-        debug!("const_to_pat: pat={:?}", pat);
+        debug!(?pat);
         pat
     }
 }
@@ -61,6 +59,8 @@ struct ConstToPat<'a, 'tcx> {
     infcx: InferCtxt<'a, 'tcx>,
 
     include_lint_checks: bool,
+
+    treat_byte_string_as_slice: bool,
 }
 
 mod fallback_to_const_ref {
@@ -88,6 +88,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
         span: Span,
         infcx: InferCtxt<'a, 'tcx>,
     ) -> Self {
+        trace!(?pat_ctxt.typeck_results.hir_owner);
         ConstToPat {
             id,
             span,
@@ -97,6 +98,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
             saw_const_match_error: Cell::new(false),
             saw_const_match_lint: Cell::new(false),
             behind_reference: Cell::new(false),
+            treat_byte_string_as_slice: pat_ctxt
+                .typeck_results
+                .treat_byte_string_as_slice
+                .contains(&id.local_id),
         }
     }
 
@@ -153,6 +158,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
         cv: &'tcx ty::Const<'tcx>,
         mir_structural_match_violation: bool,
     ) -> Pat<'tcx> {
+        trace!(self.treat_byte_string_as_slice);
         // This method is just a wrapper handling a validity check; the heavy lifting is
         // performed by the recursive `recur` method, which is not meant to be
         // invoked except by this method.
@@ -384,7 +390,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                     }
                     PatKind::Wild
                 }
-                // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this
+                // `&str` is represented as `ConstValue::Slice`, let's keep using this
                 // optimization for now.
                 ty::Str => PatKind::Constant { value: cv },
                 // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
@@ -393,11 +399,33 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                 // as slices. This means we turn `&[T; N]` constants into slice patterns, which
                 // has no negative effects on pattern matching, even if we're actually matching on
                 // arrays.
-                ty::Array(..) |
+                ty::Array(..) if !self.treat_byte_string_as_slice => {
+                    let old = self.behind_reference.replace(true);
+                    let array = tcx.deref_const(self.param_env.and(cv));
+                    let val = PatKind::Deref {
+                        subpattern: Pat {
+                            kind: Box::new(PatKind::Array {
+                                prefix: tcx
+                                    .destructure_const(param_env.and(array))
+                                    .fields
+                                    .iter()
+                                    .map(|val| self.recur(val, false))
+                                    .collect::<Result<_, _>>()?,
+                                slice: None,
+                                suffix: vec![],
+                            }),
+                            span,
+                            ty: pointee_ty,
+                        },
+                    };
+                    self.behind_reference.set(old);
+                    val
+                }
+                ty::Array(elem_ty, _) |
                 // Cannot merge this with the catch all branch below, because the `const_deref`
                 // changes the type from slice to array, we need to keep the original type in the
                 // pattern.
-                ty::Slice(..) => {
+                ty::Slice(elem_ty) => {
                     let old = self.behind_reference.replace(true);
                     let array = tcx.deref_const(self.param_env.and(cv));
                     let val = PatKind::Deref {
@@ -413,7 +441,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                                 suffix: vec![],
                             }),
                             span,
-                            ty: pointee_ty,
+                            ty: tcx.mk_slice(elem_ty),
                         },
                     };
                     self.behind_reference.set(old);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 188bf227c42..ffbf786491d 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1089,6 +1089,9 @@ impl<'a> Parser<'a> {
             self.parse_yield_expr(attrs)
         } else if self.eat_keyword(kw::Let) {
             self.parse_let_expr(attrs)
+        } else if self.eat_keyword(kw::Underscore) {
+            self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span);
+            Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs))
         } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
             // Don't complain about bare semicolons after unclosed braces
             // recovery in order to keep the error count down. Fixing the
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index b24c62b971a..e37c6418eb8 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -15,7 +15,6 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::{sym, Span, Symbol};
 
@@ -145,7 +144,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
                 //
                 // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
                 // is a pretty narrow case, however.
-                if nightly_options::is_nightly_build() {
+                if tcx.sess.is_nightly_build() {
                     for gate in missing_secondary {
                         let note = format!(
                             "add `#![feature({})]` to the crate attributes to enable",
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 7288015e170..debb873beb9 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -317,10 +317,11 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
         // swap in a new set of IR maps for this body
         let mut maps = IrMaps::new(self.tcx);
         let hir_id = maps.tcx.hir().body_owner(body.id());
-        let def_id = maps.tcx.hir().local_def_id(hir_id);
+        let local_def_id = maps.tcx.hir().local_def_id(hir_id);
+        let def_id = local_def_id.to_def_id();
 
         // Don't run unused pass for #[derive()]
-        if let Some(parent) = self.tcx.parent(def_id.to_def_id()) {
+        if let Some(parent) = self.tcx.parent(def_id) {
             if let DefKind::Impl = self.tcx.def_kind(parent.expect_local()) {
                 if self.tcx.has_attr(parent, sym::automatically_derived) {
                     return;
@@ -328,8 +329,8 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
             }
         }
 
-        if let Some(upvars) = maps.tcx.upvars_mentioned(def_id) {
-            for (&var_hir_id, _upvar) in upvars {
+        if let Some(captures) = maps.tcx.typeck(local_def_id).closure_captures.get(&def_id) {
+            for &var_hir_id in captures.keys() {
                 let var_name = maps.tcx.hir().name(var_hir_id);
                 maps.add_variable(Upvar(var_hir_id, var_name));
             }
@@ -340,7 +341,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
         intravisit::walk_body(&mut maps, body);
 
         // compute liveness
-        let mut lsets = Liveness::new(&mut maps, def_id);
+        let mut lsets = Liveness::new(&mut maps, local_def_id);
         let entry_ln = lsets.compute(&body, hir_id);
         lsets.log_liveness(entry_ln, body.id().hir_id);
 
@@ -397,10 +398,18 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
                 // construction site.
                 let mut call_caps = Vec::new();
                 let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id);
-                if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
-                    call_caps.extend(upvars.iter().map(|(&var_id, upvar)| {
+                if let Some(captures) = self
+                    .tcx
+                    .typeck(closure_def_id)
+                    .closure_captures
+                    .get(&closure_def_id.to_def_id())
+                {
+                    // If closure captures is Some, upvars_mentioned must also be Some
+                    let upvars = self.tcx.upvars_mentioned(closure_def_id).unwrap();
+                    call_caps.extend(captures.keys().map(|var_id| {
+                        let upvar = upvars[var_id];
                         let upvar_ln = self.add_live_node(UpvarNode(upvar.span));
-                        CaptureInfo { ln: upvar_ln, var_hid: var_id }
+                        CaptureInfo { ln: upvar_ln, var_hid: *var_id }
                     }));
                 }
                 self.set_captures(expr.hir_id, call_caps);
@@ -564,6 +573,7 @@ struct Liveness<'a, 'tcx> {
     typeck_results: &'a ty::TypeckResults<'tcx>,
     param_env: ty::ParamEnv<'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,
 
@@ -587,6 +597,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         let typeck_results = ir.tcx.typeck(body_owner);
         let param_env = ir.tcx.param_env(body_owner);
         let upvars = ir.tcx.upvars_mentioned(body_owner);
+        let closure_captures = typeck_results.closure_captures.get(&body_owner.to_def_id());
 
         let closure_ln = ir.add_live_node(ClosureNode);
         let exit_ln = ir.add_live_node(ExitNode);
@@ -600,6 +611,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             typeck_results,
             param_env,
             upvars,
+            closure_captures,
             successors: IndexVec::from_elem_n(None, num_live_nodes),
             rwu_table: RWUTable::new(num_live_nodes * num_vars),
             closure_ln,
@@ -850,14 +862,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         // if they are live on the entry to the closure, since only the closure
         // itself can access them on subsequent calls.
 
-        if let Some(upvars) = self.upvars {
+        if let Some(closure_captures) = self.closure_captures {
             // Mark upvars captured by reference as used after closure exits.
-            for (&var_hir_id, upvar) in upvars.iter().rev() {
-                let upvar_id = ty::UpvarId {
-                    var_path: ty::UpvarPath { hir_id: var_hir_id },
-                    closure_expr_id: self.body_owner,
-                };
-                match self.typeck_results.upvar_capture(upvar_id) {
+            // Since closure_captures is Some, upvars must exists too.
+            let upvars = self.upvars.unwrap();
+            for (&var_hir_id, upvar_id) in closure_captures {
+                let upvar = upvars[&var_hir_id];
+                match self.typeck_results.upvar_capture(*upvar_id) {
                     ty::UpvarCapture::ByRef(_) => {
                         let var = self.variable(var_hir_id, upvar.span);
                         self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
@@ -869,7 +880,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
         let succ = self.propagate_through_expr(&body.value, self.exit_ln);
 
-        if self.upvars.is_none() {
+        if self.closure_captures.is_none() {
             // Either not a closure, or closure without any captured variables.
             // No need to determine liveness of captured variables, since there
             // are none.
@@ -1341,7 +1352,21 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         acc: u32,
     ) -> LiveNode {
         match path.res {
-            Res::Local(hid) => self.access_var(hir_id, hid, succ, acc, path.span),
+            Res::Local(hid) => {
+                let in_upvars = self.upvars.map_or(false, |u| u.contains_key(&hid));
+                let in_captures = self.closure_captures.map_or(false, |c| c.contains_key(&hid));
+
+                match (in_upvars, in_captures) {
+                    (false, _) | (true, true) => self.access_var(hir_id, hid, succ, acc, path.span),
+                    (true, false) => {
+                        // This case is possible when with RFC-2229, a wild pattern
+                        // is used within a closure.
+                        // eg: `let _ = x`. The closure doesn't capture x here,
+                        // even though it's mentioned in the closure.
+                        succ
+                    }
+                }
+            }
             _ => succ,
         }
     }
@@ -1531,11 +1556,15 @@ impl<'tcx> Liveness<'_, 'tcx> {
     }
 
     fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
-        let upvars = match self.upvars {
+        let closure_captures = match self.closure_captures {
             None => return,
-            Some(upvars) => upvars,
+            Some(closure_captures) => closure_captures,
         };
-        for (&var_hir_id, upvar) in upvars.iter() {
+
+        // If closure_captures is Some(), upvars must be Some() too.
+        let upvars = self.upvars.unwrap();
+        for &var_hir_id in closure_captures.keys() {
+            let upvar = upvars[&var_hir_id];
             let var = self.variable(var_hir_id, upvar.span);
             let upvar_id = ty::UpvarId {
                 var_path: ty::UpvarPath { hir_id: var_hir_id },
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 75d75433f1b..4a0d356d337 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(or_patterns)]
 #![feature(control_flow_enum)]
 #![feature(try_blocks)]
+#![feature(associated_type_defaults)]
 #![recursion_limit = "256"]
 
 use rustc_attr as attr;
@@ -44,6 +45,8 @@ use std::{cmp, fmt, mem};
 /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits
 /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`.
 trait DefIdVisitor<'tcx> {
+    type BreakTy = ();
+
     fn tcx(&self) -> TyCtxt<'tcx>;
     fn shallow(&self) -> bool {
         false
@@ -56,7 +59,7 @@ trait DefIdVisitor<'tcx> {
         def_id: DefId,
         kind: &str,
         descr: &dyn fmt::Display,
-    ) -> ControlFlow<()>;
+    ) -> ControlFlow<Self::BreakTy>;
 
     /// Not overridden, but used to actually visit types and traits.
     fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
@@ -66,13 +69,16 @@ trait DefIdVisitor<'tcx> {
             dummy: Default::default(),
         }
     }
-    fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<()> {
+    fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<Self::BreakTy> {
         ty_fragment.visit_with(&mut self.skeleton())
     }
-    fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> {
+    fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
         self.skeleton().visit_trait(trait_ref)
     }
-    fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> {
+    fn visit_predicates(
+        &mut self,
+        predicates: ty::GenericPredicates<'tcx>,
+    ) -> ControlFlow<Self::BreakTy> {
         self.skeleton().visit_predicates(predicates)
     }
 }
@@ -87,13 +93,13 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V>
 where
     V: DefIdVisitor<'tcx> + ?Sized,
 {
-    fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> {
+    fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy> {
         let TraitRef { def_id, substs } = trait_ref;
         self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
         if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
     }
 
-    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> {
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
         match predicate.skip_binders() {
             ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => {
                 self.visit_trait(trait_ref)
@@ -119,7 +125,10 @@ where
         }
     }
 
-    fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> {
+    fn visit_predicates(
+        &mut self,
+        predicates: ty::GenericPredicates<'tcx>,
+    ) -> ControlFlow<V::BreakTy> {
         let ty::GenericPredicates { parent: _, predicates } = predicates;
         predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate))
     }
@@ -129,7 +138,9 @@ impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V>
 where
     V: DefIdVisitor<'tcx> + ?Sized,
 {
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+    type BreakTy = V::BreakTy;
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
         let tcx = self.def_id_visitor.tcx();
         // InternalSubsts are not visited here because they are visited below in `super_visit_with`.
         match *ty.kind() {
@@ -283,7 +294,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL>
         def_id: DefId,
         _kind: &str,
         _descr: &dyn fmt::Display,
-    ) -> ControlFlow<()> {
+    ) -> ControlFlow<Self::BreakTy> {
         self.min = VL::new_min(self, def_id);
         ControlFlow::CONTINUE
     }
@@ -902,7 +913,7 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
         def_id: DefId,
         _kind: &str,
         _descr: &dyn fmt::Display,
-    ) -> ControlFlow<()> {
+    ) -> ControlFlow<Self::BreakTy> {
         if let Some(def_id) = def_id.as_local() {
             if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
                 (self.tcx().visibility(def_id.to_def_id()), self.access_level)
@@ -1299,7 +1310,7 @@ impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
         def_id: DefId,
         kind: &str,
         descr: &dyn fmt::Display,
-    ) -> ControlFlow<()> {
+    ) -> ControlFlow<Self::BreakTy> {
         if self.check_def_id(def_id, kind, descr) {
             ControlFlow::BREAK
         } else {
@@ -1799,7 +1810,7 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
         def_id: DefId,
         kind: &str,
         descr: &dyn fmt::Display,
-    ) -> ControlFlow<()> {
+    ) -> ControlFlow<Self::BreakTy> {
         if self.check_def_id(def_id, kind, descr) {
             ControlFlow::BREAK
         } else {
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 34145c3c138..493b9f15271 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1163,9 +1163,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope);
         assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation");
 
-        let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id));
-        self.r.invocation_macro_rules_scopes.entry(invoc_id).or_default().insert(scope);
-        scope
+        self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id))
     }
 
     fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 00e6d5ca381..2473436a916 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -16,7 +16,6 @@ use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::PrimTy;
-use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -890,7 +889,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             }
             (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
                 err.span_label(span, "type aliases cannot be used as traits");
-                if nightly_options::is_nightly_build() {
+                if self.r.session.is_nightly_build() {
                     let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
                                `type` alias";
                     if let Some(span) = self.def_span(def_id) {
@@ -1675,7 +1674,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                 _ => {}
             }
         }
-        if nightly_options::is_nightly_build()
+        if self.tcx.sess.is_nightly_build()
             && !self.tcx.features().in_band_lifetimes
             && suggests_in_band
         {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 4e85c88c0e5..d18335ef2e6 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -976,9 +976,6 @@ pub struct Resolver<'a> {
     /// `macro_rules` scopes *produced* by expanding the macro invocations,
     /// include all the `macro_rules` items and other invocations generated by them.
     output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScopeRef<'a>>,
-    /// References to all `MacroRulesScope::Invocation(invoc_id)`s, used to update such scopes
-    /// when their corresponding `invoc_id`s get expanded.
-    invocation_macro_rules_scopes: FxHashMap<ExpnId, FxHashSet<MacroRulesScopeRef<'a>>>,
     /// Helper attributes that are in scope for the given expansion.
     helper_attrs: FxHashMap<ExpnId, Vec<Ident>>,
 
@@ -1310,7 +1307,6 @@ impl<'a> Resolver<'a> {
             non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
             invocation_parent_scopes: Default::default(),
             output_macro_rules_scopes: Default::default(),
-            invocation_macro_rules_scopes: Default::default(),
             helper_attrs: Default::default(),
             local_macro_def_scopes: FxHashMap::default(),
             name_already_seen: FxHashMap::default(),
@@ -1680,7 +1676,20 @@ impl<'a> Resolver<'a> {
                     !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive))
                 }
                 Scope::DeriveHelpersCompat => true,
-                Scope::MacroRules(..) => true,
+                Scope::MacroRules(macro_rules_scope) => {
+                    // Use "path compression" on `macro_rules` scope chains. This is an optimization
+                    // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`.
+                    // As another consequence of this optimization visitors never observe invocation
+                    // scopes for macros that were already expanded.
+                    while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() {
+                        if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) {
+                            macro_rules_scope.set(next_scope.get());
+                        } else {
+                            break;
+                        }
+                    }
+                    true
+                }
                 Scope::CrateRoot => true,
                 Scope::Module(..) => true,
                 Scope::RegisteredAttrs => use_prelude,
@@ -1716,11 +1725,9 @@ impl<'a> Resolver<'a> {
                     MacroRulesScope::Binding(binding) => {
                         Scope::MacroRules(binding.parent_macro_rules_scope)
                     }
-                    MacroRulesScope::Invocation(invoc_id) => Scope::MacroRules(
-                        self.output_macro_rules_scopes.get(&invoc_id).cloned().unwrap_or_else(
-                            || self.invocation_parent_scopes[&invoc_id].macro_rules,
-                        ),
-                    ),
+                    MacroRulesScope::Invocation(invoc_id) => {
+                        Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
+                    }
                     MacroRulesScope::Empty => Scope::Module(module),
                 },
                 Scope::CrateRoot => match ns {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 6bc9419ea84..21e43be2045 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -62,8 +62,8 @@ pub enum MacroRulesScope<'a> {
 }
 
 /// `macro_rules!` scopes are always kept by reference and inside a cell.
-/// The reason is that we update all scopes with value `MacroRulesScope::Invocation(invoc_id)`
-/// in-place immediately after `invoc_id` gets expanded.
+/// The reason is that we update scopes with value `MacroRulesScope::Invocation(invoc_id)`
+/// in-place after `invoc_id` gets expanded.
 /// This helps to avoid uncontrollable growth of `macro_rules!` scope chains,
 /// which usually grow lineraly with the number of macro invocations
 /// in a module (including derives) and hurt performance.
@@ -173,22 +173,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
         let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope);
         self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope);
 
-        // Update all `macro_rules` scopes referring to this invocation. This is an optimization
-        // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`.
-        if let Some(invocation_scopes) = self.invocation_macro_rules_scopes.remove(&expansion) {
-            for invocation_scope in &invocation_scopes {
-                invocation_scope.set(output_macro_rules_scope.get());
-            }
-            // All `macro_rules` scopes that previously referred to `expansion`
-            // are now rerouted to its output scope, if it's also an invocation.
-            if let MacroRulesScope::Invocation(invoc_id) = output_macro_rules_scope.get() {
-                self.invocation_macro_rules_scopes
-                    .entry(invoc_id)
-                    .or_default()
-                    .extend(invocation_scopes);
-            }
-        }
-
         parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
     }
 
@@ -687,11 +671,7 @@ impl<'a> Resolver<'a> {
                         {
                             Ok((macro_rules_binding.binding, Flags::MACRO_RULES))
                         }
-                        MacroRulesScope::Invocation(invoc_id)
-                            if !this.output_macro_rules_scopes.contains_key(&invoc_id) =>
-                        {
-                            Err(Determinacy::Undetermined)
-                        }
+                        MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined),
                         _ => Err(Determinacy::Determined),
                     },
                     Scope::CrateRoot => {
@@ -1054,6 +1034,7 @@ impl<'a> Resolver<'a> {
                 depr.suggestion,
                 lint,
                 span,
+                node_id,
             );
         }
     }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 87687339370..db16a90cc60 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1250,7 +1250,7 @@ fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
         None => DEFAULT_EDITION,
     };
 
-    if !edition.is_stable() && !nightly_options::is_nightly_build() {
+    if !edition.is_stable() && !nightly_options::match_is_nightly_build(matches) {
         early_error(
             ErrorOutputType::default(),
             &format!(
@@ -1547,7 +1547,9 @@ fn parse_libs(
                     );
                 }
             };
-            if kind == NativeLibKind::StaticNoBundle && !nightly_options::is_nightly_build() {
+            if kind == NativeLibKind::StaticNoBundle
+                && !nightly_options::match_is_nightly_build(matches)
+            {
                 early_error(
                     error_format,
                     "the library kind 'static-nobundle' is only \
@@ -1836,10 +1838,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         cg,
         error_format,
         externs,
+        unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
         crate_name,
         alt_std_name: None,
         libs,
-        unstable_features: UnstableFeatures::from_environment(),
         debug_assertions,
         actually_rustdoc: false,
         trimmed_def_paths: TrimmedDefPaths::default(),
@@ -1960,17 +1962,21 @@ pub mod nightly_options {
     use rustc_feature::UnstableFeatures;
 
     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
-        is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
+        match_is_nightly_build(matches)
+            && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
     }
 
-    pub fn is_nightly_build() -> bool {
-        UnstableFeatures::from_environment().is_nightly_build()
+    pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
+        is_nightly_build(matches.opt_str("crate-name").as_deref())
+    }
+
+    pub fn is_nightly_build(krate: Option<&str>) -> bool {
+        UnstableFeatures::from_environment(krate).is_nightly_build()
     }
 
     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
-        let really_allows_unstable_options =
-            UnstableFeatures::from_environment().is_nightly_build();
+        let really_allows_unstable_options = match_is_nightly_build(matches);
 
         for opt in flags.iter() {
             if opt.stability == OptionStability::Stable {
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 6f10d0c4b89..66c3738fb5b 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -4,7 +4,7 @@
 use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
 use rustc_ast::node_id::NodeId;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::sync::{Lock, Lrc, OnceCell};
+use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
 use rustc_errors::{error_code, Applicability, DiagnosticBuilder};
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
@@ -129,7 +129,6 @@ pub struct ParseSess {
     /// operation token that followed it, but that the parser cannot identify without further
     /// analysis.
     pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
-    pub injected_crate_name: OnceCell<Symbol>,
     pub gated_spans: GatedSpans,
     pub symbol_gallery: SymbolGallery,
     /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
@@ -150,7 +149,7 @@ impl ParseSess {
     pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
         Self {
             span_diagnostic: handler,
-            unstable_features: UnstableFeatures::from_environment(),
+            unstable_features: UnstableFeatures::from_environment(None),
             config: FxHashSet::default(),
             edition: ExpnId::root().expn_data().edition,
             raw_identifier_spans: Lock::new(Vec::new()),
@@ -158,7 +157,6 @@ impl ParseSess {
             source_map,
             buffered_lints: Lock::new(vec![]),
             ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
-            injected_crate_name: OnceCell::new(),
             gated_spans: GatedSpans::default(),
             symbol_gallery: SymbolGallery::default(),
             reached_eof: Lock::new(false),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 98b7f03df38..419d1447764 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -745,6 +745,9 @@ impl Session {
     pub fn unstable_options(&self) -> bool {
         self.opts.debugging_opts.unstable_options
     }
+    pub fn is_nightly_build(&self) -> bool {
+        self.opts.unstable_features.is_nightly_build()
+    }
     pub fn overflow_checks(&self) -> bool {
         self.opts
             .cg
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ad58f89d87d..3a2a3adce35 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -318,6 +318,7 @@ symbols! {
         call_mut,
         call_once,
         caller_location,
+        capture_disjoint_fields,
         cdylib,
         ceilf32,
         ceilf64,
@@ -909,6 +910,7 @@ symbols! {
         rustc_args_required_const,
         rustc_attrs,
         rustc_builtin_macro,
+        rustc_capture_analysis,
         rustc_clean,
         rustc_const_stable,
         rustc_const_unstable,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index ac91fcf6293..eba8e1a0613 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -51,7 +51,7 @@ pub(super) fn mangle(
 
     // Erase regions because they may not be deterministic when hashed
     // and should not matter anyhow.
-    let instance_ty = tcx.erase_regions(&instance_ty);
+    let instance_ty = tcx.erase_regions(instance_ty);
 
     let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
 
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 822a8352934..a28c8cac728 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -39,7 +39,7 @@ impl SymbolNamesTest<'tcx> {
                 let def_id = def_id.to_def_id();
                 let instance = Instance::new(
                     def_id,
-                    tcx.erase_regions(&InternalSubsts::identity_for_item(tcx, def_id)),
+                    tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)),
                 );
                 let mangled = tcx.symbol_name(instance);
                 tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index b9c5123e49a..05b6c4a48de 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -109,7 +109,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
             param_env,
             state: AutoderefSnapshot {
                 steps: vec![],
-                cur_ty: infcx.resolve_vars_if_possible(&base_ty),
+                cur_ty: infcx.resolve_vars_if_possible(base_ty),
                 obligations: vec![],
                 at_start: true,
                 reached_recursion_limit: false,
@@ -164,14 +164,14 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
         self.state.obligations.extend(obligations);
 
-        Some(self.infcx.resolve_vars_if_possible(&normalized_ty))
+        Some(self.infcx.resolve_vars_if_possible(normalized_ty))
     }
 
     /// Returns the final type we ended up with, which may be an inference
     /// variable (we will resolve it first, if we want).
     pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> {
         if resolve {
-            self.infcx.resolve_vars_if_possible(&self.state.cur_ty)
+            self.infcx.resolve_vars_if_possible(self.state.cur_ty)
         } else {
             self.state.cur_ty
         }
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 4ec1b29bca4..41184ce2116 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -28,7 +28,7 @@ pub trait InferCtxtExt<'tcx> {
         span: Span,
         body_id: hir::HirId,
         param_env: ty::ParamEnv<'tcx>,
-        value: &T,
+        value: T,
     ) -> InferOk<'tcx, T>
     where
         T: TypeFoldable<'tcx>;
@@ -41,7 +41,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         ty: Ty<'tcx>,
         span: Span,
     ) -> bool {
-        let ty = self.resolve_vars_if_possible(&ty);
+        let ty = self.resolve_vars_if_possible(ty);
 
         if !(param_env, ty).needs_infer() {
             return ty.is_copy_modulo_regions(self.tcx.at(span), param_env);
@@ -63,7 +63,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         span: Span,
         body_id: hir::HirId,
         param_env: ty::ParamEnv<'tcx>,
-        value: &T,
+        value: T,
     ) -> InferOk<'tcx, T>
     where
         T: TypeFoldable<'tcx>,
@@ -173,7 +173,7 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
         debug!("add_implied_bounds()");
 
         for &ty in fn_sig_tys {
-            let ty = infcx.resolve_vars_if_possible(&ty);
+            let ty = infcx.resolve_vars_if_possible(ty);
             debug!("add_implied_bounds: ty = {}", ty);
             let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
             self.add_outlives_bounds(Some(infcx), implied_bounds)
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 914fa1e52c2..ca547bf88b5 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -12,7 +12,6 @@ use rustc_infer::infer::{self, InferCtxt, InferOk};
 use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::config::nightly_options;
 use rustc_span::Span;
 
 use std::ops::ControlFlow;
@@ -113,7 +112,7 @@ pub trait InferCtxtExt<'tcx> {
         parent_def_id: LocalDefId,
         body_id: hir::HirId,
         param_env: ty::ParamEnv<'tcx>,
-        value: &T,
+        value: T,
         value_span: Span,
     ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>;
 
@@ -189,7 +188,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         parent_def_id: LocalDefId,
         body_id: hir::HirId,
         param_env: ty::ParamEnv<'tcx>,
-        value: &T,
+        value: T,
         value_span: Span,
     ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> {
         debug!(
@@ -403,7 +402,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
         let tcx = self.tcx;
 
-        let concrete_ty = self.resolve_vars_if_possible(&opaque_defn.concrete_ty);
+        let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
 
         debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty);
 
@@ -602,7 +601,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         };
         err.span_label(span, label);
 
-        if nightly_options::is_nightly_build() {
+        if self.tcx.sess.is_nightly_build() {
             err.help("add #![feature(member_constraints)] to the crate attributes to enable");
         }
 
@@ -693,12 +692,15 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
 where
     OP: FnMut(ty::Region<'tcx>),
 {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<()> {
+    fn visit_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: &ty::Binder<T>,
+    ) -> ControlFlow<Self::BreakTy> {
         t.as_ref().skip_binder().visit_with(self);
         ControlFlow::CONTINUE
     }
 
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *r {
             // ignore bound regions, keep visiting
             ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
@@ -709,7 +711,7 @@ where
         }
     }
 
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // We're only interested in types involving regions
         if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
             return ControlFlow::CONTINUE;
@@ -1002,7 +1004,7 @@ struct Instantiator<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Instantiator<'a, 'tcx> {
-    fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
+    fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
         debug!("instantiate_opaque_types_in_map(value={:?})", value);
         let tcx = self.infcx.tcx;
         value.fold_with(&mut BottomUpFolder {
@@ -1126,7 +1128,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
 
         let param_env = tcx.param_env(def_id);
         let InferOk { value: bounds, obligations } =
-            infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, &bounds);
+            infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, bounds);
         self.obligations.extend(obligations);
 
         debug!("instantiate_opaque_types: bounds={:?}", bounds);
@@ -1174,7 +1176,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
             // Change the predicate to refer to the type variable,
             // which will be the concrete type instead of the opaque type.
             // This also instantiates nested instances of `impl Trait`.
-            let predicate = self.instantiate_opaque_types_in_map(&predicate);
+            let predicate = self.instantiate_opaque_types_in_map(predicate);
 
             let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation);
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 93a0073588e..6ab16886ed2 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -304,11 +304,8 @@ impl AutoTraitFinder<'tcx> {
 
             // Call `infcx.resolve_vars_if_possible` to see if we can
             // get rid of any inference variables.
-            let obligation = infcx.resolve_vars_if_possible(&Obligation::new(
-                dummy_cause.clone(),
-                new_env,
-                pred,
-            ));
+            let obligation =
+                infcx.resolve_vars_if_possible(Obligation::new(dummy_cause.clone(), new_env, pred));
             let result = select.select(&obligation);
 
             match &result {
@@ -627,7 +624,7 @@ impl AutoTraitFinder<'tcx> {
                 fresh_preds.insert(self.clean_pred(select.infcx(), obligation.predicate));
 
             // Resolve any inference variables that we can, to help selection succeed
-            let predicate = select.infcx().resolve_vars_if_possible(&obligation.predicate);
+            let predicate = select.infcx().resolve_vars_if_possible(obligation.predicate);
 
             // We only add a predicate as a user-displayable bound if
             // it involves a generic parameter, and doesn't contain
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index adc8ae59086..026ab414443 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -37,7 +37,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         obligation: PredicateObligation<'tcx>,
     ) {
         assert!(!infcx.is_in_snapshot());
-        let obligation = infcx.resolve_vars_if_possible(&obligation);
+        let obligation = infcx.resolve_vars_if_possible(obligation);
 
         self.obligations.insert(obligation);
     }
@@ -80,11 +80,11 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
             // We iterate over all obligations, and record if we are able
             // to unambiguously prove at least one obligation.
             for obligation in self.obligations.drain(..) {
-                let obligation = infcx.resolve_vars_if_possible(&obligation);
+                let obligation = infcx.resolve_vars_if_possible(obligation);
                 let environment = obligation.param_env.caller_bounds();
                 let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
                 let mut orig_values = OriginalQueryValues::default();
-                let canonical_goal = infcx.canonicalize_query(&goal, &mut orig_values);
+                let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values);
 
                 match infcx.tcx.evaluate_goal(canonical_goal) {
                     Ok(response) => {
@@ -100,7 +100,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
                                 Ok(infer_ok) => next_round.extend(
                                     infer_ok.obligations.into_iter().map(|obligation| {
                                         assert!(!infcx.is_in_snapshot());
-                                        infcx.resolve_vars_if_possible(&obligation)
+                                        infcx.resolve_vars_if_possible(obligation)
                                     }),
                                 ),
 
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 3cb6ec86261..657d5c123e8 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -25,7 +25,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
 ) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
     // Remove any references to regions; this helps improve caching.
-    let trait_ref = tcx.erase_regions(&trait_ref);
+    let trait_ref = tcx.erase_regions(trait_ref);
     // We expect the input to be fully normalized.
     debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
     debug!(
@@ -89,7 +89,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
             debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
             fulfill_cx.register_predicate_obligation(&infcx, predicate);
         });
-        let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source);
+        let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
 
         info!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
         Ok(impl_source)
@@ -110,7 +110,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
 fn drain_fulfillment_cx_or_panic<T>(
     infcx: &InferCtxt<'_, 'tcx>,
     fulfill_cx: &mut FulfillmentContext<'tcx>,
-    result: &T,
+    result: T,
 ) -> T
 where
     T: TypeFoldable<'tcx>,
@@ -128,5 +128,5 @@ where
     }
 
     let result = infcx.resolve_vars_if_possible(result);
-    infcx.tcx.erase_regions(&result)
+    infcx.tcx.erase_regions(result)
 }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index c53c65c00b7..9324d55ac1b 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -103,7 +103,7 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
     };
 
     let Normalized { value: mut header, obligations } =
-        traits::normalize(selcx, param_env, ObligationCause::dummy(), &header);
+        traits::normalize(selcx, param_env, ObligationCause::dummy(), header);
 
     header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
     header
@@ -162,7 +162,8 @@ fn overlap_within_probe(
     let opt_failing_obligation = a_impl_header
         .predicates
         .iter()
-        .chain(&b_impl_header.predicates)
+        .copied()
+        .chain(b_impl_header.predicates)
         .map(|p| infcx.resolve_vars_if_possible(p))
         .map(|p| Obligation {
             cause: ObligationCause::dummy(),
@@ -188,7 +189,7 @@ fn overlap_within_probe(
         }
     }
 
-    let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header);
+    let impl_header = selcx.infcx().resolve_vars_if_possible(a_impl_header);
     let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
     debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
 
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index e1721a5a88a..fdb2361ba03 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -78,7 +78,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
                     Concrete,
                 }
                 let mut failure_kind = FailureKind::Concrete;
-                walk_abstract_const(tcx, ct, |node| match node {
+                walk_abstract_const::<!, _>(tcx, ct, |node| match node {
                     Node::Leaf(leaf) => {
                         let leaf = leaf.subst(tcx, ct.substs);
                         if leaf.has_infer_types_or_consts() {
@@ -574,19 +574,19 @@ pub(super) fn try_unify_abstract_consts<'tcx>(
     // on `ErrorReported`.
 }
 
-pub fn walk_abstract_const<'tcx, F>(
+pub fn walk_abstract_const<'tcx, R, F>(
     tcx: TyCtxt<'tcx>,
     ct: AbstractConst<'tcx>,
     mut f: F,
-) -> ControlFlow<()>
+) -> ControlFlow<R>
 where
-    F: FnMut(Node<'tcx>) -> ControlFlow<()>,
+    F: FnMut(Node<'tcx>) -> ControlFlow<R>,
 {
-    fn recurse<'tcx>(
+    fn recurse<'tcx, R>(
         tcx: TyCtxt<'tcx>,
         ct: AbstractConst<'tcx>,
-        f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<()>,
-    ) -> ControlFlow<()> {
+        f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<R>,
+    ) -> ControlFlow<R> {
         let root = ct.root();
         f(root)?;
         match root {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 2d57c39f7c7..d429d889fcc 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -182,7 +182,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     where
         T: fmt::Display + TypeFoldable<'tcx>,
     {
-        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
+        let predicate = self.resolve_vars_if_possible(obligation.predicate.clone());
         let mut err = struct_span_err!(
             self.tcx.sess,
             obligation.cause.span,
@@ -213,7 +213,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     /// we do not suggest increasing the overflow limit, which is not
     /// going to help).
     fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
-        let cycle = self.resolve_vars_if_possible(&cycle.to_owned());
+        let cycle = self.resolve_vars_if_possible(cycle.to_owned());
         assert!(!cycle.is_empty());
 
         debug!("report_overflow_error_cycle: cycle={:?}", cycle);
@@ -259,7 +259,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 match bound_predicate.skip_binder() {
                     ty::PredicateAtom::Trait(trait_predicate, _) => {
                         let trait_predicate = bound_predicate.rebind(trait_predicate);
-                        let trait_predicate = self.resolve_vars_if_possible(&trait_predicate);
+                        let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
 
                         if self.tcx.sess.has_errors() && trait_predicate.references_error() {
                             return;
@@ -414,17 +414,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             err.span_label(enclosing_scope_span, s.as_str());
                         }
 
-                        self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg);
-                        self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
-                        self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
-                        self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
+                        self.suggest_dereferences(&obligation, &mut err, trait_ref, points_at_arg);
+                        self.suggest_fn_call(&obligation, &mut err, trait_ref, points_at_arg);
+                        self.suggest_remove_reference(&obligation, &mut err, trait_ref);
+                        self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref);
                         self.note_version_mismatch(&mut err, &trait_ref);
 
                         if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
-                            self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span);
+                            self.suggest_await_before_try(&mut err, &obligation, trait_ref, span);
                         }
 
-                        if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) {
+                        if self.suggest_impl_trait(&mut err, span, &obligation, trait_ref) {
                             err.emit();
                             return;
                         }
@@ -487,7 +487,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                 self.suggest_change_mut(
                                     &obligation,
                                     &mut err,
-                                    &trait_ref,
+                                    trait_ref,
                                     points_at_arg,
                                 );
                             }
@@ -533,7 +533,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
                     ty::PredicateAtom::RegionOutlives(predicate) => {
                         let predicate = bound_predicate.rebind(predicate);
-                        let predicate = self.resolve_vars_if_possible(&predicate);
+                        let predicate = self.resolve_vars_if_possible(predicate);
                         let err = self
                             .region_outlives_predicate(&obligation.cause, predicate)
                             .err()
@@ -549,7 +549,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     }
 
                     ty::PredicateAtom::Projection(..) | ty::PredicateAtom::TypeOutlives(..) => {
-                        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
+                        let predicate = self.resolve_vars_if_possible(obligation.predicate);
                         struct_span_err!(
                             self.tcx.sess,
                             span,
@@ -671,9 +671,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 }
             }
 
-            OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => {
-                let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref);
-                let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref);
+            OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => {
+                let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
+                let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
 
                 if expected_trait_ref.self_ty().references_error() {
                     return;
@@ -1035,7 +1035,7 @@ trait InferCtxtPrivExt<'tcx> {
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: &ty::PolyTraitRef<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         new_self_ty: Ty<'tcx>,
     ) -> PredicateObligation<'tcx>;
 
@@ -1157,7 +1157,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
         error: &MismatchedProjectionTypes<'tcx>,
     ) {
-        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
+        let predicate = self.resolve_vars_if_possible(obligation.predicate);
 
         if predicate.references_error() {
             return;
@@ -1178,7 +1178,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 let (data, _) = self.replace_bound_vars_with_fresh_vars(
                     obligation.cause.span,
                     infer::LateBoundRegionConversionTime::HigherRankedType,
-                    &bound_predicate.rebind(data),
+                    bound_predicate.rebind(data),
                 );
                 let mut obligations = vec![];
                 let normalized_ty = super::normalize_projection_type(
@@ -1343,7 +1343,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
 
         // Sort impl candidates so that ordering is consistent for UI tests.
         let mut normalized_impl_candidates =
-            impl_candidates.iter().map(normalize).collect::<Vec<String>>();
+            impl_candidates.iter().copied().map(normalize).collect::<Vec<String>>();
 
         // Sort before taking the `..end` range,
         // because the ordering of `impl_candidates` may not be deterministic:
@@ -1364,7 +1364,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
     ) -> Option<(String, Option<Span>)> {
         match code {
             &ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
-                let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
+                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
                 match self.get_parent_trait_ref(&data.parent_code) {
                     Some(t) => Some(t),
                     None => {
@@ -1414,7 +1414,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: &ty::PolyTraitRef<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         new_self_ty: Ty<'tcx>,
     ) -> PredicateObligation<'tcx> {
         assert!(!new_self_ty.has_escaping_bound_vars());
@@ -1441,7 +1441,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
         // ambiguous impls. The latter *ought* to be a
         // coherence violation, so we don't report it here.
 
-        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
+        let predicate = self.resolve_vars_if_possible(obligation.predicate);
         let span = obligation.cause.span;
 
         debug!(
@@ -1673,7 +1673,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 &mut selcx,
                 param_env,
                 ObligationCause::dummy(),
-                &cleaned_pred,
+                cleaned_pred,
             )
             .value;
 
@@ -1808,7 +1808,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
         cause_code: &ObligationCauseCode<'tcx>,
     ) -> bool {
         if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
-            let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
+            let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
 
             if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) {
                 return true;
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 0f5aad5af12..1b5375938af 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -36,7 +36,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     ) -> Option<DefId> {
         let tcx = self.tcx;
         let param_env = obligation.param_env;
-        let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
+        let trait_ref = tcx.erase_late_bound_regions(trait_ref);
         let trait_self_ty = trait_ref.self_ty();
 
         let mut self_match_impls = vec![];
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 1c6e661782f..7e92df28ca2 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -49,7 +49,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
-        trait_ref: &ty::PolyTraitRef<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         points_at_arg: bool,
     );
 
@@ -64,7 +64,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
         points_at_arg: bool,
     );
 
@@ -81,14 +81,14 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
     );
 
     fn suggest_change_mut(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
         points_at_arg: bool,
     );
 
@@ -97,7 +97,7 @@ pub trait InferCtxtExt<'tcx> {
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
     );
 
     fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>;
@@ -107,7 +107,7 @@ pub trait InferCtxtExt<'tcx> {
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
     ) -> bool;
 
     fn point_at_returns_when_relevant(
@@ -168,7 +168,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         err: &mut DiagnosticBuilder<'_>,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
         span: Span,
     );
 }
@@ -462,7 +462,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
-        trait_ref: &ty::PolyTraitRef<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         points_at_arg: bool,
     ) {
         // It only make sense when suggesting dereferences for arguments
@@ -475,7 +475,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let real_trait_ref = match &obligation.cause.code {
             ObligationCauseCode::ImplDerivedObligation(cause)
             | ObligationCauseCode::DerivedObligation(cause)
-            | ObligationCauseCode::BuiltinDerivedObligation(cause) => &cause.parent_trait_ref,
+            | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_ref,
             _ => trait_ref,
         };
         let real_ty = match real_trait_ref.self_ty().no_bound_vars() {
@@ -556,7 +556,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
         points_at_arg: bool,
     ) {
         let self_ty = match trait_ref.self_ty().no_bound_vars() {
@@ -734,7 +734,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
     ) {
         let span = obligation.cause.span;
 
@@ -797,7 +797,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
         points_at_arg: bool,
     ) {
         let span = obligation.cause.span;
@@ -832,7 +832,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
                 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    &trait_ref,
+                    trait_ref,
                     suggested_ty,
                 );
                 let suggested_ty_would_satisfy_obligation = self
@@ -869,7 +869,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
     ) {
         let is_empty_tuple =
             |ty: ty::Binder<Ty<'_>>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty());
@@ -919,7 +919,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
     ) -> bool {
         match obligation.cause.code.peel_derives() {
             // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
@@ -976,12 +976,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             .returns
             .iter()
             .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id))
-            .map(|ty| self.resolve_vars_if_possible(&ty));
+            .map(|ty| self.resolve_vars_if_possible(ty));
         let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold(
             (None, true, true),
             |(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool),
              ty| {
-                let ty = self.resolve_vars_if_possible(&ty);
+                let ty = self.resolve_vars_if_possible(ty);
                 same &=
                     !matches!(ty.kind(), ty::Error(_))
                         && last_ty.map_or(true, |last_ty| {
@@ -1133,7 +1133,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
             for expr in &visitor.returns {
                 if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) {
-                    let ty = self.resolve_vars_if_possible(&returned_ty);
+                    let ty = self.resolve_vars_if_possible(returned_ty);
                     err.span_label(expr.span, &format!("this returned value is of type `{}`", ty));
                 }
             }
@@ -1406,7 +1406,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
         // Look for a type inside the generator interior that matches the target type to get
         // a span.
-        let target_ty_erased = self.tcx.erase_regions(&target_ty);
+        let target_ty_erased = self.tcx.erase_regions(target_ty);
         let ty_matches = |ty| -> bool {
             // Careful: the regions for types that appear in the
             // generator interior are not generally known, so we
@@ -1420,8 +1420,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             // generator frame. Bound regions are preserved by
             // `erase_regions` and so we must also call
             // `erase_late_bound_regions`.
-            let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(ty));
-            let ty_erased = self.tcx.erase_regions(&ty_erased);
+            let ty_erased = self.tcx.erase_late_bound_regions(ty::Binder::bind(ty));
+            let ty_erased = self.tcx.erase_regions(ty_erased);
             let eq = ty::TyS::same_type(ty_erased, target_ty_erased);
             debug!(
                 "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \
@@ -1437,7 +1437,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
             interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
                 let upvar_ty = typeck_results.node_type(*upvar_id);
-                let upvar_ty = self.resolve_vars_if_possible(&upvar_ty);
+                let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
                 if ty_matches(&upvar_ty) {
                     Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
                 } else {
@@ -2010,7 +2010,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 err.note("shared static variables must have a type that implements `Sync`");
             }
             ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
-                let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
+                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
                 let ty = parent_trait_ref.skip_binder().self_ty();
                 if parent_trait_ref.references_error() {
                     err.cancel();
@@ -2025,8 +2025,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     if let ObligationCauseCode::BuiltinDerivedObligation(ref data) =
                         *data.parent_code
                     {
-                        let parent_trait_ref =
-                            self.resolve_vars_if_possible(&data.parent_trait_ref);
+                        let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
                         let ty = parent_trait_ref.skip_binder().self_ty();
                         matches!(ty.kind(), ty::Generator(..))
                             || matches!(ty.kind(), ty::Closure(..))
@@ -2056,7 +2055,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 }
             }
             ObligationCauseCode::ImplDerivedObligation(ref data) => {
-                let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
+                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
                 err.note(&format!(
                     "required because of the requirements on the impl of `{}` for `{}`",
                     parent_trait_ref.print_only_trait_path(),
@@ -2074,7 +2073,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 });
             }
             ObligationCauseCode::DerivedObligation(ref data) => {
-                let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
+                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
                 let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
                 // #74711: avoid a stack overflow
                 ensure_sufficient_stack(|| {
@@ -2132,7 +2131,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         err: &mut DiagnosticBuilder<'_>,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
         span: Span,
     ) {
         debug!(
@@ -2150,13 +2149,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
                 let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
 
-                let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty());
+                let self_ty = self.resolve_vars_if_possible(trait_ref.self_ty());
 
                 // Do not check on infer_types to avoid panic in evaluate_obligation.
                 if self_ty.has_infer_types() {
                     return;
                 }
-                let self_ty = self.tcx.erase_regions(&self_ty);
+                let self_ty = self.tcx.erase_regions(self_ty);
 
                 let impls_future = self.tcx.type_implements_trait((
                     future_trait,
@@ -2197,7 +2196,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
                 debug!(
                     "suggest_await_before_try: normalized_projection_type {:?}",
-                    self.resolve_vars_if_possible(&normalized_ty)
+                    self.resolve_vars_if_possible(normalized_ty)
                 );
                 let try_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 538c14c6b72..a04f816b0f8 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -202,7 +202,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
     ) {
         // this helps to reduce duplicate errors, as well as making
         // debug output much nicer to read and so on.
-        let obligation = infcx.resolve_vars_if_possible(&obligation);
+        let obligation = infcx.resolve_vars_if_possible(obligation);
 
         debug!(?obligation, "register_predicate_obligation");
 
@@ -298,7 +298,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
         if !change {
             debug!(
                 "process_predicate: pending obligation {:?} still stalled on {:?}",
-                self.selcx.infcx().resolve_vars_if_possible(&pending_obligation.obligation),
+                self.selcx.infcx().resolve_vars_if_possible(pending_obligation.obligation.clone()),
                 pending_obligation.stalled_on
             );
             return ProcessResult::Unchanged;
@@ -338,14 +338,14 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
 
         if obligation.predicate.has_infer_types_or_consts() {
             obligation.predicate =
-                self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate);
+                self.selcx.infcx().resolve_vars_if_possible(obligation.predicate);
         }
 
         debug!(?obligation, ?obligation.cause, "process_obligation");
 
         let infcx = self.selcx.infcx();
 
-        match obligation.predicate.kind() {
+        match *obligation.predicate.kind() {
             ty::PredicateKind::ForAll(binder) => match binder.skip_binder() {
                 // Evaluation will discard candidates using the leak check.
                 // This means we need to pass it the bound version of our
@@ -384,9 +384,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
             },
-            &ty::PredicateKind::Atom(atom) => match atom {
-                ty::PredicateAtom::Trait(ref data, _) => {
-                    let trait_obligation = obligation.with(Binder::dummy(*data));
+            ty::PredicateKind::Atom(atom) => match atom {
+                ty::PredicateAtom::Trait(data, _) => {
+                    let trait_obligation = obligation.with(Binder::dummy(data));
 
                     self.process_trait_obligation(
                         obligation,
@@ -639,7 +639,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
 
                 debug!(
                     "process_predicate: pending obligation {:?} now stalled on {:?}",
-                    infcx.resolve_vars_if_possible(obligation),
+                    infcx.resolve_vars_if_possible(obligation.clone()),
                     stalled_on
                 );
 
@@ -684,7 +684,7 @@ fn trait_ref_infer_vars<'a, 'tcx>(
 ) -> Vec<TyOrConstInferVar<'tcx>> {
     selcx
         .infcx()
-        .resolve_vars_if_possible(&trait_ref)
+        .resolve_vars_if_possible(trait_ref)
         .skip_binder()
         .substs
         .iter()
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index e23f5a583b2..cedd1aa54b8 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -50,7 +50,7 @@ pub fn can_type_implement_copy(
                 let span = tcx.def_span(field.did);
                 let cause = ObligationCause::dummy_with_span(span);
                 let ctx = traits::FulfillmentContext::new();
-                match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) {
+                match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) {
                     Ok(ty) => {
                         if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
                             infringing.push(field);
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index c93087a18cf..2d7df2ddd11 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -223,7 +223,7 @@ fn do_normalize_predicates<'tcx>(
         // we move over to lazy normalization *anyway*.
         let fulfill_cx = FulfillmentContext::new_ignoring_regions();
         let predicates =
-            match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) {
+            match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
                 Ok(predicates) => predicates,
                 Err(errors) => {
                     infcx.report_fulfillment_errors(&errors, None, false);
@@ -243,7 +243,7 @@ fn do_normalize_predicates<'tcx>(
             RegionckMode::default(),
         );
 
-        let predicates = match infcx.fully_resolve(&predicates) {
+        let predicates = match infcx.fully_resolve(predicates) {
             Ok(predicates) => predicates,
             Err(fixup_err) => {
                 // If we encounter a fixup error, it means that some type
@@ -384,7 +384,7 @@ pub fn fully_normalize<'a, 'tcx, T>(
     mut fulfill_cx: FulfillmentContext<'tcx>,
     cause: ObligationCause<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    value: &T,
+    value: T,
 ) -> Result<T, Vec<FulfillmentError<'tcx>>>
 where
     T: TypeFoldable<'tcx>,
@@ -404,7 +404,7 @@ where
     debug!("fully_normalize: select_all_or_error start");
     fulfill_cx.select_all_or_error(infcx)?;
     debug!("fully_normalize: select_all_or_error complete");
-    let resolved_value = infcx.resolve_vars_if_possible(&normalized_value);
+    let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
     debug!("fully_normalize: resolved_value={:?}", resolved_value);
     Ok(resolved_value)
 }
@@ -424,7 +424,7 @@ pub fn impossible_predicates<'tcx>(
         let mut fulfill_cx = FulfillmentContext::new();
         let cause = ObligationCause::dummy();
         let Normalized { value: predicates, obligations } =
-            normalize(&mut selcx, param_env, cause.clone(), &predicates);
+            normalize(&mut selcx, param_env, cause.clone(), predicates);
         for obligation in obligations {
             fulfill_cx.register_predicate_obligation(&infcx, obligation);
         }
@@ -435,7 +435,7 @@ pub fn impossible_predicates<'tcx>(
 
         fulfill_cx.select_all_or_error(&infcx).is_err()
     });
-    debug!("impossible_predicates(predicates={:?}) = {:?}", predicates, result);
+    debug!("impossible_predicates = {:?}", result);
     result
 }
 
@@ -494,7 +494,7 @@ fn vtable_methods<'tcx>(
             // erase them if they appear, so that we get the type
             // at some particular call site.
             let substs =
-                tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs);
+                tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
 
             // It's possible that the method relies on where-clauses that
             // do not hold for this particular set of type parameters.
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 32e0991733b..d912a00d6b7 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -446,7 +446,7 @@ fn virtual_call_violation_for_method<'tcx>(
     }
 
     let receiver_ty =
-        tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0]));
+        tcx.liberate_late_bound_regions(method.def_id, sig.map_bound(|sig| sig.inputs()[0]));
 
     // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
     // However, this is already considered object-safe. We allow it as a special case here.
@@ -771,7 +771,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
     }
 
     impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
-        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+        type BreakTy = ();
+
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             match t.kind() {
                 ty::Param(_) => {
                     if t == self.tcx.types.self_param {
@@ -812,7 +814,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
             }
         }
 
-        fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<()> {
+        fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             // First check if the type of this constant references `Self`.
             self.visit_ty(ct.ty)?;
 
@@ -844,7 +846,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
             }
         }
 
-        fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<()> {
+        fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
             if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() {
                 // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for
                 // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index a85ffd3c961..dead795c6af 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -168,7 +168,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
     let infcx = selcx.infcx();
     infcx.commit_if_ok(|_snapshot| {
         let placeholder_predicate =
-            infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
+            infcx.replace_bound_vars_with_placeholders(obligation.predicate);
 
         let placeholder_obligation = obligation.with(placeholder_predicate);
         let result = project_and_unify_type(selcx, &placeholder_obligation)?;
@@ -232,7 +232,7 @@ pub fn normalize<'a, 'b, 'tcx, T>(
     selcx: &'a mut SelectionContext<'b, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     cause: ObligationCause<'tcx>,
-    value: &T,
+    value: T,
 ) -> Normalized<'tcx, T>
 where
     T: TypeFoldable<'tcx>,
@@ -246,7 +246,7 @@ pub fn normalize_to<'a, 'b, 'tcx, T>(
     selcx: &'a mut SelectionContext<'b, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     cause: ObligationCause<'tcx>,
-    value: &T,
+    value: T,
     obligations: &mut Vec<PredicateObligation<'tcx>>,
 ) -> T
 where
@@ -261,7 +261,7 @@ pub fn normalize_with_depth<'a, 'b, 'tcx, T>(
     param_env: ty::ParamEnv<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize,
-    value: &T,
+    value: T,
 ) -> Normalized<'tcx, T>
 where
     T: TypeFoldable<'tcx>,
@@ -277,7 +277,7 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
     param_env: ty::ParamEnv<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize,
-    value: &T,
+    value: T,
     obligations: &mut Vec<PredicateObligation<'tcx>>,
 ) -> T
 where
@@ -309,7 +309,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
         AssocTypeNormalizer { selcx, param_env, cause, obligations, depth }
     }
 
-    fn fold<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
+    fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
         let value = self.selcx.infcx().resolve_vars_if_possible(value);
 
         if !value.has_projections() { value } else { value.fold_with(self) }
@@ -365,7 +365,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                 }
             }
 
-            ty::Projection(ref data) if !data.has_escaping_bound_vars() => {
+            ty::Projection(data) if !data.has_escaping_bound_vars() => {
                 // This is kind of hacky -- we need to be able to
                 // handle normalization within binders because
                 // otherwise we wind up a need to normalize when doing
@@ -381,7 +381,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                 let normalized_ty = normalize_projection_type(
                     self.selcx,
                     self.param_env,
-                    *data,
+                    data,
                     self.cause.clone(),
                     self.depth,
                     &mut self.obligations,
@@ -474,7 +474,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
 ) -> Result<Option<Ty<'tcx>>, InProgress> {
     let infcx = selcx.infcx();
 
-    let projection_ty = infcx.resolve_vars_if_possible(&projection_ty);
+    let projection_ty = infcx.resolve_vars_if_possible(projection_ty);
     let cache_key = ProjectionCacheKey::new(projection_ty);
 
     // FIXME(#20304) For now, I am caching here, which is good, but it
@@ -567,7 +567,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
                     depth + 1,
                     &mut projected_obligations,
                 );
-                let normalized_ty = normalizer.fold(&projected_ty);
+                let normalized_ty = normalizer.fold(projected_ty);
 
                 debug!(?normalized_ty, ?depth);
 
@@ -1013,8 +1013,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     if obligation.param_env.reveal() == Reveal::All {
                         // NOTE(eddyb) inference variables can resolve to parameters, so
                         // assume `poly_trait_ref` isn't monomorphic, if it contains any.
-                        let poly_trait_ref =
-                            selcx.infcx().resolve_vars_if_possible(&poly_trait_ref);
+                        let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(poly_trait_ref);
                         !poly_trait_ref.still_further_specializable()
                     } else {
                         debug!(
@@ -1192,7 +1191,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
         obligation.param_env,
         obligation.cause.clone(),
         obligation.recursion_depth + 1,
-        &gen_sig,
+        gen_sig,
     );
 
     debug!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate");
@@ -1263,7 +1262,7 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
         obligation.param_env,
         obligation.cause.clone(),
         obligation.recursion_depth + 1,
-        &sig,
+        sig,
     );
 
     confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
@@ -1282,7 +1281,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
         obligation.param_env,
         obligation.cause.clone(),
         obligation.recursion_depth + 1,
-        &closure_sig,
+        closure_sig,
     );
 
     debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
@@ -1336,7 +1335,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
     let (cache_entry, _) = infcx.replace_bound_vars_with_fresh_vars(
         cause.span,
         LateBoundRegionConversionTime::HigherRankedType,
-        &poly_cache_entry,
+        poly_cache_entry,
     );
 
     let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
@@ -1349,7 +1348,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
-                &cache_trait_ref,
+                cache_trait_ref,
                 &mut nested_obligations,
             )
         })
@@ -1445,7 +1444,7 @@ fn assoc_ty_own_obligations<'cx, 'tcx>(
             obligation.param_env,
             obligation.cause.clone(),
             obligation.recursion_depth + 1,
-            &predicate,
+            predicate,
             nested,
         );
         nested.push(Obligation::with_depth(
@@ -1526,7 +1525,7 @@ impl<'tcx> ProjectionCacheKeyExt<'tcx> for ProjectionCacheKey<'tcx> {
                 // from a specific call to `opt_normalize_projection_type` - if
                 // there's no precise match, the original cache entry is "stranded"
                 // anyway.
-                infcx.resolve_vars_if_possible(&predicate.projection_ty),
+                infcx.resolve_vars_if_possible(predicate.projection_ty),
             )
         })
     }
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 8212823a6db..f05582f0614 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -40,10 +40,10 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
         }
 
         let mut orig_values = OriginalQueryValues::default();
-        let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values);
+        let c_ty = self.infcx.canonicalize_query(self.param_env.and(ty), &mut orig_values);
         let span = self.cause.span;
         debug!("c_ty = {:?}", c_ty);
-        if let Ok(result) = &tcx.dropck_outlives(c_ty) {
+        if let Ok(result) = tcx.dropck_outlives(c_ty) {
             if result.is_proven() {
                 if let Ok(InferOk { value, obligations }) =
                     self.infcx.instantiate_query_response_and_region_obligations(
@@ -53,7 +53,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
                         result,
                     )
                 {
-                    let ty = self.infcx.resolve_vars_if_possible(&ty);
+                    let ty = self.infcx.resolve_vars_if_possible(ty);
                     let kinds = value.into_kinds_reporting_overflows(tcx, span, ty);
                     return InferOk { value: kinds, obligations };
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 0569f6217da..b83a4cd1e57 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -65,7 +65,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
     ) -> Result<EvaluationResult, OverflowError> {
         let mut _orig_values = OriginalQueryValues::default();
         let c_pred = self
-            .canonicalize_query(&obligation.param_env.and(obligation.predicate), &mut _orig_values);
+            .canonicalize_query(obligation.param_env.and(obligation.predicate), &mut _orig_values);
         // Run canonical query. If overflow occurs, rerun from scratch but this time
         // in standard trait query mode so that overflow is handled appropriately
         // within `SelectionContext`.
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 42a598ce3a0..54743ef9ce9 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -19,7 +19,7 @@ use super::NoSolution;
 pub use rustc_middle::traits::query::NormalizationResult;
 
 pub trait AtExt<'tcx> {
-    fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution>
+    fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
     where
         T: TypeFoldable<'tcx>;
 }
@@ -38,7 +38,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
     /// normalizing, but for now should be used only when we actually
     /// know that normalization will succeed, since error reporting
     /// and other details are still "under development".
-    fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution>
+    fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
     where
         T: TypeFoldable<'tcx>,
     {
@@ -97,6 +97,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
         self.infcx.tcx
     }
 
+    #[instrument(skip(self))]
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         if !ty.has_projections() {
             return ty;
@@ -145,7 +146,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 }
             }
 
-            ty::Projection(ref data) if !data.has_escaping_bound_vars() => {
+            ty::Projection(data) if !data.has_escaping_bound_vars() => {
                 // This is kind of hacky -- we need to be able to
                 // handle normalization within binders because
                 // otherwise we wind up a need to normalize when doing
@@ -165,7 +166,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 // so we cannot canonicalize it.
                 let c_data = self
                     .infcx
-                    .canonicalize_hr_query_hack(&self.param_env.and(*data), &mut orig_values);
+                    .canonicalize_hr_query_hack(self.param_env.and(data), &mut orig_values);
                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
                 debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
                 match tcx.normalize_projection_ty(c_data) {
@@ -180,7 +181,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                             self.cause,
                             self.param_env,
                             &orig_values,
-                            &result,
+                            result,
                         ) {
                             Ok(InferOk { value: result, obligations }) => {
                                 debug!("QueryNormalizer: result = {:#?}", result);
diff --git a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs
index a42409515db..f5fa52c915d 100644
--- a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs
@@ -51,7 +51,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         debug!("implied_outlives_bounds(ty = {:?})", ty);
 
         let mut orig_values = OriginalQueryValues::default();
-        let key = self.canonicalize_query(&param_env.and(ty), &mut orig_values);
+        let key = self.canonicalize_query(param_env.and(ty), &mut orig_values);
         let result = match self.tcx.implied_outlives_bounds(key) {
             Ok(r) => r,
             Err(NoSolution) => {
@@ -68,7 +68,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
             &ObligationCause::misc(span, body_id),
             param_env,
             &orig_values,
-            &result,
+            result,
         );
         debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result);
         let result = match result {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 915e8ae4a7a..1688539165a 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -96,7 +96,7 @@ fn scrape_region_constraints<'tcx, R>(
         region_obligations
             .iter()
             .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
-            .map(|(ty, r)| (infcx.resolve_vars_if_possible(&ty), r)),
+            .map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)),
         &region_constraint_data,
     );
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index ed6c6d0cc0a..130ffa1a33a 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -81,16 +81,14 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
         // like the subtype query, which go awry around
         // `'static` otherwise.
         let mut canonical_var_values = OriginalQueryValues::default();
-        let canonical_self =
-            infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values);
+        let old_param_env = query_key.param_env;
+        let canonical_self = infcx.canonicalize_hr_query_hack(query_key, &mut canonical_var_values);
         let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;
 
-        let param_env = query_key.param_env;
-
         let InferOk { value, obligations } = infcx
             .instantiate_nll_query_response_and_region_obligations(
                 &ObligationCause::dummy(),
-                param_env,
+                old_param_env,
                 &canonical_var_values,
                 canonical_result,
                 output_query_region_constraints,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index ea18a689065..d2556c44fb4 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -229,7 +229,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             param_env: obligation.param_env,
             cause: obligation.cause.clone(),
             recursion_depth: obligation.recursion_depth,
-            predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate),
+            predicate: self.infcx().resolve_vars_if_possible(obligation.predicate),
         };
 
         if obligation.predicate.skip_binder().self_ty().is_ty_var() {
@@ -604,7 +604,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // The code below doesn't care about regions, and the
             // self-ty here doesn't escape this probe, so just erase
             // any LBR.
-            let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty());
+            let self_ty = self.tcx().erase_late_bound_regions(obligation.self_ty());
             let poly_trait_ref = match self_ty.kind() {
                 ty::Dynamic(ref data, ..) => {
                     if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
@@ -639,9 +639,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             debug!(?poly_trait_ref, "assemble_candidates_from_object_ty");
 
-            let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
+            let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
             let placeholder_trait_predicate =
-                self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
+                self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
 
             // Count only those upcast versions that match the trait-ref
             // we are looking for. Specifically, do not only check for the
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 872b8e85f56..7c155c7684e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -126,7 +126,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
             let placeholder_trait_predicate =
-                self.infcx().replace_bound_vars_with_placeholders(&trait_predicate);
+                self.infcx().replace_bound_vars_with_placeholders(trait_predicate);
             let placeholder_self_ty = placeholder_trait_predicate.self_ty();
             let (def_id, substs) = match *placeholder_self_ty.kind() {
                 ty::Projection(proj) => (proj.item_def_id, proj.substs),
@@ -144,7 +144,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
-                &candidate,
+                candidate,
                 &mut obligations,
             );
 
@@ -163,7 +163,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         obligation.param_env,
                         obligation.cause.clone(),
                         obligation.recursion_depth + 1,
-                        &predicate,
+                        predicate,
                         &mut obligations,
                     );
                     obligations.push(Obligation::with_depth(
@@ -285,8 +285,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             let trait_obligations: Vec<PredicateObligation<'_>> =
                 self.infcx.commit_unconditionally(|_| {
                     let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
-                    let trait_ref =
-                        self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref);
+                    let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
                     let cause = obligation.derived_cause(ImplDerivedObligation);
                     self.impl_or_trait_obligations(
                         cause,
@@ -370,11 +369,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let tcx = self.tcx();
         debug!(?obligation, ?index, "confirm_object_candidate");
 
-        let trait_predicate =
-            self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
+        let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate);
         let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
         let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
-        let data = match self_ty.kind() {
+        let data = match *self_ty.kind() {
             ty::Dynamic(data, ..) => {
                 self.infcx
                     .replace_bound_vars_with_fresh_vars(
@@ -416,7 +414,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             obligation.param_env,
             obligation.cause.clone(),
             obligation.recursion_depth + 1,
-            &unnormalized_upcast_trait_ref,
+            unnormalized_upcast_trait_ref,
             &mut nested,
         );
 
@@ -442,7 +440,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    &super_trait,
+                    super_trait,
                     &mut nested,
                 );
                 nested.push(Obligation::new(
@@ -480,7 +478,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    &subst_bound,
+                    subst_bound,
                     &mut nested,
                 );
                 nested.push(Obligation::new(
@@ -520,7 +518,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
-                &trait_ref,
+                trait_ref,
             )
         });
 
@@ -541,8 +539,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate");
 
         self.infcx.commit_unconditionally(|_| {
-            let predicate =
-                self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
+            let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
             let trait_ref = predicate.trait_ref;
             let trait_def_id = trait_ref.def_id;
             let substs = trait_ref.substs;
@@ -584,7 +581,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
-                &trait_ref,
+                trait_ref,
             )
         });
 
@@ -627,7 +624,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
-                &trait_ref,
+                trait_ref,
             )
         });
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index a91f693f175..05ff9a6fb9c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1019,7 +1019,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         let obligation = &stack.obligation;
-        let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
+        let predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
 
         // Okay to skip binder because of the nature of the
         // trait-ref-is-knowable check, which does not care about
@@ -1138,9 +1138,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> smallvec::SmallVec<[usize; 2]> {
-        let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
+        let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
         let placeholder_trait_predicate =
-            self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
+            self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
         debug!(
             ?placeholder_trait_predicate,
             "match_projection_obligation_against_definition_bounds"
@@ -1220,7 +1220,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
-                &trait_bound,
+                trait_bound,
             )
         });
         self.infcx
@@ -1266,12 +1266,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    &data.map_bound_ref(|data| data.projection_ty),
+                    data.map_bound(|data| data.projection_ty),
                     &mut nested_obligations,
                 )
             })
         } else {
-            data.map_bound_ref(|data| data.projection_ty)
+            data.map_bound(|data| data.projection_ty)
         };
 
         // FIXME(generic_associated_types): Compare the whole projections
@@ -1737,7 +1737,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
 
                 self.infcx.commit_unconditionally(|_| {
-                    let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(&ty);
+                    let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
                     let Normalized { value: normalized_ty, mut obligations } =
                         ensure_sufficient_stack(|| {
                             project::normalize_with_depth(
@@ -1745,7 +1745,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 param_env,
                                 cause.clone(),
                                 recursion_depth,
-                                &placeholder_ty,
+                                placeholder_ty,
                             )
                         });
                     let placeholder_obligation = predicate_for_trait_def(
@@ -1807,7 +1807,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         let placeholder_obligation =
-            self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
+            self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
         let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
 
         let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
@@ -1821,7 +1821,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    &impl_trait_ref,
+                    impl_trait_ref,
                 )
             });
 
@@ -2028,7 +2028,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 param_env,
                 cause.clone(),
                 recursion_depth,
-                &predicate.subst(tcx, substs),
+                predicate.subst(tcx, substs),
                 &mut obligations,
             );
             obligations.push(Obligation {
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 4d81a3baa0e..512591960f5 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -158,7 +158,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
             FulfillmentContext::new(),
             ObligationCause::dummy(),
             penv,
-            &impl1_trait_ref,
+            impl1_trait_ref,
         ) {
             Ok(impl1_trait_ref) => impl1_trait_ref,
             Err(err) => {
@@ -247,7 +247,7 @@ fn fulfill_implication<'a, 'tcx>(
 
                 // Now resolve the *substitution* we built for the target earlier, replacing
                 // the inference variables inside with whatever we got from fulfillment.
-                Ok(infcx.resolve_vars_if_possible(&target_substs))
+                Ok(infcx.resolve_vars_if_possible(target_substs))
             }
         }
     })
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index ce0d3ef8a6a..3d20a8d5cf3 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -55,9 +55,7 @@ pub fn search_for_structural_match_violation<'tcx>(
 ) -> Option<NonStructuralMatchTy<'tcx>> {
     // FIXME: we should instead pass in an `infcx` from the outside.
     tcx.infer_ctxt().enter(|infcx| {
-        let mut search = Search { infcx, span, found: None, seen: FxHashSet::default() };
-        ty.visit_with(&mut search);
-        search.found
+        ty.visit_with(&mut Search { infcx, span, seen: FxHashSet::default() }).break_value()
     })
 }
 
@@ -116,9 +114,6 @@ struct Search<'a, 'tcx> {
 
     infcx: InferCtxt<'a, 'tcx>,
 
-    /// Records first ADT that does not implement a structural-match trait.
-    found: Option<NonStructuralMatchTy<'tcx>>,
-
     /// Tracks ADTs previously encountered during search, so that
     /// we will not recur on them again.
     seen: FxHashSet<hir::def_id::DefId>,
@@ -135,38 +130,33 @@ impl Search<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+    type BreakTy = NonStructuralMatchTy<'tcx>;
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!("Search visiting ty: {:?}", ty);
 
         let (adt_def, substs) = match *ty.kind() {
             ty::Adt(adt_def, substs) => (adt_def, substs),
             ty::Param(_) => {
-                self.found = Some(NonStructuralMatchTy::Param);
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(NonStructuralMatchTy::Param);
             }
             ty::Dynamic(..) => {
-                self.found = Some(NonStructuralMatchTy::Dynamic);
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(NonStructuralMatchTy::Dynamic);
             }
             ty::Foreign(_) => {
-                self.found = Some(NonStructuralMatchTy::Foreign);
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(NonStructuralMatchTy::Foreign);
             }
             ty::Opaque(..) => {
-                self.found = Some(NonStructuralMatchTy::Opaque);
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(NonStructuralMatchTy::Opaque);
             }
             ty::Projection(..) => {
-                self.found = Some(NonStructuralMatchTy::Projection);
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(NonStructuralMatchTy::Projection);
             }
             ty::Generator(..) | ty::GeneratorWitness(..) => {
-                self.found = Some(NonStructuralMatchTy::Generator);
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(NonStructuralMatchTy::Generator);
             }
             ty::Closure(..) => {
-                self.found = Some(NonStructuralMatchTy::Closure);
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(NonStructuralMatchTy::Closure);
             }
             ty::RawPtr(..) => {
                 // structural-match ignores substructure of
@@ -206,8 +196,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
 
             ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
                 // First check all contained types and then tell the caller to continue searching.
-                ty.super_visit_with(self);
-                return ControlFlow::CONTINUE;
+                return ty.super_visit_with(self);
             }
             ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
                 bug!("unexpected type during structural-match checking: {:?}", ty);
@@ -227,8 +216,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
 
         if !self.type_marked_structural(ty) {
             debug!("Search found ty: {:?}", ty);
-            self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
-            return ControlFlow::BREAK;
+            return ControlFlow::Break(NonStructuralMatchTy::Adt(&adt_def));
         }
 
         // structural-match does not care about the
@@ -244,20 +232,11 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
         // even though we skip super_visit_with, we must recur on
         // fields of ADT.
         let tcx = self.tcx();
-        for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
+        adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| {
             let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty);
             debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty);
-
-            if ty.visit_with(self).is_break() {
-                // found an ADT without structural-match; halt visiting!
-                assert!(self.found.is_some());
-                return ControlFlow::BREAK;
-            }
-        }
-
-        // Even though we do not want to recur on substs, we do
-        // want our caller to continue its own search.
-        ControlFlow::CONTINUE
+            ty.visit_with(self)
+        })
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index f626bb0b7e3..2430620323f 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -205,12 +205,12 @@ pub fn impl_trait_ref_and_oblig<'a, 'tcx>(
     let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap();
     let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs);
     let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
-        super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref);
+        super::normalize(selcx, param_env, ObligationCause::dummy(), impl_trait_ref);
 
     let predicates = selcx.tcx().predicates_of(impl_def_id);
     let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
     let Normalized { value: predicates, obligations: normalization_obligations2 } =
-        super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates);
+        super::normalize(selcx, param_env, ObligationCause::dummy(), predicates);
     let impl_obligations =
         predicates_for_generics(ObligationCause::dummy(), 0, param_env, predicates);
 
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 496dff6c5b2..e5a792f229d 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -269,7 +269,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                 param_env,
                 cause.clone(),
                 self.recursion_depth,
-                &obligation.predicate,
+                obligation.predicate,
                 &mut obligations,
             );
             obligation.predicate = normalized_predicate;
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index c5a46b1003d..b1b9ef343d5 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -227,7 +227,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars(
             &self.interner,
             self.interner.tcx,
-            &sig.inputs_and_output().subst(self.interner.tcx, bound_vars),
+            sig.inputs_and_output().subst(self.interner.tcx, bound_vars),
         );
 
         let argument_types = inputs_and_output[..inputs_and_output.len() - 1]
@@ -461,7 +461,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
     ) -> Arc<chalk_solve::rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> {
         let bound_vars = ty::fold::shift_vars(
             self.interner.tcx,
-            &bound_vars_for_item(self.interner.tcx, opaque_ty_id.0),
+            bound_vars_for_item(self.interner.tcx, opaque_ty_id.0),
             1,
         );
         let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars);
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index c4e2c7f839d..9afb980f84d 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -86,7 +86,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
             let (predicate, binders, _named_regions) = collect_bound_vars(
                 interner,
                 interner.tcx,
-                &predicate.bound_atom_with_opt_escaping(interner.tcx),
+                predicate.bound_atom_with_opt_escaping(interner.tcx),
             );
             let consequence = match predicate {
                 ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
@@ -141,7 +141,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
         let (predicate, binders, _named_regions) = collect_bound_vars(
             interner,
             interner.tcx,
-            &self.bound_atom_with_opt_escaping(interner.tcx),
+            self.bound_atom_with_opt_escaping(interner.tcx),
         );
 
         let value = match predicate {
@@ -293,7 +293,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
             }
             ty::FnPtr(sig) => {
                 let (inputs_and_outputs, binders, _named_regions) =
-                    collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output());
+                    collect_bound_vars(interner, interner.tcx, sig.inputs_and_output());
                 chalk_ir::TyKind::Function(chalk_ir::FnPointer {
                     num_binders: binders.len(interner),
                     sig: sig.lower_into(interner),
@@ -578,7 +578,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
         let (predicate, binders, _named_regions) = collect_bound_vars(
             interner,
             interner.tcx,
-            &self.bound_atom_with_opt_escaping(interner.tcx),
+            self.bound_atom_with_opt_escaping(interner.tcx),
         );
         let value = match predicate {
             ty::PredicateAtom::Trait(predicate, _) => {
@@ -627,10 +627,10 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
         // Binders<&[Binders<WhereClause<I>>]>
         // This means that any variables that are escaping `self` need to be
         // shifted in by one so that they are still escaping.
-        let shifted_predicates = ty::fold::shift_vars(interner.tcx, &self, 1);
+        let shifted_predicates = ty::fold::shift_vars(interner.tcx, self, 1);
 
         let (predicates, binders, _named_regions) =
-            collect_bound_vars(interner, interner.tcx, &shifted_predicates);
+            collect_bound_vars(interner, interner.tcx, shifted_predicates);
         let self_ty = interner.tcx.mk_ty(ty::Bound(
             // This is going to be wrapped in a binder
             ty::DebruijnIndex::from_usize(1),
@@ -707,7 +707,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
         let (predicate, binders, _named_regions) = collect_bound_vars(
             interner,
             interner.tcx,
-            &self.bound_atom_with_opt_escaping(interner.tcx),
+            self.bound_atom_with_opt_escaping(interner.tcx),
         );
         match predicate {
             ty::PredicateAtom::Trait(predicate, _) => Some(chalk_ir::Binders::new(
@@ -808,10 +808,10 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
 /// It's important to note that because of prior substitution, we may have
 /// late-bound regions, even outside of fn contexts, since this is the best way
 /// to prep types for chalk lowering.
-crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>(
+crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>(
     interner: &RustInterner<'tcx>,
     tcx: TyCtxt<'tcx>,
-    ty: &'a Binder<T>,
+    ty: Binder<T>,
 ) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
     let mut bound_vars_collector = BoundVarsCollector::new();
     ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector);
@@ -824,7 +824,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>(
         .collect();
 
     let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters);
-    let new_ty = ty.as_ref().skip_binder().fold_with(&mut bound_var_substitutor);
+    let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor);
 
     for var in named_parameters.values() {
         parameters.insert(*var, chalk_ir::VariableKind::Lifetime);
@@ -833,7 +833,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>(
     (0..parameters.len()).for_each(|i| {
         parameters
             .get(&(i as u32))
-            .or_else(|| bug!("Skipped bound var index: ty={:?}, parameters={:?}", ty, parameters));
+            .or_else(|| bug!("Skipped bound var index: parameters={:?}", parameters));
     });
 
     let binders =
@@ -859,14 +859,14 @@ impl<'tcx> BoundVarsCollector<'tcx> {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> {
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> {
         self.binder_index.shift_in(1);
         let result = t.super_visit_with(self);
         self.binder_index.shift_out(1);
         result
     }
 
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *t.kind() {
             ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
                 match self.parameters.entry(bound_ty.var.as_u32()) {
@@ -886,7 +886,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
         t.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> {
+    fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         match r {
             ty::ReLateBound(index, br) if *index == self.binder_index => match br {
                 ty::BoundRegion::BrNamed(def_id, _name) => {
@@ -941,7 +941,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> Binder<T> {
+    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<T>) -> Binder<T> {
         self.binder_index.shift_in(1);
         let result = t.super_fold_with(self);
         self.binder_index.shift_out(1);
@@ -1001,7 +1001,7 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> Binder<T> {
+    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<T>) -> Binder<T> {
         self.binder_index.shift_in(1);
         let result = t.super_fold_with(self);
         self.binder_index.shift_out(1);
@@ -1076,7 +1076,7 @@ impl PlaceholdersCollector {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
             ty::Placeholder(p) if p.universe == self.universe_index => {
                 self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1);
@@ -1088,7 +1088,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
         t.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> {
+    fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         match r {
             ty::RePlaceholder(p) if p.universe == self.universe_index => {
                 if let ty::BoundRegion::BrAnon(anon) = p.name {
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 6cffa6d02a4..2827163d854 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -106,7 +106,7 @@ fn dropck_outlives<'tcx>(
                 // do not themselves define a destructor", more or less. We have
                 // to push them onto the stack to be expanded.
                 for ty in constraints.dtorck_types.drain(..) {
-                    match infcx.at(&cause, param_env).normalize(&ty) {
+                    match infcx.at(&cause, param_env).normalize(ty) {
                         Ok(Normalized { value: ty, obligations }) => {
                             fulfill_cx.register_predicate_obligations(infcx, obligations);
 
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index c44fd1d5859..97017fbf2e5 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -115,7 +115,7 @@ fn compute_implied_outlives_bounds<'tcx>(
                     }
 
                     ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
-                        let ty_a = infcx.resolve_vars_if_possible(&ty_a);
+                        let ty_a = infcx.resolve_vars_if_possible(ty_a);
                         let mut components = smallvec![];
                         tcx.push_outlives_components(ty_a, &mut components);
                         implied_bounds_from_components(r_b, components)
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 3e7c9ac62eb..750a0922be4 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -21,7 +21,7 @@ fn normalize_generic_arg_after_erasing_regions<'tcx>(
     tcx.sess.perf_stats.normalize_generic_arg_after_erasing_regions.fetch_add(1, Ordering::Relaxed);
     tcx.infer_ctxt().enter(|infcx| {
         let cause = ObligationCause::dummy();
-        match infcx.at(&cause, param_env).normalize(&value) {
+        match infcx.at(&cause, param_env).normalize(value) {
             Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
                 // We don't care about the `obligations`; they are
                 // always only region relations, and we are about to
@@ -31,8 +31,8 @@ fn normalize_generic_arg_after_erasing_regions<'tcx>(
                     None,
                 );
 
-                let normalized_value = infcx.resolve_vars_if_possible(&normalized_value);
-                infcx.tcx.erase_regions(&normalized_value)
+                let normalized_value = infcx.resolve_vars_if_possible(normalized_value);
+                infcx.tcx.erase_regions(normalized_value)
             }
             Err(NoSolution) => bug!("could not fully normalize `{:?}`", value),
         }
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 139ed6dcd35..0addde5c44c 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -70,7 +70,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
                 DUMMY_SP,
                 hir::CRATE_HIR_ID,
                 self.param_env,
-                &value,
+                value,
             )
             .into_value_registering_obligations(self.infcx, self.fulfill_cx)
     }
@@ -184,7 +184,7 @@ where
 {
     let (param_env, Normalize { value }) = key.into_parts();
     let Normalized { value, obligations } =
-        infcx.at(&ObligationCause::dummy(), param_env).normalize(&value)?;
+        infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?;
     fulfill_cx.register_predicate_obligations(infcx, obligations);
     Ok(value)
 }
diff --git a/compiler/rustc_ty/src/instance.rs b/compiler/rustc_ty/src/instance.rs
index 220f4cec742..cf2c6efb471 100644
--- a/compiler/rustc_ty/src/instance.rs
+++ b/compiler/rustc_ty/src/instance.rs
@@ -51,7 +51,7 @@ fn inner_resolve_instance<'tcx>(
         resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
     } else {
         let ty = tcx.type_of(def.def_id_for_type_of());
-        let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty);
+        let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
 
         let def = match *item_type.kind() {
             ty::FnDef(..)
@@ -146,7 +146,7 @@ fn resolve_associated_item<'tcx>(
                     substs,
                     leaf_def.defining_node,
                 );
-                infcx.tcx.erase_regions(&substs)
+                infcx.tcx.erase_regions(substs)
             });
 
             // Since this is a trait item, we need to see if the item is either a trait default item
@@ -172,7 +172,7 @@ fn resolve_associated_item<'tcx>(
                 return Ok(None);
             }
 
-            let substs = tcx.erase_regions(&substs);
+            let substs = tcx.erase_regions(substs);
 
             // Check if we just resolved an associated `const` declaration from
             // a `trait` to an associated `const` definition in an `impl`, where
@@ -192,7 +192,7 @@ fn resolve_associated_item<'tcx>(
                 && leaf_def.item.def_id.is_local()
             {
                 let normalized_type_of = |def_id, substs| {
-                    tcx.subst_and_normalize_erasing_regions(substs, param_env, &tcx.type_of(def_id))
+                    tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
                 };
 
                 let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs);
@@ -264,7 +264,7 @@ fn resolve_associated_item<'tcx>(
                     assert_eq!(name, sym::clone_from);
 
                     // Use the default `fn clone_from` from `trait Clone`.
-                    let substs = tcx.erase_regions(&rcvr_substs);
+                    let substs = tcx.erase_regions(rcvr_substs);
                     Some(ty::Instance::new(def_id, substs))
                 }
             } else {
diff --git a/compiler/rustc_ty/src/needs_drop.rs b/compiler/rustc_ty/src/needs_drop.rs
index 0356bcec549..d62fc764c76 100644
--- a/compiler/rustc_ty/src/needs_drop.rs
+++ b/compiler/rustc_ty/src/needs_drop.rs
@@ -107,7 +107,7 @@ where
 
                         let witness = substs.witness();
                         let interior_tys = match witness.kind() {
-                            ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys),
+                            &ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys),
                             _ => {
                                 tcx.sess.delay_span_bug(
                                     tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP),
diff --git a/compiler/rustc_ty/src/ty.rs b/compiler/rustc_ty/src/ty.rs
index 2562140bb5d..720ad42da2a 100644
--- a/compiler/rustc_ty/src/ty.rs
+++ b/compiler/rustc_ty/src/ty.rs
@@ -363,7 +363,7 @@ fn well_formed_types_in_env<'tcx>(
         // well-formed.
         NodeKind::Fn => {
             let fn_sig = tcx.fn_sig(def_id);
-            let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig);
+            let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig);
 
             inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
         }
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 3bfb2d3f1b0..0db5fda272a 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -1,12 +1,13 @@
 use crate::astconv::{
-    AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
+    AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
+    GenericArgCountResult, GenericArgPosition,
 };
 use crate::errors::AssocTypeBindingNotAllowed;
 use rustc_ast::ast::ParamKindOrd;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{GenericArg, GenericArgs};
+use rustc_hir::GenericArg;
 use rustc_middle::ty::{
     self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
 };
@@ -22,6 +23,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         sess: &Session,
         arg: &GenericArg<'_>,
         kind: &'static str,
+        possible_ordering_error: bool,
         help: Option<&str>,
     ) {
         let mut err = struct_span_err!(
@@ -48,8 +50,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             GenericArg::Const(_) => ParamKindOrd::Const { unordered },
         };
 
+        if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }))
+            && matches!(kind_ord, ParamKindOrd::Const { .. })
+        {
+            let suggestions = vec![
+                (arg.span().shrink_to_lo(), String::from("{ ")),
+                (arg.span().shrink_to_hi(), String::from(" }")),
+            ];
+            err.multipart_suggestion(
+                "if this generic argument was intended as a const parameter, \
+                try surrounding it with braces:",
+                suggestions,
+                Applicability::MaybeIncorrect,
+            );
+        }
+
         // This note is only true when generic parameters are strictly ordered by their kind.
-        if kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
+        if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
             let (first, last) =
                 if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
             err.note(&format!("{} arguments must be provided before {} arguments", first, last));
@@ -90,20 +107,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     ///   instantiate a `GenericArg`.
     /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
     ///   creates a suitable inference variable.
-    pub fn create_substs_for_generic_args<'b>(
+    pub fn create_substs_for_generic_args<'a>(
         tcx: TyCtxt<'tcx>,
         def_id: DefId,
         parent_substs: &[subst::GenericArg<'tcx>],
         has_self: bool,
         self_ty: Option<Ty<'tcx>>,
         arg_count: GenericArgCountResult,
-        args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool),
-        mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>,
-        mut inferred_kind: impl FnMut(
-            Option<&[subst::GenericArg<'tcx>]>,
-            &GenericParamDef,
-            bool,
-        ) -> subst::GenericArg<'tcx>,
+        ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
     ) -> SubstsRef<'tcx> {
         // Collect the segments of the path; we need to substitute arguments
         // for parameters throughout the entire path (wherever there are
@@ -142,7 +153,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             substs.push(
                                 self_ty
                                     .map(|ty| ty.into())
-                                    .unwrap_or_else(|| inferred_kind(None, param, true)),
+                                    .unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
                             );
                             params.next();
                         }
@@ -151,10 +162,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
 
             // Check whether this segment takes generic arguments and the user has provided any.
-            let (generic_args, infer_args) = args_for_def_id(def_id);
+            let (generic_args, infer_args) = ctx.args_for_def_id(def_id);
 
-            let mut args =
-                generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable();
+            let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter());
+            let mut args = args_iter.clone().peekable();
 
             // If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
             // If we later encounter a lifetime, we know that the arguments were provided in the
@@ -173,7 +184,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
                             | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _)
                             | (GenericArg::Const(_), GenericParamDefKind::Const, _) => {
-                                substs.push(provided_kind(param, arg));
+                                substs.push(ctx.provided_kind(param, arg));
                                 args.next();
                                 params.next();
                             }
@@ -184,7 +195,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             ) => {
                                 // We expected a lifetime argument, but got a type or const
                                 // argument. That means we're inferring the lifetimes.
-                                substs.push(inferred_kind(None, param, infer_args));
+                                substs.push(ctx.inferred_kind(None, param, infer_args));
                                 force_infer_lt = Some(arg);
                                 params.next();
                             }
@@ -221,8 +232,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                                     GenericParamDefKind::Const => {
                                                         ParamKindOrd::Const {
                                                             unordered: tcx
-                                                                .sess
-                                                                .features_untracked()
+                                                                .features()
                                                                 .const_generics,
                                                         }
                                                     }
@@ -242,6 +252,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                         tcx.sess,
                                         arg,
                                         kind.descr(),
+                                        !args_iter.clone().is_sorted_by_key(|arg| match arg {
+                                            GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
+                                            GenericArg::Type(_) => ParamKindOrd::Type,
+                                            GenericArg::Const(_) => ParamKindOrd::Const {
+                                                unordered: tcx.features().const_generics,
+                                            },
+                                        }),
                                         Some(&format!(
                                             "reorder the arguments: {}: `<{}>`",
                                             param_types_present
@@ -293,7 +310,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             assert_eq!(kind, "lifetime");
                             let provided =
                                 force_infer_lt.expect("lifetimes ought to have been inferred");
-                            Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None);
+                            Self::generic_arg_mismatch_err(tcx.sess, provided, kind, false, None);
                         }
 
                         break;
@@ -302,7 +319,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     (None, Some(&param)) => {
                         // If there are fewer arguments than parameters, it means
                         // we're inferring the remaining arguments.
-                        substs.push(inferred_kind(Some(&substs), param, infer_args));
+                        substs.push(ctx.inferred_kind(Some(&substs), param, infer_args));
                         params.next();
                     }
 
@@ -351,6 +368,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // that lifetimes will proceed types. So it suffices to check the number of each generic
         // arguments in order to validate them with respect to the generic parameters.
         let param_counts = def.own_counts();
+        let named_type_param_count = param_counts.types - has_self as usize;
         let arg_counts = args.own_counts();
         let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0;
 
@@ -389,11 +407,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             // For kinds without defaults (e.g.., lifetimes), `required == permitted`.
             // For other kinds (i.e., types), `permitted` may be greater than `required`.
             if required <= provided && provided <= permitted {
-                return Ok(());
+                return true;
             }
 
             if silent {
-                return Err((0i32, None));
+                return false;
             }
 
             // Unfortunately lifetime and type parameter mismatches are typically styled
@@ -409,25 +427,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 (required, "")
             };
 
-            let (spans, label) = if required == permitted && provided > permitted {
+            let (spans, labels) = if provided > permitted {
                 // In the case when the user has provided too many arguments,
                 // we want to point to the unexpected arguments.
-                let spans: Vec<Span> = args.args[offset + permitted..offset + provided]
+                let (spans, labels): (Vec<Span>, Vec<String>) = args.args
+                    [offset + permitted..offset + provided]
                     .iter()
-                    .map(|arg| arg.span())
-                    .collect();
+                    .map(|arg| (arg.span(), format!("unexpected {} argument", arg.short_descr())))
+                    .unzip();
                 unexpected_spans.extend(spans.clone());
-                (spans, format!("unexpected {} argument", kind))
+                (spans, labels)
             } else {
                 (
                     vec![span],
-                    format!(
+                    vec![format!(
                         "expected {}{} {} argument{}",
                         quantifier,
                         bound,
                         kind,
                         pluralize!(bound),
-                    ),
+                    )],
                 )
             };
 
@@ -439,105 +458,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 ),
                 DiagnosticId::Error("E0107".into()),
             );
-            for span in spans {
+            for (span, label) in spans.into_iter().zip(labels) {
                 err.span_label(span, label.as_str());
             }
-
-            assert_ne!(bound, provided);
-            Err((bound as i32 - provided as i32, Some(err)))
+            err.emit();
+            false
         };
 
         let mut unexpected_spans = vec![];
 
-        let mut lifetime_count_correct = Ok(());
-        if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes {
-            lifetime_count_correct = check_kind_count(
-                "lifetime",
-                param_counts.lifetimes,
-                param_counts.lifetimes,
-                arg_counts.lifetimes,
-                0,
-                &mut unexpected_spans,
-                explicit_late_bound == ExplicitLateBound::Yes,
-            );
-        }
-
-        // FIXME(const_generics:defaults)
-        let mut const_count_correct = Ok(());
-        if !infer_args || arg_counts.consts > param_counts.consts {
-            const_count_correct = check_kind_count(
-                "const",
-                param_counts.consts,
-                param_counts.consts,
-                arg_counts.consts,
-                arg_counts.lifetimes + arg_counts.types,
-                &mut unexpected_spans,
-                false,
-            );
-        }
-
-        // Note that type errors are currently be emitted *after* const errors.
-        let mut type_count_correct = Ok(());
-        if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize
-        {
-            type_count_correct = check_kind_count(
-                "type",
-                param_counts.types - defaults.types - has_self as usize,
-                param_counts.types - has_self as usize,
-                arg_counts.types,
-                arg_counts.lifetimes,
-                &mut unexpected_spans,
-                false,
-            );
-        }
-
-        // Emit a help message if it's possible that a type could be surrounded in braces
-        if let Err((c_mismatch, Some(ref mut _const_err))) = const_count_correct {
-            if let Err((_, Some(ref mut type_err))) = type_count_correct {
-                let possible_matches = args.args[arg_counts.lifetimes..]
-                    .iter()
-                    .filter(|arg| {
-                        matches!(
-                            arg,
-                            GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. })
-                        )
-                    })
-                    .take(c_mismatch.max(0) as usize);
-                for arg in possible_matches {
-                    let suggestions = vec![
-                        (arg.span().shrink_to_lo(), String::from("{ ")),
-                        (arg.span().shrink_to_hi(), String::from(" }")),
-                    ];
-                    type_err.multipart_suggestion(
-                        "If this generic argument was intended as a const parameter, \
-                        try surrounding it with braces:",
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-        }
+        let lifetime_count_correct = check_kind_count(
+            "lifetime",
+            if infer_lifetimes { 0 } else { param_counts.lifetimes },
+            param_counts.lifetimes,
+            arg_counts.lifetimes,
+            0,
+            &mut unexpected_spans,
+            explicit_late_bound == ExplicitLateBound::Yes,
+        );
 
-        let emit_correct =
-            |correct: Result<(), (_, Option<rustc_errors::DiagnosticBuilder<'_>>)>| match correct {
-                Ok(()) => Ok(()),
-                Err((_, None)) => Err(()),
-                Err((_, Some(mut err))) => {
-                    err.emit();
-                    Err(())
-                }
-            };
+        let kind_str = if param_counts.consts + arg_counts.consts == 0 {
+            "type"
+        } else if named_type_param_count + arg_counts.types == 0 {
+            "const"
+        } else {
+            "generic"
+        };
 
-        let arg_count_correct = emit_correct(lifetime_count_correct)
-            .and(emit_correct(const_count_correct))
-            .and(emit_correct(type_count_correct));
+        let arg_count_correct = check_kind_count(
+            kind_str,
+            if infer_args {
+                0
+            } else {
+                param_counts.consts + named_type_param_count - defaults.types
+            },
+            param_counts.consts + named_type_param_count,
+            arg_counts.consts + arg_counts.types,
+            arg_counts.lifetimes,
+            &mut unexpected_spans,
+            false,
+        );
 
         GenericArgCountResult {
             explicit_late_bound,
-            correct: arg_count_correct.map_err(|()| GenericArgCountMismatch {
-                reported: Some(ErrorReported),
-                invalid_args: unexpected_spans,
-            }),
+            correct: if lifetime_count_correct && arg_count_correct {
+                Ok(())
+            } else {
+                Err(GenericArgCountMismatch {
+                    reported: Some(ErrorReported),
+                    invalid_args: unexpected_spans,
+                })
+            },
         }
     }
 
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 07e523af3eb..89c5adfa14c 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -165,6 +165,23 @@ pub struct GenericArgCountResult {
     pub correct: Result<(), GenericArgCountMismatch>,
 }
 
+pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> {
+    fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'a>>, bool);
+
+    fn provided_kind(
+        &mut self,
+        param: &ty::GenericParamDef,
+        arg: &GenericArg<'_>,
+    ) -> subst::GenericArg<'tcx>;
+
+    fn inferred_kind(
+        &mut self,
+        substs: Option<&[subst::GenericArg<'tcx>]>,
+        param: &ty::GenericParamDef,
+        infer_args: bool,
+    ) -> subst::GenericArg<'tcx>;
+}
+
 impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     pub fn ast_region_to_region(
         &self,
@@ -321,81 +338,102 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         );
 
         let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self);
-        let default_needs_object_self = |param: &ty::GenericParamDef| {
-            if let GenericParamDefKind::Type { has_default, .. } = param.kind {
-                if is_object && has_default {
-                    let default_ty = tcx.at(span).type_of(param.def_id);
-                    let self_param = tcx.types.self_param;
-                    if default_ty.walk().any(|arg| arg == self_param.into()) {
-                        // There is no suitable inference default for a type parameter
-                        // that references self, in an object type.
-                        return true;
+
+        struct SubstsForAstPathCtxt<'a, 'tcx> {
+            astconv: &'a (dyn AstConv<'tcx> + 'a),
+            def_id: DefId,
+            generic_args: &'a GenericArgs<'a>,
+            span: Span,
+            missing_type_params: Vec<String>,
+            inferred_params: Vec<Span>,
+            infer_args: bool,
+            is_object: bool,
+        }
+
+        impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> {
+            fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool {
+                let tcx = self.astconv.tcx();
+                if let GenericParamDefKind::Type { has_default, .. } = param.kind {
+                    if self.is_object && has_default {
+                        let default_ty = tcx.at(self.span).type_of(param.def_id);
+                        let self_param = tcx.types.self_param;
+                        if default_ty.walk().any(|arg| arg == self_param.into()) {
+                            // There is no suitable inference default for a type parameter
+                            // that references self, in an object type.
+                            return true;
+                        }
                     }
                 }
-            }
 
-            false
-        };
+                false
+            }
+        }
 
-        let mut missing_type_params = vec![];
-        let mut inferred_params = vec![];
-        let substs = Self::create_substs_for_generic_args(
-            tcx,
-            def_id,
-            parent_substs,
-            self_ty.is_some(),
-            self_ty,
-            arg_count.clone(),
-            // Provide the generic args, and whether types should be inferred.
-            |did| {
-                if did == def_id {
-                    (Some(generic_args), infer_args)
+        impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
+            fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) {
+                if did == self.def_id {
+                    (Some(self.generic_args), self.infer_args)
                 } else {
                     // The last component of this tuple is unimportant.
                     (None, false)
                 }
-            },
-            // Provide substitutions for parameters for which (valid) arguments have been provided.
-            |param, arg| match (&param.kind, arg) {
-                (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                    self.ast_region_to_region(&lt, Some(param)).into()
-                }
-                (GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
-                    if *has_default {
-                        tcx.check_optional_stability(
-                            param.def_id,
-                            Some(arg.id()),
-                            arg.span(),
-                            |_, _| {
-                                // Default generic parameters may not be marked
-                                // with stability attributes, i.e. when the
-                                // default parameter was defined at the same time
-                                // as the rest of the type. As such, we ignore missing
-                                // stability attributes.
+            }
+
+            fn provided_kind(
+                &mut self,
+                param: &ty::GenericParamDef,
+                arg: &GenericArg<'_>,
+            ) -> subst::GenericArg<'tcx> {
+                let tcx = self.astconv.tcx();
+                match (&param.kind, arg) {
+                    (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
+                        self.astconv.ast_region_to_region(&lt, Some(param)).into()
+                    }
+                    (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
+                        if has_default {
+                            tcx.check_optional_stability(
+                                param.def_id,
+                                Some(arg.id()),
+                                arg.span(),
+                                |_, _| {
+                                    // Default generic parameters may not be marked
+                                    // with stability attributes, i.e. when the
+                                    // default parameter was defined at the same time
+                                    // as the rest of the type. As such, we ignore missing
+                                    // stability attributes.
+                                },
+                            )
+                        }
+                        if let (hir::TyKind::Infer, false) =
+                            (&ty.kind, self.astconv.allow_ty_infer())
+                        {
+                            self.inferred_params.push(ty.span);
+                            tcx.ty_error().into()
+                        } else {
+                            self.astconv.ast_ty_to_ty(&ty).into()
+                        }
+                    }
+                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
+                        ty::Const::from_opt_const_arg_anon_const(
+                            tcx,
+                            ty::WithOptConstParam {
+                                did: tcx.hir().local_def_id(ct.value.hir_id),
+                                const_param_did: Some(param.def_id),
                             },
                         )
+                        .into()
                     }
-                    if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) {
-                        inferred_params.push(ty.span);
-                        tcx.ty_error().into()
-                    } else {
-                        self.ast_ty_to_ty(&ty).into()
-                    }
-                }
-                (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                    ty::Const::from_opt_const_arg_anon_const(
-                        tcx,
-                        ty::WithOptConstParam {
-                            did: tcx.hir().local_def_id(ct.value.hir_id),
-                            const_param_did: Some(param.def_id),
-                        },
-                    )
-                    .into()
+                    _ => unreachable!(),
                 }
-                _ => unreachable!(),
-            },
-            // Provide substitutions for parameters for which arguments are inferred.
-            |substs, param, infer_args| {
+            }
+
+            fn inferred_kind(
+                &mut self,
+                substs: Option<&[subst::GenericArg<'tcx>]>,
+                param: &ty::GenericParamDef,
+                infer_args: bool,
+            ) -> subst::GenericArg<'tcx> {
+                let tcx = self.astconv.tcx();
                 match param.kind {
                     GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
                     GenericParamDefKind::Type { has_default, .. } => {
@@ -407,48 +445,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             // other type parameters may reference `Self` in their
                             // defaults. This will lead to an ICE if we are not
                             // careful!
-                            if default_needs_object_self(param) {
-                                missing_type_params.push(param.name.to_string());
+                            if self.default_needs_object_self(param) {
+                                self.missing_type_params.push(param.name.to_string());
                                 tcx.ty_error().into()
                             } else {
                                 // This is a default type parameter.
-                                self.normalize_ty(
-                                    span,
-                                    tcx.at(span).type_of(param.def_id).subst_spanned(
-                                        tcx,
-                                        substs.unwrap(),
-                                        Some(span),
-                                    ),
-                                )
-                                .into()
+                                self.astconv
+                                    .normalize_ty(
+                                        self.span,
+                                        tcx.at(self.span).type_of(param.def_id).subst_spanned(
+                                            tcx,
+                                            substs.unwrap(),
+                                            Some(self.span),
+                                        ),
+                                    )
+                                    .into()
                             }
                         } else if infer_args {
                             // No type parameters were provided, we can infer all.
-                            let param =
-                                if !default_needs_object_self(param) { Some(param) } else { None };
-                            self.ty_infer(param, span).into()
+                            let param = if !self.default_needs_object_self(param) {
+                                Some(param)
+                            } else {
+                                None
+                            };
+                            self.astconv.ty_infer(param, self.span).into()
                         } else {
                             // We've already errored above about the mismatch.
                             tcx.ty_error().into()
                         }
                     }
                     GenericParamDefKind::Const => {
-                        let ty = tcx.at(span).type_of(param.def_id);
+                        let ty = tcx.at(self.span).type_of(param.def_id);
                         // FIXME(const_generics:defaults)
                         if infer_args {
                             // No const parameters were provided, we can infer all.
-                            self.ct_infer(ty, Some(param), span).into()
+                            self.astconv.ct_infer(ty, Some(param), self.span).into()
                         } else {
                             // We've already errored above about the mismatch.
                             tcx.const_error(ty).into()
                         }
                     }
                 }
-            },
+            }
+        }
+
+        let mut substs_ctx = SubstsForAstPathCtxt {
+            astconv: self,
+            def_id,
+            span,
+            generic_args,
+            missing_type_params: vec![],
+            inferred_params: vec![],
+            infer_args,
+            is_object,
+        };
+        let substs = Self::create_substs_for_generic_args(
+            tcx,
+            def_id,
+            parent_substs,
+            self_ty.is_some(),
+            self_ty,
+            arg_count.clone(),
+            &mut substs_ctx,
         );
 
         self.complain_about_missing_type_params(
-            missing_type_params,
+            substs_ctx.missing_type_params,
             def_id,
             span,
             generic_args.args.is_empty(),
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index e8eea65137f..3a5eeb5381b 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -131,7 +131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         id,
                         self.body_id,
                         self.param_env,
-                        &ty,
+                        ty,
                         arm.body.span,
                     );
                     let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty();
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index a38fb9642b9..ebfb401fcf3 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -133,7 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .replace_bound_vars_with_fresh_vars(
                             call_expr.span,
                             infer::FnCall,
-                            &closure_sig,
+                            closure_sig,
                         )
                         .0;
                     let adjustments = self.adjust_steps(autoderef);
@@ -407,8 +407,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // previously appeared within a `Binder<>` and hence would not
         // have been normalized before.
         let fn_sig =
-            self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, &fn_sig).0;
-        let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig);
+            self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig).0;
+        let fn_sig = self.normalize_associated_types_in(call_expr.span, fn_sig);
 
         // Call the generic checker.
         let expected_arg_tys = self.expected_inputs_for_expected_output(
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 5c2bdb86f76..36240a9b41e 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -87,7 +87,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Result<Option<PointerKind<'tcx>>, ErrorReported> {
         debug!("pointer_kind({:?}, {:?})", t, span);
 
-        let t = self.resolve_vars_if_possible(&t);
+        let t = self.resolve_vars_if_possible(t);
 
         if t.references_error() {
             return Err(ErrorReported);
@@ -377,12 +377,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
                     if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
                         if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) {
-                            let ty = fcx.resolve_vars_if_possible(&self.cast_ty);
+                            let ty = fcx.resolve_vars_if_possible(self.cast_ty);
                             // Erase regions to avoid panic in `prove_value` when calling
                             // `type_implements_trait`.
-                            let ty = fcx.tcx.erase_regions(&ty);
-                            let expr_ty = fcx.resolve_vars_if_possible(&self.expr_ty);
-                            let expr_ty = fcx.tcx.erase_regions(&expr_ty);
+                            let ty = fcx.tcx.erase_regions(ty);
+                            let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+                            let expr_ty = fcx.tcx.erase_regions(expr_ty);
                             let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
                             // Check for infer types because cases like `Option<{integer}>` would
                             // panic otherwise.
@@ -471,7 +471,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             self.expr_ty,
             E0620,
             "cast to unsized type: `{}` as `{}`",
-            fcx.resolve_vars_if_possible(&self.expr_ty),
+            fcx.resolve_vars_if_possible(self.expr_ty),
             tstr
         );
         match self.expr_ty.kind() {
@@ -607,7 +607,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         // Attempt a coercion to a fn pointer type.
                         let f = fcx.normalize_associated_types_in(
                             self.expr.span,
-                            &self.expr_ty.fn_sig(fcx.tcx),
+                            self.expr_ty.fn_sig(fcx.tcx),
                         );
                         let res = fcx.try_coerce(
                             self.expr,
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 70d94ef869d..1220c313932 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -75,7 +75,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     let declared_ret_ty = fn_sig.output();
 
     let revealed_ret_ty =
-        fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
+        fcx.instantiate_opaque_types_from_value(fn_id, declared_ret_ty, decl.output.span());
     debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
     fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
     fcx.ret_type_span = Some(decl.output.span());
@@ -446,24 +446,24 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
     struct ProhibitOpaqueVisitor<'tcx> {
         opaque_identity_ty: Ty<'tcx>,
         generics: &'tcx ty::Generics,
-        ty: Option<Ty<'tcx>>,
     };
 
     impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
-        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+        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() {
-                self.ty = Some(t);
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(Some(t));
             }
             ControlFlow::CONTINUE
         }
 
-        fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+        fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
             if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
                 if *index < self.generics.parent_count as u32 {
-                    return ControlFlow::BREAK;
+                    return ControlFlow::Break(None);
                 } else {
                     return ControlFlow::CONTINUE;
                 }
@@ -472,7 +472,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
             r.super_visit_with(self)
         }
 
-        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
+        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
                 // which would violate this check. Even though the particular substitution is not used
@@ -494,18 +494,17 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
                 InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
             ),
             generics: tcx.generics_of(def_id),
-            ty: None,
         };
         let prohibit_opaque = tcx
             .explicit_item_bounds(def_id)
             .iter()
-            .any(|(predicate, _)| predicate.visit_with(&mut visitor).is_break());
+            .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
         debug!(
             "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
             prohibit_opaque, visitor
         );
 
-        if prohibit_opaque {
+        if let Some(ty) = prohibit_opaque.break_value() {
             let is_async = match item.kind {
                 ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
                     hir::OpaqueTyOrigin::AsyncFn => true,
@@ -525,7 +524,7 @@ 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) = visitor.ty {
+                    if let Some(ty) = ty {
                         err.span_suggestion(
                             span,
                             "consider spelling out the type instead",
@@ -601,7 +600,7 @@ fn check_opaque_meets_bounds<'tcx>(
         let misc_cause = traits::ObligationCause::misc(span, hir_id);
 
         let (_, opaque_type_map) = inh.register_infer_ok_obligations(
-            infcx.instantiate_opaque_types(def_id, hir_id, param_env, &opaque_ty, span),
+            infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span),
         );
 
         for (def_id, opaque_defn) in opaque_type_map {
@@ -1455,7 +1454,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
             {
                 struct VisitTypes(Vec<DefId>);
                 impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
-                    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+                    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         match *t.kind() {
                             ty::Opaque(def, _) => {
                                 self.0.push(def);
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 2ba05071c05..8082a230216 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -257,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let input_tys = if is_fn {
             let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
-            let arg_param_ty = self.resolve_vars_if_possible(&arg_param_ty);
+            let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
             debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
 
             match arg_param_ty.kind() {
@@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let ret_param_ty = projection.skip_binder().ty;
-        let ret_param_ty = self.resolve_vars_if_possible(&ret_param_ty);
+        let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
         debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
 
         let sig = self.tcx.mk_fn_sig(
@@ -400,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // `deduce_expectations_from_expected_type` introduces
         // late-bound lifetimes defined elsewhere, which we now
         // anonymize away, so as not to confuse the user.
-        let bound_sig = self.tcx.anonymize_late_bound_regions(&bound_sig);
+        let bound_sig = self.tcx.anonymize_late_bound_regions(bound_sig);
 
         let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig);
 
@@ -500,7 +500,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let (supplied_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars(
                     hir_ty.span,
                     LateBoundRegionConversionTime::FnCall,
-                    &ty::Binder::bind(supplied_ty),
+                    ty::Binder::bind(supplied_ty),
                 ); // recreated from (*) above
 
                 // Check that E' = S'.
@@ -513,7 +513,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let (supplied_output_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars(
                 decl.output.span(),
                 LateBoundRegionConversionTime::FnCall,
-                &supplied_sig.output(),
+                supplied_sig.output(),
             );
             let cause = &self.misc(decl.output.span());
             let InferOk { value: (), obligations } = self
@@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         debug!("supplied_sig_of_closure: result={:?}", result);
 
-        let c_result = self.inh.infcx.canonicalize_response(&result);
+        let c_result = self.inh.infcx.canonicalize_response(result);
         self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
 
         result
@@ -683,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Extract the type from the projection. Note that there can
         // be no bound variables in this type because the "self type"
         // does not have any regions in it.
-        let output_ty = self.resolve_vars_if_possible(&predicate.ty);
+        let output_ty = self.resolve_vars_if_possible(predicate.ty);
         debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
         Some(output_ty)
     }
@@ -723,12 +723,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         body: &hir::Body<'_>,
         bound_sig: ty::PolyFnSig<'tcx>,
     ) -> ClosureSignatures<'tcx> {
-        let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, &bound_sig);
+        let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, bound_sig);
         let liberated_sig = self.inh.normalize_associated_types_in(
             body.value.span,
             body.value.hir_id,
             self.param_env,
-            &liberated_sig,
+            liberated_sig,
         );
         ClosureSignatures { bound_sig, liberated_sig }
     }
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 6da3ecde329..0f5f0ab0260 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -606,7 +606,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 // Uncertain or unimplemented.
                 Ok(None) => {
                     if trait_pred.def_id() == unsize_did {
-                        let trait_pred = self.resolve_vars_if_possible(&trait_pred);
+                        let trait_pred = self.resolve_vars_if_possible(trait_pred);
                         let self_ty = trait_pred.skip_binder().self_ty();
                         let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
                         debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
@@ -732,7 +732,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 }
 
                 let InferOk { value: a_sig, mut obligations } =
-                    self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig);
+                    self.normalize_associated_types_in_as_infer_ok(self.cause.span, a_sig);
 
                 let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig);
                 let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
@@ -973,8 +973,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
         if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) {
             // The signature must match.
-            let a_sig = self.normalize_associated_types_in(new.span, &a_sig);
-            let b_sig = self.normalize_associated_types_in(new.span, &b_sig);
+            let a_sig = self.normalize_associated_types_in(new.span, a_sig);
+            let b_sig = self.normalize_associated_types_in(new.span, b_sig);
             let sig = self
                 .at(cause, self.param_env)
                 .trace(prev_ty, new_ty)
@@ -1490,7 +1490,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                         *sp,
                         &format!(
                             "return type inferred to be `{}` here",
-                            fcx.resolve_vars_if_possible(&expected)
+                            fcx.resolve_vars_if_possible(expected)
                         ),
                     );
                 }
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 4acc7451a21..20090d37606 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -224,11 +224,11 @@ fn compare_predicate_entailment<'tcx>(
         let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars(
             impl_m_span,
             infer::HigherRankedType,
-            &ty::Binder::bind(impl_m_own_bounds.predicates),
+            ty::Binder::bind(impl_m_own_bounds.predicates),
         );
         for predicate in impl_m_own_bounds {
             let traits::Normalized { value: predicate, obligations } =
-                traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate);
+                traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
 
             inh.register_predicates(obligations);
             inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
@@ -253,17 +253,17 @@ fn compare_predicate_entailment<'tcx>(
         let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars(
             impl_m_span,
             infer::HigherRankedType,
-            &tcx.fn_sig(impl_m.def_id),
+            tcx.fn_sig(impl_m.def_id),
         );
         let impl_sig =
-            inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &impl_sig);
+            inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, impl_sig);
         let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
-        let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, &tcx.fn_sig(trait_m.def_id));
+        let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
         let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
         let trait_sig =
-            inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &trait_sig);
+            inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
         let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig));
 
         debug!("compare_impl_method: trait_fty={:?}", trait_fty);
@@ -499,7 +499,7 @@ fn compare_self_type<'tcx>(
 
         tcx.infer_ctxt().enter(|infcx| {
             let self_arg_ty =
-                tcx.liberate_late_bound_regions(method.def_id, &ty::Binder::bind(self_arg_ty));
+                tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(self_arg_ty));
             let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
             match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
                 ExplicitSelf::ByValue => "self".to_owned(),
@@ -968,12 +968,12 @@ crate fn compare_const_impl<'tcx>(
 
         // There is no "body" here, so just pass dummy id.
         let impl_ty =
-            inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, &impl_ty);
+            inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, impl_ty);
 
         debug!("compare_const_impl: impl_ty={:?}", impl_ty);
 
         let trait_ty =
-            inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, &trait_ty);
+            inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, trait_ty);
 
         debug!("compare_const_impl: trait_ty={:?}", trait_ty);
 
@@ -1136,7 +1136,7 @@ fn compare_type_predicate_entailment<'tcx>(
 
         for predicate in impl_ty_own_bounds.predicates {
             let traits::Normalized { value: predicate, obligations } =
-                traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate);
+                traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
 
             inh.register_predicates(obligations);
             inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
@@ -1261,7 +1261,7 @@ pub fn check_type_bounds<'tcx>(
                 &mut selcx,
                 normalize_param_env,
                 normalize_cause.clone(),
-                &obligation.predicate,
+                obligation.predicate,
             );
             debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
             obligation.predicate = normalized_predicate;
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index 5650b2cdd3c..ad675f1e383 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -366,8 +366,8 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
 
         // Anonymizing the LBRs is necessary to solve (Issue #59497).
         // After we do so, it should be totally fine to skip the binders.
-        let anon_a = self.tcx.anonymize_late_bound_regions(&a);
-        let anon_b = self.tcx.anonymize_late_bound_regions(&b);
+        let anon_a = self.tcx.anonymize_late_bound_regions(a);
+        let anon_b = self.tcx.anonymize_late_bound_regions(b);
         self.relate(anon_a.skip_binder(), anon_b.skip_binder())?;
 
         Ok(a)
diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_typeck/src/check/expectation.rs
index fd6fe1406c8..5a5fc893d65 100644
--- a/compiler/rustc_typeck/src/check/expectation.rs
+++ b/compiler/rustc_typeck/src/check/expectation.rs
@@ -83,9 +83,9 @@ impl<'a, 'tcx> Expectation<'tcx> {
     fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
         match self {
             NoExpectation => NoExpectation,
-            ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)),
-            ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)),
-            ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)),
+            ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(t)),
+            ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(t)),
+            ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(t)),
         }
     }
 
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index af19ad08c1d..f7f9e607a74 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -494,7 +494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .replace_bound_vars_with_fresh_vars(
                             expr.span,
                             infer::LateBoundRegionConversionTime::FnCall,
-                            &fn_sig.input(i),
+                            fn_sig.input(i),
                         )
                         .0;
                     self.require_type_is_sized_deferred(
@@ -514,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .replace_bound_vars_with_fresh_vars(
                     expr.span,
                     infer::LateBoundRegionConversionTime::FnCall,
-                    &fn_sig.output(),
+                    fn_sig.output(),
                 )
                 .0;
             self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType);
@@ -963,9 +963,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Find the type of `e`. Supply hints based on the type we are casting to,
         // if appropriate.
         let t_cast = self.to_ty_saving_user_provided_ty(t);
-        let t_cast = self.resolve_vars_if_possible(&t_cast);
+        let t_cast = self.resolve_vars_if_possible(t_cast);
         let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
-        let t_cast = self.resolve_vars_if_possible(&t_cast);
+        let t_cast = self.resolve_vars_if_possible(t_cast);
 
         // Eagerly check for some obvious errors.
         if t_expr.references_error() || t_cast.references_error() {
@@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .map(|f| {
                                 self.normalize_associated_types_in(
                                     expr.span,
-                                    &f.ty(self.tcx, substs),
+                                    f.ty(self.tcx, substs),
                                 )
                             })
                             .collect();
@@ -1571,7 +1571,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty: Ty<'tcx>,
     ) {
         let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
-            Some(output_ty) => self.resolve_vars_if_possible(&output_ty),
+            Some(output_ty) => self.resolve_vars_if_possible(output_ty),
             _ => return,
         };
         let mut add_label = true;
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 0bb7b464f16..e1a2f593b8d 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1,5 +1,6 @@
 use crate::astconv::{
-    AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg,
+    AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
+    GenericArgCountResult, PathSeg,
 };
 use crate::check::callee::{self, DeferredCallResolution};
 use crate::check::method::{self, MethodCallee, SelfSource};
@@ -87,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         // If `ty` is a type variable, see whether we already know what it is.
-        ty = self.resolve_vars_if_possible(&ty);
+        ty = self.resolve_vars_if_possible(ty);
         if !ty.has_infer_types_or_consts() {
             debug!("resolve_vars_with_obligations: ty={:?}", ty);
             return ty;
@@ -98,7 +99,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // indirect dependencies that don't seem worth tracking
         // precisely.
         self.select_obligations_where_possible(false, |_| {});
-        ty = self.resolve_vars_if_possible(&ty);
+        ty = self.resolve_vars_if_possible(ty);
 
         debug!("resolve_vars_with_obligations: ty={:?}", ty);
         ty
@@ -133,12 +134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     #[inline]
     pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
-        debug!(
-            "write_ty({:?}, {:?}) in fcx {}",
-            id,
-            self.resolve_vars_if_possible(&ty),
-            self.tag()
-        );
+        debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag());
         self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
 
         if ty.references_error() {
@@ -194,7 +190,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         user_self_ty: None, // not relevant here
                     };
 
-                    self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
+                    self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
                         method.def_id,
                         user_substs,
                     ))
@@ -239,7 +235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
 
         if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
-            let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
+            let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
                 def_id,
                 UserSubsts { substs, user_self_ty },
             ));
@@ -325,13 +321,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Basically whenever we are converting from a type scheme into
     /// the fn body space, we always want to normalize associated
     /// types as well. This function combines the two.
-    fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T
+    fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
+        debug!("instantiate_type_scheme(value={:?}, substs={:?})", value, substs);
         let value = value.subst(self.tcx, substs);
-        let result = self.normalize_associated_types_in(span, &value);
-        debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result);
+        let result = self.normalize_associated_types_in(span, value);
+        debug!("instantiate_type_scheme = {:?}", result);
         result
     }
 
@@ -346,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let bounds = self.tcx.predicates_of(def_id);
         let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
         let result = bounds.instantiate(self.tcx, substs);
-        let result = self.normalize_associated_types_in(span, &result);
+        let result = self.normalize_associated_types_in(span, result);
         debug!(
             "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
             bounds, substs, result, spans,
@@ -360,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
         &self,
         parent_id: hir::HirId,
-        value: &T,
+        value: T,
         value_span: Span,
     ) -> T {
         let parent_def_id = self.tcx.hir().local_def_id(parent_id);
@@ -388,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         value
     }
 
-    pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
+    pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -398,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn normalize_associated_types_in_as_infer_ok<T>(
         &self,
         span: Span,
-        value: &T,
+        value: T,
     ) -> InferOk<'tcx, T>
     where
         T: TypeFoldable<'tcx>,
@@ -467,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
 
         if Self::can_contain_user_lifetime_bounds(ty) {
-            let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
+            let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty));
             debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
             self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
         }
@@ -850,7 +847,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 // Record all the argument types, with the substitutions
                 // produced from the above subtyping unification.
-                Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect())
+                Ok(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect())
             })
             .unwrap_or_default();
         debug!(
@@ -1203,7 +1200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if let Res::Local(hid) = res {
             let ty = self.local_ty(span, hid).decl_ty;
-            let ty = self.normalize_associated_types_in(span, &ty);
+            let ty = self.normalize_associated_types_in(span, ty);
             self.write_ty(hir_id, ty);
             return (ty, res);
         }
@@ -1298,76 +1295,108 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             },
         };
 
-        let substs = self_ctor_substs.unwrap_or_else(|| {
-            AstConv::create_substs_for_generic_args(
-                tcx,
-                def_id,
-                &[][..],
-                has_self,
-                self_ty,
-                arg_count,
-                // Provide the generic args, and whether types should be inferred.
-                |def_id| {
-                    if let Some(&PathSeg(_, index)) =
-                        path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
-                    {
-                        // If we've encountered an `impl Trait`-related error, we're just
-                        // going to infer the arguments for better error messages.
-                        if !infer_args_for_err.contains(&index) {
-                            // Check whether the user has provided generic arguments.
-                            if let Some(ref data) = segments[index].args {
-                                return (Some(data), segments[index].infer_args);
-                            }
+        struct CreateCtorSubstsContext<'a, 'tcx> {
+            fcx: &'a FnCtxt<'a, 'tcx>,
+            span: Span,
+            path_segs: &'a [PathSeg],
+            infer_args_for_err: &'a FxHashSet<usize>,
+            segments: &'a [hir::PathSegment<'a>],
+        }
+        impl<'tcx, 'a> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for CreateCtorSubstsContext<'a, 'tcx> {
+            fn args_for_def_id(
+                &mut self,
+                def_id: DefId,
+            ) -> (Option<&'a hir::GenericArgs<'a>>, bool) {
+                if let Some(&PathSeg(_, index)) =
+                    self.path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
+                {
+                    // If we've encountered an `impl Trait`-related error, we're just
+                    // going to infer the arguments for better error messages.
+                    if !self.infer_args_for_err.contains(&index) {
+                        // Check whether the user has provided generic arguments.
+                        if let Some(ref data) = self.segments[index].args {
+                            return (Some(data), self.segments[index].infer_args);
                         }
-                        return (None, segments[index].infer_args);
                     }
+                    return (None, self.segments[index].infer_args);
+                }
 
-                    (None, true)
-                },
-                // Provide substitutions for parameters for which (valid) arguments have been provided.
-                |param, arg| match (&param.kind, arg) {
+                (None, true)
+            }
+
+            fn provided_kind(
+                &mut self,
+                param: &ty::GenericParamDef,
+                arg: &GenericArg<'_>,
+            ) -> subst::GenericArg<'tcx> {
+                match (&param.kind, arg) {
                     (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        AstConv::ast_region_to_region(self, lt, Some(param)).into()
+                        AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.to_ty(ty).into()
+                        self.fcx.to_ty(ty).into()
                     }
                     (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                        self.const_arg_to_const(&ct.value, param.def_id).into()
+                        self.fcx.const_arg_to_const(&ct.value, param.def_id).into()
                     }
                     _ => unreachable!(),
-                },
-                // Provide substitutions for parameters for which arguments are inferred.
-                |substs, param, infer_args| {
-                    match param.kind {
-                        GenericParamDefKind::Lifetime => {
-                            self.re_infer(Some(param), span).unwrap().into()
-                        }
-                        GenericParamDefKind::Type { has_default, .. } => {
-                            if !infer_args && has_default {
-                                // If we have a default, then we it doesn't matter that we're not
-                                // inferring the type arguments: we provide the default where any
-                                // is missing.
-                                let default = tcx.type_of(param.def_id);
-                                self.normalize_ty(
-                                    span,
-                                    default.subst_spanned(tcx, substs.unwrap(), Some(span)),
+                }
+            }
+
+            fn inferred_kind(
+                &mut self,
+                substs: Option<&[subst::GenericArg<'tcx>]>,
+                param: &ty::GenericParamDef,
+                infer_args: bool,
+            ) -> subst::GenericArg<'tcx> {
+                let tcx = self.fcx.tcx();
+                match param.kind {
+                    GenericParamDefKind::Lifetime => {
+                        self.fcx.re_infer(Some(param), self.span).unwrap().into()
+                    }
+                    GenericParamDefKind::Type { has_default, .. } => {
+                        if !infer_args && has_default {
+                            // If we have a default, then we it doesn't matter that we're not
+                            // inferring the type arguments: we provide the default where any
+                            // is missing.
+                            let default = tcx.type_of(param.def_id);
+                            self.fcx
+                                .normalize_ty(
+                                    self.span,
+                                    default.subst_spanned(tcx, substs.unwrap(), Some(self.span)),
                                 )
                                 .into()
-                            } else {
-                                // If no type arguments were provided, we have to infer them.
-                                // This case also occurs as a result of some malformed input, e.g.
-                                // a lifetime argument being given instead of a type parameter.
-                                // Using inference instead of `Error` gives better error messages.
-                                self.var_for_def(span, param)
-                            }
-                        }
-                        GenericParamDefKind::Const => {
-                            // FIXME(const_generics:defaults)
-                            // No const parameters were provided, we have to infer them.
-                            self.var_for_def(span, param)
+                        } else {
+                            // If no type arguments were provided, we have to infer them.
+                            // This case also occurs as a result of some malformed input, e.g.
+                            // a lifetime argument being given instead of a type parameter.
+                            // Using inference instead of `Error` gives better error messages.
+                            self.fcx.var_for_def(self.span, param)
                         }
                     }
+                    GenericParamDefKind::Const => {
+                        // FIXME(const_generics:defaults)
+                        // No const parameters were provided, we have to infer them.
+                        self.fcx.var_for_def(self.span, param)
+                    }
+                }
+            }
+        }
+
+        let substs = self_ctor_substs.unwrap_or_else(|| {
+            AstConv::create_substs_for_generic_args(
+                tcx,
+                def_id,
+                &[][..],
+                has_self,
+                self_ty,
+                arg_count,
+                &mut CreateCtorSubstsContext {
+                    fcx: self,
+                    span,
+                    path_segs: &path_segs,
+                    infer_args_for_err: &infer_args_for_err,
+                    segments,
                 },
             )
         });
@@ -1381,7 +1410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Substitute the values for the type parameters into the type of
         // the referenced item.
-        let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
+        let ty_substituted = self.instantiate_type_scheme(span, &substs, ty);
 
         if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
             // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
@@ -1391,7 +1420,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // This also occurs for an enum variant on a type alias.
             let ty = tcx.type_of(impl_def_id);
 
-            let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
+            let impl_ty = self.instantiate_type_scheme(span, &substs, ty);
             match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
                 Ok(ok) => self.register_infer_ok_obligations(ok),
                 Err(_) => {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index a820661d843..333bda00dbe 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -261,9 +261,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else {
             // is the missing argument of type `()`?
             let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit()
+                self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit()
             } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(&fn_inputs[0]).is_unit()
+                self.resolve_vars_if_possible(fn_inputs[0]).is_unit()
             } else {
                 false
             };
@@ -384,7 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                     ty::FnDef(..) => {
                         let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
-                        let ptr_ty = self.resolve_vars_if_possible(&ptr_ty);
+                        let ptr_ty = self.resolve_vars_if_possible(ptr_ty);
                         variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string());
                     }
                     _ => {}
@@ -927,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .map(|&(i, checked_ty, _)| (i, checked_ty))
                     .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
                     .flat_map(|(i, ty)| {
-                        let ty = self.resolve_vars_if_possible(&ty);
+                        let ty = self.resolve_vars_if_possible(ty);
                         // We walk the argument type because the argument's type could have
                         // been `Option<T>`, but the `FulfillmentError` references `T`.
                         if ty.walk().any(|arg| arg == predicate.self_ty().into()) {
@@ -989,7 +989,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         // from `typeck-default-trait-impl-assoc-type.rs`.
                                     } else {
                                         let ty = AstConv::ast_ty_to_ty(self, hir_ty);
-                                        let ty = self.resolve_vars_if_possible(&ty);
+                                        let ty = self.resolve_vars_if_possible(ty);
                                         if ty == predicate.self_ty() {
                                             error.obligation.cause.make_mut().span = hir_ty.span;
                                         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index 72c3b233ed9..f635e0b6f93 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -262,7 +262,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
             span,
             infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
-            &poly_trait_ref,
+            poly_trait_ref,
         );
 
         let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index a8ad9f4fdf8..17dbf989d66 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -73,8 +73,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => return false,
         };
 
-        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0;
-        let sig = self.normalize_associated_types_in(expr.span, &sig);
+        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, sig).0;
+        let sig = self.normalize_associated_types_in(expr.span, sig);
         if self.can_coerce(sig.output(), expected) {
             let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
                 (String::new(), Applicability::MachineApplicable)
diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs
index af552389de0..825ebc19fa6 100644
--- a/compiler/rustc_typeck/src/check/gather_locals.rs
+++ b/compiler/rustc_typeck/src/check/gather_locals.rs
@@ -59,16 +59,13 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
                 let o_ty = self.fcx.to_ty(&ty);
 
                 let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
-                    self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span)
+                    self.fcx.instantiate_opaque_types_from_value(self.parent_id, o_ty, ty.span)
                 } else {
                     o_ty
                 };
 
-                let c_ty = self
-                    .fcx
-                    .inh
-                    .infcx
-                    .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty));
+                let c_ty =
+                    self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(revealed_ty));
                 debug!(
                     "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
                     ty.hir_id, o_ty, revealed_ty, c_ty
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 293a995887c..602b79802b3 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -80,7 +80,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
             });
 
         if let Some(yield_data) = live_across_yield {
-            let ty = self.fcx.resolve_vars_if_possible(&ty);
+            let ty = self.fcx.resolve_vars_if_possible(ty);
             debug!(
                 "type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
                 expr, scope, ty, self.expr_count, yield_data.span
@@ -120,7 +120,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
                 self.expr_count,
                 expr.map(|e| e.span)
             );
-            let ty = self.fcx.resolve_vars_if_possible(&ty);
+            let ty = self.fcx.resolve_vars_if_possible(ty);
             if let Some((unresolved_type, unresolved_type_span)) =
                 self.fcx.unresolved_type_vars(&ty)
             {
@@ -179,13 +179,13 @@ pub fn resolve_interior<'a, 'tcx>(
         .filter_map(|mut cause| {
             // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
             // can.
-            let erased = fcx.tcx.erase_regions(&cause.ty);
+            let erased = fcx.tcx.erase_regions(cause.ty);
             if captured_tys.insert(erased) {
                 // Replace all regions inside the generator interior with late bound regions.
                 // Note that each region slot in the types gets a new fresh late bound region,
                 // which means that none of the regions inside relate to any other, even if
                 // typeck had previously found constraints that would cause them to be related.
-                let folded = fcx.tcx.fold_regions(&erased, &mut false, |_, current_depth| {
+                let folded = fcx.tcx.fold_regions(erased, &mut false, |_, current_depth| {
                     let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter)));
                     counter += 1;
                     r
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index 7e580485c3d..0011a3fc71b 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -156,7 +156,7 @@ impl Inherited<'a, 'tcx> {
         span: Span,
         body_id: hir::HirId,
         param_env: ty::ParamEnv<'tcx>,
-        value: &T,
+        value: T,
     ) -> T
     where
         T: TypeFoldable<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index fd2700b85e2..8ef723d5902 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -1,6 +1,6 @@
 use super::{probe, MethodCallee};
 
-use crate::astconv::AstConv;
+use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt};
 use crate::check::{callee, FnCtxt};
 use crate::hir::def_id::DefId;
 use crate::hir::GenericArg;
@@ -10,7 +10,7 @@ use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
 use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::subst::{self, Subst, SubstsRef};
 use rustc_middle::ty::{self, GenericParamDefKind, Ty};
 use rustc_span::Span;
 use rustc_trait_selection::traits;
@@ -90,8 +90,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // traits, no trait system method can be called before this point because they
         // could alter our Self-type, except for normalizing the receiver from the
         // signature (which is also done during probing).
-        let method_sig_rcvr =
-            self.normalize_associated_types_in(self.span, &method_sig.inputs()[0]);
+        let method_sig_rcvr = self.normalize_associated_types_in(self.span, method_sig.inputs()[0]);
         debug!(
             "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}",
             self_ty, method_sig_rcvr, method_sig, method_predicates
@@ -99,7 +98,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs);
 
         let (method_sig, method_predicates) =
-            self.normalize_associated_types_in(self.span, &(method_sig, method_predicates));
+            self.normalize_associated_types_in(self.span, (method_sig, method_predicates));
 
         // Make sure nobody calls `drop()` explicitly.
         self.enforce_illegal_method_limitations(&pick);
@@ -229,7 +228,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                     let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
                     let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
                     let upcast_trait_ref =
-                        this.replace_bound_vars_with_fresh_vars(&upcast_poly_trait_ref);
+                        this.replace_bound_vars_with_fresh_vars(upcast_poly_trait_ref);
                     debug!(
                         "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
                         original_poly_trait_ref, upcast_trait_ref, trait_def_id
@@ -249,10 +248,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                 self.fresh_substs_for_item(self.span, trait_def_id)
             }
 
-            probe::WhereClausePick(ref poly_trait_ref) => {
+            probe::WhereClausePick(poly_trait_ref) => {
                 // Where clauses can have bound regions in them. We need to instantiate
                 // those to convert from a poly-trait-ref to a trait-ref.
-                self.replace_bound_vars_with_fresh_vars(&poly_trait_ref).substs
+                self.replace_bound_vars_with_fresh_vars(poly_trait_ref).substs
             }
         }
     }
@@ -307,6 +306,52 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // parameters from the type and those from the method.
         assert_eq!(generics.parent_count, parent_substs.len());
 
+        struct MethodSubstsCtxt<'a, 'tcx> {
+            cfcx: &'a ConfirmContext<'a, 'tcx>,
+            pick: &'a probe::Pick<'tcx>,
+            seg: &'a hir::PathSegment<'a>,
+        }
+        impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for MethodSubstsCtxt<'a, 'tcx> {
+            fn args_for_def_id(
+                &mut self,
+                def_id: DefId,
+            ) -> (Option<&'a hir::GenericArgs<'a>>, bool) {
+                if def_id == self.pick.item.def_id {
+                    if let Some(ref data) = self.seg.args {
+                        return (Some(data), false);
+                    }
+                }
+                (None, false)
+            }
+
+            fn provided_kind(
+                &mut self,
+                param: &ty::GenericParamDef,
+                arg: &GenericArg<'_>,
+            ) -> subst::GenericArg<'tcx> {
+                match (&param.kind, arg) {
+                    (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
+                        AstConv::ast_region_to_region(self.cfcx.fcx, lt, Some(param)).into()
+                    }
+                    (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
+                        self.cfcx.to_ty(ty).into()
+                    }
+                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
+                        self.cfcx.const_arg_to_const(&ct.value, param.def_id).into()
+                    }
+                    _ => unreachable!(),
+                }
+            }
+
+            fn inferred_kind(
+                &mut self,
+                _substs: Option<&[subst::GenericArg<'tcx>]>,
+                param: &ty::GenericParamDef,
+                _infer_args: bool,
+            ) -> subst::GenericArg<'tcx> {
+                self.cfcx.var_for_def(self.cfcx.span, param)
+            }
+        }
         AstConv::create_substs_for_generic_args(
             self.tcx,
             pick.item.def_id,
@@ -314,29 +359,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             false,
             None,
             arg_count_correct,
-            // Provide the generic args, and whether types should be inferred.
-            |def_id| {
-                // The last component of the returned tuple here is unimportant.
-                if def_id == pick.item.def_id {
-                    if let Some(ref data) = seg.args {
-                        return (Some(data), false);
-                    }
-                }
-                (None, false)
-            },
-            // Provide substitutions for parameters for which (valid) arguments have been provided.
-            |param, arg| match (&param.kind, arg) {
-                (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                    AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into()
-                }
-                (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => self.to_ty(ty).into(),
-                (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                    self.const_arg_to_const(&ct.value, param.def_id).into()
-                }
-                _ => unreachable!(),
-            },
-            // Provide substitutions for parameters for which arguments are inferred.
-            |_, param, _| self.var_for_def(self.span, param),
+            &mut MethodSubstsCtxt { cfcx: self, pick, seg },
         )
     }
 
@@ -400,7 +423,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // N.B., instantiate late-bound regions first so that
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
-        let method_sig = self.replace_bound_vars_with_fresh_vars(&sig);
+        let method_sig = self.replace_bound_vars_with_fresh_vars(sig);
         debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig);
 
         let method_sig = method_sig.subst(self.tcx, all_substs);
@@ -506,7 +529,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         upcast_trait_refs.into_iter().next().unwrap()
     }
 
-    fn replace_bound_vars_with_fresh_vars<T>(&self, value: &ty::Binder<T>) -> T
+    fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<T>) -> T
     where
         T: TypeFoldable<'tcx>,
     {
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 84bc3979e12..8e13b374699 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         scope: ProbeScope,
     ) -> probe::PickResult<'tcx> {
         let mode = probe::Mode::MethodCall;
-        let self_ty = self.resolve_vars_if_possible(&self_ty);
+        let self_ty = self.resolve_vars_if_possible(self_ty);
         self.probe_for_name(
             span,
             mode,
@@ -358,11 +358,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
         let fn_sig = tcx.fn_sig(def_id);
-        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, &fn_sig).0;
+        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
         let fn_sig = fn_sig.subst(self.tcx, substs);
 
         let InferOk { value, obligations: o } =
-            self.normalize_associated_types_in_as_infer_ok(span, &fn_sig);
+            self.normalize_associated_types_in_as_infer_ok(span, fn_sig);
         let fn_sig = {
             obligations.extend(o);
             value
@@ -379,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
 
         let InferOk { value, obligations: o } =
-            self.normalize_associated_types_in_as_infer_ok(span, &bounds);
+            self.normalize_associated_types_in_as_infer_ok(span, bounds);
         let bounds = {
             obligations.extend(o);
             value
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 713b24e583a..478f8a16169 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -25,7 +25,6 @@ use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::{
     self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
-use rustc_session::config::nightly_options;
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
@@ -309,7 +308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     {
         let mut orig_values = OriginalQueryValues::default();
         let param_env_and_self_ty = self.infcx.canonicalize_query(
-            &ParamEnvAnd { param_env: self.param_env, value: self_ty },
+            ParamEnvAnd { param_env: self.param_env, value: self_ty },
             &mut orig_values,
         );
 
@@ -731,7 +730,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             let cause = traits::ObligationCause::misc(self.span, self.body_id);
             let selcx = &mut traits::SelectionContext::new(self.fcx);
             let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } =
-                traits::normalize(selcx, self.param_env, cause, &xform_tys);
+                traits::normalize(selcx, self.param_env, cause, xform_tys);
             debug!(
                 "assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}",
                 xform_self_ty, xform_ret_ty
@@ -775,7 +774,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         // 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);
+            let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
 
             let (xform_self_ty, xform_ret_ty) =
                 this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
@@ -821,7 +820,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         });
 
         self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
-            let trait_ref = this.erase_late_bound_regions(&poly_trait_ref);
+            let trait_ref = this.erase_late_bound_regions(poly_trait_ref);
 
             let (xform_self_ty, xform_ret_ty) =
                 this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs);
@@ -912,7 +911,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     let substs = self.fresh_substs_for_item(self.span, method.def_id);
                     let fty = fty.subst(self.tcx, substs);
                     let (fty, _) =
-                        self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, &fty);
+                        self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty);
 
                     if let Some(self_ty) = self_ty {
                         if self
@@ -943,7 +942,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             // For trait aliases, assume all super-traits are relevant.
             let bounds = iter::once(trait_ref.to_poly_trait_ref());
             self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
-                let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
+                let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
 
                 let (xform_self_ty, xform_ret_ty) =
                     this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
@@ -1272,7 +1271,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     self.tcx.def_path_str(stable_pick.item.def_id),
                 ));
 
-                if nightly_options::is_nightly_build() {
+                if self.tcx.sess.is_nightly_build() {
                     for (candidate, feature) in unstable_candidates {
                         diag.help(&format!(
                             "add `#![feature({})]` to the crate attributes to enable `{}`",
@@ -1356,7 +1355,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     let impl_bounds = self.tcx.predicates_of(impl_def_id);
                     let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
                     let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
-                        traits::normalize(selcx, self.param_env, cause.clone(), &impl_bounds);
+                        traits::normalize(selcx, self.param_env, cause.clone(), impl_bounds);
 
                     // Convert the bounds into obligations.
                     let impl_obligations =
@@ -1367,7 +1366,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                         .chain(ref_obligations.iter().cloned());
                     // Evaluate those obligations to see if they might possibly hold.
                     for o in candidate_obligations {
-                        let o = self.resolve_vars_if_possible(&o);
+                        let o = self.resolve_vars_if_possible(o);
                         if !self.predicate_may_hold(&o) {
                             result = ProbeResult::NoMatch;
                             possibly_unsatisfied_predicates.push((o.predicate, None));
@@ -1393,25 +1392,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                                     for obligation in impl_source.borrow_nested_obligations() {
                                         // Determine exactly which obligation wasn't met, so
                                         // that we can give more context in the error.
-                                        if !self.predicate_may_hold(&obligation) {
-                                            let o = self.resolve_vars_if_possible(obligation);
+                                        if !self.predicate_may_hold(obligation) {
+                                            let nested_predicate =
+                                                self.resolve_vars_if_possible(obligation.predicate);
                                             let predicate =
-                                                self.resolve_vars_if_possible(&predicate);
-                                            let p = if predicate == o.predicate {
+                                                self.resolve_vars_if_possible(predicate);
+                                            let p = if predicate == nested_predicate {
                                                 // Avoid "`MyStruct: Foo` which is required by
                                                 // `MyStruct: Foo`" in E0599.
                                                 None
                                             } else {
                                                 Some(predicate)
                                             };
-                                            possibly_unsatisfied_predicates.push((o.predicate, p));
+                                            possibly_unsatisfied_predicates
+                                                .push((nested_predicate, p));
                                         }
                                     }
                                 }
                                 _ => {
                                     // Some nested subobligation of this predicate
                                     // failed.
-                                    let predicate = self.resolve_vars_if_possible(&predicate);
+                                    let predicate = self.resolve_vars_if_possible(predicate);
                                     possibly_unsatisfied_predicates.push((predicate, None));
                                 }
                             }
@@ -1428,7 +1429,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
             // Evaluate those obligations to see if they might possibly hold.
             for o in sub_obligations {
-                let o = self.resolve_vars_if_possible(&o);
+                let o = self.resolve_vars_if_possible(o);
                 if !self.predicate_may_hold(&o) {
                     result = ProbeResult::NoMatch;
                     possibly_unsatisfied_predicates.push((o.predicate, None));
@@ -1439,7 +1440,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 if let (Some(return_ty), Some(xform_ret_ty)) =
                     (self.return_type, probe.xform_ret_ty)
                 {
-                    let xform_ret_ty = self.resolve_vars_if_possible(&xform_ret_ty);
+                    let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty);
                     debug!(
                         "comparing return_ty {:?} with xform ret ty {:?}",
                         return_ty, probe.xform_ret_ty
@@ -1605,7 +1606,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
         // Erase any late-bound regions from the method and substitute
         // in the values from the substitution.
-        let xform_fn_sig = self.erase_late_bound_regions(&fn_sig);
+        let xform_fn_sig = self.erase_late_bound_regions(fn_sig);
 
         if generics.params.is_empty() {
             xform_fn_sig.subst(self.tcx, substs)
@@ -1673,7 +1674,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     ///    region got replaced with the same variable, which requires a bit more coordination
     ///    and/or tracking the substitution and
     ///    so forth.
-    fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> T
+    fn erase_late_bound_regions<T>(&self, value: ty::Binder<T>) -> T
     where
         T: TypeFoldable<'tcx>,
     {
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 46afe4892db..3d5ce57a491 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -248,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }) => {
                 let tcx = self.tcx;
 
-                let actual = self.resolve_vars_if_possible(&rcvr_ty);
+                let actual = self.resolve_vars_if_possible(rcvr_ty);
                 let ty_str = self.ty_to_string(actual);
                 let is_method = mode == Mode::MethodCall;
                 let item_kind = if is_method {
@@ -870,7 +870,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
     ) {
         let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
-            Some(output_ty) => self.resolve_vars_if_possible(&output_ty),
+            Some(output_ty) => self.resolve_vars_if_possible(output_ty),
             _ => return,
         };
         let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 169ad0df3a5..b242900a122 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -362,7 +362,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDe
 /// conclude that we don't have a defining use of `MyItem`. By mapping inference
 /// variables back to the actual generic parameters, we will correctly see that
 /// we have a defining use of `MyItem`
-fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: &T) -> T
+fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: T) -> T
 where
     T: TypeFoldable<'tcx>,
 {
@@ -510,15 +510,15 @@ fn typeck_with_fallback<'tcx>(
             check_abi(tcx, span, fn_sig.abi());
 
             // Compute the fty from point of view of inside the fn.
-            let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), &fn_sig);
+            let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
             let fn_sig = inh.normalize_associated_types_in(
                 body.value.span,
                 body_id.hir_id,
                 param_env,
-                &fn_sig,
+                fn_sig,
             );
 
-            let fn_sig = fixup_opaque_types(tcx, &fn_sig);
+            let fn_sig = fixup_opaque_types(tcx, fn_sig);
 
             let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0;
             fcx
@@ -543,11 +543,11 @@ fn typeck_with_fallback<'tcx>(
                     _ => fallback(),
                 });
 
-            let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
+            let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
             fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
 
             let revealed_ty = if tcx.features().impl_trait_in_bindings {
-                fcx.instantiate_opaque_types_from_value(id, &expected_type, body.value.span)
+                fcx.instantiate_opaque_types_from_value(id, expected_type, body.value.span)
             } else {
                 expected_type
             };
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 247b5256726..854bc70108f 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -660,7 +660,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 method.sig.output()
             }
             Err(()) => {
-                let actual = self.resolve_vars_if_possible(&operand_ty);
+                let actual = self.resolve_vars_if_possible(operand_ty);
                 if !actual.references_error() {
                     let mut err = struct_span_err!(
                         self.tcx.sess,
@@ -983,7 +983,7 @@ fn suggest_constraining_param(
 struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
 
 impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if let ty::Param(_) = ty.kind() {
             self.0.push(ty);
         }
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 6489b7838d6..a729912126e 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -149,6 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// Outside of this module, `check_pat_top` should always be used.
     /// Conversely, inside this module, `check_pat_top` should never be used.
+    #[instrument(skip(self, ti))]
     fn check_pat(
         &self,
         pat: &'tcx Pat<'tcx>,
@@ -156,8 +157,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
     ) {
-        debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm);
-
         let path_res = match &pat.kind {
             PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)),
             _ => None,
@@ -398,6 +397,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let ty::Ref(_, inner_ty, _) = expected.kind() {
                 if matches!(inner_ty.kind(), ty::Slice(_)) {
                     let tcx = self.tcx;
+                    trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
+                    self.typeck_results
+                        .borrow_mut()
+                        .treat_byte_string_as_slice
+                        .insert(lt.hir_id.local_id);
                     pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8));
                 }
             }
@@ -459,7 +463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Now that we know the types can be unified we find the unified type
         // and use it to type the entire expression.
-        let common_type = self.resolve_vars_if_possible(&lhs_ty.or(rhs_ty).unwrap_or(expected));
+        let common_type = self.resolve_vars_if_possible(lhs_ty.or(rhs_ty).unwrap_or(expected));
 
         // Subtyping doesn't matter here, as the value is some kind of scalar.
         let demand_eqtype = |x, y| {
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 7b31b9f3915..b8b98cef763 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -229,7 +229,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
     /// of b will be `&<R0>.i32` and then `*b` will require that `<R0>` be bigger than the let and
     /// the `*b` expression, so we will effectively resolve `<R0>` to be the block B.
     pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.resolve_vars_if_possible(&unresolved_ty)
+        self.resolve_vars_if_possible(unresolved_ty)
     }
 
     /// Try to resolve the type for the given node.
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index e9dfef718fd..019fa78fb1e 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -39,10 +39,21 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_infer::infer::UpvarRegion;
-use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
+use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, ProjectionKind};
 use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts};
+use rustc_span::sym;
 use rustc_span::{Span, Symbol};
-use std::collections::hash_map::Entry;
+
+/// Describe the relationship between the paths of two places
+/// eg:
+/// - `foo` is ancestor of `foo.bar.baz`
+/// - `foo.bar.baz` is an descendant of `foo.bar`
+/// - `foo.bar` and `foo.baz` are divergent
+enum PlaceAncestryRelation {
+    Ancestor,
+    Descendant,
+    Divergent,
+}
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) {
@@ -111,40 +122,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             None
         };
 
-        if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
-            let mut closure_captures: FxIndexMap<hir::HirId, ty::UpvarId> =
-                FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default());
-            for (&var_hir_id, _) in upvars.iter() {
-                let upvar_id = ty::UpvarId {
-                    var_path: ty::UpvarPath { hir_id: var_hir_id },
-                    closure_expr_id: closure_def_id.expect_local(),
-                };
-                debug!("seed upvar_id {:?}", upvar_id);
-                // Adding the upvar Id to the list of Upvars, which will be added
-                // to the map for the closure at the end of the for loop.
-                closure_captures.insert(var_hir_id, upvar_id);
-
-                let capture_kind = match capture_clause {
-                    hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None),
-                    hir::CaptureBy::Ref => {
-                        let origin = UpvarRegion(upvar_id, span);
-                        let upvar_region = self.next_region_var(origin);
-                        let upvar_borrow =
-                            ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
-                        ty::UpvarCapture::ByRef(upvar_borrow)
-                    }
-                };
+        let local_def_id = closure_def_id.expect_local();
 
-                self.typeck_results.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
-            }
-            // Add the vector of upvars to the map keyed with the closure id.
-            // This gives us an easier access to them without having to call
-            // tcx.upvars again..
-            if !closure_captures.is_empty() {
-                self.typeck_results
-                    .borrow_mut()
-                    .closure_captures
-                    .insert(closure_def_id, closure_captures);
+        let mut capture_information: FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>> =
+            Default::default();
+        if !self.tcx.features().capture_disjoint_fields {
+            if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
+                for (&var_hir_id, _) in upvars.iter() {
+                    let place = self.place_for_root_variable(local_def_id, var_hir_id);
+
+                    debug!("seed place {:?}", place);
+
+                    let upvar_id = ty::UpvarId::new(var_hir_id, local_def_id);
+                    let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span);
+                    let info = ty::CaptureInfo { expr_id: None, capture_kind };
+
+                    capture_information.insert(place, info);
+                }
             }
         }
 
@@ -153,9 +147,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut delegate = InferBorrowKind {
             fcx: self,
             closure_def_id,
+            closure_span: span,
+            capture_clause,
             current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
             current_origin: None,
-            adjust_upvar_captures: ty::UpvarCaptureMap::default(),
+            capture_information,
         };
         euv::ExprUseVisitor::new(
             &mut delegate,
@@ -166,6 +162,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
         .consume_body(body);
 
+        debug!(
+            "For closure={:?}, capture_information={:#?}",
+            closure_def_id, delegate.capture_information
+        );
+        self.log_capture_analysis_first_pass(closure_def_id, &delegate.capture_information, span);
+
         if let Some(closure_substs) = infer_kind {
             // Unify the (as yet unbound) type variable in the closure
             // substs with the kind we inferred.
@@ -182,7 +184,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
-        self.typeck_results.borrow_mut().upvar_capture_map.extend(delegate.adjust_upvar_captures);
+        self.compute_min_captures(closure_def_id, delegate);
+        self.log_closure_min_capture_info(closure_def_id, span);
+
+        self.min_captures_to_closure_captures_bridge(closure_def_id);
 
         // Now that we've analyzed the closure, we know how each
         // variable is borrowed, and we know what traits the closure
@@ -226,15 +231,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
         let closure_def_id = tcx.hir().local_def_id(closure_id);
 
-        tcx.upvars_mentioned(closure_def_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 {
-                        var_path: ty::UpvarPath { hir_id: var_hir_id },
-                        closure_expr_id: closure_def_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);
@@ -250,6 +255,296 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             })
             .collect()
     }
+
+    /// Bridge for closure analysis
+    /// ----------------------------
+    ///
+    /// For closure with DefId `c`, the bridge converts structures required for supporting RFC 2229,
+    /// to structures currently used in the compiler for handling closure captures.
+    ///
+    /// For example the following structure will be converted:
+    ///
+    /// closure_min_captures
+    /// foo -> [ {foo.x, ImmBorrow}, {foo.y, MutBorrow} ]
+    /// bar -> [ {bar.z, ByValue}, {bar.q, MutBorrow} ]
+    ///
+    /// to
+    ///
+    /// 1. closure_captures
+    /// foo -> UpvarId(foo, c), bar -> UpvarId(bar, c)
+    ///
+    /// 2. upvar_capture_map
+    /// UpvarId(foo,c) -> MutBorrow, UpvarId(bar, c) -> ByValue
+    fn min_captures_to_closure_captures_bridge(&self, closure_def_id: DefId) {
+        let mut closure_captures: FxIndexMap<hir::HirId, ty::UpvarId> = Default::default();
+        let mut upvar_capture_map = ty::UpvarCaptureMap::default();
+
+        if let Some(min_captures) =
+            self.typeck_results.borrow().closure_min_captures.get(&closure_def_id)
+        {
+            for (var_hir_id, min_list) in min_captures.iter() {
+                for captured_place in min_list {
+                    let place = &captured_place.place;
+                    let capture_info = captured_place.info;
+
+                    let upvar_id = match place.base {
+                        PlaceBase::Upvar(upvar_id) => upvar_id,
+                        base => bug!("Expected upvar, found={:?}", base),
+                    };
+
+                    assert_eq!(upvar_id.var_path.hir_id, *var_hir_id);
+                    assert_eq!(upvar_id.closure_expr_id, closure_def_id.expect_local());
+
+                    closure_captures.insert(*var_hir_id, upvar_id);
+
+                    let new_capture_kind = if let Some(capture_kind) =
+                        upvar_capture_map.get(&upvar_id)
+                    {
+                        // upvar_capture_map only stores the UpvarCapture (CaptureKind),
+                        // so we create a fake capture info with no expression.
+                        let fake_capture_info =
+                            ty::CaptureInfo { expr_id: None, capture_kind: capture_kind.clone() };
+                        determine_capture_info(fake_capture_info, capture_info).capture_kind
+                    } else {
+                        capture_info.capture_kind
+                    };
+                    upvar_capture_map.insert(upvar_id, new_capture_kind);
+                }
+            }
+        }
+        debug!("For closure_def_id={:?}, closure_captures={:#?}", closure_def_id, closure_captures);
+        debug!(
+            "For closure_def_id={:?}, upvar_capture_map={:#?}",
+            closure_def_id, upvar_capture_map
+        );
+
+        if !closure_captures.is_empty() {
+            self.typeck_results
+                .borrow_mut()
+                .closure_captures
+                .insert(closure_def_id, closure_captures);
+
+            self.typeck_results.borrow_mut().upvar_capture_map.extend(upvar_capture_map);
+        }
+    }
+
+    /// Analyzes the information collected by `InferBorrowKind` to compute the min number of
+    /// Places (and corresponding capture kind) that we need to keep track of to support all
+    /// the required captured paths.
+    ///
+    /// Eg:
+    /// ```rust,no_run
+    /// struct Point { x: i32, y: i32 }
+    ///
+    /// let s: String;  // hir_id_s
+    /// let mut p: Point; // his_id_p
+    /// let c = || {
+    ///        println!("{}", s);  // L1
+    ///        p.x += 10;  // L2
+    ///        println!("{}" , p.y) // L3
+    ///        println!("{}", p) // L4
+    ///        drop(s);   // L5
+    /// };
+    /// ```
+    /// and let hir_id_L1..5 be the expressions pointing to use of a captured variable on
+    /// the lines L1..5 respectively.
+    ///
+    /// InferBorrowKind results in a structure like this:
+    ///
+    /// ```
+    /// {
+    ///       Place(base: hir_id_s, projections: [], ....) -> (hir_id_L5, ByValue),
+    ///       Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> (hir_id_L2, ByRef(MutBorrow))
+    ///       Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> (hir_id_L3, ByRef(ImmutBorrow))
+    ///       Place(base: hir_id_p, projections: [], ...) -> (hir_id_L4, ByRef(ImmutBorrow))
+    /// ```
+    ///
+    /// After the min capture analysis, we get:
+    /// ```
+    /// {
+    ///       hir_id_s -> [
+    ///            Place(base: hir_id_s, projections: [], ....) -> (hir_id_L4, ByValue)
+    ///       ],
+    ///       hir_id_p -> [
+    ///            Place(base: hir_id_p, projections: [], ...) -> (hir_id_L2, ByRef(MutBorrow)),
+    ///       ],
+    /// ```
+    fn compute_min_captures(
+        &self,
+        closure_def_id: DefId,
+        inferred_info: InferBorrowKind<'_, 'tcx>,
+    ) {
+        let mut root_var_min_capture_list: ty::RootVariableMinCaptureList<'_> = Default::default();
+
+        for (place, capture_info) in inferred_info.capture_information.into_iter() {
+            let var_hir_id = match place.base {
+                PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+                base => bug!("Expected upvar, found={:?}", base),
+            };
+
+            // Arrays are captured in entirety, drop Index projections and projections
+            // after Index projections.
+            let first_index_projection =
+                place.projections.split(|proj| ProjectionKind::Index == proj.kind).next();
+            let place = Place {
+                base_ty: place.base_ty,
+                base: place.base,
+                projections: first_index_projection.map_or(Vec::new(), |p| p.to_vec()),
+            };
+
+            let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
+                None => {
+                    let min_cap_list = vec![ty::CapturedPlace { place: place, info: capture_info }];
+                    root_var_min_capture_list.insert(var_hir_id, min_cap_list);
+                    continue;
+                }
+                Some(min_cap_list) => min_cap_list,
+            };
+
+            // Go through each entry in the current list of min_captures
+            // - if ancestor is found, update it's capture kind to account for current place's
+            // capture information.
+            //
+            // - if descendant is found, remove it from the list, and update the current place's
+            // capture information to account for the descendants's capture kind.
+            //
+            // We can never be in a case where the list contains both an ancestor and a descendant
+            // Also there can only be ancestor but in case of descendants there might be
+            // multiple.
+
+            let mut descendant_found = false;
+            let mut updated_capture_info = capture_info;
+            min_cap_list.retain(|possible_descendant| {
+                match determine_place_ancestry_relation(&place, &possible_descendant.place) {
+                    // current place is ancestor of possible_descendant
+                    PlaceAncestryRelation::Ancestor => {
+                        descendant_found = true;
+                        updated_capture_info =
+                            determine_capture_info(updated_capture_info, possible_descendant.info);
+                        false
+                    }
+
+                    _ => true,
+                }
+            });
+
+            let mut ancestor_found = false;
+            if !descendant_found {
+                for possible_ancestor in min_cap_list.iter_mut() {
+                    match determine_place_ancestry_relation(&place, &possible_ancestor.place) {
+                        // current place is descendant of possible_ancestor
+                        PlaceAncestryRelation::Descendant => {
+                            ancestor_found = true;
+                            possible_ancestor.info =
+                                determine_capture_info(possible_ancestor.info, capture_info);
+
+                            // Only one ancestor of the current place will be in the list.
+                            break;
+                        }
+                        _ => {}
+                    }
+                }
+            }
+
+            // Only need to insert when we don't have an ancestor in the existing min capture list
+            if !ancestor_found {
+                let captured_place =
+                    ty::CapturedPlace { place: place.clone(), info: updated_capture_info };
+                min_cap_list.push(captured_place);
+            }
+        }
+
+        debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list);
+
+        if !root_var_min_capture_list.is_empty() {
+            self.typeck_results
+                .borrow_mut()
+                .closure_min_captures
+                .insert(closure_def_id, root_var_min_capture_list);
+        }
+    }
+
+    fn init_capture_kind(
+        &self,
+        capture_clause: hir::CaptureBy,
+        upvar_id: ty::UpvarId,
+        closure_span: Span,
+    ) -> ty::UpvarCapture<'tcx> {
+        match capture_clause {
+            hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None),
+            hir::CaptureBy::Ref => {
+                let origin = UpvarRegion(upvar_id, closure_span);
+                let upvar_region = self.next_region_var(origin);
+                let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
+                ty::UpvarCapture::ByRef(upvar_borrow)
+            }
+        }
+    }
+
+    fn place_for_root_variable(
+        &self,
+        closure_def_id: LocalDefId,
+        var_hir_id: hir::HirId,
+    ) -> Place<'tcx> {
+        let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id);
+
+        Place {
+            base_ty: self.node_ty(var_hir_id),
+            base: PlaceBase::Upvar(upvar_id),
+            projections: Default::default(),
+        }
+    }
+
+    fn should_log_capture_analysis(&self, closure_def_id: DefId) -> bool {
+        self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis)
+    }
+
+    fn log_capture_analysis_first_pass(
+        &self,
+        closure_def_id: rustc_hir::def_id::DefId,
+        capture_information: &FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>,
+        closure_span: Span,
+    ) {
+        if self.should_log_capture_analysis(closure_def_id) {
+            let mut diag =
+                self.tcx.sess.struct_span_err(closure_span, "First Pass analysis includes:");
+            for (place, capture_info) in capture_information {
+                let capture_str = construct_capture_info_string(self.tcx, place, capture_info);
+                let output_str = format!("Capturing {}", capture_str);
+
+                let span = capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
+                diag.span_note(span, &output_str);
+            }
+            diag.emit();
+        }
+    }
+
+    fn log_closure_min_capture_info(&self, closure_def_id: DefId, closure_span: Span) {
+        if self.should_log_capture_analysis(closure_def_id) {
+            if let Some(min_captures) =
+                self.typeck_results.borrow().closure_min_captures.get(&closure_def_id)
+            {
+                let mut diag =
+                    self.tcx.sess.struct_span_err(closure_span, "Min Capture analysis includes:");
+
+                for (_, min_captures_for_var) in min_captures {
+                    for capture in min_captures_for_var {
+                        let place = &capture.place;
+                        let capture_info = &capture.info;
+
+                        let capture_str =
+                            construct_capture_info_string(self.tcx, place, capture_info);
+                        let output_str = format!("Min Capture {}", capture_str);
+
+                        let span =
+                            capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
+                        diag.span_note(span, &output_str);
+                    }
+                }
+                diag.emit();
+            }
+        }
+    }
 }
 
 struct InferBorrowKind<'a, 'tcx> {
@@ -258,6 +553,10 @@ struct InferBorrowKind<'a, 'tcx> {
     // The def-id of the closure whose kind and upvar accesses are being inferred.
     closure_def_id: DefId,
 
+    closure_span: Span,
+
+    capture_clause: hir::CaptureBy,
+
     // The kind that we have inferred that the current closure
     // requires. Note that we *always* infer a minimal kind, even if
     // we don't always *use* that in the final result (i.e., sometimes
@@ -270,9 +569,31 @@ struct InferBorrowKind<'a, 'tcx> {
     // variable access that caused us to do so.
     current_origin: Option<(Span, Symbol)>,
 
-    // For each upvar that we access, we track the minimal kind of
-    // access we need (ref, ref mut, move, etc).
-    adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>,
+    /// For each Place that is captured by the closure, we track the minimal kind of
+    /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
+    ///
+    /// Consider closure where s.str1 is captured via an ImmutableBorrow and
+    /// s.str2 via a MutableBorrow
+    ///
+    /// ```rust,no_run
+    /// struct SomeStruct { str1: String, str2: String }
+    ///
+    /// // Assume that the HirId for the variable definition is `V1`
+    /// let mut s = SomeStruct { str1: format!("s1"), str2: format!("s2") }
+    ///
+    /// let fix_s = |new_s2| {
+    ///     // Assume that the HirId for the expression `s.str1` is `E1`
+    ///     println!("Updating SomeStruct with str1=", s.str1);
+    ///     // Assume that the HirId for the expression `*s.str2` is `E2`
+    ///     s.str2 = new_s2;
+    /// };
+    /// ```
+    ///
+    /// For closure `fix_s`, (at a high level) the map contains
+    ///
+    /// Place { V1, [ProjectionKind::Field(Index=0, Variant=0)] } : CaptureKind { E1, ImmutableBorrow }
+    /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
+    capture_information: FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>,
 }
 
 impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
@@ -314,26 +635,15 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
             var_name(tcx, upvar_id.var_path.hir_id),
         );
 
-        let new_capture = ty::UpvarCapture::ByValue(Some(usage_span));
-        match self.adjust_upvar_captures.entry(upvar_id) {
-            Entry::Occupied(mut e) => {
-                match e.get() {
-                    // We always overwrite `ByRef`, since we require
-                    // that the upvar be available by value.
-                    //
-                    // If we had a previous by-value usage without a specific
-                    // span, use ours instead. Otherwise, keep the first span
-                    // we encountered, since there isn't an obviously better one.
-                    ty::UpvarCapture::ByRef(_) | ty::UpvarCapture::ByValue(None) => {
-                        e.insert(new_capture);
-                    }
-                    _ => {}
-                }
-            }
-            Entry::Vacant(e) => {
-                e.insert(new_capture);
-            }
-        }
+        let capture_info = ty::CaptureInfo {
+            expr_id: Some(diag_expr_id),
+            capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)),
+        };
+
+        let curr_info = self.capture_information[&place_with_id.place];
+        let updated_info = determine_capture_info(curr_info, capture_info);
+
+        self.capture_information[&place_with_id.place] = updated_info;
     }
 
     /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
@@ -349,7 +659,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
             place_with_id, diag_expr_id
         );
 
-        if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
+        if let PlaceBase::Upvar(_) = place_with_id.place.base {
             let mut borrow_kind = ty::MutBorrow;
             for pointer_ty in place_with_id.place.deref_tys() {
                 match pointer_ty.kind() {
@@ -363,7 +673,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
                     _ => (),
                 }
             }
-            self.adjust_upvar_deref(upvar_id, self.fcx.tcx.hir().span(diag_expr_id), borrow_kind);
+            self.adjust_upvar_deref(place_with_id, diag_expr_id, borrow_kind);
         }
     }
 
@@ -377,24 +687,20 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
             place_with_id, diag_expr_id
         );
 
-        if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
+        if let PlaceBase::Upvar(_) = place_with_id.place.base {
             if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
                 // Raw pointers don't inherit mutability.
                 return;
             }
             // for a borrowed pointer to be unique, its base must be unique
-            self.adjust_upvar_deref(
-                upvar_id,
-                self.fcx.tcx.hir().span(diag_expr_id),
-                ty::UniqueImmBorrow,
-            );
+            self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::UniqueImmBorrow);
         }
     }
 
     fn adjust_upvar_deref(
         &mut self,
-        upvar_id: ty::UpvarId,
-        place_span: Span,
+        place_with_id: &PlaceWithHirId<'tcx>,
+        diag_expr_id: hir::HirId,
         borrow_kind: ty::BorrowKind,
     ) {
         assert!(match borrow_kind {
@@ -411,15 +717,16 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
         // upvar, then we need to modify the
         // borrow_kind of the upvar to make sure it
         // is inferred to mutable if necessary
-        self.adjust_upvar_borrow_kind(upvar_id, borrow_kind);
+        self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind);
 
-        // also need to be in an FnMut closure since this is not an ImmBorrow
-        self.adjust_closure_kind(
-            upvar_id.closure_expr_id,
-            ty::ClosureKind::FnMut,
-            place_span,
-            var_name(tcx, upvar_id.var_path.hir_id),
-        );
+        if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
+            self.adjust_closure_kind(
+                upvar_id.closure_expr_id,
+                ty::ClosureKind::FnMut,
+                tcx.hir().span(diag_expr_id),
+                var_name(tcx, upvar_id.var_path.hir_id),
+            );
+        }
     }
 
     /// We infer the borrow_kind with which to borrow upvars in a stack closure.
@@ -427,37 +734,34 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
     /// moving from left to right as needed (but never right to left).
     /// Here the argument `mutbl` is the borrow_kind that is required by
     /// some particular use.
-    fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) {
-        let upvar_capture = self
-            .adjust_upvar_captures
-            .get(&upvar_id)
-            .copied()
-            .unwrap_or_else(|| self.fcx.typeck_results.borrow().upvar_capture(upvar_id));
+    fn adjust_upvar_borrow_kind(
+        &mut self,
+        place_with_id: &PlaceWithHirId<'tcx>,
+        diag_expr_id: hir::HirId,
+        kind: ty::BorrowKind,
+    ) {
+        let curr_capture_info = self.capture_information[&place_with_id.place];
+
         debug!(
-            "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
-            upvar_id, upvar_capture, kind
+            "adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})",
+            place_with_id, diag_expr_id, curr_capture_info, kind
         );
 
-        match upvar_capture {
-            ty::UpvarCapture::ByValue(_) => {
-                // Upvar is already by-value, the strongest criteria.
-            }
-            ty::UpvarCapture::ByRef(mut upvar_borrow) => {
-                match (upvar_borrow.kind, kind) {
-                    // Take RHS:
-                    (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow)
-                    | (ty::UniqueImmBorrow, ty::MutBorrow) => {
-                        upvar_borrow.kind = kind;
-                        self.adjust_upvar_captures
-                            .insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow));
-                    }
-                    // Take LHS:
-                    (ty::ImmBorrow, ty::ImmBorrow)
-                    | (ty::UniqueImmBorrow, ty::ImmBorrow | ty::UniqueImmBorrow)
-                    | (ty::MutBorrow, _) => {}
-                }
-            }
-        }
+        if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind {
+            // It's already captured by value, we don't need to do anything here
+            return;
+        } else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind {
+            // Use the same region as the current capture information
+            // Doesn't matter since only one of the UpvarBorrow will be used.
+            let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region };
+
+            let capture_info = ty::CaptureInfo {
+                expr_id: Some(diag_expr_id),
+                capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow),
+            };
+            let updated_info = determine_capture_info(curr_capture_info, capture_info);
+            self.capture_information[&place_with_id.place] = updated_info;
+        };
     }
 
     fn adjust_closure_kind(
@@ -501,6 +805,28 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
             }
         }
     }
+
+    fn init_capture_info_for_place(
+        &mut self,
+        place_with_id: &PlaceWithHirId<'tcx>,
+        diag_expr_id: hir::HirId,
+    ) {
+        if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
+            assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
+
+            let capture_kind =
+                self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span);
+
+            let expr_id = Some(diag_expr_id);
+            let capture_info = ty::CaptureInfo { expr_id, capture_kind };
+
+            debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info);
+
+            self.capture_information.insert(place_with_id.place.clone(), capture_info);
+        } else {
+            debug!("Not upvar: {:?}", place_with_id);
+        }
+    }
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
@@ -514,7 +840,11 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
             "consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})",
             place_with_id, diag_expr_id, mode
         );
-        self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id, mode);
+        if !self.capture_information.contains_key(&place_with_id.place) {
+            self.init_capture_info_for_place(place_with_id, diag_expr_id);
+        }
+
+        self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id, mode);
     }
 
     fn borrow(
@@ -528,6 +858,10 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
             place_with_id, diag_expr_id, bk
         );
 
+        if !self.capture_information.contains_key(&place_with_id.place) {
+            self.init_capture_info_for_place(place_with_id, diag_expr_id);
+        }
+
         match bk {
             ty::ImmBorrow => {}
             ty::UniqueImmBorrow => {
@@ -541,10 +875,175 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
 
     fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
         debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id);
+
+        if !self.capture_information.contains_key(&assignee_place.place) {
+            self.init_capture_info_for_place(assignee_place, diag_expr_id);
+        }
+
         self.adjust_upvar_borrow_kind_for_mut(assignee_place, diag_expr_id);
     }
 }
 
+fn construct_capture_info_string(
+    tcx: TyCtxt<'_>,
+    place: &Place<'tcx>,
+    capture_info: &ty::CaptureInfo<'tcx>,
+) -> String {
+    let variable_name = match place.base {
+        PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(),
+        _ => bug!("Capture_information should only contain upvars"),
+    };
+
+    let mut projections_str = String::new();
+    for (i, item) in place.projections.iter().enumerate() {
+        let proj = match item.kind {
+            ProjectionKind::Field(a, b) => format!("({:?}, {:?})", a, b),
+            ProjectionKind::Deref => String::from("Deref"),
+            ProjectionKind::Index => String::from("Index"),
+            ProjectionKind::Subslice => String::from("Subslice"),
+        };
+        if i != 0 {
+            projections_str.push_str(",");
+        }
+        projections_str.push_str(proj.as_str());
+    }
+
+    let capture_kind_str = match capture_info.capture_kind {
+        ty::UpvarCapture::ByValue(_) => "ByValue".into(),
+        ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
+    };
+    format!("{}[{}] -> {}", variable_name, projections_str, capture_kind_str)
+}
+
 fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
     tcx.hir().name(var_hir_id)
 }
+
+/// Helper function to determine if we need to escalate CaptureKind from
+/// CaptureInfo A to B and returns the escalated CaptureInfo.
+/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
+///
+/// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
+/// on the `CaptureInfo` containing an associated expression id.
+///
+/// If both the CaptureKind and Expression are considered to be equivalent,
+/// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
+/// expressions reported back to the user as part of diagnostics based on which appears earlier
+/// in the closure. This can be acheived simply by calling
+/// `determine_capture_info(existing_info, current_info)`. This works out because the
+/// expressions that occur earlier in the closure body than the current expression are processed before.
+/// Consider the following example
+/// ```rust,no_run
+/// struct Point { x: i32, y: i32 }
+/// let mut p: Point { x: 10, y: 10 };
+///
+/// let c = || {
+///     p.x     += 10;
+/// // ^ E1 ^
+///     // ...
+///     // More code
+///     // ...
+///     p.x += 10; // E2
+/// // ^ E2 ^
+/// };
+/// ```
+/// `CaptureKind` associated with both `E1` and `E2` will be ByRef(MutBorrow),
+/// and both have an expression associated, however for diagnostics we prefer reporting
+/// `E1` since it appears earlier in the closure body. When `E2` is being processed we
+/// would've already handled `E1`, and have an existing capture_information for it.
+/// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return
+/// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics.
+fn determine_capture_info(
+    capture_info_a: ty::CaptureInfo<'tcx>,
+    capture_info_b: ty::CaptureInfo<'tcx>,
+) -> ty::CaptureInfo<'tcx> {
+    // If the capture kind is equivalent then, we don't need to escalate and can compare the
+    // expressions.
+    let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
+        (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => {
+            // We don't need to worry about the spans being ignored here.
+            //
+            // The expr_id in capture_info corresponds to the span that is stored within
+            // ByValue(span) and therefore it gets handled with priortizing based on
+            // expressions below.
+            true
+        }
+        (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
+            ref_a.kind == ref_b.kind
+        }
+        (ty::UpvarCapture::ByValue(_), _) | (ty::UpvarCapture::ByRef(_), _) => false,
+    };
+
+    if eq_capture_kind {
+        match (capture_info_a.expr_id, capture_info_b.expr_id) {
+            (Some(_), _) | (None, None) => capture_info_a,
+            (None, Some(_)) => capture_info_b,
+        }
+    } else {
+        // We select the CaptureKind which ranks higher based the following priority order:
+        // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
+        match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
+            (ty::UpvarCapture::ByValue(_), _) => capture_info_a,
+            (_, ty::UpvarCapture::ByValue(_)) => capture_info_b,
+            (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
+                match (ref_a.kind, ref_b.kind) {
+                    // Take LHS:
+                    (ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow)
+                    | (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a,
+
+                    // Take RHS:
+                    (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow)
+                    | (ty::UniqueImmBorrow, ty::MutBorrow) => capture_info_b,
+
+                    (ty::ImmBorrow, ty::ImmBorrow)
+                    | (ty::UniqueImmBorrow, ty::UniqueImmBorrow)
+                    | (ty::MutBorrow, ty::MutBorrow) => {
+                        bug!("Expected unequal capture kinds");
+                    }
+                }
+            }
+        }
+    }
+}
+
+/// Determines the Ancestry relationship of Place A relative to Place B
+///
+/// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B
+/// `PlaceAncestryRelation::Descendant` implies Place A is descendant of Place B
+/// `PlaceAncestryRelation::Divergent` implies neither of them is the ancestor of the other.
+fn determine_place_ancestry_relation(
+    place_a: &Place<'tcx>,
+    place_b: &Place<'tcx>,
+) -> PlaceAncestryRelation {
+    // If Place A and Place B, don't start off from the same root variable, they are divergent.
+    if place_a.base != place_b.base {
+        return PlaceAncestryRelation::Divergent;
+    }
+
+    // Assume of length of projections_a = n
+    let projections_a = &place_a.projections;
+
+    // Assume of length of projections_b = m
+    let projections_b = &place_b.projections;
+
+    let mut same_initial_projections = true;
+
+    for (proj_a, proj_b) in projections_a.iter().zip(projections_b.iter()) {
+        if proj_a != proj_b {
+            same_initial_projections = false;
+            break;
+        }
+    }
+
+    if same_initial_projections {
+        // First min(n, m) projections are the same
+        // Select Ancestor/Descendant
+        if projections_b.len() >= projections_a.len() {
+            PlaceAncestryRelation::Ancestor
+        } else {
+            PlaceAncestryRelation::Descendant
+        }
+    } else {
+        PlaceAncestryRelation::Divergent
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 1e27357ce44..5dffe5107b5 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -403,12 +403,12 @@ fn check_associated_item(
         match item.kind {
             ty::AssocKind::Const => {
                 let ty = fcx.tcx.type_of(item.def_id);
-                let ty = fcx.normalize_associated_types_in(span, &ty);
+                let ty = fcx.normalize_associated_types_in(span, ty);
                 fcx.register_wf_obligation(ty.into(), span, code.clone());
             }
             ty::AssocKind::Fn => {
                 let sig = fcx.tcx.fn_sig(item.def_id);
-                let sig = fcx.normalize_associated_types_in(span, &sig);
+                let sig = fcx.normalize_associated_types_in(span, sig);
                 let hir_sig = sig_if_method.expect("bad signature for method");
                 check_fn_or_method(
                     tcx,
@@ -427,7 +427,7 @@ fn check_associated_item(
                 }
                 if item.defaultness.has_value() {
                     let ty = fcx.tcx.type_of(item.def_id);
-                    let ty = fcx.normalize_associated_types_in(span, &ty);
+                    let ty = fcx.normalize_associated_types_in(span, ty);
                     fcx.register_wf_obligation(ty.into(), span, code.clone());
                 }
             }
@@ -480,7 +480,7 @@ fn check_type_defn<'tcx, F>(
             let needs_drop_copy = || {
                 packed && {
                     let ty = variant.fields.last().unwrap().ty;
-                    let ty = fcx.tcx.erase_regions(&ty);
+                    let ty = fcx.tcx.erase_regions(ty);
                     if ty.needs_infer() {
                         fcx_tcx
                             .sess
@@ -592,7 +592,7 @@ fn check_associated_type_bounds(fcx: &FnCtxt<'_, '_>, item: &ty::AssocItem, span
 
     debug!("check_associated_type_bounds: bounds={:?}", bounds);
     let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
-        let normalized_bound = fcx.normalize_associated_types_in(span, &bound);
+        let normalized_bound = fcx.normalize_associated_types_in(span, bound);
         traits::wf::predicate_obligations(
             fcx,
             fcx.param_env,
@@ -618,7 +618,7 @@ fn check_item_fn(
     for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
         let def_id = fcx.tcx.hir().local_def_id(item_id);
         let sig = fcx.tcx.fn_sig(def_id);
-        let sig = fcx.normalize_associated_types_in(span, &sig);
+        let sig = fcx.normalize_associated_types_in(span, sig);
         let mut implied_bounds = vec![];
         check_fn_or_method(
             tcx,
@@ -638,7 +638,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo
 
     for_id(tcx, item_id, ty_span).with_fcx(|fcx, tcx| {
         let ty = tcx.type_of(tcx.hir().local_def_id(item_id));
-        let item_ty = fcx.normalize_associated_types_in(ty_span, &ty);
+        let item_ty = fcx.normalize_associated_types_in(ty_span, ty);
 
         let mut forbid_unsized = true;
         if allow_foreign_ty {
@@ -680,7 +680,7 @@ fn check_impl<'tcx>(
                 // won't hold).
                 let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
                 let trait_ref =
-                    fcx.normalize_associated_types_in(ast_trait_ref.path.span, &trait_ref);
+                    fcx.normalize_associated_types_in(ast_trait_ref.path.span, trait_ref);
                 let obligations = traits::wf::trait_obligations(
                     fcx,
                     fcx.param_env,
@@ -695,7 +695,7 @@ fn check_impl<'tcx>(
             }
             None => {
                 let self_ty = fcx.tcx.type_of(item_def_id);
-                let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty);
+                let self_ty = fcx.normalize_associated_types_in(item.span, self_ty);
                 fcx.register_wf_obligation(
                     self_ty.into(),
                     ast_self_ty.span,
@@ -800,18 +800,20 @@ fn check_where_clauses<'tcx, 'fcx>(
                 params: FxHashSet<u32>,
             }
             impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
-                fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+                type BreakTy = ();
+
+                fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                     if let ty::Param(param) = t.kind() {
                         self.params.insert(param.index);
                     }
                     t.super_visit_with(self)
                 }
 
-                fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<()> {
+                fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                     ControlFlow::BREAK
                 }
 
-                fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
+                fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                     if let ty::ConstKind::Param(param) = c.val {
                         self.params.insert(param.index);
                     }
@@ -845,7 +847,7 @@ fn check_where_clauses<'tcx, 'fcx>(
             // Note the subtle difference from how we handle `predicates`
             // below: there, we are not trying to prove those predicates
             // to be *true* but merely *well-formed*.
-            let pred = fcx.normalize_associated_types_in(sp, &pred);
+            let pred = fcx.normalize_associated_types_in(sp, pred);
             let cause =
                 traits::ObligationCause::new(sp, fcx.body_id, traits::ItemObligation(def_id));
             traits::Obligation::new(cause, fcx.param_env, pred)
@@ -856,12 +858,12 @@ fn check_where_clauses<'tcx, 'fcx>(
     if let Some((mut return_ty, span)) = return_ty {
         if return_ty.has_infer_types_or_consts() {
             fcx.select_obligations_where_possible(false, |_| {});
-            return_ty = fcx.resolve_vars_if_possible(&return_ty);
+            return_ty = fcx.resolve_vars_if_possible(return_ty);
         }
         check_opaque_types(tcx, fcx, def_id.expect_local(), span, return_ty);
     }
 
-    let predicates = fcx.normalize_associated_types_in(span, &predicates);
+    let predicates = fcx.normalize_associated_types_in(span, predicates);
 
     debug!("check_where_clauses: predicates={:?}", predicates.predicates);
     assert_eq!(predicates.predicates.len(), predicates.spans.len());
@@ -885,8 +887,8 @@ fn check_fn_or_method<'fcx, 'tcx>(
     def_id: DefId,
     implied_bounds: &mut Vec<Ty<'tcx>>,
 ) {
-    let sig = fcx.normalize_associated_types_in(span, &sig);
-    let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
+    let sig = fcx.normalize_associated_types_in(span, sig);
+    let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
 
     for (&input_ty, span) in sig.inputs().iter().zip(hir_decl.inputs.iter().map(|t| t.span)) {
         fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation);
@@ -1063,19 +1065,19 @@ fn check_method_receiver<'fcx, 'tcx>(
     let span = fn_sig.decl.inputs[0].span;
 
     let sig = fcx.tcx.fn_sig(method.def_id);
-    let sig = fcx.normalize_associated_types_in(span, &sig);
-    let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, &sig);
+    let sig = fcx.normalize_associated_types_in(span, sig);
+    let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, sig);
 
     debug!("check_method_receiver: sig={:?}", sig);
 
-    let self_ty = fcx.normalize_associated_types_in(span, &self_ty);
-    let self_ty = fcx.tcx.liberate_late_bound_regions(method.def_id, &ty::Binder::bind(self_ty));
+    let self_ty = fcx.normalize_associated_types_in(span, self_ty);
+    let self_ty = fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(self_ty));
 
     let receiver_ty = sig.inputs()[0];
 
-    let receiver_ty = fcx.normalize_associated_types_in(span, &receiver_ty);
+    let receiver_ty = fcx.normalize_associated_types_in(span, receiver_ty);
     let receiver_ty =
-        fcx.tcx.liberate_late_bound_regions(method.def_id, &ty::Binder::bind(receiver_ty));
+        fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(receiver_ty));
 
     if fcx.tcx.features().arbitrary_self_types {
         if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
@@ -1307,7 +1309,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) {
         let pred = obligation.predicate;
         // Match the existing behavior.
         if pred.is_global() && !pred.has_late_bound_regions() {
-            let pred = fcx.normalize_associated_types_in(span, &pred);
+            let pred = fcx.normalize_associated_types_in(span, pred);
             let obligation = traits::Obligation::new(
                 traits::ObligationCause::new(span, id, traits::TrivialBound),
                 empty_env,
@@ -1405,8 +1407,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .iter()
             .map(|field| {
                 let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id));
-                let field_ty = self.normalize_associated_types_in(field.ty.span, &field_ty);
-                let field_ty = self.resolve_vars_if_possible(&field_ty);
+                let field_ty = self.normalize_associated_types_in(field.ty.span, field_ty);
+                let field_ty = self.resolve_vars_if_possible(field_ty);
                 debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
                 AdtField { ty: field_ty, span: field.ty.span }
             })
@@ -1429,7 +1431,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub(super) fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
         match self.tcx.impl_trait_ref(impl_def_id) {
-            Some(ref trait_ref) => {
+            Some(trait_ref) => {
                 // Trait impl: take implied bounds from all types that
                 // appear in the trait reference.
                 let trait_ref = self.normalize_associated_types_in(span, trait_ref);
@@ -1439,7 +1441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             None => {
                 // Inherent impl: take implied bounds from the `self` type.
                 let self_ty = self.tcx.type_of(impl_def_id);
-                let self_ty = self.normalize_associated_types_in(span, &self_ty);
+                let self_ty = self.normalize_associated_types_in(span, self_ty);
                 vec![self_ty]
             }
         }
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 5363702a5be..335f2cc2716 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -70,6 +70,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
         wbcx.typeck_results.used_trait_imports = used_trait_imports;
 
+        wbcx.typeck_results.treat_byte_string_as_slice =
+            mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice);
+
         wbcx.typeck_results.closure_captures =
             mem::take(&mut self.typeck_results.borrow_mut().closure_captures);
 
@@ -136,7 +139,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         match e.kind {
             hir::ExprKind::Unary(hir::UnOp::UnNeg | hir::UnOp::UnNot, ref inner) => {
                 let inner_ty = self.fcx.node_ty(inner.hir_id);
-                let inner_ty = self.fcx.resolve_vars_if_possible(&inner_ty);
+                let inner_ty = self.fcx.resolve_vars_if_possible(inner_ty);
 
                 if inner_ty.is_scalar() {
                     let mut typeck_results = self.fcx.typeck_results.borrow_mut();
@@ -147,10 +150,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             hir::ExprKind::Binary(ref op, ref lhs, ref rhs)
             | hir::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
                 let lhs_ty = self.fcx.node_ty(lhs.hir_id);
-                let lhs_ty = self.fcx.resolve_vars_if_possible(&lhs_ty);
+                let lhs_ty = self.fcx.resolve_vars_if_possible(lhs_ty);
 
                 let rhs_ty = self.fcx.node_ty(rhs.hir_id);
-                let rhs_ty = self.fcx.resolve_vars_if_possible(&rhs_ty);
+                let rhs_ty = self.fcx.resolve_vars_if_possible(rhs_ty);
 
                 if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
                     let mut typeck_results = self.fcx.typeck_results.borrow_mut();
@@ -209,7 +212,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                         &format!("bad index {:?} for base: `{:?}`", index, base),
                     )
                 });
-                let index_ty = self.fcx.resolve_vars_if_possible(&index_ty);
+                let index_ty = self.fcx.resolve_vars_if_possible(index_ty);
 
                 if base_ty.builtin_index().is_some() && index_ty == self.fcx.tcx.types.usize {
                     // Remove the method call record
@@ -313,14 +316,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
     fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
         intravisit::walk_local(self, l);
         let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty;
-        let var_ty = self.resolve(&var_ty, &l.span);
+        let var_ty = self.resolve(var_ty, &l.span);
         self.write_ty_to_typeck_results(l.hir_id, var_ty);
     }
 
     fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
         intravisit::walk_ty(self, hir_ty);
         let ty = self.fcx.node_ty(hir_ty.hir_id);
-        let ty = self.resolve(&ty, &hir_ty.span);
+        let ty = self.resolve(ty, &hir_ty.span);
         self.write_ty_to_typeck_results(hir_ty.hir_id, ty);
     }
 }
@@ -432,7 +435,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     fn visit_opaque_types(&mut self, span: Span) {
         for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
             let hir_id = self.tcx().hir().local_def_id_to_hir_id(def_id.expect_local());
-            let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id);
+            let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
 
             debug_assert!(!instantiated_ty.has_escaping_bound_vars());
 
@@ -522,13 +525,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
         // Resolve the type of the node with id `node_id`
         let n_ty = self.fcx.node_ty(hir_id);
-        let n_ty = self.resolve(&n_ty, &span);
+        let n_ty = self.resolve(n_ty, &span);
         self.write_ty_to_typeck_results(hir_id, n_ty);
         debug!("node {:?} has type {:?}", hir_id, n_ty);
 
         // Resolve any substitutions
         if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) {
-            let substs = self.resolve(&substs, &span);
+            let substs = self.resolve(substs, &span);
             debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs);
             assert!(!substs.needs_infer() && !substs.has_placeholders());
             self.typeck_results.node_substs_mut().insert(hir_id, substs);
@@ -543,7 +546,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             }
 
             Some(adjustment) => {
-                let resolved_adjustment = self.resolve(&adjustment, &span);
+                let resolved_adjustment = self.resolve(adjustment, &span);
                 debug!("adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
                 self.typeck_results.adjustments_mut().insert(hir_id, resolved_adjustment);
             }
@@ -558,7 +561,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             }
 
             Some(adjustment) => {
-                let resolved_adjustment = self.resolve(&adjustment, &span);
+                let resolved_adjustment = self.resolve(adjustment, &span);
                 debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
                 self.typeck_results.pat_adjustments_mut().insert(hir_id, resolved_adjustment);
             }
@@ -570,7 +573,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
         let common_hir_owner = fcx_typeck_results.hir_owner;
 
-        for (&local_id, fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() {
+        for (&local_id, &fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() {
             let hir_id = hir::HirId { owner: common_hir_owner, local_id };
             let fn_sig = self.resolve(fn_sig, &hir_id);
             self.typeck_results.liberated_fn_sigs_mut().insert(hir_id, fn_sig);
@@ -584,12 +587,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
         for (&local_id, ftys) in fcx_typeck_results.fru_field_types().iter() {
             let hir_id = hir::HirId { owner: common_hir_owner, local_id };
-            let ftys = self.resolve(ftys, &hir_id);
+            let ftys = self.resolve(ftys.clone(), &hir_id);
             self.typeck_results.fru_field_types_mut().insert(hir_id, ftys);
         }
     }
 
-    fn resolve<T>(&mut self, x: &T, span: &dyn Locatable) -> T
+    fn resolve<T>(&mut self, x: T, span: &dyn Locatable) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -681,8 +684,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match self.infcx.fully_resolve(&t) {
-            Ok(t) => self.infcx.tcx.erase_regions(&t),
+        match self.infcx.fully_resolve(t) {
+            Ok(t) => self.infcx.tcx.erase_regions(t),
             Err(_) => {
                 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
                 self.report_type_error(t);
@@ -698,8 +701,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
     }
 
     fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        match self.infcx.fully_resolve(&ct) {
-            Ok(ct) => self.infcx.tcx.erase_regions(&ct),
+        match self.infcx.fully_resolve(ct) {
+            Ok(ct) => self.infcx.tcx.erase_regions(ct),
             Err(_) => {
                 debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
                 self.report_const_error(ct);
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index b431de90369..dee0e6c2ebb 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -386,7 +386,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
                                         "{}::{}",
                                         // Replace the existing lifetimes with a new named lifetime.
                                         self.tcx
-                                            .replace_late_bound_regions(&poly_trait_ref, |_| {
+                                            .replace_late_bound_regions(poly_trait_ref, |_| {
                                                 self.tcx.mk_region(ty::ReEarlyBound(
                                                     ty::EarlyBoundRegion {
                                                         def_id: item_def_id,
@@ -424,7 +424,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
                         format!(
                             "{}::{}",
                             // Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
-                            self.tcx.anonymize_late_bound_regions(&poly_trait_ref).skip_binder(),
+                            self.tcx.anonymize_late_bound_regions(poly_trait_ref).skip_binder(),
                             item_segment.ident
                         ),
                         Applicability::MaybeIncorrect,
@@ -2062,7 +2062,7 @@ fn const_evaluatable_predicates_of<'tcx>(
             }
 
             impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> {
-                fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<()> {
+                fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                     if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
                         self.preds.insert((
                             ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 61d1efc837b..c4f4c8bc76b 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -637,7 +637,7 @@ fn infer_placeholder_type(
     }
 
     // Typeck doesn't expect erased regions to be returned from `type_of`.
-    tcx.fold_regions(&ty, &mut false, |r, _| match r {
+    tcx.fold_regions(ty, &mut false, |r, _| match r {
         ty::ReErased => tcx.lifetimes.re_static,
         _ => r,
     })
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index bae5bde7002..e389fd4d9f0 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -57,7 +57,7 @@ struct ParameterCollector {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *t.kind() {
             ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => {
                 // projections are not injective
@@ -72,14 +72,14 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
         t.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         if let ty::ReEarlyBound(data) = *r {
             self.parameters.push(Parameter::from(data));
         }
         ControlFlow::CONTINUE
     }
 
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
+    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         match c.val {
             ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => {
                 // Constant expressions are not injective
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 57bd89b9d3d..1b51d5e0182 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -15,10 +15,10 @@ 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;
-use rustc_span::Span;
 
 ///////////////////////////////////////////////////////////////////////////
 // The Delegate trait
@@ -73,6 +73,7 @@ pub enum MutateMode {
 // This is the code that actually walks the tree.
 pub struct ExprUseVisitor<'a, 'tcx> {
     mc: mc::MemCategorizationContext<'a, 'tcx>,
+    body_owner: LocalDefId,
     delegate: &'a mut dyn Delegate<'tcx>,
 }
 
@@ -110,6 +111,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
     ) -> Self {
         ExprUseVisitor {
             mc: mc::MemCategorizationContext::new(infcx, param_env, body_owner, typeck_results),
+            body_owner,
             delegate,
         }
     }
@@ -329,8 +331,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 self.consume_expr(base);
             }
 
-            hir::ExprKind::Closure(_, _, _, fn_decl_span, _) => {
-                self.walk_captures(expr, fn_decl_span);
+            hir::ExprKind::Closure(..) => {
+                self.walk_captures(expr);
             }
 
             hir::ExprKind::Box(ref base) => {
@@ -529,7 +531,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
 
         let tcx = self.tcx();
-        let ExprUseVisitor { ref mc, ref mut delegate } = *self;
+        let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
         return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
             if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
                 debug!("walk_pat: binding place={:?} pat={:?}", place, pat,);
@@ -569,36 +571,112 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         }));
     }
 
-    fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>, fn_decl_span: Span) {
+    /// 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
+    /// - The parent closure only captures Places from the nested closure that are not local to it.
+    ///
+    /// In the following example the closures `c` only captures `p.x`` even though `incr`
+    /// is a capture of the nested closure
+    ///
+    /// ```rust,ignore(cannot-test-this-because-pseduo-code)
+    /// let p = ..;
+    /// let c = || {
+    ///    let incr = 10;
+    ///    let nested = || p.x += incr;
+    /// }
+    /// ```
+    ///
+    /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
+    /// closure as the DefId.
+    fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
         debug!("walk_captures({:?})", closure_expr);
 
-        let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id);
-        if let Some(upvars) = self.tcx().upvars_mentioned(closure_def_id) {
-            for &var_id in upvars.keys() {
-                let upvar_id = ty::UpvarId {
-                    var_path: ty::UpvarPath { hir_id: var_id },
-                    closure_expr_id: closure_def_id,
-                };
-                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,
-                    fn_decl_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,
-                        );
+        let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
+        let upvars = self.tcx().upvars_mentioned(self.body_owner);
+
+        // For purposes of this function, generator and closures are equivalent.
+        let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() {
+            ty::Closure(..) | ty::Generator(..) => true,
+            _ => false,
+        };
+
+        if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
+        {
+            for (var_hir_id, min_list) in min_captures.iter() {
+                if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) {
+                    // The nested closure might be capturing the current (enclosing) closure's local variables.
+                    // We check if the root variable is ever mentioned within the enclosing closure, if not
+                    // then for the current body (if it's a closure) these aren't captures, we will ignore them.
+                    continue;
+                }
+                for captured_place in min_list {
+                    let place = &captured_place.place;
+                    let capture_info = captured_place.info;
+
+                    let upvar_id = if body_owner_is_closure {
+                        // Mark the place to be captured by the enclosing closure
+                        ty::UpvarId::new(*var_hir_id, self.body_owner)
+                    } else {
+                        ty::UpvarId::new(*var_hir_id, closure_def_id.expect_local())
+                    };
+                    let place_with_id = PlaceWithHirId::new(
+                        capture_info.expr_id.unwrap_or(closure_expr.hir_id),
+                        place.base_ty,
+                        PlaceBase::Upvar(upvar_id),
+                        place.projections.clone(),
+                    );
+
+                    match capture_info.capture_kind {
+                        ty::UpvarCapture::ByValue(_) => {
+                            let mode = copy_or_move(&self.mc, &place_with_id);
+                            self.delegate.consume(&place_with_id, place_with_id.hir_id, mode);
+                        }
+                        ty::UpvarCapture::ByRef(upvar_borrow) => {
+                            self.delegate.borrow(
+                                &place_with_id,
+                                place_with_id.hir_id,
+                                upvar_borrow.kind,
+                            );
+                        }
                     }
                 }
             }
+        } 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)
         }
     }
 
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index 4cf3efcf513..5db9ff9524d 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -165,7 +165,7 @@ fn get_impl_substs<'tcx>(
     // Conservatively use an empty `ParamEnv`.
     let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
     infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env, RegionckMode::default());
-    let impl2_substs = match infcx.fully_resolve(&impl2_substs) {
+    let impl2_substs = match infcx.fully_resolve(impl2_substs) {
         Ok(s) => s,
         Err(_) => {
             tcx.sess.struct_span_err(span, "could not resolve substs on overridden impl").emit();
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 30904091c1b..929c88455f0 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -61,6 +61,7 @@ This API is completely unstable and subject to change.
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
+#![feature(is_sorted)]
 #![feature(nll)]
 #![feature(or_patterns)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index f6ac7aa9155..9992094117d 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -124,7 +124,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
     }
 
-    fn resolve_vars_if_possible<T>(&self, value: &T) -> T
+    fn resolve_vars_if_possible<T>(&self, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -142,7 +142,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     ) -> McResult<Ty<'tcx>> {
         match ty {
             Some(ty) => {
-                let ty = self.resolve_vars_if_possible(&ty);
+                let ty = self.resolve_vars_if_possible(ty);
                 if ty.references_error() || ty.is_ty_var() {
                     debug!("resolve_type_vars_or_error: error from {:?}", ty);
                     Err(())
@@ -274,7 +274,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
     {
         debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
-        let target = self.resolve_vars_if_possible(&adjustment.target);
+        let target = self.resolve_vars_if_possible(adjustment.target);
         match adjustment.kind {
             adjustment::Adjust::Deref(overloaded) => {
                 // Equivalent to *expr or something similar.