about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-16 08:33:11 +0000
committerbors <bors@rust-lang.org>2024-07-16 08:33:11 +0000
commit5572759b8d7012fa34eba47f4885c76fa06d9251 (patch)
tree674eeadfd4890cf8c33438f7eb4cb3d4f069cab9
parent2823cfb1e5fb0cfa9b2ef13c4b9dcef5b979ebd1 (diff)
parent658a13d2d1f76ac5cf083847085a7b56b4016dde (diff)
Auto merge of #127796 - tgross35:rollup-ubo5hzb, r=tgross35
Rollup of 6 pull requests

Successful merges:

 - #120990 (Suggest a borrow when using dbg)
 - #127047 (fix least significant digits of f128 associated constants)
 - #127709 (match lowering: Move `MatchPair` tree creation to its own module)
 - #127770 (Update books)
 - #127780 (Make sure trait def ids match before zipping args in `note_function_argument_obligation`)
 - #127795 (Fix typos in RELEASES.md)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--RELEASES.md8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs65
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs254
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs21
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs242
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs1
-rw-r--r--library/core/src/num/f128.rs6
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/embedded-book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--tests/crashes/126416.rs20
-rw-r--r--tests/ui/borrowck/dbg-issue-120327.rs68
-rw-r--r--tests/ui/borrowck/dbg-issue-120327.stderr117
-rw-r--r--tests/ui/methods/filter-relevant-fn-bounds.rs23
-rw-r--r--tests/ui/methods/filter-relevant-fn-bounds.stderr74
-rw-r--r--tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr4
19 files changed, 629 insertions, 274 deletions
diff --git a/RELEASES.md b/RELEASES.md
index 9e658568dc9..0ecd472efb6 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -67,7 +67,7 @@ Stabilized APIs
 - [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add)
 - [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub)
 - [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub)
