about summary refs log tree commit diff
diff options
context:
space:
mode:
authordswij <dharmasw@outlook.com>2025-08-23 12:24:47 +0000
committerGitHub <noreply@github.com>2025-08-23 12:24:47 +0000
commit36ef39522785dbc069c7e3b58c9142fc2b234bc6 (patch)
tree2bbc68b3d445328aefba0583107f99593c49c315
parent7d43319e0cf244bd560cac238e0ce428d90dab94 (diff)
parent8a988658a7caba4d7caf6926ba3b78e5f52d54f6 (diff)
downloadrust-36ef39522785dbc069c7e3b58c9142fc2b234bc6.tar.gz
rust-36ef39522785dbc069c7e3b58c9142fc2b234bc6.zip
Detect infinite loop in `async fn` not returning `!` (#15545)
This fixes an overzealous change made to avoid signaling infinite loops
in anonymous blocks that may never be used.

Fixes rust-lang/rust-clippy#15541

r? @dswij

changelog: none
-rw-r--r--clippy_lints/src/loops/infinite_loop.rs9
-rw-r--r--tests/ui/infinite_loops.rs15
-rw-r--r--tests/ui/infinite_loops.stderr12
3 files changed, 33 insertions, 3 deletions
diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs
index a71e6963f8c..74c0b178018 100644
--- a/clippy_lints/src/loops/infinite_loop.rs
+++ b/clippy_lints/src/loops/infinite_loop.rs
@@ -4,7 +4,8 @@ use hir::intravisit::{Visitor, walk_expr};
 use rustc_ast::Label;
 use rustc_errors::Applicability;
 use rustc_hir::{
-    self as hir, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Expr, ExprKind, FnRetTy, FnSig, Node, TyKind,
+    self as hir, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnRetTy,
+    FnSig, Node, TyKind,
 };
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::sym;
@@ -73,7 +74,11 @@ fn is_inside_unawaited_async_block(cx: &LateContext<'_>, expr: &Expr<'_>) -> boo
         if let Node::Expr(Expr {
             kind:
                 ExprKind::Closure(Closure {
-                    kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)),
+                    kind:
+                        ClosureKind::Coroutine(CoroutineKind::Desugared(
+                            CoroutineDesugaring::Async,
+                            CoroutineSource::Block | CoroutineSource::Closure,
+                        )),
                     ..
                 }),
             ..
diff --git a/tests/ui/infinite_loops.rs b/tests/ui/infinite_loops.rs
index 9b8c3933197..7d01a7fb61f 100644
--- a/tests/ui/infinite_loops.rs
+++ b/tests/ui/infinite_loops.rs
@@ -521,4 +521,19 @@ mod tokio_spawn_test {
     }
 }
 
+mod issue15541 {
+    async fn good() -> ! {
+        loop {
+            std::future::pending().await
+        }
+    }
+
+    async fn bad() {
+        //~v infinite_loop
+        loop {
+            std::future::pending().await
+        }
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/infinite_loops.stderr b/tests/ui/infinite_loops.stderr
index 4c6b6f725f1..319f1e5012b 100644
--- a/tests/ui/infinite_loops.stderr
+++ b/tests/ui/infinite_loops.stderr
@@ -333,5 +333,15 @@ LL | |             }
    |
    = help: if this is not intended, try adding a `break` or `return` condition in the loop
 
-error: aborting due to 23 previous errors
+error: infinite loop detected
+  --> tests/ui/infinite_loops.rs:533:9
+   |
+LL | /         loop {
+LL | |             std::future::pending().await
+LL | |         }
+   | |_________^
+   |
+   = help: if this is not intended, try adding a `break` or `return` condition in the loop
+
+error: aborting due to 24 previous errors