Try to point out when edition 2024 lifetime capture rules cause borrowck issues

This commit is contained in:
Michael Goulet 2024-10-03 00:44:14 -04:00
parent e093b82a41
commit c1457798db
9 changed files with 754 additions and 2 deletions

View File

@ -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::*;

View File

@ -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};

View File

@ -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(()),
}
}
}

View File

@ -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};

View File

@ -0,0 +1,6 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
use std::fmt::Display;
pub fn hello(x: &Vec<i32>) -> impl Display { 0 }

View File

@ -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
}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.