about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/borrowck_errors.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs174
-rw-r--r--compiler/rustc_hir/src/hir.rs39
-rw-r--r--tests/ui/async-await/feature-self-return-type.stderr1
-rw-r--r--tests/ui/async-await/issue-61949-self-return-type.stderr1
-rw-r--r--tests/ui/borrowck/issue-109271-pass-self-into-closure.fixed39
-rw-r--r--tests/ui/borrowck/issue-109271-pass-self-into-closure.rs39
-rw-r--r--tests/ui/borrowck/issue-109271-pass-self-into-closure.stderr85
-rw-r--r--tests/ui/consts/const-eval/generic-slice.stderr4
-rw-r--r--tests/ui/generator/auto-trait-regions.drop_tracking.stderr12
-rw-r--r--tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr12
-rw-r--r--tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr12
-rw-r--r--tests/ui/generator/auto-trait-regions.stderr47
-rw-r--r--tests/ui/lifetimes/issue-69314.stderr2
-rw-r--r--tests/ui/nll/user-annotations/adt-brace-enums.stderr4
-rw-r--r--tests/ui/nll/user-annotations/adt-brace-structs.stderr4
-rw-r--r--tests/ui/nll/user-annotations/adt-nullary-enums.stderr5
-rw-r--r--tests/ui/nll/user-annotations/adt-tuple-enums.stderr4
-rw-r--r--tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr9
-rw-r--r--tests/ui/nll/user-annotations/adt-tuple-struct.stderr4
-rw-r--r--tests/ui/nll/user-annotations/fns.stderr4
-rw-r--r--tests/ui/nll/user-annotations/method-call.stderr2
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-3.stderr2
-rw-r--r--tests/ui/static/issue-18118.stderr2
24 files changed, 425 insertions, 83 deletions
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 2bbb9618dbf..acca1a1477f 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -469,6 +469,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     #[rustc_lint_diagnostics]
+    #[track_caller]
     pub(crate) fn struct_span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index a4a3c738f47..49e74a1b000 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1,3 +1,5 @@
+use std::iter;
+
 use either::Either;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexSet;
@@ -10,27 +12,26 @@ use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::ObligationCause;
+use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
     FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
-use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
+use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty, TypeckResults};
 use rustc_middle::util::CallKind;
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::borrow_set::TwoPhaseActivation;
 use crate::borrowck_errors;
-
 use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
-use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
 use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt};
 use crate::{
     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
@@ -959,7 +960,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     &msg_borrow,
                     None,
                 );
-                self.suggest_binding_for_closure_capture_self(
+                self.suggest_binding_for_closure_capture_self(&mut err, &issued_spans);
+                self.suggest_using_closure_argument_instead_of_capture(
                     &mut err,
                     issued_borrow.borrowed_place,
                     &issued_spans,
@@ -982,6 +984,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     place,
                     issued_borrow.borrowed_place,
                 );
+                self.suggest_using_closure_argument_instead_of_capture(
+                    &mut err,
+                    issued_borrow.borrowed_place,
+                    &issued_spans,
+                );
                 err
             }
 
