Skip to content

Commit

Permalink
De-duplicate moved variable errors.
Browse files Browse the repository at this point in the history
By introducing a new map that tracks the errors reported and the
`Place`s that spawned those errors against the move out that the error
was referring to, we are able to silence duplicate errors by emitting
only the error which corresponds to the most specific `Place` (that which
other `Place`s which reported errors are prefixes of).

This generally is an improvement, however there is a case -
`liveness-move-in-while` - where the output regresses.
  • Loading branch information
davidtwco committed Sep 6, 2018
1 parent 308d197 commit b45648b
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 130 deletions.
26 changes: 23 additions & 3 deletions src/librustc_mir/borrow_check/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(place, span): (&Place<'tcx>, Span),
mpi: MovePathIndex,
) {
debug!(
"report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} place={:?} \
span={:?} mpi={:?}",
context, desired_action, place, span, mpi
);

let use_spans = self
.move_spans(place, context.loc)
.or_else(|| self.borrow_spans(span, context.loc));
Expand All @@ -49,15 +55,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
if mois.is_empty() {
let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();

if self.moved_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
);
return;
}

self.moved_error_reported.insert(root_place.clone());
self.uninitialized_error_reported.insert(root_place.clone());

let item_msg = match self.describe_place_with_options(place, IncludingDowncast(true)) {
Some(name) => format!("`{}`", name),
Expand All @@ -80,6 +86,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {

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);
return;
}
}

let msg = ""; //FIXME: add "partially " or "collaterally "

let mut err = self.tcx.cannot_act_on_moved_value(
Expand Down Expand Up @@ -167,7 +181,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
}

err.buffer(&mut self.errors_buffer);
if let Some((_, mut old_err)) = self.move_error_reported.insert(
mois,
(place.clone(), err)
) {
// Cancel the old error so it doesn't ICE.
old_err.cancel();
}
}
}

Expand Down
28 changes: 23 additions & 5 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use rustc::ty::{self, ParamEnv, TyCtxt, Ty};

use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level};
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_set::IdxSet;
use rustc_data_structures::indexed_vec::Idx;
use smallvec::SmallVec;
Expand All @@ -38,6 +38,7 @@ use syntax_pos::Span;

use dataflow::indexes::BorrowIndex;
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveError, MovePathIndex};
use dataflow::move_paths::indexes::MoveOutIndex;
use dataflow::Borrows;
use dataflow::DataflowResultsConsumer;
use dataflow::FlowAtLocation;
Expand Down Expand Up @@ -247,7 +248,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
},
access_place_error_reported: FxHashSet(),
reservation_error_reported: FxHashSet(),
moved_error_reported: FxHashSet(),
move_error_reported: FxHashMap(),
uninitialized_error_reported: FxHashSet(),
errors_buffer,
nonlexical_regioncx: regioncx,
used_mut: FxHashSet(),
Expand Down Expand Up @@ -325,6 +327,11 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
}
}

// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in mbcx.move_error_reported.drain() {
diag.buffer(&mut mbcx.errors_buffer);
}

