From 5ade2ea9c18676d279c6e3bc6c3c1345d6109bd8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Oct 2024 00:44:14 -0400 Subject: [PATCH] Try to point out when edition 2024 lifetime capture rules cause borrowck issues --- .../src/diagnostics/conflict_errors.rs | 8 +- .../rustc_borrowck/src/diagnostics/mod.rs | 1 + .../src/diagnostics/opaque_suggestions.rs | 224 ++++++++++++++ .../precise-capturing/auxiliary/foreign.rs | 6 + .../precise-capturing/foreign-2021.rs | 15 + .../precise-capturing/foreign-2021.stderr | 26 ++ .../precise-capturing/migration-note.rs | 190 ++++++++++++ .../precise-capturing/migration-note.stderr | 284 ++++++++++++++++++ 8 files changed, 753 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs create mode 100644 tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs create mode 100644 tests/ui/impl-trait/precise-capturing/foreign-2021.rs create mode 100644 tests/ui/impl-trait/precise-capturing/foreign-2021.stderr create mode 100644 tests/ui/impl-trait/precise-capturing/migration-note.rs create mode 100644 tests/ui/impl-trait/precise-capturing/migration-note.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 60ea0d1edbf4e..231567f1dbaeb 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 801c7af2de701..3b60071603619 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 0000000000000..ff496a9e0e71b --- /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 since Rust 2024 \ + has adjusted `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 `use<..>` 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 `use<..>` 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> 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, + seen_lifetimes: FxIndexSet, +} + +impl<'tcx> TypeVisitor> 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/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs b/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs new file mode 100644 index 0000000000000..49015bc48baf2 --- /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) -> 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 0000000000000..62b0fe8403be4 --- /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 since Rust 2024 + //~| 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 0000000000000..2497366b8884e --- /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 since Rust 2024 has adjusted `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 `use<..>` precise capturing bound to avoid overcapturing: `+ use<>` + --> $DIR/auxiliary/foreign.rs:6:31 + | +LL | pub fn hello(x: &Vec) -> 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 0000000000000..ae7d3e5d8ee3d --- /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(x: &Vec) -> 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 since Rust 2024 + //~| 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 since Rust 2024 + //~| 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 since Rust 2024 + //~| 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(x: &mut Vec) -> 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 since Rust 2024 + //~| 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 since Rust 2024 + //~| 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 since Rust 2024 + //~| 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: &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 since Rust 2024 + //~| 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: &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 since Rust 2024 + //~| 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 since Rust 2024 + //~| 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, +} + +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 since Rust 2024 + //~| 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 since Rust 2024 + //~| 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 0000000000000..189d388a4604a --- /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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:17:13 + | +LL | let a = display_len(&x); + | ^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ + +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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:30:13 + | +LL | let a = display_len(&x); + | ^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ + +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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:44:13 + | +LL | let a = display_len(&x); + | ^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ +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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:64:13 + | +LL | let a = display_len_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { + | ++++++++ + +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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:77:13 + | +LL | let a = display_len_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { + | ++++++++ + +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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:91:13 + | +LL | let a = display_len_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { + | ++++++++ +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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:113:13 + | +LL | let a = display_field(&s.f); + | ^^^^^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_field(t: &T) -> impl Display + use { + | ++++++++ + +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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:129:13 + | +LL | let a = display_field(&mut s.f); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_field(t: &T) -> impl Display + use { + | ++++++++ + +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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:141:13 + | +LL | let a = display_field(&mut s.f); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_field(t: &T) -> impl Display + use { + | ++++++++ + +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 since Rust 2024 has adjusted `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:160:13 + | +LL | x = display_len(&z.f); + | ^^^^^^^^^^^^^^^^^ +help: add a `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ + +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 since Rust 2024 has adjusted `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 `use<..>` precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ + +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`.