about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs224
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs6
-rw-r--r--tests/ui/impl-trait/precise-capturing/foreign-2021.rs15
-rw-r--r--tests/ui/impl-trait/precise-capturing/foreign-2021.stderr26
-rw-r--r--tests/ui/impl-trait/precise-capturing/migration-note.rs190
-rw-r--r--tests/ui/impl-trait/precise-capturing/migration-note.stderr284
9 files changed, 754 insertions, 2 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index c687be69b1a..1bfb54a7bb7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1489,6 +1489,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             &borrow_msg,
             &value_msg,
         );
+        self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err);
 
         borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
 
@@ -1561,6 +1562,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             borrow_span,
             &self.describe_any_place(borrow.borrowed_place.as_ref()),
         );
+        self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err);
+
         borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {
             use crate::session_diagnostics::CaptureVarCause::*;
             let place = &borrow.borrowed_place;
@@ -1820,6 +1823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 unreachable!()
             }
         };
+        self.note_due_to_edition_2024_opaque_capture_rules(issued_borrow, &mut err);
 
         if issued_spans == borrow_spans {
             borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| {
@@ -2860,7 +2864,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         debug!(?place_desc, ?explanation);
 
-        let err = match (place_desc, explanation) {
+        let mut err = match (place_desc, explanation) {
             // If the outlives constraint comes from inside the closure,
             // for example:
             //
@@ -2939,6 +2943,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 explanation,
             ),
         };
+        self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err);
 
         self.buffer_error(err);
     }
@@ -3777,6 +3782,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         }
 
         let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
+        self.note_due_to_edition_2024_opaque_capture_rules(loan, &mut err);
 
         loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| {
             use crate::session_diagnostics::CaptureVarCause::*;
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 801c7af2de7..3b600716036 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -48,6 +48,7 @@ mod conflict_errors;
 mod explain_borrow;
 mod move_errors;
 mod mutability_errors;
+mod opaque_suggestions;
 mod region_errors;
 
 pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};
diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
new file mode 100644
index 00000000000..bfd7e83501c
--- /dev/null
+++ b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
@@ -0,0 +1,224 @@
+#![allow(rustc::diagnostic_outside_of_impl)]
+#![allow(rustc::untranslatable_diagnostic)]
+
+use std::ops::ControlFlow;
+
+use either::Either;
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_errors::{Applicability, Diag};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_middle::mir::{self, ConstraintCategory, Location};
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+};
+use rustc_span::Symbol;
+
+use crate::MirBorrowckCtxt;
+use crate::borrow_set::BorrowData;
+use crate::consumers::RegionInferenceContext;
+use crate::type_check::Locations;
+
+impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
+    /// Try to note when an opaque is involved in a borrowck error and that
+    /// opaque captures lifetimes due to edition 2024.
+    // FIXME: This code is otherwise somewhat general, and could easily be adapted
+    // to explain why other things overcapture... like async fn and RPITITs.
+    pub(crate) fn note_due_to_edition_2024_opaque_capture_rules(
+        &self,
+        borrow: &BorrowData<'tcx>,
+        diag: &mut Diag<'_>,
+    ) {
+        // We look at all the locals. Why locals? Because it's the best thing
+        // I could think of that's correlated with the *instantiated* higer-ranked
+        // binder for calls, since we don't really store those anywhere else.
+        for ty in self.body.local_decls.iter().map(|local| local.ty) {
+            if !ty.has_opaque_types() {
+                continue;
+            }
+
+            let tcx = self.infcx.tcx;
+            let ControlFlow::Break((opaque_def_id, offending_region_idx, location)) = ty
+                .visit_with(&mut FindOpaqueRegion {
+                    regioncx: &self.regioncx,
+                    tcx,
+                    borrow_region: borrow.region,
+                })
+            else {
+                continue;
+            };
+
+            // If an opaque explicitly captures a lifetime, then no need to point it out.
+            // FIXME: We should be using a better heuristic for `use<>`.
+            if tcx.rendered_precise_capturing_args(opaque_def_id).is_some() {
+                continue;
+            }
+
+            // If one of the opaque's bounds mentions the region, then no need to
+            // point it out, since it would've been captured on edition 2021 as well.
+            //
+            // Also, while we're at it, collect all the lifetimes that the opaque
+            // *does* mention. We'll use that for the `+ use<'a>` suggestion below.
+            let mut visitor = CheckExplicitRegionMentionAndCollectGenerics {
+                tcx,
+                offending_region_idx,
+                seen_opaques: [opaque_def_id].into_iter().collect(),
+                seen_lifetimes: Default::default(),
+            };
+            if tcx
+                .explicit_item_bounds(opaque_def_id)
+                .skip_binder()
+                .visit_with(&mut visitor)
+                .is_break()
+            {
+                continue;
+            }
+
+            // If we successfully located a terminator, then point it out
+            // and provide a suggestion if it's local.
+            match self.body.stmt_at(location) {
+                Either::Right(mir::Terminator { source_info, .. }) => {
+                    diag.span_note(
+                        source_info.span,
+                        "this call may capture more lifetimes than intended, \
+                        because Rust 2024 has adjusted the `impl Trait` lifetime capture rules",
+                    );
+                    let mut seen_generics: Vec<_> =
+                        visitor.seen_lifetimes.iter().map(ToString::to_string).collect();
+                    // Capture all in-scope ty/const params.
+                    seen_generics.extend(
+                        ty::GenericArgs::identity_for_item(tcx, opaque_def_id)
+                            .iter()
+                            .filter(|arg| {
+                                matches!(
+                                    arg.unpack(),
+                                    ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_)
+                                )
+                            })
+                            .map(|arg| arg.to_string()),
+                    );
+                    if opaque_def_id.is_local() {
+                        diag.span_suggestion_verbose(
+                            tcx.def_span(opaque_def_id).shrink_to_hi(),
+                            "add a precise capturing bound to avoid overcapturing",
+                            format!(" + use<{}>", seen_generics.join(", ")),
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        diag.span_help(
+                            tcx.def_span(opaque_def_id),
+                            format!(
+                                "if you can modify this crate, add a precise \
+                                capturing bound to avoid overcapturing: `+ use<{}>`",
+                                seen_generics.join(", ")
+                            ),
+                        );
+                    }
+                    return;
+                }
+                Either::Left(_) => {}
+            }
+        }
+    }
+}
+
+/// This visitor contains the bulk of the logic for this lint.
+struct FindOpaqueRegion<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    regioncx: &'a RegionInferenceContext<'tcx>,
+    borrow_region: ty::RegionVid,
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> {
+    type Result = ControlFlow<(DefId, usize, Location), ()>;
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
+        // If we find an opaque in a local ty, then for each of its captured regions,
+        // try to find a path between that captured regions and our borrow region...
+        if let ty::Alias(ty::Opaque, opaque) = *ty.kind()
+            && let hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: None } =
+                self.tcx.opaque_ty_origin(opaque.def_id)
+        {
+            let variances = self.tcx.variances_of(opaque.def_id);
+            for (idx, (arg, variance)) in std::iter::zip(opaque.args, variances).enumerate() {
+                // Skip uncaptured args.
+                if *variance == ty::Bivariant {
+                    continue;
+                }
+                // We only care about regions.
+                let Some(opaque_region) = arg.as_region() else {
+                    continue;
+                };
+                // Don't try to convert a late-bound region, which shouldn't exist anyways (yet).
+                if opaque_region.is_bound() {
+                    continue;
+                }
+                let opaque_region_vid = self.regioncx.to_region_vid(opaque_region);
+
+                // Find a path between the borrow region and our opaque capture.
+                if let Some((path, _)) =
+                    self.regioncx.find_constraint_paths_between_regions(self.borrow_region, |r| {
+                        r == opaque_region_vid
+                    })
+                {
+                    for constraint in path {
+                        // If we find a call in this path, then check if it defines the opaque.
+                        if let ConstraintCategory::CallArgument(Some(call_ty)) = constraint.category
+                            && let ty::FnDef(call_def_id, _) = *call_ty.kind()
+                            // This function defines the opaque :D
+                            && call_def_id == parent
+                            && let Locations::Single(location) = constraint.locations
+                        {
+                            return ControlFlow::Break((opaque.def_id, idx, location));
+                        }
+                    }
+                }
+            }
+        }
+
+        ty.super_visit_with(self)
+    }
+}
+
+struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    offending_region_idx: usize,
+    seen_opaques: FxIndexSet<DefId>,
+    seen_lifetimes: FxIndexSet<Symbol>,
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
+    type Result = ControlFlow<(), ()>;
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
+        match *ty.kind() {
+            ty::Alias(ty::Opaque, opaque) => {
+                if self.seen_opaques.insert(opaque.def_id) {
+                    for (bound, _) in self
+                        .tcx
+                        .explicit_item_bounds(opaque.def_id)
+                        .iter_instantiated_copied(self.tcx, opaque.args)
+                    {
+                        bound.visit_with(self)?;
+                    }
+                }
+                ControlFlow::Continue(())
+            }
+            _ => ty.super_visit_with(self),
+        }
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
+        match r.kind() {
+            ty::ReEarlyParam(param) => {
+                if param.index as usize == self.offending_region_idx {
+                    ControlFlow::Break(())
+                } else {
+                    self.seen_lifetimes.insert(param.name);
+                    ControlFlow::Continue(())
+                }
+            }
+            _ => ControlFlow::Continue(()),
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 9f1ffabc4f8..9abad6d1a68 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -55,7 +55,7 @@ use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 pub use rustc_type_ir::lift::Lift;
 use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph};