if mbcx.errors_buffer.len() > 0 {
mbcx.errors_buffer.sort_by_key(|diag| diag.span.primary_span());

Expand Down Expand Up @@ -400,9 +407,20 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
/// but it is currently inconvenient to track down the BorrowIndex
/// at the time we detect and report a reservation error.
reservation_error_reported: FxHashSet<Place<'tcx>>,
/// This field keeps track of errors reported in the checking of moved variables,
/// This field keeps track of move errors that are to be reported for given move indicies.
///
/// There are situations where many errors can be reported for a single move out (see #53807)
/// and we want only the best of those errors.
///
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
/// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
/// all move errors have been reported, any diagnostics in this map are added to the buffer
/// to be emitted.
move_error_reported: FxHashMap<Vec<MoveOutIndex>, (Place<'tcx>, DiagnosticBuilder<'cx>)>,
/// This field keeps track of errors reported in the checking of uninitialized variables,
/// so that we don't report seemingly duplicate errors.
moved_error_reported: FxHashSet<Place<'tcx>>,
uninitialized_error_reported: FxHashSet<Place<'tcx>>,
/// Errors to be reported buffer
errors_buffer: Vec<Diagnostic>,
/// This field keeps track of all the local variables that are declared mut and are mutated.
Expand Down Expand Up @@ -793,7 +811,7 @@ enum LocalMutationIsAllowed {
No,
}

#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
enum InitializationRequiringAction {
Update,
Borrow,
Expand Down
16 changes: 8 additions & 8 deletions src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,31 @@ LL | drop(x2); //~ ERROR cannot move `x2` into closure because it is bor
LL | borrow(&*p2);
| ---- borrow later used here

error[E0382]: use of moved value: `x1`
error[E0382]: use of moved value: `x2`
--> $DIR/borrowck-multiple-captures.rs:35:19
|
LL | drop(x1);
LL | drop(x2);
| -- value moved here
...
LL | thread::spawn(move|| {
| ^^^^^^ value used here after move
LL | drop(x1); //~ ERROR capture of moved value: `x1`
LL | drop(x2); //~ ERROR capture of moved value: `x2`
| -- use occurs due to use in closure
|
= note: move occurs because `x1` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
= note: move occurs because `x2` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `x2`
error[E0382]: use of moved value: `x1`
--> $DIR/borrowck-multiple-captures.rs:35:19
|
LL | drop(x2);
LL | drop(x1);
| -- value moved here
...
LL | thread::spawn(move|| {
| ^^^^^^ value used here after move
LL | drop(x1); //~ ERROR capture of moved value: `x1`
LL | drop(x2); //~ ERROR capture of moved value: `x2`
| -- use occurs due to use in closure
|
= note: move occurs because `x2` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
= note: move occurs because `x1` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `x`
--> $DIR/borrowck-multiple-captures.rs:46:14
Expand Down
3 changes: 0 additions & 3 deletions src/test/ui/borrowck/issue-41962.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ pub fn main(){
}
//~^^ ERROR use of partially moved value: `maybe` (Ast) [E0382]
//~| ERROR use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast) [E0382]
//~| ERROR use of moved value: `maybe` (Mir) [E0382]
//~| ERROR use of moved value: `maybe` (Mir) [E0382]
//~| ERROR use of moved value (Mir) [E0382]
//~| ERROR borrow of moved value: `maybe` (Mir) [E0382]
}
}
33 changes: 1 addition & 32 deletions src/test/ui/borrowck/issue-41962.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,6 @@ LL | if let Some(thing) = maybe {
|
= note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `maybe` (Mir)
--> $DIR/issue-41962.rs:17:16
|
LL | if let Some(thing) = maybe {
| ^^^^^-----^
| | |
| | value moved here
| value used here after move
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait

error[E0382]: use of moved value (Mir)
--> $DIR/issue-41962.rs:17:21
|
Expand All @@ -35,26 +24,6 @@ LL | if let Some(thing) = maybe {
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `maybe` (Mir)
--> $DIR/issue-41962.rs:17:30
|
LL | if let Some(thing) = maybe {
| ----- ^^^^^ value used here after move
| |
| value moved here
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait

error[E0382]: borrow of moved value: `maybe` (Mir)
--> $DIR/issue-41962.rs:17:30
|
LL | if let Some(thing) = maybe {
| ----- ^^^^^ value borrowed here after move
| |
| value moved here
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait

error: aborting due to 6 previous errors
error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0382`.
43 changes: 1 addition & 42 deletions src/test/ui/issues/issue-17385.nll.stderr
Original file line number Diff line number Diff line change
@@ -1,23 +1,3 @@
error[E0382]: use of moved value: `foo`
--> $DIR/issue-17385.rs:28:11
|
LL | drop(foo);
| --- value moved here
LL | match foo { //~ ERROR use of moved value
| ^^^ value used here after move
|
= note: move occurs because `foo` has type `X`, which does not implement the `Copy` trait

error[E0382]: borrow of moved value: `foo`
--> $DIR/issue-17385.rs:28:11
|
LL | drop(foo);
| --- value moved here
LL | match foo { //~ ERROR use of moved value
| ^^^ value borrowed here after move
|
= note: move occurs because `foo` has type `X`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `foo.0`
--> $DIR/issue-17385.rs:29:11
|
Expand All @@ -39,27 +19,6 @@ LL | match e { //~ ERROR use of moved value
|
= note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait

error[E0382]: borrow of moved value: `e`
--> $DIR/issue-17385.rs:35:11
|
LL | drop(e);
| - value moved here
LL | match e { //~ ERROR use of moved value
| ^ value borrowed here after move
|
= note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `e`
--> $DIR/issue-17385.rs:36:9
|
LL | drop(e);
| - value moved here
LL | match e { //~ ERROR use of moved value
LL | Enum::Variant1 => unreachable!(),
| ^^^^^^^^^^^^^^ value used here after move
|
= note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait

error: aborting due to 6 previous errors
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0382`.
10 changes: 1 addition & 9 deletions src/test/ui/liveness/liveness-move-in-while.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@ LL | while true { while true { while true { x = y; x.clone(); } } }
|
= note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `y`
--> $DIR/liveness-move-in-while.rs:18:52
|
LL | 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

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
11 changes: 11 additions & 0 deletions src/test/ui/nll/issue-53807.nll.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
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
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
17 changes: 17 additions & 0 deletions src/test/ui/nll/issue-53807.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub fn main(){
let maybe = Some(vec![true, true]);
loop {
if let Some(thing) = maybe {
}
}
}
21 changes: 21 additions & 0 deletions src/test/ui/nll/issue-53807.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0382]: use of partially moved value: `maybe`
--> $DIR/issue-53807.rs:14:30
|
LL | if let Some(thing) = maybe {
| ----- ^^^^^ value used here after move
| |
| value moved here
|
= note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `(maybe as std::prelude::v1::Some).0`
--> $DIR/issue-53807.rs:14:21
|
LL | if let Some(thing) = maybe {
| ^^^^^ value moved here in previous iteration of loop
|
= note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0382`.
15 changes: 1 addition & 14 deletions src/test/ui/no-capture-arc.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,6 @@ LL | assert_eq!((*arc_v)[2], 3);
|
= note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait

error[E0382]: borrow of moved value: `arc_v`
--> $DIR/no-capture-arc.rs:26:23
|
LL | thread::spawn(move|| {
| ------ value moved into closure here
LL | assert_eq!((*arc_v)[3], 4);
| ----- variable moved due to use in closure
...
LL | println!("{:?}", *arc_v);
| ^^^^^ value borrowed here after move
|
= note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
15 changes: 1 addition & 14 deletions src/test/ui/no-reuse-move-arc.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,6 @@ LL | assert_eq!((*arc_v)[2], 3); //~ ERROR use of moved value: `arc_v`
|
= note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait

error[E0382]: borrow of moved value: `arc_v`
--> $DIR/no-reuse-move-arc.rs:24:23
|
LL | thread::spawn(move|| {
| ------ value moved into closure here
LL | assert_eq!((*arc_v)[3], 4);
| ----- variable moved due to use in closure
...
LL | println!("{:?}", *arc_v); //~ ERROR use of moved value: `arc_v`
| ^^^^^ value borrowed here after move
|
= note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.

0 comments on commit b45648b

Please sign in to comment.