about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-10-10 13:43:40 +0530
committerGitHub <noreply@github.com>2022-10-10 13:43:40 +0530
commit7e16f9f1eaea28e7fe2fc93319fdfcd4e1968c91 (patch)
treeb96433616143a8f0a449cec841fc9be07de08d4b
parente495b37c9a301d776a7bd0c72d5c4a202e159032 (diff)
parent9d4edff1b0179e3514bcc27618edd6348903e99a (diff)
downloadrust-7e16f9f1eaea28e7fe2fc93319fdfcd4e1968c91.tar.gz
rust-7e16f9f1eaea28e7fe2fc93319fdfcd4e1968c91.zip
Rollup merge of #99696 - WaffleLapkin:uplift, r=fee1-dead
Uplift `clippy::for_loops_over_fallibles` lint into rustc

This PR, as the title suggests, uplifts [`clippy::for_loops_over_fallibles`] lint into rustc. This lint warns for code like this:
```rust
for _ in Some(1) {}
for _ in Ok::<_, ()>(1) {}
```
i.e. directly iterating over `Option` and `Result` using `for` loop.

There are a number of suggestions that this PR adds (on top of what clippy suggested):
1. If the argument (? is there a better name for that expression) of a `for` loop is a `.next()` call, then we can suggest removing it (or rather replacing with `.by_ref()` to allow iterator being used later)
   ```rust
    for _ in iter.next() {}
    // turns into
    for _ in iter.by_ref() {}
    ```
2. (otherwise) We can suggest using `while let`, this is useful for non-iterator, iterator-like things like [async] channels
   ```rust
   for _ in rx.recv() {}
   // turns into
   while let Some(_) = rx.recv() {}
   ```
3. If the argument type is `Result<impl IntoIterator, _>` and the body has a `Result<_, _>` type, we can suggest using `?`
   ```rust
   for _ in f() {}
   // turns into
   for _ in f()? {}
   ```
4. To preserve the original behavior and clear intent, we can suggest using `if let`
   ```rust
   for _ in f() {}
   // turns into
   if let Some(_) = f() {}
   ```
(P.S. `Some` and `Ok` are interchangeable depending on the type)

I still feel that the lint wording/look is somewhat off, so I'll be happy to hear suggestions (on how to improve suggestions :D)!

Resolves #99272

