Skip to content

Commit d5ae6f7

Browse files
committed
[54015] NLL:Improve move error loop detection
Before this patch running the following command would generate the given output: $ rustc +stage1 src/test/ui/liveness/liveness-move-in-while.rs -Zborrowck=mir -Ztwo-phase-borrows error[E0382]: borrow of moved value: `y` --> src/main.rs:8:24 | 8 | println!("{}", y); //~ ERROR use of moved value: `y` | ^ value borrowed here after move 9 | while true { while true { while true { x = y; x.clone(); } } } | - value moved here | = note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait We want to give the user more hint by telling them that the value was moved in the previous iteration of the loop. After this patch, the error message adds the phrase "in previous iteration of loop" and in totality looks like this: $ rustc +stage1 src/test/ui/liveness/liveness-move-in-while.rs -Zborrowck=mir -Ztwo-phase-borrows error[E0382]: borrow of moved value: `y` --> src/test/ui/liveness/liveness-move-in-while.rs:17:24 | 17 | println!("{}", y); //~ ERROR use of moved value: `y` | ^ value borrowed here after move 18 | while true { while true { while true { x = y; x.clone(); } } } | - 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
1 parent 2ac6cdf commit d5ae6f7

File tree

2 files changed

+60
-25
lines changed

2 files changed

+60
-25
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

+58-23
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ use dataflow::move_paths::indexes::MoveOutIndex;
3535
use dataflow::move_paths::MovePathIndex;
3636
use util::borrowck_errors::{BorrowckErrors, Origin};
3737

