diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 54bd25d647130..28072f153a479 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/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 4e1dcb2842f67..a5b24c403dd37 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 5c69e53521275..c528118be0808 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/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 3ab42497d6d4f..f33089a2545b1 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -134,12 +134,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         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::Loop(ref body, opt_label, span) => self.with_loop_scope(e.id, |this| {
                     hir::ExprKind::Loop(
                         this.lower_block(body, false),
                         this.lower_label(opt_label),
                         hir::LoopSource::Loop,
-                        DUMMY_SP,
+                        this.lower_span(span),
                     )
                 }),
                 ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 1da40d2302e12..4b37fa027f53b 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 8f1ae594a9247..d79d40cae548a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -7,7 +7,7 @@ use rustc_errors::{
 };
 use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
-use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
+use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::mir::tcx::PlaceTy;
@@ -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(hir::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,28 @@ 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),
+                ty::List::empty(),
+                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());
@@ -601,7 +766,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         else { return; };
         // Try to find predicates on *generic params* that would allow copying `ty`
         let infcx = tcx.infer_ctxt().build();
-        let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
+        let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
         let cause = ObligationCause::new(
             span,
             self.mir_hir_id(),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 4c3216d98783b..c500cbc49e4a3 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_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 94d5103286609..b2702eafd33bd 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -2,9 +2,8 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRe
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_infer::traits::PredicateObligations;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::TypeRelation;
-use rustc_middle::ty::{self, Const, Ty};
+use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::Fallible;
 
@@ -141,13 +140,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
         );
     }
 
-    // We don't have to worry about the equality of consts during borrow checking
-    // as consts always have a static lifetime.
-    // FIXME(oli-obk): is this really true? We can at least have HKL and with
-    // inline consts we may have further lifetimes that may be unsound to treat as
-    // 'static.
-    fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {}
-
     fn normalization() -> NormalizationStrategy {
         NormalizationStrategy::Eager
     }
@@ -156,10 +148,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
         true
     }
 
-    fn register_opaque_type_obligations(
-        &mut self,
-        obligations: PredicateObligations<'tcx>,
-    ) -> Result<(), TypeError<'tcx>> {
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.type_checker
             .fully_perform_op(
                 self.locations,
@@ -172,6 +161,5 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
                 },
             )
             .unwrap();
-        Ok(())
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index 220b7a8ad0fcd..9f42a0c2d585c 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_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 2d4afd0dc356b..c62c665158779 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -1,7 +1,7 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
 use hir::def_id::LocalDefId;
-use hir::ConstContext;
+use hir::{ConstContext, LangItem};
 use rustc_errors::{
     error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
 };
@@ -304,7 +304,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                     err.span_note(deref_target, "deref defined here");
                 }
 
-                diag_trait(&mut err, self_ty, tcx.lang_items().deref_trait().unwrap());
+                diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
                 err
             }
             _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => {
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs
index 5446ccb1a4730..b38a6c551388e 100644
--- a/compiler/rustc_const_eval/src/util/call_kind.rs
+++ b/compiler/rustc_const_eval/src/util/call_kind.rs
@@ -3,7 +3,7 @@
 //! context.
 
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items;
+use rustc_hir::{lang_items, LangItem};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt};
 use rustc_span::symbol::Ident;
@@ -26,7 +26,7 @@ impl CallDesugaringKind {
         match self {
             Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(),
             Self::QuestionBranch | Self::TryBlockFromOutput => {
-                tcx.lang_items().try_trait().unwrap()
+                tcx.require_lang_item(LangItem::Try, None)
             }
             Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
         }
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index a74016e220e62..e0b465bab16d9 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -244,6 +244,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
         self.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.param_env
     }
@@ -256,6 +260,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index b2c9e7389b047..11661215ae1cc 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -114,7 +114,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                     traits::ObligationCause::dummy_with_span(field_ty_span),
                     param_env,
                     ty,
-                    tcx.lang_items().copy_trait().unwrap(),
+                    tcx.require_lang_item(LangItem::Copy, Some(span)),
                 ) {
                     let error_predicate = error.obligation.predicate;
                     // Only note if it's not the root obligation, otherwise it's trivial and
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 71c932d747bca..d66b6585fb6f7 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{struct_span_err, DelayDm};
 use rustc_errors::{Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IgnoreRegions;
 use rustc_middle::ty::{
@@ -47,58 +46,6 @@ fn do_orphan_check_impl<'tcx>(
     let sp = tcx.def_span(def_id);
     let tr = impl_.of_trait.as_ref().unwrap();
 
-    // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
-    // and #84660 where it would otherwise allow unsoundness.
-    if trait_ref.has_opaque_types() {
-        trace!("{:#?}", item);
-        // First we find the opaque type in question.
-        for ty in trait_ref.substs {
-            for ty in ty.walk() {
-                let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
-                let ty::Opaque(def_id, _) = *ty.kind() else { continue };
-                trace!(?def_id);
-
-                // Then we search for mentions of the opaque type's type alias in the HIR
-                struct SpanFinder<'tcx> {
-                    sp: Span,
-                    def_id: DefId,
-                    tcx: TyCtxt<'tcx>,
-                }
-                impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
-                    #[instrument(level = "trace", skip(self, _id))]
-                    fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
-                        // You can't mention an opaque type directly, so we look for type aliases
-                        if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
-                            // And check if that type alias's type contains the opaque type we're looking for
-                            for arg in self.tcx.type_of(def_id).walk() {
-                                if let GenericArgKind::Type(ty) = arg.unpack() {
-                                    if let ty::Opaque(def_id, _) = *ty.kind() {
-                                        if def_id == self.def_id {
-                                            // Finally we update the span to the mention of the type alias
-                                            self.sp = path.span;
-                                            return;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                        hir::intravisit::walk_path(self, path)
-                    }
-                }
-
-                let mut visitor = SpanFinder { sp, def_id, tcx };
-                hir::intravisit::walk_item(&mut visitor, item);
-                let reported = tcx
-                    .sess
-                    .struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
-                    .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
-                    .emit();
-                return Err(reported);
-            }
-        }
-        span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
-    }
-
     match traits::orphan_check(tcx, item.owner_id.to_def_id()) {
         Ok(()) => {}
         Err(err) => emit_orphan_check_error(
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 55cca0cd2d7b5..bae43138b4d52 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -517,6 +517,7 @@ fn trait_predicate_kind<'tcx>(
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::ConstEvaluatable(..)
         | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 7534482cce9bb..f0381353551c2 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -59,6 +59,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     | ty::PredicateKind::Coerce(..)
                     | ty::PredicateKind::ConstEvaluatable(..)
                     | ty::PredicateKind::ConstEquate(..)
+                    | ty::PredicateKind::Ambiguous
                     | ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
                 }
             }
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 43c7127b0d4c5..3f0d0a76027f4 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;
@@ -1055,9 +1054,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/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 886a3ad755df9..91f65b8c0f21f 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1118,7 +1118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let lhs_deref_ty_is_sized = self
                     .infcx
                     .type_implements_trait(
-                        self.tcx.lang_items().sized_trait().unwrap(),
+                        self.tcx.require_lang_item(LangItem::Sized, None),
                         [lhs_deref_ty],
                         self.param_env,
                     )
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 38499907663e1..c7bfe99aa9a8a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -702,6 +702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // code is looking for a self type of an unresolved
                 // inference variable.
                 | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             },
         )
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 9d75ccad133dd..44c3edf06a883 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -803,6 +803,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 | ty::PredicateKind::TypeOutlives(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             }
         });
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 5ff3779fa1438..2483ab724a4e3 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -81,6 +81,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 .normalize_fn_sig_for_diagnostic
                 .as_ref()
                 .map(|f| f.clone()),
+            intercrate: self.intercrate,
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 34f54328230f4..b4a427a5d419a 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -23,11 +23,10 @@ use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, BoundVar, ToPredicate, Ty, TyCtxt};
 use rustc_span::Span;
 use std::fmt::Debug;
 use std::iter;
@@ -729,10 +728,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
         });
     }
 
-    fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {
-        span_bug!(self.cause.span(), "generic_const_exprs: unreachable `const_equate`");
-    }
-
     fn normalization() -> NormalizationStrategy {
         NormalizationStrategy::Eager
     }
@@ -741,11 +736,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
         true
     }
 
-    fn register_opaque_type_obligations(
-        &mut self,
-        obligations: PredicateObligations<'tcx>,
-    ) -> Result<(), TypeError<'tcx>> {
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.obligations.extend(obligations);
-        Ok(())
     }
 }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index c2552561c42df..eec938cefbb70 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -450,6 +450,15 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
             ty::Binder::dummy(predicate),
         ));
     }
+
+    pub fn mark_ambiguous(&mut self) {
+        self.obligations.push(Obligation::new(
+            self.tcx(),
+            self.trace.cause.clone(),
+            self.param_env,
+            ty::Binder::dummy(ty::PredicateKind::Ambiguous),
+        ));
+    }
 }
 
 struct Generalizer<'cx, 'tcx> {
@@ -521,6 +530,11 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
+
+    fn intercrate(&self) -> bool {
+        self.infcx.intercrate
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.param_env
     }
@@ -533,6 +547,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        span_bug!(self.cause.span, "opaque types are handled in `tys`");
+    }
+
     fn binders<T>(
         &mut self,
         a: ty::Binder<'tcx, T>,
@@ -657,6 +675,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                 // relatable.
                 Ok(t)
             }
+            ty::Opaque(def_id, substs) => {
+                let s = self.relate(substs, substs)?;
+                Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) })
+            }
             _ => relate::super_relate_tys(self, t, t),
         }?;
 
@@ -799,6 +821,11 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
         self.infcx.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.infcx.intercrate);
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.param_env
     }
@@ -811,6 +838,10 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 59728148a84c4..8682f4d3b7aed 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -32,6 +32,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
         self.fields.tcx()
     }
 
+    fn intercrate(&self) -> bool {
+        self.fields.infcx.intercrate
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.fields.param_env
     }
@@ -40,6 +44,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
         self.a_is_expected
     }
 
+    fn mark_ambiguous(&mut self) {
+        self.fields.mark_ambiguous();
+    }
+
     fn relate_item_substs(
         &mut self,
         _item_def_id: DefId,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 613a05e415ff9..0dee3be705474 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2937,6 +2937,11 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
         self.0.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.0.intercrate);
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         // Unused, only for consts which we treat as always equal
         ty::ParamEnv::empty()
@@ -2950,6 +2955,10 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: relate::Relate<'tcx>>(
         &mut self,
         _variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 6ffefcb7a286a..7f27b35a54e4f 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -30,6 +30,11 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
         "Glb"
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.fields.infcx.intercrate);
+        false
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.fields.tcx()
     }
@@ -42,6 +47,10 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
         self.a_is_expected
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!("mark_ambiguous used outside of coherence");
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index d6e56fcb7fd27..97ed4729bd0d9 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -30,6 +30,11 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
         "Lub"
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.fields.infcx.intercrate);
+        false
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.fields.tcx()
     }
@@ -42,6 +47,10 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
         self.a_is_expected
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!("mark_ambiguous used outside of coherence");
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index b9ed6b28c220d..2798477d1815d 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -337,6 +337,26 @@ pub struct InferCtxt<'tcx> {
 
     normalize_fn_sig_for_diagnostic:
         Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
+
+    /// During coherence we have to assume that other crates may add
+    /// additional impls which we currently don't know about.
+    ///
+    /// To deal with this evaluation should be conservative
+    /// and consider the possibility of impls from outside this crate.
+    /// This comes up primarily when resolving ambiguity. Imagine
+    /// there is some trait reference `$0: Bar` where `$0` is an
+    /// inference variable. If `intercrate` is true, then we can never
+    /// say for sure that this reference is not implemented, even if
+    /// there are *no impls at all for `Bar`*, because `$0` could be
+    /// bound to some type that in a downstream crate that implements
+    /// `Bar`.
+    ///
+    /// Outside of coherence we set this to false because we are only
+    /// interested in types that the user could actually have written.
+    /// In other words, we consider `$0: Bar` to be unimplemented if
+    /// there is no type that the user could *actually name* that
+    /// would satisfy it. This avoids crippling inference, basically.
+    pub intercrate: bool,
 }
 
 /// See the `error_reporting` module for more details.
@@ -552,6 +572,8 @@ pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
     defining_use_anchor: DefiningAnchor,
     considering_regions: bool,
+    /// Whether we are in coherence mode.
+    intercrate: bool,
     normalize_fn_sig_for_diagnostic:
         Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
 }
@@ -567,6 +589,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
             defining_use_anchor: DefiningAnchor::Error,
             considering_regions: true,
             normalize_fn_sig_for_diagnostic: None,
+            intercrate: false,
         }
     }
 }
@@ -583,6 +606,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         self
     }
 
+    pub fn intercrate(mut self) -> Self {
+        self.intercrate = true;
+        self
+    }
+
     pub fn ignoring_regions(mut self) -> Self {
         self.considering_regions = false;
         self
@@ -622,6 +650,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             defining_use_anchor,
             considering_regions,
             ref normalize_fn_sig_for_diagnostic,
+            intercrate,
         } = *self;
         InferCtxt {
             tcx,
@@ -641,6 +670,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic
                 .as_ref()
                 .map(|f| f.clone()),
+            intercrate,
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 167a82d4499a1..4f8460955c3de 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -25,7 +25,7 @@ use crate::infer::combine::ConstEquateRelation;
 use crate::infer::InferCtxt;
 use crate::infer::{ConstVarValue, ConstVariableValue};
 use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::traits::PredicateObligation;
+use crate::traits::{Obligation, PredicateObligation};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
@@ -92,11 +92,7 @@ pub trait TypeRelatingDelegate<'tcx> {
         info: ty::VarianceDiagInfo<'tcx>,
     );
 
