@@ -22,6 +22,8 @@ use std::cell::RefCell;
2222use std:: marker:: PhantomData ;
2323use std:: ops:: { ControlFlow , Deref } ;
2424
25+ use borrow_set:: LocalsStateAtExit ;
26+ use diagnostics:: RegionErrors ;
2527use root_cx:: BorrowCheckRootCtxt ;
2628use rustc_abi:: FieldIdx ;
2729use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
@@ -304,33 +306,13 @@ fn do_mir_borrowck<'tcx>(
304306 root_cx. set_tainted_by_errors ( e) ;
305307 }
306308
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-
327309 // Replace all regions with fresh inference variables. This
328310 // requires first making our own copy of the MIR. This copy will
329311 // be modified (in place) to contain non-lexical lifetimes. It
330312 // will have a lifetime tied to the inference context.
331313 let mut body_owned = input_body. clone ( ) ;
332314 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) ;
334316 let body = & body_owned; // no further changes
335317
336318 let location_table = PoloniusLocationTable :: new ( body) ;
@@ -355,7 +337,7 @@ fn do_mir_borrowck<'tcx>(
355337 } = nll:: compute_regions (
356338 root_cx,
357339 & infcx,
358- free_regions ,
340+ universal_regions ,
359341 body,
360342 & promoted,
361343 & location_table,
@@ -368,27 +350,76 @@ fn do_mir_borrowck<'tcx>(
368350 // Dump MIR results into a file, if that is enabled. This lets us
369351 // write unit-tests, as well as helping with debugging.
370352 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+ ) ;
371361
372362 // We also have a `#[rustc_regions]` annotation that causes us to dump
373363 // 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 ;
388418
419+ let diags_buffer = & mut BorrowckDiagnosticsBuffer :: default ( ) ;
389420 // While promoteds should mostly be correct by construction, we need to check them for
390421 // 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 {
392423 use rustc_middle:: mir:: visit:: Visitor ;
393424 // This assumes that we won't use some of the fields of the `promoted_mbcx`
394425 // when detecting and reporting move errors. While it would be nice to move
@@ -403,7 +434,6 @@ fn do_mir_borrowck<'tcx>(
403434 location_table : & location_table,
404435 movable_coroutine,
405436 fn_self_span_reported : Default :: default ( ) ,
406- locals_are_invalidated_at_exit,
407437 access_place_error_reported : Default :: default ( ) ,
408438 reservation_error_reported : Default :: default ( ) ,
409439 uninitialized_error_reported : Default :: default ( ) ,
@@ -415,10 +445,11 @@ fn do_mir_borrowck<'tcx>(
415445 local_names : IndexVec :: from_elem ( None , & promoted_body. local_decls ) ,
416446 region_names : RefCell :: default ( ) ,
417447 next_region_name : RefCell :: new ( 1 ) ,
418- polonius_output : None ,
419448 move_errors : Vec :: new ( ) ,
420449 diags_buffer,
421- polonius_diagnostics : polonius_diagnostics. as_ref ( ) ,
450+
451+ polonius_output,
452+ polonius_diagnostics,
422453 } ;
423454 struct MoveVisitor < ' a , ' b , ' infcx , ' tcx > {
424455 ctxt : & ' a mut MirBorrowckCtxt < ' b , ' infcx , ' tcx > ,
@@ -435,30 +466,49 @@ fn do_mir_borrowck<'tcx>(
435466 promoted_mbcx. report_move_errors ( ) ;
436467 }
437468
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+
438489 let mut mbcx = MirBorrowckCtxt {
439490 root_cx,
440491 infcx : & infcx,
441492 body,
442493 move_data : & move_data,
443494 location_table : & location_table,
444495 movable_coroutine,
445- locals_are_invalidated_at_exit,
446496 fn_self_span_reported : Default :: default ( ) ,
447497 access_place_error_reported : Default :: default ( ) ,
448498 reservation_error_reported : Default :: default ( ) ,
449499 uninitialized_error_reported : Default :: default ( ) ,
450- regioncx : & regioncx ,
500+ regioncx,
451501 used_mut : Default :: default ( ) ,
452502 used_mut_upvars : SmallVec :: new ( ) ,
453503 borrow_set : & borrow_set,
454- upvars : tcx. closure_captures ( def ) ,
504+ upvars : tcx. closure_captures ( body . source . def_id ( ) . expect_local ( ) ) ,
455505 local_names,
456506 region_names : RefCell :: default ( ) ,
457507 next_region_name : RefCell :: new ( 1 ) ,
458- polonius_output,
459508 move_errors : Vec :: new ( ) ,
460509 diags_buffer,
461- polonius_diagnostics : polonius_diagnostics. as_ref ( ) ,
510+ polonius_output,
511+ polonius_diagnostics,
462512 } ;
463513
464514 // Compute and report region errors, if any.
@@ -474,16 +524,6 @@ fn do_mir_borrowck<'tcx>(
474524
475525 mbcx. report_move_errors ( ) ;
476526
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-
487527 // For each non-user used mutable variable, check if it's been assigned from
488528 // a user-declared local. If so, then put that local into the used_mut set.
489529 // Note that this set is expected to be small - only upvars from closures
@@ -508,29 +548,7 @@ fn do_mir_borrowck<'tcx>(
508548 mbcx. root_cx . set_tainted_by_errors ( guar) ;
509549 }
510550
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
534552}
535553
536554fn get_flow_results < ' a , ' tcx > (
@@ -655,13 +673,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
655673 location_table : & ' a PoloniusLocationTable ,
656674
657675 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 ,
665676 /// This field keeps track of when borrow errors are reported in the access_place function
666677 /// so that there is no duplicate reporting. This field cannot also be used for the conflicting
667678 /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
@@ -709,12 +720,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
709720 /// The counter for generating new region names.
710721 next_region_name : RefCell < usize > ,
711722
712- /// Results of Polonius analysis.
713- polonius_output : Option < Box < PoloniusOutput > > ,
714-
715723 diags_buffer : & ' a mut BorrowckDiagnosticsBuffer < ' infcx , ' tcx > ,
716724 move_errors : Vec < MoveError < ' tcx > > ,
717725
726+ /// Results of Polonius analysis.
727+ polonius_output : Option < & ' a PoloniusOutput > ,
718728 /// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
719729 polonius_diagnostics : Option < & ' a PoloniusDiagnosticsContext > ,
720730}
@@ -938,13 +948,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
938948 | TerminatorKind :: Return
939949 | TerminatorKind :: TailCall { .. }
940950 | 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 : _ } => { }
948965 }
949966 }
950967
@@ -1716,22 +1733,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
17161733 // we'll have a memory leak) and assume that all statics have a destructor.
17171734 //
17181735 // 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+ } ;
17351745
17361746 let sd = if might_be_alive { Deep } else { Shallow ( None ) } ;
17371747
0 commit comments