1
Fork 0

Auto merge of #85686 - ptrojahn:loop_reinitialize, r=estebank

Add help on reinitialization between move and access

Fixes #83760
This commit is contained in:
bors 2021-07-18 02:13:12 +00:00
commit 77d155973c
3 changed files with 176 additions and 18 deletions

View file

@ -12,7 +12,7 @@ use rustc_middle::mir::{
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
use crate::dataflow::drop_flag_effects;
@ -66,7 +66,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location));
let span = use_spans.args_or_use();
let move_site_vec = self.get_moved_indexes(location, mpi);
let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi);
debug!(
"report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
move_site_vec, use_spans
@ -139,6 +139,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.describe_place_with_options(moved_place, IncludingDowncast(true)),
);
let reinit_spans = maybe_reinitialized_locations
.iter()
.take(3)
.map(|loc| {
self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc)
.args_or_use()
})
.collect::<Vec<Span>>();
let reinits = maybe_reinitialized_locations.len();
if reinits == 1 {
err.span_label(reinit_spans[0], "this reinitialization might get skipped");
} else if reinits > 1 {
err.span_note(
MultiSpan::from_spans(reinit_spans),
&if reinits <= 3 {
format!("these {} reinitializations might get skipped", reinits)
} else {
format!(
"these 3 reinitializations and {} other{} might get skipped",
reinits - 3,
if reinits == 4 { "" } else { "s" }
)
},
);
}
self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
let mut is_loop_move = false;
@ -219,7 +245,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
),
);
}
if is_option_or_result {
if is_option_or_result && maybe_reinitialized_locations.is_empty() {
err.span_suggestion_verbose(
fn_call_span.shrink_to_lo(),
"consider calling `.as_ref()` to borrow the type's contents",
@ -260,19 +286,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
if let UseSpans::PatUse(span) = move_spans {
err.span_suggestion_verbose(
span.shrink_to_lo(),
&format!(
"borrow this field in the pattern to avoid moving {}",
self.describe_place(moved_place.as_ref())
.map(|n| format!("`{}`", n))
.unwrap_or_else(|| "the value".to_string())
),
"ref ".to_string(),
Applicability::MachineApplicable,
);
in_pattern = true;
if let (UseSpans::PatUse(span), []) =
(move_spans, &maybe_reinitialized_locations[..])
{
if maybe_reinitialized_locations.is_empty() {
err.span_suggestion_verbose(
span.shrink_to_lo(),
&format!(
"borrow this field in the pattern to avoid moving {}",
self.describe_place(moved_place.as_ref())
.map(|n| format!("`{}`", n))
.unwrap_or_else(|| "the value".to_string())
),
"ref ".to_string(),
Applicability::MachineApplicable,
);
in_pattern = true;
}
}
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
@ -1465,7 +1495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err
}
fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
fn get_moved_indexes(
&mut self,
location: Location,
mpi: MovePathIndex,
) -> (Vec<MoveSite>, Vec<Location>) {
fn predecessor_locations(
body: &'a mir::Body<'tcx>,
location: Location,
@ -1488,6 +1522,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}));
let mut visited = FxHashSet::default();
let mut move_locations = FxHashSet::default();
let mut reinits = vec![];
let mut result = vec![];
'dfs: while let Some((location, is_back_edge)) = stack.pop() {
@ -1529,6 +1565,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_paths[path].place
);
result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge });
move_locations.insert(location);
// 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
@ -1565,6 +1602,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
},
);
if any_match {
reinits.push(location);
continue 'dfs;
}
@ -1574,7 +1612,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}));
}
result
// Check if we can reach these reinits from a move location.
let reinits_reachable = reinits
.into_iter()
.filter(|reinit| {
let mut visited = FxHashSet::default();
let mut stack = vec![*reinit];
while let Some(location) = stack.pop() {
if !visited.insert(location) {
continue;
}
if move_locations.contains(&location) {
return true;
}
stack.extend(predecessor_locations(self.body, location));
}
false
})
.collect::<Vec<Location>>();
(result, reinits_reachable)
}
pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(