-- [`NonNull:offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
+- [`NonNull::offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
 - [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from)
 - [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read)
 - [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile)
@@ -91,9 +91,9 @@ Stabilized APIs
 - [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii)
 - [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start)
 - [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end)
-- [`<[AsciiChar]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
-- [`<[AsciiChar]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
-- [`<[AsciiChar]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
+- [`<[u8]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
+- [`<[u8]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
+- [`<[u8]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
 - [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS)
 - [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits)
 - [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits)
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 1cb74849017..c7f6840e401 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -4,7 +4,7 @@
 #![allow(rustc::untranslatable_diagnostic)]
 
 use either::Either;
-use hir::ClosureKind;
+use hir::{ClosureKind, Path};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
@@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::tcx::PlaceTy;
+use rustc_middle::mir::VarDebugInfoContents;
 use rustc_middle::mir::{
     self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
     FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
@@ -546,7 +547,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     self.suggest_cloning(err, ty, expr, None, Some(move_spans));
                 }
             }
-            if let Some(pat) = finder.pat {
+
+            self.suggest_ref_for_dbg_args(expr, place, move_span, err);
+
+            // it's useless to suggest inserting `ref` when the span don't comes from local code
+            if let Some(pat) = finder.pat
+                && !move_span.is_dummy()
+                && !self.infcx.tcx.sess.source_map().is_imported(move_span)
+            {
                 *in_pattern = true;
                 let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
                 if let Some(pat) = finder.parent_pat {
@@ -561,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         }
     }
 
+    // for dbg!(x) which may take ownership, suggest dbg!(&x) instead
+    // but here we actually do not check whether the macro name is `dbg!`
+    // so that we may extend the scope a bit larger to cover more cases
+    fn suggest_ref_for_dbg_args(
+        &self,
+        body: &hir::Expr<'_>,
+        place: &Place<'tcx>,
+        move_span: Span,
+        err: &mut Diag<'infcx>,
+    ) {
+        let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
+            VarDebugInfoContents::Place(ref p) => p == place,
+            _ => false,
+        });
+        let arg_name = if let Some(var_info) = var_info {
+            var_info.name
+        } else {
+            return;
+        };
+        struct MatchArgFinder {
+            expr_span: Span,
+            match_arg_span: Option<Span>,
+            arg_name: Symbol,
+        }
+        impl Visitor<'_> for MatchArgFinder {
+            fn visit_expr(&mut self, e: &hir::Expr<'_>) {
+                // dbg! is expanded into a match pattern, we need to find the right argument span
+                if let hir::ExprKind::Match(expr, ..) = &e.kind
+                    && let hir::ExprKind::Path(hir::QPath::Resolved(
+                        _,
+                        path @ Path { segments: [seg], .. },
+                    )) = &expr.kind
+                    && seg.ident.name == self.arg_name
+                    && self.expr_span.source_callsite().contains(expr.span)
+                {
+                    self.match_arg_span = Some(path.span);
+                }
+                hir::intravisit::walk_expr(self, e);
+            }
+        }
+
+        let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
+        finder.visit_expr(body);
+        if let Some(macro_arg_span) = finder.match_arg_span {
+            err.span_suggestion_verbose(
+                macro_arg_span.shrink_to_lo(),
+                "consider borrowing instead of transferring ownership",
+                "&",
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     fn report_use_of_uninitialized(
         &self,
         mpi: MovePathIndex,
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
new file mode 100644
index 00000000000..2f540478674
--- /dev/null
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -0,0 +1,254 @@
+use rustc_middle::mir::*;
+use rustc_middle::thir::{self, *};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
+
+use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
+use crate::build::matches::{FlatPat, MatchPair, TestCase};
+use crate::build::Builder;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Builds and returns [`MatchPair`] trees, one for each pattern in
+    /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or
+    /// [`PatKind::Leaf`].
+    ///
+    /// Used internally by [`MatchPair::new`].
+    fn field_match_pairs<'pat>(
+        &mut self,
+        place: PlaceBuilder<'tcx>,
+        subpatterns: &'pat [FieldPat<'tcx>],
+    ) -> Vec<MatchPair<'pat, 'tcx>> {
+        subpatterns
+            .iter()
+            .map(|fieldpat| {
+                let place =
+                    place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
+                MatchPair::new(place, &fieldpat.pattern, self)
+            })
+            .collect()
+    }
+
+    /// Builds [`MatchPair`] trees for the prefix/middle/suffix parts of an
+    /// array pattern or slice pattern, and adds those trees to `match_pairs`.
+    ///
+    /// Used internally by [`MatchPair::new`].
+    fn prefix_slice_suffix<'pat>(
+        &mut self,
+        match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
+        place: &PlaceBuilder<'tcx>,
+        prefix: &'pat [Box<Pat<'tcx>>],
+        opt_slice: &'pat Option<Box<Pat<'tcx>>>,
+        suffix: &'pat [Box<Pat<'tcx>>],
+    ) {
+        let tcx = self.tcx;
+        let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
+            match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
+                ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
+                _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+            }
+        } else {
+            ((prefix.len() + suffix.len()).try_into().unwrap(), false)
+        };
+
+        match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
+            let elem =
+                ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
+            MatchPair::new(place.clone_project(elem), subpattern, self)
+        }));
+
+        if let Some(subslice_pat) = opt_slice {
+            let suffix_len = suffix.len() as u64;
+            let subslice = place.clone_project(PlaceElem::Subslice {
+                from: prefix.len() as u64,
+                to: if exact_size { min_length - suffix_len } else { suffix_len },
+                from_end: !exact_size,
+            });
+            match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
+        }
+
+        match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
+            let end_offset = (idx + 1) as u64;
+            let elem = ProjectionElem::ConstantIndex {
+                offset: if exact_size { min_length - end_offset } else { end_offset },
+                min_length,
+                from_end: !exact_size,
+            };
+            let place = place.clone_project(elem);
+            MatchPair::new(place, subpattern, self)
+        }));
+    }
+}
+
+impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
+    /// Recursively builds a `MatchPair` tree for the given pattern and its
+    /// subpatterns.
+    pub(in crate::build) fn new(
+        mut place_builder: PlaceBuilder<'tcx>,
+        pattern: &'pat Pat<'tcx>,
+        cx: &mut Builder<'_, 'tcx>,
+    ) -> MatchPair<'pat, 'tcx> {
+        // Force the place type to the pattern's type.
+        // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
+        if let Some(resolved) = place_builder.resolve_upvar(cx) {
+            place_builder = resolved;
+        }
+
+        // Only add the OpaqueCast projection if the given place is an opaque type and the
+        // expected type from the pattern is not.
+        let may_need_cast = match place_builder.base() {
+            PlaceBase::Local(local) => {
+                let ty =
+                    Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
+                ty != pattern.ty && ty.has_opaque_types()
+            }
+            _ => true,
+        };
+        if may_need_cast {
+            place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
+        }
+
+        let place = place_builder.try_to_place(cx);
+        let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
+        let mut subpairs = Vec::new();
+        let test_case = match pattern.kind {
+            PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
+
+            PatKind::Or { ref pats } => TestCase::Or {
+                pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
+            },
+
+            PatKind::Range(ref range) => {
+                if range.is_full_range(cx.tcx) == Some(true) {
+                    default_irrefutable()
+                } else {
+                    TestCase::Range(range)
+                }
+            }
+
+            PatKind::Constant { value } => TestCase::Constant { value },
+
+            PatKind::AscribeUserType {
+                ascription: thir::Ascription { ref annotation, variance },
+                ref subpattern,
+                ..
+            } => {
+                // Apply the type ascription to the value at `match_pair.place`
+                let ascription = place.map(|source| super::Ascription {
+                    annotation: annotation.clone(),
+                    source,
+                    variance,
+                });
+
+                subpairs.push(MatchPair::new(place_builder, subpattern, cx));
+                TestCase::Irrefutable { ascription, binding: None }
+            }
+
+            PatKind::Binding { mode, var, ref subpattern, .. } => {
+                let binding = place.map(|source| super::Binding {
+                    span: pattern.span,
+                    source,
+                    var_id: var,
+                    binding_mode: mode,
+                });
+
+                if let Some(subpattern) = subpattern.as_ref() {
+                    // this is the `x @ P` case; have to keep matching against `P` now
+                    subpairs.push(MatchPair::new(place_builder, subpattern, cx));
+                }
+                TestCase::Irrefutable { ascription: None, binding }
+            }
+
+            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
+                // Apply a type ascription for the inline constant to the value at `match_pair.place`
+                let ascription = place.map(|source| {
+                    let span = pattern.span;
+                    let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
+                    let args = ty::InlineConstArgs::new(
+                        cx.tcx,
+                        ty::InlineConstArgsParts {
+                            parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
+                            ty: cx.infcx.next_ty_var(span),
+                        },
+                    )
+                    .args;
+                    let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
+                        def.to_def_id(),
+                        ty::UserArgs { args, user_self_ty: None },
+                    ));
+                    let annotation = ty::CanonicalUserTypeAnnotation {
+                        inferred_ty: pattern.ty,
+                        span,
+                        user_ty: Box::new(user_ty),
+                    };
+                    super::Ascription { annotation, source, variance: ty::Contravariant }
+                });
+
+                subpairs.push(MatchPair::new(place_builder, pattern, cx));
+                TestCase::Irrefutable { ascription, binding: None }
+            }
+
+            PatKind::Array { ref prefix, ref slice, ref suffix } => {
+                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
+                default_irrefutable()
+            }
+            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
+                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
+
+                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
+                    default_irrefutable()
+                } else {
+                    TestCase::Slice {
+                        len: prefix.len() + suffix.len(),
+                        variable_length: slice.is_some(),
+                    }
+                }
+            }
+
+            PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
+                let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
+                subpairs = cx.field_match_pairs(downcast_place, subpatterns);
+
+                let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
+                    i == variant_index || {
+                        (cx.tcx.features().exhaustive_patterns
+                            || cx.tcx.features().min_exhaustive_patterns)
+                            && !v
+                                .inhabited_predicate(cx.tcx, adt_def)
+                                .instantiate(cx.tcx, args)
+                                .apply_ignore_module(cx.tcx, cx.param_env)
+                    }
+                }) && (adt_def.did().is_local()
+                    || !adt_def.is_variant_list_non_exhaustive());
+                if irrefutable {
+                    default_irrefutable()
+                } else {
+                    TestCase::Variant { adt_def, variant_index }
+                }
+            }
+
+            PatKind::Leaf { ref subpatterns } => {
+                subpairs = cx.field_match_pairs(place_builder, subpatterns);
+                default_irrefutable()
+            }
+
+            PatKind::Deref { ref subpattern } => {
+                subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
+                default_irrefutable()
+            }
+
+            PatKind::DerefPattern { ref subpattern, mutability } => {
+                // Create a new temporary for each deref pattern.
+                // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
+                let temp = cx.temp(
+                    Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
+                    pattern.span,
+                );
+                subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
+                TestCase::Deref { temp, mutability }
+            }
+
+            PatKind::Never => TestCase::Never,
+        };
+
+        MatchPair { place, test_case, subpairs, pattern }
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 841ef2719c9..98de4df3ce3 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -24,6 +24,7 @@ use tracing::{debug, instrument};
 use util::visit_bindings;
 
 // helper functions, broken out by category:
