@@ -34,27 +34,15 @@ pub(super) fn check<'tcx>(
34
34
return ;
35
35
}
36
36
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 {
41
38
cx,
42
39
label,
43
40
is_finite : false ,
44
- enter_nested_loop : false ,
41
+ loop_depth : 0 ,
45
42
} ;
46
- direct_visitor . visit_block ( loop_block) ;
43
+ loop_visitor . visit_block ( loop_block) ;
47
44
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 ;
58
46
59
47
if !is_finite_loop {
60
48
span_lint_and_then ( cx, INFINITE_LOOPS , expr. span , "infinite loop detected" , |diag| {
@@ -103,26 +91,29 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option
103
91
struct LoopVisitor < ' hir , ' tcx > {
104
92
cx : & ' hir LateContext < ' tcx > ,
105
93
label : Option < Label > ,
94
+ loop_depth : usize ,
106
95
is_finite : bool ,
107
- enter_nested_loop : bool ,
108
96
}
109
97
110
98
impl < ' hir > Visitor < ' hir > for LoopVisitor < ' hir , ' _ > {
111
99
fn visit_expr ( & mut self , ex : & ' hir Expr < ' _ > ) {
112
100
match & ex. kind {
113
101
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
106
+ || ( label. is_some ( ) && * label == self . label )
107
+ {
121
108
self . is_finite = true ;
122
109
}
123
110
} ,
124
111
ExprKind :: Ret ( ..) => self . is_finite = true ,
125
- ExprKind :: Loop ( ..) if !self . enter_nested_loop => ( ) ,
112
+ ExprKind :: Loop ( ..) => {
113
+ self . loop_depth += 1 ;
114
+ walk_expr ( self , ex) ;
115
+ self . loop_depth = self . loop_depth . saturating_sub ( 1 ) ;
116
+ } ,
126
117
_ => {
127
118
// Calls to a function that never return
128
119
if let Some ( did) = fn_def_id ( self . cx , ex) {
0 commit comments