From 874e08bdd802f527bc1e1e2c41442796e4d44c6b Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 6 Sep 2018 13:07:14 +0200 Subject: [PATCH 1/3] Log when buffering a diagnostic. This is useful in debugging when and where errors are emitted in logs. --- src/Cargo.lock | 1 + src/librustc_errors/Cargo.toml | 1 + src/librustc_errors/diagnostic_builder.rs | 3 +++ src/librustc_errors/lib.rs | 2 ++ 4 files changed, 7 insertions(+) diff --git a/src/Cargo.lock b/src/Cargo.lock index 412cbbfb2db41..b7d36929f54fb 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2183,6 +2183,7 @@ name = "rustc_errors" version = "0.0.0" dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 101ca0650c8a4..b24f8ddf4d9f7 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -9,6 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] +log = "0.4" serialize = { path = "../libserialize" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 5e962a4af32f6..a4b5b000f8776 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -108,6 +108,9 @@ impl<'a> DiagnosticBuilder<'a> { diagnostic = ::std::ptr::read(&self.diagnostic); ::std::mem::forget(self); }; + // Logging here is useful to help track down where in logs an error was + // actually emitted. + debug!("buffer: diagnostic={:?}", diagnostic); buffered_diagnostics.push(diagnostic); } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d0ea6fba5ebb3..266aa32698168 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -23,6 +23,8 @@ extern crate atty; extern crate termcolor; #[cfg(unix)] extern crate libc; +#[macro_use] +extern crate log; extern crate rustc_data_structures; extern crate serialize as rustc_serialize; extern crate syntax_pos; From 783bad4295f0eca1598572cee9f7171562f8e673 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 6 Sep 2018 15:48:33 +0200 Subject: [PATCH 2/3] De-duplicate moved variable errors. 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. --- .../borrow_check/error_reporting.rs | 26 +++++++++-- src/librustc_mir/borrow_check/mod.rs | 28 +++++++++--- .../borrowck-multiple-captures.nll.stderr | 16 +++---- src/test/ui/borrowck/issue-41962.rs | 3 -- src/test/ui/borrowck/issue-41962.stderr | 33 +------------- src/test/ui/issues/issue-17385.nll.stderr | 43 +------------------ .../liveness-move-in-while.nll.stderr | 10 +---- src/test/ui/nll/issue-53807.nll.stderr | 11 +++++ src/test/ui/nll/issue-53807.rs | 17 ++++++++ src/test/ui/nll/issue-53807.stderr | 21 +++++++++ src/test/ui/no-capture-arc.nll.stderr | 15 +------ src/test/ui/no-reuse-move-arc.nll.stderr | 15 +------ 12 files changed, 108 insertions(+), 130 deletions(-) create mode 100644 src/test/ui/nll/issue-53807.nll.stderr create mode 100644 src/test/ui/nll/issue-53807.rs create mode 100644 src/test/ui/nll/issue-53807.stderr diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 4671332f2824c..fda6b34971625 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -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)); @@ -49,7 +55,7 @@ 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 @@ -57,7 +63,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { 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), @@ -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( @@ -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(); + } } } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 521e7ade00ea9..668f05da89ee9 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -27,7 +27,7 @@ use rustc::ty::{self, ParamEnv, TyCtxt, Ty}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::indexed_vec::Idx; use smallvec::SmallVec; @@ -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; @@ -255,7 +256,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( locals_are_invalidated_at_exit, 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(), @@ -333,6 +335,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()); @@ -408,9 +415,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>, - /// 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, (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>, + uninitialized_error_reported: FxHashSet>, /// Errors to be reported buffer errors_buffer: Vec, /// This field keeps track of all the local variables that are declared mut and are mutated. @@ -801,7 +819,7 @@ enum LocalMutationIsAllowed { No, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] enum InitializationRequiringAction { Update, Borrow, diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr index ce1880c584a6e..79cfbc5a36022 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr +++ b/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr @@ -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`, which does not implement the `Copy` trait + = note: move occurs because `x2` has type `std::boxed::Box`, 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`, which does not implement the `Copy` trait + = note: move occurs because `x1` has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x` --> $DIR/borrowck-multiple-captures.rs:46:14 diff --git a/src/test/ui/borrowck/issue-41962.rs b/src/test/ui/borrowck/issue-41962.rs index 2a94e05016d4e..9431ef5f13dc8 100644 --- a/src/test/ui/borrowck/issue-41962.rs +++ b/src/test/ui/borrowck/issue-41962.rs @@ -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] } } diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr index b6e005a6673eb..957ccfe45dd01 100644 --- a/src/test/ui/borrowck/issue-41962.stderr +++ b/src/test/ui/borrowck/issue-41962.stderr @@ -16,17 +16,6 @@ LL | if let Some(thing) = maybe { | = note: move occurs because the value has type `std::vec::Vec`, 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`, which does not implement the `Copy` trait - error[E0382]: use of moved value (Mir) --> $DIR/issue-41962.rs:17:21 | @@ -35,26 +24,6 @@ LL | if let Some(thing) = maybe { | = note: move occurs because value has type `std::vec::Vec`, 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`, 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`, 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`. diff --git a/src/test/ui/issues/issue-17385.nll.stderr b/src/test/ui/issues/issue-17385.nll.stderr index 85924a7526168..c7b0b57000f5e 100644 --- a/src/test/ui/issues/issue-17385.nll.stderr +++ b/src/test/ui/issues/issue-17385.nll.stderr @@ -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 | @@ -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`. diff --git a/src/test/ui/liveness/liveness-move-in-while.nll.stderr b/src/test/ui/liveness/liveness-move-in-while.nll.stderr index 5ca5dc647090d..9f1ffd91518b3 100644 --- a/src/test/ui/liveness/liveness-move-in-while.nll.stderr +++ b/src/test/ui/liveness/liveness-move-in-while.nll.stderr @@ -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`, 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`, 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`. diff --git a/src/test/ui/nll/issue-53807.nll.stderr b/src/test/ui/nll/issue-53807.nll.stderr new file mode 100644 index 0000000000000..0c019a4ec3cdc --- /dev/null +++ b/src/test/ui/nll/issue-53807.nll.stderr @@ -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`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/nll/issue-53807.rs b/src/test/ui/nll/issue-53807.rs new file mode 100644 index 0000000000000..791dee2fb3183 --- /dev/null +++ b/src/test/ui/nll/issue-53807.rs @@ -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 or the MIT license +// , 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 { + } + } +} diff --git a/src/test/ui/nll/issue-53807.stderr b/src/test/ui/nll/issue-53807.stderr new file mode 100644 index 0000000000000..7056899d0a48a --- /dev/null +++ b/src/test/ui/nll/issue-53807.stderr @@ -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`, 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`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/no-capture-arc.nll.stderr b/src/test/ui/no-capture-arc.nll.stderr index a58d5ad6fa723..31dba18338ab7 100644 --- a/src/test/ui/no-capture-arc.nll.stderr +++ b/src/test/ui/no-capture-arc.nll.stderr @@ -11,19 +11,6 @@ LL | assert_eq!((*arc_v)[2], 3); | = note: move occurs because `arc_v` has type `std::sync::Arc>`, 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>`, 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`. diff --git a/src/test/ui/no-reuse-move-arc.nll.stderr b/src/test/ui/no-reuse-move-arc.nll.stderr index 902affc80462c..bffcae6e2f50a 100644 --- a/src/test/ui/no-reuse-move-arc.nll.stderr +++ b/src/test/ui/no-reuse-move-arc.nll.stderr @@ -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>`, 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>`, 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`. From 88ca3412e238d2d6b738ff5e81fa123e33fcc9ae Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 11 Sep 2018 16:01:53 +0200 Subject: [PATCH 3/3] Switched from FxHashMap to BTreeMap to preserve ordering when iterating. --- src/librustc_mir/borrow_check/mod.rs | 13 +++++++++---- .../borrowck-multiple-captures.nll.stderr | 16 ++++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 668f05da89ee9..c7e53714e3e84 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -27,12 +27,13 @@ use rustc::ty::{self, ParamEnv, TyCtxt, Ty}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::indexed_vec::Idx; use smallvec::SmallVec; use std::rc::Rc; +use std::collections::BTreeMap; use syntax_pos::Span; @@ -256,7 +257,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( locals_are_invalidated_at_exit, access_place_error_reported: FxHashSet(), reservation_error_reported: FxHashSet(), - move_error_reported: FxHashMap(), + move_error_reported: BTreeMap::new(), uninitialized_error_reported: FxHashSet(), errors_buffer, nonlexical_regioncx: regioncx, @@ -336,7 +337,7 @@ 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() { + for (_, (_, diag)) in mbcx.move_error_reported { diag.buffer(&mut mbcx.errors_buffer); } @@ -425,7 +426,11 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// `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, (Place<'tcx>, DiagnosticBuilder<'cx>)>, + /// + /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary + /// when errors in the map are being re-added to the error buffer so that errors with the + /// same primary span come out in a consistent order. + move_error_reported: BTreeMap, (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. uninitialized_error_reported: FxHashSet>, diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr index 79cfbc5a36022..ce1880c584a6e 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr +++ b/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr @@ -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: `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`, which does not implement the `Copy` trait + = note: move occurs because `x1` has type `std::boxed::Box`, which does not implement the `Copy` trait -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`, which does not implement the `Copy` trait + = note: move occurs because `x2` has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x` --> $DIR/borrowck-multiple-captures.rs:46:14