@@ -175,10 +175,13 @@ fn do_mir_borrowck<'a, 'tcx>(
175
175
}
176
176
}
177
177
178
+ let mut errors = error:: BorrowckErrors :: new ( ) ;
179
+
178
180
// Gather the upvars of a closure, if any.
179
181
let tables = tcx. typeck_opt_const_arg ( def) ;
180
182
if let Some ( ErrorReported ) = tables. tainted_by_errors {
181
183
infcx. set_tainted_by_errors ( ) ;
184
+ errors. set_tainted_by_errors ( ) ;
182
185
}
183
186
let upvars: Vec < _ > = tables
184
187
. closure_min_captures_flattened ( def. did . to_def_id ( ) )
@@ -205,7 +208,6 @@ fn do_mir_borrowck<'a, 'tcx>(
205
208
let location_table_owned = LocationTable :: new ( body) ;
206
209
let location_table = & location_table_owned;
207
210
208
- let mut errors_buffer = Vec :: new ( ) ;
209
211
let ( move_data, move_errors) : ( MoveData < ' tcx > , Vec < ( Place < ' tcx > , MoveError < ' tcx > ) > ) =
210
212
match MoveData :: gather_moves ( & body, tcx, param_env) {
211
213
Ok ( move_data) => ( move_data, Vec :: new ( ) ) ,
@@ -263,7 +265,7 @@ fn do_mir_borrowck<'a, 'tcx>(
263
265
& regioncx,
264
266
& opt_closure_req,
265
267
& opaque_type_values,
266
- & mut errors_buffer ,
268
+ & mut errors ,
267
269
) ;
268
270
269
271
// The various `flow_*` structures can be large. We drop `flow_inits` here
@@ -310,10 +312,7 @@ fn do_mir_borrowck<'a, 'tcx>(
310
312
access_place_error_reported : Default :: default ( ) ,
311
313
reservation_error_reported : Default :: default ( ) ,
312
314
reservation_warnings : Default :: default ( ) ,
313
- move_error_reported : BTreeMap :: new ( ) ,
314
315
uninitialized_error_reported : Default :: default ( ) ,
315
- errors_buffer,
316
- tainted_by_errors : false ,
317
316
regioncx : regioncx. clone ( ) ,
318
317
used_mut : Default :: default ( ) ,
319
318
used_mut_upvars : SmallVec :: new ( ) ,
@@ -324,9 +323,10 @@ fn do_mir_borrowck<'a, 'tcx>(
324
323
region_names : RefCell :: default ( ) ,
325
324
next_region_name : RefCell :: new ( 1 ) ,
326
325
polonius_output : None ,
326
+ errors,
327
327
} ;
328
328
promoted_mbcx. report_move_errors ( move_errors) ;
329
- errors_buffer = promoted_mbcx. errors_buffer ;
329
+ errors = promoted_mbcx. errors ;
330
330
} ;
331
331
}
332
332
@@ -344,10 +344,7 @@ fn do_mir_borrowck<'a, 'tcx>(
344
344
access_place_error_reported : Default :: default ( ) ,
345
345
reservation_error_reported : Default :: default ( ) ,
346
346
reservation_warnings : Default :: default ( ) ,
347
- move_error_reported : BTreeMap :: new ( ) ,
348
347
uninitialized_error_reported : Default :: default ( ) ,
349
- errors_buffer,
350
- tainted_by_errors : false ,
351
348
regioncx : Rc :: clone ( & regioncx) ,
352
349
used_mut : Default :: default ( ) ,
353
350
used_mut_upvars : SmallVec :: new ( ) ,
@@ -358,6 +355,7 @@ fn do_mir_borrowck<'a, 'tcx>(
358
355
region_names : RefCell :: default ( ) ,
359
356
next_region_name : RefCell :: new ( 1 ) ,
360
357
polonius_output,
358
+ errors,
361
359
} ;
362
360
363
361
// Compute and report region errors, if any.
@@ -462,24 +460,13 @@ fn do_mir_borrowck<'a, 'tcx>(
462
460
} )
463
461
}
464
462
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 ( ) ;
477
464
478
465
let result = BorrowCheckResult {
479
466
concrete_opaque_types : opaque_type_values,
480
467
closure_requirements : opt_closure_req,
481
468
used_mut_upvars : mbcx. used_mut_upvars ,
482
- tainted_by_errors : mbcx . tainted_by_errors ,
469
+ tainted_by_errors,
483
470
} ;
484
471
485
472
let body_with_facts = if return_body_with_facts {
@@ -556,28 +543,9 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
556
543
/// for the activation of the borrow.
557
544
reservation_warnings :
558
545
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 > ) > ,
574
546
/// This field keeps track of errors reported in the checking of uninitialized variables,
575
547
/// so that we don't report seemingly duplicate errors.
576
548
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 ,
581
549
/// This field keeps track of all the local variables that are declared mut and are mutated.
582
550
/// Used for the warning issued by an unused mutable local variable.
583
551
used_mut : FxHashSet < Local > ,
@@ -609,6 +577,8 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
609
577
610
578
/// Results of Polonius analysis.
611
579
polonius_output : Option < Rc < PoloniusOutput > > ,
580
+
581
+ errors : error:: BorrowckErrors < ' tcx > ,
612
582
}
613
583
614
584
// Check that:
@@ -1032,8 +1002,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1032
1002
1033
1003
if conflict_error || mutability_error {
1034
1004
debug ! ( "access_place: logging error place_span=`{:?}` kind=`{:?}`" , place_span, kind) ;
1035
-
1036
- self . set_tainted_by_errors ( ) ;
1037
1005
self . access_place_error_reported . insert ( ( place_span. 0 , place_span. 1 ) ) ;
1038
1006
}
1039
1007
}
@@ -2055,10 +2023,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2055
2023
| WriteKind :: MutableBorrow ( BorrowKind :: Shared )
2056
2024
| WriteKind :: MutableBorrow ( BorrowKind :: Shallow ) ,
2057
2025
) => {
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
+ {
2062
2029
// rust-lang/rust#46908: In pure NLL mode this code path should be
2063
2030
// unreachable, but we use `delay_span_bug` because we can hit this when
2064
2031
// dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
@@ -2308,14 +2275,102 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2308
2275
fn is_upvar_field_projection ( & self , place_ref : PlaceRef < ' tcx > ) -> Option < Field > {
2309
2276
path_utils:: is_upvar_field_projection ( self . infcx . tcx , & self . upvars , place_ref, self . body ( ) )
2310
2277
}
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
+ }
2311
2319
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
+ }
2315
2323
}
2316
2324
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
+ }
2319
2374
}
2320
2375
}
2321
2376
0 commit comments