@@ -33,11 +33,13 @@ use rustc_data_structures::indexed_vec::Idx;
3333use smallvec:: SmallVec ;
3434
3535use std:: rc:: Rc ;
36+ use std:: collections:: BTreeMap ;
3637
3738use syntax_pos:: Span ;
3839
3940use dataflow:: indexes:: BorrowIndex ;
4041use dataflow:: move_paths:: { HasMoveData , LookupResult , MoveData , MoveError , MovePathIndex } ;
42+ use dataflow:: move_paths:: indexes:: MoveOutIndex ;
4143use dataflow:: Borrows ;
4244use dataflow:: DataflowResultsConsumer ;
4345use dataflow:: FlowAtLocation ;
@@ -255,7 +257,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
255257 locals_are_invalidated_at_exit,
256258 access_place_error_reported : FxHashSet ( ) ,
257259 reservation_error_reported : FxHashSet ( ) ,
258- moved_error_reported : FxHashSet ( ) ,
260+ move_error_reported : BTreeMap :: new ( ) ,
261+ uninitialized_error_reported : FxHashSet ( ) ,
259262 errors_buffer,
260263 nonlexical_regioncx : regioncx,
261264 used_mut : FxHashSet ( ) ,
@@ -333,6 +336,11 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
333336 }
334337 }
335338
339+ // Buffer any move errors that we collected and de-duplicated.
340+ for ( _, ( _, diag) ) in mbcx. move_error_reported {
341+ diag. buffer ( & mut mbcx. errors_buffer ) ;
342+ }
343+
336344 if mbcx. errors_buffer . len ( ) > 0 {
337345 mbcx. errors_buffer . sort_by_key ( |diag| diag. span . primary_span ( ) ) ;
338346
@@ -408,9 +416,24 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
408416 /// but it is currently inconvenient to track down the BorrowIndex
409417 /// at the time we detect and report a reservation error.
410418 reservation_error_reported : FxHashSet < Place < ' tcx > > ,
411- /// This field keeps track of errors reported in the checking of moved variables,
419+ /// This field keeps track of move errors that are to be reported for given move indicies.
420+ ///
421+ /// There are situations where many errors can be reported for a single move out (see #53807)
422+ /// and we want only the best of those errors.
423+ ///
424+ /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
425+ /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
426+ /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
427+ /// all move errors have been reported, any diagnostics in this map are added to the buffer
428+ /// to be emitted.
429+ ///
430+ /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
431+ /// when errors in the map are being re-added to the error buffer so that errors with the
432+ /// same primary span come out in a consistent order.
433+ move_error_reported : BTreeMap < Vec < MoveOutIndex > , ( Place < ' tcx > , DiagnosticBuilder < ' cx > ) > ,
434+ /// This field keeps track of errors reported in the checking of uninitialized variables,
412435 /// so that we don't report seemingly duplicate errors.
413- moved_error_reported : FxHashSet < Place < ' tcx > > ,
436+ uninitialized_error_reported : FxHashSet < Place < ' tcx > > ,
414437 /// Errors to be reported buffer
415438 errors_buffer : Vec < Diagnostic > ,
416439 /// This field keeps track of all the local variables that are declared mut and are mutated.
@@ -801,7 +824,7 @@ enum LocalMutationIsAllowed {
801824 No ,
802825}
803826
804- #[ derive( Copy , Clone ) ]
827+ #[ derive( Copy , Clone , Debug ) ]
805828enum InitializationRequiringAction {
806829 Update ,
807830 Borrow ,
0 commit comments