@@ -378,13 +378,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
378
378
// check for never_loop
379
379
match expr. node {
380
380
ExprWhile ( _, ref block, _) | ExprLoop ( ref block, _, _) => {
381
- let mut state = NeverLoopState {
382
- breaks : HashSet :: new ( ) ,
383
- continues : HashSet :: new ( ) ,
384
- } ;
385
- let may_complete = never_loop_block ( block, & mut state) ;
386
- if !may_complete && !state. continues . contains ( & expr. id ) {
387
- span_lint ( cx, NEVER_LOOP , expr. span , "this loop never actually loops" ) ;
381
+ match never_loop_block ( block, & expr. id ) {
382
+ NeverLoopResult :: AlwaysBreak =>
383
+ span_lint ( cx, NEVER_LOOP , expr. span , "this loop never actually loops" ) ,
384
+ NeverLoopResult :: MayContinueMainLoop | NeverLoopResult :: Otherwise => ( ) ,
388
385
}
389
386
} ,
390
387
_ => ( ) ,
@@ -491,16 +488,59 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
491
488
}
492
489
}
493
490
494
- struct NeverLoopState {
495
- breaks : HashSet < NodeId > ,
496
- continues : HashSet < NodeId > ,
491
+ enum NeverLoopResult {
492
+ // A break/return always get triggered but not necessarily for the main loop.
493
+ AlwaysBreak ,
494
+ // A continue may occur for the main loop.
495
+ MayContinueMainLoop ,
496
+ Otherwise ,
497
+ }
498
+
499
+ fn absorb_break ( arg : & NeverLoopResult ) -> NeverLoopResult {
500
+ match * arg {
501
+ NeverLoopResult :: AlwaysBreak |
502
+ NeverLoopResult :: Otherwise => NeverLoopResult :: Otherwise ,
503
+ NeverLoopResult :: MayContinueMainLoop => NeverLoopResult :: MayContinueMainLoop ,
504
+ }
505
+ }
506
+
507
+ // Combine two results for parts that are called in order.
508
+ fn combine_seq ( first : NeverLoopResult , second : NeverLoopResult ) -> NeverLoopResult {
509
+ match first {
510
+ NeverLoopResult :: AlwaysBreak | NeverLoopResult :: MayContinueMainLoop => first,
511
+ NeverLoopResult :: Otherwise => second,
512
+ }
513
+ }
514
+
515
+ // Combine two results where both parts are called but not necessarily in order.
516
+ fn combine_both ( left : NeverLoopResult , right : NeverLoopResult ) -> NeverLoopResult {
517
+ match ( left, right) {
518
+ ( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) =>
519
+ NeverLoopResult :: MayContinueMainLoop ,
520
+ ( NeverLoopResult :: AlwaysBreak , _) | ( _, NeverLoopResult :: AlwaysBreak ) =>
521
+ NeverLoopResult :: AlwaysBreak ,
522
+ ( NeverLoopResult :: Otherwise , NeverLoopResult :: Otherwise ) =>
523
+ NeverLoopResult :: Otherwise ,
524
+ }
525
+ }
526
+
527
+ // Combine two results where only one of the part may have been executed.
528
+ fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult ) -> NeverLoopResult {
529
+ match ( b1, b2) {
530
+ ( NeverLoopResult :: AlwaysBreak , NeverLoopResult :: AlwaysBreak ) =>
531
+ NeverLoopResult :: AlwaysBreak ,
532
+ ( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) =>
533
+ NeverLoopResult :: MayContinueMainLoop ,
534
+ ( NeverLoopResult :: Otherwise , _) | ( _, NeverLoopResult :: Otherwise ) =>
535
+ NeverLoopResult :: Otherwise ,
536
+ }
497
537
}
498
538
499
- fn never_loop_block ( block : & Block , state : & mut NeverLoopState ) -> bool {
539
+ fn never_loop_block ( block : & Block , main_loop_id : & NodeId ) -> NeverLoopResult {
500
540
let stmts = block. stmts . iter ( ) . map ( stmt_to_expr) ;
501
541
let expr = once ( block. expr . as_ref ( ) . map ( |p| & * * p) ) ;
502
542
let mut iter = stmts. chain ( expr) . filter_map ( |e| e) ;
503
- never_loop_expr_seq ( & mut iter, state )
543
+ never_loop_expr_seq ( & mut iter, main_loop_id )
504
544
}
505
545
506
546
fn stmt_to_expr ( stmt : & Stmt ) -> Option < & Expr > {
@@ -517,7 +557,7 @@ fn decl_to_expr(decl: &Decl) -> Option<&Expr> {
517
557
}
518
558
}
519
559
520
- fn never_loop_expr ( expr : & Expr , state : & mut NeverLoopState ) -> bool {
560
+ fn never_loop_expr ( expr : & Expr , main_loop_id : & NodeId ) -> NeverLoopResult {
521
561
match expr. node {
522
562
ExprBox ( ref e) |
523
563
ExprUnary ( _, ref e) |
@@ -526,77 +566,84 @@ fn never_loop_expr(expr: &Expr, state: &mut NeverLoopState) -> bool {
526
566
ExprField ( ref e, _) |
527
567
ExprTupField ( ref e, _) |
528
568
ExprAddrOf ( _, ref e) |
529
- ExprRepeat ( ref e, _) => never_loop_expr ( e, state) ,
569
+ ExprStruct ( _, _, Some ( ref e) ) |
570
+ ExprRepeat ( ref e, _) => never_loop_expr ( e, main_loop_id) ,
530
571
ExprArray ( ref es) | ExprMethodCall ( _, _, ref es) | ExprTup ( ref es) => {
531
- never_loop_expr_seq ( & mut es. iter ( ) , state )
572
+ never_loop_expr_all ( & mut es. iter ( ) , main_loop_id )
532
573
} ,
533
- ExprCall ( ref e, ref es) => never_loop_expr_seq ( & mut once ( & * * e) . chain ( es. iter ( ) ) , state ) ,
574
+ ExprCall ( ref e, ref es) => never_loop_expr_all ( & mut once ( & * * e) . chain ( es. iter ( ) ) , main_loop_id ) ,
534
575
ExprBinary ( _, ref e1, ref e2) |
535
576
ExprAssign ( ref e1, ref e2) |
536
577
ExprAssignOp ( _, ref e1, ref e2) |
537
- ExprIndex ( ref e1, ref e2) => never_loop_expr_seq ( & mut [ & * * e1, & * * e2] . iter ( ) . cloned ( ) , state ) ,
578
+ ExprIndex ( ref e1, ref e2) => never_loop_expr_all ( & mut [ & * * e1, & * * e2] . iter ( ) . cloned ( ) , main_loop_id ) ,
538
579
ExprIf ( ref e, ref e2, ref e3) => {
539
- let e1 = never_loop_expr ( e, state) ;
540
- let e2 = never_loop_expr ( e2, state) ;
541
- match * e3 {
542
- Some ( ref e3) => {
543
- let e3 = never_loop_expr ( e3, state) ;
544
- e1 && ( e2 || e3)
545
- } ,
546
- None => e1,
547
- }
580
+ let e1 = never_loop_expr ( e, main_loop_id) ;
581
+ let e2 = never_loop_expr ( e2, main_loop_id) ;
582
+ let e3 = e3. as_ref ( ) . map_or ( NeverLoopResult :: Otherwise , |e| never_loop_expr ( e, main_loop_id) ) ;
583
+ combine_seq ( e1, combine_branches ( e2, e3) )
548
584
} ,
549
585
ExprLoop ( ref b, _, _) => {
550
- let block_may_complete = never_loop_block ( b, state) ;
551
- let has_break = state. breaks . remove ( & expr. id ) ;
552
- state. continues . remove ( & expr. id ) ;
553
- block_may_complete || has_break
586
+ // Break can come from the inner loop so remove them.
587
+ absorb_break ( & never_loop_block ( b, main_loop_id) )
554
588
} ,
555
589
ExprWhile ( ref e, ref b, _) => {
556
- let e = never_loop_expr ( e, state) ;
557
- let block_may_complete = never_loop_block ( b, state) ;
558
- let has_break = state. breaks . remove ( & expr. id ) ;
559
- let has_continue = state. continues . remove ( & expr. id ) ;
560
- e && ( block_may_complete || has_break || has_continue)
590
+ let e = never_loop_expr ( e, main_loop_id) ;
591
+ let result = never_loop_block ( b, main_loop_id) ;
592
+ // Break can come from the inner loop so remove them.
593
+ combine_seq ( e, absorb_break ( & result) )
561
594
} ,
562
595
ExprMatch ( ref e, ref arms, _) => {
563
- let e = never_loop_expr ( e, state) ;
564
- let arms = never_loop_expr_branch ( & mut arms. iter ( ) . map ( |a| & * a. body ) , state) ;
565
- e && arms
596
+ let e = never_loop_expr ( e, main_loop_id) ;
597
+ if arms. is_empty ( ) {
598
+ e
599
+ } else {
600
+ let arms = never_loop_expr_branch ( & mut arms. iter ( ) . map ( |a| & * a. body ) , main_loop_id) ;
601
+ combine_seq ( e, arms)
602
+ }
566
603
} ,
567
- ExprBlock ( ref b) => never_loop_block ( b, state ) ,
604
+ ExprBlock ( ref b) => never_loop_block ( b, main_loop_id ) ,
568
605
ExprAgain ( d) => {
569
606
let id = d. target_id
570
607
. opt_id ( )
571
608
. expect ( "target id can only be missing in the presence of compilation errors" ) ;
572
- state. continues . insert ( id) ;
573
- false
609
+ if id == * main_loop_id {
610
+ NeverLoopResult :: MayContinueMainLoop
611
+ } else {
612
+ NeverLoopResult :: AlwaysBreak
613
+ }
574
614
} ,
575
- ExprBreak ( d, _) => {
576
- let id = d. target_id
577
- . opt_id ( )
578
- . expect ( "target id can only be missing in the presence of compilation errors" ) ;
579
- state. breaks . insert ( id) ;
580
- false
615
+ ExprBreak ( _, _) => {
616
+ NeverLoopResult :: AlwaysBreak
581
617
} ,
582
618
ExprRet ( ref e) => {
583
619
if let Some ( ref e) = * e {
584
- never_loop_expr ( e, state) ;
620
+ combine_seq ( never_loop_expr ( e, main_loop_id) , NeverLoopResult :: AlwaysBreak )
621
+ } else {
622
+ NeverLoopResult :: AlwaysBreak
585
623
}
586
- false
587
624
} ,
588
- _ => true ,
625
+ ExprStruct ( _, _, None ) |
626
+ ExprYield ( _) |
627
+ ExprClosure ( _, _, _, _, _) |
628
+ ExprInlineAsm ( _, _, _) |
629
+ ExprPath ( _) |
630
+ ExprLit ( _) => NeverLoopResult :: Otherwise ,
589
631
}
590
632
}
591
633
592
- fn never_loop_expr_seq < ' a , T : Iterator < Item = & ' a Expr > > ( es : & mut T , state : & mut NeverLoopState ) -> bool {
593
- es. map ( |e| never_loop_expr ( e, state) )
594
- . fold ( true , |a, b| a && b)
634
+ fn never_loop_expr_seq < ' a , T : Iterator < Item =& ' a Expr > > ( es : & mut T , main_loop_id : & NodeId ) -> NeverLoopResult {
635
+ es. map ( |e| never_loop_expr ( e, main_loop_id) )
636
+ . fold ( NeverLoopResult :: Otherwise , combine_seq)
637
+ }
638
+
639
+ fn never_loop_expr_all < ' a , T : Iterator < Item =& ' a Expr > > ( es : & mut T , main_loop_id : & NodeId ) -> NeverLoopResult {
640
+ es. map ( |e| never_loop_expr ( e, main_loop_id) )
641
+ . fold ( NeverLoopResult :: Otherwise , combine_both)
595
642
}
596
643
597
- fn never_loop_expr_branch < ' a , T : Iterator < Item = & ' a Expr > > ( e : & mut T , state : & mut NeverLoopState ) -> bool {
598
- e. map ( |e| never_loop_expr ( e, state ) )
599
- . fold ( false , |a , b| a || b )
644
+ fn never_loop_expr_branch < ' a , T : Iterator < Item = & ' a Expr > > ( e : & mut T , main_loop_id : & NodeId ) -> NeverLoopResult {
645
+ e. map ( |e| never_loop_expr ( e, main_loop_id ) )
646
+ . fold ( NeverLoopResult :: AlwaysBreak , combine_branches )
600
647
}
601
648
602
649
fn check_for_loop < ' a , ' tcx > (
0 commit comments