Auto merge of #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 #13511
This commit is contained in:
commit
d9c8d976cb
@ -42,6 +42,7 @@ pub(super) fn check<'tcx>(
|
|||||||
let mut loop_visitor = LoopVisitor {
|
let mut loop_visitor = LoopVisitor {
|
||||||
cx,
|
cx,
|
||||||
label,
|
label,
|
||||||
|
inner_labels: label.into_iter().collect(),
|
||||||
is_finite: false,
|
is_finite: false,
|
||||||
loop_depth: 0,
|
loop_depth: 0,
|
||||||
};
|
};
|
||||||
@ -93,6 +94,7 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option
|
|||||||
struct LoopVisitor<'hir, 'tcx> {
|
struct LoopVisitor<'hir, 'tcx> {
|
||||||
cx: &'hir LateContext<'tcx>,
|
cx: &'hir LateContext<'tcx>,
|
||||||
label: Option<Label>,
|
label: Option<Label>,
|
||||||
|
inner_labels: Vec<Label>,
|
||||||
loop_depth: usize,
|
loop_depth: usize,
|
||||||
is_finite: bool,
|
is_finite: bool,
|
||||||
}
|
}
|
||||||
@ -108,11 +110,24 @@ fn visit_expr(&mut self, ex: &'hir Expr<'_>) {
|
|||||||
self.is_finite = true;
|
self.is_finite = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ExprKind::Continue(hir::Destination { label, .. }) => {
|
||||||
|
// Check whether we are leaving this loop by continuing into an outer loop
|
||||||
|
// whose label we did not encounter.
|
||||||
|
if label.is_some_and(|label| !self.inner_labels.contains(&label)) {
|
||||||
|
self.is_finite = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
ExprKind::Ret(..) => self.is_finite = true,
|
ExprKind::Ret(..) => self.is_finite = true,
|
||||||
ExprKind::Loop(..) => {
|
ExprKind::Loop(_, label, _, _) => {
|
||||||
|
if let Some(label) = label {
|
||||||
|
self.inner_labels.push(*label);
|
||||||
|
}
|
||||||
self.loop_depth += 1;
|
self.loop_depth += 1;
|
||||||
walk_expr(self, ex);
|
walk_expr(self, ex);
|
||||||
self.loop_depth -= 1;
|
self.loop_depth -= 1;
|
||||||
|
if label.is_some() {
|
||||||
|
self.inner_labels.pop();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// Calls to a function that never return
|
// Calls to a function that never return
|
||||||
|
@ -390,4 +390,42 @@ fn span_inside_fn() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn continue_outer() {
|
||||||
|
// Should not lint (issue #13511)
|
||||||
|
let mut count = 0;
|
||||||
|
'outer: loop {
|
||||||
|
if count != 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
count += 1;
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should lint as we continue the loop itself
|
||||||
|
'infinite: loop {
|
||||||
|
//~^ ERROR: infinite loop detected
|
||||||
|
loop {
|
||||||
|
continue 'infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This should lint as we continue an inner loop
|
||||||
|
loop {
|
||||||
|
//~^ ERROR: infinite loop detected
|
||||||
|
'inner: loop {
|
||||||
|
loop {
|
||||||
|
continue 'inner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should lint as we continue the loop itself
|
||||||
|
loop {
|
||||||
|
//~^ ERROR: infinite loop detected
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -255,5 +255,67 @@ LL | | })
|
|||||||
|
|
|
|
||||||
= help: if this is not intended, try adding a `break` or `return` condition in the loop
|
= help: if this is not intended, try adding a `break` or `return` condition in the loop
|
||||||
|
|
||||||
error: aborting due to 17 previous errors
|
error: infinite loop detected
|
||||||
|
--> tests/ui/infinite_loops.rs:408:5
|
||||||
|
|
|
||||||
|
LL | / 'infinite: loop {
|
||||||
|
LL | |
|
||||||
|
LL | | loop {
|
||||||
|
LL | | continue 'infinite;
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
||||||
|
LL | fn continue_outer() -> ! {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: infinite loop detected
|
||||||
|
--> tests/ui/infinite_loops.rs:415:5
|
||||||
|
|
|
||||||
|
LL | / loop {
|
||||||
|
LL | |
|
||||||
|
LL | | 'inner: loop {
|
||||||
|
LL | | loop {
|
||||||
|
... |
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
||||||
|
LL | fn continue_outer() -> ! {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: infinite loop detected
|
||||||
|
--> tests/ui/infinite_loops.rs:417:9
|
||||||
|
|
|
||||||
|
LL | / 'inner: loop {
|
||||||
|
LL | | loop {
|
||||||
|
LL | | continue 'inner;
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
|
||||||
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
||||||
|
LL | fn continue_outer() -> ! {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: infinite loop detected
|
||||||
|
--> tests/ui/infinite_loops.rs:425:5
|
||||||
|
|
|
||||||
|
LL | / loop {
|
||||||
|
LL | |
|
||||||
|
LL | | continue;
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
||||||
|
LL | fn continue_outer() -> ! {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: aborting due to 21 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user