@@ -34,27 +34,15 @@ pub(super) fn check<'tcx>(
3434 return ;
3535 }
3636
37- // First, find any `break` or `return` without entering any inner loop,
38- // then, find `return` or labeled `break` which breaks this loop with entering inner loop,
39- // otherwise this loop is a infinite loop.
40- let mut direct_visitor = LoopVisitor {
37+ let mut loop_visitor = LoopVisitor {
4138 cx,
4239 label,
4340 is_finite : false ,
44- enter_nested_loop : false ,
41+ loop_depth : 0 ,
4542 } ;
46- direct_visitor . visit_block ( loop_block) ;
43+ loop_visitor . visit_block ( loop_block) ;
4744
48- let is_finite_loop = direct_visitor. is_finite || {
49- let mut inner_loop_visitor = LoopVisitor {
50- cx,
51- label,
52- is_finite : false ,
53- enter_nested_loop : true ,
54- } ;
55- inner_loop_visitor. visit_block ( loop_block) ;
56- inner_loop_visitor. is_finite
57- } ;
45+ let is_finite_loop = loop_visitor. is_finite ;
5846
5947 if !is_finite_loop {
6048 span_lint_and_then ( cx, INFINITE_LOOPS , expr. span , "infinite loop detected" , |diag| {
@@ -103,26 +91,27 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option
10391struct LoopVisitor < ' hir , ' tcx > {
10492 cx : & ' hir LateContext < ' tcx > ,
10593 label : Option < Label > ,
94+ loop_depth : usize ,
10695 is_finite : bool ,
107- enter_nested_loop : bool ,
10896}
10997
11098impl < ' hir > Visitor < ' hir > for LoopVisitor < ' hir , ' _ > {
11199 fn visit_expr ( & mut self , ex : & ' hir Expr < ' _ > ) {
112100 match & ex. kind {
113101 ExprKind :: Break ( hir:: Destination { label, .. } , ..) => {
114- // When entering nested loop, only by breaking this loop's label
115- // would be considered as exiting this loop.
116- if self . enter_nested_loop {
117- if label. is_some ( ) && * label == self . label {
118- self . is_finite = true ;
119- }
120- } else {
102+ // Assuming breaks the loop when `loop_depth` is 0,
103+ // as it could only means this `break` breaks current loop or any of its upper loop.
104+ // Or, the depth is not zero but the label is matched.
105+ if self . loop_depth == 0 || ( label. is_some ( ) && * label == self . label ) {
121106 self . is_finite = true ;
122107 }
123108 } ,
124109 ExprKind :: Ret ( ..) => self . is_finite = true ,
125- ExprKind :: Loop ( ..) if !self . enter_nested_loop => ( ) ,
110+ ExprKind :: Loop ( ..) => {
111+ self . loop_depth += 1 ;
112+ walk_expr ( self , ex) ;
113+ self . loop_depth = self . loop_depth . saturating_sub ( 1 ) ;
114+ } ,
126115 _ => {
127116 // Calls to a function that never return
128117 if let Some ( did) = fn_def_id ( self . cx , ex) {
0 commit comments