about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2025-04-28 15:41:40 +0000
committerGitHub <noreply@github.com>2025-04-28 15:41:40 +0000
commit549107dbada33d5531d8d896791d8dc07852d8af (patch)
treefce357e1a0d2dc9fb6eb1c20731ea7a6ee7c61f9
parent542762e8afd10aad8140cdf7d183184927fa5c6a (diff)
parent5123ad590461b236a90426556ddb2f6fd95311af (diff)
downloadrust-549107dbada33d5531d8d896791d8dc07852d8af.tar.gz
rust-549107dbada33d5531d8d896791d8dc07852d8af.zip
Fix `zombie_processes` FP inside closures (#14696)
Closes rust-lang/rust-clippy#14677

changelog: [`zombie_processes`] fix FP inside closures
-rw-r--r--clippy_lints/src/zombie_processes.rs5
-rw-r--r--tests/ui/zombie_processes.rs22
2 files changed, 26 insertions, 1 deletions
diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs
index 39c1aab8967..09f1084fe70 100644
--- a/clippy_lints/src/zombie_processes.rs
+++ b/clippy_lints/src/zombie_processes.rs
@@ -4,6 +4,7 @@ use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id};
 use rustc_ast::Mutability;
 use rustc_ast::visit::visit_opt;
 use rustc_errors::Applicability;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local};
 use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -68,6 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses {
                     let mut vis = WaitFinder {
                         cx,
                         local_id,
+                        body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id),
                         state: VisitorState::WalkUpToLocal,
                         early_return: None,
                         missing_wait_branch: None,
@@ -129,6 +131,7 @@ struct MaybeWait(Span);
 struct WaitFinder<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     local_id: HirId,
+    body_id: LocalDefId,
     state: VisitorState,
     early_return: Option<Span>,
     // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targeted help
@@ -186,7 +189,7 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
             }
         } else {
             match ex.kind {
-                ExprKind::Ret(e) => {
+                ExprKind::Ret(e) if self.cx.tcx.hir_enclosing_body_owner(ex.hir_id) == self.body_id => {
                     visit_opt!(self, visit_expr, e);
                     if self.early_return.is_none() {
                         self.early_return = Some(ex.span);
diff --git a/tests/ui/zombie_processes.rs b/tests/ui/zombie_processes.rs
index 25bbc02ffb7..395f9dd2def 100644
--- a/tests/ui/zombie_processes.rs
+++ b/tests/ui/zombie_processes.rs
@@ -176,3 +176,25 @@ fn return_wait() -> ExitStatus {
     let mut x = Command::new("").spawn().unwrap();
     return x.wait().unwrap();
 }
+
+mod issue14677 {
+    use std::io;
+    use std::process::Command;
+
+    fn do_something<F: Fn() -> Result<(), ()>>(f: F) {
+        todo!()
+    }
+
+    fn foo() {
+        let mut child = Command::new("true").spawn().unwrap();
+        let some_condition = true;
+        do_something(|| {
+            if some_condition {
+                return Err(());
+            }
+            Ok(())
+        });
+        child.kill().unwrap();
+        child.wait().unwrap();
+    }
+}