about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_arena/src/tests.rs16
-rw-r--r--compiler/rustc_ast/src/ast.rs2
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs9
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs3
-rw-r--r--compiler/rustc_ast/src/visit.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs32
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs164
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs181
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs118
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs54
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs8
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs224
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/utils.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/config.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs30
-rw-r--r--compiler/rustc_driver/src/lib.rs9
-rw-r--r--compiler/rustc_errors/src/emitter.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs51
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs63
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs4
-rw-r--r--compiler/rustc_interface/src/interface.rs2
-rw-r--r--compiler/rustc_interface/src/queries.rs6
-rw-r--r--compiler/rustc_interface/src/util.rs7
-rw-r--r--compiler/rustc_lexer/src/unescape/tests.rs6
-rw-r--r--compiler/rustc_lint/src/context.rs17
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs92
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs46
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp2
-rw-r--r--compiler/rustc_metadata/src/creader.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs168
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs48
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs13
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs35
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs12
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs16
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs4
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs12
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs12
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs13
-rw-r--r--compiler/rustc_parse/src/parser/item.rs38
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs12
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs16
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs6
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs6
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs9
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs2
-rw-r--r--compiler/rustc_session/src/config.rs4
-rw-r--r--compiler/rustc_session/src/session.rs4
-rw-r--r--compiler/rustc_span/src/lib.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs17
-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.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs23
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs29
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs28
-rw-r--r--src/bootstrap/builder.rs8
-rw-r--r--src/bootstrap/doc.rs21
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css2
-rw-r--r--src/test/codegen/issue-37945.rs4
-rw-r--r--src/test/codegen/mem-replace-direct-memcpy.rs4
-rw-r--r--src/test/codegen/slice-iter-len-eq-zero.rs2
-rw-r--r--src/test/run-make/rustdoc-verify-output-files/Makefile36
-rw-r--r--src/test/run-make/rustdoc-verify-output-files/src/lib.rs1
-rw-r--r--src/test/rustdoc-gui/src/test_docs/lib.rs5
-rw-r--r--src/test/rustdoc-gui/struct-fields.goml5
-rw-r--r--src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs106
-rw-r--r--src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr62
-rw-r--r--src/test/ui/binding/issue-53114-borrow-checks.stderr16
-rw-r--r--src/test/ui/binop/binop-move-semantics.stderr4
-rw-r--r--src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr25
-rw-r--r--src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr12
-rw-r--r--src/test/ui/borrowck/borrowck-consume-upcast-box.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-drop-from-guard.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr40
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr36
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr56
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr36
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr56
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array.stderr40
-rw-r--r--src/test/ui/borrowck/borrowck-multiple-captures.stderr15
-rw-r--r--src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-reinit.stderr5
-rw-r--r--src/test/ui/borrowck/issue-31287-drop-in-guard.stderr5
-rw-r--r--src/test/ui/borrowck/issue-41962.stderr2
-rw-r--r--src/test/ui/borrowck/issue-83760.stderr4
-rw-r--r--src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr2
-rw-r--r--src/test/ui/borrowck/move-in-pattern-mut.stderr4
-rw-r--r--src/test/ui/borrowck/move-in-pattern.stderr4
-rw-r--r--src/test/ui/borrowck/mut-borrow-in-loop-2.stderr8
-rw-r--r--src/test/ui/borrowck/or-patterns.stderr16
-rw-r--r--src/test/ui/codemap_tests/tab_3.stderr4
-rw-r--r--src/test/ui/drop/repeat-drop-2.stderr5
-rw-r--r--src/test/ui/dyn-star/dispatch-on-pin-mut.rs52
-rw-r--r--src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout1
-rw-r--r--src/test/ui/dyn-star/dispatch-on-pin-mut.stderr11
-rw-r--r--src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs5
-rw-r--r--src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout2
-rw-r--r--src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr11
-rw-r--r--src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs13
-rw-r--r--src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr23
-rw-r--r--src/test/ui/dyn-star/upcast.rs3
-rw-r--r--src/test/ui/dyn-star/upcast.stderr20
-rw-r--r--src/test/ui/issues/issue-23122-2.rs1
-rw-r--r--src/test/ui/issues/issue-23122-2.stderr10
-rw-r--r--src/test/ui/issues/issue-29723.stderr5
-rw-r--r--src/test/ui/issues/issue-42796.stderr4
-rw-r--r--src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr20
-rw-r--r--src/test/ui/liveness/liveness-move-call-arg.stderr16
-rw-r--r--src/test/ui/liveness/liveness-move-in-loop.stderr14
-rw-r--r--src/test/ui/liveness/liveness-move-in-while.stderr12
-rw-r--r--src/test/ui/liveness/liveness-use-after-move.stderr4
-rw-r--r--src/test/ui/liveness/liveness-use-after-send.stderr9
-rw-r--r--src/test/ui/moves/borrow-closures-instead-of-move.stderr15
-rw-r--r--src/test/ui/moves/issue-46099-move-in-macro.stderr5
-rw-r--r--src/test/ui/moves/issue-72649-uninit-in-loop.rs6
-rw-r--r--src/test/ui/moves/issue-72649-uninit-in-loop.stderr10
-rw-r--r--src/test/ui/moves/move-fn-self-receiver.stderr10
-rw-r--r--src/test/ui/moves/move-guard-same-consts.stderr12
-rw-r--r--src/test/ui/moves/move-in-guard-1.stderr12
-rw-r--r--src/test/ui/moves/move-in-guard-2.stderr12
-rw-r--r--src/test/ui/moves/moves-based-on-type-access-to-field.stderr4
-rw-r--r--src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr2
-rw-r--r--src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr10
-rw-r--r--src/test/ui/moves/moves-based-on-type-exprs.stderr60
-rw-r--r--src/test/ui/moves/moves-based-on-type-match-bindings.stderr4
-rw-r--r--src/test/ui/moves/moves-based-on-type-tuple.stderr5
-rw-r--r--src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr5
-rw-r--r--src/test/ui/nll/closure-access-spans.stderr10
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-use.stderr24
-rw-r--r--src/test/ui/nll/issue-51512.stderr5
-rw-r--r--src/test/ui/nll/issue-53807.stderr2
-rw-r--r--src/test/ui/nll/match-cfg-fake-edges.stderr5
-rw-r--r--src/test/ui/nll/ref-suggestion.stderr12
-rw-r--r--src/test/ui/parser/issue-104620.rs4
-rw-r--r--src/test/ui/parser/issue-104620.stderr8
-rw-r--r--src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr14
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr31
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr4
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr5
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr148
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr25
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr20
-rw-r--r--src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr4
-rw-r--r--src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr10
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr4
-rw-r--r--src/test/ui/recursion/issue-83150.stderr4
-rw-r--r--src/test/ui/recursion/issue-95134.rs4
-rw-r--r--src/test/ui/recursion/issue-95134.stderr7
-rw-r--r--src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr6
-rw-r--r--src/test/ui/stats/hir-stats.rs1
-rw-r--r--src/test/ui/stats/hir-stats.stderr20
-rw-r--r--src/test/ui/structs-enums/type-sizes.rs21
-rw-r--r--src/test/ui/suggestions/borrow-for-loop-head.stderr1
-rw-r--r--src/test/ui/suggestions/ref-pattern-binding.fixed19
-rw-r--r--src/test/ui/suggestions/ref-pattern-binding.rs19
-rw-r--r--src/test/ui/suggestions/ref-pattern-binding.stderr107
-rw-r--r--src/test/ui/track-diagnostics/track2.stderr5
-rw-r--r--src/test/ui/traits/predicate_can_apply-hang.rs6
-rw-r--r--src/test/ui/traits/predicate_can_apply-hang.stderr21
-rw-r--r--src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs6
-rw-r--r--src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr11
-rw-r--r--src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr4
-rw-r--r--src/test/ui/typeck/hang-in-overflow.rs19
-rw-r--r--src/test/ui/typeck/hang-in-overflow.stderr22
-rw-r--r--src/test/ui/union/union-move.mirunsafeck.stderr16
-rw-r--r--src/test/ui/union/union-move.thirunsafeck.stderr16
-rw-r--r--src/test/ui/unop-move-semantics.stderr4
-rw-r--r--src/test/ui/unsized-locals/borrow-after-move.stderr13
-rw-r--r--src/test/ui/unsized-locals/double-move.stderr8
-rw-r--r--src/test/ui/use/use-after-move-based-on-type.stderr4
-rw-r--r--src/test/ui/use/use-after-move-implicity-coerced-object.stderr8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs19
-rw-r--r--src/tools/rustfmt/src/expr.rs2
204 files changed, 2751 insertions, 956 deletions
diff --git a/compiler/rustc_arena/src/tests.rs b/compiler/rustc_arena/src/tests.rs
index ad61464343a..49a070badc6 100644
--- a/compiler/rustc_arena/src/tests.rs
+++ b/compiler/rustc_arena/src/tests.rs
@@ -52,19 +52,15 @@ fn test_arena_alloc_nested() {
 
     impl<'a> Wrap<'a> {
         fn alloc_inner<F: Fn() -> Inner>(&self, f: F) -> &Inner {
-            let r: &EI<'_> = self.0.alloc(EI::I(f()));
-            if let &EI::I(ref i) = r {
-                i
-            } else {
-                panic!("mismatch");
+            match self.0.alloc(EI::I(f())) {
+                EI::I(i) => i,
+                _ => panic!("mismatch"),
             }
         }
         fn alloc_outer<F: Fn() -> Outer<'a>>(&self, f: F) -> &Outer<'_> {
-            let r: &EI<'_> = self.0.alloc(EI::O(f()));
-            if let &EI::O(ref o) = r {
-                o
-            } else {
-                panic!("mismatch");
+            match self.0.alloc(EI::O(f())) {
+                EI::O(o) => o,
+                _ => panic!("mismatch"),
             }
         }
     }
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 54bd25d6471..28072f153a4 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1376,7 +1376,7 @@ pub enum ExprKind {
     /// Conditionless loop (can be exited with `break`, `continue`, or `return`).
     ///
     /// `'label: loop { block }`
-    Loop(P<Block>, Option<Label>),
+    Loop(P<Block>, Option<Label>, Span),
     /// A `match` block.
     Match(P<Expr>, Vec<Arm>),
     /// A closure (e.g., `move |a, b, c| a + b + c`).
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 2f7c7a29492..3e012953115 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -618,9 +618,12 @@ impl MetaItemKind {
             }) => MetaItemKind::list_from_tokens(tokens.clone()),
             AttrArgs::Delimited(..) => None,
             AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind {
-                ast::ExprKind::Lit(token_lit) => Some(MetaItemKind::NameValue(
-                    Lit::from_token_lit(token_lit, expr.span).expect("token_lit in from_attr_args"),
-                )),
+                ast::ExprKind::Lit(token_lit) => {
+                    // Turn failures to `None`, we'll get parse errors elsewhere.
+                    Lit::from_token_lit(token_lit, expr.span)
+                        .ok()
+                        .map(|lit| MetaItemKind::NameValue(lit))
+                }
                 _ => None,
             },
             AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())),
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 4e1dcb2842f..a5b24c403dd 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1355,9 +1355,10 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_block(body);
             visit_opt(label, |label| vis.visit_label(label));
         }
