@@ -22,6 +22,8 @@ use std::cell::RefCell;
22
22
use std:: marker:: PhantomData ;
23
23
use std:: ops:: { ControlFlow , Deref } ;
24
24
25
+ use borrow_set:: LocalsStateAtExit ;
26
+ use diagnostics:: RegionErrors ;
25
27
use root_cx:: BorrowCheckRootCtxt ;
26
28
use rustc_abi:: FieldIdx ;
27
29
use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
@@ -304,33 +306,13 @@ fn do_mir_borrowck<'tcx>(
304
306
root_cx. set_tainted_by_errors ( e) ;
305
307
}
306
308
307
- let mut local_names = IndexVec :: from_elem ( None , & input_body. local_decls ) ;
308
- for var_debug_info in & input_body. var_debug_info {
309
- if let VarDebugInfoContents :: Place ( place) = var_debug_info. value {
310
- if let Some ( local) = place. as_local ( ) {
311
- if let Some ( prev_name) = local_names[ local]
312
- && var_debug_info. name != prev_name
313
- {
314
- span_bug ! (
315
- var_debug_info. source_info. span,
316
- "local {:?} has many names (`{}` vs `{}`)" ,
317
- local,
318
- prev_name,
319
- var_debug_info. name
320
- ) ;
321
- }
322
- local_names[ local] = Some ( var_debug_info. name ) ;
323
- }
324
- }
325
- }
326
-
327
309
// Replace all regions with fresh inference variables. This
328
310
// requires first making our own copy of the MIR. This copy will
329
311
// be modified (in place) to contain non-lexical lifetimes. It
330
312
// will have a lifetime tied to the inference context.
331
313
let mut body_owned = input_body. clone ( ) ;
332
314
let mut promoted = input_promoted. to_owned ( ) ;
333
- let free_regions = nll:: replace_regions_in_mir ( & infcx, & mut body_owned, & mut promoted) ;
315
+ let universal_regions = nll:: replace_regions_in_mir ( & infcx, & mut body_owned, & mut promoted) ;
334
316
let body = & body_owned; // no further changes
335
317
336
318
let location_table = PoloniusLocationTable :: new ( body) ;
@@ -355,7 +337,7 @@ fn do_mir_borrowck<'tcx>(
355
337
} = nll:: compute_regions (
356
338
root_cx,
357
339
& infcx,
358
- free_regions ,
340
+ universal_regions ,
359
341
body,
360
342
& promoted,
361
343
& location_table,
@@ -368,27 +350,76 @@ fn do_mir_borrowck<'tcx>(
368
350
// Dump MIR results into a file, if that is enabled. This lets us
369
351
// write unit-tests, as well as helping with debugging.
370
352
nll:: dump_nll_mir ( & infcx, body, & regioncx, & opt_closure_req, & borrow_set) ;
353
+ polonius:: dump_polonius_mir (
354
+ & infcx,
355
+ body,
356
+ & regioncx,
357
+ & opt_closure_req,
358
+ & borrow_set,
359
+ polonius_diagnostics. as_ref ( ) ,
360
+ ) ;
371
361
372
362
// We also have a `#[rustc_regions]` annotation that causes us to dump
373
363
// information.
374
- let diags_buffer = & mut BorrowckDiagnosticsBuffer :: default ( ) ;
375
- nll:: dump_annotation ( & infcx, body, & regioncx, & opt_closure_req, diags_buffer) ;
376
-
377
- let movable_coroutine =
378
- // The first argument is the coroutine type passed by value
379
- if let Some ( local) = body. local_decls . raw . get ( 1 )
380
- // Get the interior types and args which typeck computed
381
- && let ty:: Coroutine ( def_id, _) = * local. ty . kind ( )
382
- && tcx. coroutine_movability ( def_id) == hir:: Movability :: Movable
383
- {
384
- true
385
- } else {
386
- false
387
- } ;
364
+ nll:: dump_annotation ( & infcx, body, & regioncx, & opt_closure_req) ;
365
+
366
+ let used_mut_upvars = borrowck_body (
367
+ root_cx,
368
+ & infcx,
369
+ & body,
370
+ & promoted,
371
+ & location_table,
372
+ & move_data,
373
+ & borrow_set,
374
+ & regioncx,
375
+ polonius_output. as_deref ( ) ,
376
+ polonius_diagnostics. as_ref ( ) ,
377
+ nll_errors,
378
+ ) ;
379
+
380
+ let result =
381
+ PropagatedBorrowCheckResults { closure_requirements : opt_closure_req, used_mut_upvars } ;
382
+
383
+ let body_with_facts = if consumer_options. is_some ( ) {
384
+ Some ( Box :: new ( BodyWithBorrowckFacts {
385
+ body : body_owned,
386
+ promoted,
387
+ borrow_set,
388
+ region_inference_context : regioncx,
389
+ location_table : polonius_input. as_ref ( ) . map ( |_| location_table) ,
390
+ input_facts : polonius_input,
391
+ output_facts : polonius_output,
392
+ } ) )
393
+ } else {
394
+ None
395
+ } ;
396
+
397
+ debug ! ( "do_mir_borrowck: result = {:#?}" , result) ;
398
+
399
+ ( result, body_with_facts)
400
+ }
401
+
402
+ fn borrowck_body < ' tcx > (
403
+ root_cx : & mut BorrowCheckRootCtxt < ' tcx > ,
404
+ infcx : & BorrowckInferCtxt < ' tcx > ,
405
+ body : & Body < ' tcx > ,
406
+ promoted : & IndexVec < Promoted , Body < ' tcx > > ,
407
+ location_table : & PoloniusLocationTable ,
408
+ move_data : & MoveData < ' tcx > ,
409
+ borrow_set : & BorrowSet < ' tcx > ,
410
+ regioncx : & RegionInferenceContext < ' tcx > ,
411
+ polonius_output : Option < & PoloniusOutput > ,
412
+ polonius_diagnostics : Option < & PoloniusDiagnosticsContext > ,
413
+ nll_errors : RegionErrors < ' tcx > ,
414
+ ) -> SmallVec < [ FieldIdx ; 8 ] > {
415
+ let tcx = infcx. tcx ;
416
+ let movable_coroutine = body. coroutine . is_some ( )
417
+ && tcx. coroutine_movability ( body. source . def_id ( ) ) == hir:: Movability :: Movable ;
388
418
419
+ let diags_buffer = & mut BorrowckDiagnosticsBuffer :: default ( ) ;
389
420
// While promoteds should mostly be correct by construction, we need to check them for
390
421
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
391
- for promoted_body in & promoted {
422
+ for promoted_body in promoted {
392
423
use rustc_middle:: mir:: visit:: Visitor ;
393
424
// This assumes that we won't use some of the fields of the `promoted_mbcx`
394
425
// when detecting and reporting move errors. While it would be nice to move
@@ -403,7 +434,6 @@ fn do_mir_borrowck<'tcx>(
403
434
location_table : & location_table,
404
435
movable_coroutine,
405
436
fn_self_span_reported : Default :: default ( ) ,
406
- locals_are_invalidated_at_exit,
407
437
access_place_error_reported : Default :: default ( ) ,
408
438
reservation_error_reported : Default :: default ( ) ,
409
439
uninitialized_error_reported : Default :: default ( ) ,
@@ -415,10 +445,11 @@ fn do_mir_borrowck<'tcx>(
415
445
local_names : IndexVec :: from_elem ( None , & promoted_body. local_decls ) ,
416
446
region_names : RefCell :: default ( ) ,
417
447
next_region_name : RefCell :: new ( 1 ) ,
418
- polonius_output : None ,
419
448
move_errors : Vec :: new ( ) ,
420
449
diags_buffer,
421
- polonius_diagnostics : polonius_diagnostics. as_ref ( ) ,
450
+
451
+ polonius_output,
452
+ polonius_diagnostics,
422
453
} ;
423
454
struct MoveVisitor < ' a , ' b , ' infcx , ' tcx > {
424
455
ctxt : & ' a mut MirBorrowckCtxt < ' b , ' infcx , ' tcx > ,
@@ -435,30 +466,49 @@ fn do_mir_borrowck<'tcx>(
435
466
promoted_mbcx. report_move_errors ( ) ;
436
467
}
437
468
469
+ let mut local_names = IndexVec :: from_elem ( None , & body. local_decls ) ;
470
+ for var_debug_info in & body. var_debug_info {
471
+ if let VarDebugInfoContents :: Place ( place) = var_debug_info. value {
472
+ if let Some ( local) = place. as_local ( ) {
473
+ if let Some ( prev_name) = local_names[ local]
474
+ && var_debug_info. name != prev_name
475
+ {
476
+ span_bug ! (
477
+ var_debug_info. source_info. span,
478
+ "local {:?} has many names (`{}` vs `{}`)" ,
479
+ local,
480
+ prev_name,
481
+ var_debug_info. name
482
+ ) ;
483
+ }
484
+ local_names[ local] = Some ( var_debug_info. name ) ;
485
+ }
486
+ }
487
+ }
488
+
438
489
let mut mbcx = MirBorrowckCtxt {
439
490
root_cx,
440
491
infcx : & infcx,
441
492
body,
442
493
move_data : & move_data,
443
494
location_table : & location_table,
444
495
movable_coroutine,
445
- locals_are_invalidated_at_exit,
446
496
fn_self_span_reported : Default :: default ( ) ,
447
497
access_place_error_reported : Default :: default ( ) ,
448
498
reservation_error_reported : Default :: default ( ) ,
449
499
uninitialized_error_reported : Default :: default ( ) ,
450
- regioncx : & regioncx ,
500
+ regioncx,
451
501
used_mut : Default :: default ( ) ,
452
502
used_mut_upvars : SmallVec :: new ( ) ,
453
503
borrow_set : & borrow_set,
454
- upvars : tcx. closure_captures ( def ) ,
504
+ upvars : tcx. closure_captures ( body . source . def_id ( ) . expect_local ( ) ) ,
455
505
local_names,
456
506
region_names : RefCell :: default ( ) ,
457
507
next_region_name : RefCell :: new ( 1 ) ,
458
- polonius_output,
459
508
move_errors : Vec :: new ( ) ,
460
509
diags_buffer,
461
- polonius_diagnostics : polonius_diagnostics. as_ref ( ) ,
510
+ polonius_output,
511
+ polonius_diagnostics,
462
512
} ;
463
513
464
514
// Compute and report region errors, if any.
@@ -474,16 +524,6 @@ fn do_mir_borrowck<'tcx>(
474
524
475
525
mbcx. report_move_errors ( ) ;
476
526
477
- // If requested, dump polonius MIR.
478
- polonius:: dump_polonius_mir (
479
- & infcx,
480
- body,
481
- & regioncx,
482
- & borrow_set,
483
- polonius_diagnostics. as_ref ( ) ,
484
- & opt_closure_req,
485
- ) ;
486
-
487
527
// For each non-user used mutable variable, check if it's been assigned from
488
528
// a user-declared local. If so, then put that local into the used_mut set.
489
529
// Note that this set is expected to be small - only upvars from closures
@@ -508,29 +548,7 @@ fn do_mir_borrowck<'tcx>(
508
548
mbcx. root_cx . set_tainted_by_errors ( guar) ;
509
549
}
510
550
511
- let result = PropagatedBorrowCheckResults {
512
- closure_requirements : opt_closure_req,
513
- used_mut_upvars : mbcx. used_mut_upvars ,
514
- } ;
515
-
516
- let body_with_facts = if consumer_options. is_some ( ) {
517
- let output_facts = mbcx. polonius_output ;
518
- Some ( Box :: new ( BodyWithBorrowckFacts {
519
- body : body_owned,
520
- promoted,
521
- borrow_set,
522
- region_inference_context : regioncx,
523
- location_table : polonius_input. as_ref ( ) . map ( |_| location_table) ,
524
- input_facts : polonius_input,
525
- output_facts,
526
- } ) )
527
- } else {
528
- None
529
- } ;
530
-
531
- debug ! ( "do_mir_borrowck: result = {:#?}" , result) ;
532
-
533
- ( result, body_with_facts)
551
+ mbcx. used_mut_upvars
534
552
}
535
553
536
554
fn get_flow_results < ' a , ' tcx > (
@@ -655,13 +673,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
655
673
location_table : & ' a PoloniusLocationTable ,
656
674
657
675
movable_coroutine : bool ,
658
- /// This keeps track of whether local variables are free-ed when the function
659
- /// exits even without a `StorageDead`, which appears to be the case for
660
- /// constants.
661
- ///
662
- /// I'm not sure this is the right approach - @eddyb could you try and
663
- /// figure this out?
664
- locals_are_invalidated_at_exit : bool ,
665
676
/// This field keeps track of when borrow errors are reported in the access_place function
666
677
/// so that there is no duplicate reporting. This field cannot also be used for the conflicting
667
678
/// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
@@ -709,12 +720,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
709
720
/// The counter for generating new region names.
710
721
next_region_name : RefCell < usize > ,
711
722
712
- /// Results of Polonius analysis.
713
- polonius_output : Option < Box < PoloniusOutput > > ,
714
-
715
723
diags_buffer : & ' a mut BorrowckDiagnosticsBuffer < ' infcx , ' tcx > ,
716
724
move_errors : Vec < MoveError < ' tcx > > ,
717
725
726
+ /// Results of Polonius analysis.
727
+ polonius_output : Option < & ' a PoloniusOutput > ,
718
728
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
719
729
polonius_diagnostics : Option < & ' a PoloniusDiagnosticsContext > ,
720
730
}
@@ -938,13 +948,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
938
948
| TerminatorKind :: Return
939
949
| TerminatorKind :: TailCall { .. }
940
950
| TerminatorKind :: CoroutineDrop => {
941
- // Returning from the function implicitly kills storage for all locals and statics.
942
- // Often, the storage will already have been killed by an explicit
943
- // StorageDead, but we don't always emit those (notably on unwind paths),
944
- // so this "extra check" serves as a kind of backup.
945
- for i in state. borrows . iter ( ) {
946
- let borrow = & self . borrow_set [ i] ;
947
- self . check_for_invalidation_at_exit ( loc, borrow, span) ;
951
+ match self . borrow_set . locals_state_at_exit ( ) {
952
+ LocalsStateAtExit :: AllAreInvalidated => {
953
+ // Returning from the function implicitly kills storage for all locals and statics.
954
+ // Often, the storage will already have been killed by an explicit
955
+ // StorageDead, but we don't always emit those (notably on unwind paths),
956
+ // so this "extra check" serves as a kind of backup.
957
+ for i in state. borrows . iter ( ) {
958
+ let borrow = & self . borrow_set [ i] ;
959
+ self . check_for_invalidation_at_exit ( loc, borrow, span) ;
960
+ }
961
+ }
962
+ // If we do not implicitly invalidate all locals on exit,
963
+ // we check for conflicts when dropping or moving this local.
964
+ LocalsStateAtExit :: SomeAreInvalidated { has_storage_dead_or_moved : _ } => { }
948
965
}
949
966
}
950
967
@@ -1716,22 +1733,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1716
1733
// we'll have a memory leak) and assume that all statics have a destructor.
1717
1734
//
1718
1735
// FIXME: allow thread-locals to borrow other thread locals?
1719
-
1720
- let ( might_be_alive, will_be_dropped) =
1721
- if self . body . local_decls [ root_place. local ] . is_ref_to_thread_local ( ) {
1722
- // Thread-locals might be dropped after the function exits
1723
- // We have to dereference the outer reference because
1724
- // borrows don't conflict behind shared references.
1725
- root_place. projection = TyCtxtConsts :: DEREF_PROJECTION ;
1726
- ( true , true )
1727
- } else {
1728
- ( false , self . locals_are_invalidated_at_exit )
1729
- } ;
1730
-
1731
- if !will_be_dropped {
1732
- debug ! ( "place_is_invalidated_at_exit({:?}) - won't be dropped" , place) ;
1733
- return ;
1734
- }
1736
+ let might_be_alive = if self . body . local_decls [ root_place. local ] . is_ref_to_thread_local ( ) {
1737
+ // Thread-locals might be dropped after the function exits
1738
+ // We have to dereference the outer reference because
1739
+ // borrows don't conflict behind shared references.
1740
+ root_place. projection = TyCtxtConsts :: DEREF_PROJECTION ;
1741
+ true
1742
+ } else {
1743
+ false
1744
+ } ;
1735
1745
1736
1746
let sd = if might_be_alive { Deep } else { Shallow ( None ) } ;
1737
1747
0 commit comments