Skip to content

Commit 5a8a577

Browse files
Fix infinite_loop wrong suggestion inside conditional branches (#16619)
Fix #16155 Suppress the `-> !` suggestion when the loop is inside a conditional where not all branches diverge. When every branch does diverge (e.g. `if cond { loop {} } else { loop {} }`), the suggestion is still emitted. changelog: [`infinite_loop`]: Fix wrong suggestion to add `-> !` when the loop is inside a conditional branch
2 parents 8c1c477 + 5522517 commit 5a8a577

File tree

3 files changed

+166
-30
lines changed

3 files changed

+166
-30
lines changed

clippy_lints/src/loops/infinite_loop.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
2-
use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed};
2+
use clippy_utils::{RequiresSemi, fn_def_id, is_from_proc_macro, is_lint_allowed, is_never_expr};
33
use hir::intravisit::{Visitor, walk_expr};
44
use rustc_ast::Label;
55
use rustc_errors::Applicability;
@@ -52,16 +52,20 @@ pub(super) fn check<'tcx>(
5252

5353
if !is_finite_loop {
5454
span_lint_and_then(cx, INFINITE_LOOP, expr.span, "infinite loop detected", |diag| {
55-
if let FnRetTy::DefaultReturn(ret_span) = parent_fn_ret {
55+
if let FnRetTy::DefaultReturn(ret_span) = parent_fn_ret
56+
&& cx
57+
.enclosing_body
58+
.is_some_and(|id| matches!(is_never_expr(cx, cx.tcx.hir_body(id).value), Some(RequiresSemi::No)))
59+
{
5660
diag.span_suggestion(
5761
ret_span,
5862
"if this is intentional, consider specifying `!` as function return",
5963
" -> !",
6064
Applicability::MaybeIncorrect,
6165
);
62-
} else {
63-
diag.help("if this is not intended, try adding a `break` or `return` condition in the loop");
6466
}
67+
68+
diag.help("if this is not intended, try adding a `break` or `return` to the loop");
6569
});
6670
}
6771
}

tests/ui/infinite_loops.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,4 +536,57 @@ mod issue15541 {
536536
}
537537
}
538538

539+
mod issue16155 {
540+
#![allow(clippy::empty_loop)]
541+
542+
use super::do_something;
543+
544+
fn let_then_else(cond: bool) {
545+
let true = cond else { loop {} };
546+
//~^ infinite_loop
547+
}
548+
549+
fn loop_in_one_if_branch(cond: bool) {
550+
if cond {
551+
loop {}
552+
//~^ infinite_loop
553+
}
554+
}
555+
556+
fn loop_in_one_match_arm(x: Option<i32>) {
557+
match x {
558+
Some(_) => {},
559+
None => loop {},
560+
//~^ infinite_loop
561+
}
562+
}
563+
564+
fn loop_in_if_let_else(x: Option<i32>) {
565+
if let Some(_val) = x {
566+
do_something();
567+
} else {
568+
loop {}
569+
//~^ infinite_loop
570+
}
571+
}
572+
573+
#[expect(clippy::if_same_then_else)]
574+
fn all_branches_diverge_if(cond: bool) {
575+
if cond {
576+
loop {}
577+
//~^ infinite_loop
578+
} else {
579+
loop {}
580+
//~^ infinite_loop
581+
}
582+
}
583+
584+
fn all_branches_diverge_match(x: Option<i32>) {
585+
match x {
586+
Some(_) => loop {}, //~ infinite_loop
587+
None => loop {}, //~ infinite_loop
588+
}
589+
}
590+
}
591+
539592
fn main() {}

tests/ui/infinite_loops.stderr