[`clippy::for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
-rw-r--r--compiler/rustc_ast/src/visit.rs14
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs183
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--library/core/tests/option.rs1
-rw-r--r--src/test/ui/drop/dropck_legal_cycles.rs14
-rw-r--r--src/test/ui/issues/issue-30371.rs1
-rw-r--r--src/test/ui/lint/for_loop_over_fallibles.rs43
-rw-r--r--src/test/ui/lint/for_loop_over_fallibles.stderr101
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs5
-rw-r--r--src/tools/clippy/src/docs.rs1
-rw-r--r--src/tools/clippy/src/docs/for_loops_over_fallibles.txt32
-rw-r--r--src/tools/clippy/tests/ui/for_loop_unfixable.rs1
-rw-r--r--src/tools/clippy/tests/ui/for_loop_unfixable.stderr2
-rw-r--r--src/tools/clippy/tests/ui/for_loops_over_fallibles.rs73
-rw-r--r--src/tools/clippy/tests/ui/for_loops_over_fallibles.stderr95
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed7
-rw-r--r--src/tools/clippy/tests/ui/rename.rs3
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr34
26 files changed, 381 insertions, 366 deletions
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index a71e055a4b3..145b31842ef 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -244,14 +244,12 @@ pub trait Visitor<'ast>: Sized {
 
 #[macro_export]
 macro_rules! walk_list {
-    ($visitor: expr, $method: ident, $list: expr) => {
-        for elem in $list {
-            $visitor.$method(elem)
-        }
-    };
-    ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
-        for elem in $list {
-            $visitor.$method(elem, $($extra_args,)*)
+    ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => {
+        {
+            #[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))]
+            for elem in $list {
+                $visitor.$method(elem $(, $($extra_args,)* )?)
+            }
         }
     }
 }
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
new file mode 100644
index 00000000000..ed8d424e0c6
--- /dev/null
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -0,0 +1,183 @@
+use crate::{LateContext, LateLintPass, LintContext};
+
+use hir::{Expr, Pat};
+use rustc_errors::{Applicability, DelayDm};
+use rustc_hir as hir;
+use rustc_infer::traits::TraitEngine;
+use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
+use rustc_middle::ty::{self, List};
+use rustc_span::{sym, Span};
+use rustc_trait_selection::traits::TraitEngineExt;
+
+declare_lint! {
+    /// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let opt = Some(1);
+    /// for x in opt { /* ... */}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Both `Option` and `Result` implement `IntoIterator` trait, which allows using them in a `for` loop.
+    /// `for` loop over `Option` or `Result` will iterate either 0 (if the value is `None`/`Err(_)`)
+    /// or 1 time (if the value is `Some(_)`/`Ok(_)`). This is not very useful and is more clearly expressed
+    /// via `if let`.
+    ///
+    /// `for` loop can also be accidentally written with the intention to call a function multiple times,
+    /// while the function returns `Some(_)`, in these cases `while let` loop should be used instead.
+    ///
+    /// The "intended" use of `IntoIterator` implementations for `Option` and `Result` is passing them to
+    /// generic code that expects something implementing `IntoIterator`. For example using `.chain(option)`
+    /// to optionally add a value to an iterator.
+    pub FOR_LOOPS_OVER_FALLIBLES,
+    Warn,
+    "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
+}
+
+declare_lint_pass!(ForLoopsOverFallibles => [FOR_LOOPS_OVER_FALLIBLES]);
+
+impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        let Some((pat, arg)) = extract_for_loop(expr) else { return };
+
+        let ty = cx.typeck_results().expr_ty(arg);
+
+        let &ty::Adt(adt, substs) = ty.kind() else { return };
+
+        let (article, ty, var) = match adt.did() {
+            did if cx.tcx.is_diagnostic_item(sym::Option, did) => ("an", "Option", "Some"),
+            did if cx.tcx.is_diagnostic_item(sym::Result, did) => ("a", "Result", "Ok"),
+            _ => return,
+        };
+
+        let msg = DelayDm(|| {
+            format!(
+                "for loop over {article} `{ty}`. This is more readably written as an `if let` statement",
+            )
+        });
+
+        cx.struct_span_lint(FOR_LOOPS_OVER_FALLIBLES, arg.span, msg, |lint| {
+            if let Some(recv) = extract_iterator_next_call(cx, arg)
+            && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
+            {
+                lint.span_suggestion(
+                    recv.span.between(arg.span.shrink_to_hi()),
+                    format!("to iterate over `{recv_snip}` remove the call to `next`"),
+                    ".by_ref()",
+                    Applicability::MaybeIncorrect
+                );
+            } else {
+                lint.multipart_suggestion_verbose(
+                    format!("to check pattern in a loop use `while let`"),
+                    vec![
+                        // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
+                        (expr.span.with_hi(pat.span.lo()), format!("while let {var}(")),
+                        (pat.span.between(arg.span), format!(") = ")),
+                    ],
+                    Applicability::MaybeIncorrect
+                );
+            }
+
+            if suggest_question_mark(cx, adt, substs, expr.span) {
+                lint.span_suggestion(
+                    arg.span.shrink_to_hi(),
+                    "consider unwrapping the `Result` with `?` to iterate over its contents",
+                    "?",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+
+            lint.multipart_suggestion_verbose(
+                "consider using `if let` to clear intent",
+                vec![
+                    // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
+                    (expr.span.with_hi(pat.span.lo()), format!("if let {var}(")),
+                    (pat.span.between(arg.span), format!(") = ")),
+                ],
+                Applicability::MaybeIncorrect,
+            )
+        })
+    }
+}
+
+fn extract_for_loop<'tcx>(expr: &Expr<'tcx>) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>)> {
+    if let hir::ExprKind::DropTemps(e) = expr.kind
+    && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind
+    && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind
+    && let hir::ExprKind::Loop(block, ..) = arm.body.kind
+    && let [stmt] = block.stmts
+    && let hir::StmtKind::Expr(e) = stmt.kind
+    && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind
+    && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind
+    {
+        Some((field.pat, arg))
+    } else {
+        None
+    }
+}
+
+fn extract_iterator_next_call<'tcx>(
+    cx: &LateContext<'_>,
+    expr: &Expr<'tcx>,
+) -> Option<&'tcx Expr<'tcx>> {
+    // This won't work for `Iterator::next(iter)`, is this an issue?
+    if let hir::ExprKind::MethodCall(_, recv, _, _) = expr.kind
+    && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn()
+    {
+        Some(recv)
+    } else {
+        return None
+    }
+}
+
+fn suggest_question_mark<'tcx>(
+    cx: &LateContext<'tcx>,
+    adt: ty::AdtDef<'tcx>,
+    substs: &List<ty::GenericArg<'tcx>>,
+    span: Span,
+) -> bool {
+    let Some(body_id) = cx.enclosing_body else { return false };
+    let Some(into_iterator_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else { return false };
+
+    if !cx.tcx.is_diagnostic_item(sym::Result, adt.did()) {
+        return false;
+    }
+
+    // Check that the function/closure/constant we are in has a `Result` type.
+    // Otherwise suggesting using `?` may not be a good idea.
+    {
+        let ty = cx.typeck_results().expr_ty(&cx.tcx.hir().body(body_id).value);
+        let ty::Adt(ret_adt, ..) = ty.kind() else { return false };
+        if !cx.tcx.is_diagnostic_item(sym::Result, ret_adt.did()) {
+            return false;
+        }
+    }
+
+    let ty = substs.type_at(0);
+    let infcx = cx.tcx.infer_ctxt().build();
+    let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+
+    let cause = ObligationCause::new(
+        span,
+        body_id.hir_id,
+        rustc_infer::traits::ObligationCauseCode::MiscObligation,
+    );
+    fulfill_cx.register_bound(
+        &infcx,
+        ty::ParamEnv::empty(),
+        // Erase any region vids from the type, which may not be resolved
+        infcx.tcx.erase_regions(ty),
+        into_iterator_did,
+        cause,
+    );
+
+    // Select all, including ambiguous predicates
+    let errors = fulfill_cx.select_all_or_error(&infcx);
+
+    errors.is_empty()
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 070cccd141b..fee6e080c4f 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -52,6 +52,7 @@ mod early;
 mod enum_intrinsics_non_enums;
 mod errors;
 mod expect;
+mod for_loops_over_fallibles;
 pub mod hidden_unicode_codepoints;
 mod internal;
 mod late;
@@ -86,6 +87,7 @@ use rustc_span::Span;
 use array_into_iter::ArrayIntoIter;
 use builtin::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
+use for_loops_over_fallibles::*;
 use hidden_unicode_codepoints::*;
 use internal::*;
 use let_underscore::*;
@@ -188,6 +190,7 @@ macro_rules! late_lint_mod_passes {
         $macro!(
             $args,
             [
+                ForLoopsOverFallibles: ForLoopsOverFallibles,
                 HardwiredLints: HardwiredLints,
                 ImproperCTypesDeclarations: ImproperCTypesDeclarations,
                 ImproperCTypesDefinitions: ImproperCTypesDefinitions,
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index 9f5e537dcef..f36f7c26806 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -57,6 +57,7 @@ fn test_get_resource() {
 }
 
 #[test]
+#[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))]
 fn test_option_dance() {
     let x = Some(());
     let mut y = Some(5);
diff --git a/src/test/ui/drop/dropck_legal_cycles.rs b/src/test/ui/drop/dropck_legal_cycles.rs
index 27a599315dc..6a0fe7784fb 100644
--- a/src/test/ui/drop/dropck_legal_cycles.rs
+++ b/src/test/ui/drop/dropck_legal_cycles.rs
@@ -1017,7 +1017,7 @@ impl<'a> Children<'a> for HM<'a> {
         where C: Context + PrePost<Self>, Self: Sized
     {
         if let Some(ref hm) = self.contents.get() {
-            for (k, v) in hm.iter().nth(index / 2) {
+            if let Some((k, v)) = hm.iter().nth(index / 2) {
                 [k, v][index % 2].descend_into_self(context);
             }
         }
@@ -1032,7 +1032,7 @@ impl<'a> Children<'a> for VD<'a> {
         where C: Context + PrePost<Self>, Self: Sized
     {
         if let Some(ref vd) = self.contents.get() {
-            for r in vd.iter().nth(index) {
+            if let Some(r) = vd.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
@@ -1047,7 +1047,7 @@ impl<'a> Children<'a> for VM<'a> {
         where C: Context + PrePost<VM<'a>>
     {
         if let Some(ref vd) = self.contents.get() {
-            for (_idx, r) in vd.iter().nth(index) {
+            if let Some((_idx, r)) = vd.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
@@ -1062,7 +1062,7 @@ impl<'a> Children<'a> for LL<'a> {
         where C: Context + PrePost<LL<'a>>
     {
         if let Some(ref ll) = self.contents.get() {
-            for r in ll.iter().nth(index) {
+            if let Some(r) = ll.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
@@ -1077,7 +1077,7 @@ impl<'a> Children<'a> for BH<'a> {
         where C: Context + PrePost<BH<'a>>
     {
         if let Some(ref bh) = self.contents.get() {
-            for r in bh.iter().nth(index) {
+            if let Some(r) = bh.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
@@ -1092,7 +1092,7 @@ impl<'a> Children<'a> for BTM<'a> {
         where C: Context + PrePost<BTM<'a>>
     {
         if let Some(ref bh) = self.contents.get() {
-            for (k, v) in bh.iter().nth(index / 2) {
+            if let Some((k, v)) = bh.iter().nth(index / 2) {
                 [k, v][index % 2].descend_into_self(context);
             }
         }
@@ -1107,7 +1107,7 @@ impl<'a> Children<'a> for BTS<'a> {
         where C: Context + PrePost<BTS<'a>>
     {
         if let Some(ref bh) = self.contents.get() {
-            for r in bh.iter().nth(index) {
+            if let Some(r) = bh.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
diff --git a/src/test/ui/issues/issue-30371.rs b/src/test/ui/issues/issue-30371.rs
index a1ae9a36bc1..eea548c482f 100644
--- a/src/test/ui/issues/issue-30371.rs
+++ b/src/test/ui/issues/issue-30371.rs
@@ -1,5 +1,6 @@
 // run-pass
 #![allow(unreachable_code)]
+#![allow(for_loops_over_fallibles)]
 #![deny(unused_variables)]
 
 fn main() {
diff --git a/src/test/ui/lint/for_loop_over_fallibles.rs b/src/test/ui/lint/for_loop_over_fallibles.rs
new file mode 100644
index 00000000000..43d71c2e808
--- /dev/null
+++ b/src/test/ui/lint/for_loop_over_fallibles.rs
@@ -0,0 +1,43 @@
+// check-pass
+
+fn main() {
+    // Common
+    for _ in Some(1) {}
+    //~^ WARN for loop over an `Option`. This is more readably written as an `if let` statement
+    //~| HELP to check pattern in a loop use `while let`
+    //~| HELP consider using `if let` to clear intent
+    for _ in Ok::<_, ()>(1) {}
+    //~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
+    //~| HELP to check pattern in a loop use `while let`
+    //~| HELP consider using `if let` to clear intent
+
+    // `Iterator::next` specific
+    for _ in [0; 0].iter().next() {}
+    //~^ WARN for loop over an `Option`. This is more readably written as an `if let` statement
+    //~| HELP to iterate over `[0; 0].iter()` remove the call to `next`
+    //~| HELP consider using `if let` to clear intent
+
+    // `Result<impl Iterator, _>`, but function doesn't return `Result`
+    for _ in Ok::<_, ()>([0; 0].iter()) {}
+    //~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
+    //~| HELP to check pattern in a loop use `while let`
+    //~| HELP consider using `if let` to clear intent
+}
+
+fn _returns_result() -> Result<(), ()> {
+    // `Result<impl Iterator, _>`
+    for _ in Ok::<_, ()>([0; 0].iter()) {}
+    //~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
+    //~| HELP to check pattern in a loop use `while let`
+    //~| HELP consider unwrapping the `Result` with `?` to iterate over its contents
+    //~| HELP consider using `if let` to clear intent
+
+    // `Result<impl IntoIterator>`
+    for _ in Ok::<_, ()>([0; 0]) {}
+    //~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
+    //~| HELP to check pattern in a loop use `while let`
+    //~| HELP consider unwrapping the `Result` with `?` to iterate over its contents
+    //~| HELP consider using `if let` to clear intent
+
+    Ok(())
+}
diff --git a/src/test/ui/lint/for_loop_over_fallibles.stderr b/src/test/ui/lint/for_loop_over_fallibles.stderr
new file mode 100644
index 00000000000..96efdf85c49
--- /dev/null
+++ b/src/test/ui/lint/for_loop_over_fallibles.stderr
@@ -0,0 +1,101 @@
+warning: for loop over an `Option`. This is more readably written as an `if let` statement
+  --> $DIR/for_loop_over_fallibles.rs:5:14
+   |
+LL |     for _ in Some(1) {}
+   |              ^^^^^^^
+   |
+   = note: `#[warn(for_loops_over_fallibles)]` on by default
+help: to check pattern in a loop use `while let`
+   |
+LL |     while let Some(_) = Some(1) {}
+   |     ~~~~~~~~~~~~~~~ ~~~
+help: consider using `if let` to clear intent
+   |
+LL |     if let Some(_) = Some(1) {}
+   |     ~~~~~~~~~~~~ ~~~
+
+warning: for loop over a `Result`. This is more readably written as an `if let` statement
+  --> $DIR/for_loop_over_fallibles.rs:9:14
+   |
+LL |     for _ in Ok::<_, ()>(1) {}
+   |              ^^^^^^^^^^^^^^
+   |
+help: to check pattern in a loop use `while let`
+   |
+LL |     while let Ok(_) = Ok::<_, ()>(1) {}
+   |     ~~~~~~~~~~~~~ ~~~
+help: consider using `if let` to clear intent
+   |
+LL |     if let Ok(_) = Ok::<_, ()>(1) {}
+   |     ~~~~~~~~~~ ~~~
+
+warning: for loop over an `Option`. This is more readably written as an `if let` statement
+  --> $DIR/for_loop_over_fallibles.rs:15:14
+   |
+LL |     for _ in [0; 0].iter().next() {}
+   |              ^^^^^^^^^^^^^^^^^^^^
+   |
+help: to iterate over `[0; 0].iter()` remove the call to `next`
+   |
+LL |     for _ in [0; 0].iter().by_ref() {}
+   |                           ~~~~~~~~~
+help: consider using `if let` to clear intent
+   |
+LL |     if let Some(_) = [0; 0].iter().next() {}
+   |     ~~~~~~~~~~~~ ~~~
+
+warning: for loop over a `Result`. This is more readably written as an `if let` statement
+  --> $DIR/for_loop_over_fallibles.rs:21:14
+   |
+LL |     for _ in Ok::<_, ()>([0; 0].iter()) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: to check pattern in a loop use `while let`
+   |
+LL |     while let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
+   |     ~~~~~~~~~~~~~ ~~~
+help: consider using `if let` to clear intent
+   |
+LL |     if let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
+   |     ~~~~~~~~~~ ~~~
+
+warning: for loop over a `Result`. This is more readably written as an `if let` statement
+  --> $DIR/for_loop_over_fallibles.rs:29:14
+   |
+LL |     for _ in Ok::<_, ()>([0; 0].iter()) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: to check pattern in a loop use `while let`
+   |
+LL |     while let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
+   |     ~~~~~~~~~~~~~ ~~~
+help: consider unwrapping the `Result` with `?` to iterate over its contents
+   |
+LL |     for _ in Ok::<_, ()>([0; 0].iter())? {}
+   |                                        +
+help: consider using `if let` to clear intent
+   |
+LL |     if let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
+   |     ~~~~~~~~~~ ~~~
+
+warning: for loop over a `Result`. This is more readably written as an `if let` statement
+  --> $DIR/for_loop_over_fallibles.rs:36:14
+   |
+LL |     for _ in Ok::<_, ()>([0; 0]) {}
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+help: to check pattern in a loop use `while let`
+   |
+LL |     while let Ok(_) = Ok::<_, ()>([0; 0]) {}
+   |     ~~~~~~~~~~~~~ ~~~
+help: consider unwrapping the `Result` with `?` to iterate over its contents
+   |
+LL |     for _ in Ok::<_, ()>([0; 0])? {}
+   |                                 +
+help: consider using `if let` to clear intent
+   |
+LL |     if let Ok(_) = Ok::<_, ()>([0; 0]) {}
+   |     ~~~~~~~~~~ ~~~
+
+warning: 6 warnings emitted
+
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index 5d26e4b3360..fe1f0b56646 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -109,7 +109,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(loops::EMPTY_LOOP),
     LintId::of(loops::EXPLICIT_COUNTER_LOOP),
     LintId::of(loops::FOR_KV_MAP),
-    LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
     LintId::of(loops::ITER_NEXT_LOOP),
     LintId::of(loops::MANUAL_FIND),
     LintId::of(loops::MANUAL_FLATTEN),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
index 05d927dbea7..306cb6a61c9 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
@@ -227,7 +227,6 @@ store.register_lints(&[
     loops::EXPLICIT_INTO_ITER_LOOP,
     loops::EXPLICIT_ITER_LOOP,
     loops::FOR_KV_MAP,
-    loops::FOR_LOOPS_OVER_FALLIBLES,
     loops::ITER_NEXT_LOOP,
     loops::MANUAL_FIND,
     loops::MANUAL_FLATTEN,
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
index 6125d0f7a86..d6d95c95c85 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
@@ -21,7 +21,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
     LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
     LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
     LintId::of(loops::EMPTY_LOOP),
-    LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
     LintId::of(loops::MUT_RANGE_BOUND),
     LintId::of(methods::NO_EFFECT_REPLACE),
     LintId::of(methods::SUSPICIOUS_MAP),
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs b/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs
deleted file mode 100644
index 77de90fd7b9..00000000000
--- a/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-use super::FOR_LOOPS_OVER_FALLIBLES;
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use rustc_hir::{Expr, Pat};
-use rustc_lint::LateContext;
-use rustc_span::symbol::sym;
-
-/// Checks for `for` loops over `Option`s and `Result`s.
-pub(super) fn check(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, method_name: Option<&str>) {
-    let ty = cx.typeck_results().expr_ty(arg);
-    if is_type_diagnostic_item(cx, ty, sym::Option) {
-        let help_string = if let Some(method_name) = method_name {
-            format!(
-                "consider replacing `for {0} in {1}.{method_name}()` with `if let Some({0}) = {1}`",
-                snippet(cx, pat.span, "_"),
-                snippet(cx, arg.span, "_")
-            )
-        } else {
-            format!(
-                "consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`",
-                snippet(cx, pat.span, "_"),
-                snippet(cx, arg.span, "_")
-            )
-        };
-        span_lint_and_help(
-            cx,
-            FOR_LOOPS_OVER_FALLIBLES,
-            arg.span,
-            &format!(
-                "for loop over `{0}`, which is an `Option`. This is more readably written as an \
-                `if let` statement",
-                snippet(cx, arg.span, "_")
-            ),
-            None,
-            &help_string,
-        );
-    } else if is_type_diagnostic_item(cx, ty, sym::Result) {
-        let help_string = if let Some(method_name) = method_name {
-            format!(
-                "consider replacing `for {0} in {1}.{method_name}()` with `if let Ok({0}) = {1}`",
-                snippet(cx, pat.span, "_"),
-                snippet(cx, arg.span, "_")
-            )
-        } else {
-            format!(
-                "consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`",
-                snippet(cx, pat.span, "_"),
-                snippet(cx, arg.span, "_")
-            )
-        };
-        span_lint_and_help(
-            cx,
-            FOR_LOOPS_OVER_FALLIBLES,
-            arg.span,
-            &format!(
-                "for loop over `{0}`, which is a `Result`. This is more readably written as an \
-                `if let` statement",
-                snippet(cx, arg.span, "_")
-            ),
-            None,
-            &help_string,
-        );
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs b/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs
index e640c62ebda..b8a263817d2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs
@@ -5,7 +5,7 @@ use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
-pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
+pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) {
     if is_trait_method(cx, arg, sym::Iterator) {
         span_lint(
             cx,
@@ -14,8 +14,5 @@ pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
             "you are iterating over `Iterator::next()` which is an Option; this will compile but is \
             probably not what you want",
         );
-        true
-    } else {
-        false
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index c0a0444485e..bcf278d9c83 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -3,7 +3,6 @@ mod explicit_counter_loop;
 mod explicit_into_iter_loop;
 mod explicit_iter_loop;
 mod for_kv_map;
-mod for_loops_over_fallibles;
 mod iter_next_loop;
 mod manual_find;
 mod manual_flatten;
@@ -175,49 +174,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `for` loops over `Option` or `Result` values.
-    ///
-    /// ### Why is this bad?
-    /// Readability. This is more clearly expressed as an `if
-    /// let`.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # let opt = Some(1);
-    /// # let res: Result<i32, std::io::Error> = Ok(1);
-    /// for x in opt {
-    ///     // ..
-    /// }
-    ///
-    /// for x in &res {
-    ///     // ..
-    /// }
-    ///
-    /// for x in res.iter() {
-    ///     // ..
-    /// }
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// # let opt = Some(1);
-    /// # let res: Result<i32, std::io::Error> = Ok(1);
-    /// if let Some(x) = opt {
-    ///     // ..
-    /// }
-    ///
-    /// if let Ok(x) = res {
-    ///     // ..
-    /// }
-    /// ```
-    #[clippy::version = "1.45.0"]
-    pub FOR_LOOPS_OVER_FALLIBLES,
-    suspicious,
-    "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Detects `loop + match` combinations that are easier
     /// written as a `while let` loop.
     ///
@@ -648,7 +604,6 @@ declare_lint_pass!(Loops => [
     EXPLICIT_ITER_LOOP,
     EXPLICIT_INTO_ITER_LOOP,
     ITER_NEXT_LOOP,
-    FOR_LOOPS_OVER_FALLIBLES,
     WHILE_LET_LOOP,
     NEEDLESS_COLLECT,
     EXPLICIT_COUNTER_LOOP,
@@ -739,30 +694,22 @@ fn check_for_loop<'tcx>(
     manual_find::check(cx, pat, arg, body, span, expr);
 }
 
-fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
-    let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
-
+fn check_for_loop_arg(cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
     if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
         let method_name = method.ident.as_str();
         // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
         match method_name {
             "iter" | "iter_mut" => {
                 explicit_iter_loop::check(cx, self_arg, arg, method_name);
-                for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
             },
             "into_iter" => {
                 explicit_iter_loop::check(cx, self_arg, arg, method_name);
                 explicit_into_iter_loop::check(cx, self_arg, arg);
-                for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
             },
             "next" => {
-                next_loop_linted = iter_next_loop::check(cx, arg);
+                iter_next_loop::check(cx, arg);
             },
             _ => {},
         }
     }
-
-    if !next_loop_linted {
-        for_loops_over_fallibles::check(cx, pat, arg, None);
-    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index d320eea1c37..76d6ad0b23e 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -11,8 +11,8 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::disallowed_method", "clippy::disallowed_methods"),
     ("clippy::disallowed_type", "clippy::disallowed_types"),
     ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
-    ("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles"),
-    ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
+    ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
+    ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
     ("clippy::identity_conversion", "clippy::useless_conversion"),
     ("clippy::if_let_some_result", "clippy::match_result_ok"),
     ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
@@ -31,6 +31,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
     ("clippy::zero_width_space", "clippy::invisible_characters"),
     ("clippy::drop_bounds", "drop_bounds"),
+    ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
     ("clippy::into_iter_on_array", "array_into_iter"),
     ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
     ("clippy::invalid_ref", "invalid_value"),
diff --git a/src/tools/clippy/src/docs.rs b/src/tools/clippy/src/docs.rs
index 3bf488ab477..bd27bc7938f 100644
--- a/src/tools/clippy/src/docs.rs
+++ b/src/tools/clippy/src/docs.rs
@@ -170,7 +170,6 @@ docs! {
     "fn_to_numeric_cast_any",
     "fn_to_numeric_cast_with_truncation",
     "for_kv_map",
-    "for_loops_over_fallibles",
     "forget_copy",
     "forget_non_drop",
     "forget_ref",
diff --git a/src/tools/clippy/src/docs/for_loops_over_fallibles.txt b/src/tools/clippy/src/docs/for_loops_over_fallibles.txt
deleted file mode 100644
index c5a7508e45d..00000000000
--- a/src/tools/clippy/src/docs/for_loops_over_fallibles.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-### What it does
-Checks for `for` loops over `Option` or `Result` values.
-
-### Why is this bad?
-Readability. This is more clearly expressed as an `if
-let`.
-
-### Example
-```
-for x in opt {
-    // ..
-}
-
-for x in &res {
-    // ..
-}
-
-for x in res.iter() {
-    // ..
-}
-```
-
-Use instead:
-```
-if let Some(x) = opt {
-    // ..
-}
-
-if let Ok(x) = res {
-    // ..
-}
-```
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/for_loop_unfixable.rs b/src/tools/clippy/tests/ui/for_loop_unfixable.rs
index efcaffce24e..55fb3788a8b 100644
--- a/src/tools/clippy/tests/ui/for_loop_unfixable.rs
+++ b/src/tools/clippy/tests/ui/for_loop_unfixable.rs
@@ -8,6 +8,7 @@
     clippy::for_kv_map
 )]
 #[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
+#[allow(for_loops_over_fallibles)]
 fn main() {
     let vec = vec![1, 2, 3, 4];
 
diff --git a/src/tools/clippy/tests/ui/for_loop_unfixable.stderr b/src/tools/clippy/tests/ui/for_loop_unfixable.stderr
index f769b4bdc94..50a86eaa68f 100644
--- a/src/tools/clippy/tests/ui/for_loop_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/for_loop_unfixable.stderr
@@ -1,5 +1,5 @@
 error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
-  --> $DIR/for_loop_unfixable.rs:14:15
+  --> $DIR/for_loop_unfixable.rs:15:15
    |
 LL |     for _v in vec.iter().next() {}
    |               ^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/for_loops_over_fallibles.rs b/src/tools/clippy/tests/ui/for_loops_over_fallibles.rs
deleted file mode 100644
index 4b2a9297d08..00000000000
--- a/src/tools/clippy/tests/ui/for_loops_over_fallibles.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-#![warn(clippy::for_loops_over_fallibles)]
-#![allow(clippy::uninlined_format_args)]
-
-fn for_loops_over_fallibles() {
-    let option = Some(1);
-    let mut result = option.ok_or("x not found");
-    let v = vec![0, 1, 2];
-
-    // check over an `Option`
-    for x in option {
-        println!("{}", x);
-    }
-
-    // check over an `Option`
-    for x in option.iter() {
-        println!("{}", x);
-    }
-
-    // check over a `Result`
-    for x in result {
-        println!("{}", x);
-    }
-
-    // check over a `Result`
-    for x in result.iter_mut() {
-        println!("{}", x);
-    }
-
-    // check over a `Result`
-    for x in result.into_iter() {
-        println!("{}", x);
-    }
-
-    for x in option.ok_or("x not found") {
-        println!("{}", x);
-    }
-
-    // make sure LOOP_OVER_NEXT lint takes clippy::precedence when next() is the last call
-    // in the chain
-    for x in v.iter().next() {
-        println!("{}", x);
-    }
-
-    // make sure we lint when next() is not the last call in the chain
-    for x in v.iter().next().and(Some(0)) {
-        println!("{}", x);
-    }
-
-    for x in v.iter().next().ok_or("x not found") {
-        println!("{}", x);
-    }
-
-    // check for false positives
-
-    // for loop false positive
-    for x in v {
-        println!("{}", x);
-    }
-
-    // while let false positive for Option
-    while let Some(x) = option {
-        println!("{}", x);
-        break;
-    }
-
-    // while let false positive for Result
-    while let Ok(x) = result {
-        println!("{}", x);
-        break;
-    }
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/for_loops_over_fallibles.stderr b/src/tools/clippy/tests/ui/for_loops_over_fallibles.stderr
deleted file mode 100644
index f09adccabd1..00000000000
--- a/src/tools/clippy/tests/ui/for_loops_over_fallibles.stderr
+++ /dev/null
@@ -1,95 +0,0 @@
-error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement
-  --> $DIR/for_loops_over_fallibles.rs:10:14
-   |
-LL |     for x in option {
-   |              ^^^^^^
-   |
-   = help: consider replacing `for x in option` with `if let Some(x) = option`
-   = note: `-D clippy::for-loops-over-fallibles` implied by `-D warnings`
-
-error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement
-  --> $DIR/for_loops_over_fallibles.rs:15:14
-   |
-LL |     for x in option.iter() {
-   |              ^^^^^^
-   |
-   = help: consider replacing `for x in option.iter()` with `if let Some(x) = option`
-
-error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement
-  --> $DIR/for_loops_over_fallibles.rs:20:14
-   |
-LL |     for x in result {
-   |              ^^^^^^
-   |
-   = help: consider replacing `for x in result` with `if let Ok(x) = result`
-
-error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement
-  --> $DIR/for_loops_over_fallibles.rs:25:14
-   |
-LL |     for x in result.iter_mut() {
-   |              ^^^^^^
-   |
-   = help: consider replacing `for x in result.iter_mut()` with `if let Ok(x) = result`
-
-error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement
-  --> $DIR/for_loops_over_fallibles.rs:30:14
-   |
-LL |     for x in result.into_iter() {
-   |              ^^^^^^
-   |
-   = help: consider replacing `for x in result.into_iter()` with `if let Ok(x) = result`
-
-error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement
-  --> $DIR/for_loops_over_fallibles.rs:34:14
-   |
-LL |     for x in option.ok_or("x not found") {
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")`
-
-error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
-  --> $DIR/for_loops_over_fallibles.rs:40:14
-   |
-LL |     for x in v.iter().next() {
-   |              ^^^^^^^^^^^^^^^
-   |
-   = note: `#[deny(clippy::iter_next_loop)]` on by default
-
-error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement
-  --> $DIR/for_loops_over_fallibles.rs:45:14
-   |
-LL |     for x in v.iter().next().and(Some(0)) {
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))`
-
-error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement
-  --> $DIR/for_loops_over_fallibles.rs:49:14
-   |
-LL |     for x in v.iter().next().ok_or("x not found") {
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")`
-
-error: this loop never actually loops
-  --> $DIR/for_loops_over_fallibles.rs:61:5
-   |
-LL | /     while let Some(x) = option {
-LL | |         println!("{}", x);
-LL | |         break;
-LL | |     }
-   | |_____^
-   |
-   = note: `#[deny(clippy::never_loop)]` on by default
-
-error: this loop never actually loops
-  --> $DIR/for_loops_over_fallibles.rs:67:5
-   |
-LL | /     while let Ok(x) = result {
-LL | |         println!("{}", x);
-LL | |         break;
-LL | |     }
-   | |_____^
-
-error: aborting due to 11 previous errors
-
diff --git a/src/tools/clippy/tests/ui/manual_map_option.fixed b/src/tools/clippy/tests/ui/manual_map_option.fixed
index a59da4ae10b..e12ea7ec145 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.fixed
+++ b/src/tools/clippy/tests/ui/manual_map_option.fixed
@@ -7,7 +7,7 @@
     clippy::unit_arg,
     clippy::match_ref_pats,
     clippy::redundant_pattern_matching,
-    clippy::for_loops_over_fallibles,
+    for_loops_over_fallibles,
     dead_code
 )]
 
diff --git a/src/tools/clippy/tests/ui/manual_map_option.rs b/src/tools/clippy/tests/ui/manual_map_option.rs
index 0bdbefa51e8..325a6db06c4 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.rs
+++ b/src/tools/clippy/tests/ui/manual_map_option.rs
@@ -7,7 +7,7 @@
     clippy::unit_arg,
     clippy::match_ref_pats,
     clippy::redundant_pattern_matching,
-    clippy::for_loops_over_fallibles,
+    for_loops_over_fallibles,
     dead_code
 )]
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index a6e7bdba77c..8beae8dee08 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -12,7 +12,7 @@
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::for_loops_over_fallibles)]
+#![allow(for_loops_over_fallibles)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::overly_complex_bool_expr)]
@@ -45,8 +45,8 @@
 #![warn(clippy::disallowed_methods)]
 #![warn(clippy::disallowed_types)]
 #![warn(clippy::mixed_read_write_in_expression)]
-#![warn(clippy::for_loops_over_fallibles)]
-#![warn(clippy::for_loops_over_fallibles)]
+#![warn(for_loops_over_fallibles)]
+#![warn(for_loops_over_fallibles)]
 #![warn(clippy::useless_conversion)]
 #![warn(clippy::match_result_ok)]
 #![warn(clippy::overly_complex_bool_expr)]
@@ -65,6 +65,7 @@
 #![warn(clippy::recursive_format_impl)]
 #![warn(clippy::invisible_characters)]
 #![warn(drop_bounds)]
+#![warn(for_loops_over_fallibles)]
 #![warn(array_into_iter)]
 #![warn(invalid_atomic_ordering)]
 #![warn(invalid_value)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index e8f57597d02..9e665047baa 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -12,7 +12,7 @@
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::for_loops_over_fallibles)]
+#![allow(for_loops_over_fallibles)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::overly_complex_bool_expr)]
@@ -65,6 +65,7 @@
 #![warn(clippy::to_string_in_display)]
 #![warn(clippy::zero_width_space)]
 #![warn(clippy::drop_bounds)]
+#![warn(clippy::for_loops_over_fallibles)]
 #![warn(clippy::into_iter_on_array)]
 #![warn(clippy::invalid_atomic_ordering)]
 #![warn(clippy::invalid_ref)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 31865a7f66d..63eb565185f 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -54,17 +54,17 @@ error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_r
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
-error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
+error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
   --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
-error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
+error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
   --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
   --> $DIR/rename.rs:50:9
@@ -174,59 +174,65 @@ error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
-error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
+error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
   --> $DIR/rename.rs:68:9
    |
+LL | #![warn(clippy::for_loops_over_fallibles)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
+
+error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
+  --> $DIR/rename.rs:69:9
+   |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 38 previous errors
+error: aborting due to 39 previous errors