38+
#[derive(Debug)]
39+
struct MoveSite {
40+
/// Index of the "move out" that we found. The `MoveData` can
41+
/// then tell us where the move occurred.
42+
moi: MoveOutIndex,
43+
44+
/// True if we traversed a back edge while walking from the point
45+
/// of error to the move site.
46+
traversed_back_edge: bool
47+
}
48+
3849
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
3950
pub(super) fn report_use_of_moved_or_uninitialized(
4051
&mut self,
@@ -53,10 +64,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
5364
.or_else(|| self.borrow_spans(span, context.loc));
5465
let span = use_spans.args_or_use();
5566

56-
let mois = self.get_moved_indexes(context, mpi);
57-
debug!("report_use_of_moved_or_uninitialized: mois={:?}", mois);
67+
let move_site_vec = self.get_moved_indexes(context, mpi);
68+
debug!(
69+
"report_use_of_moved_or_uninitialized: move_site_vec={:?}",
70+
move_site_vec
71+
);
72+
let move_out_indices: Vec<_> = move_site_vec
73+
.iter()
74+
.map(|move_site| move_site.moi)
75+
.collect();
5876

59-
if mois.is_empty() {
77+
if move_out_indices.is_empty() {
6078
let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
6179

6280
if self.uninitialized_error_reported
@@ -91,14 +109,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
91109

92110
err.buffer(&mut self.errors_buffer);
93111
} else {
94-
if let Some((reported_place, _)) = self.move_error_reported.get(&mois) {
112+
if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
95113
if self.prefixes(&reported_place, PrefixSet::All)
96114
.any(|p| p == place)
97115
{
98116
debug!(
99117
"report_use_of_moved_or_uninitialized place: error suppressed \
100118
mois={:?}",
101-
mois
119+
move_out_indices
102120
);
103121
return;
104122
}
@@ -115,8 +133,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
115133
);
116134

117135
let mut is_loop_move = false;
118-
for moi in &mois {
119-
let move_out = self.move_data.moves[*moi];
136+
for move_site in &move_site_vec {
137+
let move_out = self.move_data.moves[(*move_site).moi];
120138
let moved_place = &self.move_data.move_paths[move_out.path].place;
121139

122140
let move_spans = self.move_spans(moved_place, move_out.source);
@@ -131,9 +149,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
131149
if span == move_span {
132150
err.span_label(
133151
span,
134-
format!("value moved{} here in previous iteration of loop", move_msg),
152+
format!("value moved{} here, in previous iteration of loop", move_msg),
135153
);
136154
is_loop_move = true;
155+
} else if move_site.traversed_back_edge {
156+
err.span_label(
157+
move_span,
158+
format!(
159+
"value moved{} here, in previous iteration of loop",
160+
move_msg
161+
),
162+
);
137163
} else {
138164
err.span_label(move_span, format!("value moved{} here", move_msg));
139165
move_spans.var_span_label(&mut err, "variable moved due to use in closure");
@@ -171,7 +197,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
171197
};
172198

173199
if needs_note {
174-
let mpi = self.move_data.moves[mois[0]].path;
200+
let mpi = self.move_data.moves[move_out_indices[0]].path;
175201
let place = &self.move_data.move_paths[mpi].place;
176202

177203
if let Some(ty) = self.retrieve_type_for_place(place) {
@@ -192,8 +218,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
192218
}
193219
}
194220

195-
if let Some((_, mut old_err)) =
196-
self.move_error_reported.insert(mois, (place.clone(), err))
221+
if let Some((_, mut old_err)) = self.move_error_reported
222+
.insert(move_out_indices, (place.clone(), err))
197223
{
198224
// Cancel the old error so it doesn't ICE.
199225
old_err.cancel();
@@ -733,29 +759,32 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
733759
err
734760
}
735761

736-
fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveOutIndex> {
762+
fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveSite> {
737763
let mir = self.mir;
738764

739765
let mut stack = Vec::new();
740-
stack.extend(mir.predecessor_locations(context.loc));
766+
stack.extend(mir.predecessor_locations(context.loc).map(|predecessor| {
767+
let is_back_edge = context.loc.dominates(predecessor, &self.dominators);
768+
(predecessor, is_back_edge)
769+
}));
741770

742771
let mut visited = FxHashSet();
743772
let mut result = vec![];
744773

745-
'dfs: while let Some(l) = stack.pop() {
774+
'dfs: while let Some((location, is_back_edge)) = stack.pop() {
746775
debug!(
747-
"report_use_of_moved_or_uninitialized: current_location={:?}",
748-
l
776+
"report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
777+
location, is_back_edge
749778
);
750779

751-
if !visited.insert(l) {
780+
if !visited.insert(location) {
752781
continue;
753782
}
754783

755784
// check for moves
756-
let stmt_kind = mir[l.block]
785+
let stmt_kind = mir[location.block]
757786
.statements
758-
.get(l.statement_index)
787+
.get(location.statement_index)
759788
.map(|s| &s.kind);
760789
if let Some(StatementKind::StorageDead(..)) = stmt_kind {
761790
// this analysis only tries to find moves explicitly
@@ -774,11 +803,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
774803
let move_paths = &self.move_data.move_paths;
775804
mpis.extend(move_paths[mpi].parents(move_paths));
776805

777-
for moi in &self.move_data.loc_map[l] {
806+
for moi in &self.move_data.loc_map[location] {
778807
debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
779808
if mpis.contains(&self.move_data.moves[*moi].path) {
780809
debug!("report_use_of_moved_or_uninitialized: found");
781-
result.push(*moi);
810+
result.push(MoveSite {
811+
moi: *moi,
812+
traversed_back_edge: is_back_edge,
813+
});
782814

783815
// Strictly speaking, we could continue our DFS here. There may be
784816
// other moves that can reach the point of error. But it is kind of
@@ -807,7 +839,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
807839
self.infcx.tcx,
808840
self.mir,
809841
self.move_data,
810-
l,
842+
location,
811843
|m| {
812844
if m == mpi {
813845
any_match = true;
@@ -818,7 +850,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
818850
continue 'dfs;
819851
}
820852

821-
stack.extend(mir.predecessor_locations(l));
853+
stack.extend(mir.predecessor_locations(location).map(|predecessor| {
854+
let back_edge = location.dominates(predecessor, &self.dominators);
855+
(predecessor, is_back_edge || back_edge)
856+
}));
822857
}
823858

824859
result

src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ impl<'tcx> BorrowExplanation<'tcx> {
4646
},
4747
BorrowExplanation::UsedLaterInLoop(is_in_closure, var_or_use_span) => {
4848
let message = if is_in_closure {
49-
"borrow captured here by closure in later iteration of loop"
49+
"borrow captured here by closure, in later iteration of loop"
5050
} else {
51-
"borrow used here in later iteration of loop"
51+
"borrow used here, in later iteration of loop"
5252
};
5353
err.span_label(var_or_use_span, message);
5454
},

0 commit comments

Comments
 (0)