-    fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
-    fn register_opaque_type_obligations(
-        &mut self,
-        obligations: Vec<PredicateObligation<'tcx>>,
-    ) -> Result<(), TypeError<'tcx>>;
+    fn register_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
 
     /// Creates a new universe index. Used when instantiating placeholders.
     fn create_next_universe(&mut self) -> ty::UniverseIndex;
@@ -419,7 +415,7 @@ where
             .infcx
             .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?
             .obligations;
-        self.delegate.register_opaque_type_obligations(obligations)?;
+        self.delegate.register_obligations(obligations);
         trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
         Ok(a)
     }
@@ -531,6 +527,10 @@ where
         self.infcx.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        self.infcx.intercrate
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.delegate.param_env()
     }
@@ -543,6 +543,17 @@ where
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        let cause = ObligationCause::dummy_with_span(self.delegate.span());
+        let param_env = self.delegate.param_env();
+        self.delegate.register_obligations(vec![Obligation::new(
+            self.tcx(),
+            cause,
+            param_env,
+            ty::Binder::dummy(ty::PredicateKind::Ambiguous),
+        )]);
+    }
+
     #[instrument(skip(self, info), level = "trace", ret)]
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
@@ -800,8 +811,12 @@ impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
 where
     D: TypeRelatingDelegate<'tcx>,
 {
-    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
-        self.delegate.const_equate(a, b);
+    fn const_equate_obligation(&mut self, _a: ty::Const<'tcx>, _b: ty::Const<'tcx>) {
+        // We don't have to worry about the equality of consts during borrow checking
+        // as consts always have a static lifetime.
+        // FIXME(oli-obk): is this really true? We can at least have HKL and with
+        // inline consts we may have further lifetimes that may be unsound to treat as
+        // 'static.
     }
 }
 
@@ -898,6 +913,11 @@ where
         self.infcx.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.infcx.intercrate);
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.delegate.param_env()
     }
@@ -910,6 +930,10 @@ where
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 2d19d1823fdfc..8f7805794513d 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -29,6 +29,7 @@ pub fn explicit_outlives_bounds<'tcx>(
             | ty::PredicateKind::TypeOutlives(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
                 Some(OutlivesBound::RegionSubRegion(r_b, r_a))
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index a5c21f0fb9b50..5d204dd70ed0c 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -136,6 +136,11 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
     fn tag(&self) -> &'static str {
         "Match"
     }
+
+    fn intercrate(&self) -> bool {
+        false
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -146,6 +151,10 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
         true
     } // irrelevant
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index bd3c5780b891b..2c6987cc3f456 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -35,6 +35,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
     fn tag(&self) -> &'static str {
         "Sub"
     }
+
+    fn intercrate(&self) -> bool {
+        self.fields.infcx.intercrate
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.fields.infcx.tcx
     }
@@ -47,6 +52,10 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
         self.a_is_expected
     }
 
+    fn mark_ambiguous(&mut self) {
+        self.fields.mark_ambiguous()
+    }
+
     fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index e12c069dcc1d9..b2a31ac7e6f1a 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -285,6 +285,7 @@ impl<'tcx> Elaborator<'tcx> {
             ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                 // Nothing to elaborate
             }
+            ty::PredicateKind::Ambiguous => {}
         }
     }
 }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 8c779579a4f1d..ada3c3b67fb05 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1659,6 +1659,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     Coerce(..) |
                     ConstEvaluatable(..) |
                     ConstEquate(..) |
+                    Ambiguous |
                     TypeWellFormedFromEnv(..) => continue,
                 };
                 if predicate.is_global() {
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 100a8788763c2..0471890230aa6 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -13,6 +13,7 @@ use rustc_middle::ty::{self, DefIdTree, Ty};
 use rustc_span::symbol::Symbol;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span};
+use std::iter;
 
 declare_lint! {
     /// The `unused_must_use` lint detects unused result of a type flagged as
@@ -113,30 +114,19 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         }
 
         let ty = cx.typeck_results().expr_ty(&expr);
-        let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, expr.span, "", "", 1);
 
-        let mut fn_warned = false;
-        let mut op_warned = false;
-        let maybe_def_id = match expr.kind {
-            hir::ExprKind::Call(ref callee, _) => {
-                match callee.kind {
-                    hir::ExprKind::Path(ref qpath) => {
-                        match cx.qpath_res(qpath, callee.hir_id) {
-                            Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
-                            // `Res::Local` if it was a closure, for which we
-                            // do not currently support must-use linting
-                            _ => None,
-                        }
-                    }
-                    _ => None,
-                }
+        let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span);
+        let type_lint_emitted_or_suppressed = match must_use_result {
+            Some(path) => {
+                emit_must_use_untranslated(cx, &path, "", "", 1);
+                true
             }
-            hir::ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
-            _ => None,
+            None => false,
         };
-        if let Some(def_id) = maybe_def_id {
-            fn_warned = check_must_use_def(cx, def_id, expr.span, "return value of ", "");
-        } else if type_permits_lack_of_use {
+
+        let fn_warned = check_fn_must_use(cx, expr);
+
+        if !fn_warned && type_lint_emitted_or_suppressed {
             // We don't warn about unused unit or uninhabited types.
             // (See https://github.com/rust-lang/rust/issues/43806 for details.)
             return;
@@ -170,6 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
             _ => None,
         };
 
+        let mut op_warned = false;
+
         if let Some(must_use_op) = must_use_op {
             cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| {
                 lint.set_arg("op", must_use_op)
@@ -184,22 +176,64 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
             op_warned = true;
         }
 
-        if !(type_permits_lack_of_use || fn_warned || op_warned) {
+        if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) {
             cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| {
                 lint.set_arg("ty", ty)
             });
         }
 
-        // Returns whether an error has been emitted (and thus another does not need to be later).
-        fn check_must_use_ty<'tcx>(
+        fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+            let maybe_def_id = match expr.kind {
+                hir::ExprKind::Call(ref callee, _) => {
+                    match callee.kind {
+                        hir::ExprKind::Path(ref qpath) => {
+                            match cx.qpath_res(qpath, callee.hir_id) {
+                                Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
+                                // `Res::Local` if it was a closure, for which we
+                                // do not currently support must-use linting
+                                _ => None,
+                            }
+                        }
+                        _ => None,
+                    }
+                }
+                hir::ExprKind::MethodCall(..) => {
+                    cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                }
+                _ => None,
+            };
+            if let Some(def_id) = maybe_def_id {
+                check_must_use_def(cx, def_id, expr.span, "return value of ", "")
+            } else {
+                false
+            }
+        }
+
+        /// A path through a type to a must_use source. Contains useful info for the lint.
+        #[derive(Debug)]
+        enum MustUsePath {
+            /// Suppress must_use checking.
+            Suppressed,
+            /// The root of the normal must_use lint with an optional message.
+            Def(Span, DefId, Option<Symbol>),
+            Boxed(Box<Self>),
+            Opaque(Box<Self>),
+            TraitObject(Box<Self>),
+            TupleElement(Vec<(usize, Self)>),
+            Array(Box<Self>, u64),
+            /// The root of the unused_closures lint.
+            Closure(Span),
+            /// The root of the unused_generators lint.
+            Generator(Span),
+        }
+
+        #[instrument(skip(cx, expr), level = "debug", ret)]
+        fn is_ty_must_use<'tcx>(
             cx: &LateContext<'tcx>,
             ty: Ty<'tcx>,
             expr: &hir::Expr<'_>,
             span: Span,
-            descr_pre: &str,
-            descr_post: &str,
-            plural_len: usize,
-        ) -> bool {
+        ) -> Option<MustUsePath> {
             if ty.is_unit()
                 || !ty.is_inhabited_from(
                     cx.tcx,
@@ -207,87 +241,164 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     cx.param_env,
                 )
             {
-                return true;
+                return Some(MustUsePath::Suppressed);
             }
 
-            let plural_suffix = pluralize!(plural_len);
-
             match *ty.kind() {
                 ty::Adt(..) if ty.is_box() => {
                     let boxed_ty = ty.boxed_ty();
-                    let descr_pre = &format!("{}boxed ", descr_pre);
-                    check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len)
+                    is_ty_must_use(cx, boxed_ty, expr, span)
+                        .map(|inner| MustUsePath::Boxed(Box::new(inner)))
                 }
-                ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post),
+                ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
                 ty::Opaque(def, _) => {
-                    let mut has_emitted = false;
-                    for obligation in elaborate_predicates_with_span(
+                    elaborate_predicates_with_span(
                         cx.tcx,
                         cx.tcx.explicit_item_bounds(def).iter().cloned(),
-                    ) {
+                    )
+                    .filter_map(|obligation| {
                         // We only look at the `DefId`, so it is safe to skip the binder here.
                         if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
                             obligation.predicate.kind().skip_binder()
                         {
                             let def_id = poly_trait_predicate.trait_ref.def_id;
-                            let descr_pre =
-                                &format!("{}implementer{} of ", descr_pre, plural_suffix,);
-                            if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
-                                has_emitted = true;
-                                break;
-                            }
+
+                            is_def_must_use(cx, def_id, span)
+                        } else {
+                            None
                         }
-                    }
-                    has_emitted
+                    })
+                    .map(|inner| MustUsePath::Opaque(Box::new(inner)))
+                    .next()
                 }
-                ty::Dynamic(binder, _, _) => {
-                    let mut has_emitted = false;
-                    for predicate in binder.iter() {
+                ty::Dynamic(binders, _, _) => binders
+                    .iter()
+                    .filter_map(|predicate| {
                         if let ty::ExistentialPredicate::Trait(ref trait_ref) =
                             predicate.skip_binder()
                         {
                             let def_id = trait_ref.def_id;
-                            let descr_post =
-                                &format!(" trait object{}{}", plural_suffix, descr_post,);
-                            if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
-                                has_emitted = true;
-                                break;
-                            }
+                            is_def_must_use(cx, def_id, span)
+                        } else {
+                            None
                         }
-                    }
-                    has_emitted
-                }
-                ty::Tuple(ref tys) => {
-                    let mut has_emitted = false;
-                    let comps = if let hir::ExprKind::Tup(comps) = expr.kind {
-                        debug_assert_eq!(comps.len(), tys.len());
-                        comps
+                        .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
+                    })
+                    .next(),
+                ty::Tuple(tys) => {
+                    let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind {
+                        debug_assert_eq!(elem_exprs.len(), tys.len());
+                        elem_exprs
                     } else {
                         &[]
                     };
-                    for (i, ty) in tys.iter().enumerate() {
-                        let descr_post = &format!(" in tuple element {}", i);
-                        let e = comps.get(i).unwrap_or(expr);
-                        let span = e.span;
-                        if check_must_use_ty(cx, ty, e, span, descr_pre, descr_post, plural_len) {
-                            has_emitted = true;
-                        }
+
+                    // Default to `expr`.
+                    let elem_exprs = elem_exprs.iter().chain(iter::repeat(expr));
+
+                    let nested_must_use = tys
+                        .iter()
+                        .zip(elem_exprs)
+                        .enumerate()
+                        .filter_map(|(i, (ty, expr))| {
+                            is_ty_must_use(cx, ty, expr, expr.span).map(|path| (i, path))
+                        })
+                        .collect::<Vec<_>>();
+
+                    if !nested_must_use.is_empty() {
+                        Some(MustUsePath::TupleElement(nested_must_use))
+                    } else {
+                        None
                     }
-                    has_emitted
                 }
                 ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) {
                     // If the array is empty we don't lint, to avoid false positives
-                    Some(0) | None => false,
+                    Some(0) | None => None,
                     // If the array is definitely non-empty, we can do `#[must_use]` checking.
-                    Some(n) => {
-                        let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix,);
-                        check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, n as usize + 1)
-                    }
+                    Some(len) => is_ty_must_use(cx, ty, expr, span)
+                        .map(|inner| MustUsePath::Array(Box::new(inner), len)),
                 },
-                ty::Closure(..) => {
+                ty::Closure(..) => Some(MustUsePath::Closure(span)),
+                ty::Generator(..) => Some(MustUsePath::Generator(span)),
+                _ => None,
+            }
+        }
+
+        fn is_def_must_use(cx: &LateContext<'_>, def_id: DefId, span: Span) -> Option<MustUsePath> {
+            if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
+                // check for #[must_use = "..."]
+                let reason = attr.value_str();
+                Some(MustUsePath::Def(span, def_id, reason))
+            } else {
+                None
+            }
+        }
+
+        // Returns whether further errors should be suppressed because either a lint has been emitted or the type should be ignored.
+        fn check_must_use_def(
+            cx: &LateContext<'_>,
+            def_id: DefId,
+            span: Span,
+            descr_pre_path: &str,
+            descr_post_path: &str,
+        ) -> bool {
+            is_def_must_use(cx, def_id, span)
+                .map(|must_use_path| {
+                    emit_must_use_untranslated(
+                        cx,
+                        &must_use_path,
+                        descr_pre_path,
+                        descr_post_path,
+                        1,
+                    )
+                })
+                .is_some()
+        }
+
+        #[instrument(skip(cx), level = "debug")]
+        fn emit_must_use_untranslated(
+            cx: &LateContext<'_>,
+            path: &MustUsePath,
+            descr_pre: &str,
+            descr_post: &str,
+            plural_len: usize,
+        ) {
+            let plural_suffix = pluralize!(plural_len);
+
+            match path {
+                MustUsePath::Suppressed => {}
+                MustUsePath::Boxed(path) => {
+                    let descr_pre = &format!("{}boxed ", descr_pre);
+                    emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
+                }
+                MustUsePath::Opaque(path) => {
+                    let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix);
+                    emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
+                }
+                MustUsePath::TraitObject(path) => {
+                    let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post);
+                    emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
+                }
+                MustUsePath::TupleElement(elems) => {
+                    for (index, path) in elems {
+                        let descr_post = &format!(" in tuple element {}", index);
+                        emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
+                    }
+                }
+                MustUsePath::Array(path, len) => {
+                    let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix);
+                    emit_must_use_untranslated(
+                        cx,
+                        path,
+                        descr_pre,
+                        descr_post,
+                        plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
+                    );
+                }
+                MustUsePath::Closure(span) => {
                     cx.struct_span_lint(
                         UNUSED_MUST_USE,
-                        span,
+                        *span,
                         fluent::lint_unused_closure,
                         |lint| {
                             // FIXME(davidtwco): this isn't properly translatable because of the
@@ -298,12 +409,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                                 .note(fluent::note)
                         },
                     );
-                    true
                 }
