Skip to content

Commit d9c8d97

Browse files
committed
Auto merge of rust-lang#13512 - samueltardieu:issue-13511, r=xFrednet
`infinite_loop`: continuing an outer loop leaves the inner loop changelog: [`infinite_loop`]: detect a `continue` targeting an outer loop Fix rust-lang#13511
2 parents 6f4bf90 + 99ce411 commit d9c8d97

File tree

3 files changed

+117
-2
lines changed

3 files changed

+117
-2
lines changed

clippy_lints/src/loops/infinite_loop.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub(super) fn check<'tcx>(
4242
let mut loop_visitor = LoopVisitor {
4343
cx,
4444
label,
45+
inner_labels: label.into_iter().collect(),
4546
is_finite: false,
4647
loop_depth: 0,
4748
};
@@ -93,6 +94,7 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option
9394
struct LoopVisitor<'hir, 'tcx> {
9495
cx: &'hir LateContext<'tcx>,
9596
label: Option<Label>,
97+
inner_labels: Vec<Label>,
9698
loop_depth: usize,
9799
is_finite: bool,
98100
}
@@ -108,11 +110,24 @@ impl<'hir> Visitor<'hir> for LoopVisitor<'hir, '_> {
108110
self.is_finite = true;
109111
}
110112
},
113+
ExprKind::Continue(hir::Destination { label, .. }) => {
114+
// Check whether we are leaving this loop by continuing into an outer loop
115+
// whose label we did not encounter.
116+
if label.is_some_and(|label| !self.inner_labels.contains(&label)) {
117+
self.is_finite = true;
118+
}
119+
},
111120
ExprKind::Ret(..) => self.is_finite = true,
112-
ExprKind::Loop(..) => {
121+
ExprKind::Loop(_, label, _, _) => {
122+
if let Some(label) = label {
123+
self.inner_labels.push(*label);
124+
}
113125
self.loop_depth += 1;
114126
walk_expr(self, ex);
115127
self.loop_depth -= 1;
128+
if label.is_some() {
129+
self.inner_labels.pop();
130+
}
116131
},
117132
_ => {
118133
// Calls to a function that never return

tests/ui/infinite_loops.rs

+38
Original file line numberDiff line numberDiff line change
@@ -390,4 +390,42 @@ fn span_inside_fn() {
390390
}
391391
}
392392

393+
fn continue_outer() {
394+
// Should not lint (issue #13511)
395+
let mut count = 0;
396+
'outer: loop {
397+
if count != 0 {
398+
break;
399+
}
400+
401+
loop {
402+
count += 1;
403+
continue 'outer;
404+
}
405+
}
406+
407+
// This should lint as we continue the loop itself
408+
'infinite: loop {
409+
//~^ ERROR: infinite loop detected
410+
loop {
411+
continue 'infinite;
412+
}
413+
}
414+
// This should lint as we continue an inner loop
415+
loop {
416+
//~^ ERROR: infinite loop detected
417+
'inner: loop {
418+
loop {
419+
continue 'inner;
420+
}
421+
}
422+
}
423+
424+
// This should lint as we continue the loop itself
425+
loop {
426+
//~^ ERROR: infinite loop detected
427+
continue;
428+
}
429+
}
430+
393431
fn main() {}

tests/ui/infinite_loops.stderr

+63-1
Original file line numberDiff line numberDiff line change
@@ -255,5 +255,67 @@ LL | | })
255255
|
256256
= help: if this is not intended, try adding a `break` or `return` condition in the loop
257257

258-
error: aborting due to 17 previous errors
258+
error: infinite loop detected
259+
--> tests/ui/infinite_loops.rs:408:5
260+
|
261+
LL | / 'infinite: loop {
262+
LL | |
263+
LL | | loop {
264+
LL | | continue 'infinite;
265+
LL | | }
266+
LL | | }
267+
| |_____^
268+
|
269+
help: if this is intentional, consider specifying `!` as function return
270+
|
271+
LL | fn continue_outer() -> ! {
272+
| ++++
273+
274+
error: infinite loop detected
275+
--> tests/ui/infinite_loops.rs:415:5
276+
|
277+
LL | / loop {
278+
LL | |
279+
LL | | 'inner: loop {
280+
LL | | loop {
281+
... |
282+
LL | | }
283+
LL | | }
284+
| |_____^
285+
|
286+
help: if this is intentional, consider specifying `!` as function return
287+
|
288+
LL | fn continue_outer() -> ! {
289+
| ++++
290+
291+
error: infinite loop detected
292+
--> tests/ui/infinite_loops.rs:417:9
293+
|
294+
LL | / 'inner: loop {
295+
LL | | loop {
296+
LL | | continue 'inner;
297+
LL | | }
298+
LL | | }
299+
| |_________^
300+
|
301+
help: if this is intentional, consider specifying `!` as function return
302+
|
303+
LL | fn continue_outer() -> ! {
304+
| ++++
305+
306+
error: infinite loop detected
307+
--> tests/ui/infinite_loops.rs:425:5
308+
|
309+
LL | / loop {
310+
LL | |
311+
LL | | continue;
312+
LL | | }
313+
| |_____^
314+
|
315+
help: if this is intentional, consider specifying `!` as function return
316+
|
317+
LL | fn continue_outer() -> ! {
318+
| ++++
319+
320+
error: aborting due to 21 previous errors
259321

0 commit comments

Comments
 (0)