@@ -436,15 +436,19 @@ fn do_mir_borrowck<'tcx>(
436436 // Compute and report region errors, if any.
437437 mbcx. report_region_errors ( nll_errors) ;
438438
439- let ( mut flow_analysis, flow_entry_states) =
440- get_flow_results ( tcx, body, & move_data, & borrow_set, & regioncx) ;
441- visit_results (
442- body,
443- traversal:: reverse_postorder ( body) . map ( |( bb, _) | bb) ,
444- & mut flow_analysis,
445- & flow_entry_states,
446- & mut mbcx,
447- ) ;
439+ if body. basic_blocks . is_cfg_cyclic ( ) {
440+ let ( mut flow_analysis, flow_entry_states) =
441+ get_flow_results ( tcx, body, & move_data, & borrow_set, & regioncx) ;
442+ visit_results (
443+ body,
444+ traversal:: reverse_postorder ( body) . map ( |( bb, _) | bb) ,
445+ & mut flow_analysis,
446+ & flow_entry_states,
447+ & mut mbcx,
448+ ) ;
449+ } else {
450+ compute_dataflow ( tcx, body, & move_data, & borrow_set, & regioncx, & mut mbcx) ;
451+ }
448452
449453 mbcx. report_move_errors ( ) ;
450454
@@ -497,6 +501,186 @@ fn do_mir_borrowck<'tcx>(
497501 result
498502}
499503
504+ fn compute_dataflow < ' a , ' tcx > (
505+ tcx : TyCtxt < ' tcx > ,
506+ body : & ' a Body < ' tcx > ,
507+
508+ move_data : & ' a MoveData < ' tcx > ,
509+ borrow_set : & ' a BorrowSet < ' tcx > ,
510+ regioncx : & RegionInferenceContext < ' tcx > ,
511+
512+ vis : & mut MirBorrowckCtxt < ' a , ' _ , ' tcx > ,
513+ ) {
514+ let borrows = Borrows :: new ( tcx, body, regioncx, borrow_set) ;
515+ let uninits = MaybeUninitializedPlaces :: new ( tcx, body, move_data) ;
516+ let ever_inits = EverInitializedPlaces :: new ( body, move_data) ;
517+
518+ let mut analysis = Borrowck { borrows, uninits, ever_inits } ;
519+
520+ // Set up lazy state for the CFG
521+ use rustc_middle:: mir;
522+ use rustc_mir_dataflow:: JoinSemiLattice ;
523+
524+ let mut results: IndexVec < BasicBlock , Option < BorrowckDomain > > =
525+ IndexVec :: from_elem_n ( None , body. basic_blocks . len ( ) ) ;
526+
527+ // Ensure the start block has some state in it;
528+ results[ mir:: START_BLOCK ] = Some ( analysis. bottom_value ( body) ) ;
529+ analysis. initialize_start_block ( body, results[ mir:: START_BLOCK ] . as_mut ( ) . unwrap ( ) ) ;
530+
531+ for ( _idx, ( block, block_data) ) in traversal:: reverse_postorder ( body) . enumerate ( ) {
532+ // Apply effects in block
533+ let mut block_state = results[ block] . take ( ) . unwrap_or_else ( || analysis. bottom_value ( body) ) ;
534+
535+ vis. visit_block_start ( & mut block_state) ;
536+
537+ for ( statement_index, statement) in block_data. statements . iter ( ) . enumerate ( ) {
538+ let location = Location { block, statement_index } ;
539+ analysis. apply_early_statement_effect ( & mut block_state, statement, location) ;
540+ vis. visit_after_early_statement_effect (
541+ & mut analysis,
542+ & block_state,
543+ statement,
544+ location,
545+ ) ;
546+
547+ analysis. apply_primary_statement_effect ( & mut block_state, statement, location) ;
548+ vis. visit_after_primary_statement_effect (
549+ & mut analysis,
550+ & block_state,
551+ statement,
552+ location,
553+ ) ;
554+ }
555+ let terminator = block_data. terminator ( ) ;
556+ let location = Location { block, statement_index : block_data. statements . len ( ) } ;
557+ analysis. apply_early_terminator_effect ( & mut block_state, terminator, location) ;
558+ vis. visit_after_early_terminator_effect ( & mut analysis, & block_state, terminator, location) ;
559+
560+ let edges =
561+ analysis. apply_primary_terminator_effect ( & mut block_state, terminator, location) ;
562+ vis. visit_after_primary_terminator_effect (
563+ & mut analysis,
564+ & block_state,
565+ terminator,
566+ location,
567+ ) ;
568+
569+ // notify visitor the block is ready
570+ vis. visit_block_end ( & mut block_state) ;
571+
572+ match edges {
573+ TerminatorEdges :: None => { }
574+ TerminatorEdges :: Single ( target) => match results[ target] . as_mut ( ) {
575+ None => {
576+ results[ target] = Some ( block_state) ;
577+ }
578+ Some ( existing_state) => {
579+ existing_state. join ( & block_state) ;
580+ }
581+ } ,
582+ TerminatorEdges :: Double ( target, unwind) if target == unwind => {
583+ // wtf
584+ match results[ target] . as_mut ( ) {
585+ None => {
586+ results[ target] = Some ( block_state) ;
587+ }
588+ Some ( existing_state) => {
589+ existing_state. join ( & block_state) ;
590+ }
591+ }
592+ }
593+ TerminatorEdges :: Double ( target, unwind) => match results. pick2_mut ( target, unwind) {
594+ ( None , None ) => {
595+ results[ target] = Some ( block_state. clone ( ) ) ;
596+ results[ unwind] = Some ( block_state) ;
597+ }
598+ ( None , Some ( unwind_state) ) => {
599+ unwind_state. join ( & block_state) ;
600+ results[ target] = Some ( block_state) ;
601+ }
602+ ( Some ( target_state) , None ) => {
603+ target_state. join ( & block_state) ;
604+ results[ unwind] = Some ( block_state) ;
605+ }
606+ ( Some ( target_state) , Some ( unwind_state) ) => {
607+ target_state. join ( & block_state) ;
608+ unwind_state. join ( & block_state) ;
609+ }
610+ } ,
611+ TerminatorEdges :: AssignOnReturn { return_, cleanup, place } => {
612+ // This must be done *first*, otherwise the unwind path will see the assignments.
613+ if let Some ( cleanup) = cleanup {
614+ match results[ cleanup] . as_mut ( ) {
615+ None => {
616+ results[ cleanup] = Some ( block_state. clone ( ) ) ;
617+ }
618+ Some ( existing_state) => {
619+ existing_state. join ( & block_state) ;
620+ }
621+ }
622+ }
623+
624+ if !return_. is_empty ( ) {
625+ analysis. apply_call_return_effect ( & mut block_state, block, place) ;
626+
627+ // fixme: optimize, if we've merged the previous target states instead
628+ // of moving, we don't need to clone it.
629+
630+ let target_count = return_. len ( ) ;
631+ for & target in return_. iter ( ) . take ( target_count - 1 ) {
632+ match results[ target] . as_mut ( ) {
633+ None => {
634+ results[ target] = Some ( block_state. clone ( ) ) ;
635+ }
636+ Some ( existing_state) => {
637+ existing_state. join ( & block_state) ;
638+ }
639+ }
640+ }
641+
642+ let target = * return_. last ( ) . unwrap ( ) ;
643+ match results[ target] . as_mut ( ) {
644+ None => {
645+ results[ target] = Some ( block_state. clone ( ) ) ;
646+ }
647+ Some ( existing_state) => {
648+ existing_state. join ( & block_state) ;
649+ }
650+ }
651+ }
652+ }
653+ TerminatorEdges :: SwitchInt { targets, discr } => {
654+ if let Some ( _data) = analysis. get_switch_int_data ( block, discr) {
655+ todo ! ( "wat. this is unused in tests" ) ;
656+ } else {
657+ let target_count = targets. all_targets ( ) . len ( ) ;
658+ for & target in targets. all_targets ( ) . iter ( ) . take ( target_count - 1 ) {
659+ match results[ target] . as_mut ( ) {
660+ None => {
661+ results[ target] = Some ( block_state. clone ( ) ) ;
662+ }
663+ Some ( existing_state) => {
664+ existing_state. join ( & block_state) ;
665+ }
666+ }
667+ }
668+
669+ let target = * targets. all_targets ( ) . last ( ) . unwrap ( ) ;
670+ match results[ target] . as_mut ( ) {
671+ None => {
672+ results[ target] = Some ( block_state. clone ( ) ) ;
673+ }
674+ Some ( existing_state) => {
675+ existing_state. join ( & block_state) ;
676+ }
677+ }
678+ }
679+ }
680+ }
681+ }
682+ }
683+
500684fn get_flow_results < ' a , ' tcx > (
501685 tcx : TyCtxt < ' tcx > ,
502686 body : & ' a Body < ' tcx > ,
0 commit comments