+mod match_pair;
 mod simplify;
 mod test;
 mod util;
@@ -1195,17 +1196,27 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> {
     }
 }
 
+/// Node in a tree of "match pairs", where each pair consists of a place to be
+/// tested, and a test to perform on that place.
+///
+/// Each node also has a list of subpairs (possibly empty) that must also match,
+/// and a reference to the THIR pattern it represents.
 #[derive(Debug, Clone)]
 pub(crate) struct MatchPair<'pat, 'tcx> {
     /// This place...
-    // This can be `None` if it referred to a non-captured place in a closure.
-    // Invariant: place.is_none() => test_case is Irrefutable
-    // In other words this must be `Some(_)` after simplification.
+    ///
+    /// ---
+    /// This can be `None` if it referred to a non-captured place in a closure.
+    ///
+    /// Invariant: Can only be `None` when `test_case` is `Irrefutable`.
+    /// Therefore this must be `Some(_)` after simplification.
     place: Option<Place<'tcx>>,
 
     /// ... must pass this test...
-    // Invariant: after creation and simplification in `Candidate::new()`, this must not be
-    // `Irrefutable`.
+    ///
+    /// ---
+    /// Invariant: after creation and simplification in [`FlatPat::new`],
+    /// this must not be [`TestCase::Irrefutable`].
     test_case: TestCase<'pat, 'tcx>,
 
     /// ... and these subpairs must match.
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 3bec154e1df..e67fc843285 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,78 +1,15 @@
 use std::marker::PhantomData;
 
-use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
+use crate::build::expr::as_place::PlaceBase;
 use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
 use crate::build::Builder;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_middle::mir::*;
-use rustc_middle::thir::{self, *};
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::Ty;
 use rustc_span::Span;
 use tracing::debug;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    pub(crate) fn field_match_pairs<'pat>(
-        &mut self,
-        place: PlaceBuilder<'tcx>,
-        subpatterns: &'pat [FieldPat<'tcx>],
-    ) -> Vec<MatchPair<'pat, 'tcx>> {
-        subpatterns
-            .iter()
-            .map(|fieldpat| {
-                let place =
-                    place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
-                MatchPair::new(place, &fieldpat.pattern, self)
-            })
-            .collect()
-    }
-
-    pub(crate) fn prefix_slice_suffix<'pat>(
-        &mut self,
-        match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
-        place: &PlaceBuilder<'tcx>,
-        prefix: &'pat [Box<Pat<'tcx>>],
-        opt_slice: &'pat Option<Box<Pat<'tcx>>>,
-        suffix: &'pat [Box<Pat<'tcx>>],
-    ) {
-        let tcx = self.tcx;
-        let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
-            match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
-                ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
-                _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
-            }
-        } else {
-            ((prefix.len() + suffix.len()).try_into().unwrap(), false)
-        };
-
-        match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
-            let elem =
-                ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
-            MatchPair::new(place.clone_project(elem), subpattern, self)
-        }));
-
-        if let Some(subslice_pat) = opt_slice {
-            let suffix_len = suffix.len() as u64;
-            let subslice = place.clone_project(PlaceElem::Subslice {
-                from: prefix.len() as u64,
-                to: if exact_size { min_length - suffix_len } else { suffix_len },
-                from_end: !exact_size,
-            });
-            match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
-        }
-
-        match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
-            let end_offset = (idx + 1) as u64;
-            let elem = ProjectionElem::ConstantIndex {
-                offset: if exact_size { min_length - end_offset } else { end_offset },
-                min_length,
-                from_end: !exact_size,
-            };
-            let place = place.clone_project(elem);
-            MatchPair::new(place, subpattern, self)
-        }));
-    }
-
     /// Creates a false edge to `imaginary_target` and a real edge to
     /// real_target. If `imaginary_target` is none, or is the same as the real
     /// target, a Goto is generated instead to simplify the generated MIR.