-use tracing::{debug, trace};
+use tracing::{debug, instrument};
 
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
diff --git a/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs b/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs
new file mode 100644
index 00000000000..49015bc48ba
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs
@@ -0,0 +1,6 @@
+//@ edition: 2024
+//@ compile-flags: -Zunstable-options
+
+use std::fmt::Display;
+
+pub fn hello(x: &Vec<i32>) -> impl Display { 0 }
diff --git a/tests/ui/impl-trait/precise-capturing/foreign-2021.rs b/tests/ui/impl-trait/precise-capturing/foreign-2021.rs
new file mode 100644
index 00000000000..aee412ff7f1
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/foreign-2021.rs
@@ -0,0 +1,15 @@
+//@ aux-build: foreign.rs
+
+extern crate foreign;
+
+fn main() {
+    let mut x = vec![];
+    let h = foreign::hello(&x);
+    //~^ NOTE this call may capture more lifetimes than intended
+    //~| NOTE immutable borrow occurs here
+    x.push(0);
+    //~^ ERROR cannot borrow `x` as mutable
+    //~| NOTE mutable borrow occurs here
+    println!("{h}");
+    //~^ NOTE immutable borrow later used here
+}
diff --git a/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
new file mode 100644
index 00000000000..2a17ef72912
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
@@ -0,0 +1,26 @@
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/foreign-2021.rs:10:5
+   |
+LL |     let h = foreign::hello(&x);
+   |                            -- immutable borrow occurs here
+...
+LL |     x.push(0);
+   |     ^^^^^^^^^ mutable borrow occurs here
+...
+LL |     println!("{h}");
+   |               --- immutable borrow later used here
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/foreign-2021.rs:7:13
+   |
+LL |     let h = foreign::hello(&x);
+   |             ^^^^^^^^^^^^^^^^^^
+help: if you can modify this crate, add a precise capturing bound to avoid overcapturing: `+ use<>`
+  --> $DIR/auxiliary/foreign.rs:6:31
+   |
+LL | pub fn hello(x: &Vec<i32>) -> impl Display { 0 }
+   |                               ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.rs b/tests/ui/impl-trait/precise-capturing/migration-note.rs
new file mode 100644
index 00000000000..a5bade4ddc5
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/migration-note.rs
@@ -0,0 +1,190 @@
+//@ edition: 2024
+//@ compile-flags: -Zunstable-options
+
+use std::fmt::Display;
+
+fn display_len<T>(x: &Vec<T>) -> impl Display {
+    //~^ NOTE in this expansion of desugaring of `impl Trait`
+    //~| NOTE in this expansion of desugaring of `impl Trait`
+    //~| NOTE in this expansion of desugaring of `impl Trait`
+    //~| NOTE in this expansion of desugaring of `impl Trait`
+    //~| NOTE in this expansion of desugaring of `impl Trait`
+    x.len()
+}
+
+fn conflicting_borrow() {
+    let mut x = vec![];
+    let a = display_len(&x);
+    //~^ NOTE this call may capture more lifetimes than intended
+    //~| NOTE immutable borrow occurs here
+    x.push(1);
+    //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
+    //~| NOTE mutable borrow occurs here
+    println!("{a}");
+    //~^ NOTE immutable borrow later used here
+}
+
+fn needs_static() {
+    let x = vec![1];
+    //~^ NOTE binding `x` declared here
+    let a = display_len(&x);
+    //~^ ERROR `x` does not live long enough
+    //~| NOTE this call may capture more lifetimes than intended
+    //~| NOTE argument requires that `x` is borrowed for `'static`
+    //~| NOTE borrowed value does not live long enoug
+
+    fn needs_static(_: impl Sized + 'static) {}
+    needs_static(a);
+}
+//~^ NOTE `x` dropped here while still borrowed
+
+fn is_moved() {
+    let x = vec![1];
+    //~^ NOTE binding `x` declared here
+    let a = display_len(&x);
+    //~^ NOTE this call may capture more lifetimes than intended
+    //~| NOTE borrow of `x` occurs here
+
+    fn mv(_: impl Sized) {}
+    mv(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
+    //~| NOTE move out of `x` occurs here
+}
+//~^ NOTE borrow might be used here, when `a` is dropped
+
+fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display {
+    //~^ NOTE in this expansion of desugaring of `impl Trait`
+    //~| NOTE in this expansion of desugaring of `impl Trait`
+    //~| NOTE in this expansion of desugaring of `impl Trait`
+    x.len()
+}
+
+fn conflicting_borrow_mut() {
+    let mut x = vec![];
+    let a = display_len_mut(&mut x);
+    //~^ NOTE this call may capture more lifetimes than intended
+    //~| NOTE first mutable borrow occurs here
+    x.push(1);
+    //~^ ERROR cannot borrow `x` as mutable more than once
+    //~| NOTE second mutable borrow occurs here
+    println!("{a}");
+    //~^ NOTE first borrow later used here
+}
+
+fn needs_static_mut() {
+    let mut x = vec![1];
+    //~^ NOTE binding `x` declared here
+    let a = display_len_mut(&mut x);
+    //~^ ERROR `x` does not live long enough
+    //~| NOTE this call may capture more lifetimes than intended
+    //~| NOTE argument requires that `x` is borrowed for `'static`
+    //~| NOTE borrowed value does not live long enough
+
+    fn needs_static(_: impl Sized + 'static) {}
+    needs_static(a);
+}
+//~^ NOTE `x` dropped here while still borrowed
+
+fn is_move_mut() {
+    let mut x = vec![1];
+    //~^ NOTE binding `x` declared here
+    let a = display_len_mut(&mut x);
+    //~^ NOTE this call may capture more lifetimes than intended
+    //~| NOTE borrow of `x` occurs here
+
+    fn mv(_: impl Sized) {}
+    mv(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
+    //~| NOTE move out of `x` occurs here
+}
+//~^ NOTE borrow might be used here, when `a` is dropped
+
+struct S { f: i32 }
+
+fn display_field<T: Copy + Display>(t: &T) -> impl Display {
+    //~^ NOTE in this expansion of desugaring of `impl Trait`
+    //~| NOTE in this expansion of desugaring of `impl Trait`
+    //~| NOTE in this expansion of desugaring of `impl Trait`
+    *t
+}
+
+fn conflicting_borrow_field() {
+    let mut s = S { f: 0 };
+    let a = display_field(&s.f);
+    //~^ NOTE this call may capture more lifetimes than intended
+    //~| NOTE `s.f` is borrowed here
+    s.f = 1;
+    //~^ ERROR cannot assign to `s.f` because it is borrowed
+    //~| NOTE `s.f` is assigned to here but it was already borrowed
+    println!("{a}");
+    //~^ NOTE borrow later used here
+}
+
+fn display_field_mut<T: Copy + Display>(t: &mut T) -> impl Display {
+    *t
+}
+
+fn conflicting_borrow_field_mut() {
+    let mut s = S { f: 0 };
+    let a = display_field(&mut s.f);
+    //~^ NOTE this call may capture more lifetimes than intended
+    //~| NOTE `s.f` is borrowed here
+    s.f = 1;
+    //~^ ERROR cannot assign to `s.f` because it is borrowed
+    //~| NOTE `s.f` is assigned to here but it was already borrowed
+    println!("{a}");
+    //~^ NOTE borrow later used here
+}
+
+fn field_move() {
+    let mut s = S { f: 0 };
+    let a = display_field(&mut s.f);
+    //~^ NOTE this call may capture more lifetimes than intended
+    //~| NOTE `s.f` is borrowed here
+    s.f;
+    //~^ ERROR cannot use `s.f` because it was mutably borrowed
+    //~| NOTE use of borrowed `s.f`
+    println!("{a}");
+    //~^ NOTE borrow later used here
+}
+
+struct Z {
+    f: Vec<i32>,
+}
+
+fn live_long() {
+    let x;
+    {
+        let z = Z { f: vec![1] };
+        //~^ NOTE binding `z` declared here
+        x = display_len(&z.f);
+        //~^ ERROR `z.f` does not live long enough
+        //~| NOTE this call may capture more lifetimes than intended
+        //~| NOTE values in a scope are dropped in the opposite order they are defined
+        //~| NOTE borrowed value does not live long enough
+    }
+    //~^ NOTE `z.f` dropped here while still borrowed
+}
+//~^ NOTE borrow might be used here, when `x` is dropped
+
+fn temp() {
+    let x = { let x = display_len(&mut vec![0]); x };
+    //~^ ERROR temporary value dropped while borrowed
+    //~| NOTE this call may capture more lifetimes than intended
+    //~| NOTE consider using a `let` binding to create a longer lived value
+    //~| NOTE borrow later used here
+    //~| NOTE temporary value is freed at the end of this statement
+}
+
+// FIXME: This doesn't display a useful Rust 2024 suggestion :(
+fn returned() -> impl Sized {
+    let x = vec![0];
+    //~^ NOTE binding `x` declared here
+    display_len(&x)
+    //~^ ERROR `x` does not live long enough
+    //~| NOTE borrowed value does not live long enough
+    //~| NOTE argument requires that `x` is borrowed for `'static`
+}
+//~^ NOTE `x` dropped here while still borrowed
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr
new file mode 100644
index 00000000000..3ac47ed1bcd
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr
@@ -0,0 +1,284 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/migration-note.rs:183:17
+   |
+LL |     let x = vec![0];
+   |         - binding `x` declared here
+LL |
+LL |     display_len(&x)
+   |     ------------^^-
+   |     |           |
+   |     |           borrowed value does not live long enough
+   |     argument requires that `x` is borrowed for `'static`
+...
+LL | }
+   | - `x` dropped here while still borrowed
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/migration-note.rs:20:5
+   |
+LL |     let a = display_len(&x);
+   |                         -- immutable borrow occurs here
+...
+LL |     x.push(1);
+   |     ^^^^^^^^^ mutable borrow occurs here
+...
+LL |     println!("{a}");
+   |               --- immutable borrow later used here
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:17:13
+   |
+LL |     let a = display_len(&x);
+   |             ^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
+   |                                               ++++++++
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/migration-note.rs:30:25
+   |
+LL |     let x = vec![1];
+   |         - binding `x` declared here
+LL |
+LL |     let a = display_len(&x);
+   |             ------------^^-
+   |             |           |
+   |             |           borrowed value does not live long enough
+   |             argument requires that `x` is borrowed for `'static`
+...
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:30:13
+   |
+LL |     let a = display_len(&x);
+   |             ^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
+   |                                               ++++++++
+
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/migration-note.rs:49:8
+   |
+LL |     let x = vec![1];
+   |         - binding `x` declared here
+LL |
+LL |     let a = display_len(&x);
+   |                         -- borrow of `x` occurs here
+...
+LL |     mv(x);
+   |        ^ move out of `x` occurs here
+...
+LL | }
+   | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display`
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:44:13
+   |
+LL |     let a = display_len(&x);
+   |             ^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
+   |                                               ++++++++
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let a = display_len(&x.clone());
+   |                           ++++++++
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/migration-note.rs:67:5
+   |
+LL |     let a = display_len_mut(&mut x);
+   |                             ------ first mutable borrow occurs here
+...
+LL |     x.push(1);
+   |     ^ second mutable borrow occurs here
+...
+LL |     println!("{a}");
+   |               --- first borrow later used here
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:64:13
+   |
+LL |     let a = display_len_mut(&mut x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
+   |                                                       ++++++++
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/migration-note.rs:77:29
+   |
+LL |     let mut x = vec![1];
+   |         ----- binding `x` declared here
+LL |
+LL |     let a = display_len_mut(&mut x);
+   |             ----------------^^^^^^-
+   |             |               |
+   |             |               borrowed value does not live long enough
+   |             argument requires that `x` is borrowed for `'static`
+...
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:77:13
+   |
+LL |     let a = display_len_mut(&mut x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
+   |                                                       ++++++++
+
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/migration-note.rs:96:8
+   |
+LL |     let mut x = vec![1];
+   |         ----- binding `x` declared here
+LL |
+LL |     let a = display_len_mut(&mut x);
+   |                             ------ borrow of `x` occurs here
+...
+LL |     mv(x);
+   |        ^ move out of `x` occurs here
+...
+LL | }
+   | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display`
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:91:13
+   |
+LL |     let a = display_len_mut(&mut x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
+   |                                                       ++++++++
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let a = display_len_mut(&mut x.clone());
+   |                                   ++++++++
+
+error[E0506]: cannot assign to `s.f` because it is borrowed
+  --> $DIR/migration-note.rs:116:5
+   |
+LL |     let a = display_field(&s.f);
+   |                           ---- `s.f` is borrowed here
+...
+LL |     s.f = 1;
+   |     ^^^^^^^ `s.f` is assigned to here but it was already borrowed
+...
+LL |     println!("{a}");
+   |               --- borrow later used here
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:113:13
+   |
+LL |     let a = display_field(&s.f);
+   |             ^^^^^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
+   |                                                            ++++++++
+
+error[E0506]: cannot assign to `s.f` because it is borrowed
+  --> $DIR/migration-note.rs:132:5
+   |
+LL |     let a = display_field(&mut s.f);
+   |                           -------- `s.f` is borrowed here
+...
+LL |     s.f = 1;
+   |     ^^^^^^^ `s.f` is assigned to here but it was already borrowed
+...
+LL |     println!("{a}");
+   |               --- borrow later used here
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:129:13
+   |
+LL |     let a = display_field(&mut s.f);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
+   |                                                            ++++++++
+
+error[E0503]: cannot use `s.f` because it was mutably borrowed
+  --> $DIR/migration-note.rs:144:5
+   |
+LL |     let a = display_field(&mut s.f);
+   |                           -------- `s.f` is borrowed here
+...
+LL |     s.f;
+   |     ^^^ use of borrowed `s.f`
+...
+LL |     println!("{a}");
+   |               --- borrow later used here
+   |
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:141:13
+   |
+LL |     let a = display_field(&mut s.f);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
+   |                                                            ++++++++
+
+error[E0597]: `z.f` does not live long enough
+  --> $DIR/migration-note.rs:160:25
+   |
+LL |         let z = Z { f: vec![1] };
+   |             - binding `z` declared here
+LL |
+LL |         x = display_len(&z.f);
+   |                         ^^^^ borrowed value does not live long enough
+...
+LL |     }
+   |     - `z.f` dropped here while still borrowed
+LL |
+LL | }
+   | - borrow might be used here, when `x` is dropped and runs the destructor for type `impl std::fmt::Display`
+   |
+   = note: values in a scope are dropped in the opposite order they are defined
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:160:13
+   |
+LL |         x = display_len(&z.f);
+   |             ^^^^^^^^^^^^^^^^^
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
+   |                                               ++++++++
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/migration-note.rs:171:40
+   |
+LL |     let x = { let x = display_len(&mut vec![0]); x };
+   |                                        ^^^^^^^ - - borrow later used here
+   |                                        |       |
+   |                                        |       temporary value is freed at the end of this statement
+   |                                        creates a temporary value which is freed while still in use
+   |
+   = note: consider using a `let` binding to create a longer lived value
+note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
+  --> $DIR/migration-note.rs:171:23
+   |
+LL |     let x = { let x = display_len(&mut vec![0]); x };
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add a precise capturing bound to avoid overcapturing
+   |
+LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
+   |                                               ++++++++
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0503, E0505, E0506, E0597, E0716.
+For more information about an error, try `rustc --explain E0499`.