Lines changed: 105 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ LL | | do_something();
77
LL | | }
88
| |_____^
99
|
10+
= help: if this is not intended, try adding a `break` or `return` to the loop
1011
= note: `-D clippy::infinite-loop` implied by `-D warnings`
1112
= help: to override `-D warnings` add `#[allow(clippy::infinite_loop)]`
1213
help: if this is intentional, consider specifying `!` as function return
@@ -25,6 +26,7 @@ LL | | do_something();
2526
LL | | }
2627
| |_____^
2728
|
29+
= help: if this is not intended, try adding a `break` or `return` to the loop
2830
help: if this is intentional, consider specifying `!` as function return
2931
|
3032
LL | fn all_inf() -> ! {
@@ -40,6 +42,7 @@ LL | | loop {
4042
LL | | }
4143
| |_________^
4244
|
45+
= help: if this is not intended, try adding a `break` or `return` to the loop
4346
help: if this is intentional, consider specifying `!` as function return
4447
|
4548
LL | fn all_inf() -> ! {
@@ -54,6 +57,7 @@ LL | | do_something();
5457
LL | | }
5558
| |_____________^
5659
|
60+
= help: if this is not intended, try adding a `break` or `return` to the loop
5761
help: if this is intentional, consider specifying `!` as function return
5862
|
5963
LL | fn all_inf() -> ! {
@@ -68,7 +72,7 @@ LL | | do_something();
6872
LL | | }
6973
| |_____^
7074
|
71-
= help: if this is not intended, try adding a `break` or `return` condition in the loop
75+
= help: if this is not intended, try adding a `break` or `return` to the loop
7276

7377
error: infinite loop detected
7478
--> tests/ui/infinite_loops.rs:51:5
@@ -82,6 +86,7 @@ LL | | do_something();
8286
LL | | }
8387
| |_____^
8488
|
89+
= help: if this is not intended, try adding a `break` or `return` to the loop
8590
help: if this is intentional, consider specifying `!` as function return
8691
|
8792
LL | fn no_break_never_ret_noise() -> ! {
@@ -98,6 +103,7 @@ LL | | if cond {
98103
LL | | }
99104
| |_____^
100105
|
106+
= help: if this is not intended, try adding a `break` or `return` to the loop
101107
help: if this is intentional, consider specifying `!` as function return
102108
|
103109
LL | fn break_inner_but_not_outer_1(cond: bool) -> ! {
@@ -114,6 +120,7 @@ LL | | loop {
114120
LL | | }
115121
| |_____^
116122
|
123+
= help: if this is not intended, try adding a `break` or `return` to the loop
117124
help: if this is intentional, consider specifying `!` as function return
118125
|
119126
LL | fn break_inner_but_not_outer_2(cond: bool) -> ! {
@@ -128,10 +135,7 @@ LL | | do_something();
128135
LL | | }
129136
| |_________^
130137
|
131-
help: if this is intentional, consider specifying `!` as function return
132-
|
133-
LL | fn break_outer_but_not_inner() -> ! {
134-
| ++++
138+
= help: if this is not intended, try adding a `break` or `return` to the loop
135139

136140
error: infinite loop detected
137141
--> tests/ui/infinite_loops.rs:143:9
@@ -144,10 +148,7 @@ LL | | loop {
144148
LL | | }
145149
| |_________^
146150
|
147-
help: if this is intentional, consider specifying `!` as function return
148-
|
149-
LL | fn break_wrong_loop(cond: bool) -> ! {
150-
| ++++
151+
= help: if this is not intended, try adding a `break` or `return` to the loop
151152

152153
error: infinite loop detected
153154
--> tests/ui/infinite_loops.rs:183:5
@@ -160,10 +161,7 @@ LL | | Some(v) => {
160161
LL | | }
161162
| |_____^
162163
|
163-
help: if this is intentional, consider specifying `!` as function return
164-
|
165-
LL | fn match_like() -> ! {
166-
| ++++
164+
= help: if this is not intended, try adding a `break` or `return` to the loop
167165

168166
error: infinite loop detected
169167
--> tests/ui/infinite_loops.rs:224:5
@@ -174,10 +172,7 @@ LL | | let _x = matches!(result, Ok(v) if v != 0).then_some(0);
174172
LL | | }
175173
| |_____^
176174
|
177-
help: if this is intentional, consider specifying `!` as function return
178-
|
179-
LL | fn match_like() -> ! {
180-
| ++++
175+
= help: if this is not intended, try adding a `break` or `return` to the loop
181176

182177
error: infinite loop detected
183178
--> tests/ui/infinite_loops.rs:229:5
@@ -191,10 +186,7 @@ LL | | });
191186
LL | | }
192187
| |_____^
193188
|
194-
help: if this is intentional, consider specifying `!` as function return
195-
|
196-
LL | fn match_like() -> ! {
197-
| ++++
189+
= help: if this is not intended, try adding a `break` or `return` to the loop
198190

199191
error: infinite loop detected
200192
--> tests/ui/infinite_loops.rs:334:9
@@ -205,6 +197,7 @@ LL | | do_something();
205197
LL | | }
206198
| |_________^
207199
|
200+
= help: if this is not intended, try adding a `break` or `return` to the loop
208201
help: if this is intentional, consider specifying `!` as function return
209202
|
210203
LL | fn problematic_trait_method() -> ! {
@@ -219,6 +212,7 @@ LL | | do_something();
219212
LL | | }
220213
| |_________^
221214
|
215+
= help: if this is not intended, try adding a `break` or `return` to the loop
222216
help: if this is intentional, consider specifying `!` as function return
223217
|
224218
LL | fn could_be_problematic() -> ! {
@@ -233,6 +227,7 @@ LL | | do_something();
233227
LL | | }
234228
| |_________^
235229
|
230+
= help: if this is not intended, try adding a `break` or `return` to the loop
236231
help: if this is intentional, consider specifying `!` as function return
237232
|
238233
LL | let _loop_forever = || -> ! {
@@ -248,7 +243,7 @@ LL | | do_something()
248243
LL | | })
249244
| |_____^
250245
|
251-
= help: if this is not intended, try adding a `break` or `return` condition in the loop
246+
= help: if this is not intended, try adding a `break` or `return` to the loop
252247

253248
error: infinite loop detected
254249
--> tests/ui/infinite_loops.rs:410:5
@@ -261,6 +256,7 @@ LL | | }
261256
LL | | }
262257
| |_____^
263258
|
259+
= help: if this is not intended, try adding a `break` or `return` to the loop
264260
help: if this is intentional, consider specifying `!` as function return
265261
|
266262
LL | fn continue_outer() -> ! {
@@ -276,6 +272,7 @@ LL | | 'inner: loop {
276272
LL | | }
277273
| |_____^
278274
|
275+
= help: if this is not intended, try adding a `break` or `return` to the loop
279276
help: if this is intentional, consider specifying `!` as function return
280277
|
281278
LL | fn continue_outer() -> ! {
@@ -292,6 +289,7 @@ LL | | }
292289
LL | | }
293290
| |_________^
294291
|
292+
= help: if this is not intended, try adding a `break` or `return` to the loop
295293
help: if this is intentional, consider specifying `!` as function return
296294
|
297295
LL | fn continue_outer() -> ! {
@@ -306,6 +304,7 @@ LL | | continue;
306304
LL | | }
307305
| |_____^
308306
|
307+
= help: if this is not intended, try adding a `break` or `return` to the loop
309308
help: if this is intentional, consider specifying `!` as function return
310309
|
311310
LL | fn continue_outer() -> ! {
@@ -320,7 +319,7 @@ LL | | do_something();
320319
LL | | }
321320
| |_____________^
322321
|
323-
= help: if this is not intended, try adding a `break` or `return` condition in the loop
322+
= help: if this is not intended, try adding a `break` or `return` to the loop
324323

