A return in an iterator closure should not trigger never_loop

The iterator never loops when the closure used in, e.g., `.any()`,
panics, not when it diverges as a regular `return` lets the iterator
continue.
This commit is contained in:
Samuel Tardieu
2026-01-08 19:33:24 +01:00
parent 3b282feee6
commit 68365697b3
3 changed files with 11 additions and 4 deletions
+2 -2
View File
@@ -4,8 +4,8 @@
use clippy_utils::higher::ForLoop;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::source::{snippet, snippet_with_context};
use clippy_utils::sym;
use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
use clippy_utils::{contains_return, sym};
use rustc_errors::Applicability;
use rustc_hir::{
Block, Closure, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind,
@@ -82,7 +82,7 @@ pub(super) fn check_iterator_reduction<'tcx>(
) {
let closure_body = cx.tcx.hir_body(closure.body).value;
let body_ty = cx.typeck_results().expr_ty(closure_body);
if body_ty.is_never() {
if body_ty.is_never() && !contains_return(closure_body) {
span_lint_and_then(
cx,
NEVER_LOOP,
+8 -1
View File
@@ -1,8 +1,9 @@
//@no-rustfix
#![warn(clippy::never_loop)]
#![expect(clippy::needless_return)]
fn main() {
// diverging closure: should trigger
// diverging closure with no `return`: should trigger
[0, 1].into_iter().for_each(|x| {
//~^ never_loop
@@ -14,4 +15,10 @@ fn main() {
[0, 1].into_iter().for_each(|x| {
let _ = x + 1;
});
// `return` should NOT trigger even though it is diverging
[0, 1].into_iter().for_each(|x| {
println!("x = {x}");
return;
});
}
@@ -1,5 +1,5 @@
error: this iterator reduction never loops (closure always diverges)
--> tests/ui/never_loop_iterator_reduction.rs:6:5
--> tests/ui/never_loop_iterator_reduction.rs:7:5
|
LL | / [0, 1].into_iter().for_each(|x| {
LL | |