mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #131186 - compiler-errors:precise-capturing-borrowck, r=estebank
Try to point out when edition 2024 lifetime capture rules cause borrowck issues Lifetime capture rules in 2024 are modified to capture more lifetimes, which sometimes lead to some non-local borrowck errors. This PR attempts to link these back together with a useful note pointing out the capture rule changes. This is not a blocking concern, but I'd appreciate feedback (though, again, I'd like to stress that I don't want to block this PR on this): I'm worried about this note drowning in the sea of other diagnostics that borrowck emits. I was tempted to change the level of the note to `.span_warn` just so it would show up in a different color. Thoughts? Fixes #130545 Opening as a draft first since it's stacked on #131183. r? `@ghost`
This commit is contained in:
commit
c8b83785dc
@ -272,7 +272,7 @@ enum ImplTraitContext {
|
||||
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
|
||||
/// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
|
||||
///
|
||||
OpaqueTy { origin: hir::OpaqueTyOrigin },
|
||||
OpaqueTy { origin: hir::OpaqueTyOrigin<LocalDefId> },
|
||||
/// `impl Trait` is unstably accepted in this position.
|
||||
FeatureGated(ImplTraitPosition, Symbol),
|
||||
/// `impl Trait` is not accepted in this position.
|
||||
@ -1416,7 +1416,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_opaque_impl_trait(
|
||||
&mut self,
|
||||
span: Span,
|
||||
origin: hir::OpaqueTyOrigin,
|
||||
origin: hir::OpaqueTyOrigin<LocalDefId>,
|
||||
opaque_ty_node_id: NodeId,
|
||||
bounds: &GenericBounds,
|
||||
itctx: ImplTraitContext,
|
||||
@ -1458,7 +1458,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_opaque_inner(
|
||||
&mut self,
|
||||
opaque_ty_node_id: NodeId,
|
||||
origin: hir::OpaqueTyOrigin,
|
||||
origin: hir::OpaqueTyOrigin<LocalDefId>,
|
||||
opaque_ty_span: Span,
|
||||
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
|
||||
) -> hir::TyKind<'hir> {
|
||||
|
@ -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(()),
|
||||
}
|
||||
}
|
||||
}
|
@ -502,7 +502,7 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
|
||||
}
|
||||
|
||||
let &Self { tcx, def_id, .. } = self;
|
||||
let origin = tcx.opaque_type_origin(def_id);
|
||||
let origin = tcx.local_opaque_ty_origin(def_id);
|
||||
let parent = match origin {
|
||||
hir::OpaqueTyOrigin::FnReturn { parent, .. }
|
||||
| hir::OpaqueTyOrigin::AsyncFn { parent, .. }
|
||||
|
@ -2746,7 +2746,7 @@ pub struct OpaqueTy<'hir> {
|
||||
pub hir_id: HirId,
|
||||
pub def_id: LocalDefId,
|
||||
pub bounds: GenericBounds<'hir>,
|
||||
pub origin: OpaqueTyOrigin,
|
||||
pub origin: OpaqueTyOrigin<LocalDefId>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
@ -2784,33 +2784,35 @@ pub struct PreciseCapturingNonLifetimeArg {
|
||||
pub res: Res,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum RpitContext {
|
||||
Trait,
|
||||
TraitImpl,
|
||||
}
|
||||
|
||||
/// From whence the opaque type came.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
|
||||
pub enum OpaqueTyOrigin {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum OpaqueTyOrigin<D> {
|
||||
/// `-> impl Trait`
|
||||
FnReturn {
|
||||
/// The defining function.
|
||||
parent: LocalDefId,
|
||||
parent: D,
|
||||
// Whether this is an RPITIT (return position impl trait in trait)
|
||||
in_trait_or_impl: Option<RpitContext>,
|
||||
},
|
||||
/// `async fn`
|
||||
AsyncFn {
|
||||
/// The defining function.
|
||||
parent: LocalDefId,
|
||||
parent: D,
|
||||
// Whether this is an AFIT (async fn in trait)
|
||||
in_trait_or_impl: Option<RpitContext>,
|
||||
},
|
||||
/// type aliases: `type Foo = impl Trait;`
|
||||
TyAlias {
|
||||
/// The type alias or associated type parent of the TAIT/ATPIT
|
||||
parent: LocalDefId,
|
||||
parent: D,
|
||||
/// associated types in impl blocks for traits.
|
||||
in_assoc_ty: bool,
|
||||
},
|
||||
|
@ -268,7 +268,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
span: Span,
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
origin: &hir::OpaqueTyOrigin<LocalDefId>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let defining_use_anchor = match *origin {
|
||||
hir::OpaqueTyOrigin::FnReturn { parent, .. }
|
||||
@ -677,7 +677,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
DefKind::OpaqueTy => {
|
||||
check_opaque_precise_captures(tcx, def_id);
|
||||
|
||||
let origin = tcx.opaque_type_origin(def_id);
|
||||
let origin = tcx.local_opaque_ty_origin(def_id);
|
||||
if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
|
||||
| hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = origin
|
||||
&& let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
|
||||
|
@ -86,7 +86,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
impl_trait_header,
|
||||
coroutine_kind,
|
||||
coroutine_for_closure,
|
||||
is_type_alias_impl_trait,
|
||||
opaque_ty_origin,
|
||||
rendered_precise_capturing_args,
|
||||
..*providers
|
||||
};
|
||||
@ -1759,9 +1759,18 @@ fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId {
|
||||
def_id.to_def_id()
|
||||
}
|
||||
|
||||
fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
|
||||
let opaque = tcx.hir().expect_opaque_ty(def_id);
|
||||
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
|
||||
fn opaque_ty_origin<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> hir::OpaqueTyOrigin<DefId> {
|
||||
match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
|
||||
hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl } => {
|
||||
hir::OpaqueTyOrigin::FnReturn { parent: parent.to_def_id(), in_trait_or_impl }
|
||||
}
|
||||
hir::OpaqueTyOrigin::AsyncFn { parent, in_trait_or_impl } => {
|
||||
hir::OpaqueTyOrigin::AsyncFn { parent: parent.to_def_id(), in_trait_or_impl }
|
||||
}
|
||||
hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty } => {
|
||||
hir::OpaqueTyOrigin::TyAlias { parent: parent.to_def_id(), in_assoc_ty }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rendered_precise_capturing_args<'tcx>(
|
||||
|
@ -20,6 +20,7 @@ pub mod errors;
|
||||
pub mod generics;
|
||||
mod lint;
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::slice;
|
||||
|
||||
use rustc_ast::TraitObjectSyntax;
|
||||
@ -1811,7 +1812,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
match path.res {
|
||||
Res::Def(DefKind::OpaqueTy, did) => {
|
||||
// Check for desugared `impl Trait`.
|
||||
assert!(tcx.is_type_alias_impl_trait(did));
|
||||
assert_matches!(tcx.opaque_ty_origin(did), hir::OpaqueTyOrigin::TyAlias { .. });
|
||||
let item_segment = path.segments.split_last().unwrap();
|
||||
let _ = self
|
||||
.prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy);
|
||||
|
@ -601,7 +601,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
_ => return None,
|
||||
};
|
||||
let hir::OpaqueTyOrigin::FnReturn { parent: parent_def_id, .. } =
|
||||
self.tcx.opaque_type_origin(def_id)
|
||||
self.tcx.local_opaque_ty_origin(def_id)
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
@ -155,7 +155,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
// however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, where
|
||||
// it is of no concern, so we only check for TAITs.
|
||||
if self.can_define_opaque_ty(b_def_id)
|
||||
&& self.tcx.is_type_alias_impl_trait(b_def_id)
|
||||
&& matches!(
|
||||
self.tcx.opaque_ty_origin(b_def_id),
|
||||
hir::OpaqueTyOrigin::TyAlias { .. }
|
||||
)
|
||||
{
|
||||
self.dcx().emit_err(OpaqueHiddenTypeDiag {
|
||||
span,
|
||||
|
@ -316,10 +316,7 @@ provide! { tcx, def_id, other, cdata,
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
is_type_alias_impl_trait => {
|
||||
debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy);
|
||||
cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index)
|
||||
}
|
||||
opaque_ty_origin => { table }
|
||||
assumed_wf_types_for_rpitit => { table }
|
||||
collect_return_position_impl_trait_in_trait_tys => {
|
||||
Ok(cdata
|
||||
|
@ -1188,7 +1188,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
|
||||
| DefKind::SyntheticCoroutineBody => true,
|
||||
|
||||
DefKind::OpaqueTy => {
|
||||
let origin = tcx.opaque_type_origin(def_id);
|
||||
let origin = tcx.local_opaque_ty_origin(def_id);
|
||||
if let hir::OpaqueTyOrigin::FnReturn { parent, .. }
|
||||
| hir::OpaqueTyOrigin::AsyncFn { parent, .. } = origin
|
||||
&& let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(parent)
|
||||
@ -1530,9 +1530,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
if let DefKind::OpaqueTy = def_kind {
|
||||
self.encode_explicit_item_bounds(def_id);
|
||||
self.encode_explicit_item_super_predicates(def_id);
|
||||
self.tables
|
||||
.is_type_alias_impl_trait
|
||||
.set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id));
|
||||
record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id));
|
||||
self.encode_precise_capturing_args(def_id);
|
||||
}
|
||||
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
|
||||
|
@ -378,7 +378,6 @@ define_tables! {
|
||||
- defaulted:
|
||||
intrinsic: Table<DefIndex, Option<LazyValue<ty::IntrinsicDef>>>,
|
||||
is_macro_rules: Table<DefIndex, bool>,
|
||||
is_type_alias_impl_trait: Table<DefIndex, bool>,
|
||||
type_alias_is_lazy: Table<DefIndex, bool>,
|
||||
attr_flags: Table<DefIndex, AttrFlags>,
|
||||
// The u64 is the crate-local part of the DefPathHash. All hashes in this crate have the same
|
||||
@ -468,6 +467,7 @@ define_tables! {
|
||||
doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
|
||||
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
|
||||
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
|
||||
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
|
||||
}
|
||||
|
||||
#[derive(TyEncodable, TyDecodable)]
|
||||
|
@ -280,6 +280,7 @@ trivial! {
|
||||
rustc_hir::IsAsync,
|
||||
rustc_hir::ItemLocalId,
|
||||
rustc_hir::LangItem,
|
||||
rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>,
|
||||
rustc_hir::OwnerId,
|
||||
rustc_hir::Upvar,
|
||||
rustc_index::bit_set::FiniteBitSet<u32>,
|
||||
|
@ -260,11 +260,10 @@ rustc_queries! {
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
query is_type_alias_impl_trait(key: DefId) -> bool
|
||||
query opaque_ty_origin(key: DefId) -> hir::OpaqueTyOrigin<DefId>
|
||||
{
|
||||
desc { "determine whether the opaque is a type-alias impl trait" }
|
||||
desc { "determine where the opaque originates from" }
|
||||
separate_provide_extern
|
||||
feedable
|
||||
}
|
||||
|
||||
query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32>
|
||||
|
@ -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};
|
||||
@ -2103,11 +2103,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
|
||||
/// Returns the origin of the opaque type `def_id`.
|
||||
#[track_caller]
|
||||
pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin {
|
||||
let origin = self.hir().expect_opaque_ty(def_id).origin;
|
||||
trace!("opaque_type_origin({def_id:?}) => {origin:?}");
|
||||
origin
|
||||
#[instrument(skip(self), level = "trace", ret)]
|
||||
pub fn local_opaque_ty_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin<LocalDefId> {
|
||||
self.hir().expect_opaque_ty(def_id).origin
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,7 @@ trivially_parameterized_over_tcx! {
|
||||
rustc_hir::def_id::DefId,
|
||||
rustc_hir::def_id::DefIndex,
|
||||
rustc_hir::definitions::DefKey,
|
||||
rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>,
|
||||
rustc_index::bit_set::BitSet<u32>,
|
||||
rustc_index::bit_set::FiniteBitSet<u32>,
|
||||
rustc_session::cstore::ForeignModule,
|
||||
|
@ -384,7 +384,10 @@ impl<T> Trait<T> for X {
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
)
|
||||
&& tcx.is_type_alias_impl_trait(opaque_ty.def_id)
|
||||
&& matches!(
|
||||
tcx.opaque_ty_origin(opaque_ty.def_id),
|
||||
hir::OpaqueTyOrigin::TyAlias { .. }
|
||||
)
|
||||
&& !tcx
|
||||
.opaque_types_defined_by(body_owner_def_id.expect_local())
|
||||
.contains(&opaque_ty.def_id.expect_local())
|
||||
|
@ -2648,7 +2648,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> ErrorGuaranteed {
|
||||
let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
|
||||
let name = match self.tcx.local_opaque_ty_origin(def_id.expect_local()) {
|
||||
hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } => {
|
||||
"opaque type".to_string()
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ fn associated_type_for_impl_trait_in_trait(
|
||||
) -> LocalDefId {
|
||||
let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
|
||||
| hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
|
||||
tcx.opaque_type_origin(opaque_ty_def_id)
|
||||
tcx.local_opaque_ty_origin(opaque_ty_def_id)
|
||||
else {
|
||||
bug!("expected opaque for {opaque_ty_def_id:?}");
|
||||
};
|
||||
@ -281,8 +281,6 @@ fn associated_type_for_impl_trait_in_trait(
|
||||
// Copy defaultness of the containing function.
|
||||
trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
|
||||
|
||||
trait_assoc_ty.is_type_alias_impl_trait(false);
|
||||
|
||||
// There are no inferred outlives for the synthesized associated type.
|
||||
trait_assoc_ty.inferred_outlives_of(&[]);
|
||||
|
||||
|
@ -139,7 +139,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
|
||||
}
|
||||
|
||||
// TAITs outside their defining scopes are ignored.
|
||||
let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local());
|
||||
let origin = self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local());
|
||||
trace!(?origin);
|
||||
match origin {
|
||||
rustc_hir::OpaqueTyOrigin::FnReturn { .. }
|
||||
|
@ -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