325324
error: infinite loop detected
326325
--> tests/ui/infinite_loops.rs:466:13
@@ -331,7 +330,7 @@ LL | | continue;
331330
LL | | }
332331
| |_____________^
333332
|
334-
= help: if this is not intended, try adding a `break` or `return` condition in the loop
333+
= help: if this is not intended, try adding a `break` or `return` to the loop
335334

336335
error: infinite loop detected
337336
--> tests/ui/infinite_loops.rs:533:9
@@ -341,7 +340,87 @@ LL | | std::future::pending().await
341340
LL | | }
342341
| |_________^
343342
|
344-
= help: if this is not intended, try adding a `break` or `return` condition in the loop
343+
= help: if this is not intended, try adding a `break` or `return` to the loop
344+
345+
error: infinite loop detected
346+
--> tests/ui/infinite_loops.rs:545:32
347+
|
348+
LL | let true = cond else { loop {} };
349+
| ^^^^^^^
350+
|
351+
= help: if this is not intended, try adding a `break` or `return` to the loop
352+
353+
error: infinite loop detected
354+
--> tests/ui/infinite_loops.rs:551:13
355+
|
356+
LL | loop {}
357+
| ^^^^^^^
358+
|
359+
= help: if this is not intended, try adding a `break` or `return` to the loop
360+
361+
error: infinite loop detected
362+
--> tests/ui/infinite_loops.rs:559:21
363+
|
364+
LL | None => loop {},
365+
| ^^^^^^^
366+
|
367+
= help: if this is not intended, try adding a `break` or `return` to the loop
368+
369+
error: infinite loop detected
370+
--> tests/ui/infinite_loops.rs:568:13
371+
|
372+
LL | loop {}
373+
| ^^^^^^^
374+
|
375+
= help: if this is not intended, try adding a `break` or `return` to the loop
376+
377+
error: infinite loop detected
378+
--> tests/ui/infinite_loops.rs:576:13
379+
|
380+
LL | loop {}
381+
| ^^^^^^^
382+
|
383+
= help: if this is not intended, try adding a `break` or `return` to the loop
384+
help: if this is intentional, consider specifying `!` as function return
385+
|
386+
LL | fn all_branches_diverge_if(cond: bool) -> ! {
387+
| ++++
388+
389+
error: infinite loop detected
390+
--> tests/ui/infinite_loops.rs:579:13
391+
|
392+
LL | loop {}
393+
| ^^^^^^^
394+
|
395+
= help: if this is not intended, try adding a `break` or `return` to the loop
396+
help: if this is intentional, consider specifying `!` as function return
397+
|
398+
LL | fn all_branches_diverge_if(cond: bool) -> ! {
399+
| ++++
400+
401+
error: infinite loop detected
402+
--> tests/ui/infinite_loops.rs:586:24
403+
|
404+
LL | Some(_) => loop {},
405+
| ^^^^^^^
406+
|
407+
= help: if this is not intended, try adding a `break` or `return` to the loop
408+
help: if this is intentional, consider specifying `!` as function return
409+
|
410+
LL | fn all_branches_diverge_match(x: Option<i32>) -> ! {
411+
| ++++
412+
413+
error: infinite loop detected
414+
--> tests/ui/infinite_loops.rs:587:21
415+
|
416+
LL | None => loop {},
417+
| ^^^^^^^
418+
|
419+
= help: if this is not intended, try adding a `break` or `return` to the loop
420+
help: if this is intentional, consider specifying `!` as function return
421+
|
422+
LL | fn all_branches_diverge_match(x: Option<i32>) -> ! {
423+
| ++++
345424

346-
error: aborting due to 24 previous errors
425+
error: aborting due to 32 previous errors
347426

0 commit comments

Comments
 (0)