-                ty::Generator(..) => {
+                MustUsePath::Generator(span) => {
                     cx.struct_span_lint(
                         UNUSED_MUST_USE,
-                        span,
+                        *span,
                         fluent::lint_unused_generator,
                         |lint| {
                             // FIXME(davidtwco): this isn't properly translatable because of the
@@ -314,40 +424,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                                 .note(fluent::note)
                         },
                     );
-                    true
                 }
-                _ => false,
-            }
-        }
-
-        // Returns whether an error has been emitted (and thus another does not need to be later).
-        // FIXME: Args desc_{pre,post}_path could be made lazy by taking Fn() -> &str, but this
-        // would make calling it a big awkward. Could also take String (so args are moved), but
-        // this would still require a copy into the format string, which would only be executed
-        // when needed.
-        fn check_must_use_def(
-            cx: &LateContext<'_>,
-            def_id: DefId,
-            span: Span,
-            descr_pre_path: &str,
-            descr_post_path: &str,
-        ) -> bool {
-            if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
-                cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint_unused_def, |lint| {
-                    // FIXME(davidtwco): this isn't properly translatable because of the pre/post
-                    // strings
-                    lint.set_arg("pre", descr_pre_path);
-                    lint.set_arg("post", descr_post_path);
-                    lint.set_arg("def", cx.tcx.def_path_str(def_id));
-                    // check for #[must_use = "..."]
-                    if let Some(note) = attr.value_str() {
-                        lint.note(note.as_str());
-                    }
-                    lint
-                });
-                true
-            } else {
-                false
+                MustUsePath::Def(span, def_id, reason) => {
+                    cx.struct_span_lint(UNUSED_MUST_USE, *span, fluent::lint_unused_def, |lint| {
+                        // FIXME(davidtwco): this isn't properly translatable because of the pre/post
+                        // strings
+                        lint.set_arg("pre", descr_pre);
+                        lint.set_arg("post", descr_post);
+                        lint.set_arg("def", cx.tcx.def_path_str(*def_id));
+                        if let Some(note) = reason {
+                            lint.note(note.as_str());
+                        }
+                        lint
+                    });
+                }
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
index e6aab30a150de..cd147d7e55813 100644
--- a/compiler/rustc_middle/src/ty/_match.rs
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -36,6 +36,11 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
+
+    fn intercrate(&self) -> bool {
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.param_env
     }
@@ -43,6 +48,10 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
         true
     } // irrelevant
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 0d6c26a582246..273a61c966c72 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -5,6 +5,7 @@ use crate::{mir, ty};
 
 use std::fmt::Write;
 
+use hir::LangItem;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -130,11 +131,14 @@ impl<'tcx> ClosureKind {
     }
 
     pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId {
-        match self {
-            ClosureKind::Fn => tcx.lang_items().fn_once_trait().unwrap(),
-            ClosureKind::FnMut => tcx.lang_items().fn_mut_trait().unwrap(),
-            ClosureKind::FnOnce => tcx.lang_items().fn_trait().unwrap(),
-        }
+        tcx.require_lang_item(
+            match self {
+                ClosureKind::Fn => LangItem::Fn,
+                ClosureKind::FnMut => LangItem::FnMut,
+                ClosureKind::FnOnce => LangItem::FnOnce,
+            },
+            None,
+        )
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 8d6ae14231457..26d30308ed371 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2293,7 +2293,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Given a `ty`, return whether it's an `impl Future<...>`.
     pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool {
         let ty::Opaque(def_id, _) = ty.kind() else { return false };
-        let future_trait = self.lang_items().future_trait().unwrap();
+        let future_trait = self.require_lang_item(LangItem::Future, None);
 
         self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| {
             let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 3be0bc4defc5c..1ee4985cf8de0 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -42,7 +42,6 @@ where
     ClosureSimplifiedType(D),
     GeneratorSimplifiedType(D),
     GeneratorWitnessSimplifiedType(usize),
-    OpaqueSimplifiedType(D),
     FunctionSimplifiedType(usize),
     PlaceholderSimplifiedType,
 }
@@ -127,7 +126,7 @@ pub fn simplify_type<'tcx>(
             TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
             TreatParams::AsInfer => None,
         },
-        ty::Projection(_) => match treat_params {
+        ty::Opaque(..) | ty::Projection(_) => match treat_params {
             // When treating `ty::Param` as a placeholder, projections also
             // don't unify with anything else as long as they are fully normalized.
             //
@@ -138,7 +137,6 @@ pub fn simplify_type<'tcx>(
             }
             TreatParams::AsPlaceholder | TreatParams::AsInfer => None,
         },
-        ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)),
         ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
         ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
     }
@@ -151,8 +149,7 @@ impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> {
             | ForeignSimplifiedType(d)
             | TraitSimplifiedType(d)
             | ClosureSimplifiedType(d)
-            | GeneratorSimplifiedType(d)
-            | OpaqueSimplifiedType(d) => Some(d),
+            | GeneratorSimplifiedType(d) => Some(d),
             _ => None,
         }
     }
@@ -182,7 +179,6 @@ impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> {
             ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)),
             GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)),
             GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
-            OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)),
             FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
             PlaceholderSimplifiedType => PlaceholderSimplifiedType,
         }
@@ -229,7 +225,7 @@ impl DeepRejectCtxt {
         match impl_ty.kind() {
             // Start by checking whether the type in the impl may unify with
             // pretty much everything. Just return `true` in that case.
-            ty::Param(_) | ty::Projection(_) | ty::Error(_) => return true,
+            ty::Param(_) | ty::Projection(_) | ty::Error(_) | ty::Opaque(..) => return true,
             // These types only unify with inference variables or their own
             // variant.
             ty::Bool
@@ -247,8 +243,7 @@ impl DeepRejectCtxt {
             | ty::Never
             | ty::Tuple(..)
             | ty::FnPtr(..)
-            | ty::Foreign(..)
-            | ty::Opaque(..) => {}
+            | ty::Foreign(..) => {}
             ty::FnDef(..)
             | ty::Closure(..)
             | ty::Generator(..)
@@ -328,10 +323,7 @@ impl DeepRejectCtxt {
                 _ => false,
             },
 
-            // Opaque types in impls should be forbidden, but that doesn't
-            // stop compilation. So this match arm should never return true
-            // if compilation succeeds.
-            ty::Opaque(..) => matches!(k, ty::Opaque(..)),
+            ty::Opaque(..) => true,
 
             // Impls cannot contain these types as these cannot be named directly.
             ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false,
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 7201737be657b..ee4b8f91c5487 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -259,6 +259,7 @@ impl FlagComputation {
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 self.add_ty(ty);
             }
+            ty::PredicateKind::Ambiguous => {}
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 3f26d337d4575..0458c4abd3d4c 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -620,6 +620,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Coerce(_)
             | PredicateKind::ConstEvaluatable(_)
             | PredicateKind::ConstEquate(_, _)
+            | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(_) => true,
         }
     }
@@ -702,6 +703,10 @@ pub enum PredicateKind<'tcx> {
     ///
     /// Only used for Chalk.
     TypeWellFormedFromEnv(Ty<'tcx>),
+
+    /// A marker predicate that is always ambiguous.
+    /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
+    Ambiguous,
 }
 
 /// The crate outlives map is computed during typeck and contains the
@@ -1186,6 +1191,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::TypeOutlives(..)
             | PredicateKind::ConstEvaluatable(..)
             | PredicateKind::ConstEquate(..)
+            | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
         }
     }
@@ -1204,6 +1210,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::TypeOutlives(..)
             | PredicateKind::ConstEvaluatable(..)
             | PredicateKind::ConstEquate(..)
+            | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
         }
     }
@@ -1222,6 +1229,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::ClosureKind(..)
             | PredicateKind::ConstEvaluatable(..)
             | PredicateKind::ConstEquate(..)
+            | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
         }
     }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index d828d08805ec3..bddcdd0b693ca 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -11,6 +11,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
 use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
+use rustc_hir::LangItem;
 use rustc_session::config::TrimmedDefPaths;
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
 use rustc_session::Limit;
@@ -889,7 +890,7 @@ pub trait PrettyPrinter<'tcx>:
                                 // Group the return ty with its def id, if we had one.
                                 entry
                                     .return_ty
-                                    .map(|ty| (tcx.lang_items().fn_once_output().unwrap(), ty)),
+                                    .map(|ty| (tcx.require_lang_item(LangItem::FnOnce, None), ty)),
                             );
                         }
                         if let Some(trait_ref) = entry.fn_mut_trait_ref {
@@ -2703,6 +2704,7 @@ define_print_and_forward_display! {
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 p!("the type `", print(ty), "` is found in the environment")
             }
+            ty::PredicateKind::Ambiguous => p!("ambiguous"),
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 0adc700586d9c..3d47b71b7ce62 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -23,6 +23,8 @@ pub enum Cause {
 pub trait TypeRelation<'tcx>: Sized {
     fn tcx(&self) -> TyCtxt<'tcx>;
 
+    fn intercrate(&self) -> bool;
+
     fn param_env(&self) -> ty::ParamEnv<'tcx>;
 
     /// Returns a static string we can use for printouts.
@@ -32,6 +34,9 @@ pub trait TypeRelation<'tcx>: Sized {
     /// relation. Just affects error messages.
     fn a_is_expected(&self) -> bool;
 
+    /// Used during coherence. If called, must emit an always-ambiguous obligation.
+    fn mark_ambiguous(&mut self);
+
     fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
@@ -562,16 +567,23 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         (&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
             if a_def_id == b_def_id =>
         {
-            let opt_variances = tcx.variances_of(a_def_id);
-            let substs = relate_substs_with_variances(
-                relation,
-                a_def_id,
-                opt_variances,
-                a_substs,
-                b_substs,
-                false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
-            )?;
-            Ok(tcx.mk_opaque(a_def_id, substs))
+            if relation.intercrate() {
+                // During coherence, opaque types should be treated as equal to each other, even if their generic params
+                // differ, as they could resolve to the same hidden type, even for different generic params.
+                relation.mark_ambiguous();
+                Ok(a)
+            } else {
+                let opt_variances = tcx.variances_of(a_def_id);
+                let substs = relate_substs_with_variances(
+                    relation,
+                    a_def_id,
+                    opt_variances,
+                    a_substs,
+                    b_substs,
+                    false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
+                )?;
+                Ok(tcx.mk_opaque(a_def_id, substs))
+            }
         }
 
         _ => Err(TypeError::Sorts(expected_found(relation, a, b))),
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 6be8fdd7cd795..64b4fd1176252 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -173,6 +173,7 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 write!(f, "TypeWellFormedFromEnv({:?})", ty)
             }
+            ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index db18558e947a3..e7a751fa0afca 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -17,6 +17,7 @@ use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::Interned;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::LangItem;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -2108,7 +2109,7 @@ impl<'tcx> Ty<'tcx> {
 
             ty::Str | ty::Slice(_) => (tcx.types.usize, false),
             ty::Dynamic(..) => {
-                let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
+                let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
                 (tcx.bound_type_of(dyn_metadata).subst(tcx, &[tail.into()]), false)
             },
 
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 ba04cb6eef82d..e369dba55242c 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_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index ba73fbd3e12fb..5cd2e0f6ce921 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1734,7 +1734,7 @@ impl<'a> Parser<'a> {
                         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,
         ))
     }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 5072d2aad1669..93b0f5814dedf 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_target/src/spec/aix_base.rs b/compiler/rustc_target/src/spec/aix_base.rs
new file mode 100644
index 0000000000000..c71c4ba2cc902
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aix_base.rs
@@ -0,0 +1,32 @@
+use crate::abi::Endian;
+use crate::spec::{crt_objects, cvs, Cc, CodeModel, LinkOutputKind, LinkerFlavor, TargetOptions};
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        abi: "vec-extabi".into(),
+        code_model: Some(CodeModel::Small),
+        cpu: "pwr7".into(),
+        os: "aix".into(),
+        vendor: "ibm".into(),
+        dynamic_linking: true,
+        endian: Endian::Big,
+        executables: true,
+        archive_format: "aix_big".into(),
+        families: cvs!["unix"],
+        has_rpath: false,
+        has_thread_local: true,
+        crt_static_respected: true,
+        linker_flavor: LinkerFlavor::Unix(Cc::No),
+        linker: Some("ld".into()),
+        eh_frame_header: false,
+        is_like_aix: true,
+        default_dwarf_version: 3,
+        function_sections: true,
+        pre_link_objects: crt_objects::new(&[
+            (LinkOutputKind::DynamicNoPicExe, &["/usr/lib/crt0_64.o", "/usr/lib/crti_64.o"]),
+            (LinkOutputKind::DynamicPicExe, &["/usr/lib/crt0_64.o", "/usr/lib/crti_64.o"]),
+        ]),
+        dll_suffix: ".a".into(),
+        ..Default::default()
+    }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 6d936d2cb9ff0..c633ef1e76193 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -58,6 +58,7 @@ use rustc_macros::HashStable_Generic;
 pub mod abi;
 pub mod crt_objects;
 
