@@ -436,15 +436,19 @@ fn do_mir_borrowck<'tcx>(
436
436
// Compute and report region errors, if any.
437
437
mbcx. report_region_errors ( nll_errors) ;
438
438
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
+ }
448
452
449
453
mbcx. report_move_errors ( ) ;
450
454
@@ -497,6 +501,186 @@ fn do_mir_borrowck<'tcx>(
497
501
result
498
502
}
499
503
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
+
500
684
fn get_flow_results < ' a , ' tcx > (
501
685
tcx : TyCtxt < ' tcx > ,
502
686
body : & ' a Body < ' tcx > ,
0 commit comments