mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-07 09:13:07 +03:00
Auto merge of #54343 - blitzerr:master, r=nikomatsakis
First shot at #54015 Closes #54015
This commit is contained in:
@@ -8,22 +8,22 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::WriteKind;
|
||||
use borrow_check::prefixes::IsPrefixOf;
|
||||
use borrow_check::nll::explain_borrow::BorrowExplanation;
|
||||
use borrow_check::prefixes::IsPrefixOf;
|
||||
use borrow_check::WriteKind;
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::region::ScopeTree;
|
||||
use rustc::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, FakeReadCause, Field, Local,
|
||||
LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem, Rvalue,
|
||||
Statement, StatementKind, TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::ty;
|
||||
use rustc::util::ppaux::with_highlight_region_for_bound_region;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc::util::ppaux::with_highlight_region_for_bound_region;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use super::borrow_set::BorrowData;
|
||||
@@ -35,6 +35,17 @@
|
||||
use dataflow::move_paths::MovePathIndex;
|
||||
use util::borrowck_errors::{BorrowckErrors, Origin};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MoveSite {
|
||||
/// Index of the "move out" that we found. The `MoveData` can
|
||||
/// then tell us where the move occurred.
|
||||
moi: MoveOutIndex,
|
||||
|
||||
/// True if we traversed a back edge while walking from the point
|
||||
/// of error to the move site.
|
||||
traversed_back_edge: bool
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
pub(super) fn report_use_of_moved_or_uninitialized(
|
||||
&mut self,
|
||||
@@ -45,22 +56,30 @@ pub(super) fn report_use_of_moved_or_uninitialized(
|
||||
) {
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} place={:?} \
|
||||
span={:?} mpi={:?}",
|
||||
span={:?} mpi={:?}",
|
||||
context, desired_action, place, span, mpi
|
||||
);
|
||||
|
||||
let use_spans = self
|
||||
.move_spans(place, context.loc)
|
||||
let use_spans = self.move_spans(place, context.loc)
|
||||
.or_else(|| self.borrow_spans(span, context.loc));
|
||||
let span = use_spans.args_or_use();
|
||||
|
||||
let mois = self.get_moved_indexes(context, mpi);
|
||||
debug!("report_use_of_moved_or_uninitialized: mois={:?}", mois);
|
||||
let move_site_vec = self.get_moved_indexes(context, mpi);
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized: move_site_vec={:?}",
|
||||
move_site_vec
|
||||
);
|
||||
let move_out_indices: Vec<_> = move_site_vec
|
||||
.iter()
|
||||
.map(|move_site| move_site.moi)
|
||||
.collect();
|
||||
|
||||
if mois.is_empty() {
|
||||
if move_out_indices.is_empty() {
|
||||
let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
|
||||
|
||||
if self.uninitialized_error_reported.contains(&root_place.clone()) {
|
||||
if self.uninitialized_error_reported
|
||||
.contains(&root_place.clone())
|
||||
{
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
|
||||
root_place
|
||||
@@ -77,8 +96,7 @@ pub(super) fn report_use_of_moved_or_uninitialized(
|
||||
let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable(
|
||||
span,
|
||||
desired_action.as_noun(),
|
||||
&self
|
||||
.describe_place_with_options(place, IncludingDowncast(true))
|
||||
&self.describe_place_with_options(place, IncludingDowncast(true))
|
||||
.unwrap_or("_".to_owned()),
|
||||
Origin::Mir,
|
||||
);
|
||||
@@ -91,10 +109,15 @@ pub(super) fn report_use_of_moved_or_uninitialized(
|
||||
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
} else {
|
||||
if let Some((reported_place, _)) = self.move_error_reported.get(&mois) {
|
||||
if self.prefixes(&reported_place, PrefixSet::All).any(|p| p == place) {
|
||||
debug!("report_use_of_moved_or_uninitialized place: error suppressed \
|
||||
mois={:?}", mois);
|
||||
if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
|
||||
if self.prefixes(&reported_place, PrefixSet::All)
|
||||
.any(|p| p == place)
|
||||
{
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized place: error suppressed \
|
||||
mois={:?}",
|
||||
move_out_indices
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -110,8 +133,8 @@ pub(super) fn report_use_of_moved_or_uninitialized(
|
||||
);
|
||||
|
||||
let mut is_loop_move = false;
|
||||
for moi in &mois {
|
||||
let move_out = self.move_data.moves[*moi];
|
||||
for move_site in &move_site_vec {
|
||||
let move_out = self.move_data.moves[(*move_site).moi];
|
||||
let moved_place = &self.move_data.move_paths[move_out.path].place;
|
||||
|
||||
let move_spans = self.move_spans(moved_place, move_out.source);
|
||||
@@ -126,9 +149,17 @@ pub(super) fn report_use_of_moved_or_uninitialized(
|
||||
if span == move_span {
|
||||
err.span_label(
|
||||
span,
|
||||
format!("value moved{} here in previous iteration of loop", move_msg),
|
||||
format!("value moved{} here, in previous iteration of loop", move_msg),
|
||||
);
|
||||
is_loop_move = true;
|
||||
} else if move_site.traversed_back_edge {
|
||||
err.span_label(
|
||||
move_span,
|
||||
format!(
|
||||
"value moved{} here, in previous iteration of loop",
|
||||
move_msg
|
||||
),
|
||||
);
|
||||
} else {
|
||||
err.span_label(move_span, format!("value moved{} here", move_msg));
|
||||
move_spans.var_span_label(&mut err, "variable moved due to use in closure");
|
||||
@@ -166,13 +197,14 @@ pub(super) fn report_use_of_moved_or_uninitialized(
|
||||
};
|
||||
|
||||
if needs_note {
|
||||
let mpi = self.move_data.moves[mois[0]].path;
|
||||
let mpi = self.move_data.moves[move_out_indices[0]].path;
|
||||
let place = &self.move_data.move_paths[mpi].place;
|
||||
|
||||
if let Some(ty) = self.retrieve_type_for_place(place) {
|
||||
let note_msg = match self
|
||||
.describe_place_with_options(place, IncludingDowncast(true))
|
||||
{
|
||||
let note_msg = match self.describe_place_with_options(
|
||||
place,
|
||||
IncludingDowncast(true),
|
||||
) {
|
||||
Some(name) => format!("`{}`", name),
|
||||
None => "value".to_owned(),
|
||||
};
|
||||
@@ -186,10 +218,9 @@ pub(super) fn report_use_of_moved_or_uninitialized(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((_, mut old_err)) = self.move_error_reported.insert(
|
||||
mois,
|
||||
(place.clone(), err)
|
||||
) {
|
||||
if let Some((_, mut old_err)) = self.move_error_reported
|
||||
.insert(move_out_indices, (place.clone(), err))
|
||||
{
|
||||
// Cancel the old error so it doesn't ICE.
|
||||
old_err.cancel();
|
||||
}
|
||||
@@ -255,8 +286,7 @@ pub(super) fn report_use_while_mutably_borrowed(
|
||||
span,
|
||||
&self.describe_place(place).unwrap_or("_".to_owned()),
|
||||
borrow_span,
|
||||
&self
|
||||
.describe_place(&borrow.borrowed_place)
|
||||
&self.describe_place(&borrow.borrowed_place)
|
||||
.unwrap_or("_".to_owned()),
|
||||
Origin::Mir,
|
||||
);
|
||||
@@ -299,8 +329,8 @@ pub(super) fn report_conflicting_borrow(
|
||||
"mutable",
|
||||
) {
|
||||
(BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
|
||||
| (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => tcx
|
||||
.cannot_reborrow_already_borrowed(
|
||||
| (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
|
||||
tcx.cannot_reborrow_already_borrowed(
|
||||
span,
|
||||
&desc_place,
|
||||
"",
|
||||
@@ -311,10 +341,11 @@ pub(super) fn report_conflicting_borrow(
|
||||
"",
|
||||
None,
|
||||
Origin::Mir,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => tcx
|
||||
.cannot_mutably_borrow_multiply(
|
||||
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => {
|
||||
tcx.cannot_mutably_borrow_multiply(
|
||||
span,
|
||||
&desc_place,
|
||||
"",
|
||||
@@ -322,16 +353,18 @@ pub(super) fn report_conflicting_borrow(
|
||||
"",
|
||||
None,
|
||||
Origin::Mir,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => tcx
|
||||
.cannot_uniquely_borrow_by_two_closures(
|
||||
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => {
|
||||
tcx.cannot_uniquely_borrow_by_two_closures(
|
||||
span,
|
||||
&desc_place,
|
||||
issued_span,
|
||||
None,
|
||||
Origin::Mir,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
(BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _)
|
||||
| (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => {
|
||||
@@ -344,10 +377,7 @@ pub(super) fn report_conflicting_borrow(
|
||||
);
|
||||
borrow_spans.var_span_label(
|
||||
&mut err,
|
||||
format!(
|
||||
"borrow occurs due to use of `{}` in closure",
|
||||
desc_place
|
||||
),
|
||||
format!("borrow occurs due to use of `{}` in closure", desc_place),
|
||||
);
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
|
||||
@@ -365,8 +395,8 @@ pub(super) fn report_conflicting_borrow(
|
||||
Origin::Mir,
|
||||
),
|
||||
|
||||
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => tcx
|
||||
.cannot_reborrow_already_uniquely_borrowed(
|
||||
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => {
|
||||
tcx.cannot_reborrow_already_uniquely_borrowed(
|
||||
span,
|
||||
&desc_place,
|
||||
"",
|
||||
@@ -375,10 +405,11 @@ pub(super) fn report_conflicting_borrow(
|
||||
"",
|
||||
None,
|
||||
Origin::Mir,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => tcx
|
||||
.cannot_reborrow_already_uniquely_borrowed(
|
||||
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => {
|
||||
tcx.cannot_reborrow_already_uniquely_borrowed(
|
||||
span,
|
||||
&desc_place,
|
||||
"",
|
||||
@@ -387,13 +418,14 @@ pub(super) fn report_conflicting_borrow(
|
||||
"",
|
||||
None,
|
||||
Origin::Mir,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
(BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
|
||||
| (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => {
|
||||
// Shallow borrows are uses from the user's point of view.
|
||||
self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow);
|
||||
return
|
||||
return;
|
||||
}
|
||||
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
|
||||
| (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
|
||||
@@ -447,16 +479,16 @@ pub(super) fn report_borrowed_value_does_not_live_long_enough(
|
||||
place_span: (&Place<'tcx>, Span),
|
||||
kind: Option<WriteKind>,
|
||||
) {
|
||||
debug!("report_borrowed_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}\
|
||||
)",
|
||||
context, borrow, place_span, kind
|
||||
debug!(
|
||||
"report_borrowed_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}\
|
||||
)",
|
||||
context, borrow, place_span, kind
|
||||
);
|
||||
|
||||
let drop_span = place_span.1;
|
||||
let scope_tree = self.infcx.tcx.region_scope_tree(self.mir_def_id);
|
||||
let root_place = self
|
||||
.prefixes(&borrow.borrowed_place, PrefixSet::All)
|
||||
let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
|
||||
.last()
|
||||
.unwrap();
|
||||
|
||||
@@ -468,8 +500,7 @@ pub(super) fn report_borrowed_value_does_not_live_long_enough(
|
||||
_ => drop_span,
|
||||
};
|
||||
|
||||
if self
|
||||
.access_place_error_reported
|
||||
if self.access_place_error_reported
|
||||
.contains(&(root_place.clone(), borrow_span))
|
||||
{
|
||||
debug!(
|
||||
@@ -482,8 +513,8 @@ pub(super) fn report_borrowed_value_does_not_live_long_enough(
|
||||
self.access_place_error_reported
|
||||
.insert((root_place.clone(), borrow_span));
|
||||
|
||||
if let StorageDeadOrDrop::Destructor(dropped_ty)
|
||||
= self.classify_drop_access_kind(&borrow.borrowed_place)
|
||||
if let StorageDeadOrDrop::Destructor(dropped_ty) =
|
||||
self.classify_drop_access_kind(&borrow.borrowed_place)
|
||||
{
|
||||
// If a borrow of path `B` conflicts with drop of `D` (and
|
||||
// we're not in the uninteresting case where `B` is a
|
||||
@@ -491,19 +522,16 @@ pub(super) fn report_borrowed_value_does_not_live_long_enough(
|
||||
// destructor conflict.
|
||||
if !borrow.borrowed_place.is_prefix_of(place_span.0) {
|
||||
self.report_borrow_conflicts_with_destructor(
|
||||
context,
|
||||
borrow,
|
||||
place_span,
|
||||
kind,
|
||||
dropped_ty,
|
||||
context, borrow, place_span, kind, dropped_ty,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let err = match &self.describe_place(&borrow.borrowed_place) {
|
||||
Some(_) if self.is_place_thread_local(root_place) =>
|
||||
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span),
|
||||
Some(_) if self.is_place_thread_local(root_place) => {
|
||||
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
|
||||
}
|
||||
Some(name) => self.report_local_value_does_not_live_long_enough(
|
||||
context,
|
||||
name,
|
||||
@@ -556,7 +584,7 @@ fn report_local_value_does_not_live_long_enough(
|
||||
|
||||
err.span_label(
|
||||
borrow_span,
|
||||
format!("`{}` would have to be valid for `{}`...", name, region_name)
|
||||
format!("`{}` would have to be valid for `{}`...", name, region_name),
|
||||
);
|
||||
|
||||
if let Some(fn_node_id) = self.infcx.tcx.hir.as_local_node_id(self.mir_def_id) {
|
||||
@@ -564,8 +592,9 @@ fn report_local_value_does_not_live_long_enough(
|
||||
drop_span,
|
||||
format!(
|
||||
"...but `{}` will be dropped here, when the function `{}` returns",
|
||||
name, self.infcx.tcx.hir.name(fn_node_id),
|
||||
)
|
||||
name,
|
||||
self.infcx.tcx.hir.name(fn_node_id),
|
||||
),
|
||||
);
|
||||
|
||||
err.note(
|
||||
@@ -579,16 +608,20 @@ fn report_local_value_does_not_live_long_enough(
|
||||
} else {
|
||||
err.span_label(
|
||||
drop_span,
|
||||
format!("...but `{}` dropped here while still borrowed", name)
|
||||
format!("...but `{}` dropped here while still borrowed", name),
|
||||
);
|
||||
}
|
||||
|
||||
if let BorrowExplanation::MustBeValidFor(..) = explanation { } else {
|
||||
if let BorrowExplanation::MustBeValidFor(..) = explanation {
|
||||
} else {
|
||||
explanation.emit(self.infcx.tcx, &mut err);
|
||||
}
|
||||
} else {
|
||||
err.span_label(borrow_span, "borrowed value does not live long enough");
|
||||
err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
|
||||
err.span_label(
|
||||
drop_span,
|
||||
format!("`{}` dropped here while still borrowed", name),
|
||||
);
|
||||
|
||||
borrow_spans.args_span_label(&mut err, "value captured here");
|
||||
|
||||
@@ -616,7 +649,9 @@ pub(super) fn report_borrow_conflicts_with_destructor(
|
||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||
let borrow_span = borrow_spans.var_or_use();
|
||||
|
||||
let mut err = self.infcx.tcx.cannot_borrow_across_destructor(borrow_span, Origin::Mir);
|
||||
let mut err = self.infcx
|
||||
.tcx
|
||||
.cannot_borrow_across_destructor(borrow_span, Origin::Mir);
|
||||
|
||||
let what_was_dropped = match self.describe_place(place) {
|
||||
Some(name) => format!("`{}`", name.as_str()),
|
||||
@@ -624,26 +659,30 @@ pub(super) fn report_borrow_conflicts_with_destructor(
|
||||
};
|
||||
|
||||
let label = match self.describe_place(&borrow.borrowed_place) {
|
||||
Some(borrowed) =>
|
||||
format!("here, drop of {D} needs exclusive access to `{B}`, \
|
||||
because the type `{T}` implements the `Drop` trait",
|
||||
D=what_was_dropped, T=dropped_ty, B=borrowed),
|
||||
None =>
|
||||
format!("here is drop of {D}; whose type `{T}` implements the `Drop` trait",
|
||||
D=what_was_dropped, T=dropped_ty),
|
||||
Some(borrowed) => format!(
|
||||
"here, drop of {D} needs exclusive access to `{B}`, \
|
||||
because the type `{T}` implements the `Drop` trait",
|
||||
D = what_was_dropped,
|
||||
T = dropped_ty,
|
||||
B = borrowed
|
||||
),
|
||||
None => format!(
|
||||
"here is drop of {D}; whose type `{T}` implements the `Drop` trait",
|
||||
D = what_was_dropped,
|
||||
T = dropped_ty
|
||||
),
|
||||
};
|
||||
err.span_label(drop_span, label);
|
||||
|
||||
// Only give this note and suggestion if they could be relevant.
|
||||
let explanation = self.explain_why_borrow_contains_point(
|
||||
context, borrow, kind.map(|k| (k, place)),
|
||||
);
|
||||
let explanation =
|
||||
self.explain_why_borrow_contains_point(context, borrow, kind.map(|k| (k, place)));
|
||||
match explanation {
|
||||
BorrowExplanation::UsedLater {..} |
|
||||
BorrowExplanation::UsedLaterWhenDropped {..} => {
|
||||
BorrowExplanation::UsedLater { .. }
|
||||
| BorrowExplanation::UsedLaterWhenDropped { .. } => {
|
||||
err.note("consider using a `let` binding to create a longer lived value");
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
explanation.emit(self.infcx.tcx, &mut err);
|
||||
@@ -663,9 +702,9 @@ fn report_thread_local_value_does_not_live_long_enough(
|
||||
drop_span, borrow_span
|
||||
);
|
||||
|
||||
let mut err = self.infcx.tcx.thread_local_value_does_not_live_long_enough(
|
||||
borrow_span, Origin::Mir
|
||||
);
|
||||
let mut err = self.infcx
|
||||
.tcx
|
||||
.thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir);
|
||||
|
||||
err.span_label(
|
||||
borrow_span,
|
||||
@@ -693,20 +732,25 @@ fn report_temporary_value_does_not_live_long_enough(
|
||||
);
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let mut err =
|
||||
tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir);
|
||||
err.span_label(proper_span, "creates a temporary which is freed while still in use");
|
||||
err.span_label(drop_span, "temporary value is freed at the end of this statement");
|
||||
let mut err = tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir);
|
||||
err.span_label(
|
||||
proper_span,
|
||||
"creates a temporary which is freed while still in use",
|
||||
);
|
||||
err.span_label(
|
||||
drop_span,
|
||||
"temporary value is freed at the end of this statement",
|
||||
);
|
||||
|
||||
let explanation = self.explain_why_borrow_contains_point(context, borrow, None);
|
||||
match explanation {
|
||||
BorrowExplanation::UsedLater(..) |
|
||||
BorrowExplanation::UsedLaterInLoop(..) |
|
||||
BorrowExplanation::UsedLaterWhenDropped(..) => {
|
||||
BorrowExplanation::UsedLater(..)
|
||||
| BorrowExplanation::UsedLaterInLoop(..)
|
||||
| BorrowExplanation::UsedLaterWhenDropped(..) => {
|
||||
// Only give this note and suggestion if it could be relevant.
|
||||
err.note("consider using a `let` binding to create a longer lived value");
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
explanation.emit(self.infcx.tcx, &mut err);
|
||||
|
||||
@@ -715,29 +759,32 @@ fn report_temporary_value_does_not_live_long_enough(
|
||||
err
|
||||
}
|
||||
|
||||
fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveOutIndex> {
|
||||
fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveSite> {
|
||||
let mir = self.mir;
|
||||
|
||||
let mut stack = Vec::new();
|
||||
stack.extend(mir.predecessor_locations(context.loc));
|
||||
stack.extend(mir.predecessor_locations(context.loc).map(|predecessor| {
|
||||
let is_back_edge = context.loc.dominates(predecessor, &self.dominators);
|
||||
(predecessor, is_back_edge)
|
||||
}));
|
||||
|
||||
let mut visited = FxHashSet();
|
||||
let mut result = vec![];
|
||||
|
||||
'dfs: while let Some(l) = stack.pop() {
|
||||
'dfs: while let Some((location, is_back_edge)) = stack.pop() {
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized: current_location={:?}",
|
||||
l
|
||||
"report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
|
||||
location, is_back_edge
|
||||
);
|
||||
|
||||
if !visited.insert(l) {
|
||||
if !visited.insert(location) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for moves
|
||||
let stmt_kind = mir[l.block]
|
||||
let stmt_kind = mir[location.block]
|
||||
.statements
|
||||
.get(l.statement_index)
|
||||
.get(location.statement_index)
|
||||
.map(|s| &s.kind);
|
||||
if let Some(StatementKind::StorageDead(..)) = stmt_kind {
|
||||
// this analysis only tries to find moves explicitly
|
||||
@@ -756,11 +803,14 @@ fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<Mov
|
||||
let move_paths = &self.move_data.move_paths;
|
||||
mpis.extend(move_paths[mpi].parents(move_paths));
|
||||
|
||||
for moi in &self.move_data.loc_map[l] {
|
||||
for moi in &self.move_data.loc_map[location] {
|
||||
debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
|
||||
if mpis.contains(&self.move_data.moves[*moi].path) {
|
||||
debug!("report_use_of_moved_or_uninitialized: found");
|
||||
result.push(*moi);
|
||||
result.push(MoveSite {
|
||||
moi: *moi,
|
||||
traversed_back_edge: is_back_edge,
|
||||
});
|
||||
|
||||
// Strictly speaking, we could continue our DFS here. There may be
|
||||
// other moves that can reach the point of error. But it is kind of
|
||||
@@ -785,16 +835,25 @@ fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<Mov
|
||||
|
||||
// check for inits
|
||||
let mut any_match = false;
|
||||
drop_flag_effects::for_location_inits(self.infcx.tcx, self.mir, self.move_data, l, |m| {
|
||||
if m == mpi {
|
||||
any_match = true;
|
||||
}
|
||||
});
|
||||
drop_flag_effects::for_location_inits(
|
||||
self.infcx.tcx,
|
||||
self.mir,
|
||||
self.move_data,
|
||||
location,
|
||||
|m| {
|
||||
if m == mpi {
|
||||
any_match = true;
|
||||
}
|
||||
},
|
||||
);
|
||||
if any_match {
|
||||
continue 'dfs;
|
||||
}
|
||||
|
||||
stack.extend(mir.predecessor_locations(l));
|
||||
stack.extend(mir.predecessor_locations(location).map(|predecessor| {
|
||||
let back_edge = location.dominates(predecessor, &self.dominators);
|
||||
(predecessor, is_back_edge || back_edge)
|
||||
}));
|
||||
}
|
||||
|
||||
result
|
||||
@@ -829,7 +888,8 @@ pub(super) fn report_illegal_mutation_of_borrowed(
|
||||
|
||||
loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
|
||||
|
||||
self.explain_why_borrow_contains_point(context, loan, None).emit(self.infcx.tcx, &mut err);
|
||||
self.explain_why_borrow_contains_point(context, loan, None)
|
||||
.emit(self.infcx.tcx, &mut err);
|
||||
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
@@ -1151,7 +1211,9 @@ fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String {
|
||||
// the closure comes from another crate. But in that case we wouldn't
|
||||
// be borrowck'ing it, so we can just unwrap:
|
||||
let node_id = self.infcx.tcx.hir.as_local_node_id(def_id).unwrap();
|
||||
let freevar = self.infcx.tcx.with_freevars(node_id, |fv| fv[field.index()]);
|
||||
let freevar = self.infcx
|
||||
.tcx
|
||||
.with_freevars(node_id, |fv| fv[field.index()]);
|
||||
|
||||
self.infcx.tcx.hir.name(freevar.var_id()).to_string()
|
||||
}
|
||||
@@ -1218,35 +1280,30 @@ pub(super) fn retrieve_fake_read_cause_for_location(
|
||||
fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
match place {
|
||||
Place::Local(_)
|
||||
| Place::Static(_)
|
||||
| Place::Promoted(_) => StorageDeadOrDrop::LocalStorageDead,
|
||||
Place::Local(_) | Place::Static(_) | Place::Promoted(_) => {
|
||||
StorageDeadOrDrop::LocalStorageDead
|
||||
}
|
||||
Place::Projection(box PlaceProjection { base, elem }) => {
|
||||
let base_access = self.classify_drop_access_kind(base);
|
||||
match elem {
|
||||
ProjectionElem::Deref => {
|
||||
match base_access {
|
||||
StorageDeadOrDrop::LocalStorageDead
|
||||
| StorageDeadOrDrop::BoxedStorageDead => {
|
||||
assert!(base.ty(self.mir, tcx).to_ty(tcx).is_box(),
|
||||
"Drop of value behind a reference or raw pointer");
|
||||
StorageDeadOrDrop::BoxedStorageDead
|
||||
}
|
||||
StorageDeadOrDrop::Destructor(_) => {
|
||||
base_access
|
||||
}
|
||||
ProjectionElem::Deref => match base_access {
|
||||
StorageDeadOrDrop::LocalStorageDead
|
||||
| StorageDeadOrDrop::BoxedStorageDead => {
|
||||
assert!(
|
||||
base.ty(self.mir, tcx).to_ty(tcx).is_box(),
|
||||
"Drop of value behind a reference or raw pointer"
|
||||
);
|
||||
StorageDeadOrDrop::BoxedStorageDead
|
||||
}
|
||||
}
|
||||
ProjectionElem::Field(..)
|
||||
| ProjectionElem::Downcast(..) => {
|
||||
StorageDeadOrDrop::Destructor(_) => base_access,
|
||||
},
|
||||
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
|
||||
let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
|
||||
match base_ty.sty {
|
||||
ty::Adt(def, _) if def.has_dtor(tcx) => {
|
||||
// Report the outermost adt with a destructor
|
||||
match base_access {
|
||||
StorageDeadOrDrop::Destructor(_) => {
|
||||
base_access
|
||||
}
|
||||
StorageDeadOrDrop::Destructor(_) => base_access,
|
||||
StorageDeadOrDrop::LocalStorageDead
|
||||
| StorageDeadOrDrop::BoxedStorageDead => {
|
||||
StorageDeadOrDrop::Destructor(base_ty)
|
||||
@@ -1277,13 +1334,12 @@ fn annotate_argument_and_return_for_borrow(
|
||||
if is_closure {
|
||||
None
|
||||
} else {
|
||||
let ty = self.infcx.tcx.type_of(self.mir_def_id);
|
||||
match ty.sty {
|
||||
ty::TyKind::FnDef(_, _) | ty::TyKind::FnPtr(_) =>
|
||||
self.annotate_fn_sig(
|
||||
self.mir_def_id,
|
||||
self.infcx.tcx.fn_sig(self.mir_def_id)
|
||||
),
|
||||
let ty = self.infcx.tcx.type_of(self.mir_def_id);
|
||||
match ty.sty {
|
||||
ty::TyKind::FnDef(_, _) | ty::TyKind::FnPtr(_) => self.annotate_fn_sig(
|
||||
self.mir_def_id,
|
||||
self.infcx.tcx.fn_sig(self.mir_def_id),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1296,13 +1352,22 @@ fn annotate_argument_and_return_for_borrow(
|
||||
// place. If it was, we can add annotations about the function's return type and arguments
|
||||
// and it'll make sense.
|
||||
let location = borrow.reserve_location;
|
||||
debug!("annotate_argument_and_return_for_borrow: location={:?}", location);
|
||||
match &self.mir[location.block].statements.get(location.statement_index) {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: location={:?}",
|
||||
location
|
||||
);
|
||||
match &self.mir[location.block]
|
||||
.statements
|
||||
.get(location.statement_index)
|
||||
{
|
||||
Some(&Statement {
|
||||
kind: StatementKind::Assign(ref reservation, _),
|
||||
..
|
||||
}) => {
|
||||
debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation);
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: reservation={:?}",
|
||||
reservation
|
||||
);
|
||||
// Check that the initial assignment of the reserve location is into a temporary.
|
||||
let mut target = *match reservation {
|
||||
Place::Local(local) if self.mir.local_kind(*local) == LocalKind::Temp => local,
|
||||
@@ -1317,21 +1382,24 @@ fn annotate_argument_and_return_for_borrow(
|
||||
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
|
||||
target, stmt
|
||||
);
|
||||
if let StatementKind::Assign(
|
||||
Place::Local(assigned_to),
|
||||
box rvalue,
|
||||
) = &stmt.kind {
|
||||
debug!("annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||
rvalue={:?}", assigned_to, rvalue);
|
||||
if let StatementKind::Assign(Place::Local(assigned_to), box rvalue) = &stmt.kind
|
||||
{
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||
rvalue={:?}",
|
||||
assigned_to, rvalue
|
||||
);
|
||||
// Check if our `target` was captured by a closure.
|
||||
if let Rvalue::Aggregate(
|
||||
box AggregateKind::Closure(def_id, substs),
|
||||
operands,
|
||||
) = rvalue {
|
||||
box AggregateKind::Closure(def_id, substs),
|
||||
operands,
|
||||
) = rvalue
|
||||
{
|
||||
for operand in operands {
|
||||
let assigned_from = match operand {
|
||||
Operand::Copy(assigned_from) |
|
||||
Operand::Move(assigned_from) => assigned_from,
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
@@ -1354,13 +1422,13 @@ fn annotate_argument_and_return_for_borrow(
|
||||
// case it ends up being assigned into the return place.
|
||||
annotated_closure = self.annotate_fn_sig(
|
||||
*def_id,
|
||||
self.infcx.closure_sig(*def_id, *substs)
|
||||
self.infcx.closure_sig(*def_id, *substs),
|
||||
);
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
annotated_closure={:?} assigned_from_local={:?} \
|
||||
assigned_to={:?}",
|
||||
annotated_closure, assigned_from_local, assigned_to
|
||||
annotated_closure, assigned_from_local, assigned_to
|
||||
);
|
||||
|
||||
if *assigned_to == mir::RETURN_PLACE {
|
||||
@@ -1382,15 +1450,17 @@ fn annotate_argument_and_return_for_borrow(
|
||||
let assigned_from = match rvalue {
|
||||
Rvalue::Ref(_, _, assigned_from) => assigned_from,
|
||||
Rvalue::Use(operand) => match operand {
|
||||
Operand::Copy(assigned_from) |
|
||||
Operand::Move(assigned_from) => assigned_from,
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from={:?}", assigned_from,
|
||||
assigned_from={:?}",
|
||||
assigned_from,
|
||||
);
|
||||
|
||||
// Find the local from the rvalue.
|
||||
@@ -1400,7 +1470,8 @@ fn annotate_argument_and_return_for_borrow(
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?}", assigned_from_local,
|
||||
assigned_from_local={:?}",
|
||||
assigned_from_local,
|
||||
);
|
||||
|
||||
// Check if our local matches the target - if so, we've assigned our
|
||||
@@ -1414,7 +1485,7 @@ fn annotate_argument_and_return_for_borrow(
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?} assigned_to={:?}",
|
||||
assigned_from_local, assigned_to
|
||||
assigned_from_local, assigned_to
|
||||
);
|
||||
if *assigned_to == mir::RETURN_PLACE {
|
||||
// If it was then return the annotated closure if there was one,
|
||||
@@ -1438,15 +1509,17 @@ fn annotate_argument_and_return_for_borrow(
|
||||
destination: Some((Place::Local(assigned_to), _)),
|
||||
args,
|
||||
..
|
||||
} = &terminator.kind {
|
||||
} = &terminator.kind
|
||||
{
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
|
||||
assigned_to, args
|
||||
);
|
||||
for operand in args {
|
||||
let assigned_from = match operand {
|
||||
Operand::Copy(assigned_from) |
|
||||
Operand::Move(assigned_from) => assigned_from,
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
@@ -1460,9 +1533,7 @@ fn annotate_argument_and_return_for_borrow(
|
||||
assigned_from_local,
|
||||
);
|
||||
|
||||
if *assigned_to == mir::RETURN_PLACE &&
|
||||
assigned_from_local == target
|
||||
{
|
||||
if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
|
||||
return annotated_closure.or_else(fallback);
|
||||
}
|
||||
}
|
||||
@@ -1529,7 +1600,7 @@ fn annotate_fn_sig(
|
||||
// With access to the lifetime, we can get
|
||||
// the span of it.
|
||||
arguments.push((*argument, lifetime.span));
|
||||
},
|
||||
}
|
||||
_ => bug!("ty type is a ref but hir type is not"),
|
||||
}
|
||||
}
|
||||
@@ -1556,7 +1627,7 @@ fn annotate_fn_sig(
|
||||
return_ty,
|
||||
return_span,
|
||||
})
|
||||
},
|
||||
}
|
||||
ty::TyKind::Ref(_, _, _) if is_closure => {
|
||||
// This is case 2 from above but only for closures, return type is anonymous
|
||||
// reference so we select
|
||||
@@ -1577,7 +1648,7 @@ fn annotate_fn_sig(
|
||||
}
|
||||
|
||||
None
|
||||
},
|
||||
}
|
||||
ty::TyKind::Ref(_, _, _) => {
|
||||
// This is also case 2 from above but for functions, return type is still an
|
||||
// anonymous reference so we select the first argument.
|
||||
@@ -1589,7 +1660,7 @@ fn annotate_fn_sig(
|
||||
|
||||
// We expect the first argument to be a reference.
|
||||
match argument_ty.sty {
|
||||
ty::TyKind::Ref(_, _, _) => {},
|
||||
ty::TyKind::Ref(_, _, _) => {}
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
@@ -1599,12 +1670,12 @@ fn annotate_fn_sig(
|
||||
return_ty,
|
||||
return_span,
|
||||
})
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
// This is case 3 from above, return type is not a reference so don't highlight
|
||||
// anything.
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1625,25 +1696,25 @@ enum AnnotatedBorrowFnSignature<'tcx> {
|
||||
Closure {
|
||||
argument_ty: ty::Ty<'tcx>,
|
||||
argument_span: Span,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
|
||||
/// Annotate the provided diagnostic with information about borrow from the fn signature that
|
||||
/// helps explain.
|
||||
fn emit(
|
||||
&self,
|
||||
diag: &mut DiagnosticBuilder<'_>
|
||||
) -> String {
|
||||
fn emit(&self, diag: &mut DiagnosticBuilder<'_>) -> String {
|
||||
match self {
|
||||
AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
|
||||
AnnotatedBorrowFnSignature::Closure {
|
||||
argument_ty,
|
||||
argument_span,
|
||||
} => {
|
||||
diag.span_label(
|
||||
*argument_span,
|
||||
format!("has type `{}`", self.get_name_for_ty(argument_ty, 0)),
|
||||
);
|
||||
|
||||
self.get_region_name_for_ty(argument_ty, 0)
|
||||
},
|
||||
}
|
||||
AnnotatedBorrowFnSignature::AnonymousFunction {
|
||||
argument_ty,
|
||||
argument_span,
|
||||
@@ -1651,10 +1722,7 @@ fn emit(
|
||||
return_span,
|
||||
} => {
|
||||
let argument_ty_name = self.get_name_for_ty(argument_ty, 0);
|
||||
diag.span_label(
|
||||
*argument_span,
|
||||
format!("has type `{}`", argument_ty_name)
|
||||
);
|
||||
diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
|
||||
|
||||
let return_ty_name = self.get_name_for_ty(return_ty, 0);
|
||||
let types_equal = return_ty_name == argument_ty_name;
|
||||
@@ -1664,7 +1732,7 @@ fn emit(
|
||||
"{}has type `{}`",
|
||||
if types_equal { "also " } else { "" },
|
||||
return_ty_name,
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
diag.note(
|
||||
@@ -1676,7 +1744,7 @@ fn emit(
|
||||
);
|
||||
|
||||
self.get_region_name_for_ty(return_ty, 0)
|
||||
},
|
||||
}
|
||||
AnnotatedBorrowFnSignature::NamedFunction {
|
||||
arguments,
|
||||
return_ty,
|
||||
@@ -1685,30 +1753,22 @@ fn emit(
|
||||
// Region of return type and arguments checked to be the same earlier.
|
||||
let region_name = self.get_region_name_for_ty(return_ty, 0);
|
||||
for (_, argument_span) in arguments {
|
||||
diag.span_label(
|
||||
*argument_span,
|
||||
format!("has lifetime `{}`", region_name)
|
||||
);
|
||||
diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
|
||||
}
|
||||
|
||||
diag.span_label(
|
||||
*return_span,
|
||||
format!(
|
||||
"also has lifetime `{}`",
|
||||
region_name,
|
||||
)
|
||||
format!("also has lifetime `{}`", region_name,),
|
||||
);
|
||||
|
||||
diag.help(
|
||||
&format!(
|
||||
"use data from the highlighted arguments which match the `{}` lifetime of \
|
||||
the return type",
|
||||
region_name,
|
||||
),
|
||||
);
|
||||
diag.help(&format!(
|
||||
"use data from the highlighted arguments which match the `{}` lifetime of \
|
||||
the return type",
|
||||
region_name,
|
||||
));
|
||||
|
||||
region_name
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1719,9 +1779,10 @@ fn get_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
|
||||
// this by hooking into the pretty printer and telling it to label the
|
||||
// lifetimes without names with the value `'0`.
|
||||
match ty.sty {
|
||||
ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _) |
|
||||
ty::TyKind::Ref(ty::RegionKind::ReSkolemized(_, br), _, _) =>
|
||||
with_highlight_region_for_bound_region(*br, counter, || format!("{}", ty)),
|
||||
ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _)
|
||||
| ty::TyKind::Ref(ty::RegionKind::ReSkolemized(_, br), _, _) => {
|
||||
with_highlight_region_for_bound_region(*br, counter, || format!("{}", ty))
|
||||
}
|
||||
_ => format!("{}", ty),
|
||||
}
|
||||
}
|
||||
@@ -1731,11 +1792,11 @@ fn get_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
|
||||
fn get_region_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
|
||||
match ty.sty {
|
||||
ty::TyKind::Ref(region, _, _) => match region {
|
||||
ty::RegionKind::ReLateBound(_, br) |
|
||||
ty::RegionKind::ReSkolemized(_, br) =>
|
||||
with_highlight_region_for_bound_region(*br, counter, || format!("{}", region)),
|
||||
ty::RegionKind::ReLateBound(_, br) | ty::RegionKind::ReSkolemized(_, br) => {
|
||||
with_highlight_region_for_bound_region(*br, counter, || format!("{}", region))
|
||||
}
|
||||
_ => format!("{}", region),
|
||||
}
|
||||
},
|
||||
_ => bug!("ty for annotation of borrow region is not a reference"),
|
||||
}
|
||||
}
|
||||
@@ -1828,9 +1889,9 @@ pub(super) fn move_spans(
|
||||
debug!("find_closure_move_span: found closure {:?}", places);
|
||||
|
||||
if let Some(node_id) = self.infcx.tcx.hir.as_local_node_id(def_id) {
|
||||
if let Closure(
|
||||
_, _, _, args_span, _
|
||||
) = self.infcx.tcx.hir.expect_expr(node_id).node {
|
||||
if let Closure(_, _, _, args_span, _) =
|
||||
self.infcx.tcx.hir.expect_expr(node_id).node
|
||||
{
|
||||
if let Some(var_span) = self.infcx.tcx.with_freevars(node_id, |freevars| {
|
||||
for (v, place) in freevars.iter().zip(places) {
|
||||
match place {
|
||||
@@ -1886,8 +1947,8 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan
|
||||
}
|
||||
|
||||
for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
|
||||
if let StatementKind::Assign(_, box Rvalue::Aggregate(ref kind, ref places))
|
||||
= stmt.kind {
|
||||
if let StatementKind::Assign(_, box Rvalue::Aggregate(ref kind, ref places)) = stmt.kind
|
||||
{
|
||||
if let AggregateKind::Closure(def_id, _) = **kind {
|
||||
debug!("find_closure_borrow_span: found closure {:?}", places);
|
||||
|
||||
@@ -1900,13 +1961,13 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan
|
||||
return OtherUse(use_span);
|
||||
};
|
||||
|
||||
self.infcx.tcx
|
||||
self.infcx
|
||||
.tcx
|
||||
.with_freevars(node_id, |freevars| {
|
||||
for (v, place) in freevars.iter().zip(places) {
|
||||
match *place {
|
||||
Operand::Copy(Place::Local(l))
|
||||
| Operand::Move(Place::Local(l))
|
||||
if local == l =>
|
||||
| Operand::Move(Place::Local(l)) if local == l =>
|
||||
{
|
||||
debug!(
|
||||
"find_closure_borrow_span: found captured local \
|
||||
@@ -1919,10 +1980,12 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan
|
||||
}
|
||||
}
|
||||
None
|
||||
}).map(|var_span| ClosureUse {
|
||||
})
|
||||
.map(|var_span| ClosureUse {
|
||||
args_span,
|
||||
var_span,
|
||||
}).unwrap_or(OtherUse(use_span))
|
||||
})
|
||||
.unwrap_or(OtherUse(use_span))
|
||||
} else {
|
||||
OtherUse(use_span)
|
||||
};
|
||||
|
||||
@@ -46,9 +46,9 @@ pub(in borrow_check) fn emit<'cx, 'gcx>(
|
||||
},
|
||||
BorrowExplanation::UsedLaterInLoop(is_in_closure, var_or_use_span) => {
|
||||
let message = if is_in_closure {
|
||||
"borrow captured here by closure in later iteration of loop"
|
||||
"borrow captured here by closure, in later iteration of loop"
|
||||
} else {
|
||||
"borrow used here in later iteration of loop"
|
||||
"borrow used here, in later iteration of loop"
|
||||
};
|
||||
err.span_label(var_or_use_span, message);
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@ LL | for &x in &vector {
|
||||
| -------
|
||||
| |
|
||||
| immutable borrow occurs here
|
||||
| borrow used here in later iteration of loop
|
||||
| borrow used here, in later iteration of loop
|
||||
LL | let cap = vector.capacity();
|
||||
LL | vector.extend(repeat(0)); //~ ERROR cannot borrow
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
@@ -17,7 +17,7 @@ LL | for &x in &vector {
|
||||
| -------
|
||||
| |
|
||||
| immutable borrow occurs here
|
||||
| borrow used here in later iteration of loop
|
||||
| borrow used here, in later iteration of loop
|
||||
...
|
||||
LL | vector[1] = 5; //~ ERROR cannot borrow
|
||||
| ^^^^^^ mutable borrow occurs here
|
||||
|
||||
@@ -8,13 +8,13 @@ LL | borrow(&*v); //~ ERROR cannot borrow
|
||||
| ^^^ immutable borrow occurs here
|
||||
LL | }
|
||||
LL | *x = box 5;
|
||||
| -- borrow used here in later iteration of loop
|
||||
| -- borrow used here, in later iteration of loop
|
||||
|
||||
error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-lend-flow-loop.rs:109:16
|
||||
|
|
||||
LL | **x += 1;
|
||||
| -------- borrow used here in later iteration of loop
|
||||
| -------- borrow used here, in later iteration of loop
|
||||
LL | borrow(&*v); //~ ERROR cannot borrow
|
||||
| ^^^ immutable borrow occurs here
|
||||
LL | if cond2 {
|
||||
|
||||
@@ -4,7 +4,7 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
|
||||
LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
|
||||
| ---- ^^^^^^ second mutable borrow occurs here
|
||||
| |
|
||||
| borrow used here in later iteration of loop
|
||||
| borrow used here, in later iteration of loop
|
||||
...
|
||||
LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
|
||||
| ------ first mutable borrow occurs here
|
||||
@@ -13,7 +13,7 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
|
||||
--> $DIR/borrowck-mut-borrow-linear-errors.rs:25:30
|
||||
|
|
||||
LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
|
||||
| ---- borrow used here in later iteration of loop
|
||||
| ---- borrow used here, in later iteration of loop
|
||||
LL | //[mir]~^ ERROR [E0499]
|
||||
LL | 2 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
|
||||
| ^^^^^^ second mutable borrow occurs here
|
||||
|
||||
@@ -4,7 +4,7 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
|
||||
LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
|
||||
| ---- ^^^^^^ second mutable borrow occurs here
|
||||
| |
|
||||
| borrow used here in later iteration of loop
|
||||
| borrow used here, in later iteration of loop
|
||||
...
|
||||
LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
|
||||
| ------ first mutable borrow occurs here
|
||||
@@ -13,7 +13,7 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
|
||||
--> $DIR/borrowck-mut-borrow-linear-errors.rs:25:30
|
||||
|
|
||||
LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
|
||||
| ---- borrow used here in later iteration of loop
|
||||
| ---- borrow used here, in later iteration of loop
|
||||
LL | //[mir]~^ ERROR [E0499]
|
||||
LL | 2 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
|
||||
| ^^^^^^ second mutable borrow occurs here
|
||||
|
||||
@@ -20,7 +20,7 @@ error[E0382]: use of moved value (Mir)
|
||||
--> $DIR/issue-41962.rs:17:21
|
||||
|
|
||||
LL | if let Some(thing) = maybe {
|
||||
| ^^^^^ value moved here in previous iteration of loop
|
||||
| ^^^^^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ LL | let inner_second = &mut inner_void; //~ ERROR cannot borrow
|
||||
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
|
||||
LL | inner_second.use_mut();
|
||||
LL | inner_first.use_mut();
|
||||
| ----------- borrow used here in later iteration of loop
|
||||
| ----------- borrow used here, in later iteration of loop
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `tx`
|
||||
--> $DIR/issue-12041.rs:18:22
|
||||
|
|
||||
LL | let tx = tx;
|
||||
| ^^ value moved here in previous iteration of loop
|
||||
| ^^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `tx` has type `std::sync::mpsc::Sender<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ LL | let v: Vec<&str> = line.split_whitespace().collect();
|
||||
| ^^^^ borrowed value does not live long enough
|
||||
LL | //~^ ERROR `line` does not live long enough
|
||||
LL | println!("accumulator before add_assign {:?}", acc.map);
|
||||
| ------- borrow used here in later iteration of loop
|
||||
| ------- borrow used here, in later iteration of loop
|
||||
...
|
||||
LL | }
|
||||
| - `line` dropped here while still borrowed
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/liveness-move-call-arg.rs:19:14
|
||||
|
|
||||
LL | take(x); //~ ERROR use of moved value: `x`
|
||||
| ^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
@@ -0,0 +1,11 @@
|
||||
error[E0382]: use of moved value: `y`
|
||||
--> $DIR/liveness-move-in-loop.rs:21:25
|
||||
|
|
||||
LL | x = y; //~ ERROR use of moved value
|
||||
| ^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
@@ -4,7 +4,7 @@ error[E0382]: borrow of moved value: `y`
|
||||
LL | println!("{}", y); //~ ERROR use of moved value: `y`
|
||||
| ^ value borrowed here after move
|
||||
LL | while true { while true { while true { x = y; x.clone(); } } }
|
||||
| - value moved here
|
||||
| - value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/move-in-guard-2.rs:20:24
|
||||
|
|
||||
LL | (_, 2) if take(x) => (), //~ ERROR use of moved value: `x`
|
||||
| ^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
@@ -4,7 +4,7 @@ error[E0382]: use of moved value: `x`
|
||||
LL | || x; //~ ERROR
|
||||
| ^^ - use occurs due to use in closure
|
||||
| |
|
||||
| value moved into closure here in previous iteration of loop
|
||||
| value moved into closure here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ error[E0382]: use of moved value
|
||||
--> $DIR/issue-53807.rs:14:21
|
||||
|
|
||||
LL | if let Some(thing) = maybe {
|
||||
| ^^^^^ value moved here in previous iteration of loop
|
||||
| ^^^^^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ LL | foo.mutate();
|
||||
| ^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | //~^ ERROR cannot borrow `foo` as mutable
|
||||
LL | println!("foo={:?}", *string);
|
||||
| ------- borrow used here in later iteration of loop
|
||||
| ------- borrow used here, in later iteration of loop
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ error[E0597]: `x` does not live long enough
|
||||
--> $DIR/regions-escape-loop-via-variable.rs:21:13
|
||||
|
|
||||
LL | let x = 1 + *p;
|
||||
| -- borrow used here in later iteration of loop
|
||||
| -- borrow used here, in later iteration of loop
|
||||
LL | p = &x;
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
|
||||
@@ -7,7 +7,7 @@ LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed
|
||||
| ^ use of borrowed `x`
|
||||
LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
|
||||
LL | _y.push(&mut z);
|
||||
| -- borrow used here in later iteration of loop
|
||||
| -- borrow used here, in later iteration of loop
|
||||
|
||||
error[E0503]: cannot use `x` because it was mutably borrowed
|
||||
--> $DIR/regions-escape-loop-via-vec.rs:16:21
|
||||
@@ -18,7 +18,7 @@ LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed
|
||||
LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
|
||||
| ^ use of borrowed `x`
|
||||
LL | _y.push(&mut z);
|
||||
| -- borrow used here in later iteration of loop
|
||||
| -- borrow used here, in later iteration of loop
|
||||
|
||||
error[E0597]: `z` does not live long enough
|
||||
--> $DIR/regions-escape-loop-via-vec.rs:17:17
|
||||
@@ -26,7 +26,7 @@ error[E0597]: `z` does not live long enough
|
||||
LL | _y.push(&mut z);
|
||||
| -- ^^^^^^ borrowed value does not live long enough
|
||||
| |
|
||||
| borrow used here in later iteration of loop
|
||||
| borrow used here, in later iteration of loop
|
||||
...
|
||||
LL | }
|
||||
| - `z` dropped here while still borrowed
|
||||
@@ -38,7 +38,7 @@ LL | let mut _y = vec![&mut x];
|
||||
| ------ borrow of `x` occurs here
|
||||
...
|
||||
LL | _y.push(&mut z);
|
||||
| -- borrow used here in later iteration of loop
|
||||
| -- borrow used here, in later iteration of loop
|
||||
LL | //~^ ERROR `z` does not live long enough
|
||||
LL | x += 1; //~ ERROR cannot assign
|
||||
| ^^^^^^ use of borrowed `x`
|
||||
|
||||
@@ -5,7 +5,7 @@ LL | for x in &mut xs {
|
||||
| -------
|
||||
| |
|
||||
| first mutable borrow occurs here
|
||||
| borrow used here in later iteration of loop
|
||||
| borrow used here, in later iteration of loop
|
||||
LL | xs.push(1) //~ ERROR cannot borrow `xs`
|
||||
| ^^ second mutable borrow occurs here
|
||||
|
||||
|
||||
Reference in New Issue
Block a user