@@ -1268,22 +1275,161 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
-    fn suggest_binding_for_closure_capture_self(
+    /// Suggest using closure argument instead of capture.
+    ///
+    /// For example:
+    /// ```ignore (illustrative)
+    /// struct S;
+    ///
+    /// impl S {
+    ///     fn call(&mut self, f: impl Fn(&mut Self)) { /* ... */ }
+    ///     fn x(&self) {}
+    /// }
+    ///
+    ///     let mut v = S;
+    ///     v.call(|this: &mut S| v.x());
+    /// //  ^\                    ^-- help: try using the closure argument: `this`
+    /// //    *-- error: cannot borrow `v` as mutable because it is also borrowed as immutable
+    /// ```
+    fn suggest_using_closure_argument_instead_of_capture(
         &self,
         err: &mut Diagnostic,
         borrowed_place: Place<'tcx>,
         issued_spans: &UseSpans<'tcx>,
     ) {
-        let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
-        let hir = self.infcx.tcx.hir();
+        let &UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
+        let tcx = self.infcx.tcx;
+        let hir = tcx.hir();
 
-        // check whether the borrowed place is capturing `self` by mut reference
+        // Get the type of the local that we are trying to borrow
         let local = borrowed_place.local;
-        let Some(_) = self
-            .body
-            .local_decls
-            .get(local)
-            .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
+        let local_ty = self.body.local_decls[local].ty;
+
+        // Get the body the error happens in
+        let Some(body_id) = hir.get(self.mir_hir_id()).body_id() else { return };
+
+        let body_expr = hir.body(body_id).value;
+
+        struct ClosureFinder<'hir> {
+            hir: rustc_middle::hir::map::Map<'hir>,
+            borrow_span: Span,
+            res: Option<(&'hir hir::Expr<'hir>, &'hir hir::Closure<'hir>)>,
+            /// The path expression with the `borrow_span` span
+            error_path: Option<(&'hir hir::Expr<'hir>, &'hir hir::QPath<'hir>)>,
+        }
+        impl<'hir> Visitor<'hir> for ClosureFinder<'hir> {
+            type NestedFilter = OnlyBodies;
+
+            fn nested_visit_map(&mut self) -> Self::Map {
+                self.hir
+            }
+
+            fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
+                if let hir::ExprKind::Path(qpath) = &ex.kind
+                    && ex.span == self.borrow_span
+                {
+                    self.error_path = Some((ex, qpath));
+                }
+
+                if let hir::ExprKind::Closure(closure) = ex.kind
+                    && ex.span.contains(self.borrow_span)
+                    // To support cases like `|| { v.call(|this| v.get()) }`
+                    // FIXME: actually support such cases (need to figure out how to move from the capture place to original local)
+                    && self.res.as_ref().map_or(true, |(prev_res, _)| prev_res.span.contains(ex.span))
+                {
+                    self.res = Some((ex, closure));
+                }
+
+                hir::intravisit::walk_expr(self, ex);
+            }
+        }
+
+        // Find the closure that most tightly wraps `capture_kind_span`
+        let mut finder =
+            ClosureFinder { hir, borrow_span: capture_kind_span, res: None, error_path: None };
+        finder.visit_expr(body_expr);
+        let Some((closure_expr, closure)) = finder.res else { return };
+
+        let typeck_results: &TypeckResults<'_> =
+            tcx.typeck_opt_const_arg(self.body.source.with_opt_param().as_local().unwrap());
+
+        // Check that the parent of the closure is a method call,
+        // with receiver matching with local's type (modulo refs)
+        let parent = hir.parent_id(closure_expr.hir_id);
+        if let hir::Node::Expr(parent) = hir.get(parent) {
+            if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
+                let recv_ty = typeck_results.expr_ty(recv);
+
+                if recv_ty.peel_refs() != local_ty {
+                    return;
+                }
+            }
+        }
+
+        // Get closure's arguments
+        let ty::Closure(_, substs) = typeck_results.expr_ty(closure_expr).kind() else { unreachable!() };
+        let sig = substs.as_closure().sig();
+        let tupled_params =
+            tcx.erase_late_bound_regions(sig.inputs().iter().next().unwrap().map_bound(|&b| b));
+        let ty::Tuple(params) = tupled_params.kind() else { return };
+
+        // Find the first argument with a matching type, get its name
+        let Some((_, this_name)) = params
+            .iter()
+            .zip(hir.body_param_names(closure.body))
+            .find(|(param_ty, name)|{
+                // FIXME: also support deref for stuff like `Rc` arguments
+                param_ty.peel_refs() == local_ty && name != &Ident::empty()
+            })
+            else { return };
+
+        let spans;
+        if let Some((_path_expr, qpath)) = finder.error_path
+            && let hir::QPath::Resolved(_, path) = qpath
+            && let hir::def::Res::Local(local_id) = path.res
+        {
+            // Find all references to the problematic variable in this closure body
+
+            struct VariableUseFinder {
+                local_id: hir::HirId,
+                spans: Vec<Span>,
+            }
+            impl<'hir> Visitor<'hir> for VariableUseFinder {
+                fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
+                    if let hir::ExprKind::Path(qpath) = &ex.kind
+                        && let hir::QPath::Resolved(_, path) = qpath
+                        && let hir::def::Res::Local(local_id) = path.res
+                        && local_id == self.local_id
+                    {
+                        self.spans.push(ex.span);
+                    }
+
+                    hir::intravisit::walk_expr(self, ex);
+                }
+            }
+
+            let mut finder = VariableUseFinder { local_id, spans: Vec::new() };
+            finder.visit_expr(hir.body(closure.body).value);
+
+            spans = finder.spans;
+        } else {
+            spans = vec![capture_kind_span];
+        }
+
+        err.multipart_suggestion(
+            "try using the closure argument",
+            iter::zip(spans, iter::repeat(this_name.to_string())).collect(),
+            Applicability::MaybeIncorrect,
+        );
+    }
+
+    fn suggest_binding_for_closure_capture_self(
+        &self,
+        err: &mut Diagnostic,
+        issued_spans: &UseSpans<'tcx>,
+    ) {
+        let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
+        let hir = self.infcx.tcx.hir();
 
         struct ExpressionFinder<'hir> {
             capture_span: Span,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 486718ea6a0..54b328e78f8 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3529,12 +3529,20 @@ impl<'hir> OwnerNode<'hir> {
 
     pub fn body_id(&self) -> Option<BodyId> {
         match self {
-            OwnerNode::TraitItem(TraitItem {
-                kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
+            OwnerNode::Item(Item {
+                kind:
+                    ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body),
                 ..
             })
-            | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
-            | OwnerNode::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
+            | OwnerNode::TraitItem(TraitItem {
+                kind:
+                    TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)),
+                ..
+            })
+            | OwnerNode::ImplItem(ImplItem {
+                kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body),
+                ..
+            }) => Some(*body),
             _ => None,
         }
     }