+mod aix_base;
 mod android_base;
 mod apple_base;
 mod avr_gnu_base;
@@ -1027,6 +1028,7 @@ supported_targets! {
     ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu),
     ("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe),
     ("powerpc-unknown-linux-musl", powerpc_unknown_linux_musl),
+    ("powerpc64-ibm-aix", powerpc64_ibm_aix),
     ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu),
     ("powerpc64-unknown-linux-musl", powerpc64_unknown_linux_musl),
     ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
@@ -1454,6 +1456,9 @@ pub struct TargetOptions {
     pub families: StaticCow<[StaticCow<str>]>,
     /// Whether the target toolchain's ABI supports returning small structs as an integer.
     pub abi_return_struct_as_int: bool,
+    /// Whether the target toolchain is like AIX's. Linker options on AIX are special and it uses
+    /// XCOFF as binary format. Defaults to false.
+    pub is_like_aix: bool,
     /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS,
     /// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false.
     /// Also indiates whether to use Apple-specific ABI changes, such as extending function
@@ -1817,6 +1822,7 @@ impl Default for TargetOptions {
             staticlib_suffix: ".a".into(),
             families: cvs![],
             abi_return_struct_as_int: false,
+            is_like_aix: false,
             is_like_osx: false,
             is_like_solaris: false,
             is_like_windows: false,
@@ -2488,6 +2494,7 @@ impl Target {
         key!(staticlib_suffix);
         key!(families, TargetFamilies);
         key!(abi_return_struct_as_int, bool);
+        key!(is_like_aix, bool);
         key!(is_like_osx, bool);
         key!(is_like_solaris, bool);
         key!(is_like_windows, bool);
@@ -2741,6 +2748,7 @@ impl ToJson for Target {
         target_option_val!(staticlib_suffix);
         target_option_val!(families, "target-family");
         target_option_val!(abi_return_struct_as_int);
+        target_option_val!(is_like_aix);
         target_option_val!(is_like_osx);
         target_option_val!(is_like_solaris);
         target_option_val!(is_like_windows);
diff --git a/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs
new file mode 100644
index 0000000000000..e3eb9bccd5ed7
--- /dev/null
+++ b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs
@@ -0,0 +1,23 @@
+use crate::spec::{Cc, LinkerFlavor, Target};
+
+pub fn target() -> Target {
+    let mut base = super::aix_base::opts();
+    base.max_atomic_width = Some(64);
+    base.add_pre_link_args(
+        LinkerFlavor::Unix(Cc::No),
+        &[
+            "-b64".into(),
+            "-bpT:0x100000000".into(),
+            "-bpD:0x110000000".into(),
+            "-bcdtors:all:0:s".into(),
+        ],
+    );
+
+    Target {
+        llvm_target: "powerpc64-ibm-aix".into(),
+        pointer_width: 64,
+        data_layout: "E-m:a-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        arch: "powerpc64".into(),
+        options: base,
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index a057e45ad6af4..78af187cd8f80 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -841,6 +841,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
+                ty::PredicateKind::Ambiguous => return false,
             };
         }
         true
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 1ef77e06b4874..741bf206d037e 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::CRATE_HIR_ID;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@@ -94,8 +94,9 @@ pub fn overlapping_impls<'tcx>(
         return None;
     }
 
-    let infcx = tcx.infer_ctxt().build();
-    let selcx = &mut SelectionContext::intercrate(&infcx);
+    let infcx =
+        tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+    let selcx = &mut SelectionContext::new(&infcx);
     let overlaps =
         overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
     if !overlaps {
@@ -105,8 +106,9 @@ pub fn overlapping_impls<'tcx>(
     // In the case where we detect an error, run the check again, but
     // this time tracking intercrate ambiguity causes for better
     // diagnostics. (These take time and can lead to false errors.)
-    let infcx = tcx.infer_ctxt().build();
-    let selcx = &mut SelectionContext::intercrate(&infcx);
+    let infcx =
+        tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+    let selcx = &mut SelectionContext::new(&infcx);
     selcx.enable_tracking_intercrate_ambiguity_causes();
     Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
 }
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 946e6e77a3da0..de31eb1aa5719 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"),
@@ -1168,6 +1166,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         )
                     }
 
+                    ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
+
                     ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!(
                         span,
                         "TypeWellFormedFromEnv predicate should only exist in the environment"
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 8086cac0d551a..186109e7075f1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2625,7 +2625,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     }
                 };
 
-                let from_generator = tcx.lang_items().from_generator_fn().unwrap();
+                let from_generator = tcx.require_lang_item(LangItem::FromGenerator, None);
 
                 // Don't print the tuple of capture types
                 'print: {
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index d84f768cce4d7..d238e7556aea3 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -336,6 +336,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
                     ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
                 }
+                ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
@@ -569,6 +570,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         }
                     }
                 }
+                ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index ff18aa1f9e909..e241213aba930 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/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 90f48658113af..7c4c58ba36167 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -319,6 +319,7 @@ fn predicate_references_self<'tcx>(
         | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::ConstEvaluatable(..)
         | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
     }
 }
@@ -350,6 +351,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             | ty::PredicateKind::TypeOutlives(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
         }
     })
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index e54e290fb4b11..2803a2d38c807 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -110,25 +110,6 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// require themselves.
     freshener: TypeFreshener<'cx, 'tcx>,
 
-    /// During coherence we have to assume that other crates may add
-    /// additional impls which we currently don't know about.
-    ///
-    /// To deal with this evaluation should be conservative
-    /// and consider the possibility of impls from outside this crate.
-    /// This comes up primarily when resolving ambiguity. Imagine
-    /// there is some trait reference `$0: Bar` where `$0` is an
-    /// inference variable. If `intercrate` is true, then we can never
-    /// say for sure that this reference is not implemented, even if
-    /// there are *no impls at all for `Bar`*, because `$0` could be
-    /// bound to some type that in a downstream crate that implements
-    /// `Bar`.
-    ///
-    /// Outside of coherence we set this to false because we are only
-    /// interested in types that the user could actually have written.
-    /// In other words, we consider `$0: Bar` to be unimplemented if
-    /// there is no type that the user could *actually name* that
-    /// would satisfy it. This avoids crippling inference, basically.
-    intercrate: bool,
     /// If `intercrate` is set, we remember predicates which were
     /// considered ambiguous because of impls potentially added in other crates.
     /// This is used in coherence to give improved diagnostics.
@@ -226,16 +207,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         SelectionContext {
             infcx,
             freshener: infcx.freshener_keep_static(),
-            intercrate: false,
             intercrate_ambiguity_causes: None,
             query_mode: TraitQueryMode::Standard,
         }
     }
 
-    pub fn intercrate(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
-        SelectionContext { intercrate: true, ..SelectionContext::new(infcx) }
-    }
-
     pub fn with_query_mode(
         infcx: &'cx InferCtxt<'tcx>,
         query_mode: TraitQueryMode,
@@ -247,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// Enables tracking of intercrate ambiguity causes. See
     /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
-        assert!(self.intercrate);
+        assert!(self.is_intercrate());
         assert!(self.intercrate_ambiguity_causes.is_none());
         self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
         debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
@@ -257,7 +233,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// was enabled and disables tracking at the same time. If
     /// tracking is not enabled, just returns an empty vector.
     pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> {
-        assert!(self.intercrate);
+        assert!(self.is_intercrate());
         self.intercrate_ambiguity_causes.take().unwrap_or_default()
     }
 
@@ -270,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     pub fn is_intercrate(&self) -> bool {
-        self.intercrate
+        self.infcx.intercrate
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -741,6 +717,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
+                ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
             }
         })
     }