@@ -96,181 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     }
 }
 
-impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
-    /// Recursively builds a `MatchPair` tree for the given pattern and its
-    /// subpatterns.
-    pub(in crate::build) fn new(
-        mut place_builder: PlaceBuilder<'tcx>,
-        pattern: &'pat Pat<'tcx>,
-        cx: &mut Builder<'_, 'tcx>,
-    ) -> MatchPair<'pat, 'tcx> {
-        // Force the place type to the pattern's type.
-        // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
-        if let Some(resolved) = place_builder.resolve_upvar(cx) {
-            place_builder = resolved;
-        }
-
-        // Only add the OpaqueCast projection if the given place is an opaque type and the
-        // expected type from the pattern is not.
-        let may_need_cast = match place_builder.base() {
-            PlaceBase::Local(local) => {
-                let ty =
-                    Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
-                ty != pattern.ty && ty.has_opaque_types()
-            }
-            _ => true,
-        };
-        if may_need_cast {
-            place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
-        }
-
-        let place = place_builder.try_to_place(cx);
-        let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
-        let mut subpairs = Vec::new();
-        let test_case = match pattern.kind {
-            PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
-
-            PatKind::Or { ref pats } => TestCase::Or {
-                pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
-            },
-
-            PatKind::Range(ref range) => {
-                if range.is_full_range(cx.tcx) == Some(true) {
-                    default_irrefutable()
-                } else {
-                    TestCase::Range(range)
-                }
-            }
-
-            PatKind::Constant { value } => TestCase::Constant { value },
-
-            PatKind::AscribeUserType {
-                ascription: thir::Ascription { ref annotation, variance },
-                ref subpattern,
-                ..
-            } => {
-                // Apply the type ascription to the value at `match_pair.place`
-                let ascription = place.map(|source| super::Ascription {
-                    annotation: annotation.clone(),
-                    source,
-                    variance,
-                });
-
-                subpairs.push(MatchPair::new(place_builder, subpattern, cx));
-                TestCase::Irrefutable { ascription, binding: None }
-            }
-
-            PatKind::Binding { mode, var, ref subpattern, .. } => {
-                let binding = place.map(|source| super::Binding {
-                    span: pattern.span,
-                    source,
-                    var_id: var,
-                    binding_mode: mode,
-                });
-
-                if let Some(subpattern) = subpattern.as_ref() {
-                    // this is the `x @ P` case; have to keep matching against `P` now
-                    subpairs.push(MatchPair::new(place_builder, subpattern, cx));
-                }
-                TestCase::Irrefutable { ascription: None, binding }
-            }
-
-            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
-                // Apply a type ascription for the inline constant to the value at `match_pair.place`
-                let ascription = place.map(|source| {
-                    let span = pattern.span;
-                    let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
-                    let args = ty::InlineConstArgs::new(
-                        cx.tcx,
-                        ty::InlineConstArgsParts {
-                            parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
-                            ty: cx.infcx.next_ty_var(span),
-                        },
-                    )
-                    .args;
-                    let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
-                        def.to_def_id(),
-                        ty::UserArgs { args, user_self_ty: None },
-                    ));
-                    let annotation = ty::CanonicalUserTypeAnnotation {
-                        inferred_ty: pattern.ty,
-                        span,
-                        user_ty: Box::new(user_ty),
-                    };
-                    super::Ascription { annotation, source, variance: ty::Contravariant }
-                });
-
-                subpairs.push(MatchPair::new(place_builder, pattern, cx));
-                TestCase::Irrefutable { ascription, binding: None }
-            }
-
-            PatKind::Array { ref prefix, ref slice, ref suffix } => {
-                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
-                default_irrefutable()
-            }
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
-
-                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
-                    default_irrefutable()
-                } else {
-                    TestCase::Slice {
-                        len: prefix.len() + suffix.len(),
-                        variable_length: slice.is_some(),
-                    }
-                }
-            }
-
-            PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
-                let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
-                subpairs = cx.field_match_pairs(downcast_place, subpatterns);
-
-                let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
-                    i == variant_index || {
-                        (cx.tcx.features().exhaustive_patterns
-                            || cx.tcx.features().min_exhaustive_patterns)
-                            && !v
-                                .inhabited_predicate(cx.tcx, adt_def)
-                                .instantiate(cx.tcx, args)
-                                .apply_ignore_module(cx.tcx, cx.param_env)
-                    }
-                }) && (adt_def.did().is_local()
-                    || !adt_def.is_variant_list_non_exhaustive());
-                if irrefutable {
-                    default_irrefutable()
-                } else {
-                    TestCase::Variant { adt_def, variant_index }
-                }
-            }
-
-            PatKind::Leaf { ref subpatterns } => {
-                subpairs = cx.field_match_pairs(place_builder, subpatterns);
-                default_irrefutable()
-            }
-
-            PatKind::Deref { ref subpattern } => {
-                subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
-                default_irrefutable()
-            }
-
-            PatKind::DerefPattern { ref subpattern, mutability } => {
-                // Create a new temporary for each deref pattern.
-                // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
-                let temp = cx.temp(
-                    Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
-                    pattern.span,
-                );
-                subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
-                TestCase::Deref { temp, mutability }
-            }
-
-            PatKind::Never => TestCase::Never,
-        };
-
-        MatchPair { place, test_case, subpairs, pattern }
-    }
-}
-
 /// Determine the set of places that have to be stable across match guards.
 ///
 /// Returns a list of places that need a fake borrow along with a local to store it.
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 2cf808f962f..f8843b892db 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3810,6 +3810,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             {
                 if let Some(where_pred) = where_pred.as_trait_clause()
                     && let Some(failed_pred) = failed_pred.as_trait_clause()
+                    && where_pred.def_id() == failed_pred.def_id()
                 {
                     self.enter_forall(where_pred, |where_pred| {
                         let failed_pred = self.instantiate_binder_with_fresh_vars(
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 002a41b5669..05dc1e97852 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -170,7 +170,7 @@ impl f128 {
     /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
     /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
     #[unstable(feature = "f128", issue = "116909")]
-    pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128;
+    pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128;
 
     /// Smallest finite `f128` value.
     ///
@@ -178,7 +178,7 @@ impl f128 {
     ///
     /// [`MAX`]: f128::MAX
     #[unstable(feature = "f128", issue = "116909")]
-    pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128;
+    pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128;
     /// Smallest positive normal `f128` value.
     ///
     /// Equal to 2<sup>[`MIN_EXP`]&nbsp;&minus;&nbsp;1</sup>.
@@ -194,7 +194,7 @@ impl f128 {
     /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
     /// [`MAX_EXP`]: f128::MAX_EXP
     #[unstable(feature = "f128", issue = "116909")]
-    pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128;
+    pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128;
 
     /// One greater than the minimum possible normal power of 2 exponent.
     ///
diff --git a/src/doc/book b/src/doc/book
-Subproject f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc6
+Subproject 67fa536768013d9d5a13f3a06790521d511ef71
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 941db8b3df45fd46cd87b50a5c86714b91dcde9
+Subproject 5454de3d12b9ccc6375b629cf7ccda8264640aa
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject b10c6acaf0f43481f6600e95d4b5013446e29f7
+Subproject 019f3928d8b939ec71b63722dcc2e4633015644
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 1ae3deebc3ac16e276b6558e01420f8e605def0
+Subproject e2f0bdc4031866734661dcdb548184bde1450ba
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 658c6c27cb975b92227936024816986c2d3716f
+Subproject 89aecb6951b77bc746da73df8c9f2b2ceaad494
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject d6e3a32a557db5902e714604def8015d6bb7e0f
+Subproject 0c4d55cb59fe440d1a630e4e5774d043968edb3
diff --git a/tests/crashes/126416.rs b/tests/crashes/126416.rs
deleted file mode 100644
index 9b6c5169d44..00000000000
--- a/tests/crashes/126416.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ known-bug: rust-lang/rust#126416
-
-trait Output<'a, T: 'a> {
-    type Type;
-}
-
-struct Wrapper;
-
-impl Wrapper {
-    fn do_something_wrapper<O, F>(&mut self, _: F)
-    where
-        F: for<'a> FnOnce(<F as Output<i32>>::Type),
-    {
-    }
-}
-
-fn main() {
-    let mut wrapper = Wrapper;
-    wrapper.do_something_wrapper(|value| ());
-}
diff --git a/tests/ui/borrowck/dbg-issue-120327.rs b/tests/ui/borrowck/dbg-issue-120327.rs
new file mode 100644
index 00000000000..2de43f63487
--- /dev/null
+++ b/tests/ui/borrowck/dbg-issue-120327.rs
@@ -0,0 +1,68 @@
+fn s() -> String {
+    let a = String::new();
+    dbg!(a);
+    return a; //~ ERROR use of moved value:
+}
+
+fn m() -> String {
+    let a = String::new();
+    dbg!(1, 2, a, 1, 2);
+    return a; //~ ERROR use of moved value:
+}
+
+fn t(a: String) -> String {
+    let b: String = "".to_string();
+    dbg!(a, b);
+    return b; //~ ERROR use of moved value:
+}
+
+fn x(a: String) -> String {
+    let b: String = "".to_string();
+    dbg!(a, b);
+    return a; //~ ERROR use of moved value:
+}
+
+macro_rules! my_dbg {
+    () => {
+        eprintln!("[{}:{}:{}]", file!(), line!(), column!())
+    };
+    ($val:expr $(,)?) => {
+        match $val {
+            tmp => {
+                eprintln!("[{}:{}:{}] {} = {:#?}",
+                    file!(), line!(), column!(), stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($(my_dbg!($val)),+,)
+    };
+}
+
+fn test_my_dbg() -> String {
+    let b: String = "".to_string();
+    my_dbg!(b, 1);
+    return b; //~ ERROR use of moved value:
+}
+
+fn test_not_macro() -> String {
+    let a = String::new();
+    let _b = match a {
+        tmp => {
+            eprintln!("dbg: {}", tmp);
+            tmp
+        }
+    };
+    return a; //~ ERROR use of moved value:
+}
+
+fn get_expr(_s: String) {}
+
+fn test() {
+    let a: String = "".to_string();
+    let _res = get_expr(dbg!(a));
+    let _l = a.len(); //~ ERROR borrow of moved value
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/dbg-issue-120327.stderr b/tests/ui/borrowck/dbg-issue-120327.stderr
new file mode 100644
index 00000000000..efacc0c3f13
--- /dev/null
+++ b/tests/ui/borrowck/dbg-issue-120327.stderr
@@ -0,0 +1,117 @@
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:4:12
+   |
+LL |     let a = String::new();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     dbg!(a);
+   |     ------- value moved here
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(&a);
+   |          +
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:10:12
+   |
+LL |     let a = String::new();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     dbg!(1, 2, a, 1, 2);
+   |     ------------------- value moved here
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(1, 2, &a, 1, 2);
+   |                +
+
+error[E0382]: use of moved value: `b`
+  --> $DIR/dbg-issue-120327.rs:16:12
+   |
+LL |     let b: String = "".to_string();
+   |         - move occurs because `b` has type `String`, which does not implement the `Copy` trait
+LL |     dbg!(a, b);
+   |     ---------- value moved here
+LL |     return b;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(a, &b);
+   |             +
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:22:12
+   |
+LL | fn x(a: String) -> String {
+   |      - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     let b: String = "".to_string();
+LL |     dbg!(a, b);
+   |     ---------- value moved here
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(&a, b);
+   |          +
+
+error[E0382]: use of moved value: `b`
+  --> $DIR/dbg-issue-120327.rs:46:12
+   |
+LL |             tmp => {
+   |             --- value moved here
+...
+LL |     let b: String = "".to_string();
+   |         - move occurs because `b` has type `String`, which does not implement the `Copy` trait
+LL |     my_dbg!(b, 1);
+LL |     return b;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     my_dbg!(&b, 1);
+   |             +
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |             ref tmp => {
+   |             +++
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:57:12
+   |
+LL |     let a = String::new();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     let _b = match a {
+LL |         tmp => {
+   |         --- value moved here
+...
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref tmp => {
+   |         +++
+
+error[E0382]: borrow of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:65:14
+   |
+LL |     let a: String = "".to_string();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     let _res = get_expr(dbg!(a));
+   |                         ------- value moved here
+LL |     let _l = a.len();
+   |              ^ value borrowed here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     let _res = get_expr(dbg!(&a));
+   |                              +
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/methods/filter-relevant-fn-bounds.rs b/tests/ui/methods/filter-relevant-fn-bounds.rs
new file mode 100644
index 00000000000..76ececf7baa
--- /dev/null
+++ b/tests/ui/methods/filter-relevant-fn-bounds.rs
@@ -0,0 +1,23 @@
+trait Output<'a> {
+    type Type;
+}
+
+struct Wrapper;
+
+impl Wrapper {
+    fn do_something_wrapper<O, F>(self, _: F)
+    //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
+    //~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
+    where
+        F: for<'a> FnOnce(<F as Output<'a>>::Type),
+        //~^ ERROR the trait bound `F: Output<'_>` is not satisfied
+        //~| ERROR the trait bound `F: Output<'_>` is not satisfied
+    {
+    }
+}
+
+fn main() {
+    let mut wrapper = Wrapper;
+    wrapper.do_something_wrapper(|value| ());
+    //~^ ERROR expected a `FnOnce
+}
diff --git a/tests/ui/methods/filter-relevant-fn-bounds.stderr b/tests/ui/methods/filter-relevant-fn-bounds.stderr
new file mode 100644
index 00000000000..b737c0ab11f
--- /dev/null
+++ b/tests/ui/methods/filter-relevant-fn-bounds.stderr
@@ -0,0 +1,74 @@
+error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
+  --> $DIR/filter-relevant-fn-bounds.rs:8:5
+   |
+LL | /     fn do_something_wrapper<O, F>(self, _: F)
+LL | |
+LL | |
+LL | |     where
+LL | |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
+   | |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F`
+   |
+help: consider further restricting this bound
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
+   |                                                    ++++++++++++++++++++
+
+error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
+  --> $DIR/filter-relevant-fn-bounds.rs:8:8
+   |
+LL |     fn do_something_wrapper<O, F>(self, _: F)
+   |        ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F`
+   |
+help: consider further restricting this bound
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
+   |                                                    ++++++++++++++++++++
+
+error[E0277]: the trait bound `F: Output<'_>` is not satisfied
+  --> $DIR/filter-relevant-fn-bounds.rs:12:12
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
+   |
+help: consider further restricting this bound
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
+   |                                                    ++++++++++++
+
+error[E0277]: the trait bound `F: Output<'_>` is not satisfied
+  --> $DIR/filter-relevant-fn-bounds.rs:12:20
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
+   |
+help: consider further restricting this bound
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
+   |                                                    ++++++++++++
+
+error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
+  --> $DIR/filter-relevant-fn-bounds.rs:21:34
+   |
+LL |     wrapper.do_something_wrapper(|value| ());
+   |             -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
+   |             |
+   |             required by a bound introduced by this call
+   |
+   = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
+help: this trait has no implementations, consider adding one
+  --> $DIR/filter-relevant-fn-bounds.rs:1:1
+   |
+LL | trait Output<'a> {
+   | ^^^^^^^^^^^^^^^^
+note: required by a bound in `Wrapper::do_something_wrapper`
+  --> $DIR/filter-relevant-fn-bounds.rs:12:12
+   |
+LL |     fn do_something_wrapper<O, F>(self, _: F)
+   |        -------------------- required by a bound in this associated function
+...
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
index c2b9899e20d..f515cb62c7c 100644
--- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
+++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
@@ -9,6 +9,10 @@ LL |     let _ = dbg!(a);
    |             ^^^^^^^ value used here after move
    |
    = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing instead of transferring ownership
+   |
+LL |     let _ = dbg!(&a);
+   |                  +
 
 error: aborting due to 1 previous error