mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Try to point out when edition 2024 lifetime capture rules cause borrowck issues
This commit is contained in:
parent
e093b82a41
commit
c1457798db
@ -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::*;
|
||||
|
@ -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};
|
||||
|
224
compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
Normal file
224
compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
Normal 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(()),
|
||||
}
|
||||
}
|
||||
}
|
@ -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};
|
||||
|
@ -0,0 +1,6 @@
|
||||
//@ edition: 2024
|
||||
//@ compile-flags: -Zunstable-options
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
pub fn hello(x: &Vec<i32>) -> impl Display { 0 }
|
15
tests/ui/impl-trait/precise-capturing/foreign-2021.rs
Normal file
15
tests/ui/impl-trait/precise-capturing/foreign-2021.rs
Normal 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
|
||||
}
|
26
tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
Normal file
26
tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
Normal 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`.
|
190
tests/ui/impl-trait/precise-capturing/migration-note.rs
Normal file
190
tests/ui/impl-trait/precise-capturing/migration-note.rs
Normal 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() {}
|
284
tests/ui/impl-trait/precise-capturing/migration-note.stderr
Normal file
284
tests/ui/impl-trait/precise-capturing/migration-note.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user