@@ -175,10 +175,13 @@ fn do_mir_borrowck<'a, 'tcx>(
175175 }
176176 }
177177
178+ let mut errors = error:: BorrowckErrors :: new ( ) ;
179+
178180 // Gather the upvars of a closure, if any.
179181 let tables = tcx. typeck_opt_const_arg ( def) ;
180182 if let Some ( ErrorReported ) = tables. tainted_by_errors {
181183 infcx. set_tainted_by_errors ( ) ;
184+ errors. set_tainted_by_errors ( ) ;
182185 }
183186 let upvars: Vec < _ > = tables
184187 . closure_min_captures_flattened ( def. did . to_def_id ( ) )
@@ -205,7 +208,6 @@ fn do_mir_borrowck<'a, 'tcx>(
205208 let location_table_owned = LocationTable :: new ( body) ;
206209 let location_table = & location_table_owned;
207210
208- let mut errors_buffer = Vec :: new ( ) ;
209211 let ( move_data, move_errors) : ( MoveData < ' tcx > , Vec < ( Place < ' tcx > , MoveError < ' tcx > ) > ) =
210212 match MoveData :: gather_moves ( & body, tcx, param_env) {
211213 Ok ( move_data) => ( move_data, Vec :: new ( ) ) ,
@@ -263,7 +265,7 @@ fn do_mir_borrowck<'a, 'tcx>(
263265 & regioncx,
264266 & opt_closure_req,
265267 & opaque_type_values,
266- & mut errors_buffer ,
268+ & mut errors ,
267269 ) ;
268270
269271 // The various `flow_*` structures can be large. We drop `flow_inits` here
@@ -310,10 +312,7 @@ fn do_mir_borrowck<'a, 'tcx>(
310312 access_place_error_reported : Default :: default ( ) ,
311313 reservation_error_reported : Default :: default ( ) ,
312314 reservation_warnings : Default :: default ( ) ,
313- move_error_reported : BTreeMap :: new ( ) ,
314315 uninitialized_error_reported : Default :: default ( ) ,
315- errors_buffer,
316- tainted_by_errors : false ,
317316 regioncx : regioncx. clone ( ) ,
318317 used_mut : Default :: default ( ) ,
319318 used_mut_upvars : SmallVec :: new ( ) ,
@@ -324,9 +323,10 @@ fn do_mir_borrowck<'a, 'tcx>(
324323 region_names : RefCell :: default ( ) ,
325324 next_region_name : RefCell :: new ( 1 ) ,
326325 polonius_output : None ,
326+ errors,
327327 } ;
328328 promoted_mbcx. report_move_errors ( move_errors) ;
329- errors_buffer = promoted_mbcx. errors_buffer ;
329+ errors = promoted_mbcx. errors ;
330330 } ;
331331 }
332332
@@ -344,10 +344,7 @@ fn do_mir_borrowck<'a, 'tcx>(
344344 access_place_error_reported : Default :: default ( ) ,
345345 reservation_error_reported : Default :: default ( ) ,
346346 reservation_warnings : Default :: default ( ) ,
347- move_error_reported : BTreeMap :: new ( ) ,
348347 uninitialized_error_reported : Default :: default ( ) ,
349- errors_buffer,
350- tainted_by_errors : false ,
351348 regioncx : Rc :: clone ( & regioncx) ,
352349 used_mut : Default :: default ( ) ,
353350 used_mut_upvars : SmallVec :: new ( ) ,
@@ -358,6 +355,7 @@ fn do_mir_borrowck<'a, 'tcx>(
358355 region_names : RefCell :: default ( ) ,
359356 next_region_name : RefCell :: new ( 1 ) ,
360357 polonius_output,
358+ errors,
361359 } ;
362360
363361 // Compute and report region errors, if any.
@@ -462,24 +460,13 @@ fn do_mir_borrowck<'a, 'tcx>(
462460 } )
463461 }
464462
465- // Buffer any move errors that we collected and de-duplicated.
466- for ( _, ( _, diag) ) in std:: mem:: take ( & mut mbcx. move_error_reported ) {
467- mbcx. buffer_error ( diag) ;
468- }
469-
470- if !mbcx. errors_buffer . is_empty ( ) {
471- mbcx. errors_buffer . sort_by_key ( |diag| diag. sort_span ) ;
472-
473- for diag in mbcx. errors_buffer . drain ( ..) {
474- mbcx. infcx . tcx . sess . diagnostic ( ) . emit_diagnostic ( & diag) ;
475- }
476- }
463+ let tainted_by_errors = mbcx. emit_errors ( ) ;
477464
478465 let result = BorrowCheckResult {
479466 concrete_opaque_types : opaque_type_values,
480467 closure_requirements : opt_closure_req,
481468 used_mut_upvars : mbcx. used_mut_upvars ,
482- tainted_by_errors : mbcx . tainted_by_errors ,
469+ tainted_by_errors,
483470 } ;
484471
485472 let body_with_facts = if return_body_with_facts {
@@ -556,28 +543,9 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
556543 /// for the activation of the borrow.
557544 reservation_warnings :
558545 FxHashMap < BorrowIndex , ( Place < ' tcx > , Span , Location , BorrowKind , BorrowData < ' tcx > ) > ,
559- /// This field keeps track of move errors that are to be reported for given move indices.
560- ///
561- /// There are situations where many errors can be reported for a single move out (see #53807)
562- /// and we want only the best of those errors.
563- ///
564- /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
565- /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
566- /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
567- /// all move errors have been reported, any diagnostics in this map are added to the buffer
568- /// to be emitted.
569- ///
570- /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
571- /// when errors in the map are being re-added to the error buffer so that errors with the
572- /// same primary span come out in a consistent order.
573- move_error_reported : BTreeMap < Vec < MoveOutIndex > , ( PlaceRef < ' tcx > , DiagnosticBuilder < ' cx > ) > ,
574546 /// This field keeps track of errors reported in the checking of uninitialized variables,
575547 /// so that we don't report seemingly duplicate errors.
576548 uninitialized_error_reported : FxHashSet < PlaceRef < ' tcx > > ,
577- /// Errors to be reported buffer
578- errors_buffer : Vec < Diagnostic > ,
579- /// Set to true if we emit an error during borrowck
580- tainted_by_errors : bool ,
581549 /// This field keeps track of all the local variables that are declared mut and are mutated.
582550 /// Used for the warning issued by an unused mutable local variable.
583551 used_mut : FxHashSet < Local > ,
@@ -609,6 +577,8 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
609577
610578 /// Results of Polonius analysis.
611579 polonius_output : Option < Rc < PoloniusOutput > > ,
580+
581+ errors : error:: BorrowckErrors < ' tcx > ,
612582}
613583
614584// Check that:
@@ -1032,8 +1002,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10321002
10331003 if conflict_error || mutability_error {
10341004 debug ! ( "access_place: logging error place_span=`{:?}` kind=`{:?}`" , place_span, kind) ;
1035-
1036- self . set_tainted_by_errors ( ) ;
10371005 self . access_place_error_reported . insert ( ( place_span. 0 , place_span. 1 ) ) ;
10381006 }
10391007 }
@@ -2055,10 +2023,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
20552023 | WriteKind :: MutableBorrow ( BorrowKind :: Shared )
20562024 | WriteKind :: MutableBorrow ( BorrowKind :: Shallow ) ,
20572025 ) => {
2058- if let ( Err ( _) , true ) = (
2059- self . is_mutable ( place. as_ref ( ) , is_local_mutation_allowed) ,
2060- self . errors_buffer . is_empty ( ) ,
2061- ) {
2026+ if self . is_mutable ( place. as_ref ( ) , is_local_mutation_allowed) . is_err ( )
2027+ && !self . has_buffered_errors ( )
2028+ {
20622029 // rust-lang/rust#46908: In pure NLL mode this code path should be
20632030 // unreachable, but we use `delay_span_bug` because we can hit this when
20642031 // dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
@@ -2308,14 +2275,102 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
23082275 fn is_upvar_field_projection ( & self , place_ref : PlaceRef < ' tcx > ) -> Option < Field > {
23092276 path_utils:: is_upvar_field_projection ( self . infcx . tcx , & self . upvars , place_ref, self . body ( ) )
23102277 }
2278+ }
2279+
2280+ mod error {
2281+ use super :: * ;
2282+
2283+ pub struct BorrowckErrors < ' tcx > {
2284+ /// This field keeps track of move errors that are to be reported for given move indices.
2285+ ///
2286+ /// There are situations where many errors can be reported for a single move out (see #53807)
2287+ /// and we want only the best of those errors.
2288+ ///
2289+ /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
2290+ /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
2291+ /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
2292+ /// all move errors have been reported, any diagnostics in this map are added to the buffer
2293+ /// to be emitted.
2294+ ///
2295+ /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
2296+ /// when errors in the map are being re-added to the error buffer so that errors with the
2297+ /// same primary span come out in a consistent order.
2298+ buffered_move_errors :
2299+ BTreeMap < Vec < MoveOutIndex > , ( PlaceRef < ' tcx > , DiagnosticBuilder < ' tcx > ) > ,
2300+ /// Errors to be reported buffer
2301+ buffered : Vec < Diagnostic > ,
2302+ /// Set to Some if we emit an error during borrowck
2303+ tainted_by_errors : Option < ErrorReported > ,
2304+ }
2305+
2306+ impl BorrowckErrors < ' _ > {
2307+ pub fn new ( ) -> Self {
2308+ BorrowckErrors {
2309+ buffered_move_errors : BTreeMap :: new ( ) ,
2310+ buffered : Default :: default ( ) ,
2311+ tainted_by_errors : None ,
2312+ }
2313+ }
2314+
2315+ pub fn buffer_error ( & mut self , t : DiagnosticBuilder < ' _ > ) {
2316+ self . tainted_by_errors = Some ( ErrorReported { } ) ;
2317+ t. buffer ( & mut self . buffered ) ;
2318+ }
23112319
2312- pub fn buffer_error ( & mut self , t : DiagnosticBuilder < ' _ > ) {
2313- self . tainted_by_errors = true ;
2314- t . buffer ( & mut self . errors_buffer ) ;
2320+ pub fn set_tainted_by_errors ( & mut self ) {
2321+ self . tainted_by_errors = Some ( ErrorReported { } ) ;
2322+ }
23152323 }
23162324
2317- pub fn set_tainted_by_errors ( & mut self ) {
2318- self . tainted_by_errors = true ;
2325+ impl < ' cx , ' tcx > MirBorrowckCtxt < ' cx , ' tcx > {
2326+ pub fn buffer_error ( & mut self , t : DiagnosticBuilder < ' _ > ) {
2327+ self . errors . buffer_error ( t) ;
2328+ }
2329+
2330+ pub fn buffer_move_error (
2331+ & mut self ,
2332+ move_out_indices : Vec < MoveOutIndex > ,
2333+ place_and_err : ( PlaceRef < ' tcx > , DiagnosticBuilder < ' tcx > ) ,
2334+ ) -> bool {
2335+ if let Some ( ( _, mut diag) ) =
2336+ self . errors . buffered_move_errors . insert ( move_out_indices, place_and_err)
2337+ {
2338+ // Cancel the old diagnostic so we don't ICE
2339+ diag. cancel ( ) ;
2340+ false
2341+ } else {
2342+ true
2343+ }
2344+ }
2345+
2346+ pub fn emit_errors ( & mut self ) -> Option < ErrorReported > {
2347+ // Buffer any move errors that we collected and de-duplicated.
2348+ for ( _, ( _, diag) ) in std:: mem:: take ( & mut self . errors . buffered_move_errors ) {
2349+ // We have already set tainted for this error, so just buffer it.
2350+ diag. buffer ( & mut self . errors . buffered ) ;
2351+ }
2352+
2353+ if !self . errors . buffered . is_empty ( ) {
2354+ self . errors . buffered . sort_by_key ( |diag| diag. sort_span ) ;
2355+
2356+ for diag in self . errors . buffered . drain ( ..) {
2357+ self . infcx . tcx . sess . diagnostic ( ) . emit_diagnostic ( & diag) ;
2358+ }
2359+ }
2360+
2361+ self . errors . tainted_by_errors
2362+ }
2363+
2364+ pub fn has_buffered_errors ( & self ) -> bool {
2365+ self . errors . buffered . is_empty ( )
2366+ }
2367+
2368+ pub fn has_move_error (
2369+ & self ,
2370+ move_out_indices : & [ MoveOutIndex ] ,
2371+ ) -> Option < & ( PlaceRef < ' tcx > , DiagnosticBuilder < ' cx > ) > {
2372+ self . errors . buffered_move_errors . get ( move_out_indices)
2373+ }
23192374 }
23202375}
23212376
0 commit comments