@@ -751,7 +728,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: TraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        if !self.intercrate
+        if !self.is_intercrate()
             && obligation.is_global()
             && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
         {
@@ -1014,7 +991,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // mode, so don't do any caching. In particular, we might
         // re-use the same `InferCtxt` with both an intercrate
         // and non-intercrate `SelectionContext`
-        if self.intercrate {
+        if self.is_intercrate() {
             return None;
         }
 
@@ -1044,7 +1021,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // mode, so don't do any caching. In particular, we might
         // re-use the same `InferCtxt` with both an intercrate
         // and non-intercrate `SelectionContext`
-        if self.intercrate {
+        if self.is_intercrate() {
             return;
         }
 
@@ -1225,9 +1202,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> {
-        debug!("is_knowable(intercrate={:?})", self.intercrate);
+        debug!("is_knowable(intercrate={:?})", self.is_intercrate());
 
-        if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
+        if !self.is_intercrate() || stack.obligation.polarity() == ty::ImplPolarity::Negative {
             return Ok(());
         }
 
@@ -1258,7 +1235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // the master cache. Since coherence executes pretty quickly,
         // it's not worth going to more trouble to increase the
         // hit-rate, I don't think.
-        if self.intercrate {
+        if self.is_intercrate() {
             return false;
         }
 
@@ -1275,7 +1252,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // mode, so don't do any caching. In particular, we might
         // re-use the same `InferCtxt` with both an intercrate
         // and non-intercrate `SelectionContext`
-        if self.intercrate {
+        if self.is_intercrate() {
             return None;
         }
         let tcx = self.tcx();
@@ -1314,7 +1291,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // mode, so don't do any caching. In particular, we might
         // re-use the same `InferCtxt` with both an intercrate
         // and non-intercrate `SelectionContext`
-        if self.intercrate {
+        if self.is_intercrate() {
             return false;
         }
         match result {
@@ -2191,7 +2168,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?;
         nested_obligations.extend(obligations);
 
-        if !self.intercrate
+        if !self.is_intercrate()
             && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
         {
             debug!("reservation impls only apply in intercrate mode");
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 7cc12eff20e8b..9a3c0707c7ce9 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 932dbbb81e5cc..40dbe0b3ff063 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_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 53783e1bc4b2c..5e506a23f383f 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -155,6 +155,7 @@ pub fn predicate_obligations<'tcx>(
             wf.compute(c1.into());
             wf.compute(c2.into());
         }
+        ty::PredicateKind::Ambiguous => {}
         ty::PredicateKind::TypeWellFormedFromEnv(..) => {
             bug!("TypeWellFormedFromEnv is only used for Chalk")
         }
@@ -875,6 +876,7 @@ pub(crate) fn required_region_bounds<'tcx>(
                 | ty::PredicateKind::RegionOutlives(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                 ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
                     // Search for a bound of the form `erased_self_ty
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 06a42a95d6061..ee013515e86c4 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -121,6 +121,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
             };
             let value = chalk_ir::ProgramClauseImplication {
@@ -212,6 +213,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::ConstEquate(..) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
             }
@@ -625,6 +627,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                 bug!("unexpected predicate {}", &self)
             }
@@ -754,6 +757,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                 bug!("unexpected predicate {}", &self)
             }
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 82f6111f6f92e..3ab353c963802 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(),
         );
 
@@ -97,6 +94,7 @@ fn compute_implied_outlives_bounds<'tcx>(
                     | ty::PredicateKind::ObjectSafe(..)
                     | ty::PredicateKind::ConstEvaluatable(..)
                     | ty::PredicateKind::ConstEquate(..)
+                    | ty::PredicateKind::Ambiguous
                     | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                     ty::PredicateKind::WellFormed(arg) => {
                         wf_args.push(arg);
@@ -115,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),
     }
@@ -129,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_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index f1835d317e841..5200908527a16 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -66,6 +66,7 @@ fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool {
         | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::ConstEvaluatable(..)
         | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
     }
 }
diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs
index d418965cd2f6b..b25d63d835b54 100644
--- a/library/alloc/benches/lib.rs
+++ b/library/alloc/benches/lib.rs
@@ -5,7 +5,9 @@
 #![feature(iter_next_chunk)]
 #![feature(repr_simd)]
 #![feature(slice_partition_dedup)]
+#![feature(strict_provenance)]
 #![feature(test)]
+#![deny(fuzzy_provenance_casts)]
 
 extern crate test;
 
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 5e13547abcb70..96960d43f5820 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -82,6 +82,7 @@
 //
 // Lints:
 #![deny(unsafe_op_in_unsafe_fn)]
+#![deny(fuzzy_provenance_casts)]
 #![warn(deprecated_in_future)]
 #![warn(missing_debug_implementations)]
 #![warn(missing_docs)]
diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs
index 5ee6db43fda24..04da95bbb83ed 100644
--- a/library/alloc/tests/fmt.rs
+++ b/library/alloc/tests/fmt.rs
@@ -2,6 +2,7 @@
 
 use std::cell::RefCell;
 use std::fmt::{self, Write};
+use std::ptr;
 
 #[test]
 fn test_format() {
@@ -76,14 +77,14 @@ fn test_format_macro_interface() {
     t!(format!("{}", "foo"), "foo");
     t!(format!("{}", "foo".to_string()), "foo");
     if cfg!(target_pointer_width = "32") {
-        t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234");
-        t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234");
+        t!(format!("{:#p}", ptr::invalid::<isize>(0x1234)), "0x00001234");
+        t!(format!("{:#p}", ptr::invalid_mut::<isize>(0x1234)), "0x00001234");
     } else {
-        t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234");
-        t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234");
+        t!(format!("{:#p}", ptr::invalid::<isize>(0x1234)), "0x0000000000001234");
+        t!(format!("{:#p}", ptr::invalid_mut::<isize>(0x1234)), "0x0000000000001234");
     }
-    t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
-    t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
+    t!(format!("{:p}", ptr::invalid::<isize>(0x1234)), "0x1234");
+    t!(format!("{:p}", ptr::invalid_mut::<isize>(0x1234)), "0x1234");
     t!(format!("{A:x}"), "aloha");
     t!(format!("{B:X}"), "adios");
     t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index ffc5ca7a5c6cc..d066ec03ee57e 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -47,6 +47,7 @@
 #![feature(strict_provenance)]
 #![feature(once_cell)]
 #![feature(drain_keep_rest)]
+#![deny(fuzzy_provenance_casts)]
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 63ee6c521d793..65d4c3c891ea6 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -220,6 +220,7 @@
 #![allow(explicit_outlives_requirements)]
 #![allow(unused_lifetimes)]
 #![deny(rustc::existing_doc_keyword)]
+#![deny(fuzzy_provenance_casts)]
 // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
 #![deny(ffi_unwind_calls)]
 // std may use features in a platform-specific way
@@ -598,7 +599,7 @@ mod panicking;
 mod personality;
 
 #[path = "../../backtrace/src/lib.rs"]
-#[allow(dead_code, unused_attributes)]
+#[allow(dead_code, unused_attributes, fuzzy_provenance_casts)]
 mod backtrace_rs;
 
 // Re-export macros defined in libcore.
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index 72cb3406dcada..5c1634084a055 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -90,6 +90,7 @@ impl OwnedSocket {
     }
 
     // FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-;
+    #[allow(fuzzy_provenance_casts)]
     #[cfg(not(target_vendor = "uwp"))]
     pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
         cvt(unsafe {
diff --git a/library/std/src/personality/dwarf/eh.rs b/library/std/src/personality/dwarf/eh.rs
index 27b50c13b77ca..a783e187004fc 100644
--- a/library/std/src/personality/dwarf/eh.rs
+++ b/library/std/src/personality/dwarf/eh.rs
@@ -13,6 +13,7 @@
 
 use super::DwarfReader;
 use core::mem;
+use core::ptr;
 
 pub const DW_EH_PE_omit: u8 = 0xFF;
 pub const DW_EH_PE_absptr: u8 = 0x00;
@@ -151,7 +152,7 @@ unsafe fn read_encoded_pointer(
 
     // DW_EH_PE_aligned implies it's an absolute pointer value
     if encoding == DW_EH_PE_aligned {
-        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>())? as *const u8;
+        reader.ptr = reader.ptr.with_addr(round_up(reader.ptr.addr(), mem::size_of::<usize>())?);
         return Ok(reader.read::<usize>());
     }
 
@@ -171,7 +172,7 @@ unsafe fn read_encoded_pointer(
     result += match encoding & 0x70 {
         DW_EH_PE_absptr => 0,
         // relative to address of the encoded value, despite the name
-        DW_EH_PE_pcrel => reader.ptr as usize,
+        DW_EH_PE_pcrel => reader.ptr.expose_addr(),
         DW_EH_PE_funcrel => {
             if context.func_start == 0 {
                 return Err(());
@@ -184,7 +185,7 @@ unsafe fn read_encoded_pointer(
     };
 
     if encoding & DW_EH_PE_indirect != 0 {
-        result = *(result as *const usize);
+        result = *ptr::from_exposed_addr::<usize>(result);
     }
 
     Ok(result)
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index b1d32929ecfde..01e4ffe3dfc8a 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -3,6 +3,7 @@
 //! This module contains the facade (aka platform-specific) implementations of
 //! OS level functionality for Fortanix SGX.
 #![deny(unsafe_op_in_unsafe_fn)]
+#![allow(fuzzy_provenance_casts)] // FIXME: this entire module systematically confuses pointers and integers
 
 use crate::io::ErrorKind;
 use crate::sync::atomic::{AtomicBool, Ordering};
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 5d267891bb0ed..154b608c0dc5c 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -181,7 +181,8 @@ macro_rules! thread_local {
 macro_rules! __thread_local_inner {
     // used to generate the `LocalKey` value for const-initialized thread locals
     (@key $t:ty, const $init:expr) => {{
-        #[cfg_attr(not(windows), inline)] // see comments below
+        #[cfg_attr(not(all(windows, target_thread_local)), inline)] // see comments below
+        #[cfg_attr(all(windows, target_thread_local), inline(never))]
         #[deny(unsafe_op_in_unsafe_fn)]
         unsafe fn __getit(
             _init: $crate::option::Option<&mut $crate::option::Option<$t>>,
@@ -294,12 +295,17 @@ macro_rules! __thread_local_inner {
             fn __init() -> $t { $init }
 
             // When reading this function you might ask "why is this inlined
-            // everywhere other than Windows?", and that's a very reasonable
-            // question to ask. The short story is that it segfaults rustc if
-            // this function is inlined. The longer story is that Windows looks
-            // to not support `extern` references to thread locals across DLL
-            // boundaries. This appears to at least not be supported in the ABI
-            // that LLVM implements.
+            // everywhere other than Windows?", and "why must it not be inlined
+            // on Windows?" and these are very reasonable questions to ask.
+            //
+            // The short story is that Windows doesn't support referencing
+            // `#[thread_local]` across DLL boundaries. The slightly longer
+            // story is that each module (dll or exe) has its own separate set
+            // of static thread locals, so if you try and reference a
+            // `#[thread_local]` that comes from `crate1.dll` from within one of
+            // `crate2.dll`'s functions, then it might give you a completely
+            // different thread local than what you asked for (or it might just
+            // crash).
             //
             // Because of this we never inline on Windows, but we do inline on
             // other platforms (where external references to thread locals
@@ -314,8 +320,9 @@ macro_rules! __thread_local_inner {
             // Cargo question kinda). This means that, unfortunately, Windows
             // gets the pessimistic path for now where it's never inlined.
             //
-            // The issue of "should enable on Windows sometimes" is #84933
-            #[cfg_attr(not(windows), inline)]
+            // The issue of "should improve things on Windows" is #84933
+            #[cfg_attr(not(all(windows, target_thread_local)), inline)]
+            #[cfg_attr(all(windows, target_thread_local), inline(never))]
             unsafe fn __getit(
                 init: $crate::option::Option<&mut $crate::option::Option<$t>>,
             ) -> $crate::option::Option<&'static $t> {
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 28929acb9b48d..27e911c6be5a2 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -283,6 +283,7 @@ target | std | host | notes
 `powerpc64-wrs-vxworks` | ? |  |
 `powerpc64le-unknown-linux-musl` | ? |  |
 [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64
+`powerpc64-ibm-aix` | ? |  | 64-bit AIX (7.2 and newer)
 `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
 `riscv32im-unknown-none-elf` | * |  | Bare RISC-V (RV32IM ISA)
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7085bc8d1be55..b5d4ab55b4a83 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -318,6 +318,7 @@ pub(crate) fn clean_predicate<'tcx>(
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
     }
 }
diff --git a/src/test/ui/binding/issue-53114-borrow-checks.stderr b/src/test/ui/binding/issue-53114-borrow-checks.stderr
index 489bf70d920a3..0ec2ae8839e79 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 695b01d5ee3ad..994eaf9d8c778 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 1fd1eb128511b..50eee1049db6e 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 17b9310661583..d2e9497d0795c 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 4e20bbf175770..ed7e883ca6392 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 cd0d2fee9422f..eaf4bb38bc590 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 0dd720ff6ce04..e1b9916208805 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 346b82a266644..67b00c1dd90ce 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 6c6a25c251e70..47429ea3eebae 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 77702e145df81..bfab13d42d2a1 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 6cc2c2f7a984c..8412c24fe6112 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 9add7553afa70..e2aeaafc63c25 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 363effcfe5322..dd456681f57bc 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 86d2955e2364f..f94cbc30db421 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 e01c26adcfc2d..fb0e274c2919a 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 22253cd96f1a6..f785900d53fc0 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 d33115988a9a8..ad898fcabd9db 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 b20cc6d8cf59f..716cc9d0c8ba2 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 beeda5685dc09..2552fff860cd3 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 c6931ba72579b..55948afca733b 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 2bf34b32176c0..dd3471e2c8be5 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 6b84c0032cdde..250acbe5928a0 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 8b05b23882273..74e7067c9afaa 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 dd5797c3f79cc..9501798bb06d0 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/check-cfg/well-known-values.stderr b/src/test/ui/check-cfg/well-known-values.stderr
index 6c0dc05ba2330..29ececea5d394 100644
--- a/src/test/ui/check-cfg/well-known-values.stderr
+++ b/src/test/ui/check-cfg/well-known-values.stderr
@@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")]
    |                   |
    |                   help: did you mean: `"linux"`
    |
-   = note: expected values for `target_os` are: android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous
+   = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr
index 9072cc925ffff..080f6c39449f0 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/coherence/coherence-with-closure.rs b/src/test/ui/coherence/coherence-with-closure.rs
index 6e3281d8508ab..5b6a62b24d4b3 100644
--- a/src/test/ui/coherence/coherence-with-closure.rs
+++ b/src/test/ui/coherence/coherence-with-closure.rs
@@ -8,7 +8,6 @@ fn defining_use() -> OpaqueClosure {
 struct Wrapper<T>(T);
 trait Trait {}
 impl Trait for Wrapper<OpaqueClosure> {}
-//~^ ERROR cannot implement trait on type alias impl trait
 impl<T: Sync> Trait for Wrapper<T> {}
 //~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
 
diff --git a/src/test/ui/coherence/coherence-with-closure.stderr b/src/test/ui/coherence/coherence-with-closure.stderr
index d2ca63fa14691..431108e14d7d8 100644
--- a/src/test/ui/coherence/coherence-with-closure.stderr
+++ b/src/test/ui/coherence/coherence-with-closure.stderr
@@ -1,24 +1,11 @@
 error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
-  --> $DIR/coherence-with-closure.rs:12:1
+  --> $DIR/coherence-with-closure.rs:11:1
    |
 LL | impl Trait for Wrapper<OpaqueClosure> {}
    | ------------------------------------- first implementation here
-LL |
 LL | impl<T: Sync> Trait for Wrapper<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>`
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/coherence-with-closure.rs:10:24
-   |
-LL | impl Trait for Wrapper<OpaqueClosure> {}
-   |                        ^^^^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/coherence-with-closure.rs:3:22
-   |
-LL | type OpaqueClosure = impl Sized;
-   |                      ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-with-generator.rs b/src/test/ui/coherence/coherence-with-generator.rs
index d34c391db9fb0..70665ba06f954 100644
--- a/src/test/ui/coherence/coherence-with-generator.rs
+++ b/src/test/ui/coherence/coherence-with-generator.rs
@@ -12,7 +12,6 @@ fn defining_use() -> OpaqueGenerator {
 struct Wrapper<T>(T);
 trait Trait {}
 impl Trait for Wrapper<OpaqueGenerator> {}
-//~^ ERROR cannot implement trait on type alias impl trait
 impl<T: Sync> Trait for Wrapper<T> {}
 //~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
 
diff --git a/src/test/ui/coherence/coherence-with-generator.stderr b/src/test/ui/coherence/coherence-with-generator.stderr
index 804bc1c3a6dd4..6d3be2e16c657 100644
--- a/src/test/ui/coherence/coherence-with-generator.stderr
+++ b/src/test/ui/coherence/coherence-with-generator.stderr
@@ -1,24 +1,11 @@
 error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
-  --> $DIR/coherence-with-generator.rs:16:1
+  --> $DIR/coherence-with-generator.rs:15:1
    |
 LL | impl Trait for Wrapper<OpaqueGenerator> {}
    | --------------------------------------- first implementation here
-LL |
 LL | impl<T: Sync> Trait for Wrapper<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>`
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/coherence-with-generator.rs:14:24
-   |
-LL | impl Trait for Wrapper<OpaqueGenerator> {}
-   |                        ^^^^^^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/coherence-with-generator.rs:3:24
-   |
-LL | type OpaqueGenerator = impl Sized;
-   |                        ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/const-generics/projection-as-arg-const.rs b/src/test/ui/const-generics/projection-as-arg-const.rs
new file mode 100644
index 0000000000000..903548c75db56
--- /dev/null
+++ b/src/test/ui/const-generics/projection-as-arg-const.rs
@@ -0,0 +1,20 @@
+// This is currently not possible to use projections as const generics.
+// More information about this available here:
+// https://github.com/rust-lang/rust/pull/104443#discussion_r1029375633
+
+pub trait Identity {
+    type Identity;
+}
+
+impl<T> Identity for T {
+    type Identity = Self;
+}
+
+pub fn foo<const X: <i32 as Identity>::Identity>() {
+//~^ ERROR
+    assert!(X == 12);
+}
+
+fn main() {
+    foo::<12>();
+}
diff --git a/src/test/ui/const-generics/projection-as-arg-const.stderr b/src/test/ui/const-generics/projection-as-arg-const.stderr
new file mode 100644
index 0000000000000..803ed9c959752
--- /dev/null
+++ b/src/test/ui/const-generics/projection-as-arg-const.stderr
@@ -0,0 +1,11 @@
+error: `<i32 as Identity>::Identity` is forbidden as the type of a const generic parameter
+  --> $DIR/projection-as-arg-const.rs:13:21
+   |
+LL | pub fn foo<const X: <i32 as Identity>::Identity>() {
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = help: more complex types are supported with `#![feature(adt_const_params)]`
+
+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 7357551c4a7f6..f030228f71ae4 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/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs
index afa95645a2786..35994e4a5ba3f 100644
--- a/src/test/ui/impl-trait/auto-trait.rs
+++ b/src/test/ui/impl-trait/auto-trait.rs
@@ -20,7 +20,6 @@ impl<T: Send> AnotherTrait for T {}
 // in the future.)
 impl AnotherTrait for D<OpaqueType> {
     //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
-    //~| ERROR cannot implement trait on type alias impl trait
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr
index 5e10272b0db3c..81009413c9a26 100644
--- a/src/test/ui/impl-trait/auto-trait.stderr
+++ b/src/test/ui/impl-trait/auto-trait.stderr
@@ -7,18 +7,6 @@ LL | impl<T: Send> AnotherTrait for T {}
 LL | impl AnotherTrait for D<OpaqueType> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/auto-trait.rs:21:25
-   |
-LL | impl AnotherTrait for D<OpaqueType> {
-   |                         ^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/auto-trait.rs:7:19
-   |
-LL | type OpaqueType = impl OpaqueTrait;
-   |                   ^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs
index da69bb349ae24..70e24a3a9d029 100644
--- a/src/test/ui/impl-trait/negative-reasoning.rs
+++ b/src/test/ui/impl-trait/negative-reasoning.rs
@@ -18,7 +18,6 @@ impl<T: std::fmt::Debug> AnotherTrait for T {}
 // This is in error, because we cannot assume that `OpaqueType: !Debug`
 impl AnotherTrait for D<OpaqueType> {
     //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
-    //~| ERROR cannot implement trait on type alias impl trait
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr
index 479b451855d55..6b8cc9e737423 100644
--- a/src/test/ui/impl-trait/negative-reasoning.stderr
+++ b/src/test/ui/impl-trait/negative-reasoning.stderr
@@ -9,18 +9,6 @@ LL | impl AnotherTrait for D<OpaqueType> {
    |
    = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/negative-reasoning.rs:19:25
-   |
-LL | impl AnotherTrait for D<OpaqueType> {
-   |                         ^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/negative-reasoning.rs:7:19
-   |
-LL | type OpaqueType = impl OpaqueTrait;
-   |                   ^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
index 621c4ea6e0d48..af9dfe25bb4ce 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
@@ -5,13 +5,13 @@ type Foo = impl PartialEq<(Foo, i32)>;
 struct Bar;
 
 impl PartialEq<(Foo, i32)> for Bar {
-//~^ ERROR cannot implement trait on type alias impl trait
     fn eq(&self, _other: &(Foo, i32)) -> bool {
         true
     }
 }
 
 fn foo() -> Foo {
+    //~^ ERROR can't compare `Bar` with `(Bar, i32)`
     Bar
 }
 
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
index 2ef1697ba341d..7b63a3d0b9f10 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
@@ -1,14 +1,15 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:7:17
+error[E0277]: can't compare `Bar` with `(Bar, i32)`
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:13:13
    |
-LL | impl PartialEq<(Foo, i32)> for Bar {
-   |                 ^^^
+LL | fn foo() -> Foo {
+   |             ^^^ no implementation for `Bar == (Bar, i32)`
+LL |
+LL |     Bar
+   |     --- return type was inferred to be `Bar` here
    |
-note: type alias impl trait defined here
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:3:12
-   |
-LL | type Foo = impl PartialEq<(Foo, i32)>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar`
+   = help: the trait `PartialEq<(Foo, i32)>` is implemented for `Bar`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
index df7966f00e172..91f1ed48133f5 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
@@ -2,11 +2,13 @@
 
 mod a {
     type Foo = impl PartialEq<(Foo, i32)>;
+    //~^ ERROR: unconstrained opaque type
 
     struct Bar;
 
     impl PartialEq<(Bar, i32)> for Bar {
         fn eq(&self, _other: &(Foo, i32)) -> bool {
+            //~^ ERROR: `eq` has an incompatible type for trait
             true
         }
     }
@@ -14,12 +16,13 @@ mod a {
 
 mod b {
     type Foo = impl PartialEq<(Foo, i32)>;
+    //~^ ERROR: unconstrained opaque type
 
     struct Bar;
 
     impl PartialEq<(Foo, i32)> for Bar {
-        //~^ ERROR cannot implement trait on type alias impl trait
         fn eq(&self, _other: &(Bar, i32)) -> bool {
+            //~^ ERROR: `eq` has an incompatible type for trait
             true
         }
     }
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
index 6cd63dcf81c7f..3dda5761ada6b 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
@@ -1,14 +1,49 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:20:21
+error: unconstrained opaque type
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
    |
-LL |     impl PartialEq<(Foo, i32)> for Bar {
-   |                     ^^^
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
+
+error[E0053]: method `eq` has an incompatible type for trait
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:30
+   |
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                -------------------------- the found opaque type
+...
+LL |         fn eq(&self, _other: &(Foo, i32)) -> bool {
+   |                              ^^^^^^^^^^^
+   |                              |
+   |                              expected struct `a::Bar`, found opaque type
+   |                              help: change the parameter type to match the trait: `&(a::Bar, i32)`
    |
-note: type alias impl trait defined here
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:16:16
+   = note: expected fn pointer `fn(&a::Bar, &(a::Bar, i32)) -> _`
+              found fn pointer `fn(&a::Bar, &(a::Foo, i32)) -> _`
+
+error: unconstrained opaque type
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16
    |
 LL |     type Foo = impl PartialEq<(Foo, i32)>;
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
+
+error[E0053]: method `eq` has an incompatible type for trait
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:30
+   |
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                -------------------------- the expected opaque type
+...
+LL |         fn eq(&self, _other: &(Bar, i32)) -> bool {
+   |                              ^^^^^^^^^^^
+   |                              |
+   |                              expected opaque type, found struct `b::Bar`
+   |                              help: change the parameter type to match the trait: `&(b::Foo, i32)`
+   |
+   = note: expected fn pointer `fn(&b::Bar, &(b::Foo, i32)) -> _`
+              found fn pointer `fn(&b::Bar, &(b::Bar, i32)) -> _`
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0053`.
diff --git a/src/test/ui/issues/issue-29723.stderr b/src/test/ui/issues/issue-29723.stderr
index e39ddfc81c968..92ee5cf22b719 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 f3e0e7b20a178..f2971df5db275 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/lint/unused/must-use-ops.rs b/src/test/ui/lint/unused/must-use-ops.rs
index 3e425727e7829..60f877aa8b303 100644
--- a/src/test/ui/lint/unused/must-use-ops.rs
+++ b/src/test/ui/lint/unused/must-use-ops.rs
@@ -3,12 +3,18 @@
 // check-pass
 
 #![warn(unused_must_use)]
+#![feature(never_type)]
+
+fn deref_never(x: &!) {
+    // Don't lint for uninhabited typess
+    *x;
+}
 
 fn main() {
     let val = 1;
     let val_pointer = &val;
 
-// Comparison Operators
+    // Comparison Operators
     val == 1; //~ WARNING unused comparison
     val < 1; //~ WARNING unused comparison
     val <= 1; //~ WARNING unused comparison
@@ -16,26 +22,30 @@ fn main() {
     val >= 1; //~ WARNING unused comparison
     val > 1; //~ WARNING unused comparison
 
-// Arithmetic Operators
+    // Arithmetic Operators
     val + 2; //~ WARNING unused arithmetic operation
     val - 2; //~ WARNING unused arithmetic operation
     val / 2; //~ WARNING unused arithmetic operation
     val * 2; //~ WARNING unused arithmetic operation
     val % 2; //~ WARNING unused arithmetic operation
 
-// Logical Operators
+    // Logical Operators
     true && true; //~ WARNING unused logical operation
     false || true; //~ WARNING unused logical operation
 
-// Bitwise Operators
+    // Bitwise Operators
     5 ^ val; //~ WARNING unused bitwise operation
     5 & val; //~ WARNING unused bitwise operation
     5 | val; //~ WARNING unused bitwise operation
     5 << val; //~ WARNING unused bitwise operation
     5 >> val; //~ WARNING unused bitwise operation
 
-// Unary Operators
+    // Unary Operators
     !val; //~ WARNING unused unary operation
     -val; //~ WARNING unused unary operation
     *val_pointer; //~ WARNING unused unary operation
+
+    if false {
+        deref_never(&panic!());
+    }
 }
diff --git a/src/test/ui/lint/unused/must-use-ops.stderr b/src/test/ui/lint/unused/must-use-ops.stderr
index b248dd0fe1547..79a53d39cbf10 100644
--- a/src/test/ui/lint/unused/must-use-ops.stderr
+++ b/src/test/ui/lint/unused/must-use-ops.stderr
@@ -1,5 +1,5 @@
 warning: unused comparison that must be used
-  --> $DIR/must-use-ops.rs:12:5
+  --> $DIR/must-use-ops.rs:18:5
    |
 LL |     val == 1;
    |     ^^^^^^^^ the comparison produces a value
@@ -15,7 +15,7 @@ LL |     let _ = val == 1;
    |     +++++++
 
 warning: unused comparison that must be used
-  --> $DIR/must-use-ops.rs:13:5
+  --> $DIR/must-use-ops.rs:19:5
    |
 LL |     val < 1;
    |     ^^^^^^^ the comparison produces a value
@@ -26,7 +26,7 @@ LL |     let _ = val < 1;
    |     +++++++
 
 warning: unused comparison that must be used
-  --> $DIR/must-use-ops.rs:14:5
+  --> $DIR/must-use-ops.rs:20:5
    |
 LL |     val <= 1;
    |     ^^^^^^^^ the comparison produces a value
@@ -37,7 +37,7 @@ LL |     let _ = val <= 1;
    |     +++++++
 
 warning: unused comparison that must be used
-  --> $DIR/must-use-ops.rs:15:5
+  --> $DIR/must-use-ops.rs:21:5
    |
 LL |     val != 1;
    |     ^^^^^^^^ the comparison produces a value
@@ -48,7 +48,7 @@ LL |     let _ = val != 1;
    |     +++++++
 
 warning: unused comparison that must be used
-  --> $DIR/must-use-ops.rs:16:5
+  --> $DIR/must-use-ops.rs:22:5
    |
 LL |     val >= 1;
    |     ^^^^^^^^ the comparison produces a value
@@ -59,7 +59,7 @@ LL |     let _ = val >= 1;
    |     +++++++
 
 warning: unused comparison that must be used
-  --> $DIR/must-use-ops.rs:17:5
+  --> $DIR/must-use-ops.rs:23:5
    |
 LL |     val > 1;
    |     ^^^^^^^ the comparison produces a value
@@ -70,7 +70,7 @@ LL |     let _ = val > 1;
    |     +++++++
 
 warning: unused arithmetic operation that must be used
-  --> $DIR/must-use-ops.rs:20:5
+  --> $DIR/must-use-ops.rs:26:5
    |
 LL |     val + 2;
    |     ^^^^^^^ the arithmetic operation produces a value
@@ -81,7 +81,7 @@ LL |     let _ = val + 2;
    |     +++++++
 
 warning: unused arithmetic operation that must be used
-  --> $DIR/must-use-ops.rs:21:5
+  --> $DIR/must-use-ops.rs:27:5
    |
 LL |     val - 2;
    |     ^^^^^^^ the arithmetic operation produces a value
@@ -92,7 +92,7 @@ LL |     let _ = val - 2;
    |     +++++++
 
 warning: unused arithmetic operation that must be used
-  --> $DIR/must-use-ops.rs:22:5
+  --> $DIR/must-use-ops.rs:28:5
    |
 LL |     val / 2;
    |     ^^^^^^^ the arithmetic operation produces a value
@@ -103,7 +103,7 @@ LL |     let _ = val / 2;
    |     +++++++
 
 warning: unused arithmetic operation that must be used
-  --> $DIR/must-use-ops.rs:23:5
+  --> $DIR/must-use-ops.rs:29:5
    |
 LL |     val * 2;
    |     ^^^^^^^ the arithmetic operation produces a value
@@ -114,7 +114,7 @@ LL |     let _ = val * 2;
    |     +++++++
 
 warning: unused arithmetic operation that must be used
-  --> $DIR/must-use-ops.rs:24:5
+  --> $DIR/must-use-ops.rs:30:5
    |
 LL |     val % 2;
    |     ^^^^^^^ the arithmetic operation produces a value
@@ -125,7 +125,7 @@ LL |     let _ = val % 2;
    |     +++++++
 
 warning: unused logical operation that must be used
-  --> $DIR/must-use-ops.rs:27:5
+  --> $DIR/must-use-ops.rs:33:5
    |
 LL |     true && true;
    |     ^^^^^^^^^^^^ the logical operation produces a value
@@ -136,7 +136,7 @@ LL |     let _ = true && true;
    |     +++++++
 
 warning: unused logical operation that must be used
-  --> $DIR/must-use-ops.rs:28:5
+  --> $DIR/must-use-ops.rs:34:5
    |
 LL |     false || true;
    |     ^^^^^^^^^^^^^ the logical operation produces a value
@@ -147,7 +147,7 @@ LL |     let _ = false || true;
    |     +++++++
 
 warning: unused bitwise operation that must be used
-  --> $DIR/must-use-ops.rs:31:5
+  --> $DIR/must-use-ops.rs:37:5
    |
 LL |     5 ^ val;
    |     ^^^^^^^ the bitwise operation produces a value
@@ -158,7 +158,7 @@ LL |     let _ = 5 ^ val;
    |     +++++++
 
 warning: unused bitwise operation that must be used
-  --> $DIR/must-use-ops.rs:32:5
+  --> $DIR/must-use-ops.rs:38:5
    |
 LL |     5 & val;
    |     ^^^^^^^ the bitwise operation produces a value
@@ -169,7 +169,7 @@ LL |     let _ = 5 & val;
    |     +++++++
 
 warning: unused bitwise operation that must be used
-  --> $DIR/must-use-ops.rs:33:5
+  --> $DIR/must-use-ops.rs:39:5
    |
 LL |     5 | val;
    |     ^^^^^^^ the bitwise operation produces a value
@@ -180,7 +180,7 @@ LL |     let _ = 5 | val;
    |     +++++++
 
 warning: unused bitwise operation that must be used
-  --> $DIR/must-use-ops.rs:34:5
+  --> $DIR/must-use-ops.rs:40:5
    |
 LL |     5 << val;
    |     ^^^^^^^^ the bitwise operation produces a value
@@ -191,7 +191,7 @@ LL |     let _ = 5 << val;
    |     +++++++
 
 warning: unused bitwise operation that must be used
-  --> $DIR/must-use-ops.rs:35:5
+  --> $DIR/must-use-ops.rs:41:5
    |
 LL |     5 >> val;
    |     ^^^^^^^^ the bitwise operation produces a value
@@ -202,7 +202,7 @@ LL |     let _ = 5 >> val;
    |     +++++++
 
 warning: unused unary operation that must be used
-  --> $DIR/must-use-ops.rs:38:5
+  --> $DIR/must-use-ops.rs:44:5
    |
 LL |     !val;
    |     ^^^^ the unary operation produces a value
@@ -213,7 +213,7 @@ LL |     let _ = !val;
    |     +++++++
 
 warning: unused unary operation that must be used
-  --> $DIR/must-use-ops.rs:39:5
+  --> $DIR/must-use-ops.rs:45:5
    |
 LL |     -val;
    |     ^^^^ the unary operation produces a value
@@ -224,7 +224,7 @@ LL |     let _ = -val;
    |     +++++++
 
 warning: unused unary operation that must be used
-  --> $DIR/must-use-ops.rs:40:5
+  --> $DIR/must-use-ops.rs:46:5
    |
 LL |     *val_pointer;
    |     ^^^^^^^^^^^^ the unary operation produces a value
diff --git a/src/test/ui/lint/unused/must_use-array.rs b/src/test/ui/lint/unused/must_use-array.rs
index 97825dd2f6c43..b7bae4b0acf12 100644
--- a/src/test/ui/lint/unused/must_use-array.rs
+++ b/src/test/ui/lint/unused/must_use-array.rs
@@ -1,6 +1,7 @@
 #![deny(unused_must_use)]
 
 #[must_use]
+#[derive(Clone, Copy)]
 struct S;
 
 struct A;
@@ -34,6 +35,10 @@ fn array_of_arrays_of_arrays() -> [[[S; 1]; 2]; 1] {
     [[[S], [S]]]
 }
 
+fn usize_max() -> [S; usize::MAX] {
+    [S; usize::MAX]
+}
+
 fn main() {
     empty(); // ok
     singleton(); //~ ERROR unused array of `S` that must be used
@@ -44,4 +49,6 @@ fn main() {
     //~^ ERROR unused array of boxed `T` trait objects in tuple element 1 that must be used
     array_of_arrays_of_arrays();
     //~^ ERROR unused array of arrays of arrays of `S` that must be used
+    usize_max();
+    //~^ ERROR unused array of `S` that must be used
 }
diff --git a/src/test/ui/lint/unused/must_use-array.stderr b/src/test/ui/lint/unused/must_use-array.stderr
index bba2b1ba078c6..61ef2088d30e5 100644
--- a/src/test/ui/lint/unused/must_use-array.stderr
+++ b/src/test/ui/lint/unused/must_use-array.stderr
@@ -1,5 +1,5 @@
 error: unused array of `S` that must be used
-  --> $DIR/must_use-array.rs:39:5
+  --> $DIR/must_use-array.rs:44:5
    |
 LL |     singleton();
    |     ^^^^^^^^^^^
@@ -11,34 +11,40 @@ LL | #![deny(unused_must_use)]
    |         ^^^^^^^^^^^^^^^
 
 error: unused array of `S` that must be used
-  --> $DIR/must_use-array.rs:40:5
+  --> $DIR/must_use-array.rs:45:5
    |
 LL |     many();
    |     ^^^^^^
 
 error: unused array of `S` in tuple element 0 that must be used
-  --> $DIR/must_use-array.rs:41:6
+  --> $DIR/must_use-array.rs:46:6
    |
 LL |     ([S], 0, ());
    |      ^^^
 
 error: unused array of implementers of `T` that must be used
-  --> $DIR/must_use-array.rs:42:5
+  --> $DIR/must_use-array.rs:47:5
    |
 LL |     array_of_impl_trait();
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: unused array of boxed `T` trait objects in tuple element 1 that must be used
-  --> $DIR/must_use-array.rs:43:5
+  --> $DIR/must_use-array.rs:48:5
    |
 LL |     impl_array();
    |     ^^^^^^^^^^^^
 
 error: unused array of arrays of arrays of `S` that must be used
-  --> $DIR/must_use-array.rs:45:5
+  --> $DIR/must_use-array.rs:50:5
    |
 LL |     array_of_arrays_of_arrays();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: unused array of `S` that must be used
+  --> $DIR/must_use-array.rs:52:5
+   |
+LL |     usize_max();
+   |     ^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr
index 7c0e916eddcaa..d14cd6cb4e03a 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 832d4f8fa030f..a060914f17859 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 b04a05fe40906..4dff7447dd766 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 218b93c8e4f45..3accba197a13d 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 8edc0463fe571..65d55ca8f7073 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/mismatched_types/overloaded-calls-bad.rs b/src/test/ui/mismatched_types/overloaded-calls-bad.rs
index 902a6ec81d60b..232cd2ba88cc2 100644
--- a/src/test/ui/mismatched_types/overloaded-calls-bad.rs
+++ b/src/test/ui/mismatched_types/overloaded-calls-bad.rs
@@ -20,14 +20,23 @@ impl FnOnce<(isize,)> for S {
     }
 }
 
+struct F;
+
+impl FnOnce<(i32,)> for F {
+    type Output = ();
+
+    extern "rust-call" fn call_once(self, args: (i32,)) -> Self::Output {}
+}
+
 fn main() {
-    let mut s = S {
-        x: 3,
-        y: 3,
-    };
-    let ans = s("what");    //~ ERROR mismatched types
+    let mut s = S { x: 3, y: 3 };
+    let ans = s("what");
+    //~^ ERROR mismatched types
     let ans = s();
     //~^ ERROR this function takes 1 argument but 0 arguments were supplied
     let ans = s("burma", "shave");
     //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+
+    F("");
+    //~^ ERROR mismatched types
 }
diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr
index fb3597aa85300..3a895acbdb5dd 100644
--- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr
+++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/overloaded-calls-bad.rs:28:17
+  --> $DIR/overloaded-calls-bad.rs:33:17
    |
 LL |     let ans = s("what");
    |               - ^^^^^^ expected `isize`, found `&str`
@@ -13,7 +13,7 @@ LL | impl FnMut<(isize,)> for S {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0057]: this function takes 1 argument but 0 arguments were supplied
-  --> $DIR/overloaded-calls-bad.rs:29:15
+  --> $DIR/overloaded-calls-bad.rs:35:15
    |
 LL |     let ans = s();
    |               ^-- an argument of type `isize` is missing
@@ -29,7 +29,7 @@ LL |     let ans = s(/* isize */);
    |                ~~~~~~~~~~~~~
 
 error[E0057]: this function takes 1 argument but 2 arguments were supplied
-  --> $DIR/overloaded-calls-bad.rs:31:15
+  --> $DIR/overloaded-calls-bad.rs:37:15
    |
 LL |     let ans = s("burma", "shave");
    |               ^ -------  ------- argument of type `&'static str` unexpected
@@ -46,7 +46,21 @@ help: remove the extra argument
 LL |     let ans = s(/* isize */);
    |                ~~~~~~~~~~~~~
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/overloaded-calls-bad.rs:40:7
+   |
+LL |     F("");
+   |     - ^^ expected `i32`, found `&str`
+   |     |
+   |     arguments to this struct are incorrect
+   |
+note: implementation defined here
+  --> $DIR/overloaded-calls-bad.rs:25:1
+   |
+LL | impl FnOnce<(i32,)> for F {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0057, E0308.
 For more information about an error, try `rustc --explain E0057`.
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 3146b6959001e..9a84ddef7e64e 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 baa87e3e9fdb2..94bc9e6f45465 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 d76b69ecdc8bb..56c225bab8cbc 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 974994223a3fd..7e119fe8cda64 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 3a686121a9283..c13dc58826eb8 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 2048fefefa31b..86e5f65248b97 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 5e9aa66b90dae..f04cb34d7c46e 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 8d636c11b78c7..26047861f55d7 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 3cc8ca29144ca..a49ee31b46622 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 a315bbaab33c0..db4382b58fcb2 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 ee7971691a4a1..0930df148059d 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 9bcec36740d62..838b1282cb4ed 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 ad1a2db8b52ba..225935532ead7 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 eef8ce61fa9d8..0bcce30126306 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 c25981e6f8063..22e7951dbe367 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 e9d7ca953d65b..0a09353b8ec0a 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 947c9e29b4508..97ed414b1eceb 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 e591ca08290eb..072e96788b17e 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 574a114340f03..d8f58b591311d 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 2d48a914218fd..f72ed3af71823 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 a973c583a9d66..b1f5117cb0243 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/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 fad84dda0e192..c8b45fd24d98c 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 a227cc583d68d..324897151124c 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 002c7609f6109..f27df32ccfa5c 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 be4e81c61aa62..d6474f1b49fb0 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 a9e66de084242..389e86e646457 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 b2f22fe86388e..770bb89530cca 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 384a57b2ee092..ad4ce7952ca74 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 cd3234952fa54..e0e623fa544f7 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 840a513d6c67d..638bdd6db7606 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 bac2db6ce825c..bb7b818368b78 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/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
index 5611b5f4ece5f..06699b947be40 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/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr
index 1059e3d1525aa..0cc8994fe1f2d 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 0000000000000..c36040eeca301
--- /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 0000000000000..c0d4feb033098
--- /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 0000000000000..10447ba7089ca
--- /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/threads-sendsync/mpsc_stress.rs b/src/test/ui/threads-sendsync/mpsc_stress.rs
index a889542fec0be..c2e1912deb7aa 100644
--- a/src/test/ui/threads-sendsync/mpsc_stress.rs
+++ b/src/test/ui/threads-sendsync/mpsc_stress.rs
@@ -64,9 +64,11 @@ fn shared_close_sender_does_not_lose_messages_iter() {
 
 #[test]
 fn shared_close_sender_does_not_lose_messages() {
-    for _ in 0..10000 {
-        shared_close_sender_does_not_lose_messages_iter();
-    }
+    with_minimum_timer_resolution(|| {
+        for _ in 0..10000 {
+            shared_close_sender_does_not_lose_messages_iter();
+        }
+    });
 }
 
 
@@ -96,17 +98,11 @@ fn concurrent_recv_timeout_and_upgrade_iter() {
 
 #[test]
 fn concurrent_recv_timeout_and_upgrade() {
-    // FIXME: fix and enable
-    if true { return }
-
-    // at the moment of writing this test fails like this:
-    // thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
-    //  left: `4561387584`,
-    // right: `0`', libstd/sync/mpsc/shared.rs:253:13
-
-    for _ in 0..10000 {
-        concurrent_recv_timeout_and_upgrade_iter();
-    }
+    with_minimum_timer_resolution(|| {
+        for _ in 0..10000 {
+            concurrent_recv_timeout_and_upgrade_iter();
+        }
+    });
 }
 
 
@@ -159,7 +155,46 @@ fn concurrent_writes_iter() {
 
 #[test]
 fn concurrent_writes() {
-    for _ in 0..100 {
-        concurrent_writes_iter();
+    with_minimum_timer_resolution(|| {
+        for _ in 0..100 {
+            concurrent_writes_iter();
+        }
+    });
+}
+
+#[cfg(windows)]
+pub mod timeapi {
+    #![allow(non_snake_case)]
+    use std::ffi::c_uint;
+
+    pub const TIMERR_NOERROR: c_uint = 0;
+
+    #[link(name = "winmm")]
+    extern "system" {
+        pub fn timeBeginPeriod(uPeriod: c_uint) -> c_uint;
+        pub fn timeEndPeriod(uPeriod: c_uint) -> c_uint;
+    }
+}
+
+/// Window's minimum sleep time can be as much as 16ms.
+// This function evaluates the closure with this resolution
+// set as low as possible.
+///
+/// This takes the above test's duration from 10000*16/1000/60=2.67 minutes to ~16 seconds.
+fn with_minimum_timer_resolution(f: impl Fn()) {
+    #[cfg(windows)]
+    unsafe {
+        let ret = timeapi::timeBeginPeriod(1);
+        assert_eq!(ret, timeapi::TIMERR_NOERROR);
+
+        f();
+
+        let ret = timeapi::timeEndPeriod(1);
+        assert_eq!(ret, timeapi::TIMERR_NOERROR);
+    }
+
+    #[cfg(not(windows))]
+    {
+        f();
     }
 }
diff --git a/src/test/ui/track-diagnostics/track2.stderr b/src/test/ui/track-diagnostics/track2.stderr
index 38a621da81644..fe13e5ef3f546 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/alias/issue-83613.rs b/src/test/ui/traits/alias/issue-83613.rs
index 04320e7207683..2462e703a7165 100644
--- a/src/test/ui/traits/alias/issue-83613.rs
+++ b/src/test/ui/traits/alias/issue-83613.rs
@@ -9,5 +9,4 @@ trait AnotherTrait {}
 impl<T: Send> AnotherTrait for T {}
 impl AnotherTrait for OpaqueType {}
 //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
-//~| ERROR cannot implement trait on type alias impl trait
 fn main() {}
diff --git a/src/test/ui/traits/alias/issue-83613.stderr b/src/test/ui/traits/alias/issue-83613.stderr
index b9d93160192e9..a78294da6c140 100644
--- a/src/test/ui/traits/alias/issue-83613.stderr
+++ b/src/test/ui/traits/alias/issue-83613.stderr
@@ -6,18 +6,6 @@ LL | impl<T: Send> AnotherTrait for T {}
 LL | impl AnotherTrait for OpaqueType {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType`
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-83613.rs:10:23
-   |
-LL | impl AnotherTrait for OpaqueType {}
-   |                       ^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-83613.rs:4:19
-   |
-LL | type OpaqueType = impl OpaqueTrait;
-   |                   ^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
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 c9f2a3ed9f4bf..f738b03eed6b8 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/type-alias-impl-trait/coherence.rs b/src/test/ui/type-alias-impl-trait/coherence.rs
index 98ac215ad6cc5..077a31494a972 100644
--- a/src/test/ui/type-alias-impl-trait/coherence.rs
+++ b/src/test/ui/type-alias-impl-trait/coherence.rs
@@ -12,6 +12,6 @@ fn use_alias<T>(val: T) -> AliasOfForeignType<T> {
 }
 
 impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
-//~^ ERROR cannot implement trait on type alias impl trait
+//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/coherence.stderr b/src/test/ui/type-alias-impl-trait/coherence.stderr
index 3ce25d94f6e12..c923eb08ab312 100644
--- a/src/test/ui/type-alias-impl-trait/coherence.stderr
+++ b/src/test/ui/type-alias-impl-trait/coherence.stderr
@@ -1,14 +1,14 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/coherence.rs:14:41
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence.rs:14:1
    |
 LL | impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
-   |                                         ^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------
+   | |                                       |
+   | |                                       `AliasOfForeignType<T>` is not defined in the current crate
+   | impl doesn't use only types from inside the current crate
    |
-note: type alias impl trait defined here
-  --> $DIR/coherence.rs:9:30
-   |
-LL | type AliasOfForeignType<T> = impl LocalTrait;
-   |                              ^^^^^^^^^^^^^^^
+   = note: define and implement a trait or new type instead
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/type-alias-impl-trait/coherence_generalization.rs b/src/test/ui/type-alias-impl-trait/coherence_generalization.rs
new file mode 100644
index 0000000000000..5c9ad9498b6de
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/coherence_generalization.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+trait Trait {}
+type Opaque<T> = impl Sized;
+fn foo<T>() -> Opaque<T> {
+    ()
+}
+
+impl<T, V> Trait for (T, V, V, u32) {}
+impl<U, V> Trait for (Opaque<U>, V, i32, V) {}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs
new file mode 100644
index 0000000000000..0efbd1c2bd5fd
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+trait Foo {
+    type Assoc;
+}
+
+impl Foo for i32 {
+    type Assoc = u32;
+}
+type ImplTrait = impl Sized;
+fn constrain() -> ImplTrait {
+    1u64
+}
+impl Foo for i64 {
+    type Assoc = ImplTrait;
+}
+
+trait Bar<T> {}
+
+impl<T: Foo> Bar<<T as Foo>::Assoc> for T {}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs
new file mode 100644
index 0000000000000..3f1a9d12b44f9
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs
@@ -0,0 +1,33 @@
+#![feature(type_alias_impl_trait)]
+
+trait Foo {}
+impl Foo for () {}
+impl Foo for i32 {}
+
+type Bar<T: Foo> = impl std::fmt::Debug;
+fn defining_use<T: Foo>() -> Bar<T> {
+    42
+}
+
+trait Bop {}
+
+impl Bop for Bar<()> {}
+
+// If the hidden type is the same, this is effectively a second impl for the same type.
+impl Bop for Bar<i32> {}
+//~^ ERROR conflicting implementations
+
+type Barr = impl std::fmt::Debug;
+fn defining_use2() -> Barr {
+    42
+}
+
+// Even completely different opaque types must conflict.
+impl Bop for Barr {}
+//~^ ERROR conflicting implementations
+
+// And obviously the hidden type must conflict, too.
+impl Bop for i32 {}
+//~^ ERROR conflicting implementations
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr
new file mode 100644
index 0000000000000..aaf75cc3db97c
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr
@@ -0,0 +1,30 @@
+error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>`
+  --> $DIR/impl_trait_for_same_tait.rs:17:1
+   |
+LL | impl Bop for Bar<()> {}
+   | -------------------- first implementation here
+...
+LL | impl Bop for Bar<i32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>`
+
+error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>`
+  --> $DIR/impl_trait_for_same_tait.rs:26:1
+   |
+LL | impl Bop for Bar<()> {}
+   | -------------------- first implementation here
+...
+LL | impl Bop for Barr {}
+   | ^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>`
+
+error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>`
+  --> $DIR/impl_trait_for_same_tait.rs:30:1
+   |
+LL | impl Bop for Bar<()> {}
+   | -------------------- first implementation here
+...
+LL | impl Bop for i32 {}
+   | ^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs
new file mode 100644
index 0000000000000..9f32c5d888b5f
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs
@@ -0,0 +1,21 @@
+// compile-flags: --crate-type=lib
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+type Alias = impl Sized;
+
+fn constrain() -> Alias {
+    1i32
+}
+
+trait HideIt {
+    type Assoc;
+}
+
+impl HideIt for () {
+    type Assoc = Alias;
+}
+
+pub trait Yay {}
+
+impl Yay for <() as HideIt>::Assoc {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs
new file mode 100644
index 0000000000000..8ec20acef4de6
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs
@@ -0,0 +1,19 @@
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+
+type Foo = impl Debug;
+pub trait Yay { }
+impl Yay for Foo { }
+
+fn foo() {
+    is_yay::<u32>();   //~ ERROR: the trait bound `u32: Yay` is not satisfied
+    is_debug::<u32>(); // OK
+    is_yay::<Foo>();   // OK
+    is_debug::<Foo>(); // OK
+}
+
+fn is_yay<T: Yay>() { }
+fn is_debug<T: Debug>() { }
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr
new file mode 100644
index 0000000000000..1c83105a18aff
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `u32: Yay` is not satisfied
+  --> $DIR/impl_trait_for_tait_bound.rs:10:14
+   |
+LL |     is_yay::<u32>();
+   |              ^^^ the trait `Yay` is not implemented for `u32`
+   |
+   = help: the trait `Yay` is implemented for `Foo`
+note: required by a bound in `is_yay`
+  --> $DIR/impl_trait_for_tait_bound.rs:16:14
+   |
+LL | fn is_yay<T: Yay>() { }
+   |              ^^^ required by this bound in `is_yay`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs
new file mode 100644
index 0000000000000..a4b8c2d190db9
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs
@@ -0,0 +1,16 @@
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+
+type Foo = impl Debug;
+
+pub trait Yay { }
+impl Yay for u32 { }
+
+fn foo() {
+    is_yay::<Foo>(); //~ ERROR: the trait bound `Foo: Yay` is not satisfied
+}
+
+fn is_yay<T: Yay>() { }
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr
new file mode 100644
index 0000000000000..a6440f02c27d8
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `Foo: Yay` is not satisfied
+  --> $DIR/impl_trait_for_tait_bound2.rs:11:14
+   |
+LL |     is_yay::<Foo>();
+   |              ^^^ the trait `Yay` is not implemented for `Foo`
+   |
+   = help: the trait `Yay` is implemented for `u32`
+note: required by a bound in `is_yay`
+  --> $DIR/impl_trait_for_tait_bound2.rs:14:14
+   |
+LL | fn is_yay<T: Yay>() { }
+   |              ^^^ required by this bound in `is_yay`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-65384.rs b/src/test/ui/type-alias-impl-trait/issue-65384.rs
index 9a119c4d2e0aa..9a9b2269f802e 100644
--- a/src/test/ui/type-alias-impl-trait/issue-65384.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-65384.rs
@@ -8,7 +8,7 @@ impl MyTrait for () {}
 type Bar = impl MyTrait;
 
 impl MyTrait for Bar {}
-//~^ ERROR: cannot implement trait on type alias impl trait
+//~^ ERROR: conflicting implementations of trait `MyTrait` for type `()`
 
 fn bazr() -> Bar { }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-65384.stderr b/src/test/ui/type-alias-impl-trait/issue-65384.stderr
index 41bcea27e1fa3..f6692ae320733 100644
--- a/src/test/ui/type-alias-impl-trait/issue-65384.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-65384.stderr
@@ -1,14 +1,12 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-65384.rs:10:18
+error[E0119]: conflicting implementations of trait `MyTrait` for type `()`
+  --> $DIR/issue-65384.rs:10:1
    |
+LL | impl MyTrait for () {}
+   | ------------------- first implementation here
+...
 LL | impl MyTrait for Bar {}
-   |                  ^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-65384.rs:8:12
-   |
-LL | type Bar = impl MyTrait;
-   |            ^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs
index fb56cc54d634b..b97e444c6d0e0 100644
--- a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs
@@ -1,6 +1,8 @@
 // Regression test for issue #76202
 // Tests that we don't ICE when we have a trait impl on a TAIT.
 
+// check-pass
+
 #![feature(type_alias_impl_trait)]
 
 trait Dummy {}
@@ -14,7 +16,12 @@ trait Test {
 }
 
 impl Test for F {
-    //~^ ERROR cannot implement trait
+    fn test(self) {}
+}
+
+// Ok because `i32` does not implement `Dummy`,
+// so it can't possibly be the hidden type of `F`.
+impl Test for i32 {
     fn test(self) {}
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr
deleted file mode 100644
index 2d4a6854a920b..0000000000000
--- a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-76202-trait-impl-for-tait.rs:16:15
-   |
-LL | impl Test for F {
-   |               ^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-76202-trait-impl-for-tait.rs:9:10
-   |
-LL | type F = impl Dummy;
-   |          ^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs
index fa25d8f762e6c..2ba4befea2a39 100644
--- a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs
@@ -1,6 +1,8 @@
 // Regression test for issues #84660 and #86411: both are variations on #76202.
 // Tests that we don't ICE when we have an opaque type appearing anywhere in an impl header.
 
+// check-pass
+
 #![feature(type_alias_impl_trait)]
 
 trait Foo {}
@@ -12,7 +14,7 @@ trait TraitArg<T> {
     fn f();
 }
 
-impl TraitArg<Bar> for () { //~ ERROR cannot implement trait
+impl TraitArg<Bar> for () {
     fn f() {
         println!("ho");
     }
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr
deleted file mode 100644
index bb70d07be59bb..0000000000000
--- a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-84660-trait-impl-for-tait.rs:15:15
-   |
-LL | impl TraitArg<Bar> for () {
-   |               ^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-84660-trait-impl-for-tait.rs:8:12
-   |
-LL | type Bar = impl Foo;
-   |            ^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
index f12d1b6d953cd..48d4b0c96ff0a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
@@ -13,14 +13,14 @@ trait Trait<T, In> {
     fn convert(i: In) -> Self::Out;
 }
 
-impl<In, Out> Trait<Bar, In> for Out { //~ ERROR cannot implement trait
+impl<In, Out> Trait<Bar, In> for Out {
     type Out = Out;
     fn convert(_i: In) -> Self::Out {
         unreachable!();
     }
 }
 
-impl<In, Out> Trait<(), In> for Out {
+impl<In, Out> Trait<(), In> for Out { //~ ERROR conflicting implementations of trait `Trait<Bar, _>`
     type Out = In;
     fn convert(i: In) -> Self::Out {
         i
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr
index f2d600fb46c54..6a75e1bd2c0fa 100644
--- a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr
@@ -1,14 +1,12 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-84660-unsoundness.rs:16:21
+error[E0119]: conflicting implementations of trait `Trait<Bar, _>`
+  --> $DIR/issue-84660-unsoundness.rs:23:1
    |
 LL | impl<In, Out> Trait<Bar, In> for Out {
-   |                     ^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-84660-unsoundness.rs:8:12
-   |
-LL | type Bar = impl Foo;
-   |            ^^^^^^^^
+   | ------------------------------------ first implementation here
+...
+LL | impl<In, Out> Trait<(), In> for Out {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
index ebf3a99bbf9f0..b0ebdd1bfab7d 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
@@ -4,11 +4,11 @@
 use std::fmt::Debug;
 
 type FooX = impl Debug;
+//~^ ERROR unconstrained opaque type
 
 trait Foo<A> { }
 
 impl Foo<FooX> for () { }
-//~^ cannot implement trait on type alias impl trait
 
 fn foo() -> impl Foo<FooX> {
     ()
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
index 4a3fb16733e04..b1d947a9ccf4e 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
@@ -1,14 +1,10 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/nested-tait-inference3.rs:10:10
-   |
-LL | impl Foo<FooX> for () { }
-   |          ^^^^
-   |
-note: type alias impl trait defined here
+error: unconstrained opaque type
   --> $DIR/nested-tait-inference3.rs:6:13
    |
 LL | type FooX = impl Debug;
    |             ^^^^^^^^^^
+   |
+   = note: `FooX` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr
index 53050cf539eaf..6381ae874ba81 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 53050cf539eaf..6381ae874ba81 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 65d866c716e0e..d52a92b8888e8 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 28ae1c0688c8e..d8bffd4f9cf3e 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 dfae6cc75d9c6..71534818141ca 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 445f14d65e3ce..7b4d2454994d7 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 26804216d9da7..dfa0c04836eb3 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/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 78e83880e1a61..e111c7d229151 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 5c595f74eff26..6bcf0bbd7eb75 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/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 65722f142aa69..d183e28f667c0 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -37,6 +37,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: Option<
                 ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
                 ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
                 ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {predicate:#?}"),
+                ty::PredicateKind::Ambiguous => panic!("ambiguous predicate on function: {predicate:#?}"),
             }
         }
         match predicates.parent {
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index d5611082f0103..414e767690bd0 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) => {