-        ExprKind::Loop(body, label) => {
+        ExprKind::Loop(body, label, span) => {
             vis.visit_block(body);
             visit_opt(label, |label| vis.visit_label(label));
+            vis.visit_span(span);
         }
         ExprKind::Match(expr, arms) => {
             vis.visit_expr(expr);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 5c69e535212..c528118be08 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -824,7 +824,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
         }
-        ExprKind::Loop(block, opt_label) => {
+        ExprKind::Loop(block, opt_label, _) => {
             walk_list!(visitor, visit_label, opt_label);
             visitor.visit_block(block);
         }
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index db0d8b08a94..2a0338adc9c 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -123,7 +123,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             .operands
             .iter()
             .map(|(op, op_sp)| {
-                let lower_reg = |reg| match reg {
+                let lower_reg = |&reg: &_| match reg {
                     InlineAsmRegOrRegClass::Reg(reg) => {
                         asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
                             asm::InlineAsmReg::parse(asm_arch, reg).unwrap_or_else(|error| {
@@ -152,32 +152,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                 };
 
-                let op = match *op {
-                    InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
+                let op = match op {
+                    InlineAsmOperand::In { reg, expr } => hir::InlineAsmOperand::In {
                         reg: lower_reg(reg),
                         expr: self.lower_expr(expr),
                     },
-                    InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
+                    InlineAsmOperand::Out { reg, late, expr } => hir::InlineAsmOperand::Out {
                         reg: lower_reg(reg),
-                        late,
+                        late: *late,
                         expr: expr.as_ref().map(|expr| self.lower_expr(expr)),
                     },
-                    InlineAsmOperand::InOut { reg, late, ref expr } => {
-                        hir::InlineAsmOperand::InOut {
-                            reg: lower_reg(reg),
-                            late,
-                            expr: self.lower_expr(expr),
-                        }
-                    }
-                    InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
+                    InlineAsmOperand::InOut { reg, late, expr } => hir::InlineAsmOperand::InOut {
+                        reg: lower_reg(reg),
+                        late: *late,
+                        expr: self.lower_expr(expr),
+                    },
+                    InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
                         hir::InlineAsmOperand::SplitInOut {
                             reg: lower_reg(reg),
-                            late,
+                            late: *late,
                             in_expr: self.lower_expr(in_expr),
                             out_expr: out_expr.as_ref().map(|expr| self.lower_expr(expr)),
                         }
                     }
-                    InlineAsmOperand::Const { ref anon_const } => {
+                    InlineAsmOperand::Const { anon_const } => {
                         if !self.tcx.features().asm_const {
                             feature_err(
                                 &sess.parse_sess,
@@ -191,7 +189,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             anon_const: self.lower_anon_const(anon_const),
                         }
                     }
-                    InlineAsmOperand::Sym { ref sym } => {
+                    InlineAsmOperand::Sym { sym } => {
                         let static_def_id = self
                             .resolver
                             .get_partial_res(sym.id)
@@ -347,7 +345,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                     skip = true;
 
                                     let idx2 = *o.get();
-                                    let &(ref op2, op_sp2) = &operands[idx2];
+                                    let (ref op2, op_sp2) = operands[idx2];
                                     let Some(asm::InlineAsmRegOrRegClass::Reg(reg2)) = op2.reg() else {
                                         unreachable!();
                                     };
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 12a0cc0d255..d310f72f7a3 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -31,8 +31,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut stmts = SmallVec::<[hir::Stmt<'hir>; 8]>::new();
         let mut expr = None;
         while let [s, tail @ ..] = ast_stmts {
-            match s.kind {
-                StmtKind::Local(ref local) => {
+            match &s.kind {
+                StmtKind::Local(local) => {
                     let hir_id = self.lower_node_id(s.id);
                     let local = self.lower_local(local);
                     self.alias_attrs(hir_id, local.hir_id);
@@ -40,7 +40,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     let span = self.lower_span(s.span);
                     stmts.push(hir::Stmt { hir_id, kind, span });
                 }
-                StmtKind::Item(ref it) => {
+                StmtKind::Item(it) => {
                     stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
                         |(i, item_id)| {
                             let hir_id = match i {
@@ -53,7 +53,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         },
                     ));
                 }
-                StmtKind::Expr(ref e) => {
+                StmtKind::Expr(e) => {
                     let e = self.lower_expr(e);
                     if tail.is_empty() {
                         expr = Some(e);
@@ -65,7 +65,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         stmts.push(hir::Stmt { hir_id, kind, span });
                     }
                 }
-                StmtKind::Semi(ref e) => {
+                StmtKind::Semi(e) => {
                     let e = self.lower_expr(e);
                     let hir_id = self.lower_node_id(s.id);
                     self.alias_attrs(hir_id, e.hir_id);
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 6855344356a..3c217c0249a 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -31,20 +31,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
         ensure_sufficient_stack(|| {
-            let kind = match e.kind {
-                ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
-                ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
-                ExprKind::ConstBlock(ref anon_const) => {
+            let kind = match &e.kind {
+                ExprKind::Box(inner) => hir::ExprKind::Box(self.lower_expr(inner)),
+                ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
+                ExprKind::ConstBlock(anon_const) => {
                     let anon_const = self.lower_anon_const(anon_const);
                     hir::ExprKind::ConstBlock(anon_const)
                 }
-                ExprKind::Repeat(ref expr, ref count) => {
+                ExprKind::Repeat(expr, count) => {
                     let expr = self.lower_expr(expr);
                     let count = self.lower_array_length(count);
                     hir::ExprKind::Repeat(expr, count)
                 }
-                ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
-                ExprKind::Call(ref f, ref args) => {
+                ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
+                ExprKind::Call(f, args) => {
                     if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
                         if let [inner] = &args[..] && e.attrs.len() == 1 {
                             let kind = hir::ExprKind::Box(self.lower_expr(&inner));
@@ -61,7 +61,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         hir::ExprKind::Call(f, self.lower_exprs(args))
                     }
                 }
-                ExprKind::MethodCall(box MethodCall { ref seg, ref receiver, ref args, span }) => {
+                ExprKind::MethodCall(box MethodCall { seg, receiver, args, span }) => {
                     let hir_seg = self.arena.alloc(self.lower_path_segment(
                         e.span,
                         seg,
@@ -72,92 +72,88 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let receiver = self.lower_expr(receiver);
                     let args =
                         self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));
-                    hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span))
+                    hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(*span))
                 }
-                ExprKind::Binary(binop, ref lhs, ref rhs) => {
-                    let binop = self.lower_binop(binop);
+                ExprKind::Binary(binop, lhs, rhs) => {
+                    let binop = self.lower_binop(*binop);
                     let lhs = self.lower_expr(lhs);
                     let rhs = self.lower_expr(rhs);
                     hir::ExprKind::Binary(binop, lhs, rhs)
                 }
-                ExprKind::Unary(op, ref ohs) => {
-                    let op = self.lower_unop(op);
+                ExprKind::Unary(op, ohs) => {
+                    let op = self.lower_unop(*op);
                     let ohs = self.lower_expr(ohs);
                     hir::ExprKind::Unary(op, ohs)
                 }
                 ExprKind::Lit(token_lit) => {
-                    let lit_kind = match LitKind::from_token_lit(token_lit) {
+                    let lit_kind = match LitKind::from_token_lit(*token_lit) {
                         Ok(lit_kind) => lit_kind,
                         Err(err) => {
-                            report_lit_error(&self.tcx.sess.parse_sess, err, token_lit, e.span);
+                            report_lit_error(&self.tcx.sess.parse_sess, err, *token_lit, e.span);
                             LitKind::Err
                         }
                     };
                     hir::ExprKind::Lit(respan(self.lower_span(e.span), lit_kind))
                 }
-                ExprKind::IncludedBytes(ref bytes) => hir::ExprKind::Lit(respan(
+                ExprKind::IncludedBytes(bytes) => hir::ExprKind::Lit(respan(
                     self.lower_span(e.span),
                     LitKind::ByteStr(bytes.clone()),
                 )),
-                ExprKind::Cast(ref expr, ref ty) => {
+                ExprKind::Cast(expr, ty) => {
                     let expr = self.lower_expr(expr);
                     let ty =
                         self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                     hir::ExprKind::Cast(expr, ty)
                 }
-                ExprKind::Type(ref expr, ref ty) => {
+                ExprKind::Type(expr, ty) => {
                     let expr = self.lower_expr(expr);
                     let ty =
                         self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                     hir::ExprKind::Type(expr, ty)
                 }
-                ExprKind::AddrOf(k, m, ref ohs) => {
+                ExprKind::AddrOf(k, m, ohs) => {
                     let ohs = self.lower_expr(ohs);
-                    hir::ExprKind::AddrOf(k, m, ohs)
+                    hir::ExprKind::AddrOf(*k, *m, ohs)
                 }
-                ExprKind::Let(ref pat, ref scrutinee, span) => {
+                ExprKind::Let(pat, scrutinee, span) => {
                     hir::ExprKind::Let(self.arena.alloc(hir::Let {
                         hir_id: self.next_id(),
-                        span: self.lower_span(span),
+                        span: self.lower_span(*span),
                         pat: self.lower_pat(pat),
                         ty: None,
                         init: self.lower_expr(scrutinee),
                     }))
                 }
-                ExprKind::If(ref cond, ref then, ref else_opt) => {
+                ExprKind::If(cond, then, else_opt) => {
                     self.lower_expr_if(cond, then, else_opt.as_deref())
                 }
-                ExprKind::While(ref cond, ref body, opt_label) => {
-                    self.with_loop_scope(e.id, |this| {
-                        let span =
-                            this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);
-                        this.lower_expr_while_in_loop_scope(span, cond, body, opt_label)
-                    })
-                }
-                ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
+                ExprKind::While(cond, body, opt_label) => self.with_loop_scope(e.id, |this| {
+                    let span = this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);
+                    this.lower_expr_while_in_loop_scope(span, cond, body, *opt_label)
+                }),
+                ExprKind::Loop(body, opt_label, span) => self.with_loop_scope(e.id, |this| {
                     hir::ExprKind::Loop(
                         this.lower_block(body, false),
-                        this.lower_label(opt_label),
+                        this.lower_label(*opt_label),
                         hir::LoopSource::Loop,
-                        DUMMY_SP,
+                        this.lower_span(*span),
                     )
                 }),
-                ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
-                ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match(
+                ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
+                ExprKind::Match(expr, arms) => hir::ExprKind::Match(
                     self.lower_expr(expr),
                     self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
                     hir::MatchSource::Normal,
                 ),
-                ExprKind::Async(capture_clause, closure_node_id, ref block) => self
-                    .make_async_expr(
-                        capture_clause,
-                        closure_node_id,
-                        None,
-                        block.span,
-                        hir::AsyncGeneratorKind::Block,
-                        |this| this.with_new_scopes(|this| this.lower_block_expr(block)),
-                    ),
-                ExprKind::Await(ref expr) => {
+                ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
+                    *capture_clause,
+                    *closure_node_id,
+                    None,
+                    block.span,
+                    hir::AsyncGeneratorKind::Block,
+                    |this| this.with_new_scopes(|this| this.lower_block_expr(block)),
+                ),
+                ExprKind::Await(expr) => {
                     let dot_await_span = if expr.span.hi() < e.span.hi() {
                         let span_with_whitespace = self
                             .tcx
@@ -173,65 +169,63 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     self.lower_expr_await(dot_await_span, expr)
                 }
                 ExprKind::Closure(box Closure {
-                    ref binder,
+                    binder,
                     capture_clause,
                     asyncness,
                     movability,
-                    ref fn_decl,
-                    ref body,
+                    fn_decl,
+                    body,
                     fn_decl_span,
                 }) => {
                     if let Async::Yes { closure_id, .. } = asyncness {
                         self.lower_expr_async_closure(
                             binder,
-                            capture_clause,
+                            *capture_clause,
                             e.id,
-                            closure_id,
+                            *closure_id,
                             fn_decl,
                             body,
-                            fn_decl_span,
+                            *fn_decl_span,
                         )
                     } else {
                         self.lower_expr_closure(
                             binder,
-                            capture_clause,
+                            *capture_clause,
                             e.id,
-                            movability,
+                            *movability,
                             fn_decl,
                             body,
-                            fn_decl_span,
+                            *fn_decl_span,
                         )
                     }
                 }
-                ExprKind::Block(ref blk, opt_label) => {
-                    let opt_label = self.lower_label(opt_label);
+                ExprKind::Block(blk, opt_label) => {
+                    let opt_label = self.lower_label(*opt_label);
                     hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
                 }
-                ExprKind::Assign(ref el, ref er, span) => {
-                    self.lower_expr_assign(el, er, span, e.span)
-                }
-                ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
-                    self.lower_binop(op),
+                ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span),
+                ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp(
+                    self.lower_binop(*op),
                     self.lower_expr(el),
                     self.lower_expr(er),
                 ),
-                ExprKind::Field(ref el, ident) => {
-                    hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(ident))
+                ExprKind::Field(el, ident) => {
+                    hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))
                 }
-                ExprKind::Index(ref el, ref er) => {
+                ExprKind::Index(el, er) => {
                     hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
                 }
-                ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
+                ExprKind::Range(Some(e1), Some(e2), RangeLimits::Closed) => {
                     self.lower_expr_range_closed(e.span, e1, e2)
                 }
-                ExprKind::Range(ref e1, ref e2, lims) => {
-                    self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
+                ExprKind::Range(e1, e2, lims) => {
+                    self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
                 }
                 ExprKind::Underscore => {
                     self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span });
                     hir::ExprKind::Err
                 }
-                ExprKind::Path(ref qself, ref path) => {
+                ExprKind::Path(qself, path) => {
                     let qpath = self.lower_qpath(
                         e.id,
                         qself,
@@ -241,22 +235,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     );
                     hir::ExprKind::Path(qpath)
                 }
-                ExprKind::Break(opt_label, ref opt_expr) => {
+                ExprKind::Break(opt_label, opt_expr) => {
                     let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x));
-                    hir::ExprKind::Break(self.lower_jump_destination(e.id, opt_label), opt_expr)
+                    hir::ExprKind::Break(self.lower_jump_destination(e.id, *opt_label), opt_expr)
                 }
                 ExprKind::Continue(opt_label) => {
-                    hir::ExprKind::Continue(self.lower_jump_destination(e.id, opt_label))
+                    hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))
                 }
-                ExprKind::Ret(ref e) => {
+                ExprKind::Ret(e) => {
                     let e = e.as_ref().map(|x| self.lower_expr(x));
                     hir::ExprKind::Ret(e)
                 }
-                ExprKind::Yeet(ref sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
-                ExprKind::InlineAsm(ref asm) => {
+                ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
+                ExprKind::InlineAsm(asm) => {
                     hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
                 }
-                ExprKind::Struct(ref se) => {
+                ExprKind::Struct(se) => {
                     let rest = match &se.rest {
                         StructRest::Base(e) => Some(self.lower_expr(e)),
                         StructRest::Rest(sp) => {
@@ -278,10 +272,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         rest,
                     )
                 }
-                ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
+                ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
                 ExprKind::Err => hir::ExprKind::Err,
-                ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr),
-                ExprKind::Paren(ref ex) => {
+                ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
+                ExprKind::Paren(ex) => {
                     let mut ex = self.lower_expr_mut(ex);
                     // Include parens in span, but only if it is a super-span.
                     if e.span.contains(ex.span) {
@@ -306,8 +300,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
                 // Desugar `ExprForLoop`
                 // from: `[opt_ident]: for <pat> in <head> <body>`
-                ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
-                    return self.lower_expr_for(e, pat, head, body, opt_label);
+                ExprKind::ForLoop(pat, head, body, opt_label) => {
+                    return self.lower_expr_for(e, pat, head, body, *opt_label);
                 }
                 ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
             };
@@ -358,7 +352,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         args: Vec<AstP<Expr>>,
         legacy_args_idx: &[usize],
     ) -> hir::ExprKind<'hir> {
-        let ExprKind::Path(None, ref mut path) = f.kind else {
+        let ExprKind::Path(None, path) = &mut f.kind else {
             unreachable!();
         };
 
@@ -552,10 +546,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
         let pat = self.lower_pat(&arm.pat);
         let guard = arm.guard.as_ref().map(|cond| {
-            if let ExprKind::Let(ref pat, ref scrutinee, span) = cond.kind {
+            if let ExprKind::Let(pat, scrutinee, span) = &cond.kind {
                 hir::Guard::IfLet(self.arena.alloc(hir::Let {
                     hir_id: self.next_id(),
-                    span: self.lower_span(span),
+                    span: self.lower_span(*span),
                     pat: self.lower_pat(pat),
                     ty: None,
                     init: self.lower_expr(scrutinee),
@@ -961,8 +955,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
     ) -> (hir::ClosureBinder, &'c [GenericParam]) {
         let (binder, params) = match binder {
             ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
-            &ClosureBinder::For { span, ref generic_params } => {
-                let span = self.lower_span(span);
+            ClosureBinder::For { span, generic_params } => {
+                let span = self.lower_span(*span);
                 (hir::ClosureBinder::For { span }, &**generic_params)
             }
         };
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 3a0e5f55ec1..695a698e022 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -145,7 +145,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     fn visit_item(&mut self, i: &'hir Item<'hir>) {
         debug_assert_eq!(i.owner_id, self.owner);
         self.with_parent(i.hir_id(), |this| {
-            if let ItemKind::Struct(ref struct_def, _) = i.kind {
+            if let ItemKind::Struct(struct_def, _) = &i.kind {
                 // If this is a tuple or unit-like struct, register the constructor.
                 if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
                     this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 99b3ac864dd..a1941b5d8d3 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -142,7 +142,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
             // This is used to track which lifetimes have already been defined,
             // and which need to be replicated when lowering an async fn.
             match parent_hir.node().expect_item().kind {
-                hir::ItemKind::Impl(hir::Impl { ref of_trait, .. }) => {
+                hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
                     lctx.is_in_trait_impl = of_trait.is_some();
                 }
                 _ => {}
@@ -178,7 +178,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
         let mut node_ids =
             smallvec![hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }];
-        if let ItemKind::Use(ref use_tree) = &i.kind {
+        if let ItemKind::Use(use_tree) = &i.kind {
             self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids);
         }
         node_ids
@@ -190,8 +190,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         base_id: NodeId,
         vec: &mut SmallVec<[hir::ItemId; 1]>,
     ) {
-        match tree.kind {
-            UseTreeKind::Nested(ref nested_vec) => {
+        match &tree.kind {
+            UseTreeKind::Nested(nested_vec) => {
                 for &(ref nested, id) in nested_vec {
                     vec.push(hir::ItemId {
                         owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
@@ -201,8 +201,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
             UseTreeKind::Glob => {}
             UseTreeKind::Simple(_, id1, id2) => {
-                for (_, &id) in
-                    iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
+                for (_, id) in
+                    iter::zip(self.expect_full_res_from_use(base_id).skip(1), [*id1, *id2])
                 {
                     vec.push(hir::ItemId {
                         owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
@@ -238,26 +238,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
         vis_span: Span,
         i: &ItemKind,
     ) -> hir::ItemKind<'hir> {
-        match *i {
-            ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(orig_name),
-            ItemKind::Use(ref use_tree) => {
+        match i {
+            ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(*orig_name),
+            ItemKind::Use(use_tree) => {
                 // Start with an empty prefix.
                 let prefix = Path { segments: ThinVec::new(), span: use_tree.span, tokens: None };
 
                 self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
             }
-            ItemKind::Static(ref t, m, ref e) => {
+            ItemKind::Static(t, m, e) => {
                 let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
-                hir::ItemKind::Static(ty, m, body_id)
+                hir::ItemKind::Static(ty, *m, body_id)
             }
-            ItemKind::Const(_, ref t, ref e) => {
+            ItemKind::Const(_, t, e) => {
                 let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
                 hir::ItemKind::Const(ty, body_id)
             }
             ItemKind::Fn(box Fn {
-                sig: FnSig { ref decl, header, span: fn_sig_span },
-                ref generics,
-                ref body,
+                sig: FnSig { decl, header, span: fn_sig_span },
+                generics,
+                body,
                 ..
             }) => {
                 self.with_new_scopes(|this| {
@@ -274,37 +274,30 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let mut itctx = ImplTraitContext::Universal;
                     let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
                         let ret_id = asyncness.opt_return_id();
-                        this.lower_fn_decl(&decl, Some(id), fn_sig_span, FnDeclKind::Fn, ret_id)
+                        this.lower_fn_decl(&decl, Some(id), *fn_sig_span, FnDeclKind::Fn, ret_id)
                     });
                     let sig = hir::FnSig {
                         decl,
-                        header: this.lower_fn_header(header),
-                        span: this.lower_span(fn_sig_span),
+                        header: this.lower_fn_header(*header),
+                        span: this.lower_span(*fn_sig_span),
                     };
                     hir::ItemKind::Fn(sig, generics, body_id)
                 })
             }
-            ItemKind::Mod(_, ref mod_kind) => match mod_kind {
+            ItemKind::Mod(_, mod_kind) => match mod_kind {
                 ModKind::Loaded(items, _, spans) => {
                     hir::ItemKind::Mod(self.lower_mod(items, spans))
                 }
                 ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
             },
-            ItemKind::ForeignMod(ref fm) => hir::ItemKind::ForeignMod {
+            ItemKind::ForeignMod(fm) => hir::ItemKind::ForeignMod {
                 abi: fm.abi.map_or(abi::Abi::FALLBACK, |abi| self.lower_abi(abi)),
                 items: self
                     .arena
                     .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
             },
-            ItemKind::GlobalAsm(ref asm) => {
-                hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
-            }
-            ItemKind::TyAlias(box TyAlias {
-                ref generics,
-                where_clauses,
-                ty: Some(ref ty),
-                ..
-            }) => {
+            ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)),
+            ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty: Some(ty), .. }) => {
                 // We lower
                 //
                 // type Foo = impl Trait
@@ -314,7 +307,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // type Foo = Foo1
                 // opaque type Foo1: Trait
                 let mut generics = generics.clone();
-                add_ty_alias_where_clause(&mut generics, where_clauses, true);
+                add_ty_alias_where_clause(&mut generics, *where_clauses, true);
                 let (generics, ty) = self.lower_generics(
                     &generics,
                     id,
@@ -323,9 +316,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
-            ItemKind::TyAlias(box TyAlias {
-                ref generics, ref where_clauses, ty: None, ..
-            }) => {
+            ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty: None, .. }) => {
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, *where_clauses, true);
                 let (generics, ty) = self.lower_generics(
@@ -336,7 +327,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
-            ItemKind::Enum(ref enum_definition, ref generics) => {
+            ItemKind::Enum(enum_definition, generics) => {
                 let (generics, variants) = self.lower_generics(
                     generics,
                     id,
@@ -349,7 +340,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 hir::ItemKind::Enum(hir::EnumDef { variants }, generics)
             }
-            ItemKind::Struct(ref struct_def, ref generics) => {
+            ItemKind::Struct(struct_def, generics) => {
                 let (generics, struct_def) = self.lower_generics(
                     generics,
                     id,
@@ -358,7 +349,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 hir::ItemKind::Struct(struct_def, generics)
             }
-            ItemKind::Union(ref vdata, ref generics) => {
+            ItemKind::Union(vdata, generics) => {
                 let (generics, vdata) = self.lower_generics(
                     generics,
                     id,
@@ -372,10 +363,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 polarity,
                 defaultness,
                 constness,
-                generics: ref ast_generics,
-                of_trait: ref trait_ref,
-                self_ty: ref ty,
-                items: ref impl_items,
+                generics: ast_generics,
+                of_trait: trait_ref,
+                self_ty: ty,
+                items: impl_items,
             }) => {
                 // Lower the "impl header" first. This ordering is important
                 // for in-band lifetimes! Consider `'a` here:
@@ -413,30 +404,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // `defaultness.has_value()` is never called for an `impl`, always `true` in order
                 // to not cause an assertion failure inside the `lower_defaultness` function.
                 let has_val = true;
-                let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
+                let (defaultness, defaultness_span) = self.lower_defaultness(*defaultness, has_val);
                 let polarity = match polarity {
                     ImplPolarity::Positive => ImplPolarity::Positive,
-                    ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
+                    ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)),
                 };
                 hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
-                    unsafety: self.lower_unsafety(unsafety),
+                    unsafety: self.lower_unsafety(*unsafety),
                     polarity,
                     defaultness,
                     defaultness_span,
-                    constness: self.lower_constness(constness),
+                    constness: self.lower_constness(*constness),
                     generics,
                     of_trait: trait_ref,
                     self_ty: lowered_ty,
                     items: new_impl_items,
                 }))
             }
-            ItemKind::Trait(box Trait {
-                is_auto,
-                unsafety,
-                ref generics,
-                ref bounds,
-                ref items,
-            }) => {
+            ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => {
                 let (generics, (unsafety, items, bounds)) = self.lower_generics(
                     generics,
                     id,
@@ -449,13 +434,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         let items = this.arena.alloc_from_iter(
                             items.iter().map(|item| this.lower_trait_item_ref(item)),
                         );
-                        let unsafety = this.lower_unsafety(unsafety);
+                        let unsafety = this.lower_unsafety(*unsafety);
                         (unsafety, items, bounds)
                     },
                 );
-                hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, items)
+                hir::ItemKind::Trait(*is_auto, unsafety, generics, bounds, items)
             }
-            ItemKind::TraitAlias(ref generics, ref bounds) => {
+            ItemKind::TraitAlias(generics, bounds) => {
                 let (generics, bounds) = self.lower_generics(
                     generics,
                     id,
@@ -469,10 +454,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 hir::ItemKind::TraitAlias(generics, bounds)
             }
-            ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
+            ItemKind::MacroDef(MacroDef { body, macro_rules }) => {
                 let body = P(self.lower_delim_args(body));
                 let macro_kind = self.resolver.decl_macro_kind(self.local_def_id(id));
-                hir::ItemKind::Macro(ast::MacroDef { body, macro_rules }, macro_kind)
+                hir::ItemKind::Macro(ast::MacroDef { body, macro_rules: *macro_rules }, macro_kind)
             }
             ItemKind::MacCall(..) => {
                 panic!("`TyMac` should have been expanded by now")
@@ -664,8 +649,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let item = hir::ForeignItem {
             owner_id,
             ident: self.lower_ident(i.ident),
-            kind: match i.kind {
-                ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
+            kind: match &i.kind {
+                ForeignItemKind::Fn(box Fn { sig, generics, .. }) => {
                     let fdec = &sig.decl;
                     let mut itctx = ImplTraitContext::Universal;
                     let (generics, (fn_dec, fn_args)) =
@@ -685,10 +670,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
                     hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
                 }
-                ForeignItemKind::Static(ref t, m, _) => {
+                ForeignItemKind::Static(t, m, _) => {
                     let ty =
                         self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
-                    hir::ForeignItemKind::Static(ty, m)
+                    hir::ForeignItemKind::Static(ty, *m)
                 }
                 ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
                 ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"),
@@ -725,33 +710,33 @@ impl<'hir> LoweringContext<'_, 'hir> {
         parent_id: hir::HirId,
         vdata: &VariantData,
     ) -> hir::VariantData<'hir> {
-        match *vdata {
-            VariantData::Struct(ref fields, recovered) => hir::VariantData::Struct(
+        match vdata {
+            VariantData::Struct(fields, recovered) => hir::VariantData::Struct(
                 self.arena
                     .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
-                recovered,
+                *recovered,
             ),
-            VariantData::Tuple(ref fields, id) => {
-                let ctor_id = self.lower_node_id(id);
+            VariantData::Tuple(fields, id) => {
+                let ctor_id = self.lower_node_id(*id);
                 self.alias_attrs(ctor_id, parent_id);
                 hir::VariantData::Tuple(
                     self.arena.alloc_from_iter(
                         fields.iter().enumerate().map(|f| self.lower_field_def(f)),
                     ),
                     ctor_id,
-                    self.local_def_id(id),
+                    self.local_def_id(*id),
                 )
             }
             VariantData::Unit(id) => {
-                let ctor_id = self.lower_node_id(id);
+                let ctor_id = self.lower_node_id(*id);
                 self.alias_attrs(ctor_id, parent_id);
-                hir::VariantData::Unit(ctor_id, self.local_def_id(id))
+                hir::VariantData::Unit(ctor_id, self.local_def_id(*id))
             }
         }
     }
 
     fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
-        let ty = if let TyKind::Path(ref qself, ref path) = f.ty.kind {
+        let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
             let t = self.lower_path_ty(
                 &f.ty,
                 qself,
@@ -783,13 +768,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let hir_id = self.lower_node_id(i.id);
         let trait_item_def_id = hir_id.expect_owner();
 
-        let (generics, kind, has_default) = match i.kind {
-            AssocItemKind::Const(_, ref ty, ref default) => {
+        let (generics, kind, has_default) = match &i.kind {
+            AssocItemKind::Const(_, ty, default) => {
                 let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
                 (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
             }
-            AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
+            AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
                 let asyncness = sig.header.asyncness;
                 let names = self.lower_fn_params_to_names(&sig.decl);
                 let (generics, sig) = self.lower_method_sig(
@@ -801,7 +786,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
             }
-            AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
+            AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => {
                 let asyncness = sig.header.asyncness;
                 let body_id =
                     self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body));
@@ -814,15 +799,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
             }
-            AssocItemKind::Type(box TyAlias {
-                ref generics,
-                where_clauses,
-                ref bounds,
-                ref ty,
-                ..
-            }) => {
+            AssocItemKind::Type(box TyAlias { generics, where_clauses, bounds, ty, .. }) => {
                 let mut generics = generics.clone();
-                add_ty_alias_where_clause(&mut generics, where_clauses, false);
+                add_ty_alias_where_clause(&mut generics, *where_clauses, false);
                 let (generics, kind) = self.lower_generics(
                     &generics,
                     i.id,
@@ -1354,7 +1333,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // keep track of the Span info. Now, `add_implicitly_sized` in `AstConv` checks both param bounds and
         // where clauses for `?Sized`.
         for pred in &generics.where_clause.predicates {
-            let WherePredicate::BoundPredicate(ref bound_pred) = *pred else {
+            let WherePredicate::BoundPredicate(bound_pred) = pred else {
                 continue;
             };
             let compute_is_param = || {
@@ -1515,11 +1494,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
-        match *pred {
+        match pred {
             WherePredicate::BoundPredicate(WhereBoundPredicate {
-                ref bound_generic_params,
-                ref bounded_ty,
-                ref bounds,
+                bound_generic_params,
+                bounded_ty,
+                bounds,
                 span,
             }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                 hir_id: self.next_id(),
@@ -1532,29 +1511,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         &ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                     )
                 })),
-                span: self.lower_span(span),
+                span: self.lower_span(*span),
                 origin: PredicateOrigin::WhereClause,
             }),
-            WherePredicate::RegionPredicate(WhereRegionPredicate {
-                ref lifetime,
-                ref bounds,
-                span,
-            }) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
-                span: self.lower_span(span),
-                lifetime: self.lower_lifetime(lifetime),
-                bounds: self.lower_param_bounds(
-                    bounds,
-                    &ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                ),
-                in_where_clause: true,
-            }),
-            WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span }) => {
+            WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span }) => {
+                hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+                    span: self.lower_span(*span),
+                    lifetime: self.lower_lifetime(lifetime),
+                    bounds: self.lower_param_bounds(
+                        bounds,
+                        &ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                    ),
+                    in_where_clause: true,
+                })
+            }
+            WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span }) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                     lhs_ty: self
                         .lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
                     rhs_ty: self
                         .lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
-                    span: self.lower_span(span),
+                    span: self.lower_span(*span),
                 })
             }
         }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index bd1876d4284..d1666dfbf64 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -932,13 +932,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     fn lower_attr_args(&self, args: &AttrArgs) -> AttrArgs {
-        match *args {
+        match args {
             AttrArgs::Empty => AttrArgs::Empty,
-            AttrArgs::Delimited(ref args) => AttrArgs::Delimited(self.lower_delim_args(args)),
+            AttrArgs::Delimited(args) => AttrArgs::Delimited(self.lower_delim_args(args)),
             // This is an inert key-value attribute - it will never be visible to macros
             // after it gets lowered to HIR. Therefore, we can extract literals to handle
             // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
-            AttrArgs::Eq(eq_span, AttrArgsEq::Ast(ref expr)) => {
+            AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => {
                 // In valid code the value always ends up as a single literal. Otherwise, a dummy
                 // literal suffices because the error is handled elsewhere.
                 let lit = if let ExprKind::Lit(token_lit) = expr.kind {
@@ -957,9 +957,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         span: DUMMY_SP,
                     }
                 };
-                AttrArgs::Eq(eq_span, AttrArgsEq::Hir(lit))
+                AttrArgs::Eq(*eq_span, AttrArgsEq::Hir(lit))
             }
-            AttrArgs::Eq(_, AttrArgsEq::Hir(ref lit)) => {
+            AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
                 unreachable!("in literal form when lowering mac args eq: {:?}", lit)
             }
         }
@@ -987,12 +987,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
         // lower generic arguments of identifier in constraint
-        let gen_args = if let Some(ref gen_args) = constraint.gen_args {
+        let gen_args = if let Some(gen_args) = &constraint.gen_args {
             let gen_args_ctor = match gen_args {
-                GenericArgs::AngleBracketed(ref data) => {
+                GenericArgs::AngleBracketed(data) => {
                     self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
                 }
-                GenericArgs::Parenthesized(ref data) => {
+                GenericArgs::Parenthesized(data) => {
                     self.emit_bad_parenthesized_trait_in_assoc_ty(data);
                     let aba = self.ast_arena.aba.alloc(data.as_angle_bracketed_args());
                     self.lower_angle_bracketed_parameter_data(aba, ParamMode::Explicit, itctx).0
@@ -1004,15 +1004,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         };
         let itctx_tait = &ImplTraitContext::TypeAliasesOpaqueTy;
 
-        let kind = match constraint.kind {
-            AssocConstraintKind::Equality { ref term } => {
+        let kind = match &constraint.kind {
+            AssocConstraintKind::Equality { term } => {
                 let term = match term {
-                    Term::Ty(ref ty) => self.lower_ty(ty, itctx).into(),
-                    Term::Const(ref c) => self.lower_anon_const(c).into(),
+                    Term::Ty(ty) => self.lower_ty(ty, itctx).into(),
+                    Term::Const(c) => self.lower_anon_const(c).into(),
                 };
                 hir::TypeBindingKind::Equality { term }
             }
-            AssocConstraintKind::Bound { ref bounds } => {
+            AssocConstraintKind::Bound { bounds } => {
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
                 let (desugar_to_impl_trait, itctx) = match itctx {
                     // We are in the return position:
@@ -1122,7 +1122,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         match arg {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
             ast::GenericArg::Type(ty) => {
-                match ty.kind {
+                match &ty.kind {
                     TyKind::Infer if self.tcx.features().generic_arg_infer => {
                         return GenericArg::Infer(hir::InferArg {
                             hir_id: self.lower_node_id(ty.id),
@@ -1133,7 +1133,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // parsing. We try to resolve that ambiguity by attempting resolution in both the
                     // type and value namespaces. If we resolved the path in the value namespace, we
                     // transform it into a generic const argument.
-                    TyKind::Path(ref qself, ref path) => {
+                    TyKind::Path(qself, path) => {
                         if let Some(res) = self
                             .resolver
                             .get_partial_res(ty.id)
@@ -1240,12 +1240,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir> {
-        let kind = match t.kind {
+        let kind = match &t.kind {
             TyKind::Infer => hir::TyKind::Infer,
             TyKind::Err => hir::TyKind::Err,
-            TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
-            TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
-            TyKind::Rptr(ref region, ref mt) => {
+            TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
+            TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
+            TyKind::Rptr(region, mt) => {
                 let region = region.unwrap_or_else(|| {
                     let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
                         self.resolver.get_lifetime_res(t.id)
@@ -1261,7 +1261,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let lifetime = self.lower_lifetime(&region);
                 hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
             }
-            TyKind::BareFn(ref f) => {
+            TyKind::BareFn(f) => {
                 let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
                 hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
                     generic_params,
@@ -1272,13 +1272,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }))
             }
             TyKind::Never => hir::TyKind::Never,
-            TyKind::Tup(ref tys) => hir::TyKind::Tup(
+            TyKind::Tup(tys) => hir::TyKind::Tup(
                 self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
             ),
-            TyKind::Paren(ref ty) => {
+            TyKind::Paren(ty) => {
                 return self.lower_ty_direct(ty, itctx);
             }
-            TyKind::Path(ref qself, ref path) => {
+            TyKind::Path(qself, path) => {
                 return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
             }
             TyKind::ImplicitSelf => {
@@ -1298,48 +1298,46 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }),
                 ))
             }
-            TyKind::Array(ref ty, ref length) => {
+            TyKind::Array(ty, length) => {
                 hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
             }
-            TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
-            TyKind::TraitObject(ref bounds, kind) => {
+            TyKind::Typeof(expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
+            TyKind::TraitObject(bounds, kind) => {
                 let mut lifetime_bound = None;
                 let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
                     let bounds =
-                        this.arena.alloc_from_iter(bounds.iter().filter_map(
-                            |bound| match *bound {
-                                GenericBound::Trait(
-                                    ref ty,
-                                    TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
-                                ) => Some(this.lower_poly_trait_ref(ty, itctx)),
-                                // `~const ?Bound` will cause an error during AST validation
-                                // anyways, so treat it like `?Bound` as compilation proceeds.
-                                GenericBound::Trait(
-                                    _,
-                                    TraitBoundModifier::Maybe | TraitBoundModifier::MaybeConstMaybe,
-                                ) => None,
-                                GenericBound::Outlives(ref lifetime) => {
-                                    if lifetime_bound.is_none() {
-                                        lifetime_bound = Some(this.lower_lifetime(lifetime));
-                                    }
-                                    None
+                        this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
+                            GenericBound::Trait(
+                                ty,
+                                TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
+                            ) => Some(this.lower_poly_trait_ref(ty, itctx)),
+                            // `~const ?Bound` will cause an error during AST validation
+                            // anyways, so treat it like `?Bound` as compilation proceeds.
+                            GenericBound::Trait(
+                                _,
+                                TraitBoundModifier::Maybe | TraitBoundModifier::MaybeConstMaybe,
+                            ) => None,
+                            GenericBound::Outlives(lifetime) => {
+                                if lifetime_bound.is_none() {
+                                    lifetime_bound = Some(this.lower_lifetime(lifetime));
                                 }
-                            },
-                        ));
+                                None
+                            }
+                        }));
                     let lifetime_bound =
                         lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
                     (bounds, lifetime_bound)
                 });
-                hir::TyKind::TraitObject(bounds, lifetime_bound, kind)
+                hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
             }
-            TyKind::ImplTrait(def_node_id, ref bounds) => {
+            TyKind::ImplTrait(def_node_id, bounds) => {
                 let span = t.span;
                 match itctx {
                     ImplTraitContext::ReturnPositionOpaqueTy { origin, in_trait } => self
                         .lower_opaque_impl_trait(
                             span,
                             *origin,
-                            def_node_id,
+                            *def_node_id,
                             bounds,
                             *in_trait,
                             itctx,
@@ -1347,7 +1345,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait(
                         span,
                         hir::OpaqueTyOrigin::TyAlias,
-                        def_node_id,
+                        *def_node_id,
                         bounds,
                         false,
                         itctx,
@@ -1355,13 +1353,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     ImplTraitContext::Universal => {
                         self.create_def(
                             self.current_hir_id_owner.def_id,
-                            def_node_id,
+                            *def_node_id,
                             DefPathData::ImplTrait,
                         );
                         let span = t.span;
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
                         let (param, bounds, path) =
-                            self.lower_generic_and_bounds(def_node_id, span, ident, bounds);
+                            self.lower_generic_and_bounds(*def_node_id, span, ident, bounds);
                         self.impl_trait_defs.push(param);
                         if let Some(bounds) = bounds {
                             self.impl_trait_bounds.push(bounds);
@@ -1740,8 +1738,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 matches!(kind, FnDeclKind::Trait),
             )
         } else {
-            match decl.output {
-                FnRetTy::Ty(ref ty) => {
+            match &decl.output {
+                FnRetTy::Ty(ty) => {
                     let mut context = match fn_node_id {
                         Some(fn_node_id) if kind.impl_trait_allowed(self.tcx) => {
                             let fn_def_id = self.local_def_id(fn_node_id);
@@ -1763,7 +1761,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     };
                     hir::FnRetTy::Return(self.lower_ty(ty, &mut context))
                 }
-                FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
+                FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
             }
         };
 
@@ -1777,18 +1775,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     PatKind::Ident(hir::BindingAnnotation(_, Mutability::Mut), ..)
                 );
 
-                match arg.ty.kind {
+                match &arg.ty.kind {
                     TyKind::ImplicitSelf if is_mutable_pat => hir::ImplicitSelfKind::Mut,
                     TyKind::ImplicitSelf => hir::ImplicitSelfKind::Imm,
                     // Given we are only considering `ImplicitSelf` types, we needn't consider
                     // the case where we have a mutable pattern to a reference as that would
                     // no longer be an `ImplicitSelf`.
-                    TyKind::Rptr(_, ref mt)
+                    TyKind::Rptr(_, mt)
                         if mt.ty.kind.is_implicit_self() && mt.mutbl == ast::Mutability::Mut =>
                     {
                         hir::ImplicitSelfKind::MutRef
                     }
-                    TyKind::Rptr(_, ref mt) if mt.ty.kind.is_implicit_self() => {
+                    TyKind::Rptr(_, mt) if mt.ty.kind.is_implicit_self() => {
                         hir::ImplicitSelfKind::ImmRef
                     }
                     _ => hir::ImplicitSelfKind::None,
@@ -2181,7 +2179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         param: &GenericParam,
     ) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
-        match param.kind {
+        match &param.kind {
             GenericParamKind::Lifetime => {
                 // AST resolution emitted an error on those parameters, so we lower them using
                 // `ParamName::Error`.
@@ -2197,7 +2195,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                 (param_name, kind)
             }
-            GenericParamKind::Type { ref default, .. } => {
+            GenericParamKind::Type { default, .. } => {
                 let kind = hir::GenericParamKind::Type {
                     default: default.as_ref().map(|x| {
                         self.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
@@ -2207,7 +2205,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                 (hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
             }
-            GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
+            GenericParamKind::Const { ty, kw_span: _, default } => {
                 let ty = self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 let default = default.as_ref().map(|def| self.lower_anon_const(def));
                 (
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 7fdfc79164b..16b012630da 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -22,16 +22,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         ensure_sufficient_stack(|| {
             // loop here to avoid recursion
             let node = loop {
-                match pattern.kind {
+                match &pattern.kind {
                     PatKind::Wild => break hir::PatKind::Wild,
-                    PatKind::Ident(binding_mode, ident, ref sub) => {
-                        let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
-                        break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
+                    PatKind::Ident(binding_mode, ident, sub) => {
+                        let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s));
+                        break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub);
                     }
-                    PatKind::Lit(ref e) => {
+                    PatKind::Lit(e) => {
                         break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
                     }
-                    PatKind::TupleStruct(ref qself, ref path, ref pats) => {
+                    PatKind::TupleStruct(qself, path, pats) => {
                         let qpath = self.lower_qpath(
                             pattern.id,
                             qself,
@@ -42,12 +42,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
                         break hir::PatKind::TupleStruct(qpath, pats, ddpos);
                     }
-                    PatKind::Or(ref pats) => {
+                    PatKind::Or(pats) => {
                         break hir::PatKind::Or(
                             self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat_mut(x))),
                         );
                     }
-                    PatKind::Path(ref qself, ref path) => {
+                    PatKind::Path(qself, path) => {
                         let qpath = self.lower_qpath(
                             pattern.id,
                             qself,
@@ -57,7 +57,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         );
                         break hir::PatKind::Path(qpath);
                     }
-                    PatKind::Struct(ref qself, ref path, ref fields, etc) => {
+                    PatKind::Struct(qself, path, fields, etc) => {
                         let qpath = self.lower_qpath(
                             pattern.id,
                             qself,
@@ -78,32 +78,32 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 span: self.lower_span(f.span),
                             }
                         }));
-                        break hir::PatKind::Struct(qpath, fs, etc);
+                        break hir::PatKind::Struct(qpath, fs, *etc);
                     }
-                    PatKind::Tuple(ref pats) => {
+                    PatKind::Tuple(pats) => {
                         let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
                         break hir::PatKind::Tuple(pats, ddpos);
                     }
-                    PatKind::Box(ref inner) => {
+                    PatKind::Box(inner) => {
                         break hir::PatKind::Box(self.lower_pat(inner));
                     }
-                    PatKind::Ref(ref inner, mutbl) => {
-                        break hir::PatKind::Ref(self.lower_pat(inner), mutbl);
+                    PatKind::Ref(inner, mutbl) => {
+                        break hir::PatKind::Ref(self.lower_pat(inner), *mutbl);
                     }
-                    PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => {
+                    PatKind::Range(e1, e2, Spanned { node: end, .. }) => {
                         break hir::PatKind::Range(
                             e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
                             e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
                             self.lower_range_end(end, e2.is_some()),
                         );
                     }
-                    PatKind::Slice(ref pats) => break self.lower_pat_slice(pats),
+                    PatKind::Slice(pats) => break self.lower_pat_slice(pats),
                     PatKind::Rest => {
                         // If we reach here the `..` pattern is not semantically allowed.
                         break self.ban_illegal_rest_pat(pattern.span);
                     }
                     // return inner to be processed in next loop
-                    PatKind::Paren(ref inner) => pattern = inner,
+                    PatKind::Paren(inner) => pattern = inner,
                     PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
                 }
             };
@@ -126,7 +126,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // Note that unlike for slice patterns,
             // where `xs @ ..` is a legal sub-slice pattern,
             // it is not a legal sub-tuple pattern.
-            match pat.kind {
+            match &pat.kind {
                 // Found a sub-tuple rest pattern
                 PatKind::Rest => {
                     rest = Some((idx, pat.span));
@@ -134,12 +134,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
                 // Found a sub-tuple pattern `$binding_mode $ident @ ..`.
                 // This is not allowed as a sub-tuple pattern
-                PatKind::Ident(ref _bm, ident, Some(ref sub)) if sub.is_rest() => {
+                PatKind::Ident(_, ident, Some(sub)) if sub.is_rest() => {
                     let sp = pat.span;
                     self.tcx.sess.emit_err(SubTupleBinding {
                         span: sp,
                         ident_name: ident.name,
-                        ident,
+                        ident: *ident,
                         ctx,
                     });
                 }
@@ -176,7 +176,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut prev_rest_span = None;
 
         // Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
-        let lower_rest_sub = |this: &mut Self, pat, ann, ident, sub| {
+        let lower_rest_sub = |this: &mut Self, pat, &ann, &ident, sub| {
             let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
             let node = this.lower_pat_ident(pat, ann, ident, lower_sub);
             this.pat_with_node_id_of(pat, node)
@@ -185,7 +185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut iter = pats.iter();
         // Lower all the patterns until the first occurrence of a sub-slice pattern.
         for pat in iter.by_ref() {
-            match pat.kind {
+            match &pat.kind {
                 // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
                 PatKind::Rest => {
                     prev_rest_span = Some(pat.span);
@@ -194,7 +194,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
                 // Found a sub-slice pattern `$binding_mode $ident @ ..`.
                 // Record, lower it to `$binding_mode $ident @ _`, and stop here.
-                PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => {
+                PatKind::Ident(ann, ident, Some(sub)) if sub.is_rest() => {
                     prev_rest_span = Some(sub.span);
                     slice = Some(self.arena.alloc(lower_rest_sub(self, pat, ann, ident, sub)));
                     break;
@@ -207,9 +207,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // Lower all the patterns after the first sub-slice pattern.
         for pat in iter {
             // There was a previous subslice pattern; make sure we don't allow more.
-            let rest_span = match pat.kind {
+            let rest_span = match &pat.kind {
                 PatKind::Rest => Some(pat.span),
-                PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => {
+                PatKind::Ident(ann, ident, Some(sub)) if sub.is_rest() => {
                     // #69103: Lower into `binding @ _` as above to avoid ICEs.
                     after.push(lower_rest_sub(self, pat, ann, ident, sub));
                     Some(sub.span)
@@ -322,13 +322,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     // m!(S);
     // ```
     fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
-        match expr.kind {
+        match &expr.kind {
             ExprKind::Lit(..)
             | ExprKind::ConstBlock(..)
             | ExprKind::IncludedBytes(..)
             | ExprKind::Err => {}
             ExprKind::Path(..) if allow_paths => {}
-            ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
+            ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
             _ => {
                 self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span });
                 return self.arena.alloc(self.expr_err(expr.span));
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 83d459d899b..27b44c0b6a2 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -185,12 +185,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         itctx: &ImplTraitContext,
     ) -> hir::PathSegment<'hir> {
         debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
-        let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
-            match **generic_args {
-                GenericArgs::AngleBracketed(ref data) => {
+        let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
+            match generic_args {
+                GenericArgs::AngleBracketed(data) => {
                     self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
                 }
-                GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
+                GenericArgs::Parenthesized(data) => match parenthesized_generic_args {
                     ParenthesizedGenericArgs::Ok => {
                         self.lower_parenthesized_parameter_data(data, itctx)
                     }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 712fb5ac71f..acd7eb69ffc 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1637,7 +1637,7 @@ fn deny_equality_constraints(
                                     // Remove `Bar` from `Foo::Bar`.
                                     assoc_path.segments.pop();
                                     let len = assoc_path.segments.len() - 1;
-                                    let gen_args = args.as_ref().map(|p| (**p).clone());
+                                    let gen_args = args.as_deref().cloned();
                                     // Build `<Bar = RhsTy>`.
                                     let arg = AngleBracketedArg::Constraint(AssocConstraint {
                                         id: rustc_ast::node_id::DUMMY_NODE_ID,
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 1da40d2302e..4b37fa027f5 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -377,7 +377,7 @@ impl<'a> State<'a> {
                 self.space();
                 self.print_block_with_attrs(blk, attrs);
             }
-            ast::ExprKind::Loop(ref blk, opt_label) => {
+            ast::ExprKind::Loop(ref blk, opt_label, _) => {
                 if let Some(label) = opt_label {
                     self.print_ident(label.ident);
                     self.word_space(":");
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 5f99d86b4ea..5c645c66cd7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -167,10 +167,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 );
             }
 
-            self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
+            let closure = self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
 
             let mut is_loop_move = false;
             let mut in_pattern = false;
+            let mut seen_spans = FxHashSet::default();
 
             for move_site in &move_site_vec {
                 let move_out = self.move_data.moves[(*move_site).moi];
@@ -191,37 +192,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     is_loop_move = true;
                 }
 
-                self.explain_captures(
-                    &mut err,
-                    span,
-                    move_span,
-                    move_spans,
-                    *moved_place,
-                    partially_str,
-                    loop_message,
-                    move_msg,
-                    is_loop_move,
-                    maybe_reinitialized_locations.is_empty(),
-                );
-
-                if let (UseSpans::PatUse(span), []) =
-                    (move_spans, &maybe_reinitialized_locations[..])
-                {
-                    if maybe_reinitialized_locations.is_empty() {
-                        err.span_suggestion_verbose(
-                            span.shrink_to_lo(),
-                            &format!(
-                                "borrow this field in the pattern to avoid moving {}",
-                                self.describe_place(moved_place.as_ref())
-                                    .map(|n| format!("`{}`", n))
-                                    .unwrap_or_else(|| "the value".to_string())
-                            ),
-                            "ref ",
-                            Applicability::MachineApplicable,
-                        );
-                        in_pattern = true;
+                if !seen_spans.contains(&move_span) {
+                    if !closure {
+                        self.suggest_ref_or_clone(mpi, move_span, &mut err, &mut in_pattern);
                     }
+
+                    self.explain_captures(
+                        &mut err,
+                        span,
+                        move_span,
+                        move_spans,
+                        *moved_place,
+                        partially_str,
+                        loop_message,
+                        move_msg,
+                        is_loop_move,
+                        maybe_reinitialized_locations.is_empty(),
+                    );
                 }
+                seen_spans.insert(move_span);
             }
 
             use_spans.var_path_only_subdiag(&mut err, desired_action);
@@ -317,6 +306,160 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
+    fn suggest_ref_or_clone(
+        &mut self,
+        mpi: MovePathIndex,
+        move_span: Span,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        in_pattern: &mut bool,
+    ) {
+        struct ExpressionFinder<'hir> {
+            expr_span: Span,
+            expr: Option<&'hir hir::Expr<'hir>>,
+            pat: Option<&'hir hir::Pat<'hir>>,
+            parent_pat: Option<&'hir hir::Pat<'hir>>,
+        }
+        impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
+            fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
+                if e.span == self.expr_span {
+                    self.expr = Some(e);
+                }
+                hir::intravisit::walk_expr(self, e);
+            }
+            fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
+                if p.span == self.expr_span {
+                    self.pat = Some(p);
+                }
+                if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, sub) = p.kind {
+                    if i.span == self.expr_span || p.span == self.expr_span {
+                        self.pat = Some(p);
+                    }
+                    // Check if we are in a situation of `ident @ ident` where we want to suggest
+                    // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.
+                    if let Some(subpat) = sub && self.pat.is_none() {
+                        self.visit_pat(subpat);
+                        if self.pat.is_some() {
+                            self.parent_pat = Some(p);
+                        }
+                        return;
+                    }
+                }
+                hir::intravisit::walk_pat(self, p);
+            }
+        }
+        let hir = self.infcx.tcx.hir();
+        if let Some(hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Fn(_, _, body_id),
+            ..
+        })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
+            && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
+        {
+            let place = &self.move_data.move_paths[mpi].place;
+            let span = place.as_local()
+                .map(|local| self.body.local_decls[local].source_info.span);
+            let mut finder = ExpressionFinder {
+                expr_span: move_span,
+                expr: None,
+                pat: None,
+                parent_pat: None,
+            };
+            finder.visit_expr(expr);
+            if let Some(span) = span && let Some(expr) = finder.expr {
+                for (_, expr) in hir.parent_iter(expr.hir_id) {
+                    if let hir::Node::Expr(expr) = expr {
+                        if expr.span.contains(span) {
+                            // If the let binding occurs within the same loop, then that
+                            // loop isn't relevant, like in the following, the outermost `loop`
+                            // doesn't play into `x` being moved.
+                            // ```
+                            // loop {
+                            //     let x = String::new();
+                            //     loop {
+                            //         foo(x);
+                            //     }
+                            // }
+                            // ```
+                            break;
+                        }
+                        if let hir::ExprKind::Loop(.., loop_span) = expr.kind {
+                            err.span_label(loop_span, "inside of this loop");
+                        }
+                    }
+                }
+                let typeck = self.infcx.tcx.typeck(self.mir_def_id());
+                let hir_id = hir.get_parent_node(expr.hir_id);
+                if let Some(parent) = hir.find(hir_id) {
+                    let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
+                        && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
+                        && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
+                    {
+                        (def_id.as_local(), args, 1)
+                    } else if let hir::Node::Expr(parent_expr) = parent
+                        && let hir::ExprKind::Call(call, args) = parent_expr.kind
+                        && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
+                    {
+                        (def_id.as_local(), args, 0)
+                    } else {
+                        (None, &[][..], 0)
+                    };
+                    if let Some(def_id) = def_id
+                        && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id))
+                        && let Some(fn_sig) = node.fn_sig()
+                        && let Some(ident) = node.ident()
+                        && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
+                        && let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
+                    {
+                        let mut span: MultiSpan = arg.span.into();
+                        span.push_span_label(
+                            arg.span,
+                            "this parameter takes ownership of the value".to_string(),
+                        );
+                        let descr = match node.fn_kind() {
+                            Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function",
+                            Some(hir::intravisit::FnKind::Method(..)) => "method",
+                            Some(hir::intravisit::FnKind::Closure) => "closure",
+                        };
+                        span.push_span_label(
+                            ident.span,
+                            format!("in this {descr}"),
+                        );
+                        err.span_note(
+                            span,
+                            format!(
+                                "consider changing this parameter type in {descr} `{ident}` to \
+                                 borrow instead if owning the value isn't necessary",
+                            ),
+                        );
+                    }
+                    let place = &self.move_data.move_paths[mpi].place;
+                    let ty = place.ty(self.body, self.infcx.tcx).ty;
+                    if let hir::Node::Expr(parent_expr) = parent
+                        && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
+                        && let hir::ExprKind::Path(
+                            hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _)
+                        ) = call_expr.kind
+                    {
+                        // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
+                    } else {
+                        self.suggest_cloning(err, ty, move_span);
+                    }
+                }
+            }
+            if let Some(pat) = finder.pat {
+                *in_pattern = true;
+                let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
+                if let Some(pat) = finder.parent_pat {
+                    sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string()));
+                }
+                err.multipart_suggestion_verbose(
+                    "borrow this binding in the pattern to avoid moving the value",
+                    sugg,
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+
     fn report_use_of_uninitialized(
         &self,
         mpi: MovePathIndex,
@@ -590,6 +733,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         true
     }
 
+    fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
+        let tcx = self.infcx.tcx;
+        // Try to find predicates on *generic params* that would allow copying `ty`
+        let infcx = tcx.infer_ctxt().build();
+        if infcx
+            .type_implements_trait(
+                tcx.lang_items().clone_trait().unwrap(),
+                [tcx.erase_regions(ty)],
+                self.param_env,
+            )
+            .must_apply_modulo_regions()
+        {
+            err.span_suggestion_verbose(
+                span.shrink_to_hi(),
+                "consider cloning the value if the performance cost is acceptable",
+                ".clone()".to_string(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
         let tcx = self.infcx.tcx;
         let generics = tcx.generics_of(self.mir_def_id());
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 4c3216d9878..c500cbc49e4 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -70,7 +70,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         location: Location,
         place: PlaceRef<'tcx>,
         diag: &mut Diagnostic,
-    ) {
+    ) -> bool {
         debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
         let mut target = place.local_or_deref_local();
         for stmt in &self.body[location.block].statements[location.statement_index..] {
@@ -106,7 +106,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         {
                             place.local_or_deref_local().unwrap()
                         }
-                        _ => return,
+                        _ => return false,
                     };
 
                     debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
@@ -125,7 +125,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
                                 ),
                             );
-                            return;
+                            return true;
                         }
                     }
                 }
@@ -149,9 +149,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
                         ),
                     );
+                    return true;
                 }
             }
         }
+        false
     }
 
     /// End-user visible description of `place` if one can be found.
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index a34c17a4258..900c4427424 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -564,7 +564,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
         let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
         template_strs.push((
             template_str,
-            template_snippet.as_ref().map(|s| Symbol::intern(s)),
+            template_snippet.as_deref().map(Symbol::intern),
             template_sp,
         ));
         let template_str = template_str.as_str();
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index 220b7a8ad0f..9f42a0c2d58 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -307,7 +307,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::InlineAsm(_)
             | ExprKind::Let(_, _, _)
             | ExprKind::Lit(_)
-            | ExprKind::Loop(_, _)
+            | ExprKind::Loop(_, _, _)
             | ExprKind::MacCall(_)
             | ExprKind::Match(_, _)
             | ExprKind::Path(_, _)
diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
index fc7442470ac..df773910dbc 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
@@ -100,7 +100,7 @@ fn test_iter() {
     let s = "The %d'th word %% is: `%.*s` %!\n";
     let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect();
     assert_eq!(
-        subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
+        subs.iter().map(Option::as_deref).collect::<Vec<_>>(),
         vec![Some("{}"), None, Some("{:.*}"), None]
     );
 }
diff --git a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs
index f5f82732f20..93a7afcd6e8 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs
@@ -39,7 +39,7 @@ fn test_iter() {
     let s = "The $0'th word $$ is: `$WORD` $!\n";
     let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect();
     assert_eq!(
-        subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
+        subs.iter().map(Option::as_deref).collect::<Vec<_>>(),
         vec![Some("{0}"), None, Some("{WORD}")]
     );
 }
diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs
index 48da64906e2..c627af4e62f 100644
--- a/compiler/rustc_codegen_cranelift/build_system/utils.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs
@@ -104,5 +104,5 @@ pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) {
 }
 
 pub(crate) fn is_ci() -> bool {
-    env::var("CI").as_ref().map(|val| &**val) == Ok("true")
+    env::var("CI").as_deref() == Ok("true")
 }
diff --git a/compiler/rustc_codegen_cranelift/src/config.rs b/compiler/rustc_codegen_cranelift/src/config.rs
index e59a0cb0a23..45522fb1a4c 100644
--- a/compiler/rustc_codegen_cranelift/src/config.rs
+++ b/compiler/rustc_codegen_cranelift/src/config.rs
@@ -2,7 +2,7 @@ use std::env;
 use std::str::FromStr;
 
 fn bool_env_var(key: &str) -> bool {
-    env::var(key).as_ref().map(|val| &**val) == Ok("1")
+    env::var(key).as_deref() == Ok("1")
 }
 
 /// The mode to use for compilation.
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 8a8d889a298..86580d05d41 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -174,7 +174,7 @@ impl CoverageMapGenerator {
         counter_regions.sort_unstable_by_key(|(_counter, region)| *region);
         for (counter, region) in counter_regions {
             let CodeRegion { file_name, start_line, start_col, end_line, end_col } = *region;
-            let same_file = current_file_name.as_ref().map_or(false, |p| *p == file_name);
+            let same_file = current_file_name.map_or(false, |p| p == file_name);
             if !same_file {
                 if current_file_name.is_some() {
                     current_file_id += 1;
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 7822d924c01..03d833fbba8 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -938,7 +938,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         // that is understood elsewhere in the compiler as a method on
                         // `dyn Trait`.
                         // To get a `*mut RcBox<Self>`, we just keep unwrapping newtypes until
-                        // we get a value of a built-in pointer type
+                        // we get a value of a built-in pointer type.
+                        //
+                        // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`.
                         'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
                             && !op.layout.ty.is_region_ptr()
                         {
@@ -980,13 +982,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         continue;
                     }
                     Immediate(_) => {
-                        let ty::Ref(_, ty, _) = op.layout.ty.kind() else {
-                            span_bug!(span, "can't codegen a virtual call on {:#?}", op);
-                        };
-                        if !ty.is_dyn_star() {
+                        // See comment above explaining why we peel these newtypes
+                        'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
+                            && !op.layout.ty.is_region_ptr()
+                        {
+                            for i in 0..op.layout.fields.count() {
+                                let field = op.extract_field(bx, i);
+                                if !field.layout.is_zst() {
+                                    // we found the one non-zero-sized field that is allowed
+                                    // now find *its* non-zero-sized field, or stop if it's a
+                                    // pointer
+                                    op = field;
+                                    continue 'descend_newtypes;
+                                }
+                            }
+
+                            span_bug!(span, "receiver has no non-zero-sized fields {:?}", op);
+                        }
+
+                        // Make sure that we've actually unwrapped the rcvr down
+                        // to a pointer or ref to `dyn* Trait`.
+                        if !op.layout.ty.builtin_deref(true).unwrap().ty.is_dyn_star() {
                             span_bug!(span, "can't codegen a virtual call on {:#?}", op);
                         }
-                        // FIXME(dyn-star): Make sure this is done on a &dyn* receiver
                         let place = op.deref(bx.cx());
                         let data_ptr = place.project_field(bx, 0);
                         let meta_ptr = place.project_field(bx, 1);
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 8a712cec852..8e176efb2a9 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -318,7 +318,7 @@ fn run_compiler(
                             compiler.input(),
                             &*expanded_crate,
                             *ppm,
-                            compiler.output_file().as_ref().map(|p| &**p),
+                            compiler.output_file().as_deref(),
                         );
                         Ok(())
                     })?;
@@ -329,7 +329,7 @@ fn run_compiler(
                         compiler.input(),
                         &krate,
                         *ppm,
-                        compiler.output_file().as_ref().map(|p| &**p),
+                        compiler.output_file().as_deref(),
                     );
                 }
                 trace!("finished pretty-printing");
@@ -383,10 +383,7 @@ fn run_compiler(
                             &crate_name,
                             compiler.input(),
                             None,
-                            DumpHandler::new(
-                                compiler.output_dir().as_ref().map(|p| &**p),
-                                &crate_name,
-                            ),
+                            DumpHandler::new(compiler.output_dir().as_deref(), &crate_name),
                         )
                     });
                 }
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index bc136aea44d..bf20c7431e4 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -248,7 +248,7 @@ pub trait Emitter: Translate {
         fluent_args: &FluentArgs<'_>,
     ) -> (MultiSpan, &'a [CodeSuggestion]) {
         let mut primary_span = diag.span.clone();
-        let suggestions = diag.suggestions.as_ref().map_or(&[][..], |suggestions| &suggestions[..]);
+        let suggestions = diag.suggestions.as_deref().unwrap_or(&[]);
         if let Some((sugg, rest)) = suggestions.split_first() {
             let msg = self.translate_message(&sugg.msg, fluent_args);
             if rest.is_empty() &&
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index bd5b93293a9..473a04f33a9 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3594,9 +3594,16 @@ mod size_asserts {
     static_assert_size!(Res, 12);
     static_assert_size!(Stmt<'_>, 32);
     static_assert_size!(StmtKind<'_>, 16);
+    // tidy-alphabetical-end
+    // FIXME: move the tidy directive to the end after the next bootstrap bump
+    #[cfg(bootstrap)]
     static_assert_size!(TraitItem<'_>, 88);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(TraitItem<'_>, 80);
+    #[cfg(bootstrap)]
     static_assert_size!(TraitItemKind<'_>, 48);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(TraitItemKind<'_>, 40);
     static_assert_size!(Ty<'_>, 48);
     static_assert_size!(TyKind<'_>, 32);
-    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 9b8cc884e18..5d63d90f304 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -2157,7 +2157,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
         .emit();
     }
     let meta_item_list = attr.meta_item_list();
-    let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref);
+    let meta_item_list = meta_item_list.as_deref();
     let sole_meta_list = match meta_item_list {
         Some([item]) => item.literal(),
         Some(_) => {
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 42aa3bcee49..25b6cf4ef2e 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -30,7 +30,7 @@ use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
-use std::iter;
+use std::{iter, slice};
 
 /// Checks that it is legal to call methods of the trait corresponding
 /// to `trait_id` (this only cares about the trait, not the specific
@@ -227,22 +227,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ] {
             let Some(trait_def_id) = opt_trait_def_id else { continue };
 
-            let opt_input_types = opt_arg_exprs.map(|arg_exprs| {
-                [self.tcx.mk_tup(arg_exprs.iter().map(|e| {
+            let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
+                self.tcx.mk_tup(arg_exprs.iter().map(|e| {
                     self.next_ty_var(TypeVariableOrigin {
                         kind: TypeVariableOriginKind::TypeInference,
                         span: e.span,
                     })
-                }))]
+                }))
             });
-            let opt_input_types = opt_input_types.as_ref().map(AsRef::as_ref);
 
             if let Some(ok) = self.lookup_method_in_trait(
                 call_expr.span,
                 method_name,
                 trait_def_id,
                 adjusted_ty,
-                opt_input_types,
+                opt_input_type.as_ref().map(slice::from_ref),
             ) {
                 let method = self.register_infer_ok_obligations(ok);
                 let mut autoref = None;
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 43c7127b0d4..82784bb8a66 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -46,7 +46,7 @@ use rustc_hir::Expr;
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
-use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
+use rustc_infer::traits::Obligation;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -62,8 +62,7 @@ use rustc_span::{self, BytePos, DesugaringKind, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::TraitEngineExt as _;
-use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt};
 
 use smallvec::{smallvec, SmallVec};
 use std::ops::Deref;
@@ -589,7 +588,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             }
             _ => None,
         };
-        let coerce_source = reborrow.as_ref().map_or(source, |&(_, ref r)| r.target);
+        let coerce_source = reborrow.as_ref().map_or(source, |(_, r)| r.target);
 
         // Setup either a subtyping or a LUB relationship between
         // the `CoerceUnsized` target type and the expected type.
@@ -756,20 +755,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         if let ty::Dynamic(a_data, _, _) = a.kind()
             && let ty::Dynamic(b_data, _, _) = b.kind()
+            && a_data.principal_def_id() == b_data.principal_def_id()
         {
-            if a_data.principal_def_id() == b_data.principal_def_id() {
-                return self.unify_and(a, b, |_| vec![]);
-            } else if !self.tcx().features().trait_upcasting {
-                let mut err = feature_err(
-                    &self.tcx.sess.parse_sess,
-                    sym::trait_upcasting,
-                    self.cause.span,
-                    &format!(
-                        "cannot cast `{a}` to `{b}`, trait upcasting coercion is experimental"
-                    ),
-                );
-                err.emit();
-            }
+            return self.unify_and(a, b, |_| vec![]);
         }
 
         // Check the obligations of the cast -- for example, when casting
@@ -797,19 +785,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             ])
             .collect();
 
-        // Enforce that the type is `usize`/pointer-sized. For now, only those
-        // can be coerced to `dyn*`, except for `dyn* -> dyn*` upcasts.
-        if !a.is_dyn_star() {
-            obligations.push(Obligation::new(
-                self.tcx,
-                self.cause.clone(),
-                self.param_env,
-                ty::Binder::dummy(
-                    self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
-                )
-                .to_poly_trait_predicate(),
-            ));
-        }
+        // Enforce that the type is `usize`/pointer-sized.
+        obligations.push(Obligation::new(
+            self.tcx,
+            self.cause.clone(),
+            self.param_env,
+            ty::Binder::dummy(
+                self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
+            )
+            .to_poly_trait_predicate(),
+        ));
 
         Ok(InferOk {
             value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
@@ -1055,9 +1040,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let Ok(ok) = coerce.coerce(source, target) else {
                 return false;
             };
-            let mut fcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx);
-            fcx.register_predicate_obligations(self, ok.obligations);
-            fcx.select_where_possible(&self).is_empty()
+            let ocx = ObligationCtxt::new_in_snapshot(self);
+            ocx.register_obligations(ok.obligations);
+            ocx.select_where_possible().is_empty()
         })
     }
 
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index a78b294181c..fd8ea1ad7bf 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -9,9 +9,10 @@ use hir::{
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_index::vec::IndexVec;
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::{
     hir::map::Map,
-    ty::{TyCtxt, TypeckResults},
+    ty::{ParamEnv, TyCtxt, TypeVisitable, TypeckResults},
 };
 use std::mem::swap;
 
@@ -21,20 +22,29 @@ use std::mem::swap;
 /// The resulting structure still needs to be iterated to a fixed point, which
 /// can be done with propagate_to_fixpoint in cfg_propagate.
 pub(super) fn build_control_flow_graph<'tcx>(
-    hir: Map<'tcx>,
-    tcx: TyCtxt<'tcx>,
+    infcx: &InferCtxt<'tcx>,
     typeck_results: &TypeckResults<'tcx>,
+    param_env: ParamEnv<'tcx>,
     consumed_borrowed_places: ConsumedAndBorrowedPlaces,
     body: &'tcx Body<'tcx>,
     num_exprs: usize,
 ) -> (DropRangesBuilder, FxHashSet<HirId>) {
-    let mut drop_range_visitor =
-        DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
+    let mut drop_range_visitor = DropRangeVisitor::new(
+        infcx,
+        typeck_results,
+        param_env,
+        consumed_borrowed_places,
+        num_exprs,
+    );
     intravisit::walk_body(&mut drop_range_visitor, body);
 
     drop_range_visitor.drop_ranges.process_deferred_edges();
-    if let Some(filename) = &tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
-        super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
+    if let Some(filename) = &infcx.tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
+        super::cfg_visualize::write_graph_to_file(
+            &drop_range_visitor.drop_ranges,
+            filename,
+            infcx.tcx,
+        );
     }
 
     (drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
@@ -82,40 +92,44 @@ pub(super) fn build_control_flow_graph<'tcx>(
 /// ```
 
 struct DropRangeVisitor<'a, 'tcx> {
-    hir: Map<'tcx>,
+    typeck_results: &'a TypeckResults<'tcx>,
+    infcx: &'a InferCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
     places: ConsumedAndBorrowedPlaces,
     drop_ranges: DropRangesBuilder,
     expr_index: PostOrderId,
-    tcx: TyCtxt<'tcx>,
-    typeck_results: &'a TypeckResults<'tcx>,
     label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
 }
 
 impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
     fn new(
-        hir: Map<'tcx>,
-        tcx: TyCtxt<'tcx>,
+        infcx: &'a InferCtxt<'tcx>,
         typeck_results: &'a TypeckResults<'tcx>,
+        param_env: ParamEnv<'tcx>,
         places: ConsumedAndBorrowedPlaces,
         num_exprs: usize,
     ) -> Self {
         debug!("consumed_places: {:?}", places.consumed);
         let drop_ranges = DropRangesBuilder::new(
             places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
-            hir,
+            infcx.tcx.hir(),
             num_exprs,
         );
         Self {
-            hir,
+            infcx,
+            typeck_results,
+            param_env,
             places,
             drop_ranges,
             expr_index: PostOrderId::from_u32(0),
-            typeck_results,
-            tcx,
             label_stack: vec![],
         }
     }
 
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
     fn record_drop(&mut self, value: TrackedValue) {
         if self.places.borrowed.contains(&value) {
             debug!("not marking {:?} as dropped because it is borrowed at some point", value);
@@ -137,7 +151,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
             .map_or(vec![], |places| places.iter().cloned().collect());
         for place in places {
             trace!(?place, "consuming place");
-            for_each_consumable(self.hir, place, |value| self.record_drop(value));
+            for_each_consumable(self.tcx().hir(), place, |value| self.record_drop(value));
         }
     }
 
@@ -214,10 +228,15 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
     /// return.
     fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
         let ty = self.typeck_results.expr_ty(expr);
-        let ty = self.tcx.erase_regions(ty);
-        let m = self.tcx.parent_module(expr.hir_id).to_def_id();
-        let param_env = self.tcx.param_env(m.expect_local());
-        if !ty.is_inhabited_from(self.tcx, m, param_env) {
+        let ty = self.infcx.resolve_vars_if_possible(ty);
+        if ty.has_non_region_infer() {
+            self.tcx()
+                .sess
+                .delay_span_bug(expr.span, format!("could not resolve infer vars in `{ty}`"));
+        }
+        let ty = self.tcx().erase_regions(ty);
+        let m = self.tcx().parent_module(expr.hir_id).to_def_id();
+        if !ty.is_inhabited_from(self.tcx(), m, self.param_env) {
             // This function will not return. We model this fact as an infinite loop.
             self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
         }
@@ -238,7 +257,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
         destination: hir::Destination,
     ) -> Result<HirId, LoopIdError> {
         destination.target_id.map(|target| {
-            let node = self.hir.get(target);
+            let node = self.tcx().hir().get(target);
             match node {
                 hir::Node::Expr(_) => target,
                 hir::Node::Block(b) => find_last_block_expression(b),
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
index 4f3bdfbe758..2abcadcc9ce 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
@@ -43,9 +43,9 @@ pub fn compute_drop_ranges<'a, 'tcx>(
         let typeck_results = &fcx.typeck_results.borrow();
         let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
         let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
-            fcx.tcx.hir(),
-            fcx.tcx,
+            &fcx,
             typeck_results,
+            fcx.param_env,
             consumed_borrowed_places,
             body,
             num_exprs,
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 89aaa0b95e4..99c934862c4 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -304,7 +304,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 parse_sess_created(&mut sess.parse_sess);
             }
 
-            let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
+            let temps_dir = sess.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
 
             let compiler = Compiler {
                 sess: Lrc::new(sess),
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 91d180e1eb7..fc0b11183f7 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -33,11 +33,7 @@ pub struct Query<T> {
 
 impl<T> Query<T> {
     fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
-        let mut result = self.result.borrow_mut();
-        if result.is_none() {
-            *result = Some(f());
-        }
-        result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err)
+        self.result.borrow_mut().get_or_insert_with(f).as_ref().map(|_| self).map_err(|&err| err)
     }
 
     /// Takes ownership of the query result. Further attempts to take or peek the query
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 2fe3fb2fa56..4142964a0da 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -68,10 +68,7 @@ pub fn create_session(
     let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
         make_codegen_backend(&sopts)
     } else {
-        get_codegen_backend(
-            &sopts.maybe_sysroot,
-            sopts.unstable_opts.codegen_backend.as_ref().map(|name| &name[..]),
-        )
+        get_codegen_backend(&sopts.maybe_sysroot, sopts.unstable_opts.codegen_backend.as_deref())
     };
 
     // target_override is documented to be called before init(), so this is okay
@@ -260,7 +257,7 @@ pub fn rustc_path<'a>() -> Option<&'a Path> {
 
     const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR");
 
-    RUSTC_PATH.get_or_init(|| get_rustc_path_inner(BIN_PATH)).as_ref().map(|v| &**v)
+    RUSTC_PATH.get_or_init(|| get_rustc_path_inner(BIN_PATH)).as_deref()
 }
 
 fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
diff --git a/compiler/rustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs
index c7ca8fd16ae..1c25b03fdb2 100644
--- a/compiler/rustc_lexer/src/unescape/tests.rs
+++ b/compiler/rustc_lexer/src/unescape/tests.rs
@@ -132,8 +132,7 @@ fn test_unescape_str_good() {
                 }
             }
         });
-        let buf = buf.as_ref().map(|it| it.as_ref());
-        assert_eq!(buf, Ok(expected))
+        assert_eq!(buf.as_deref(), Ok(expected))
     }
 
     check("foo", "foo");
@@ -250,8 +249,7 @@ fn test_unescape_byte_str_good() {
                 }
             }
         });
-        let buf = buf.as_ref().map(|it| it.as_ref());
-        assert_eq!(buf, Ok(expected))
+        assert_eq!(buf.as_deref(), Ok(expected))
     }
 
     check("foo", b"foo");
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 589b4d6a10f..67cf66f4708 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1245,6 +1245,23 @@ impl<'tcx> LateContext<'tcx> {
 
         AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap()
     }
+
+    /// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`.
+    /// Do not invoke without first verifying that the type implements the trait.
+    pub fn get_associated_type(
+        &self,
+        self_ty: Ty<'tcx>,
+        trait_id: DefId,
+        name: &str,
+    ) -> Option<Ty<'tcx>> {
+        let tcx = self.tcx;
+        tcx.associated_items(trait_id)
+            .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
+            .and_then(|assoc| {
+                let proj = tcx.mk_projection(assoc.def_id, tcx.mk_substs_trait(self_ty, []));
+                tcx.try_normalize_erasing_regions(self.param_env, proj).ok()
+            })
+    }
 }
 
 impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
new file mode 100644
index 00000000000..1d29a234a3c
--- /dev/null
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -0,0 +1,92 @@
+use crate::{LateContext, LateLintPass, LintContext};
+
+use rustc_errors::DelayDm;
+use rustc_hir as hir;
+use rustc_middle::{traits::util::supertraits, ty};
+use rustc_span::sym;
+
+declare_lint! {
+    /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
+    /// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
+    ///
+    /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
+    /// The `deref` functions will no longer be called implicitly, so there might be behavior change.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(deref_into_dyn_supertrait)]
+    /// #![allow(dead_code)]
+    ///
+    /// use core::ops::Deref;
+    ///
+    /// trait A {}
+    /// trait B: A {}
+    /// impl<'a> Deref for dyn 'a + B {
+    ///     type Target = dyn A;
+    ///     fn deref(&self) -> &Self::Target {
+    ///         todo!()
+    ///     }
+    /// }
+    ///
+    /// fn take_a(_: &dyn A) { }
+    ///
+    /// fn take_b(b: &dyn B) {
+    ///     take_a(b);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The dyn upcasting coercion feature adds new coercion rules, taking priority
+    /// over certain other coercion rules, which will cause some behavior change.
+    pub DEREF_INTO_DYN_SUPERTRAIT,
+    Warn,
+    "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
+    };
+}
+
+declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);
+
+impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+        // `Deref` is being implemented for `t`
+        if let hir::ItemKind::Impl(impl_) = item.kind
+            && let Some(trait_) = &impl_.of_trait
+            && let t = cx.tcx.type_of(item.owner_id)
+            && let opt_did @ Some(did) = trait_.trait_def_id()
+            && opt_did == cx.tcx.lang_items().deref_trait()
+            // `t` is `dyn t_principal`
+            && let ty::Dynamic(data, _, ty::Dyn) = t.kind()
+            && let Some(t_principal) = data.principal()
+            // `<T as Deref>::Target` is `dyn target_principal`
+            && let Some(target) = cx.get_associated_type(t, did, "Target")
+            && let ty::Dynamic(data, _, ty::Dyn) = target.kind()
+            && let Some(target_principal) = data.principal()
+            // `target_principal` is a supertrait of `t_principal`
+            && supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self))
+                .any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal)
+        {
+            cx.struct_span_lint(
+                DEREF_INTO_DYN_SUPERTRAIT,
+                cx.tcx.def_span(item.owner_id.def_id),
+                DelayDm(|| {
+                    format!(
+                        "`{t}` implements `Deref` with supertrait `{target_principal}` as target"
+                    )
+                }),
+                |lint| {
+                    if let Some(target_span) = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) {
+                        lint.span_label(target_span, "target type is set here");
+                    }
+
+                    lint
+                },
+            )
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index ebb7de70e05..b6027476adf 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -49,6 +49,7 @@ extern crate tracing;
 mod array_into_iter;
 pub mod builtin;
 mod context;
+mod deref_into_dyn_supertrait;
 mod early;
 mod enum_intrinsics_non_enums;
 mod errors;
@@ -87,6 +88,7 @@ use rustc_span::Span;
 
 use array_into_iter::ArrayIntoIter;
 use builtin::*;
+use deref_into_dyn_supertrait::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
 use for_loops_over_fallibles::*;
 use hidden_unicode_codepoints::*;
@@ -192,6 +194,7 @@ macro_rules! late_lint_mod_passes {
             $args,
             [
                 ForLoopsOverFallibles: ForLoopsOverFallibles,
+                DerefIntoDynSupertrait: DerefIntoDynSupertrait,
                 HardwiredLints: HardwiredLints,
                 ImproperCTypesDeclarations: ImproperCTypesDeclarations,
                 ImproperCTypesDefinitions: ImproperCTypesDefinitions,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index b80facb1759..df0e17dea3c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3262,7 +3262,6 @@ declare_lint_pass! {
         UNUSED_TUPLE_STRUCT_FIELDS,
         NON_EXHAUSTIVE_OMITTED_PATTERNS,
         TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
-        DEREF_INTO_DYN_SUPERTRAIT,
         DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
         DUPLICATE_MACRO_ATTRIBUTES,
         SUSPICIOUS_AUTO_TRAIT_IMPLS,
@@ -3765,51 +3764,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
-    /// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
-    ///
-    /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
-    /// The `deref` functions will no longer be called implicitly, so there might be behavior change.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail
-    /// #![deny(deref_into_dyn_supertrait)]
-    /// #![allow(dead_code)]
-    ///
-    /// use core::ops::Deref;
-    ///
-    /// trait A {}
-    /// trait B: A {}
-    /// impl<'a> Deref for dyn 'a + B {
-    ///     type Target = dyn A;
-    ///     fn deref(&self) -> &Self::Target {
-    ///         todo!()
-    ///     }
-    /// }
-    ///
-    /// fn take_a(_: &dyn A) { }
-    ///
-    /// fn take_b(b: &dyn B) {
-    ///     take_a(b);
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// The dyn upcasting coercion feature adds new coercion rules, taking priority
-    /// over certain other coercion rules, which will cause some behavior change.
-    pub DEREF_INTO_DYN_SUPERTRAIT,
-    Warn,
-    "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
-    };
-}
-
-declare_lint! {
     /// The `duplicate_macro_attributes` lint detects when a `#[test]`-like built-in macro
     /// attribute is duplicated on an item. This lint may trigger on `bench`, `cfg_eval`, `test`
     /// and `test_case`.
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 18d37d95a83..5f02bb6c307 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -800,7 +800,7 @@ LLVMRustOptimize(
       auto Plugin = PassPlugin::Load(PluginPath.str());
       if (!Plugin) {
         LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str());
-        continue;
+        return LLVMRustResult::Failure;
       }
       Plugin->registerPassBuilderCallbacks(PB);
     }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index d4c457975a8..1a2389c7a84 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -162,7 +162,7 @@ impl CStore {
     pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
         self.metas
             .iter_enumerated()
-            .filter_map(|(cnum, data)| data.as_ref().map(|data| (cnum, &**data)))
+            .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
     }
 
     fn push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum) {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index af4be12fe3a..0602b7fc3bd 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -2166,7 +2166,7 @@ impl EncodedMetadata {
 
     #[inline]
     pub fn raw_data(&self) -> &[u8] {
-        self.mmap.as_ref().map(|mmap| mmap.as_ref()).unwrap_or_default()
+        self.mmap.as_deref().unwrap_or_default()
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 396782d45d2..edd52728626 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -65,7 +65,7 @@ pub(crate) enum PlaceBase {
 
 /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
 /// place by pushing more and more projections onto the end, and then convert the final set into a
-/// place using the `into_place` method.
+/// place using the `to_place` method.
 ///
 /// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
 /// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
@@ -167,59 +167,54 @@ fn find_capture_matching_projections<'a, 'tcx>(
     })
 }
 
-/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the
-/// `PlaceBuilder` now starts from `PlaceBase::Local`.
-///
-/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
+/// Takes an upvar place and tries to resolve it into a `PlaceBuilder`
+/// with `PlaceBase::Local`
 #[instrument(level = "trace", skip(cx), ret)]
 fn to_upvars_resolved_place_builder<'tcx>(
-    from_builder: PlaceBuilder<'tcx>,
     cx: &Builder<'_, 'tcx>,
-) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
-    match from_builder.base {
-        PlaceBase::Local(_) => Ok(from_builder),
-        PlaceBase::Upvar { var_hir_id, closure_def_id } => {
-            let Some((capture_index, capture)) =
-                find_capture_matching_projections(
-                    &cx.upvars,
-                    var_hir_id,
-                    &from_builder.projection,
-                ) else {
-                let closure_span = cx.tcx.def_span(closure_def_id);
-                if !enable_precise_capture(cx.tcx, closure_span) {
-                    bug!(
-                        "No associated capture found for {:?}[{:#?}] even though \
-                            capture_disjoint_fields isn't enabled",
-                        var_hir_id,
-                        from_builder.projection
-                    )
-                } else {
-                    debug!(
-                        "No associated capture found for {:?}[{:#?}]",
-                        var_hir_id, from_builder.projection,
-                    );
-                }
-                return Err(from_builder);
-            };
+    var_hir_id: LocalVarId,
+    closure_def_id: LocalDefId,
+    projection: &[PlaceElem<'tcx>],
+) -> Option<PlaceBuilder<'tcx>> {
+    let Some((capture_index, capture)) =
+        find_capture_matching_projections(
+            &cx.upvars,
+            var_hir_id,
+            &projection,
+        ) else {
+        let closure_span = cx.tcx.def_span(closure_def_id);
+        if !enable_precise_capture(cx.tcx, closure_span) {
+            bug!(
+                "No associated capture found for {:?}[{:#?}] even though \
+                    capture_disjoint_fields isn't enabled",
+                var_hir_id,
+                projection
+            )
+        } else {
+            debug!(
+                "No associated capture found for {:?}[{:#?}]",
+                var_hir_id, projection,
+            );
+        }
+        return None;
+    };
 
-            // Access the capture by accessing the field within the Closure struct.
-            let capture_info = &cx.upvars[capture_index];
+    // Access the capture by accessing the field within the Closure struct.
+    let capture_info = &cx.upvars[capture_index];
 
-            let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place);
+    let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place);
 
-            // We used some of the projections to build the capture itself,
-            // now we apply the remaining to the upvar resolved place.
-            trace!(?capture.captured_place, ?from_builder.projection);
-            let remaining_projections = strip_prefix(
-                capture.captured_place.place.base_ty,
-                from_builder.projection,
-                &capture.captured_place.place.projections,
-            );
-            upvar_resolved_place_builder.projection.extend(remaining_projections);
+    // We used some of the projections to build the capture itself,
+    // now we apply the remaining to the upvar resolved place.
+    trace!(?capture.captured_place, ?projection);
+    let remaining_projections = strip_prefix(
+        capture.captured_place.place.base_ty,
+        projection,
+        &capture.captured_place.place.projections,
+    );
+    upvar_resolved_place_builder.projection.extend(remaining_projections);
 
-            Ok(upvar_resolved_place_builder)
-        }
-    }
+    Some(upvar_resolved_place_builder)
 }
 
 /// Returns projections remaining after stripping an initial prefix of HIR
@@ -228,13 +223,14 @@ fn to_upvars_resolved_place_builder<'tcx>(
 /// Supports only HIR projection kinds that represent a path that might be
 /// captured by a closure or a generator, i.e., an `Index` or a `Subslice`
 /// projection kinds are unsupported.
-fn strip_prefix<'tcx>(
+fn strip_prefix<'a, 'tcx>(
     mut base_ty: Ty<'tcx>,
-    projections: Vec<PlaceElem<'tcx>>,
+    projections: &'a [PlaceElem<'tcx>],
     prefix_projections: &[HirProjection<'tcx>],
-) -> impl Iterator<Item = PlaceElem<'tcx>> {
+) -> impl Iterator<Item = PlaceElem<'tcx>> + 'a {
     let mut iter = projections
-        .into_iter()
+        .iter()
+        .copied()
         // Filter out opaque casts, they are unnecessary in the prefix.
         .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..)));
     for projection in prefix_projections {
@@ -258,21 +254,21 @@ fn strip_prefix<'tcx>(
 }
 
 impl<'tcx> PlaceBuilder<'tcx> {
-    pub(in crate::build) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
-        if let PlaceBase::Local(local) = self.base {
-            Place { local, projection: cx.tcx.intern_place_elems(&self.projection) }
-        } else {
-            self.expect_upvars_resolved(cx).into_place(cx)
-        }
+    pub(in crate::build) fn to_place(&self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
+        self.try_to_place(cx).unwrap()
     }
 
-    fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> {
-        to_upvars_resolved_place_builder(self, cx).unwrap()
+    /// Creates a `Place` or returns `None` if an upvar cannot be resolved
+    pub(in crate::build) fn try_to_place(&self, cx: &Builder<'_, 'tcx>) -> Option<Place<'tcx>> {
+        let resolved = self.resolve_upvar(cx);
+        let builder = resolved.as_ref().unwrap_or(self);
+        let PlaceBase::Local(local) = builder.base else { return None };
+        let projection = cx.tcx.intern_place_elems(&builder.projection);
+        Some(Place { local, projection })
     }
 
     /// Attempts to resolve the `PlaceBuilder`.
-    /// On success, it will return the resolved `PlaceBuilder`.
-    /// On failure, it will return itself.
+    /// Returns `None` if this is not an upvar.
     ///
     /// Upvars resolve may fail for a `PlaceBuilder` when attempting to
     /// resolve a disjoint field whose root variable is not captured
@@ -281,11 +277,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
     /// not captured. This can happen because the final mir that will be
     /// generated doesn't require a read for this place. Failures will only
     /// happen inside closures.
-    pub(in crate::build) fn try_upvars_resolved(
-        self,
+    pub(in crate::build) fn resolve_upvar(
+        &self,
         cx: &Builder<'_, 'tcx>,
-    ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
-        to_upvars_resolved_place_builder(self, cx)
+    ) -> Option<PlaceBuilder<'tcx>> {
+        let PlaceBase::Upvar { var_hir_id, closure_def_id } = self.base else {
+            return None;
+        };
+        to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &self.projection)
     }
 
     pub(crate) fn base(&self) -> PlaceBase {
@@ -316,6 +315,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
         self.projection.push(elem);
         self
     }
+
+    /// Same as `.clone().project(..)` but more efficient
+    pub(crate) fn clone_project(&self, elem: PlaceElem<'tcx>) -> Self {
+        Self {
+            base: self.base,
+            projection: Vec::from_iter(self.projection.iter().copied().chain([elem])),
+        }
+    }
 }
 
 impl<'tcx> From<Local> for PlaceBuilder<'tcx> {
@@ -355,7 +362,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_place_builder(block, expr));
-        block.and(place_builder.into_place(self))
+        block.and(place_builder.to_place(self))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -379,7 +386,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
-        block.and(place_builder.into_place(self))
+        block.and(place_builder.to_place(self))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -474,7 +481,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             inferred_ty: expr.ty,
                         });
 
-                    let place = place_builder.clone().into_place(this);
+                    let place = place_builder.to_place(this);
                     this.cfg.push(
                         block,
                         Statement {
@@ -599,7 +606,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let is_outermost_index = fake_borrow_temps.is_none();
         let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps);
 
-        let mut base_place =
+        let base_place =
             unpack!(block = self.expr_as_place(block, base, mutability, Some(fake_borrow_temps),));
 
         // Making this a *fresh* temporary means we do not have to worry about
@@ -607,14 +614,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // The "retagging" transformation (for Stacked Borrows) relies on this.
         let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not,));
 
-        block = self.bounds_check(block, base_place.clone(), idx, expr_span, source_info);
+        block = self.bounds_check(block, &base_place, idx, expr_span, source_info);
 
         if is_outermost_index {
             self.read_fake_borrows(block, fake_borrow_temps, source_info)
         } else {
-            base_place = base_place.expect_upvars_resolved(self);
             self.add_fake_borrows_of_base(
-                &base_place,
+                base_place.to_place(self),
                 block,
                 fake_borrow_temps,
                 expr_span,
@@ -628,7 +634,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn bounds_check(
         &mut self,
         block: BasicBlock,
-        slice: PlaceBuilder<'tcx>,
+        slice: &PlaceBuilder<'tcx>,
         index: Local,
         expr_span: Span,
         source_info: SourceInfo,
@@ -640,7 +646,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let lt = self.temp(bool_ty, expr_span);
 
         // len = len(slice)
-        self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self)));
+        self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.to_place(self)));
         // lt = idx < len
         self.cfg.push_assign(
             block,
@@ -658,19 +664,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     fn add_fake_borrows_of_base(
         &mut self,
-        base_place: &PlaceBuilder<'tcx>,
+        base_place: Place<'tcx>,
         block: BasicBlock,
         fake_borrow_temps: &mut Vec<Local>,
         expr_span: Span,
         source_info: SourceInfo,
     ) {
         let tcx = self.tcx;
-        let local = match base_place.base {
-            PlaceBase::Local(local) => local,
-            PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar"),
-        };
 
-        let place_ty = Place::ty_from(local, &base_place.projection, &self.local_decls, tcx);
+        let place_ty = base_place.ty(&self.local_decls, tcx);
         if let ty::Slice(_) = place_ty.ty.kind() {
             // We need to create fake borrows to ensure that the bounds
             // check that we just did stays valid. Since we can't assign to
@@ -680,7 +682,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 match elem {
                     ProjectionElem::Deref => {
                         let fake_borrow_deref_ty = Place::ty_from(
-                            local,
+                            base_place.local,
                             &base_place.projection[..idx],
                             &self.local_decls,
                             tcx,
@@ -698,14 +700,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             Rvalue::Ref(
                                 tcx.lifetimes.re_erased,
                                 BorrowKind::Shallow,
-                                Place { local, projection },
+                                Place { local: base_place.local, projection },
                             ),
                         );
                         fake_borrow_temps.push(fake_borrow_temp);
                     }
                     ProjectionElem::Index(_) => {
                         let index_ty = Place::ty_from(
-                            local,
+                            base_place.local,
                             &base_place.projection[..idx],
                             &self.local_decls,
                             tcx,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 5c82fb1ddc0..0814793f277 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -369,8 +369,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let place_builder =
                         unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
 
-                    if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) {
-                        let mir_place = place_builder_resolved.into_place(this);
+                    if let Some(mir_place) = place_builder.try_to_place(this) {
                         this.cfg.push_fake_read(
                             block,
                             this.source_info(this.tcx.hir().span(*hir_id)),
@@ -661,7 +660,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // by the parent itself. The mutability of the current capture
             // is same as that of the capture in the parent closure.
             PlaceBase::Upvar { .. } => {
-                let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this);
+                let enclosing_upvars_resolved = arg_place_builder.to_place(this);
 
                 match enclosing_upvars_resolved.as_ref() {
                     PlaceRef {
@@ -698,7 +697,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
         };
 
-        let arg_place = arg_place_builder.into_place(this);
+        let arg_place = arg_place_builder.to_place(this);
 
         this.cfg.push_assign(
             block,
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 33e4fa58399..218a26e6279 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -358,10 +358,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         .map(|(n, ty)| match fields_map.get(&n) {
                             Some(v) => v.clone(),
                             None => {
-                                let place_builder = place_builder.clone();
-                                this.consume_by_copy_or_move(
-                                    place_builder.field(n, *ty).into_place(this),
-                                )
+                                let place = place_builder.clone_project(PlaceElem::Field(n, *ty));
+                                this.consume_by_copy_or_move(place.to_place(this))
                             }
                         })
                         .collect()
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 802704d6ca7..691cbee2c73 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -169,7 +169,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let scrutinee_place =
             unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
 
-        let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms);
+        let mut arm_candidates = self.create_match_candidates(&scrutinee_place, &arms);
 
         let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard);
         let mut candidates =
@@ -221,8 +221,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
         let source_info = self.source_info(scrutinee_span);
 
-        if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) {
-            let scrutinee_place = scrutinee_builder.into_place(self);
+        if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) {
             self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
         }
 
@@ -232,7 +231,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Create the initial `Candidate`s for a `match` expression.
     fn create_match_candidates<'pat>(
         &mut self,
-        scrutinee: PlaceBuilder<'tcx>,
+        scrutinee: &PlaceBuilder<'tcx>,
         arms: &'pat [ArmId],
     ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)>
     where
@@ -335,7 +334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let arm_scope = (arm.scope, arm_source_info);
                 let match_scope = self.local_scope();
                 self.in_scope(arm_scope, arm.lint_level, |this| {
-                    // `try_upvars_resolved` may fail if it is unable to resolve the given
+                    // `try_to_place` may fail if it is unable to resolve the given
                     // `PlaceBuilder` inside a closure. In this case, we don't want to include
                     // a scrutinee place. `scrutinee_place_builder` will fail to be resolved
                     // if the only match arm is a wildcard (`_`).
@@ -346,14 +345,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     //    match foo { _ => () };
                     // };
                     // ```
-                    let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
-                    let scrutinee_place: Place<'tcx>;
-                    if let Ok(scrutinee_builder) =
-                        scrutinee_place_builder.clone().try_upvars_resolved(this)
-                    {
-                        scrutinee_place = scrutinee_builder.into_place(this);
-                        opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
-                    }
+                    let scrutinee_place = scrutinee_place_builder.try_to_place(this);
+                    let opt_scrutinee_place =
+                        scrutinee_place.as_ref().map(|place| (Some(place), scrutinee_span));
                     let scope = this.declare_bindings(
                         None,
                         arm.span,
@@ -592,7 +586,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             while let Some(next) = {
                 for binding in &candidate_ref.bindings {
                     let local = self.var_local_id(binding.var_id, OutsideGuard);
-                    // `try_upvars_resolved` may fail if it is unable to resolve the given
+                    // `try_to_place` may fail if it is unable to resolve the given
                     // `PlaceBuilder` inside a closure. In this case, we don't want to include
                     // a scrutinee place. `scrutinee_place_builder` will fail for destructured
                     // assignments. This is because a closure only captures the precise places
@@ -606,9 +600,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     //    let (v1, v2) = foo;
                     // };
                     // ```
-                    if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) {
-                        let place = match_pair_resolved.into_place(self);
-
+                    if let Some(place) = initializer.try_to_place(self) {
                         let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
                             VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
                         )))) = self.local_decls[local].local_info else {
@@ -1345,7 +1337,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 bug!("Or-patterns should have been sorted to the end");
             };
             let or_span = match_pair.pattern.span;
-            let place = match_pair.place;
 
             first_candidate.visit_leaves(|leaf_candidate| {
                 self.test_or_pattern(
@@ -1353,7 +1344,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     &mut otherwise,
                     pats,
                     or_span,
-                    place.clone(),
+                    &match_pair.place,
                     fake_borrows,
                 );
             });
@@ -1381,7 +1372,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         otherwise: &mut Option<BasicBlock>,
         pats: &'pat [Box<Pat<'tcx>>],
         or_span: Span,
-        place: PlaceBuilder<'tcx>,
+        place: &PlaceBuilder<'tcx>,
         fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
     ) {
         debug!("candidate={:#?}\npats={:#?}", candidate, pats);
@@ -1599,10 +1590,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
 
         // Insert a Shallow borrow of any places that is switched on.
-        if let Some(fb) = fake_borrows && let Ok(match_place_resolved) =
-            match_place.clone().try_upvars_resolved(self)
+        if let Some(fb) = fake_borrows
+            && let Some(resolved_place) = match_place.try_to_place(self)
         {
-            let resolved_place = match_place_resolved.into_place(self);
             fb.insert(resolved_place);
         }
 
@@ -1621,7 +1611,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // encounter a candidate where the test is not relevant; at
         // that point, we stop sorting.
         while let Some(candidate) = candidates.first_mut() {
-            let Some(idx) = self.sort_candidate(&match_place.clone(), &test, candidate) else {
+            let Some(idx) = self.sort_candidate(&match_place, &test, candidate) else {
                 break;
             };
             let (candidate, rest) = candidates.split_first_mut().unwrap();
@@ -1690,7 +1680,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             target_blocks
         };
 
-        self.perform_test(span, scrutinee_span, block, match_place, &test, make_target_blocks);
+        self.perform_test(span, scrutinee_span, block, &match_place, &test, make_target_blocks);
     }
 
     /// Determine the fake borrows that are needed from a set of places that
@@ -1796,12 +1786,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             false,
             &mut [&mut guard_candidate, &mut otherwise_candidate],
         );
-        let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
-        let expr_place: Place<'tcx>;
-        if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) {
-            expr_place = expr_builder.into_place(self);
-            opt_expr_place = Some((Some(&expr_place), expr_span));
-        }
+        let expr_place = expr_place_builder.try_to_place(self);
+        let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span));
         let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
         self.break_for_else(otherwise_post_guard_block, else_target, self.source_info(expr_span));
 
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index caf27eb39d7..f6b1955fdec 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -73,8 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             {
                 existing_bindings.extend_from_slice(&new_bindings);
                 mem::swap(&mut candidate.bindings, &mut existing_bindings);
-                candidate.subcandidates =
-                    self.create_or_subcandidates(candidate, place.clone(), pats);
+                candidate.subcandidates = self.create_or_subcandidates(candidate, &place, pats);
                 return true;
             }
 
@@ -127,7 +126,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn create_or_subcandidates<'pat>(
         &mut self,
         candidate: &Candidate<'pat, 'tcx>,
-        place: PlaceBuilder<'tcx>,
+        place: &PlaceBuilder<'tcx>,
         pats: &'pat [Box<Pat<'tcx>>],
     ) -> Vec<Candidate<'pat, 'tcx>> {
         pats.iter()
@@ -156,10 +155,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ascription: thir::Ascription { ref annotation, variance },
             } => {
                 // Apply the type ascription to the value at `match_pair.place`, which is the
-                if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
+                if let Some(source) = match_pair.place.try_to_place(self) {
                     candidate.ascriptions.push(Ascription {
                         annotation: annotation.clone(),
-                        source: place_resolved.into_place(self),
+                        source,
                         variance,
                     });
                 }
@@ -183,10 +182,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ref subpattern,
                 is_primary: _,
             } => {
-                if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
+                if let Some(source) = match_pair.place.try_to_place(self) {
                     candidate.bindings.push(Binding {
                         span: match_pair.pattern.span,
-                        source: place_resolved.into_place(self),
+                        source,
                         var_id: var,
                         binding_mode: mode,
                     });
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index a62cfecf78b..58513bde2aa 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -150,11 +150,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match_start_span: Span,
         scrutinee_span: Span,
         block: BasicBlock,
-        place_builder: PlaceBuilder<'tcx>,
+        place_builder: &PlaceBuilder<'tcx>,
         test: &Test<'tcx>,
         make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
     ) {
-        let place = place_builder.into_place(self);
+        let place = place_builder.to_place(self);
         let place_ty = place.ty(&self.local_decls, self.tcx);
         debug!(?place, ?place_ty,);
 
@@ -760,7 +760,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
         let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
             // e.g., `(x as Variant).0`
-            let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty);
+            let place = downcast_place
+                .clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty));
             // e.g., `(x as Variant).0 @ P1`
             MatchPair::new(place, &subpattern.pattern, self)
         });
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index b854ba47f8f..bd435f9ab00 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -18,7 +18,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         subpatterns
             .iter()
             .map(|fieldpat| {
-                let place = place.clone().field(fieldpat.field, fieldpat.pattern.ty);
+                let place =
+                    place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
                 MatchPair::new(place, &fieldpat.pattern, self)
             })
             .collect()
@@ -33,26 +34,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         suffix: &'pat [Box<Pat<'tcx>>],
     ) {
         let tcx = self.tcx;
-        let (min_length, exact_size) =
-            if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) {
-                match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() {
-                    ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
-                    _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
-                }
-            } else {
-                ((prefix.len() + suffix.len()).try_into().unwrap(), false)
-            };
+        let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
+            match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
+                ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
+                _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+            }
+        } else {
+            ((prefix.len() + suffix.len()).try_into().unwrap(), false)
+        };
 
         match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
             let elem =
                 ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
-            let place = place.clone().project(elem);
-            MatchPair::new(place, subpattern, self)
+            MatchPair::new(place.clone_project(elem), subpattern, self)
         }));
 
         if let Some(subslice_pat) = opt_slice {
             let suffix_len = suffix.len() as u64;
-            let subslice = place.clone().project(ProjectionElem::Subslice {
+            let subslice = place.clone_project(PlaceElem::Subslice {
                 from: prefix.len() as u64,
                 to: if exact_size { min_length - suffix_len } else { suffix_len },
                 from_end: !exact_size,
@@ -67,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 min_length,
                 from_end: !exact_size,
             };
-            let place = place.clone().project(elem);
+            let place = place.clone_project(elem);
             MatchPair::new(place, subpattern, self)
         }));
     }
@@ -97,15 +96,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
 impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
     pub(in crate::build) fn new(
-        place: PlaceBuilder<'tcx>,
+        mut place: PlaceBuilder<'tcx>,
         pattern: &'pat Pat<'tcx>,
         cx: &Builder<'_, 'tcx>,
     ) -> MatchPair<'pat, 'tcx> {
         // Force the place type to the pattern's type.
         // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
-        let mut place = match place.try_upvars_resolved(cx) {
-            Ok(val) | Err(val) => val,
-        };
+        if let Some(resolved) = place.resolve_upvar(cx) {
+            place = resolved;
+        }
 
         // Only add the OpaqueCast projection if the given place is an opaque type and the
         // expected type from the pattern is not.
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 60e64b45963..5fa41ebeb6e 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -486,7 +486,7 @@ impl<'tcx> Cx<'tcx> {
                             substs,
                             user_ty,
                             fields: self.field_refs(fields),
-                            base: base.as_ref().map(|base| FruInfo {
+                            base: base.map(|base| FruInfo {
                                 base: self.mirror_expr(base),
                                 field_types: self.typeck_results().fru_field_types()[expr.hir_id]
                                     .iter()
@@ -589,7 +589,7 @@ impl<'tcx> Cx<'tcx> {
                             InlineAsmOperand::Out {
                                 reg,
                                 late,
-                                expr: expr.as_ref().map(|expr| self.mirror_expr(expr)),
+                                expr: expr.map(|expr| self.mirror_expr(expr)),
                             }
                         }
                         hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
@@ -604,7 +604,7 @@ impl<'tcx> Cx<'tcx> {
                             reg,
                             late,
                             in_expr: self.mirror_expr(in_expr),
-                            out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)),
+                            out_expr: out_expr.map(|expr| self.mirror_expr(expr)),
                         },
                         hir::InlineAsmOperand::Const { ref anon_const } => {
                             let value = mir::ConstantKind::from_anon_const(
@@ -656,13 +656,11 @@ impl<'tcx> Cx<'tcx> {
 
                 ExprKind::Repeat { value: self.mirror_expr(v), count: *count }
             }
-            hir::ExprKind::Ret(ref v) => {
-                ExprKind::Return { value: v.as_ref().map(|v| self.mirror_expr(v)) }
-            }
+            hir::ExprKind::Ret(ref v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) },
             hir::ExprKind::Break(dest, ref value) => match dest.target_id {
                 Ok(target_id) => ExprKind::Break {
                     label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node },
-                    value: value.as_ref().map(|value| self.mirror_expr(value)),
+                    value: value.map(|value| self.mirror_expr(value)),
                 },
                 Err(err) => bug!("invalid loop id for break: {}", err),
             },
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 ba04cb6eef8..e369dba5524 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1044,11 +1044,19 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
                     name,
                     typeck_results.node_type(pat.hir_id),
                 );
-                sess.struct_span_err(pat.span, "borrow of moved value")
-                    .span_label(binding_span, format!("value moved into `{}` here", name))
+                let mut err = sess.struct_span_err(pat.span, "borrow of moved value");
+                err.span_label(binding_span, format!("value moved into `{}` here", name))
                     .span_label(binding_span, occurs_because)
-                    .span_labels(conflicts_ref, "value borrowed here after move")
-                    .emit();
+                    .span_labels(conflicts_ref, "value borrowed here after move");
+                if pat.span.contains(binding_span) {
+                    err.span_suggestion_verbose(
+                        binding_span.shrink_to_lo(),
+                        "borrow this binding in the pattern to avoid moving the value",
+                        "ref ".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+                err.emit();
             }
             return;
         }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 4b6608faba6..4c2a80e523f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -216,7 +216,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 let lo = lo_expr.map(|e| self.lower_range_expr(e));
                 let hi = hi_expr.map(|e| self.lower_range_expr(e));
 
-                let (lp, hp) = (lo.as_ref().map(|x| &x.0), hi.as_ref().map(|x| &x.0));
+                let (lp, hp) = (lo.as_ref().map(|(x, _)| x), hi.as_ref().map(|(x, _)| x));
                 let mut kind = match self.normalize_range_pattern_ends(ty, lp, hp) {
                     Some((lc, hc)) => self.lower_pattern_range(ty, lc, hc, end, lo_span),
                     None => {
@@ -358,7 +358,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         &mut self,
         pat: &'tcx Option<&'tcx hir::Pat<'tcx>>,
     ) -> Option<Box<Pat<'tcx>>> {
-        pat.as_ref().map(|p| self.lower_pattern(p))
+        pat.map(|p| self.lower_pattern(p))
     }
 
     fn slice_or_array_pattern(
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index fb2cee9e346..0ed24fe849c 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -245,9 +245,9 @@ impl<'a> Parser<'a> {
     ///     PATH `=` UNSUFFIXED_LIT
     /// The delimiters or `=` are still put into the resulting token stream.
     pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::AttrItem> {
-        let item = match self.token.kind {
-            token::Interpolated(ref nt) => match **nt {
-                Nonterminal::NtMeta(ref item) => Some(item.clone().into_inner()),
+        let item = match &self.token.kind {
+            token::Interpolated(nt) => match &**nt {
+                Nonterminal::NtMeta(item) => Some(item.clone().into_inner()),
                 _ => None,
             },
             _ => None,
@@ -364,9 +364,9 @@ impl<'a> Parser<'a> {
     /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
     /// ```
     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
-        let nt_meta = match self.token.kind {
-            token::Interpolated(ref nt) => match **nt {
-                token::NtMeta(ref e) => Some(e.clone()),
+        let nt_meta = match &self.token.kind {
+            token::Interpolated(nt) => match &**nt {
+                token::NtMeta(e) => Some(e.clone()),
                 _ => None,
             },
             _ => None,
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 4c626539238..3f5baf343c9 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -973,7 +973,7 @@ impl<'a> Parser<'a> {
         inner_op: &Expr,
         outer_op: &Spanned<AssocOp>,
     ) -> bool /* advanced the cursor */ {
-        if let ExprKind::Binary(op, ref l1, ref r1) = inner_op.kind {
+        if let ExprKind::Binary(op, l1, r1) = &inner_op.kind {
             if let ExprKind::Field(_, ident) = l1.kind
                 && ident.as_str().parse::<i32>().is_err()
                 && !matches!(r1.kind, ExprKind::Lit(_))
@@ -1079,8 +1079,8 @@ impl<'a> Parser<'a> {
 
         let mk_err_expr = |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err)));
 
-        match inner_op.kind {
-            ExprKind::Binary(op, ref l1, ref r1) if op.node.is_comparison() => {
+        match &inner_op.kind {
+            ExprKind::Binary(op, l1, r1) if op.node.is_comparison() => {
                 let mut err = ComparisonOperatorsCannotBeChained {
                     span: vec![op.span, self.prev_token.span],
                     suggest_turbofish: None,
@@ -1237,8 +1237,8 @@ impl<'a> Parser<'a> {
         let bounds = self.parse_generic_bounds(None)?;
         let sum_span = ty.span.to(self.prev_token.span);
 
-        let sub = match ty.kind {
-            TyKind::Rptr(ref lifetime, ref mut_ty) => {
+        let sub = match &ty.kind {
+            TyKind::Rptr(lifetime, mut_ty) => {
                 let sum_with_parens = pprust::to_string(|s| {
                     s.s.word("&");
                     s.print_opt_lifetime(lifetime);
@@ -2565,7 +2565,7 @@ impl<'a> Parser<'a> {
             if let [a, b] = segments {
                 let (a_span, b_span) = (a.span(), b.span());
                 let between_span = a_span.shrink_to_hi().to(b_span.shrink_to_lo());
-                if self.span_to_snippet(between_span).as_ref().map(|a| &a[..]) == Ok(":: ") {
+                if self.span_to_snippet(between_span).as_deref() == Ok(":: ") {
                     return Err(DoubleColonInBound {
                         span: path.span.shrink_to_hi(),
                         between: between_span,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index ba73fbd3e12..9f2267efb82 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -414,7 +414,7 @@ impl<'a> Parser<'a> {
                 self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
                 false
             }
-            (true, Some(ref op)) if !op.can_continue_expr_unambiguously() => false,
+            (true, Some(op)) if !op.can_continue_expr_unambiguously() => false,
             (true, Some(_)) => {
                 self.error_found_expr_would_be_stmt(lhs);
                 true
@@ -1728,13 +1728,13 @@ impl<'a> Parser<'a> {
             || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
         {
             let expr = self.parse_expr_opt()?;
-            if let Some(ref expr) = expr {
+            if let Some(expr) = &expr {
                 if label.is_some()
                     && matches!(
                         expr.kind,
                         ExprKind::While(_, _, None)
                             | ExprKind::ForLoop(_, _, _, None)
-                            | ExprKind::Loop(_, None)
+                            | ExprKind::Loop(_, None, _)
                             | ExprKind::Block(_, None)
                     )
                 {
@@ -2444,10 +2444,11 @@ impl<'a> Parser<'a> {
 
     /// Parses `loop { ... }` (`loop` token already eaten).
     fn parse_loop_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
+        let loop_span = self.prev_token.span;
         let (attrs, body) = self.parse_inner_attrs_and_block()?;
         Ok(self.mk_expr_with_attrs(
             lo.to(self.prev_token.span),
-            ExprKind::Loop(body, opt_label),
+            ExprKind::Loop(body, opt_label, loop_span),
             attrs,
         ))
     }
@@ -2590,8 +2591,8 @@ impl<'a> Parser<'a> {
         // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
         // `&&` tokens.
         fn check_let_expr(expr: &Expr) -> (bool, bool) {
-            match expr.kind {
-                ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, ref lhs, ref rhs) => {
+            match &expr.kind {
+                ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
                     let lhs_rslt = check_let_expr(lhs);
                     let rhs_rslt = check_let_expr(rhs);
                     (lhs_rslt.0 || rhs_rslt.0, false)
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 20b01f554f2..767fb9378be 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -222,7 +222,8 @@ impl<'a> Parser<'a> {
             self.parse_use_item()?
         } else if self.check_fn_front_matter(def_final, case) {
             // FUNCTION ITEM
-            let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
+            let (ident, sig, generics, body) =
+                self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;
             (ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, body })))
         } else if self.eat_keyword(kw::Extern) {
             if self.eat_keyword(kw::Crate) {
@@ -1255,8 +1256,8 @@ impl<'a> Parser<'a> {
             }
         };
 
-        match impl_info.1 {
-            ItemKind::Impl(box Impl { of_trait: Some(ref trai), ref mut constness, .. }) => {
+        match &mut impl_info.1 {
+            ItemKind::Impl(box Impl { of_trait: Some(trai), constness, .. }) => {
                 *constness = Const::Yes(const_span);
 
                 let before_trait = trai.path.span.shrink_to_lo();
@@ -1793,7 +1794,13 @@ impl<'a> Parser<'a> {
                 };
                 // We use `parse_fn` to get a span for the function
                 let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
-                match self.parse_fn(&mut AttrVec::new(), fn_parse_mode, lo, &inherited_vis) {
+                match self.parse_fn(
+                    &mut AttrVec::new(),
+                    fn_parse_mode,
+                    lo,
+                    &inherited_vis,
+                    Case::Insensitive,
+                ) {
                     Ok(_) => {
                         let mut err = self.struct_span_err(
                             lo.to(self.prev_token.span),
@@ -2114,8 +2121,9 @@ impl<'a> Parser<'a> {
         fn_parse_mode: FnParseMode,
         sig_lo: Span,
         vis: &Visibility,
+        case: Case,
     ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
-        let header = self.parse_fn_front_matter(vis)?; // `const ... fn`
+        let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn`
         let ident = self.parse_ident()?; // `foo`
         let mut generics = self.parse_generics()?; // `<'a, T, ...>`
         let decl =
@@ -2239,24 +2247,28 @@ impl<'a> Parser<'a> {
     ///
     /// `vis` represents the visibility that was already parsed, if any. Use
     /// `Visibility::Inherited` when no visibility is known.
-    pub(super) fn parse_fn_front_matter(&mut self, orig_vis: &Visibility) -> PResult<'a, FnHeader> {
+    pub(super) fn parse_fn_front_matter(
+        &mut self,
+        orig_vis: &Visibility,
+        case: Case,
+    ) -> PResult<'a, FnHeader> {
         let sp_start = self.token.span;
-        let constness = self.parse_constness(Case::Insensitive);
+        let constness = self.parse_constness(case);
 
         let async_start_sp = self.token.span;
-        let asyncness = self.parse_asyncness(Case::Insensitive);
+        let asyncness = self.parse_asyncness(case);
 
         let unsafe_start_sp = self.token.span;
-        let unsafety = self.parse_unsafety(Case::Insensitive);
+        let unsafety = self.parse_unsafety(case);
 
         let ext_start_sp = self.token.span;
-        let ext = self.parse_extern(Case::Insensitive);
+        let ext = self.parse_extern(case);
 
         if let Async::Yes { span, .. } = asyncness {
             self.ban_async_in_2015(span);
         }
 
-        if !self.eat_keyword_case(kw::Fn, Case::Insensitive) {
+        if !self.eat_keyword_case(kw::Fn, case) {
             // It is possible for `expect_one_of` to recover given the contents of
             // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
             // account for this.
@@ -2585,8 +2597,8 @@ impl<'a> Parser<'a> {
     }
 
     fn is_named_param(&self) -> bool {
-        let offset = match self.token.kind {
-            token::Interpolated(ref nt) => match **nt {
+        let offset = match &self.token.kind {
+            token::Interpolated(nt) => match **nt {
                 token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
                 _ => 0,
             },
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 8878c404c58..4d8bff28b05 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -384,8 +384,8 @@ enum TokenType {
 
 impl TokenType {
     fn to_string(&self) -> String {
-        match *self {
-            TokenType::Token(ref t) => format!("`{}`", pprust::token_kind_to_string(t)),
+        match self {
+            TokenType::Token(t) => format!("`{}`", pprust::token_kind_to_string(t)),
             TokenType::Keyword(kw) => format!("`{}`", kw),
             TokenType::Operator => "an operator".to_string(),
             TokenType::Lifetime => "lifetime".to_string(),
@@ -738,8 +738,8 @@ impl<'a> Parser<'a> {
 
     fn check_inline_const(&self, dist: usize) -> bool {
         self.is_keyword_ahead(dist, &[kw::Const])
-            && self.look_ahead(dist + 1, |t| match t.kind {
-                token::Interpolated(ref nt) => matches!(**nt, token::NtBlock(..)),
+            && self.look_ahead(dist + 1, |t| match &t.kind {
+                token::Interpolated(nt) => matches!(**nt, token::NtBlock(..)),
                 token::OpenDelim(Delimiter::Brace) => true,
                 _ => false,
             })
@@ -860,7 +860,7 @@ impl<'a> Parser<'a> {
             if let token::CloseDelim(..) | token::Eof = self.token.kind {
                 break;
             }
-            if let Some(ref t) = sep.sep {
+            if let Some(t) = &sep.sep {
                 if first {
                     first = false;
                 } else {
@@ -895,7 +895,7 @@ impl<'a> Parser<'a> {
 
                                 _ => {
                                     // Attempt to keep parsing if it was a similar separator.
-                                    if let Some(ref tokens) = t.similar_tokens() {
+                                    if let Some(tokens) = t.similar_tokens() {
                                         if tokens.contains(&self.token.kind) && !unclosed_delims {
                                             self.bump();
                                         }
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 103dd801257..239ed79ce2f 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -42,9 +42,9 @@ impl<'a> Parser<'a> {
                 token::Comma | token::Ident(..) | token::Interpolated(..) => true,
                 _ => token.can_begin_type(),
             },
-            NonterminalKind::Block => match token.kind {
+            NonterminalKind::Block => match &token.kind {
                 token::OpenDelim(Delimiter::Brace) => true,
-                token::Interpolated(ref nt) => !matches!(
+                token::Interpolated(nt) => !matches!(
                     **nt,
                     token::NtItem(_)
                         | token::NtPat(_)
@@ -56,16 +56,16 @@ impl<'a> Parser<'a> {
                 ),
                 _ => false,
             },
-            NonterminalKind::Path | NonterminalKind::Meta => match token.kind {
+            NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
                 token::ModSep | token::Ident(..) => true,
-                token::Interpolated(ref nt) => match **nt {
+                token::Interpolated(nt) => match **nt {
                     token::NtPath(_) | token::NtMeta(_) => true,
                     _ => may_be_ident(&nt),
                 },
                 _ => false,
             },
             NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
-                match token.kind {
+                match &token.kind {
                 token::Ident(..) |                          // box, ref, mut, and other identifiers (can stricten)
                 token::OpenDelim(Delimiter::Parenthesis) |  // tuple pattern
                 token::OpenDelim(Delimiter::Bracket) |      // slice pattern
@@ -80,13 +80,13 @@ impl<'a> Parser<'a> {
                 token::BinOp(token::Shl) => true,           // path (double UFCS)
                 // leading vert `|` or-pattern
                 token::BinOp(token::Or) =>  matches!(kind, NonterminalKind::PatWithOr {..}),
-                token::Interpolated(ref nt) => may_be_ident(nt),
+                token::Interpolated(nt) => may_be_ident(nt),
                 _ => false,
             }
             }
-            NonterminalKind::Lifetime => match token.kind {
+            NonterminalKind::Lifetime => match &token.kind {
                 token::Lifetime(_) => true,
-                token::Interpolated(ref nt) => {
+                token::Interpolated(nt) => {
                     matches!(**nt, token::NtLifetime(_))
                 }
                 _ => false,
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index bf52febb107..cbeec951e2d 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -485,7 +485,7 @@ impl<'a> Parser<'a> {
         let mut rhs = self.parse_pat_no_top_alt(None)?;
         let sp = lhs.span.to(rhs.span);
 
-        if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind {
+        if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind {
             // The user inverted the order, so help them fix that.
             let mut applicability = Applicability::MachineApplicable;
             // FIXME(bindings_after_at): Remove this code when stabilizing the feature.
@@ -595,7 +595,7 @@ impl<'a> Parser<'a> {
         self.recover_additional_muts();
 
         // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
-        if let token::Interpolated(ref nt) = self.token.kind {
+        if let token::Interpolated(nt) = &self.token.kind {
             if let token::NtPat(_) = **nt {
                 self.expected_ident_found().emit();
             }
@@ -796,7 +796,7 @@ impl<'a> Parser<'a> {
     /// expression syntax `...expr` for splatting in expressions.
     fn parse_pat_range_to(&mut self, mut re: Spanned<RangeEnd>) -> PResult<'a, PatKind> {
         let end = self.parse_pat_range_end()?;
-        if let RangeEnd::Included(ref mut syn @ RangeSyntax::DotDotDot) = &mut re.node {
+        if let RangeEnd::Included(syn @ RangeSyntax::DotDotDot) = &mut re.node {
             *syn = RangeSyntax::DotDotEq;
             self.struct_span_err(re.span, "range-to patterns with `...` are not allowed")
                 .span_suggestion_short(
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 73de86820d8..1b56cd72db0 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -563,9 +563,9 @@ impl<'a> Parser<'a> {
         };
 
         let mut eat_semi = true;
-        match stmt.kind {
+        match &mut stmt.kind {
             // Expression without semicolon.
-            StmtKind::Expr(ref mut expr)
+            StmtKind::Expr(expr)
                 if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => {
                 // Just check for errors and recover; do not eat semicolon yet.
                 // `expect_one_of` returns PResult<'a, bool /* recovered */>
@@ -611,7 +611,7 @@ impl<'a> Parser<'a> {
                 }
             }
             StmtKind::Expr(_) | StmtKind::MacCall(_) => {}
-            StmtKind::Local(ref mut local) if let Err(e) = self.expect_semi() => {
+            StmtKind::Local(local) if let Err(e) = self.expect_semi() => {
                 // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
                 match &mut local.kind {
                     LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => {
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index fecf67cb596..b7206b57642 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -536,7 +536,7 @@ impl<'a> Parser<'a> {
         };
         let span_start = self.token.span;
         let ast::FnHeader { ext, unsafety, constness, asyncness } =
-            self.parse_fn_front_matter(&inherited_vis)?;
+            self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
         if self.may_recover() && self.token.kind == TokenKind::Lt {
             self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
         }
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 58e1fe937a6..2234837050b 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -922,8 +922,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 //    v     v
                 //   (  succ  )
                 //
-                let else_ln =
-                    self.propagate_through_opt_expr(else_opt.as_ref().map(|e| &**e), succ);
+                let else_ln = self.propagate_through_opt_expr(else_opt.as_deref(), succ);
                 let then_ln = self.propagate_through_expr(&then, succ);
                 let ln = self.live_node(expr.hir_id, expr.span);
                 self.init_from_succ(ln, else_ln);
@@ -966,7 +965,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
             hir::ExprKind::Ret(ref o_e) => {
                 // Ignore succ and subst exit_ln.
-                self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), self.exit_ln)
+                self.propagate_through_opt_expr(o_e.as_deref(), self.exit_ln)
             }
 
             hir::ExprKind::Break(label, ref opt_expr) => {
@@ -981,7 +980,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 // look it up in the break loop nodes table
 
                 match target {
-                    Some(b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b),
+                    Some(b) => self.propagate_through_opt_expr(opt_expr.as_deref(), b),
                     None => span_bug!(expr.span, "`break` to unknown label"),
                 }
             }
@@ -1026,7 +1025,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             hir::ExprKind::Array(ref exprs) => self.propagate_through_exprs(exprs, succ),
 
             hir::ExprKind::Struct(_, ref fields, ref with_expr) => {
-                let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
+                let succ = self.propagate_through_opt_expr(with_expr.as_deref(), succ);
                 fields
                     .iter()
                     .rev()
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 5072d2aad16..93b0f5814de 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -3841,7 +3841,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 }
             }
 
-            ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
+            ExprKind::Loop(ref block, label, _) => {
+                self.resolve_labeled_block(label, expr.id, &block)
+            }
 
             ExprKind::While(ref cond, ref block, label) => {
                 self.with_resolved_label(label, expr.id, |this| {
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 0e579379ec8..fae20c2ba5f 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -1029,7 +1029,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                                 trait_item.hir_id(),
                                 trait_item.ident,
                                 Some(bounds),
-                                default_ty.as_ref().map(|ty| &**ty),
+                                default_ty.as_deref(),
                                 &self.save_ctxt,
                             ),
                             attributes: lower_attributes(attrs.to_vec(), &self.save_ctxt),
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index be084adb7b7..1ce3a613dc7 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1480,7 +1480,7 @@ pub fn get_cmd_lint_options(
 
 /// Parses the `--color` flag.
 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
-    match matches.opt_str("color").as_ref().map(|s| &s[..]) {
+    match matches.opt_str("color").as_deref() {
         Some("auto") => ColorConfig::Auto,
         Some("always") => ColorConfig::Always,
         Some("never") => ColorConfig::Never,
@@ -1589,7 +1589,7 @@ pub fn parse_error_format(
     // is unstable, it will not be present. We have to use `opts_present` not
     // `opt_present` because the latter will panic.
     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
-        match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
+        match matches.opt_str("error-format").as_deref() {
             None | Some("human") => {
                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
             }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index d602acec53e..fb0b62e025e 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1357,7 +1357,7 @@ pub fn build_session(
         let profiler = SelfProfiler::new(
             directory,
             sopts.crate_name.as_deref(),
-            sopts.unstable_opts.self_profile_events.as_ref().map(|xs| &xs[..]),
+            sopts.unstable_opts.self_profile_events.as_deref(),
             &sopts.unstable_opts.self_profile_counter,
         );
         match profiler {
@@ -1391,7 +1391,7 @@ pub fn build_session(
         local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0);
 
     let optimization_fuel = Lock::new(OptimizationFuel {
-        remaining: sopts.unstable_opts.fuel.as_ref().map_or(0, |i| i.1),
+        remaining: sopts.unstable_opts.fuel.as_ref().map_or(0, |&(_, i)| i),
         out_of_fuel: false,
     });
     let print_fuel = AtomicU64::new(0);
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 322c7104be4..7ccfa600ec3 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -217,9 +217,7 @@ impl RealFileName {
     pub fn local_path(&self) -> Option<&Path> {
         match self {
             RealFileName::LocalPath(p) => Some(p),
-            RealFileName::Remapped { local_path: p, virtual_name: _ } => {
-                p.as_ref().map(PathBuf::as_path)
-            }
+            RealFileName::Remapped { local_path, virtual_name: _ } => local_path.as_deref(),
         }
     }
 
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 ef3d300020a..59d017545c0 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -4,13 +4,12 @@ pub mod suggestions;
 
 use super::{
     FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, ObligationCause,
-    ObligationCauseCode, OutputTypeParameterMismatch, Overflow, PredicateObligation,
-    SelectionContext, SelectionError, TraitNotObjectSafe,
+    ObligationCauseCode, ObligationCtxt, OutputTypeParameterMismatch, Overflow,
+    PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
 };
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{self, InferCtxt, TyCtxtInferExt};
-use crate::traits::engine::TraitEngineExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::query::normalize::AtExt as _;
 use crate::traits::specialize::to_pretty_impl_header;
@@ -30,7 +29,6 @@ use rustc_hir::Item;
 use rustc_hir::Node;
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::TypeTrace;
-use rustc_infer::traits::TraitEngine;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
@@ -354,9 +352,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
                     param_env,
                     ty.rebind(ty::TraitPredicate { trait_ref, constness, polarity }),
                 );
-                let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx);
-                fulfill_cx.register_predicate_obligation(self, obligation);
-                if fulfill_cx.select_all_or_error(self).is_empty() {
+                let ocx = ObligationCtxt::new_in_snapshot(self);
+                ocx.register_obligation(obligation);
+                if ocx.select_all_or_error().is_empty() {
                     return Ok((
                         ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
                             .expect("expected to map DefId to ClosureKind"),
@@ -2546,7 +2544,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             let obligation =
                 Obligation::new(self.tcx, ObligationCause::dummy(), param_env, cleaned_pred);
 
-            self.predicate_may_hold(&obligation)
+            // We don't use `InferCtxt::predicate_may_hold` because that
+            // will re-run predicates that overflow locally, which ends up
+            // taking a really long time to compute.
+            self.evaluate_obligation(&obligation).map_or(false, |eval| eval.may_apply())
         })
     }
 
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 82f0440b307..9bfe527647d 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
@@ -460,7 +460,7 @@ impl<'tcx> OnUnimplementedDirective {
         info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
 
         let options_map: FxHashMap<Symbol, String> =
-            options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
+            options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect();
 
         for command in self.subcommands.iter().chain(Some(self)).rev() {
             if let Some(ref condition) = command.condition && !attr::eval_condition(
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 186109e7075..bb6d7d0e8df 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1340,9 +1340,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     obligation.param_env,
                     trait_pred_and_suggested_ty,
                 );
-                let suggested_ty_would_satisfy_obligation = self
-                    .evaluate_obligation_no_overflow(&new_obligation)
-                    .must_apply_modulo_regions();
+                let suggested_ty_would_satisfy_obligation =
+                    self.predicate_must_hold_modulo_regions(&new_obligation);
                 if suggested_ty_would_satisfy_obligation {
                     let sp = self
                         .tcx
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index ff18aa1f9e9..548ca1c1d7f 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -31,7 +31,6 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{
@@ -403,9 +402,7 @@ pub fn fully_solve_obligation<'tcx>(
     infcx: &InferCtxt<'tcx>,
     obligation: PredicateObligation<'tcx>,
 ) -> Vec<FulfillmentError<'tcx>> {
-    let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
-    engine.register_predicate_obligation(infcx, obligation);
-    engine.select_all_or_error(infcx)
+    fully_solve_obligations(infcx, [obligation])
 }
 
 /// Process a set of obligations (and any nested obligations that come from them)
@@ -414,9 +411,9 @@ pub fn fully_solve_obligations<'tcx>(
     infcx: &InferCtxt<'tcx>,
     obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
 ) -> Vec<FulfillmentError<'tcx>> {
-    let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
-    engine.register_predicate_obligations(infcx, obligations);
-    engine.select_all_or_error(infcx)
+    let ocx = ObligationCtxt::new(infcx);
+    ocx.register_obligations(obligations);
+    ocx.select_all_or_error()
 }
 
 /// Process a bound (and any nested obligations that come from it) to completion.
@@ -429,9 +426,16 @@ pub fn fully_solve_bound<'tcx>(
     ty: Ty<'tcx>,
     bound: DefId,
 ) -> Vec<FulfillmentError<'tcx>> {
-    let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
-    engine.register_bound(infcx, param_env, ty, bound, cause);
-    engine.select_all_or_error(infcx)
+    let tcx = infcx.tcx;
+    let trait_ref = ty::TraitRef { def_id: bound, substs: tcx.mk_substs_trait(ty, []) };
+    let obligation = Obligation {
+        cause,
+        recursion_depth: 0,
+        param_env,
+        predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+    };
+
+    fully_solve_obligation(infcx, obligation)
 }
 
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 9f19b0092c0..7b2329b1ddd 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -566,22 +566,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                     .flatten()
                     .unwrap_or_else(|| ty.super_fold_with(self).into())
                 };
-                // For cases like #95134 we would like to catch overflows early
-                // otherwise they slip away and cause ICE.
-                let recursion_limit = self.tcx().recursion_limit();
-                if !recursion_limit.value_within_limit(self.depth)
-                    // HACK: Don't overflow when running cargo doc see #100991
-                    && !self.tcx().sess.opts.actually_rustdoc
-                {
-                    let obligation = Obligation::with_depth(
-                        self.selcx.tcx(),
-                        self.cause.clone(),
-                        recursion_limit.0,
-                        self.param_env,
-                        ty,
-                    );
-                    self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true);
-                }
                 debug!(
                     ?self.depth,
                     ?ty,
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 3b107d9570f..cd4a0447391 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -6,11 +6,9 @@
 //!
 //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
 use hir::LangItem;
-use rustc_errors::DelayDm;
 use rustc_hir as hir;
 use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
-use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TypeVisitable};
 use rustc_target::spec::abi::Abi;
@@ -776,9 +774,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
-            (&ty::Dynamic(ref data_a, _, dyn_a), &ty::Dynamic(ref data_b, _, dyn_b))
-                if dyn_a == dyn_b =>
-            {
+            (&ty::Dynamic(ref data_a, _, ty::Dyn), &ty::Dynamic(ref data_b, _, ty::Dyn)) => {
                 // Upcast coercions permit several things:
                 //
                 // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
@@ -811,16 +807,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             &obligation.cause,
                         ) {
                             if deref_trait_ref.def_id() == target_trait_did {
-                                self.tcx().struct_span_lint_hir(
-                                    DEREF_INTO_DYN_SUPERTRAIT,
-                                    obligation.cause.body_id,
-                                    obligation.cause.span,
-                                    DelayDm(|| format!(
-                                        "`{}` implements `Deref` with supertrait `{}` as output",
-                                        source, deref_trait_ref
-                                    )),
-                                    |lint| lint,
-                                );
                                 return;
                             }
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 2ec5d925b69..3cffd2bb780 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -803,9 +803,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let upcast_trait_ref;
         match (source.kind(), target.kind()) {
             // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
-            (&ty::Dynamic(ref data_a, r_a, repr_a), &ty::Dynamic(ref data_b, r_b, repr_b))
-                if repr_a == repr_b =>
-            {
+            (
+                &ty::Dynamic(ref data_a, r_a, repr_a @ ty::Dyn),
+                &ty::Dynamic(ref data_b, r_b, ty::Dyn),
+            ) => {
                 // See `assemble_candidates_for_unsizing` for more info.
                 // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
                 let principal_a = data_a.principal().unwrap();
@@ -831,7 +832,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             .map(ty::Binder::dummy),
                     );
                 let existential_predicates = tcx.mk_poly_existential_predicates(iter);
-                let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_b);
+                let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_a);
 
                 // Require that the traits involved in this upcast are **equal**;
                 // only the **lifetime bound** is changed.
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 7cc12eff20e..9a3c0707c7c 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -10,14 +10,14 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
 
 pub mod specialization_graph;
-use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
 use specialization_graph::GraphExt;
 
 use crate::errors::NegativePositiveConflict;
 use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
-use crate::traits::engine::TraitEngineExt as _;
 use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
+use crate::traits::{
+    self, coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt,
+};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{error_code, DelayDm, Diagnostic};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -204,12 +204,12 @@ fn fulfill_implication<'tcx>(
 
     // Needs to be `in_snapshot` because this function is used to rebase
     // substitutions, which may happen inside of a select within a probe.
-    let mut engine = <dyn TraitEngine<'tcx>>::new_in_snapshot(infcx.tcx);
+    let ocx = ObligationCtxt::new_in_snapshot(infcx);
     // attempt to prove all of the predicates for impl2 given those for impl1
     // (which are packed up in penv)
-    engine.register_predicate_obligations(infcx, obligations.chain(more_obligations));
+    ocx.register_obligations(obligations.chain(more_obligations));
 
-    let errors = engine.select_all_or_error(infcx);
+    let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
         // no dice!
         debug!(
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 932dbbb81e5..40dbe0b3ff0 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -1,6 +1,5 @@
 use crate::infer::{InferCtxt, TyCtxtInferExt};
-use crate::traits::ObligationCause;
-use crate::traits::{TraitEngine, TraitEngineExt};
+use crate::traits::{ObligationCause, ObligationCtxt};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
@@ -72,28 +71,16 @@ fn type_marked_structural<'tcx>(
     adt_ty: Ty<'tcx>,
     cause: ObligationCause<'tcx>,
 ) -> bool {
-    let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+    let ocx = ObligationCtxt::new(infcx);
     // require `#[derive(PartialEq)]`
     let structural_peq_def_id =
         infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
-    fulfillment_cx.register_bound(
-        infcx,
-        ty::ParamEnv::empty(),
-        adt_ty,
-        structural_peq_def_id,
-        cause.clone(),
-    );
+    ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id);
     // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
     // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
     let structural_teq_def_id =
         infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span));
-    fulfillment_cx.register_bound(
-        infcx,
-        ty::ParamEnv::empty(),
-        adt_ty,
-        structural_teq_def_id,
-        cause,
-    );
+    ocx.register_bound(cause, ty::ParamEnv::empty(), adt_ty, structural_teq_def_id);
 
     // We deliberately skip *reporting* fulfillment errors (via
     // `report_fulfillment_errors`), for two reasons:
@@ -104,7 +91,7 @@ fn type_marked_structural<'tcx>(
     //
     // 2. We are sometimes doing future-incompatibility lints for
     //    now, so we do not want unconditional errors here.
-    fulfillment_cx.select_all_or_error(infcx).is_empty()
+    ocx.select_all_or_error().is_empty()
 }
 
 /// This implements the traversal over the structure of a given type to try to
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 2d1a3869926..3ab353c9638 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -5,16 +5,15 @@
 use rustc_hir as hir;
 use rustc_infer::infer::canonical::{self, Canonical};
 use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::query::OutlivesBound;
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
 use rustc_span::source_map::DUMMY_SP;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
 use rustc_trait_selection::traits::wf;
-use rustc_trait_selection::traits::{TraitEngine, TraitEngineExt};
+use rustc_trait_selection::traits::ObligationCtxt;
 use smallvec::{smallvec, SmallVec};
 
 pub(crate) fn provide(p: &mut Providers) {
@@ -30,16 +29,16 @@ fn implied_outlives_bounds<'tcx>(
 > {
     tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
         let (param_env, ty) = key.into_parts();
-        compute_implied_outlives_bounds(&ocx.infcx, param_env, ty)
+        compute_implied_outlives_bounds(ocx, param_env, ty)
     })
 }
 
 fn compute_implied_outlives_bounds<'tcx>(
-    infcx: &InferCtxt<'tcx>,
+    ocx: &ObligationCtxt<'_, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> Fallible<Vec<OutlivesBound<'tcx>>> {
-    let tcx = infcx.tcx;
+    let tcx = ocx.infcx.tcx;
 
     // Sometimes when we ask what it takes for T: WF, we get back that
     // U: WF is required; in that case, we push U onto this stack and
@@ -52,8 +51,6 @@ fn compute_implied_outlives_bounds<'tcx>(
     let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
         vec![];
 
-    let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
-
     while let Some(arg) = wf_args.pop() {
         if !checked_wf_args.insert(arg) {
             continue;
@@ -70,15 +67,15 @@ fn compute_implied_outlives_bounds<'tcx>(
         // FIXME(@lcnr): It's not really "always fine", having fewer implied
         // bounds can be backward incompatible, e.g. #101951 was caused by
         // us not dealing with inference vars in `TypeOutlives` predicates.
-        let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
-            .unwrap_or_default();
+        let obligations =
+            wf::obligations(ocx.infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
+                .unwrap_or_default();
 
         // While these predicates should all be implied by other parts of
         // the program, they are still relevant as they may constrain
         // inference variables, which is necessary to add the correct
         // implied bounds in some cases, mostly when dealing with projections.
-        fulfill_cx.register_predicate_obligations(
-            infcx,
+        ocx.register_obligations(
             obligations.iter().filter(|o| o.predicate.has_non_region_infer()).cloned(),
         );
 
@@ -116,9 +113,9 @@ fn compute_implied_outlives_bounds<'tcx>(
         }));
     }
 
-    // Ensure that those obligations that we had to solve
-    // get solved *here*.
-    match fulfill_cx.select_all_or_error(infcx).as_slice() {
+    // This call to `select_all_or_error` is necessary to constrain inference variables, which we
+    // use further down when computing the implied bounds.
+    match ocx.select_all_or_error().as_slice() {
         [] => (),
         _ => return Err(NoSolution),
     }
@@ -130,7 +127,7 @@ fn compute_implied_outlives_bounds<'tcx>(
         .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
             ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
             ty::GenericArgKind::Type(ty_a) => {
-                let ty_a = infcx.resolve_vars_if_possible(ty_a);
+                let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
                 let mut components = smallvec![];
                 push_outlives_components(tcx, ty_a, &mut components);
                 implied_bounds_from_components(r_b, components)
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 92e8542795f..07af3dc5164 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -138,8 +138,18 @@ fn univariant_uninterned<'tcx>(
     if optimize {
         let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
         let optimizing = &mut inverse_memory_index[..end];
-        let field_align = |f: &TyAndLayout<'_>| {
-            if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi }
+        let effective_field_align = |f: &TyAndLayout<'_>| {
+            if let Some(pack) = pack {
+                // return the packed alignment in bytes
+                f.align.abi.min(pack).bytes()
+            } else {
+                // returns log2(effective-align).
+                // This is ok since `pack` applies to all fields equally.
+                // The calculation assumes that size is an integer multiple of align, except for ZSTs.
+                //
+                // group [u8; 4] with align-4 or [u8; 6] with align-2 fields
+                f.align.abi.bytes().max(f.size.bytes()).trailing_zeros() as u64
+            }
         };
 
         // If `-Z randomize-layout` was enabled for the type definition we can shuffle
@@ -160,15 +170,23 @@ fn univariant_uninterned<'tcx>(
                     optimizing.sort_by_key(|&x| {
                         // Place ZSTs first to avoid "interesting offsets",
                         // especially with only one or two non-ZST fields.
+                        // Then place largest alignments first, largest niches within an alignment group last
                         let f = &fields[x as usize];
-                        (!f.is_zst(), cmp::Reverse(field_align(f)))
+                        let niche_size = f.largest_niche.map_or(0, |n| n.available(cx));
+                        (!f.is_zst(), cmp::Reverse(effective_field_align(f)), niche_size)
                     });
                 }
 
                 StructKind::Prefixed(..) => {
                     // Sort in ascending alignment so that the layout stays optimal
-                    // regardless of the prefix
-                    optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
+                    // regardless of the prefix.
+                    // And put the largest niche in an alignment group at the end
+                    // so it can be used as discriminant in jagged enums
+                    optimizing.sort_by_key(|&x| {
+                        let f = &fields[x as usize];
+                        let niche_size = f.largest_niche.map_or(0, |n| n.available(cx));
+                        (effective_field_align(f), niche_size)
+                    });
                 }
             }
 
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 8d999302a6d..251431a15eb 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1094,7 +1094,13 @@ impl<'a> Builder<'a> {
             let my_out = match mode {
                 // This is the intended out directory for compiler documentation.
                 Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target),
-                Mode::Std => out_dir.join(target.triple).join("doc"),
+                Mode::Std => {
+                    if self.config.cmd.json() {
+                        out_dir.join(target.triple).join("json-doc")
+                    } else {
+                        out_dir.join(target.triple).join("doc")
+                    }
+                }
                 _ => panic!("doc mode {:?} not expected", mode),
             };
             let rustdoc = self.rustdoc(compiler);
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 3180a12c85b..571396eb835 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -564,27 +564,22 @@ fn doc_std(
         );
     }
     let compiler = builder.compiler(stage, builder.config.build);
+
+    let target_doc_dir_name = if format == DocumentationFormat::JSON { "json-doc" } else { "doc" };
+    let target_dir =
+        builder.stage_out(compiler, Mode::Std).join(target.triple).join(target_doc_dir_name);
+
     // This is directory where the compiler will place the output of the command.
     // We will then copy the files from this directory into the final `out` directory, the specified
     // as a function parameter.
-    let out_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join("doc");
-    // `cargo` uses the same directory for both JSON docs and HTML docs.
-    // This could lead to cross-contamination when copying files into the specified `out` directory.
-    // For example:
-    // ```bash
-    // x doc std
-    // x doc std --json
-    // ```
-    // could lead to HTML docs being copied into the JSON docs output directory.
-    // To avoid this issue, we clean the doc folder before invoking `cargo`.
-    if out_dir.exists() {
-        builder.remove_dir(&out_dir);
-    }
+    let out_dir = target_dir.join(target.triple).join("doc");
 
     let run_cargo_rustdoc_for = |package: &str| {
         let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc");
         compile::std_cargo(builder, target, compiler.stage, &mut cargo);
         cargo
+            .arg("--target-dir")
+            .arg(&*target_dir.to_string_lossy())
             .arg("-p")
             .arg(package)
             .arg("-Zskip-rustdoc-fingerprint")
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index d4e881ad832..63530b924c2 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -701,6 +701,8 @@ a {
 }
 
 .small-section-header {
+	/* fields use <span> tags, but should get their own lines */
+	display: block;
 	position: relative;
 }
 
diff --git a/src/test/codegen/issue-37945.rs b/src/test/codegen/issue-37945.rs
index 12fa1e9e56b..fe54375bbf6 100644
--- a/src/test/codegen/issue-37945.rs
+++ b/src/test/codegen/issue-37945.rs
@@ -15,7 +15,7 @@ use std::slice::Iter;
 pub fn is_empty_1(xs: Iter<f32>) -> bool {
 // CHECK-LABEL: @is_empty_1(
 // CHECK-NEXT:  start:
-// CHECK-NEXT:    [[A:%.*]] = icmp ne {{i32\*|ptr}} %xs.1, null
+// CHECK-NEXT:    [[A:%.*]] = icmp ne {{i32\*|ptr}} {{%xs.0|%xs.1}}, null
 // CHECK-NEXT:    tail call void @llvm.assume(i1 [[A]])
 // The order between %xs.0 and %xs.1 on the next line doesn't matter
 // and different LLVM versions produce different order.
@@ -28,7 +28,7 @@ pub fn is_empty_1(xs: Iter<f32>) -> bool {
 pub fn is_empty_2(xs: Iter<f32>) -> bool {
 // CHECK-LABEL: @is_empty_2
 // CHECK-NEXT:  start:
-// CHECK-NEXT:    [[C:%.*]] = icmp ne {{i32\*|ptr}} %xs.1, null
+// CHECK-NEXT:    [[C:%.*]] = icmp ne {{i32\*|ptr}} {{%xs.0|%xs.1}}, null
 // CHECK-NEXT:    tail call void @llvm.assume(i1 [[C]])
 // The order between %xs.0 and %xs.1 on the next line doesn't matter
 // and different LLVM versions produce different order.
diff --git a/src/test/codegen/mem-replace-direct-memcpy.rs b/src/test/codegen/mem-replace-direct-memcpy.rs
index 4318e926e47..e8bbf0e1bbd 100644
--- a/src/test/codegen/mem-replace-direct-memcpy.rs
+++ b/src/test/codegen/mem-replace-direct-memcpy.rs
@@ -18,7 +18,7 @@ pub fn replace_byte(dst: &mut u8, src: u8) -> u8 {
 // CHECK-NOT: call void @llvm.memcpy
 // CHECK: ; core::mem::replace
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %dest, i{{.*}} 1, i1 false)
+// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %dest, {{i8\*|ptr}} align 1 %src{{.*}}, i{{.*}} 1, i1 false)
+// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
 // CHECK-NOT: call void @llvm.memcpy
diff --git a/src/test/codegen/slice-iter-len-eq-zero.rs b/src/test/codegen/slice-iter-len-eq-zero.rs
index 1124028253d..894b0ec3de4 100644
--- a/src/test/codegen/slice-iter-len-eq-zero.rs
+++ b/src/test/codegen/slice-iter-len-eq-zero.rs
@@ -9,7 +9,7 @@ type Demo = [u8; 3];
 #[no_mangle]
 pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool {
     // CHECK-NOT: sub
-    // CHECK: %2 = icmp eq {{i8\*|ptr}} %1, %0
+    // CHECK: %2 = icmp eq {{i8\*|ptr}} {{%1|%0}}, {{%1|%0}}
     // CHECK: ret i1 %2
     y.len() == 0
 }
diff --git a/src/test/run-make/rustdoc-verify-output-files/Makefile b/src/test/run-make/rustdoc-verify-output-files/Makefile
new file mode 100644
index 00000000000..bfabbbc6586
--- /dev/null
+++ b/src/test/run-make/rustdoc-verify-output-files/Makefile
@@ -0,0 +1,36 @@
+include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+TMP_OUTPUT_DIR := "$(TMPDIR)/tmp-rustdoc"
+
+all:
+	# Generate html docs
+	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
+
+	# Copy first output for to check if it's exactly same after second compilation
+	cp -R $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
+
+	# Generate html docs once again on same output
+	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
+
+	# Check if everything exactly same
+	$(DIFF) -r -q $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
+
+	# Generate json doc on the same output
+	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json
+
+	# Check if expected json file is generated
+	[ -e $(OUTPUT_DIR)/foobar.json ]
+
+	# TODO
+	# We should re-generate json doc once again and compare the diff with previously
+	# generated one. Because layout of json docs changes in each compilation, we can't
+	# do that currently.
+	#
+	# See https://github.com/rust-lang/rust/issues/103785#issuecomment-1307425590 for details.
+
+	# remove generated json doc
+	rm $(OUTPUT_DIR)/foobar.json
+
+	# Check if json doc compilation broke any of the html files generated previously
+	$(DIFF) -r -q $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
diff --git a/src/test/run-make/rustdoc-verify-output-files/src/lib.rs b/src/test/run-make/rustdoc-verify-output-files/src/lib.rs
new file mode 100644
index 00000000000..5df7576133a
--- /dev/null
+++ b/src/test/run-make/rustdoc-verify-output-files/src/lib.rs
@@ -0,0 +1 @@
+// nothing to see here
diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs
index 8eea5ad01c0..dea154c9319 100644
--- a/src/test/rustdoc-gui/src/test_docs/lib.rs
+++ b/src/test/rustdoc-gui/src/test_docs/lib.rs
@@ -408,6 +408,11 @@ pub struct WithGenerics<T: TraitWithNoDocblocks, S = String, E = WhoLetTheDogOut
     p: P,
 }
 
+pub struct StructWithPublicUndocumentedFields {
+    pub first: u32,
+    pub second: u32,
+}
+
 pub const CONST: u8 = 0;
 
 pub trait TraitWithoutGenerics {
diff --git a/src/test/rustdoc-gui/struct-fields.goml b/src/test/rustdoc-gui/struct-fields.goml
new file mode 100644
index 00000000000..3ec60b58cfd
--- /dev/null
+++ b/src/test/rustdoc-gui/struct-fields.goml
@@ -0,0 +1,5 @@
+goto: "file://" + |DOC_PATH| + "/test_docs/struct.StructWithPublicUndocumentedFields.html"
+
+// Both fields must be on their own line. In other words, they have display: block.
+store-property: (first_top, "//*[@id='structfield.first']", "offsetTop")
+assert-property-false: ("//*[@id='structfield.second']", { "offsetTop": |first_top| })
diff --git a/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs
new file mode 100644
index 00000000000..7f729429581
--- /dev/null
+++ b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs
@@ -0,0 +1,106 @@
+// compile-flags: -Zdrop-tracking
+// incremental
+// edition: 2021
+
+use std::future::*;
+use std::marker::PhantomData;
+use std::pin::Pin;
+use std::task::*;
+
+fn send<T: Send>(_: T) {}
+
+pub trait Stream {
+    type Item;
+
+    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
+}
+
+struct Empty<T>(PhantomData<fn() -> T>);
+
+impl<T> Stream for Empty<T> {
+    type Item = T;
+
+    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        todo!()
+    }
+}
+
+pub trait FnOnce1<A> {
+    type Output;
+    fn call_once(self, arg: A) -> Self::Output;
+}
+
+impl<T, A, R> FnOnce1<A> for T
+where
+    T: FnOnce(A) -> R,
+{
+    type Output = R;
+    fn call_once(self, arg: A) -> R {
+        self(arg)
+    }
+}
+
+pub trait FnMut1<A>: FnOnce1<A> {
+    fn call_mut(&mut self, arg: A) -> Self::Output;
+}
+
+impl<T, A, R> FnMut1<A> for T
+where
+    T: FnMut(A) -> R,
+{
+    fn call_mut(&mut self, arg: A) -> R {
+        self(arg)
+    }
+}
+
+struct Map<St, F>(St, F);
+
+impl<St, F> Stream for Map<St, F>
+where
+    St: Stream,
+    F: FnMut1<St::Item>,
+{
+    type Item = F::Output;
+
+    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        todo!()
+    }
+}
+
+struct FuturesOrdered<T: Future>(PhantomData<fn() -> T::Output>);
+
+pub struct Buffered<St: Stream>(St, FuturesOrdered<St::Item>, usize)
+where
+    St::Item: Future;
+
+impl<St> Stream for Buffered<St>
+where
+    St: Stream,
+    St::Item: Future,
+{
+    type Item = <St::Item as Future>::Output;
+
+    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        todo!()
+    }
+}
+
+struct Next<'a, T: ?Sized>(&'a T);
+
+impl<St: ?Sized + Stream + Unpin> Future for Next<'_, St> {
+    type Output = Option<St::Item>;
+
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        todo!()
+    }
+}
+
+fn main() {
+    send(async {
+        //~^ ERROR implementation of `FnOnce` is not general enough
+        //~| ERROR implementation of `FnOnce` is not general enough
+        //~| ERROR implementation of `FnOnce` is not general enough
+        //~| ERROR implementation of `FnOnce` is not general enough
+        Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+    });
+}
diff --git a/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr
new file mode 100644
index 00000000000..aa9a22e9e72
--- /dev/null
+++ b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr
@@ -0,0 +1,62 @@
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
+   |
+LL | /     send(async {
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+LL | |     });
+   | |______^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
+   |
+LL | /     send(async {
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+LL | |     });
+   | |______^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
+   |
+LL | /     send(async {
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+LL | |     });
+   | |______^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
+   |
+LL | /     send(async {
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+LL | |     });
+   | |______^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/binding/issue-53114-borrow-checks.stderr b/src/test/ui/binding/issue-53114-borrow-checks.stderr
index 489bf70d920..0ec2ae8839e 100644
--- a/src/test/ui/binding/issue-53114-borrow-checks.stderr
+++ b/src/test/ui/binding/issue-53114-borrow-checks.stderr
@@ -17,6 +17,10 @@ LL |     match mm { (_, _y) => { } }
    |           ^^ value used here after partial move
    |
    = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     match mm { (ref _x, _) => { } }
+   |                 +++
 
 error[E0382]: use of partially moved value: `mm`
   --> $DIR/issue-53114-borrow-checks.rs:29:11
@@ -28,6 +32,10 @@ LL |     match mm { (_, _) => { } }
    |           ^^ value used here after partial move
    |
    = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     match mm { (_, ref _y) => { } }
+   |                    +++
 
 error[E0382]: use of moved value: `m`
   --> $DIR/issue-53114-borrow-checks.rs:36:16
@@ -48,6 +56,10 @@ LL |     if let (_, _y) = mm { }
    |                      ^^ value used here after partial move
    |
    = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     if let (ref _x, _) = mm { }
+   |             +++
 
 error[E0382]: use of partially moved value: `mm`
   --> $DIR/issue-53114-borrow-checks.rs:43:21
@@ -59,6 +71,10 @@ LL |     if let (_, _) = mm { }
    |                     ^^ value used here after partial move
    |
    = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     if let (_, ref _y) = mm { }
+   |                +++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr
index 695b01d5ee3..994eaf9d8c7 100644
--- a/src/test/ui/binop/binop-move-semantics.stderr
+++ b/src/test/ui/binop/binop-move-semantics.stderr
@@ -32,6 +32,10 @@ LL |     +
 LL |     x.clone();
    |     ^^^^^^^^^ value borrowed here after move
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     x.clone()
+   |      ++++++++
 help: consider further restricting this bound
    |
 LL | fn move_then_borrow<T: Add<Output=()> + Clone + Copy>(x: T) {
diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
index 1fd1eb12851..50eee1049db 100644
--- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
+++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
@@ -27,6 +27,11 @@ LL |         a @ [.., _] => (),
 ...
 LL |     &x;
    |     ^^ value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ [.., _] => (),
+   |         +++
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5
@@ -71,13 +76,15 @@ LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) {
    |                                       - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         foo @ Some(Test::Foo | Test::Bar) => (),
-   |         ---
-   |         |
-   |         value moved here
-   |         value moved here
+   |         --- value moved here
 ...
 LL |     &x;
    |     ^^ value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref foo @ Some(Test::Foo | Test::Bar) => (),
+   |         +++
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5
@@ -122,13 +129,15 @@ LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4])
    |                                                       - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         a @ [.., Some(Test::Foo | Test::Bar)] => (),
-   |         -
-   |         |
-   |         value moved here
-   |         value moved here
+   |         - value moved here
 ...
 LL |     &x;
    |     ^^ value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ [.., Some(Test::Foo | Test::Bar)] => (),
+   |         +++
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5
diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr
index 17b93106615..d2e9497d079 100644
--- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr
+++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr
@@ -7,6 +7,18 @@ LL |     consume(b);
    |             - value moved here
 LL |     consume(b);
    |             ^ value used here after move
+   |
+note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrowck-consume-unsize-vec.rs:3:15
+   |
+LL | fn consume(_: Box<[i32]>) {
+   |    -------    ^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     consume(b.clone());
+   |              ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr
index 4e20bbf1757..ed7e883ca63 100644
--- a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr
+++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr
@@ -7,6 +7,14 @@ LL |     consume(b);
    |             - value moved here
 LL |     consume(b);
    |             ^ value used here after move
+   |
+note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrowck-consume-upcast-box.rs:5:15
+   |
+LL | fn consume(_: Box<dyn Foo>) {
+   |    -------    ^^^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
index cd0d2fee942..eaf4bb38bc5 100644
--- a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
+++ b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
@@ -9,6 +9,11 @@ LL |         Some(_) if { drop(my_str); false } => {}
 LL |         Some(_) => {}
 LL |         None => { foo(my_str); }
    |                       ^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if { drop(my_str.clone()); false } => {}
+   |                                 ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr
index 0dd720ff6ce..e1b99162088 100644
--- a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr
+++ b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr
@@ -7,6 +7,11 @@ LL |     let _y = {x} + x.clone(); // the `{x}` forces a move to occur
    |               -    ^^^^^^^^^ value borrowed here after move
    |               |
    |               value moved here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = {x.clone()} + x.clone(); // the `{x}` forces a move to occur
+   |                ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
index 346b82a2666..67b00c1dd90 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
@@ -8,6 +8,10 @@ LL |         [.., _y] => {}
    |              ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-match.rs:23:14
@@ -19,6 +23,10 @@ LL |         [.., _y] => {}
    |              ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:33:15
@@ -30,6 +38,10 @@ LL |         [.., (_y, _)] => {}
    |               ^^ value used here after move
    |
    = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:44:11
@@ -41,6 +53,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:55:11
@@ -52,6 +68,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:66:11
@@ -63,6 +83,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:77:11
@@ -74,6 +98,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:89:11
@@ -85,6 +113,10 @@ LL |         [(_x, _), _, _] => {}
    |           ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _, _] => {}
+   |          +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:99:15
@@ -96,6 +128,10 @@ LL |         [.., (_x, _)] => {}
    |               ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _y @ ..] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:110:11
@@ -107,6 +143,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _] => {}
+   |          +++
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
index 6c6a25c251e..47429ea3eeb 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
@@ -8,6 +8,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:28:11
@@ -19,6 +23,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:41:11
@@ -30,6 +38,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:52:11
@@ -41,6 +53,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:63:11
@@ -52,6 +68,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:74:11
@@ -63,6 +83,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11
@@ -74,6 +98,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, ref _y @ ..] => {}
+   |             +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11
@@ -85,6 +113,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11
@@ -96,6 +128,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _, _] => {}
+   |          +++
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
index 77702e145df..bfab13d42d2 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
@@ -8,6 +8,10 @@ LL |         [.., ref _y] => {}
    |              ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: borrow of partially moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:23:14
@@ -19,6 +23,10 @@ LL |         [.., ref _y] => {}
    |              ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: borrow of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:33:15
@@ -30,6 +38,10 @@ LL |         [.., (ref _y, _)] => {}
    |               ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:44:11
@@ -41,6 +53,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:55:11
@@ -52,6 +68,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:66:11
@@ -63,6 +83,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:77:11
@@ -74,6 +98,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
 
 error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11
@@ -85,6 +113,10 @@ LL |         [(ref _x, _), _, _] => {}
    |           ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _, _] => {}
+   |          +++
 
 error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15
@@ -96,6 +128,10 @@ LL |         [.., (ref _x, _)] => {}
    |               ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _y @ ..] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11
@@ -107,6 +143,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:123:5
@@ -118,6 +158,10 @@ LL |     a[2] = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:131:5
@@ -129,6 +173,10 @@ LL |     a[2].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5
@@ -140,6 +188,10 @@ LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x @ ..] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5
@@ -151,6 +203,10 @@ LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x @ ..] => {}
+   |                +++
 
 error: aborting due to 14 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
index 6cc2c2f7a98..8412c24fe61 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
@@ -8,6 +8,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:28:11
@@ -19,6 +23,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:41:11
@@ -30,6 +38,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:52:11
@@ -41,6 +53,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:63:11
@@ -52,6 +68,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:74:11
@@ -63,6 +83,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11
@@ -74,6 +98,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, ref _y @ ..] => {}
+   |             +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11
@@ -85,6 +113,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11
@@ -96,6 +128,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _, _] => {}
+   |          +++
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
index 9add7553afa..e2aeaafc63c 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
@@ -7,6 +7,10 @@ LL |     let [.., ref _y] = a;
    |              ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x] = a;
+   |                +++
 
 error[E0382]: borrow of partially moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:16:14
@@ -17,6 +21,10 @@ LL |     let [.., ref _y] = a;
    |              ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: borrow of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-use.rs:22:15
@@ -27,6 +35,10 @@ LL |     let [.., (ref _y, _)] = a;
    |               ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:30:10
@@ -37,6 +49,10 @@ LL |     let [ref _y @ .., _, _] = a;
    |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _x, _, _] = a;
+   |          +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:36:16
@@ -47,6 +63,10 @@ LL |     let [_, _, ref _y @ ..] = a;
    |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., ref _x] = a;
+   |              +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:42:10
@@ -57,6 +77,10 @@ LL |     let [ref _y @ .., _, _] = a;
    |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [(ref _x, _), _, _] = a;
+   |           +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:48:16
@@ -67,6 +91,10 @@ LL |     let [_, _, ref _y @ ..] = a;
    |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., (ref _x, _)] = a;
+   |               +++
 
 error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:54:11
@@ -77,6 +105,10 @@ LL |     let [(ref _x, _), _, _] = a;
    |           ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _y @ .., _, _] = a;
+   |          +++
 
 error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:60:15
@@ -87,6 +119,10 @@ LL |     let [.., (ref _x, _)] = a;
    |               ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _y @ ..] = a;
+   |                +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:68:13
@@ -97,6 +133,10 @@ LL |     let [_, ref _y @ ..] = a;
    |             ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref x @ .., _] = a;
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:76:5
@@ -107,6 +147,10 @@ LL |     a[2] = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x] = a;
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:82:5
@@ -117,6 +161,10 @@ LL |     a[2].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:88:5
@@ -127,6 +175,10 @@ LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x @ ..] = a;
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:94:5
@@ -137,6 +189,10 @@ LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x @ ..] = a;
+   |                +++
 
 error: aborting due to 14 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
index 363effcfe53..dd456681f57 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
@@ -7,6 +7,10 @@ LL |     let [.., _y] = a;
    |              ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x] = a;
+   |                +++
 
 error[E0382]: use of partially moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array.rs:16:14
@@ -17,6 +21,10 @@ LL |     let [.., _y] = a;
    |              ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:22:15
@@ -27,6 +35,10 @@ LL |     let [.., (_y, _)] = a;
    |               ^^ value used here after move
    |
    = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:30:10
@@ -37,6 +49,10 @@ LL |     let [_y @ .., _, _] = a;
    |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _x, _, _] = a;
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:36:16
@@ -47,6 +63,10 @@ LL |     let [_, _, _y @ ..] = a;
    |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., ref _x] = a;
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:42:10
@@ -57,6 +77,10 @@ LL |     let [_y @ .., _, _] = a;
    |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [(ref _x, _), _, _] = a;
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:48:16
@@ -67,6 +91,10 @@ LL |     let [_, _, _y @ ..] = a;
    |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., (ref _x, _)] = a;
+   |               +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:54:11
@@ -77,6 +105,10 @@ LL |     let [(_x, _), _, _] = a;
    |           ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _y @ .., _, _] = a;
+   |          +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:60:15
@@ -87,6 +119,10 @@ LL |     let [.., (_x, _)] = a;
    |               ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _y @ ..] = a;
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:68:13
@@ -97,6 +133,10 @@ LL |     let [_, _y @ ..] = a;
    |             ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref x @ .., _] = a;
+   |          +++
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.stderr
index 86d2955e236..f94cbc30db4 100644
--- a/src/test/ui/borrowck/borrowck-multiple-captures.stderr
+++ b/src/test/ui/borrowck/borrowck-multiple-captures.stderr
@@ -40,6 +40,11 @@ LL |     thread::spawn(move|| {
 ...
 LL |         drop(x1);
    |              -- use occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x1.clone());
+   |            ++++++++
 
 error[E0382]: use of moved value: `x2`
   --> $DIR/borrowck-multiple-captures.rs:27:19
@@ -53,6 +58,11 @@ LL |     thread::spawn(move|| {
 ...
 LL |         drop(x2);
    |              -- use occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x2.clone());
+   |            ++++++++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/borrowck-multiple-captures.rs:41:14
@@ -100,6 +110,11 @@ LL |     thread::spawn(move|| {
 LL |
 LL |         drop(x);
    |              - use occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x.clone());
+   |           ++++++++
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr
index e01c26adcfc..fb0e274c291 100644
--- a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr
+++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr
@@ -33,6 +33,11 @@ LL |     println!("{}", f[s]);
 ...
 LL |     f[s] = 10;
    |       ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     println!("{}", f[s.clone()]);
+   |                       ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-reinit.stderr b/src/test/ui/borrowck/borrowck-reinit.stderr
index 22253cd96f1..f785900d53f 100644
--- a/src/test/ui/borrowck/borrowck-reinit.stderr
+++ b/src/test/ui/borrowck/borrowck-reinit.stderr
@@ -8,6 +8,11 @@ LL |     drop(x);
    |          - value moved here
 LL |     let _ = (1,x);
    |                ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x.clone());
+   |           ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
index d33115988a9..ad898fcabd9 100644
--- a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
+++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
@@ -8,6 +8,11 @@ LL |         Some(_) if { drop(a); false } => None,
    |                           - value moved here
 LL |         x => x,
    |         ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if { drop(a.clone()); false } => None,
+   |                            ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr
index b20cc6d8cf5..716cc9d0c8b 100644
--- a/src/test/ui/borrowck/issue-41962.stderr
+++ b/src/test/ui/borrowck/issue-41962.stderr
@@ -5,7 +5,7 @@ LL |         if let Some(thing) = maybe {
    |                     ^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `Vec<bool>`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `maybe.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         if let Some(ref thing) = maybe {
    |                     +++
diff --git a/src/test/ui/borrowck/issue-83760.stderr b/src/test/ui/borrowck/issue-83760.stderr
index beeda5685dc..2552fff860c 100644
--- a/src/test/ui/borrowck/issue-83760.stderr
+++ b/src/test/ui/borrowck/issue-83760.stderr
@@ -8,6 +8,10 @@ LL |             val = None;
    |             ---------- this reinitialization might get skipped
    |
    = note: move occurs because value has type `Struct`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     while let Some(ref foo) = val {
+   |                    +++
 
 error[E0382]: use of moved value: `foo`
   --> $DIR/issue-83760.rs:21:14
diff --git a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
index c6931ba7257..55948afca73 100644
--- a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
+++ b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
@@ -5,7 +5,7 @@ LL |         if let Some(mut _x) = opt {}
    |                     ^^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `&mut i32`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `opt.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         if let Some(ref mut _x) = opt {}
    |                     +++
diff --git a/src/test/ui/borrowck/move-in-pattern-mut.stderr b/src/test/ui/borrowck/move-in-pattern-mut.stderr
index 2bf34b32176..dd3471e2c8b 100644
--- a/src/test/ui/borrowck/move-in-pattern-mut.stderr
+++ b/src/test/ui/borrowck/move-in-pattern-mut.stderr
@@ -8,7 +8,7 @@ LL |     foo(s);
    |         ^ value used here after partial move
    |
    = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `s.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |     if let Some(ref mut x) = s {
    |                 +++
@@ -23,7 +23,7 @@ LL |     bar(e);
    |         ^ value used here after partial move
    |
    = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `e.s`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |     let E::V { s: ref mut x } = e;
    |                   +++
diff --git a/src/test/ui/borrowck/move-in-pattern.stderr b/src/test/ui/borrowck/move-in-pattern.stderr
index 6b84c0032cd..250acbe5928 100644
--- a/src/test/ui/borrowck/move-in-pattern.stderr
+++ b/src/test/ui/borrowck/move-in-pattern.stderr
@@ -8,7 +8,7 @@ LL |     foo(s);
    |         ^ value used here after partial move
    |
    = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `s.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |     if let Some(ref x) = s {
    |                 +++
@@ -23,7 +23,7 @@ LL |     bar(e);
    |         ^ value used here after partial move
    |
    = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `e.s`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |     let E::V { s: ref x } = e;
    |                   +++
diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr
index 8b05b238822..74e7067c9af 100644
--- a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr
+++ b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr
@@ -4,9 +4,17 @@ error[E0382]: use of moved value: `value`
 LL | fn this_does_not<'a, R>(value: &'a mut Events<R>) {
    |                         ----- move occurs because `value` has type `&mut Events<R>`, which does not implement the `Copy` trait
 LL |     for _ in 0..3 {
+   |     ------------- inside of this loop
 LL |         Other::handle(value);
    |                       ^^^^^ value moved here, in previous iteration of loop
    |
+note: consider changing this parameter type in function `handle` to borrow instead if owning the value isn't necessary
+  --> $DIR/mut-borrow-in-loop-2.rs:9:22
+   |
+LL |     fn handle(value: T) -> Self;
+   |        ------        ^ this parameter takes ownership of the value
+   |        |
+   |        in this function
 help: consider creating a fresh reborrow of `value` here
    |
 LL |         Other::handle(&mut *value);
diff --git a/src/test/ui/borrowck/or-patterns.stderr b/src/test/ui/borrowck/or-patterns.stderr
index dd5797c3f79..9501798bb06 100644
--- a/src/test/ui/borrowck/or-patterns.stderr
+++ b/src/test/ui/borrowck/or-patterns.stderr
@@ -8,6 +8,10 @@ LL |     &x.0 .0;
    |     ^^^^^^^ value borrowed here after move
    |
    = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ((ref y, _) | (_, y),) => (),
+   |           +++
 
 error[E0382]: borrow of moved value: `x.0.1`
   --> $DIR/or-patterns.rs:10:5
@@ -19,6 +23,10 @@ LL |     &x.0 .1;
    |     ^^^^^^^ value borrowed here after move
    |
    = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ((y, _) | (_, ref y),) => (),
+   |                       +++
 
 error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable
   --> $DIR/or-patterns.rs:18:5
@@ -77,6 +85,10 @@ LL |     &x.0 .0;
    |     ^^^^^^^ value borrowed here after move
    |
    = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((ref y, _) | (_, y),) = x;
+   |           +++
 
 error[E0382]: borrow of moved value: `x.0.1`
   --> $DIR/or-patterns.rs:40:5
@@ -88,6 +100,10 @@ LL |     &x.0 .1;
    |     ^^^^^^^ value borrowed here after move
    |
    = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((y, _) | (_, ref y),) = x;
+   |                       +++
 
 error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable
   --> $DIR/or-patterns.rs:46:5
diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr
index 9072cc925ff..080f6c39449 100644
--- a/src/test/ui/codemap_tests/tab_3.stderr
+++ b/src/test/ui/codemap_tests/tab_3.stderr
@@ -15,6 +15,10 @@ note: this function takes ownership of the receiver `self`, which moves `some_ve
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     some_vec.clone().into_iter();
+   |             ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/drop/repeat-drop-2.stderr b/src/test/ui/drop/repeat-drop-2.stderr
index 7357551c4a7..f030228f71a 100644
--- a/src/test/ui/drop/repeat-drop-2.stderr
+++ b/src/test/ui/drop/repeat-drop-2.stderr
@@ -7,6 +7,11 @@ LL |     let _bar = foo;
    |                --- value moved here
 LL |     let _baz = [foo; 0];
    |                 ^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _bar = foo.clone();
+   |                   ++++++++
 
 error[E0493]: destructor of `String` cannot be evaluated at compile-time
   --> $DIR/repeat-drop-2.rs:7:25
diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.rs b/src/test/ui/dyn-star/dispatch-on-pin-mut.rs
new file mode 100644
index 00000000000..5774c8b2a67
--- /dev/null
+++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.rs
@@ -0,0 +1,52 @@
+// run-pass
+// edition:2021
+// check-run-results
+
+#![feature(dyn_star)]
+//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+
+use std::future::Future;
+
+async fn foo(f: dyn* Future<Output = i32>) {
+    println!("value: {}", f.await);
+}
+
+async fn async_main() {
+    foo(Box::pin(async { 1 })).await
+}
+
+// ------------------------------------------------------------------------- //
+// Implementation Details Below...
+
+use std::pin::Pin;
+use std::task::*;
+
+pub fn noop_waker() -> Waker {
+    let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
+
+    // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
+    unsafe { Waker::from_raw(raw) }
+}
+
+const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
+
+unsafe fn noop_clone(_p: *const ()) -> RawWaker {
+    RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
+}
+
+unsafe fn noop(_p: *const ()) {}
+
+fn main() {
+    let mut fut = async_main();
+
+    // Poll loop, just to test the future...
+    let waker = noop_waker();
+    let ctx = &mut Context::from_waker(&waker);
+
+    loop {
+        match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
+            Poll::Pending => {}
+            Poll::Ready(()) => break,
+        }
+    }
+}
diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout b/src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout
new file mode 100644
index 00000000000..96c5ca6985f
--- /dev/null
+++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout
@@ -0,0 +1 @@
+value: 1
diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr b/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr
new file mode 100644
index 00000000000..fdf74aa7efe
--- /dev/null
+++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr
@@ -0,0 +1,11 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/dispatch-on-pin-mut.rs:5:12
+   |
+LL | #![feature(dyn_star)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs
index b4ff8a22286..c12b16f1605 100644
--- a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs
+++ b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs
@@ -1,7 +1,8 @@
-// check-pass
+// run-pass
+// check-run-results
 
 #![feature(dyn_star)]
-#![allow(incomplete_features)]
+//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
 
 trait AddOne {
     fn add1(&mut self) -> usize;
diff --git a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout
new file mode 100644
index 00000000000..b4db3ed707d
--- /dev/null
+++ b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout
@@ -0,0 +1,2 @@
+43
+44
diff --git a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr
new file mode 100644
index 00000000000..933c133831a
--- /dev/null
+++ b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr
@@ -0,0 +1,11 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/dont-unsize-coerce-dyn-star.rs:4:12
+   |
+LL | #![feature(dyn_star)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
new file mode 100644
index 00000000000..a4eb669e321
--- /dev/null
+++ b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
@@ -0,0 +1,13 @@
+#![feature(dyn_star, trait_upcasting)]
+//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+
+trait A: B {}
+trait B {}
+impl A for usize {}
+impl B for usize {}
+
+fn main() {
+    let x: Box<dyn* A> = Box::new(1usize as dyn* A);
+    let y: Box<dyn* B> = x;
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
new file mode 100644
index 00000000000..2fc751b3b4a
--- /dev/null
+++ b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
@@ -0,0 +1,23 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/no-unsize-coerce-dyn-trait.rs:1:12
+   |
+LL | #![feature(dyn_star, trait_upcasting)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/no-unsize-coerce-dyn-trait.rs:11:26
+   |
+LL |     let y: Box<dyn* B> = x;
+   |            -----------   ^ expected trait `B`, found trait `A`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `Box<dyn* B>`
+              found struct `Box<dyn* A>`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/dyn-star/upcast.rs b/src/test/ui/dyn-star/upcast.rs
index cee76ada7df..c667ac143a3 100644
--- a/src/test/ui/dyn-star/upcast.rs
+++ b/src/test/ui/dyn-star/upcast.rs
@@ -1,7 +1,6 @@
-// run-pass
+// known-bug: #104800
 
 #![feature(dyn_star, trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo: Bar {
     fn hello(&self);
diff --git a/src/test/ui/dyn-star/upcast.stderr b/src/test/ui/dyn-star/upcast.stderr
new file mode 100644
index 00000000000..6a95f7754e6
--- /dev/null
+++ b/src/test/ui/dyn-star/upcast.stderr
@@ -0,0 +1,20 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/upcast.rs:3:12
+   |
+LL | #![feature(dyn_star, trait_upcasting)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: `dyn* Foo` needs to be a pointer-sized type
+  --> $DIR/upcast.rs:30:23
+   |
+LL |     let w: dyn* Bar = w;
+   |                       ^ `dyn* Foo` needs to be a pointer-sized type
+   |
+   = help: the trait `PointerSized` is not implemented for `dyn* Foo`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-23122-2.rs b/src/test/ui/issues/issue-23122-2.rs
index 95e1f60d8b0..338789c2e87 100644
--- a/src/test/ui/issues/issue-23122-2.rs
+++ b/src/test/ui/issues/issue-23122-2.rs
@@ -1,3 +1,4 @@
+// normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
 trait Next {
     type Next: Next;
 }
diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr
index f6cda3de5c7..5828e027b59 100644
--- a/src/test/ui/issues/issue-23122-2.stderr
+++ b/src/test/ui/issues/issue-23122-2.stderr
@@ -1,10 +1,16 @@
-error[E0275]: overflow evaluating the requirement `<T as Next>::Next`
-  --> $DIR/issue-23122-2.rs:10:17
+error[E0275]: overflow evaluating the requirement `<<<<<<<... as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
+  --> $DIR/issue-23122-2.rs:11:17
    |
 LL |     type Next = <GetNext<T::Next> as Next>::Next;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_23122_2`)
+note: required for `GetNext<<<<<<... as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` to implement `Next`
+  --> $DIR/issue-23122-2.rs:10:15
+   |
+LL | impl<T: Next> Next for GetNext<T> {
+   |               ^^^^     ^^^^^^^^^^
+   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-23122-2/issue-23122-2.long-type-hash.txt'
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-29723.stderr b/src/test/ui/issues/issue-29723.stderr
index e39ddfc81c9..92ee5cf22b7 100644
--- a/src/test/ui/issues/issue-29723.stderr
+++ b/src/test/ui/issues/issue-29723.stderr
@@ -9,6 +9,11 @@ LL |         0 if { drop(s); false } => String::from("oops"),
 ...
 LL |             s
    |             ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         0 if { drop(s.clone()); false } => String::from("oops"),
+   |                      ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-42796.stderr b/src/test/ui/issues/issue-42796.stderr
index f3e0e7b20a1..f2971df5db2 100644
--- a/src/test/ui/issues/issue-42796.stderr
+++ b/src/test/ui/issues/issue-42796.stderr
@@ -10,6 +10,10 @@ LL |     println!("{}", s);
    |                    ^ value borrowed here after move
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let mut s_copy = s.clone();
+   |                       ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
index bfabe2d12f7..20d4c418e87 100644
--- a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
+++ b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
@@ -370,23 +370,23 @@ error: layout_of(NicheFirst) = Layout {
                pref: $PREF_ALIGN,
            },
            abi: ScalarPair(
-               Initialized {
+               Union {
                    value: Int(
                        I8,
                        false,
                    ),
-                   valid_range: 0..=4,
                },
-               Union {
+               Initialized {
                    value: Int(
                        I8,
                        false,
                    ),
+                   valid_range: 0..=4,
                },
            ),
            fields: Arbitrary {
                offsets: [
-                   Size(0 bytes),
+                   Size(1 bytes),
                ],
                memory_index: [
                    0,
@@ -394,7 +394,7 @@ error: layout_of(NicheFirst) = Layout {
            },
            largest_niche: Some(
                Niche {
-                   offset: Size(0 bytes),
+                   offset: Size(1 bytes),
                    value: Int(
                        I8,
                        false,
@@ -429,29 +429,29 @@ error: layout_of(NicheFirst) = Layout {
                                    I8,
                                    false,
                                ),
-                               valid_range: 0..=2,
+                               valid_range: 0..=255,
                            },
                            Initialized {
                                value: Int(
                                    I8,
                                    false,
                                ),
-                               valid_range: 0..=255,
+                               valid_range: 0..=2,
                            },
                        ),
                        fields: Arbitrary {
                            offsets: [
-                               Size(0 bytes),
                                Size(1 bytes),
+                               Size(0 bytes),
                            ],
                            memory_index: [
-                               0,
                                1,
+                               0,
                            ],
                        },
                        largest_niche: Some(
                            Niche {
-                               offset: Size(0 bytes),
+                               offset: Size(1 bytes),
                                value: Int(
                                    I8,
                                    false,
diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr
index 7c0e916eddc..d14cd6cb4e0 100644
--- a/src/test/ui/liveness/liveness-move-call-arg.stderr
+++ b/src/test/ui/liveness/liveness-move-call-arg.stderr
@@ -3,9 +3,23 @@ error[E0382]: use of moved value: `x`
    |
 LL |     let x: Box<isize> = Box::new(25);
    |         - move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
-...
+LL |
+LL |     loop {
+   |     ---- inside of this loop
 LL |         take(x);
    |              ^ value moved here, in previous iteration of loop
+   |
+note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary
+  --> $DIR/liveness-move-call-arg.rs:1:13
+   |
+LL | fn take(_x: Box<isize>) {}
+   |    ----     ^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         take(x.clone());
+   |               ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/liveness/liveness-move-in-loop.stderr b/src/test/ui/liveness/liveness-move-in-loop.stderr
index 832d4f8fa03..a060914f178 100644
--- a/src/test/ui/liveness/liveness-move-in-loop.stderr
+++ b/src/test/ui/liveness/liveness-move-in-loop.stderr
@@ -4,8 +4,22 @@ error[E0382]: use of moved value: `y`
 LL |     let y: Box<isize> = 42.into();
    |         - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait
 ...
+LL |     loop {
+   |     ---- inside of this loop
+LL |         println!("{}", y);
+LL |         loop {
+   |         ---- inside of this loop
+LL |             loop {
+   |             ---- inside of this loop
+LL |                 loop {
+   |                 ---- inside of this loop
 LL |                     x = y;
    |                         ^ value moved here, in previous iteration of loop
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |                     x = y.clone();
+   |                          ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/liveness/liveness-move-in-while.stderr b/src/test/ui/liveness/liveness-move-in-while.stderr
index b04a05fe409..4dff7447dd7 100644
--- a/src/test/ui/liveness/liveness-move-in-while.stderr
+++ b/src/test/ui/liveness/liveness-move-in-while.stderr
@@ -24,12 +24,22 @@ error[E0382]: borrow of moved value: `y`
 LL |     let y: Box<isize> = 42.into();
    |         - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait
 ...
+LL |     loop {
+   |     ---- inside of this loop
 LL |         println!("{}", y);
    |                        ^ value borrowed here after move
 LL |         while true { while true { while true { x = y; x.clone(); } } }
-   |                                                    - value moved here, in previous iteration of loop
+   |         ----------   ----------   ----------       - value moved here, in previous iteration of loop
+   |         |            |            |
+   |         |            |            inside of this loop
+   |         |            inside of this loop
+   |         inside of this loop
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         while true { while true { while true { x = y.clone(); x.clone(); } } }
+   |                                                     ++++++++
 
 error: aborting due to previous error; 3 warnings emitted
 
diff --git a/src/test/ui/liveness/liveness-use-after-move.stderr b/src/test/ui/liveness/liveness-use-after-move.stderr
index 218b93c8e4f..3accba197a1 100644
--- a/src/test/ui/liveness/liveness-use-after-move.stderr
+++ b/src/test/ui/liveness/liveness-use-after-move.stderr
@@ -10,6 +10,10 @@ LL |     println!("{}", *x);
    |                    ^^ value borrowed here after move
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let y = x.clone();
+   |              ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr
index 8edc0463fe5..65d55ca8f70 100644
--- a/src/test/ui/liveness/liveness-use-after-send.stderr
+++ b/src/test/ui/liveness/liveness-use-after-send.stderr
@@ -8,7 +8,16 @@ LL |     send(ch, message);
 LL |     println!("{}", message);
    |                    ^^^^^^^ value borrowed here after move
    |
+note: consider changing this parameter type in function `send` to borrow instead if owning the value isn't necessary
+  --> $DIR/liveness-use-after-send.rs:3:54
+   |
+LL | fn send<T:Send + std::fmt::Debug>(ch: Chan<T>, data: T) {
+   |    ---- in this function                             ^ this parameter takes ownership of the value
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     send(ch, message.clone());
+   |                     ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/borrow-closures-instead-of-move.stderr b/src/test/ui/moves/borrow-closures-instead-of-move.stderr
index 3146b695900..9a84ddef7e6 100644
--- a/src/test/ui/moves/borrow-closures-instead-of-move.stderr
+++ b/src/test/ui/moves/borrow-closures-instead-of-move.stderr
@@ -4,9 +4,17 @@ error[E0382]: use of moved value: `f`
 LL | fn takes_fn(f: impl Fn()) {
    |             - move occurs because `f` has type `impl Fn()`, which does not implement the `Copy` trait
 LL |     loop {
+   |     ---- inside of this loop
 LL |         takes_fnonce(f);
    |                      ^ value moved here, in previous iteration of loop
    |
+note: consider changing this parameter type in function `takes_fnonce` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrow-closures-instead-of-move.rs:34:20
+   |
+LL | fn takes_fnonce(_: impl FnOnce()) {}
+   |    ------------    ^^^^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 help: consider borrowing `f`
    |
 LL |         takes_fnonce(&f);
@@ -24,6 +32,13 @@ LL |         takes_fnonce(m);
 LL |     takes_fnonce(m);
    |                  ^ value used here after move
    |
+note: consider changing this parameter type in function `takes_fnonce` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrow-closures-instead-of-move.rs:34:20
+   |
+LL | fn takes_fnonce(_: impl FnOnce()) {}
+   |    ------------    ^^^^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 help: consider mutably borrowing `m`
    |
 LL |         takes_fnonce(&mut m);
diff --git a/src/test/ui/moves/issue-46099-move-in-macro.stderr b/src/test/ui/moves/issue-46099-move-in-macro.stderr
index baa87e3e9fd..94bc9e6f454 100644
--- a/src/test/ui/moves/issue-46099-move-in-macro.stderr
+++ b/src/test/ui/moves/issue-46099-move-in-macro.stderr
@@ -5,6 +5,11 @@ LL |     let b = Box::new(true);
    |         - move occurs because `b` has type `Box<bool>`, which does not implement the `Copy` trait
 LL |     test!({b});
    |            ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     test!({b.clone()});
+   |             ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.rs b/src/test/ui/moves/issue-72649-uninit-in-loop.rs
index d76b69ecdc8..56c225bab8c 100644
--- a/src/test/ui/moves/issue-72649-uninit-in-loop.rs
+++ b/src/test/ui/moves/issue-72649-uninit-in-loop.rs
@@ -25,7 +25,7 @@ fn moved_here_1() {
 fn moved_here_2() {
     let value = NonCopy{};
     //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
-    loop {
+    loop { //~ NOTE inside of this loop
         let _used = value;
         //~^ NOTE value moved here
         loop {
@@ -38,7 +38,7 @@ fn moved_here_2() {
 fn moved_loop_1() {
     let value = NonCopy{};
     //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
-    loop {
+    loop { //~ NOTE inside of this loop
         let _used = value; //~ ERROR use of moved value: `value`
         //~^ NOTE value moved here, in previous iteration of loop
     }
@@ -49,7 +49,7 @@ fn moved_loop_2() {
     //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
     let _used = value;
     value = NonCopy{};
-    loop {
+    loop { //~ NOTE inside of this loop
         let _used2 = value; //~ ERROR use of moved value: `value`
         //~^ NOTE value moved here, in previous iteration of loop
     }
diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
index 974994223a3..7e119fe8cda 100644
--- a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
+++ b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
@@ -15,7 +15,9 @@ error[E0382]: use of moved value: `value`
    |
 LL |     let value = NonCopy{};
    |         ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
-...
+LL |
+LL |     loop {
+   |     ---- inside of this loop
 LL |         let _used = value;
    |                     ----- value moved here
 ...
@@ -27,7 +29,9 @@ error[E0382]: use of moved value: `value`
    |
 LL |     let value = NonCopy{};
    |         ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
-...
+LL |
+LL |     loop {
+   |     ---- inside of this loop
 LL |         let _used = value;
    |                     ^^^^^ value moved here, in previous iteration of loop
 
@@ -37,6 +41,8 @@ error[E0382]: use of moved value: `value`
 LL |     let mut value = NonCopy{};
    |         --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
 ...
+LL |     loop {
+   |     ---- inside of this loop
 LL |         let _used2 = value;
    |                      ^^^^^ value moved here, in previous iteration of loop
 
diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr
index 3a686121a92..c13dc58826e 100644
--- a/src/test/ui/moves/move-fn-self-receiver.stderr
+++ b/src/test/ui/moves/move-fn-self-receiver.stderr
@@ -96,6 +96,10 @@ note: this function takes ownership of the receiver `self`, which moves `rc_foo`
    |
 LL |     fn use_rc_self(self: Rc<Self>) {}
    |                    ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     rc_foo.clone().use_rc_self();
+   |           ++++++++
 
 error[E0382]: use of moved value: `foo_add`
   --> $DIR/move-fn-self-receiver.rs:59:5
@@ -137,6 +141,11 @@ LL |     for _val in explicit_into_iter.into_iter() {}
    |                                    ----------- `explicit_into_iter` moved due to this method call
 LL |     explicit_into_iter;
    |     ^^^^^^^^^^^^^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     for _val in explicit_into_iter.clone().into_iter() {}
+   |                                   ++++++++
 
 error[E0382]: use of moved value: `container`
   --> $DIR/move-fn-self-receiver.rs:71:5
@@ -160,6 +169,7 @@ error[E0382]: use of moved value: `foo2`
 LL |     let foo2 = Foo;
    |         ---- move occurs because `foo2` has type `Foo`, which does not implement the `Copy` trait
 LL |     loop {
+   |     ---- inside of this loop
 LL |         foo2.use_self();
    |         ^^^^ ---------- `foo2` moved due to this method call, in previous iteration of loop
 
diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr
index 2048fefefa3..86e5f65248b 100644
--- a/src/test/ui/moves/move-guard-same-consts.stderr
+++ b/src/test/ui/moves/move-guard-same-consts.stderr
@@ -8,6 +8,18 @@ LL |         (1, 2) if take(x) => (),
    |                        - value moved here
 LL |         (1, 2) if take(x) => (),
    |                        ^ value used here after move
+   |
+note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary
+  --> $DIR/move-guard-same-consts.rs:25:15
+   |
+LL | fn take<T>(_: T) -> bool { false }
+   |    ----       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         (1, 2) if take(x.clone()) => (),
+   |                         ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr
index 5e9aa66b90d..f04cb34d7c4 100644
--- a/src/test/ui/moves/move-in-guard-1.stderr
+++ b/src/test/ui/moves/move-in-guard-1.stderr
@@ -8,6 +8,18 @@ LL |         (1, _) if take(x) => (),
    |                        - value moved here
 LL |         (_, 2) if take(x) => (),
    |                        ^ value used here after move
+   |
+note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary
+  --> $DIR/move-in-guard-1.rs:15:15
+   |
+LL | fn take<T>(_: T) -> bool { false }
+   |    ----       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         (1, _) if take(x.clone()) => (),
+   |                         ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr
index 8d636c11b78..26047861f55 100644
--- a/src/test/ui/moves/move-in-guard-2.stderr
+++ b/src/test/ui/moves/move-in-guard-2.stderr
@@ -6,6 +6,18 @@ LL |     let x: Box<_> = Box::new(1);
 ...
 LL |         (_, 2) if take(x) => (),
    |                        ^ value used here after move
+   |
+note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary
+  --> $DIR/move-in-guard-2.rs:13:15
+   |
+LL | fn take<T>(_: T) -> bool { false }
+   |    ----       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         (_, 2) if take(x.clone()) => (),
+   |                         ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr
index 3cc8ca29144..a49ee31b466 100644
--- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr
+++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr
@@ -13,6 +13,10 @@ note: this function takes ownership of the receiver `self`, which moves `x`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     consume(x.clone().into_iter().next().unwrap());
+   |              ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr
index a315bbaab33..db4382b58fc 100644
--- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr
+++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr
@@ -8,7 +8,7 @@ LL |     consume(node) + r
    |             ^^^^ value used here after partial move
    |
    = note: partial move occurs because value has type `Box<List>`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `node.next.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         Some(ref right) => consume(right),
    |              +++
diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr
index ee7971691a4..0930df14805 100644
--- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr
+++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr
@@ -9,6 +9,11 @@ LL |     let _y = Foo { f:x };
 LL |
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = Foo { f:x.clone() };
+   |                       ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:21:11
@@ -21,6 +26,11 @@ LL |     let _y = Foo { f:(((x))) };
 LL |
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = Foo { f:(((x))).clone() };
+   |                             ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr
index 9bcec36740d..838b1282cb4 100644
--- a/src/test/ui/moves/moves-based-on-type-exprs.stderr
+++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr
@@ -7,6 +7,11 @@ LL |     let _y = Foo { f:x };
    |                      - value moved here
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = Foo { f:x.clone() };
+   |                       ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:18:11
@@ -17,6 +22,11 @@ LL |     let _y = (x, 3);
    |               - value moved here
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = (x.clone(), 3);
+   |                ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:35:11
@@ -29,6 +39,11 @@ LL |         x
 ...
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         x.clone()
+   |          ++++++++
 
 error[E0382]: borrow of moved value: `y`
   --> $DIR/moves-based-on-type-exprs.rs:36:11
@@ -41,6 +56,11 @@ LL |         y
 ...
 LL |     touch(&y);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         y.clone()
+   |          ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:46:11
@@ -53,6 +73,11 @@ LL |         true => x,
 ...
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         true => x.clone(),
+   |                  ++++++++
 
 error[E0382]: borrow of moved value: `y`
   --> $DIR/moves-based-on-type-exprs.rs:47:11
@@ -65,6 +90,11 @@ LL |         false => y
 ...
 LL |     touch(&y);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         false => y.clone()
+   |                   ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:58:11
@@ -77,6 +107,18 @@ LL |         _ if guard(x) => 10,
 ...
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+note: consider changing this parameter type in function `guard` to borrow instead if owning the value isn't necessary
+  --> $DIR/moves-based-on-type-exprs.rs:6:14
+   |
+LL | fn guard(_s: String) -> bool {panic!()}
+   |    -----     ^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         _ if guard(x.clone()) => 10,
+   |                     ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:65:11
@@ -87,6 +129,11 @@ LL |     let _y = [x];
    |               - value moved here
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = [x.clone()];
+   |                ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:71:11
@@ -97,6 +144,11 @@ LL |     let _y = vec![x];
    |                   - value moved here
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = vec![x.clone()];
+   |                    ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:77:11
@@ -113,6 +165,10 @@ note: this function takes ownership of the receiver `self`, which moves `x`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = x.clone().into_iter().next().unwrap();
+   |               ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:83:11
@@ -129,6 +185,10 @@ note: this function takes ownership of the receiver `self`, which moves `x`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = [x.clone().into_iter().next().unwrap(); 1];
+   |                ++++++++
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr
index ad1a2db8b52..225935532ea 100644
--- a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr
+++ b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr
@@ -8,6 +8,10 @@ LL |     touch(&x);
    |           ^^ value borrowed here after partial move
    |
    = note: partial move occurs because `x.f` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         Foo {ref f} => {}
+   |              +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr
index eef8ce61fa9..0bcce301263 100644
--- a/src/test/ui/moves/moves-based-on-type-tuple.stderr
+++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr
@@ -8,6 +8,11 @@ LL |     Box::new((x, x))
    |               -  ^ value used here after move
    |               |
    |               value moved here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     Box::new((x.clone(), x))
+   |                ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr
index c25981e6f80..22e7951dbe3 100644
--- a/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr
+++ b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr
@@ -7,6 +7,11 @@ LL |     (t, t)
    |      -  ^ value used here after move
    |      |
    |      value moved here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     (t.clone(), t)
+   |       ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr
index e9d7ca953d6..0a09353b8ec 100644
--- a/src/test/ui/nll/closure-access-spans.stderr
+++ b/src/test/ui/nll/closure-access-spans.stderr
@@ -67,6 +67,11 @@ LL |     || x.len();
    |     ^^ - borrow occurs due to use in closure
    |     |
    |     value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = x.clone();
+   |              ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/closure-access-spans.rs:40:5
@@ -79,6 +84,11 @@ LL |     || x = String::new();
    |     ^^ - borrow occurs due to use in closure
    |     |
    |     value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = x.clone();
+   |              ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/closure-access-spans.rs:45:5
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
index 947c9e29b45..97ed414b1ec 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
+++ b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
@@ -37,6 +37,11 @@ LL |     let mut t: T = (0, Box::new(0)); drop(t);
    |         move occurs because `t` has type `(u32, Box<u32>)`, which does not implement the `Copy` trait
 LL |     t.0 = 10; t.1 = Box::new(20);
    |     ^^^^^^^^ value partially assigned here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let mut t: T = (0, Box::new(0)); drop(t.clone());
+   |                                            ++++++++
 
 error[E0381]: partially assigned binding `s` isn't fully initialized
   --> $DIR/issue-21232-partial-init-and-use.rs:123:5
@@ -77,6 +82,11 @@ LL |     let mut t: T = (0, Box::new(0)); drop(t);
    |         move occurs because `t` has type `(u32, Box<u32>)`, which does not implement the `Copy` trait
 LL |     t.0 = 10;
    |     ^^^^^^^^ value partially assigned here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let mut t: T = (0, Box::new(0)); drop(t.clone());
+   |                                            ++++++++
 
 error[E0381]: partially assigned binding `s` isn't fully initialized
   --> $DIR/issue-21232-partial-init-and-use.rs:149:5
@@ -208,6 +218,11 @@ LL |         c2 => {
    |         -- value moved here
 LL |             c.0 = 2;
    |             ^^^^^^^ value partially assigned here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref c2 => {
+   |         +++
 
 error[E0382]: assign to part of moved value: `c`
   --> $DIR/issue-21232-partial-init-and-use.rs:255:13
@@ -219,6 +234,11 @@ LL |         c2 => {
    |         -- value moved here
 LL |             (c.1).0 = 2;
    |             ^^^^^^^^^^^ value partially assigned here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref c2 => {
+   |         +++
 
 error[E0382]: assign to part of moved value: `c.1`
   --> $DIR/issue-21232-partial-init-and-use.rs:263:13
@@ -229,6 +249,10 @@ LL |             ((c.1).1).0 = 3;
    |             ^^^^^^^^^^^^^^^ value partially assigned here after move
    |
    = note: move occurs because `c.1` has type `(i32, (i32, String))`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref c2 => {
+   |         +++
 
 error: aborting due to 23 previous errors
 
diff --git a/src/test/ui/nll/issue-51512.stderr b/src/test/ui/nll/issue-51512.stderr
index e591ca08290..072e96788b1 100644
--- a/src/test/ui/nll/issue-51512.stderr
+++ b/src/test/ui/nll/issue-51512.stderr
@@ -7,6 +7,11 @@ LL |     let r = range;
    |             ----- value moved here
 LL |     let x = range.start;
    |             ^^^^^^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = range.clone();
+   |                  ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-53807.stderr b/src/test/ui/nll/issue-53807.stderr
index 574a114340f..d8f58b59131 100644
--- a/src/test/ui/nll/issue-53807.stderr
+++ b/src/test/ui/nll/issue-53807.stderr
@@ -5,7 +5,7 @@ LL |         if let Some(thing) = maybe {
    |                     ^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `Vec<bool>`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `maybe.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         if let Some(ref thing) = maybe {
    |                     +++
diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr
index 2d48a914218..f72ed3af718 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.stderr
+++ b/src/test/ui/nll/match-cfg-fake-edges.stderr
@@ -26,6 +26,11 @@ LL |         false if { drop(x); true } => 1,
 LL |         true => {
 LL |             x;
    |             ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         false if { drop(x.clone()); true } => 1,
+   |                          ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/ref-suggestion.stderr b/src/test/ui/nll/ref-suggestion.stderr
index a973c583a9d..b1f5117cb02 100644
--- a/src/test/ui/nll/ref-suggestion.stderr
+++ b/src/test/ui/nll/ref-suggestion.stderr
@@ -7,6 +7,11 @@ LL |     let y = x;
    |             - value moved here
 LL |     x;
    |     ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let y = x.clone();
+   |              ++++++++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/ref-suggestion.rs:8:5
@@ -17,6 +22,11 @@ LL |     let mut y = x;
    |                 - value moved here
 LL |     x;
    |     ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let mut y = x.clone();
+   |                  ++++++++
 
 error[E0382]: use of partially moved value: `x`
   --> $DIR/ref-suggestion.rs:16:5
@@ -28,7 +38,7 @@ LL |     x;
    |     ^ value used here after partial move
    |
    = note: partial move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `x.0.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         (Some(ref y), ()) => {},
    |               +++
diff --git a/src/test/ui/parser/issue-104620.rs b/src/test/ui/parser/issue-104620.rs
new file mode 100644
index 00000000000..f49476c4408
--- /dev/null
+++ b/src/test/ui/parser/issue-104620.rs
@@ -0,0 +1,4 @@
+#![feature(rustc_attrs)]
+
+#![rustc_dummy=5z] //~ ERROR unexpected expression: `5z`
+fn main() {}
diff --git a/src/test/ui/parser/issue-104620.stderr b/src/test/ui/parser/issue-104620.stderr
new file mode 100644
index 00000000000..d06a6b2554b
--- /dev/null
+++ b/src/test/ui/parser/issue-104620.stderr
@@ -0,0 +1,8 @@
+error: unexpected expression: `5z`
+  --> $DIR/issue-104620.rs:3:16
+   |
+LL | #![rustc_dummy=5z]
+   |                ^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
index fad84dda0e1..c8b45fd24d9 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -16,6 +16,11 @@ LL |         Some(_z @ ref _y) => {}
    |              |    value borrowed here after move
    |              value moved into `_z` here
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         Some(ref _z @ ref _y) => {}
+   |              +++
 
 error: cannot move out of value because it is borrowed
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
@@ -35,6 +40,11 @@ LL |         Some(_z @ ref mut _y) => {}
    |              |    value borrowed here after move
    |              value moved into `_z` here
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         Some(ref _z @ ref mut _y) => {}
+   |              +++
 
 error[E0382]: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
@@ -45,7 +55,7 @@ LL |         Some(ref _y @ _z) => {}
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `x.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         Some(ref _y @ ref _z) => {}
    |                       +++
@@ -59,7 +69,7 @@ LL |         Some(ref mut _y @ _z) => {}
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `x.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         Some(ref mut _y @ ref _z) => {}
    |                           +++
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
index a227cc583d6..32489715112 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
@@ -6,6 +6,11 @@ LL |     let a @ b = U;
    |         |   |
    |         |   value moved here
    |         value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = U;
+   |         +++     +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:13:9
@@ -16,6 +21,10 @@ LL |     let a @ (b, c) = (U, U);
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (b, ref c) = (U, U);
+   |         +++         +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:15:9
@@ -26,6 +35,10 @@ LL |     let a @ (b, c) = (u(), u());
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (b, ref c) = (u(), u());
+   |         +++         +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:18:16
@@ -36,6 +49,11 @@ LL |         a @ Ok(b) | a @ Err(b) => {}
    |         -      ^ value used here after move
    |         |
    |         value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Ok(b) | a @ Err(b) => {}
+   |         +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:18:29
@@ -46,6 +64,11 @@ LL |         a @ Ok(b) | a @ Err(b) => {}
    |                     -       ^ value used here after move
    |                     |
    |                     value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Ok(b) | ref a @ Err(b) => {}
+   |                     +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:25:9
@@ -56,6 +79,10 @@ LL |         xs @ [a, .., b] => {}
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref xs @ [a, .., ref b] => {}
+   |         +++              +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:29:9
@@ -66,6 +93,10 @@ LL |         xs @ [_, ys @ .., _] => {}
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref xs @ [_, ref ys @ .., _] => {}
+   |         +++          +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:22:12
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
index 002c7609f61..f27df32ccfa 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
@@ -79,6 +79,10 @@ LL |     let ref a @ box b = Box::new(NC);
    |         value borrowed here after move
    |
    = note: move occurs because value has type `NC`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ box ref b = Box::new(NC);
+   |                     +++
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:38:9
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
index be4e81c61aa..d6474f1b49f 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
@@ -7,6 +7,11 @@ LL |     let a @ ref b = U;
    |         |   value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = U;
+   |         +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
index a9e66de0842..389e86e6464 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -7,6 +7,11 @@ LL |     let a @ ref b = U;
    |         |   value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = U;
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
@@ -18,6 +23,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         |            value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:14
@@ -28,6 +38,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |              |       value borrowed here after move
    |              value moved into `b` here
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let a @ (ref mut b @ ref mut c, d @ ref e) = (U, U);
+   |              +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:33
@@ -38,6 +53,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |                                 |   value borrowed here after move
    |                                 value moved into `d` here
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let a @ (mut b @ ref mut c, ref d @ ref e) = (U, U);
+   |                                 +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9
@@ -49,6 +69,11 @@ LL |     let a @ [ref mut b, ref c] = [U, U];
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ [ref mut b, ref c] = [U, U];
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9
@@ -59,6 +84,11 @@ LL |     let a @ ref b = u();
    |         |   value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = u();
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
@@ -70,6 +100,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         |            value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:14
@@ -80,6 +115,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |              |       value borrowed here after move
    |              value moved into `b` here
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let a @ (ref mut b @ ref mut c, d @ ref e) = (u(), u());
+   |              +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:33
@@ -90,6 +130,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |                                 |   value borrowed here after move
    |                                 value moved into `d` here
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u());
+   |                                 +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9
@@ -101,6 +146,11 @@ LL |     let a @ [ref mut b, ref c] = [u(), u()];
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ [ref mut b, ref c] = [u(), u()];
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:42:9
@@ -111,6 +161,11 @@ LL |         a @ Some(ref b) => {}
    |         |        value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some(ref b) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9
@@ -122,6 +177,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         |                 value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:19
@@ -132,6 +192,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   |       value borrowed here after move
    |                   value moved into `b` here
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+   |                   +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
@@ -142,6 +207,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      |   value borrowed here after move
    |                                      value moved into `d` here
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+   |                                      +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9
@@ -153,6 +223,11 @@ LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         |             value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref mut a @ Some([ref b, ref mut c]) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9
@@ -163,6 +238,11 @@ LL |         a @ Some(ref b) => {}
    |         |        value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some(ref b) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9
@@ -174,6 +254,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         |                 value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19
@@ -184,6 +269,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   |       value borrowed here after move
    |                   value moved into `b` here
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+   |                   +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
@@ -194,6 +284,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      |   value borrowed here after move
    |                                      value moved into `d` here
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+   |                                      +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9
@@ -205,6 +300,11 @@ LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         |             value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref mut a @ Some([ref b, ref mut c]) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11
@@ -215,6 +315,11 @@ LL |     fn f1(a @ ref b: U) {}
    |           |   value borrowed here after move
    |           value moved into `a` here
    |           move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f1(ref a @ ref b: U) {}
+   |           +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
@@ -226,6 +331,11 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |           |            value borrowed here after move
    |           value moved into `a` here
    |           move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f2(ref mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+   |           +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:20
@@ -236,6 +346,11 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                    |   value borrowed here after move
    |                    value moved into `b` here
    |                    move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f2(mut a @ (ref b @ ref c, mut d @ ref e): (U, U)) {}
+   |                    +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:31
@@ -246,6 +361,11 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                               |       value borrowed here after move
    |                               value moved into `d` here
    |                               move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f2(mut a @ (b @ ref c, ref mut d @ ref e): (U, U)) {}
+   |                               +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:19:11
@@ -257,6 +377,11 @@ LL |     fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
    |           |    value borrowed here after move
    |           value moved into `a` here
    |           move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f3(ref a @ [ref mut b, ref c]: [U; 2]) {}
+   |           +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
@@ -267,6 +392,10 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (mut b @ ref mut c, ref d @ ref e) = (U, U);
+   |         +++                         +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
@@ -277,6 +406,10 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u());
+   |         +++                         +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
@@ -285,6 +418,11 @@ LL |     match Some((U, U)) {
    |           ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         - value moved here           ^ value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+   |         +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30
@@ -305,6 +443,11 @@ LL |         a @ Some(ref b) => {}
    |         -        ^^^^^ value borrowed here after move
    |         |
    |         value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some(ref b) => {}
+   |         +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
@@ -313,6 +456,11 @@ LL |     match Some((u(), u())) {
    |           ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         - value moved here           ^ value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+   |         +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
index b2f22fe8638..770bb89530c 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
@@ -242,6 +242,10 @@ LL |     let ref mut a @ [b, mut c] = [U, U];
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref mut a @ [b, ref mut c] = [U, U];
+   |                         +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
@@ -251,6 +255,11 @@ LL |     let ref a @ b = u();
    |         |       |
    |         |       value moved here
    |         value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = u();
+   |                 +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
@@ -261,6 +270,10 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                  value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (ref b @ ref mut c, ref d @ e) = (u(), u());
+   |                          +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
@@ -271,6 +284,10 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                                 value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (ref b @ mut c, ref d @ ref e) = (u(), u());
+   |                                         +++
 
 error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
@@ -281,6 +298,10 @@ LL |     let ref mut a @ [b, mut c] = [u(), u()];
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref mut a @ [b, ref mut c] = [u(), u()];
+   |                         +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
@@ -291,7 +312,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving the value
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         ref a @ Some((ref b @ ref mut c, ref d @ e)) => {}
    |                               +++
@@ -305,7 +326,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving the value
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ ref e)) => {}
    |                                              +++
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
index 384a57b2ee0..ad4ce7952ca 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -97,6 +97,11 @@ LL |     let a @ (ref mut b, ref mut c) = (U, U);
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9
@@ -109,6 +114,11 @@ LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (b, [c, d]) = &mut val; // Same as ^--
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9
@@ -119,6 +129,11 @@ LL |     let a @ &mut ref mut b = &mut U;
    |         |        value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `&mut U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ &mut ref mut b = &mut U;
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9
@@ -130,6 +145,11 @@ LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
    |         |         value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+   |         +++
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
index cd3234952fa..e0e623fa544 100644
--- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
+++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
@@ -7,6 +7,10 @@ LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ NC(b, ref c @ NC(d, e)) = NC(C, NC(C, C));
+   |         +++           +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
index 840a513d6c6..638bdd6db76 100644
--- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
+++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -34,6 +34,11 @@ LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |                             |   value borrowed here after move
    |                             value moved into `b` here
    |                             move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         Ok(ref a @ b) | Err(ref b @ ref a) => {
+   |                             +++
 
 error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:42:9
@@ -52,6 +57,11 @@ LL |     let ref mut a @ b = NotCopy;
    |         |           |
    |         |           value moved here
    |         value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref mut a @ ref b = NotCopy;
+   |                     +++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
index bac2db6ce82..bb7b818368b 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -129,6 +129,10 @@ LL |     drop(tup.1);
    |          ^^^^^ value used here after move
    |
    = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let (ref _x0, ref _x1, ref _x2, ..) = tup;
+   |                   +++
 
 error[E0382]: borrow of moved value: `tup.1`
   --> $DIR/borrowck-move-ref-pattern.rs:29:20
diff --git a/src/test/ui/recursion/issue-83150.stderr b/src/test/ui/recursion/issue-83150.stderr
index a67bfd018a2..4d00a708313 100644
--- a/src/test/ui/recursion/issue-83150.stderr
+++ b/src/test/ui/recursion/issue-83150.stderr
@@ -9,11 +9,9 @@ LL |     func(&mut iter.map(|x| x + 1))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error[E0275]: overflow evaluating the requirement `<std::ops::Range<u8> as Iterator>::Item`
+error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>: Iterator`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
-   = note: required for `Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:12:24: 12:27]>` to implement `Iterator`
-   = note: 64 redundant requirements hidden
    = note: required for `&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>` to implement `Iterator`
    = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type-hash.txt'
 
diff --git a/src/test/ui/recursion/issue-95134.rs b/src/test/ui/recursion/issue-95134.rs
index adc9c6ee2d9..fdc4d536981 100644
--- a/src/test/ui/recursion/issue-95134.rs
+++ b/src/test/ui/recursion/issue-95134.rs
@@ -1,6 +1,8 @@
 // build-fail
+// known-bug: #95134
 // compile-flags: -Copt-level=0
-//~^^ ERROR overflow evaluating the requirement
+// failure-status: 101
+// dont-check-compiler-stderr
 
 pub fn encode_num<Writer: ExampleWriter>(n: u32, mut writer: Writer) -> Result<(), Writer::Error> {
     if n > 15 {
diff --git a/src/test/ui/recursion/issue-95134.stderr b/src/test/ui/recursion/issue-95134.stderr
deleted file mode 100644
index 57a498694b7..00000000000
--- a/src/test/ui/recursion/issue-95134.stderr
+++ /dev/null
@@ -1,7 +0,0 @@
-error[E0275]: overflow evaluating the requirement `<EmptyWriter as ExampleWriter>::Error`
-   |
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95134`)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
index 5611b5f4ece..06699b947be 100644
--- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
+++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
@@ -7,6 +7,12 @@ LL |     let _ = dbg!(a);
    |             ------- value moved here
 LL |     let _ = dbg!(a);
    |                  ^ value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+  --> $SRC_DIR/std/src/macros.rs:LL:COL
+   |
+LL |             ref tmp => {
+   |             +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/stats/hir-stats.rs b/src/test/ui/stats/hir-stats.rs
index a24b3ada57e..0b89d0b160b 100644
--- a/src/test/ui/stats/hir-stats.rs
+++ b/src/test/ui/stats/hir-stats.rs
@@ -1,6 +1,7 @@
 // check-pass
 // compile-flags: -Zhir-stats
 // only-x86_64
+// ignore-stage1  FIXME: remove after next bootstrap bump
 
 // The aim here is to include at least one of every different type of top-level
 // AST/HIR node reported by `-Zhir-stats`.
diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr
index 297245f0198..012bc848d4b 100644
--- a/src/test/ui/stats/hir-stats.stderr
+++ b/src/test/ui/stats/hir-stats.stderr
@@ -2,12 +2,12 @@ ast-stats-1 PRE EXPANSION AST STATS
 ast-stats-1 Name                Accumulated Size         Count     Item Size
 ast-stats-1 ----------------------------------------------------------------
 ast-stats-1 ExprField                 48 ( 0.6%)             1            48
+ast-stats-1 GenericArgs               56 ( 0.8%)             1            56
+ast-stats-1 - AngleBracketed            56 ( 0.8%)             1
 ast-stats-1 Crate                     56 ( 0.8%)             1            56
 ast-stats-1 Attribute                 64 ( 0.9%)             2            32
 ast-stats-1 - Normal                    32 ( 0.4%)             1
 ast-stats-1 - DocComment                32 ( 0.4%)             1
-ast-stats-1 GenericArgs               64 ( 0.9%)             1            64
-ast-stats-1 - AngleBracketed            64 ( 0.9%)             1
 ast-stats-1 Local                     72 ( 1.0%)             1            72
 ast-stats-1 WherePredicate            72 ( 1.0%)             1            72
 ast-stats-1 - BoundPredicate            72 ( 1.0%)             1
@@ -53,15 +53,15 @@ ast-stats-1 - Impl                     184 ( 2.5%)             1
 ast-stats-1 - Fn                       368 ( 5.0%)             2
 ast-stats-1 - Use                      552 ( 7.4%)             3
 ast-stats-1 ----------------------------------------------------------------
-ast-stats-1 Total                  7_424
+ast-stats-1 Total                  7_416
 ast-stats-1
 ast-stats-2 POST EXPANSION AST STATS
 ast-stats-2 Name                Accumulated Size         Count     Item Size
 ast-stats-2 ----------------------------------------------------------------
 ast-stats-2 ExprField                 48 ( 0.6%)             1            48
+ast-stats-2 GenericArgs               56 ( 0.7%)             1            56
+ast-stats-2 - AngleBracketed            56 ( 0.7%)             1
 ast-stats-2 Crate                     56 ( 0.7%)             1            56
-ast-stats-2 GenericArgs               64 ( 0.8%)             1            64
-ast-stats-2 - AngleBracketed            64 ( 0.8%)             1
 ast-stats-2 Local                     72 ( 0.9%)             1            72
 ast-stats-2 WherePredicate            72 ( 0.9%)             1            72
 ast-stats-2 - BoundPredicate            72 ( 0.9%)             1
@@ -80,9 +80,9 @@ ast-stats-2 - Expr                      96 ( 1.2%)             3
 ast-stats-2 Param                    160 ( 2.0%)             4            40
 ast-stats-2 FnDecl                   200 ( 2.5%)             5            40
 ast-stats-2 Variant                  240 ( 3.0%)             2           120
-ast-stats-2 GenericBound             288 ( 3.5%)             4            72
-ast-stats-2 - Trait                    288 ( 3.5%)             4
-ast-stats-2 Block                    288 ( 3.5%)             6            48
+ast-stats-2 GenericBound             288 ( 3.6%)             4            72
+ast-stats-2 - Trait                    288 ( 3.6%)             4
+ast-stats-2 Block                    288 ( 3.6%)             6            48
 ast-stats-2 AssocItem                416 ( 5.1%)             4           104
 ast-stats-2 - Type                     208 ( 2.6%)             2
 ast-stats-2 - Fn                       208 ( 2.6%)             2
@@ -104,7 +104,7 @@ ast-stats-2 - Rptr                      64 ( 0.8%)             1
 ast-stats-2 - Ptr                       64 ( 0.8%)             1
 ast-stats-2 - ImplicitSelf             128 ( 1.6%)             2
 ast-stats-2 - Path                     640 ( 7.9%)            10
-ast-stats-2 Item                   2_024 (24.9%)            11           184
+ast-stats-2 Item                   2_024 (25.0%)            11           184
 ast-stats-2 - Trait                    184 ( 2.3%)             1
 ast-stats-2 - Enum                     184 ( 2.3%)             1
 ast-stats-2 - ExternCrate              184 ( 2.3%)             1
@@ -113,7 +113,7 @@ ast-stats-2 - Impl                     184 ( 2.3%)             1
 ast-stats-2 - Fn                       368 ( 4.5%)             2
 ast-stats-2 - Use                      736 ( 9.1%)             4
 ast-stats-2 ----------------------------------------------------------------
-ast-stats-2 Total                  8_120
+ast-stats-2 Total                  8_112
 ast-stats-2
 hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
diff --git a/src/test/ui/structs-enums/type-sizes.rs b/src/test/ui/structs-enums/type-sizes.rs
index 7a23f13630a..63e2f3150c0 100644
--- a/src/test/ui/structs-enums/type-sizes.rs
+++ b/src/test/ui/structs-enums/type-sizes.rs
@@ -3,6 +3,7 @@
 #![allow(non_camel_case_types)]
 #![allow(dead_code)]
 #![feature(never_type)]
+#![feature(pointer_is_aligned)]
 
 use std::mem::size_of;
 use std::num::NonZeroU8;
@@ -168,6 +169,18 @@ pub enum EnumManyVariant<X> {
     _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF,
 }
 
+struct Reorder4 {
+    a: u32,
+    b: u8,
+    ary: [u8; 4],
+}
+
+struct Reorder2 {
+    a: u16,
+    b: u8,
+    ary: [u8; 6],
+}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -249,4 +262,12 @@ pub fn main() {
     assert_eq!(size_of::<EnumManyVariant<Option<NicheU16>>>(), 4);
     assert_eq!(size_of::<EnumManyVariant<Option2<NicheU16,u8>>>(), 6);
     assert_eq!(size_of::<EnumManyVariant<Option<(NicheU16,u8)>>>(), 6);
+
+
+    let v = Reorder4 {a: 0, b: 0, ary: [0; 4]};
+    assert_eq!(size_of::<Reorder4>(), 12);
+    assert!((&v.ary).as_ptr().is_aligned_to(4), "[u8; 4] should group with align-4 fields");
+    let v = Reorder2 {a: 0, b: 0, ary: [0; 6]};
+    assert_eq!(size_of::<Reorder2>(), 10);
+    assert!((&v.ary).as_ptr().is_aligned_to(2), "[u8; 6] should group with align-2 fields");
 }
diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr
index 1059e3d1525..0cc8994fe1f 100644
--- a/src/test/ui/suggestions/borrow-for-loop-head.stderr
+++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr
@@ -12,6 +12,7 @@ error[E0382]: use of moved value: `a`
 LL |     let a = vec![1, 2, 3];
    |         - move occurs because `a` has type `Vec<i32>`, which does not implement the `Copy` trait
 LL |     for i in &a {
+   |     ----------- inside of this loop
 LL |         for j in a {
    |                  ^ `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
    |
diff --git a/src/test/ui/suggestions/ref-pattern-binding.fixed b/src/test/ui/suggestions/ref-pattern-binding.fixed
new file mode 100644
index 00000000000..c36040eeca3
--- /dev/null
+++ b/src/test/ui/suggestions/ref-pattern-binding.fixed
@@ -0,0 +1,19 @@
+// run-rustfix
+#![allow(unused)]
+
+struct S {
+    f: String,
+}
+
+fn main() {
+    let ref _moved @ ref _from = String::from("foo"); //~ ERROR
+    let ref _moved @ ref _from = String::from("foo"); //~ ERROR
+    let ref _moved @ ref _from = String::from("foo"); //~ ERROR
+    //~^ ERROR
+    let ref _moved @ ref _from = String::from("foo"); // ok
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR
+    //~^ ERROR
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; // ok
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR
+}
diff --git a/src/test/ui/suggestions/ref-pattern-binding.rs b/src/test/ui/suggestions/ref-pattern-binding.rs
new file mode 100644
index 00000000000..c0d4feb0330
--- /dev/null
+++ b/src/test/ui/suggestions/ref-pattern-binding.rs
@@ -0,0 +1,19 @@
+// run-rustfix
+#![allow(unused)]
+
+struct S {
+    f: String,
+}
+
+fn main() {
+    let _moved @ _from = String::from("foo"); //~ ERROR
+    let _moved @ ref _from = String::from("foo"); //~ ERROR
+    let ref _moved @ _from = String::from("foo"); //~ ERROR
+    //~^ ERROR
+    let ref _moved @ ref _from = String::from("foo"); // ok
+    let _moved @ S { f } = S { f: String::from("foo") }; //~ ERROR
+    let ref _moved @ S { f } = S { f: String::from("foo") }; //~ ERROR
+    //~^ ERROR
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; // ok
+    let _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR
+}
diff --git a/src/test/ui/suggestions/ref-pattern-binding.stderr b/src/test/ui/suggestions/ref-pattern-binding.stderr
new file mode 100644
index 00000000000..10447ba7089
--- /dev/null
+++ b/src/test/ui/suggestions/ref-pattern-binding.stderr
@@ -0,0 +1,107 @@
+error: borrow of moved value
+  --> $DIR/ref-pattern-binding.rs:10:9
+   |
+LL |     let _moved @ ref _from = String::from("foo");
+   |         ------^^^---------
+   |         |        |
+   |         |        value borrowed here after move
+   |         value moved into `_moved` here
+   |         move occurs because `_moved` has type `String` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ ref _from = String::from("foo");
+   |         +++
+
+error: cannot move out of value because it is borrowed
+  --> $DIR/ref-pattern-binding.rs:11:9
+   |
+LL |     let ref _moved @ _from = String::from("foo");
+   |         ----------^^^-----
+   |         |            |
+   |         |            value moved into `_from` here
+   |         value borrowed, by `_moved`, here
+
+error: cannot move out of value because it is borrowed
+  --> $DIR/ref-pattern-binding.rs:15:9
+   |
+LL |     let ref _moved @ S { f } = S { f: String::from("foo") };
+   |         ----------^^^^^^^-^^
+   |         |                |
+   |         |                value moved into `f` here
+   |         value borrowed, by `_moved`, here
+
+error: borrow of moved value
+  --> $DIR/ref-pattern-binding.rs:18:9
+   |
+LL |     let _moved @ S { ref f } = S { f: String::from("foo") };
+   |         ------^^^^^^^-----^^
+   |         |            |
+   |         |            value borrowed here after move
+   |         value moved into `_moved` here
+   |         move occurs because `_moved` has type `S` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ S { ref f } = S { f: String::from("foo") };
+   |         +++
+
+error[E0382]: use of moved value
+  --> $DIR/ref-pattern-binding.rs:9:9
+   |
+LL |     let _moved @ _from = String::from("foo");
+   |         ^^^^^^   -----   ------------------- move occurs because value has type `String`, which does not implement the `Copy` trait
+   |         |        |
+   |         |        value moved here
+   |         value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ ref _from = String::from("foo");
+   |         +++          +++
+
+error[E0382]: borrow of moved value
+  --> $DIR/ref-pattern-binding.rs:11:9
+   |
+LL |     let ref _moved @ _from = String::from("foo");
+   |         ^^^^^^^^^^   -----   ------------------- move occurs because value has type `String`, which does not implement the `Copy` trait
+   |         |            |
+   |         |            value moved here
+   |         value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ ref _from = String::from("foo");
+   |                      +++
+
+error[E0382]: use of partially moved value
+  --> $DIR/ref-pattern-binding.rs:14:9
+   |
+LL |     let _moved @ S { f } = S { f: String::from("foo") };
+   |         ^^^^^^       - value partially moved here
+   |         |
+   |         value used here after partial move
+   |
+   = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ S { ref f } = S { f: String::from("foo") };
+   |         +++              +++
+
+error[E0382]: borrow of partially moved value
+  --> $DIR/ref-pattern-binding.rs:15:9
+   |
+LL |     let ref _moved @ S { f } = S { f: String::from("foo") };
+   |         ^^^^^^^^^^       - value partially moved here
+   |         |
+   |         value borrowed here after partial move
+   |
+   = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ S { ref f } = S { f: String::from("foo") };
+   |                          +++
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/track-diagnostics/track2.stderr b/src/test/ui/track-diagnostics/track2.stderr
index 38a621da816..fe13e5ef3f5 100644
--- a/src/test/ui/track-diagnostics/track2.stderr
+++ b/src/test/ui/track-diagnostics/track2.stderr
@@ -7,6 +7,11 @@ LL |     let _moved @ _from = String::from("foo");
    |         |        value moved here
    |         value used here after move
 -Ztrack-diagnostics: created at compiler/rustc_borrowck/src/borrowck_errors.rs:LL:CC
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ ref _from = String::from("foo");
+   |         +++          +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/predicate_can_apply-hang.rs b/src/test/ui/traits/predicate_can_apply-hang.rs
new file mode 100644
index 00000000000..5f01645da52
--- /dev/null
+++ b/src/test/ui/traits/predicate_can_apply-hang.rs
@@ -0,0 +1,6 @@
+fn f<B>(x: Vec<[[[B; 1]; 1]; 1]>) -> impl PartialEq<B> {
+    //~^ ERROR can't compare `Vec<[[[B; 1]; 1]; 1]>` with `B`
+    x
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/predicate_can_apply-hang.stderr b/src/test/ui/traits/predicate_can_apply-hang.stderr
new file mode 100644
index 00000000000..49fe63b412a
--- /dev/null
+++ b/src/test/ui/traits/predicate_can_apply-hang.stderr
@@ -0,0 +1,21 @@
+error[E0277]: can't compare `Vec<[[[B; 1]; 1]; 1]>` with `B`
+  --> $DIR/predicate_can_apply-hang.rs:1:38
+   |
+LL | fn f<B>(x: Vec<[[[B; 1]; 1]; 1]>) -> impl PartialEq<B> {
+   |                                      ^^^^^^^^^^^^^^^^^ no implementation for `Vec<[[[B; 1]; 1]; 1]> == B`
+LL |
+LL |     x
+   |     - return type was inferred to be `Vec<[[[B; 1]; 1]; 1]>` here
+   |
+   = help: the trait `PartialEq<B>` is not implemented for `Vec<[[[B; 1]; 1]; 1]>`
+   = help: the following other types implement trait `PartialEq<Rhs>`:
+             <Vec<T, A1> as PartialEq<Vec<U, A2>>>
+             <Vec<T, A> as PartialEq<&[U; N]>>
+             <Vec<T, A> as PartialEq<&[U]>>
+             <Vec<T, A> as PartialEq<&mut [U]>>
+             <Vec<T, A> as PartialEq<[U; N]>>
+             <Vec<T, A> as PartialEq<[U]>>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs
index 5f5a2574bab..d624187561e 100644
--- a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs
+++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs
@@ -7,7 +7,11 @@ use core::ops::Deref;
 // issue 89190
 trait A {}
 trait B: A {}
+
 impl<'a> Deref for dyn 'a + B {
+    //~^ ERROR `(dyn B + 'a)` implements `Deref` with supertrait `A` as target
+    //~| WARN this was previously accepted by the compiler but is being phased out;
+
     type Target = dyn A;
     fn deref(&self) -> &Self::Target {
         todo!()
@@ -18,8 +22,6 @@ fn take_a(_: &dyn A) {}
 
 fn whoops(b: &dyn B) {
     take_a(b)
-    //~^ ERROR `dyn B` implements `Deref` with supertrait `A` as output
-    //~^^ WARN this was previously accepted by the compiler but is being phased out;
 }
 
 fn main() {}
diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr
index 41381a3ffd1..4533b116342 100644
--- a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr
+++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr
@@ -1,8 +1,11 @@
-error: `dyn B` implements `Deref` with supertrait `A` as output
-  --> $DIR/migrate-lint-deny.rs:20:12
+error: `(dyn B + 'a)` implements `Deref` with supertrait `A` as target
+  --> $DIR/migrate-lint-deny.rs:11:1
    |
-LL |     take_a(b)
-   |            ^
+LL | impl<'a> Deref for dyn 'a + B {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     type Target = dyn A;
+   |     -------------------- target type is set here
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
index c9f2a3ed9f4..f738b03eed6 100644
--- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
+++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
@@ -23,6 +23,10 @@ LL |         println!("{}", x);
    |                        ^ value borrowed here after move
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |             ::std::mem::drop(x.clone());
+   |                               ++++++++
 
 error[E0506]: cannot assign to `i` because it is borrowed
   --> $DIR/try-block-maybe-bad-lifetime.rs:40:9
diff --git a/src/test/ui/typeck/hang-in-overflow.rs b/src/test/ui/typeck/hang-in-overflow.rs
new file mode 100644
index 00000000000..a8330c9b65c
--- /dev/null
+++ b/src/test/ui/typeck/hang-in-overflow.rs
@@ -0,0 +1,19 @@
+// normalize-stderr-test "the requirement `.*`" -> "the requirement `...`"
+// normalize-stderr-test "required for `.*` to implement `.*`" -> "required for `...` to implement `...`"
+// normalize-stderr-test: ".*the full type name has been written to.*\n" -> ""
+
+// Currently this fatally aborts instead of hanging.
+// Make sure at least that this doesn't turn into a hang.
+
+fn f() {
+    foo::<_>();
+    //~^ ERROR overflow evaluating the requirement
+}
+
+fn foo<B>()
+where
+    Vec<[[[B; 1]; 1]; 1]>: PartialEq<B>,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/hang-in-overflow.stderr b/src/test/ui/typeck/hang-in-overflow.stderr
new file mode 100644
index 00000000000..7a7b85b19b4
--- /dev/null
+++ b/src/test/ui/typeck/hang-in-overflow.stderr
@@ -0,0 +1,22 @@
+error[E0275]: overflow evaluating the requirement `...`
+  --> $DIR/hang-in-overflow.rs:9:5
+   |
+LL |     foo::<_>();
+   |     ^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hang_in_overflow`)
+   = note: required for `...` to implement `...`
+   = note: 127 redundant requirements hidden
+   = note: required for `...` to implement `...`
+note: required by a bound in `foo`
+  --> $DIR/hang-in-overflow.rs:15:28
+   |
+LL | fn foo<B>()
+   |    --- required by a bound in this
+LL | where
+LL |     Vec<[[[B; 1]; 1]; 1]>: PartialEq<B>,
+   |                            ^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr
index 53050cf539e..6381ae874ba 100644
--- a/src/test/ui/union/union-move.mirunsafeck.stderr
+++ b/src/test/ui/union/union-move.mirunsafeck.stderr
@@ -8,6 +8,14 @@ LL |         move_out(x.f1_nocopy);
    |                  ----------- value moved here
 LL |         move_out(x.f2_nocopy);
    |                  ^^^^^^^^^^^ value used here after move
+   |
+note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary
+  --> $DIR/union-move.rs:10:19
+   |
+LL | fn move_out<T>(x: T) {}
+   |    --------       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0382]: use of moved value: `x`
   --> $DIR/union-move.rs:45:18
@@ -19,6 +27,14 @@ LL |         move_out(x.f2_nocopy);
    |                  ----------- value moved here
 LL |         move_out(x.f3_copy);
    |                  ^^^^^^^^^ value used here after move
+   |
+note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary
+  --> $DIR/union-move.rs:10:19
+   |
+LL | fn move_out<T>(x: T) {}
+   |    --------       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
   --> $DIR/union-move.rs:52:18
diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr
index 53050cf539e..6381ae874ba 100644
--- a/src/test/ui/union/union-move.thirunsafeck.stderr
+++ b/src/test/ui/union/union-move.thirunsafeck.stderr
@@ -8,6 +8,14 @@ LL |         move_out(x.f1_nocopy);
    |                  ----------- value moved here
 LL |         move_out(x.f2_nocopy);
    |                  ^^^^^^^^^^^ value used here after move
+   |
+note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary
+  --> $DIR/union-move.rs:10:19
+   |
+LL | fn move_out<T>(x: T) {}
+   |    --------       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0382]: use of moved value: `x`
   --> $DIR/union-move.rs:45:18
@@ -19,6 +27,14 @@ LL |         move_out(x.f2_nocopy);
    |                  ----------- value moved here
 LL |         move_out(x.f3_copy);
    |                  ^^^^^^^^^ value used here after move
+   |
+note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary
+  --> $DIR/union-move.rs:10:19
+   |
+LL | fn move_out<T>(x: T) {}
+   |    --------       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
   --> $DIR/union-move.rs:52:18
diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr
index 65d866c716e..d52a92b8888 100644
--- a/src/test/ui/unop-move-semantics.stderr
+++ b/src/test/ui/unop-move-semantics.stderr
@@ -14,6 +14,10 @@ note: calling this operator moves the left-hand side
    |
 LL |     fn not(self) -> Self::Output;
    |            ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     !x.clone();
+   |       ++++++++
 help: consider further restricting this bound
    |
 LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) {
diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr
index 28ae1c0688c..d8bffd4f9cf 100644
--- a/src/test/ui/unsized-locals/borrow-after-move.stderr
+++ b/src/test/ui/unsized-locals/borrow-after-move.stderr
@@ -28,6 +28,14 @@ LL |         drop_unsized(y);
 ...
 LL |         println!("{}", &y);
    |                        ^^ value borrowed here after move
+   |
+note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrow-after-move.rs:14:31
+   |
+LL | fn drop_unsized<T: ?Sized>(_: T) {}
+   |    ------------               ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/borrow-after-move.rs:31:24
@@ -66,6 +74,11 @@ LL |         x.foo();
    |         - value moved here
 LL |         println!("{}", &x);
    |                        ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         x.clone().foo();
+   |          ++++++++
 
 error: aborting due to 5 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr
index dfae6cc75d9..71534818141 100644
--- a/src/test/ui/unsized-locals/double-move.stderr
+++ b/src/test/ui/unsized-locals/double-move.stderr
@@ -16,6 +16,14 @@ LL |         drop_unsized(y);
    |                      - value moved here
 LL |         drop_unsized(y);
    |                      ^ value used here after move
+   |
+note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary
+  --> $DIR/double-move.rs:14:31
+   |
+LL | fn drop_unsized<T: ?Sized>(_: T) {}
+   |    ------------               ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0382]: use of moved value: `x`
   --> $DIR/double-move.rs:27:22
diff --git a/src/test/ui/use/use-after-move-based-on-type.stderr b/src/test/ui/use/use-after-move-based-on-type.stderr
index 445f14d65e3..7b4d2454994 100644
--- a/src/test/ui/use/use-after-move-based-on-type.stderr
+++ b/src/test/ui/use/use-after-move-based-on-type.stderr
@@ -9,6 +9,10 @@ LL |     println!("{}", x);
    |                    ^ value borrowed here after move
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = x.clone();
+   |               ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr
index 26804216d9d..dfa0c04836e 100644
--- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr
+++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr
@@ -9,6 +9,14 @@ LL |     l.push(n);
 LL |
 LL |     let x = n.to_string();
    |             ^^^^^^^^^^^^^ value borrowed here after move
+   |
+note: consider changing this parameter type in method `push` to borrow instead if owning the value isn't necessary
+  --> $DIR/use-after-move-implicity-coerced-object.rs:17:27
+   |
+LL |     fn push(&mut self, n: Box<dyn ToString + 'static>) {
+   |        ----               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this parameter takes ownership of the value
+   |        |
+   |        in this method
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index 06a39c5997e..b4210d87510 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_associated_type, implements_trait, is_copy};
+use clippy_utils::ty::{implements_trait, is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
         && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id)
         && cx.tcx.trait_of_item(method_id) == Some(iter_id)
         && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv)
-        && let Some(iter_assoc_ty) = get_associated_type(cx, cloned_recv_ty, iter_id, "Item")
+        && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item")
         && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty))
     {
         if needs_into_iter
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 4eb579af7a1..52a4ff7d1ae 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::ForLoop;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
 use clippy_utils::{fn_def_id, get_parent_expr};
 use rustc_errors::Applicability;
 use rustc_hir::{def_id::DefId, Expr, ExprKind};
@@ -54,7 +54,7 @@ pub fn check_for_loop_iter(
                 if let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator);
                 let collection_ty = cx.typeck_results().expr_ty(collection);
                 if implements_trait(cx, collection_ty, into_iterator_trait_id, &[]);
-                if let Some(into_iter_item_ty) = get_associated_type(cx, collection_ty, into_iterator_trait_id, "Item");
+                if let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item");
 
                 if iter_item_ty == into_iter_item_ty;
                 if let Some(collection_snippet) = snippet_opt(cx, collection.span);
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 375ebc903b4..8b000cd754c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -2,9 +2,11 @@ use super::implicit_clone::is_clone_like;
 use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
 use clippy_utils::visitors::find_all_ret_expressions;
-use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
+use clippy_utils::{
+    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty,
+};
 use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
@@ -18,7 +20,9 @@ use rustc_middle::ty::EarlyBinder;
 use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
 use rustc_semver::RustcVersion;
 use rustc_span::{sym, Symbol};
-use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use rustc_trait_selection::traits::{
+    query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause,
+};
 use std::cmp::max;
 
 use super::UNNECESSARY_TO_OWNED;
@@ -146,7 +150,7 @@ fn check_addr_of_expr(
             if_chain! {
                 if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
                 if implements_trait(cx, receiver_ty, deref_trait_id, &[]);
-                if get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(target_ty);
+                if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty);
                 then {
                     if n_receiver_refs > 0 {
                         span_lint_and_sugg(
@@ -341,13 +345,13 @@ fn get_input_traits_and_projections<'tcx>(
                 if trait_predicate.trait_ref.self_ty() == input {
                     trait_predicates.push(trait_predicate);
                 }
-            },
+            }
             PredicateKind::Projection(projection_predicate) => {
                 if projection_predicate.projection_ty.self_ty() == input {
                     projection_predicates.push(projection_predicate);
                 }
-            },
-            _ => {},
+            }
+            _ => {}
         }
     }
     (trait_predicates, projection_predicates)
@@ -462,7 +466,12 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
 
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
-fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
+fn is_to_owned_like<'a>(
+    cx: &LateContext<'a>,
+    call_expr: &Expr<'a>,
+    method_name: Symbol,
+    method_def_id: DefId,
+) -> bool {
     is_clone_like(cx, method_name.as_str(), method_def_id)
         || is_cow_into_owned(cx, method_name, method_def_id)
         || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
@@ -490,7 +499,7 @@ fn is_to_string_on_string_like<'a>(
         && let GenericArgKind::Type(ty) = generic_arg.unpack()
         && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
         && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
-        && (get_associated_type(cx, ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) ||
+        && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) ||
             implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) {
             true
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 78e83880e1a..e111c7d2291 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -582,7 +582,7 @@ fn ident_difference_expr_with_base_location(
         | (Block(_, _), Block(_, _))
         | (Closure(_), Closure(_))
         | (Match(_, _), Match(_, _))
-        | (Loop(_, _), Loop(_, _))
+        | (Loop(_, _, _), Loop(_, _, _))
         | (ForLoop(_, _, _, _), ForLoop(_, _, _, _))
         | (While(_, _, _), While(_, _, _))
         | (If(_, _, _), If(_, _, _))
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 5c595f74eff..6bcf0bbd7eb 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -171,7 +171,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => {
             eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt)
         },
-        (Loop(lt, ll), Loop(rt, rl)) => eq_label(ll, rl) && eq_block(lt, rt),
+        (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt),
         (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
         (TryBlock(l), TryBlock(r)) => eq_block(l, r),
         (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 1b65b701409..8284dc5c28c 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -117,24 +117,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
 pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     cx.tcx
         .get_diagnostic_item(sym::Iterator)
-        .and_then(|iter_did| get_associated_type(cx, ty, iter_did, "Item"))
-}
-
-/// Returns the associated type `name` for `ty` as an implementation of `trait_id`.
-/// Do not invoke without first verifying that the type implements the trait.
-pub fn get_associated_type<'tcx>(
-    cx: &LateContext<'tcx>,
-    ty: Ty<'tcx>,
-    trait_id: DefId,
-    name: &str,
-) -> Option<Ty<'tcx>> {
-    cx.tcx
-        .associated_items(trait_id)
-        .find_by_name_and_kind(cx.tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
-        .and_then(|assoc| {
-            let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, []));
-            cx.tcx.try_normalize_erasing_regions(cx.param_env, proj).ok()
-        })
+        .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item"))
 }
 
 /// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index d5611082f01..414e767690b 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -660,7 +660,7 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow<
         ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
             Some(ControlFlow::new_for(pat, cond, block, label, expr.span))
         }
-        ast::ExprKind::Loop(ref block, label) => {
+        ast::ExprKind::Loop(ref block, label, _) => {
             Some(ControlFlow::new_loop(block, label, expr.span))
         }
         ast::ExprKind::While(ref cond, ref block, label) => {