@@ -3729,12 +3737,27 @@ impl<'hir> Node<'hir> {
 
     pub fn body_id(&self) -> Option<BodyId> {
         match self {
-            Node::TraitItem(TraitItem {
-                kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
+            Node::Item(Item {
+                kind:
+                    ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body),
+                ..
+            })
+            | Node::TraitItem(TraitItem {
+                kind:
+                    TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)),
+                ..
+            })
+            | Node::ImplItem(ImplItem {
+                kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body),
                 ..
             })
-            | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
-            | Node::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
+            | Node::Expr(Expr {
+                kind:
+                    ExprKind::ConstBlock(AnonConst { body, .. })
+                    | ExprKind::Closure(Closure { body, .. })
+                    | ExprKind::Repeat(_, ArrayLen::Body(AnonConst { body, .. })),
+                ..
+            }) => Some(*body),
             _ => None,
         }
     }
diff --git a/tests/ui/async-await/feature-self-return-type.stderr b/tests/ui/async-await/feature-self-return-type.stderr
index 8924683684f..747c54b6694 100644
--- a/tests/ui/async-await/feature-self-return-type.stderr
+++ b/tests/ui/async-await/feature-self-return-type.stderr
@@ -4,6 +4,7 @@ error[E0597]: `bar` does not live long enough
 LL |     let x = {
    |         - borrow later stored here
 LL |         let bar = 22;
+   |             --- binding `bar` declared here
 LL |         Foo::new(&bar).await
    |                  ^^^^ borrowed value does not live long enough
 LL |
diff --git a/tests/ui/async-await/issue-61949-self-return-type.stderr b/tests/ui/async-await/issue-61949-self-return-type.stderr
index 638b197bc02..ac85ed2887a 100644
--- a/tests/ui/async-await/issue-61949-self-return-type.stderr
+++ b/tests/ui/async-await/issue-61949-self-return-type.stderr
@@ -13,6 +13,7 @@ error[E0597]: `bar` does not live long enough
 LL |     let x = {
    |         - borrow later stored here
 LL |         let bar = 22;
+   |             --- binding `bar` declared here
 LL |         Foo::new(&bar).await
    |                  ^^^^ borrowed value does not live long enough
 LL |
diff --git a/tests/ui/borrowck/issue-109271-pass-self-into-closure.fixed b/tests/ui/borrowck/issue-109271-pass-self-into-closure.fixed
new file mode 100644
index 00000000000..4a8831dab95
--- /dev/null
+++ b/tests/ui/borrowck/issue-109271-pass-self-into-closure.fixed
@@ -0,0 +1,39 @@
+// run-rustfix
+#![allow(unused)]
+struct S;
+
+impl S {
+    fn call(&mut self, f: impl FnOnce((), &mut Self)) {
+        // change state or something ...
+        f((), self);
+        // change state or something ...
+    }
+
+    fn get(&self) {}
+    fn set(&mut self) {}
+}
+
+fn main() {
+    let mut v = S;
+
+    v.call(|(), this: &mut S| this.get());
+    //~^ error: cannot borrow `v` as mutable because it is also borrowed as immutable
+    v.call(|(), this: &mut S| this.set());
+    //~^ error: cannot borrow `v` as mutable more than once at a time
+    //~| error: cannot borrow `v` as mutable more than once at a time
+
+    v.call(|(), this: &mut S| {
+        //~^ error: cannot borrow `v` as mutable more than once at a time
+        //~| error: cannot borrow `v` as mutable more than once at a time
+
+        _ = this;
+        this.set();
+        this.get();
+        S::get(&this);
+
+        use std::ops::Add;
+        let v = 0u32;
+        _ = v + v;
+        _ = v.add(3);
+    });
+}
diff --git a/tests/ui/borrowck/issue-109271-pass-self-into-closure.rs b/tests/ui/borrowck/issue-109271-pass-self-into-closure.rs
new file mode 100644
index 00000000000..fcd855f862d
--- /dev/null
+++ b/tests/ui/borrowck/issue-109271-pass-self-into-closure.rs
@@ -0,0 +1,39 @@
+// run-rustfix
+#![allow(unused)]
+struct S;
+
+impl S {
+    fn call(&mut self, f: impl FnOnce((), &mut Self)) {
+        // change state or something ...
+        f((), self);
+        // change state or something ...
+    }
+
+    fn get(&self) {}
+    fn set(&mut self) {}
+}
+
+fn main() {
+    let mut v = S;
+
+    v.call(|(), this: &mut S| v.get());
+    //~^ error: cannot borrow `v` as mutable because it is also borrowed as immutable
+    v.call(|(), this: &mut S| v.set());
+    //~^ error: cannot borrow `v` as mutable more than once at a time
+    //~| error: cannot borrow `v` as mutable more than once at a time
+
+    v.call(|(), this: &mut S| {
+        //~^ error: cannot borrow `v` as mutable more than once at a time
+        //~| error: cannot borrow `v` as mutable more than once at a time
+
+        _ = v;
+        v.set();
+        v.get();
+        S::get(&v);
+
+        use std::ops::Add;
+        let v = 0u32;
+        _ = v + v;
+        _ = v.add(3);
+    });
+}
diff --git a/tests/ui/borrowck/issue-109271-pass-self-into-closure.stderr b/tests/ui/borrowck/issue-109271-pass-self-into-closure.stderr
new file mode 100644
index 00000000000..25974e0d008
--- /dev/null
+++ b/tests/ui/borrowck/issue-109271-pass-self-into-closure.stderr
@@ -0,0 +1,85 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/issue-109271-pass-self-into-closure.rs:19:5
+   |
+LL |     v.call(|(), this: &mut S| v.get());
+   |     ^^----^------------------^-^^^^^^^
+   |     | |    |                  |
+   |     | |    |                  first borrow occurs due to use of `v` in closure
+   |     | |    |                  help: try using the closure argument: `this`
+   |     | |    immutable borrow occurs here
+   |     | immutable borrow later used by call
+   |     mutable borrow occurs here
+
+error[E0499]: cannot borrow `v` as mutable more than once at a time
+  --> $DIR/issue-109271-pass-self-into-closure.rs:21:5
+   |
+LL |     v.call(|(), this: &mut S| v.set());
+   |     ^^----^------------------^-^^^^^^^
+   |     | |    |                  |
+   |     | |    |                  first borrow occurs due to use of `v` in closure
+   |     | |    |                  help: try using the closure argument: `this`
+   |     | |    first mutable borrow occurs here
+   |     | first borrow later used by call
+   |     second mutable borrow occurs here
+
+error[E0499]: cannot borrow `v` as mutable more than once at a time
+  --> $DIR/issue-109271-pass-self-into-closure.rs:21:12
+   |
+LL |     v.call(|(), this: &mut S| v.set());
+   |     -------^^^^^^^^^^^^^^^^^^---------
+   |     | |    |                  |
+   |     | |    |                  second borrow occurs due to use of `v` in closure
+   |     | |    second mutable borrow occurs here
+   |     | first borrow later used by call
+   |     first mutable borrow occurs here
+
+error[E0499]: cannot borrow `v` as mutable more than once at a time
+  --> $DIR/issue-109271-pass-self-into-closure.rs:25:5
+   |
+LL |       v.call(|(), this: &mut S| {
+   |       ^ ---- ------------------ first mutable borrow occurs here
+   |       | |
+   |  _____| first borrow later used by call
+   | |
+LL | |
+LL | |
+LL | |
+LL | |         _ = v;
+LL | |         v.set();
+   | |         - first borrow occurs due to use of `v` in closure
+...  |
+LL | |         _ = v.add(3);
+LL | |     });
+   | |______^ second mutable borrow occurs here
+   |
+help: try using the closure argument
+   |
+LL ~         _ = this;
+LL ~         this.set();
+LL ~         this.get();
+LL ~         S::get(&this);
+   |
+
+error[E0499]: cannot borrow `v` as mutable more than once at a time
+  --> $DIR/issue-109271-pass-self-into-closure.rs:25:12
+   |
+LL |       v.call(|(), this: &mut S| {
+   |       - ---- ^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+   |       | |
+   |  _____| first borrow later used by call
+   | |
+LL | |
+LL | |
+LL | |
+LL | |         _ = v;
+LL | |         v.set();
+   | |         - second borrow occurs due to use of `v` in closure
+...  |
+LL | |         _ = v.add(3);
+LL | |     });
+   | |______- first mutable borrow occurs here
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0499, E0502.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/consts/const-eval/generic-slice.stderr b/tests/ui/consts/const-eval/generic-slice.stderr
index c38088df4d8..ff1dc29ccfd 100644
--- a/tests/ui/consts/const-eval/generic-slice.stderr
+++ b/tests/ui/consts/const-eval/generic-slice.stderr
@@ -4,6 +4,8 @@ error[E0597]: `x` does not live long enough
 LL | impl<'a, T: 'static> Generic<'a, T> {
    |      -- lifetime `'a` defined here
 ...
+LL |         let x: &'static [T] = &[];
+   |             - binding `x` declared here
 LL |         &x
    |         ^^
    |         |
@@ -16,6 +18,8 @@ LL |     };
 error[E0597]: `x` does not live long enough
   --> $DIR/generic-slice.rs:27:5
    |
+LL |     let x: &[_] = &[];
+   |         - binding `x` declared here
 LL |     &x
    |     ^^
    |     |
diff --git a/tests/ui/generator/auto-trait-regions.drop_tracking.stderr b/tests/ui/generator/auto-trait-regions.drop_tracking.stderr
index 165748d4430..b2a5b92ed0f 100644
--- a/tests/ui/generator/auto-trait-regions.drop_tracking.stderr
+++ b/tests/ui/generator/auto-trait-regions.drop_tracking.stderr
@@ -9,7 +9,11 @@ LL |         let a = A(&mut true, &mut true, No);
 LL |         assert_foo(a);
    |                    - borrow later used here
    |
-   = note: consider using a `let` binding to create a longer lived value
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~         let binding = true;
+LL ~         let a = A(&mut binding, &mut true, No);
+   |
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/auto-trait-regions.rs:48:35
@@ -22,7 +26,11 @@ LL |         let a = A(&mut true, &mut true, No);
 LL |         assert_foo(a);
    |                    - borrow later used here
    |
-   = note: consider using a `let` binding to create a longer lived value
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~         let binding = true;
+LL ~         let a = A(&mut true, &mut binding, No);
+   |
 
 error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:34:5
diff --git a/tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr b/tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr
index 165748d4430..b2a5b92ed0f 100644
--- a/tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr
+++ b/tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr
@@ -9,7 +9,11 @@ LL |         let a = A(&mut true, &mut true, No);
 LL |         assert_foo(a);
    |                    - borrow later used here
    |
-   = note: consider using a `let` binding to create a longer lived value
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~         let binding = true;
+LL ~         let a = A(&mut binding, &mut true, No);
+   |
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/auto-trait-regions.rs:48:35
@@ -22,7 +26,11 @@ LL |         let a = A(&mut true, &mut true, No);
 LL |         assert_foo(a);
    |                    - borrow later used here
    |
-   = note: consider using a `let` binding to create a longer lived value
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~         let binding = true;
+LL ~         let a = A(&mut true, &mut binding, No);
+   |
 
 error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:34:5
diff --git a/tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr b/tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr
index 165748d4430..b2a5b92ed0f 100644
--- a/tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr
+++ b/tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr
@@ -9,7 +9,11 @@ LL |         let a = A(&mut true, &mut true, No);
 LL |         assert_foo(a);
    |                    - borrow later used here
    |
-   = note: consider using a `let` binding to create a longer lived value
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~         let binding = true;
+LL ~         let a = A(&mut binding, &mut true, No);
+   |
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/auto-trait-regions.rs:48:35
@@ -22,7 +26,11 @@ LL |         let a = A(&mut true, &mut true, No);
 LL |         assert_foo(a);
    |                    - borrow later used here
    |
-   = note: consider using a `let` binding to create a longer lived value
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~         let binding = true;
+LL ~         let a = A(&mut true, &mut binding, No);
+   |
 
 error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:34:5
diff --git a/tests/ui/generator/auto-trait-regions.stderr b/tests/ui/generator/auto-trait-regions.stderr
deleted file mode 100644
index 165748d4430..00000000000
--- a/tests/ui/generator/auto-trait-regions.stderr
+++ /dev/null
@@ -1,47 +0,0 @@
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/auto-trait-regions.rs:48:24
-   |
-LL |         let a = A(&mut true, &mut true, No);
-   |                        ^^^^                - temporary value is freed at the end of this statement
-   |                        |
-   |                        creates a temporary value which is freed while still in use
-...
-LL |         assert_foo(a);
-   |                    - borrow later used here
-   |
-   = note: consider using a `let` binding to create a longer lived value
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/auto-trait-regions.rs:48:35
-   |
-LL |         let a = A(&mut true, &mut true, No);
-   |                                   ^^^^     - temporary value is freed at the end of this statement
-   |                                   |
-   |                                   creates a temporary value which is freed while still in use
-...
-LL |         assert_foo(a);
-   |                    - borrow later used here
-   |
-   = note: consider using a `let` binding to create a longer lived value
-
-error: implementation of `Foo` is not general enough
-  --> $DIR/auto-trait-regions.rs:34:5
-   |
-LL |     assert_foo(gen);
-   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
-   |
-   = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
-   = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
-
-error: implementation of `Foo` is not general enough
-  --> $DIR/auto-trait-regions.rs:54:5
-   |
-LL |     assert_foo(gen);
-   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
-   |
-   = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
-   = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/lifetimes/issue-69314.stderr b/tests/ui/lifetimes/issue-69314.stderr
index 7ae6789285b..3879f35505c 100644
--- a/tests/ui/lifetimes/issue-69314.stderr
+++ b/tests/ui/lifetimes/issue-69314.stderr
@@ -12,6 +12,8 @@ LL |     async fn f2(m: Msg<'_>) {}
 error[E0597]: `buf` does not live long enough
   --> $DIR/issue-69314.rs:14:19
    |
+LL |         let mut buf = [0; 512];
+   |             ------- binding `buf` declared here
 LL |         let m2 = &buf[..];
    |                   ^^^ borrowed value does not live long enough
 LL |         let m = Self::g(m2).await;
diff --git a/tests/ui/nll/user-annotations/adt-brace-enums.stderr b/tests/ui/nll/user-annotations/adt-brace-enums.stderr
index 9e94fd5a782..900e7e25390 100644
--- a/tests/ui/nll/user-annotations/adt-brace-enums.stderr
+++ b/tests/ui/nll/user-annotations/adt-brace-enums.stderr
@@ -31,7 +31,9 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
-...
+LL |     let _closure = || {
+LL |         let c = 66;
+   |             - binding `c` declared here
 LL |         SomeEnum::SomeVariant::<&'a u32> { t: &c };
    |                                               ^^
    |                                               |
diff --git a/tests/ui/nll/user-annotations/adt-brace-structs.stderr b/tests/ui/nll/user-annotations/adt-brace-structs.stderr
index cbb7f6a55a9..d61643dc6ed 100644
--- a/tests/ui/nll/user-annotations/adt-brace-structs.stderr
+++ b/tests/ui/nll/user-annotations/adt-brace-structs.stderr
@@ -31,7 +31,9 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
-...
+LL |     let _closure = || {
+LL |         let c = 66;
+   |             - binding `c` declared here
 LL |         SomeStruct::<&'a u32> { t: &c };
    |                                    ^^
    |                                    |
diff --git a/tests/ui/nll/user-annotations/adt-nullary-enums.stderr b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr
index bca85a90d19..5b385feeedc 100644
--- a/tests/ui/nll/user-annotations/adt-nullary-enums.stderr
+++ b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr
@@ -34,7 +34,10 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
-...
+LL |     let _closure = || {
+LL |         let c = 66;
+   |             - binding `c` declared here
+LL |         combine(
 LL |             SomeEnum::SomeVariant(Cell::new(&c)),
    |                                   ----------^^-
    |                                   |         |
diff --git a/tests/ui/nll/user-annotations/adt-tuple-enums.stderr b/tests/ui/nll/user-annotations/adt-tuple-enums.stderr
index d2d85ec2b9b..766da9ec00c 100644
--- a/tests/ui/nll/user-annotations/adt-tuple-enums.stderr
+++ b/tests/ui/nll/user-annotations/adt-tuple-enums.stderr
@@ -31,7 +31,9 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
-...
+LL |     let _closure = || {
+LL |         let c = 66;
+   |             - binding `c` declared here
 LL |         SomeEnum::SomeVariant::<&'a u32>(&c);
    |                                          ^^
    |                                          |
diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
index b7bc2a10b70..2084697e7e2 100644
--- a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
+++ b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
@@ -33,7 +33,10 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
-...
+LL |     let _closure = || {
+LL |         let c = 66;
+   |             - binding `c` declared here
+LL |         let f = SomeStruct::<&'a u32>;
 LL |         f(&c);
    |         --^^-
    |         | |
@@ -47,7 +50,9 @@ error[E0597]: `c` does not live long enough
    |
 LL |     let f = SomeStruct::<&'a u32>;
    |         - lifetime `'1` appears in the type of `f`
-...
+LL |     let _closure = || {
+LL |         let c = 66;
+   |             - binding `c` declared here
 LL |         f(&c);
    |         --^^-
    |         | |
diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct.stderr
index 97d39da265f..c7480f52963 100644
--- a/tests/ui/nll/user-annotations/adt-tuple-struct.stderr
+++ b/tests/ui/nll/user-annotations/adt-tuple-struct.stderr
@@ -31,7 +31,9 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
-...
+LL |     let _closure = || {
+LL |         let c = 66;
+   |             - binding `c` declared here
 LL |         SomeStruct::<&'a u32>(&c);
    |                               ^^
    |                               |
diff --git a/tests/ui/nll/user-annotations/fns.stderr b/tests/ui/nll/user-annotations/fns.stderr
index 8b53e138d9b..abaa35e9516 100644
--- a/tests/ui/nll/user-annotations/fns.stderr
+++ b/tests/ui/nll/user-annotations/fns.stderr
@@ -31,7 +31,9 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
-...
+LL |     let _closure = || {
+LL |         let c = 66;
+   |             - binding `c` declared here
 LL |         some_fn::<&'a u32>(&c);
    |         -------------------^^-
    |         |                  |
diff --git a/tests/ui/nll/user-annotations/method-call.stderr b/tests/ui/nll/user-annotations/method-call.stderr
index 3803cbf776b..b4d1ac042a2 100644
--- a/tests/ui/nll/user-annotations/method-call.stderr
+++ b/tests/ui/nll/user-annotations/method-call.stderr
@@ -33,6 +33,8 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
 ...
+LL |         let c = 66;
+   |             - binding `c` declared here
 LL |         a.method::<&'a u32>(b,  &c);
    |         ------------------------^^-
    |         |                       |
diff --git a/tests/ui/nll/user-annotations/method-ufcs-3.stderr b/tests/ui/nll/user-annotations/method-ufcs-3.stderr
index 8cb995a03ce..4dd39e10827 100644
--- a/tests/ui/nll/user-annotations/method-ufcs-3.stderr
+++ b/tests/ui/nll/user-annotations/method-ufcs-3.stderr
@@ -33,6 +33,8 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
 ...
+LL |         let c = 66;
+   |             - binding `c` declared here
 LL |         <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c);
    |         -------------------------------------------^^-
    |         |                                          |
diff --git a/tests/ui/static/issue-18118.stderr b/tests/ui/static/issue-18118.stderr
index 49798a148de..035be2b1202 100644
--- a/tests/ui/static/issue-18118.stderr
+++ b/tests/ui/static/issue-18118.stderr
@@ -1,6 +1,8 @@
 error[E0597]: `p` does not live long enough
   --> $DIR/issue-18118.rs:4:9
    |
+LL |         let p = 3;
+   |             - binding `p` declared here
 LL |         &p
    |         ^^
    |         |