about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-09-02 12:34:47 +0000
committerbors <bors@rust-lang.org>2023-09-02 12:34:47 +0000
commitb9906aca5ac29d6b4bfeda81fc44a40b24c1c392 (patch)
treef940e2c6bc95f2d6b41b8614677499a6112903dd
parentb65e5445351ed80dfb7cab4ddc2c1c575292d9ca (diff)
parent44f64acb7e28ee914b8feb131b1ba382711be465 (diff)
downloadrust-b9906aca5ac29d6b4bfeda81fc44a40b24c1c392.tar.gz
rust-b9906aca5ac29d6b4bfeda81fc44a40b24c1c392.zip
Auto merge of #11450 - digama0:never_loop2, r=llogiq
`never_loop` catches `loop { panic!() }`

* Depends on: #11447

This is an outgrowth of #11447 which I felt would best be done as a separate PR because it yields significant new results.

This uses typecheck results to determine divergence, meaning we can now detect cases like `loop { std::process::abort() }` or `loop { panic!() }`. A downside is that `loop { unimplemented!() }` is also being linted, which is arguably a false positive. I'm not really sure how to check this from HIR though, and it seems best to leave this epicycle for a later PR.

changelog: [`never_loop`]: Now lints on `loop { panic!() }` and similar constructs
-rw-r--r--clippy_lints/src/loops/never_loop.rs256
-rw-r--r--tests/ui/crashes/ice-360.rs3
-rw-r--r--tests/ui/crashes/ice-360.stderr20
-rw-r--r--tests/ui/empty_loop.rs3
-rw-r--r--tests/ui/empty_loop.stderr4
-rw-r--r--tests/ui/iter_out_of_bounds.rs1
-rw-r--r--tests/ui/iter_out_of_bounds.stderr28
-rw-r--r--tests/ui/needless_collect_indirect.rs6
-rw-r--r--tests/ui/needless_collect_indirect.stderr7
-rw-r--r--tests/ui/never_loop.rs47
-rw-r--r--tests/ui/never_loop.stderr18
-rw-r--r--tests/ui/similar_names.rs1
-rw-r--r--tests/ui/similar_names.stderr28
-rw-r--r--tests/ui/vec.fixed7
-rw-r--r--tests/ui/vec.rs7
-rw-r--r--tests/ui/vec.stderr38
16 files changed, 281 insertions, 193 deletions
diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs
index cc19ac55e5e..5cdf0bd891f 100644
--- a/clippy_lints/src/loops/never_loop.rs
+++ b/clippy_lints/src/loops/never_loop.rs
@@ -1,6 +1,5 @@
 use super::utils::make_iterator_snippet;
 use super::NEVER_LOOP;
-use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::ForLoop;
 use clippy_utils::source::snippet;
@@ -18,7 +17,7 @@ pub(super) fn check<'tcx>(
     for_loop: Option<&ForLoop<'_>>,
 ) {
     match never_loop_block(cx, block, &mut Vec::new(), loop_id) {
-        NeverLoopResult::AlwaysBreak => {
+        NeverLoopResult::Diverging => {
             span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
                 if let Some(ForLoop {
                     arg: iterator,
@@ -39,67 +38,76 @@ pub(super) fn check<'tcx>(
                 }
             });
         },
-        NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
-        NeverLoopResult::IgnoreUntilEnd(_) => unreachable!(),
+        NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Normal => (),
     }
 }
 
+/// The `never_loop` analysis keeps track of three things:
+///
+/// * Has any (reachable) code path hit a `continue` of the main loop?
+/// * Is the current code path diverging (that is, the next expression is not reachable)
+/// * For each block label `'a` inside the main loop, has any (reachable) code path encountered a
+///   `break 'a`?
+///
+/// The first two bits of information are in this enum, and the last part is in the
+/// `local_labels` variable, which contains a list of `(block_id, reachable)` pairs ordered by
+/// scope.
 #[derive(Copy, Clone)]
 enum NeverLoopResult {
-    // A break/return always get triggered but not necessarily for the main loop.
-    AlwaysBreak,
-    // A continue may occur for the main loop.
+    /// A continue may occur for the main loop.
     MayContinueMainLoop,
-    // Ignore everything until the end of the block with this id
-    IgnoreUntilEnd(HirId),
-    Otherwise,
+    /// We have not encountered any main loop continue,
+    /// but we are diverging (subsequent control flow is not reachable)
+    Diverging,
+    /// We have not encountered any main loop continue,
+    /// and subsequent control flow is (possibly) reachable
+    Normal,
 }
 
 #[must_use]
 fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
     match arg {
-        NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
+        NeverLoopResult::Diverging | NeverLoopResult::Normal => NeverLoopResult::Normal,
         NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
-        NeverLoopResult::IgnoreUntilEnd(id) => NeverLoopResult::IgnoreUntilEnd(id),
     }
 }
 
 // Combine two results for parts that are called in order.
 #[must_use]
-fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
+fn combine_seq(first: NeverLoopResult, second: impl FnOnce() -> NeverLoopResult) -> NeverLoopResult {
     match first {
-        NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop | NeverLoopResult::IgnoreUntilEnd(_) => {
-            first
-        },
-        NeverLoopResult::Otherwise => second,
+        NeverLoopResult::Diverging | NeverLoopResult::MayContinueMainLoop => first,
+        NeverLoopResult::Normal => second(),
+    }
+}
+
+// Combine an iterator of results for parts that are called in order.
+#[must_use]
+fn combine_seq_many(iter: impl IntoIterator<Item = NeverLoopResult>) -> NeverLoopResult {
+    for e in iter {
+        if let NeverLoopResult::Diverging | NeverLoopResult::MayContinueMainLoop = e {
+            return e;
+        }
     }
+    NeverLoopResult::Normal
 }
 
 // Combine two results where only one of the part may have been executed.
 #[must_use]
-fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirId]) -> NeverLoopResult {
+fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
     match (b1, b2) {
-        (NeverLoopResult::IgnoreUntilEnd(a), NeverLoopResult::IgnoreUntilEnd(b)) => {
-            if ignore_ids.iter().find(|&e| e == &a || e == &b).unwrap() == &a {
-                NeverLoopResult::IgnoreUntilEnd(b)
-            } else {
-                NeverLoopResult::IgnoreUntilEnd(a)
-            }
-        },
-        (i @ NeverLoopResult::IgnoreUntilEnd(_), NeverLoopResult::AlwaysBreak)
-        | (NeverLoopResult::AlwaysBreak, i @ NeverLoopResult::IgnoreUntilEnd(_)) => i,
-        (NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
         (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
             NeverLoopResult::MayContinueMainLoop
         },
-        (NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
+        (NeverLoopResult::Normal, _) | (_, NeverLoopResult::Normal) => NeverLoopResult::Normal,
+        (NeverLoopResult::Diverging, NeverLoopResult::Diverging) => NeverLoopResult::Diverging,
     }
 }
 
 fn never_loop_block<'tcx>(
     cx: &LateContext<'tcx>,
     block: &Block<'tcx>,
-    ignore_ids: &mut Vec<HirId>,
+    local_labels: &mut Vec<(HirId, bool)>,
     main_loop_id: HirId,
 ) -> NeverLoopResult {
     let iter = block
@@ -107,15 +115,21 @@ fn never_loop_block<'tcx>(
         .iter()
         .filter_map(stmt_to_expr)
         .chain(block.expr.map(|expr| (expr, None)));
-
-    iter.map(|(e, els)| {
-        let e = never_loop_expr(cx, e, ignore_ids, main_loop_id);
+    combine_seq_many(iter.map(|(e, els)| {
+        let e = never_loop_expr(cx, e, local_labels, main_loop_id);
         // els is an else block in a let...else binding
         els.map_or(e, |els| {
-            combine_branches(e, never_loop_block(cx, els, ignore_ids, main_loop_id), ignore_ids)
+            combine_seq(e, || match never_loop_block(cx, els, local_labels, main_loop_id) {
+                // Returning MayContinueMainLoop here means that
+                // we will not evaluate the rest of the body
+                NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
+                // An else block always diverges, so the Normal case should not happen,
+                // but the analysis is approximate so it might return Normal anyway.
+                // Returning Normal here says that nothing more happens on the main path
+                NeverLoopResult::Diverging | NeverLoopResult::Normal => NeverLoopResult::Normal,
+            })
         })
-    })
-    .fold(NeverLoopResult::Otherwise, combine_seq)
+    }))
 }
 
 fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'tcx Block<'tcx>>)> {
@@ -131,76 +145,69 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t
 fn never_loop_expr<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &Expr<'tcx>,
-    ignore_ids: &mut Vec<HirId>,
+    local_labels: &mut Vec<(HirId, bool)>,
     main_loop_id: HirId,
 ) -> NeverLoopResult {
-    match expr.kind {
+    let result = match expr.kind {
         ExprKind::Unary(_, e)
         | ExprKind::Cast(e, _)
         | ExprKind::Type(e, _)
         | ExprKind::Field(e, _)
         | ExprKind::AddrOf(_, _, e)
         | ExprKind::Repeat(e, _)
-        | ExprKind::DropTemps(e) => never_loop_expr(cx, e, ignore_ids, main_loop_id),
-        ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, ignore_ids, main_loop_id),
-        ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, &mut es.iter(), ignore_ids, main_loop_id),
+        | ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id),
+        ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
+        ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
         ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all(
             cx,
-            &mut std::iter::once(receiver).chain(es.iter()),
-            ignore_ids,
+            std::iter::once(receiver).chain(es.iter()),
+            local_labels,
             main_loop_id,
         ),
         ExprKind::Struct(_, fields, base) => {
-            let fields = never_loop_expr_all(cx, &mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
+            let fields = never_loop_expr_all(cx, fields.iter().map(|f| f.expr), local_labels, main_loop_id);
             if let Some(base) = base {
-                combine_seq(fields, never_loop_expr(cx, base, ignore_ids, main_loop_id))
+                combine_seq(fields, || never_loop_expr(cx, base, local_labels, main_loop_id))
             } else {
                 fields
             }
         },
-        ExprKind::Call(e, es) => never_loop_expr_all(cx, &mut once(e).chain(es.iter()), ignore_ids, main_loop_id),
+        ExprKind::Call(e, es) => never_loop_expr_all(cx, once(e).chain(es.iter()), local_labels, main_loop_id),
         ExprKind::Binary(_, e1, e2)
         | ExprKind::Assign(e1, e2, _)
         | ExprKind::AssignOp(_, e1, e2)
-        | ExprKind::Index(e1, e2, _) => {
-            never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id)
-        },
+        | ExprKind::Index(e1, e2, _) => never_loop_expr_all(cx, [e1, e2].iter().copied(), local_labels, main_loop_id),
         ExprKind::Loop(b, _, _, _) => {
-            // Break can come from the inner loop so remove them.
-            absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id))
+            // We don't attempt to track reachability after a loop,
+            // just assume there may have been a break somewhere
+            absorb_break(never_loop_block(cx, b, local_labels, main_loop_id))
         },
         ExprKind::If(e, e2, e3) => {
-            let e1 = never_loop_expr(cx, e, ignore_ids, main_loop_id);
-            let e2 = never_loop_expr(cx, e2, ignore_ids, main_loop_id);
-            // If we know the `if` condition evaluates to `true`, don't check everything past it; it
-            // should just return whatever's evaluated for `e1` and `e2` since `e3` is unreachable
-            if let Some(Constant::Bool(true)) = constant(cx, cx.typeck_results(), e) {
-                return combine_seq(e1, e2);
-            }
-            let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| {
-                never_loop_expr(cx, e, ignore_ids, main_loop_id)
-            });
-            combine_seq(e1, combine_branches(e2, e3, ignore_ids))
+            let e1 = never_loop_expr(cx, e, local_labels, main_loop_id);
+            combine_seq(e1, || {
+                let e2 = never_loop_expr(cx, e2, local_labels, main_loop_id);
+                let e3 = e3.as_ref().map_or(NeverLoopResult::Normal, |e| {
+                    never_loop_expr(cx, e, local_labels, main_loop_id)
+                });
+                combine_branches(e2, e3)
+            })
         },
         ExprKind::Match(e, arms, _) => {
-            let e = never_loop_expr(cx, e, ignore_ids, main_loop_id);
-            if arms.is_empty() {
-                e
-            } else {
-                let arms = never_loop_expr_branch(cx, &mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id);
-                combine_seq(e, arms)
-            }
+            let e = never_loop_expr(cx, e, local_labels, main_loop_id);
+            combine_seq(e, || {
+                arms.iter().fold(NeverLoopResult::Diverging, |a, b| {
+                    combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id))
+                })
+            })
         },
         ExprKind::Block(b, l) => {
             if l.is_some() {
-                ignore_ids.push(b.hir_id);
-            }
-            let ret = never_loop_block(cx, b, ignore_ids, main_loop_id);
-            if l.is_some() {
-                ignore_ids.pop();
+                local_labels.push((b.hir_id, false));
             }
+            let ret = never_loop_block(cx, b, local_labels, main_loop_id);
+            let jumped_to = l.is_some() && local_labels.pop().unwrap().1;
             match ret {
-                NeverLoopResult::IgnoreUntilEnd(a) if a == b.hir_id => NeverLoopResult::Otherwise,
+                NeverLoopResult::Diverging if jumped_to => NeverLoopResult::Normal,
                 _ => ret,
             }
         },
@@ -211,74 +218,67 @@ fn never_loop_expr<'tcx>(
             if id == main_loop_id {
                 NeverLoopResult::MayContinueMainLoop
             } else {
-                NeverLoopResult::AlwaysBreak
+                NeverLoopResult::Diverging
             }
         },
-        // checks if break targets a block instead of a loop
-        ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
-            .map_or(NeverLoopResult::IgnoreUntilEnd(t), |e| {
-                never_loop_expr(cx, e, ignore_ids, main_loop_id)
-            }),
-        ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
-            combine_seq(
-                never_loop_expr(cx, e, ignore_ids, main_loop_id),
-                NeverLoopResult::AlwaysBreak,
-            )
-        }),
-        ExprKind::Become(e) => combine_seq(
-            never_loop_expr(cx, e, ignore_ids, main_loop_id),
-            NeverLoopResult::AlwaysBreak,
-        ),
-        ExprKind::InlineAsm(asm) => asm
-            .operands
-            .iter()
-            .map(|(o, _)| match o {
-                InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
-                    never_loop_expr(cx, expr, ignore_ids, main_loop_id)
-                },
-                InlineAsmOperand::Out { expr, .. } => {
-                    never_loop_expr_all(cx, &mut expr.iter().copied(), ignore_ids, main_loop_id)
-                },
-                InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
-                    cx,
-                    &mut once(*in_expr).chain(out_expr.iter().copied()),
-                    ignore_ids,
-                    main_loop_id,
-                ),
-                InlineAsmOperand::Const { .. }
-                | InlineAsmOperand::SymFn { .. }
-                | InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
+        ExprKind::Break(_, e) | ExprKind::Ret(e) => {
+            let first = e.as_ref().map_or(NeverLoopResult::Normal, |e| {
+                never_loop_expr(cx, e, local_labels, main_loop_id)
+            });
+            combine_seq(first, || {
+                // checks if break targets a block instead of a loop
+                if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind {
+                    if let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t) {
+                        *reachable = true;
+                    }
+                }
+                NeverLoopResult::Diverging
             })
-            .fold(NeverLoopResult::Otherwise, combine_seq),
+        },
+        ExprKind::Become(e) => combine_seq(never_loop_expr(cx, e, local_labels, main_loop_id), || {
+            NeverLoopResult::Diverging
+        }),
+        ExprKind::InlineAsm(asm) => combine_seq_many(asm.operands.iter().map(|(o, _)| match o {
+            InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
+                never_loop_expr(cx, expr, local_labels, main_loop_id)
+            },
+            InlineAsmOperand::Out { expr, .. } => {
+                never_loop_expr_all(cx, expr.iter().copied(), local_labels, main_loop_id)
+            },
+            InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
+                cx,
+                once(*in_expr).chain(out_expr.iter().copied()),
+                local_labels,
+                main_loop_id,
+            ),
+            InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => {
+                NeverLoopResult::Normal
+            },
+        })),
         ExprKind::OffsetOf(_, _)
         | ExprKind::Yield(_, _)
         | ExprKind::Closure { .. }
         | ExprKind::Path(_)
         | ExprKind::ConstBlock(_)
         | ExprKind::Lit(_)
-        | ExprKind::Err(_) => NeverLoopResult::Otherwise,
-    }
+        | ExprKind::Err(_) => NeverLoopResult::Normal,
+    };
+    combine_seq(result, || {
+        if cx.typeck_results().expr_ty(expr).is_never() {
+            NeverLoopResult::Diverging
+        } else {
+            NeverLoopResult::Normal
+        }
+    })
 }
 
 fn never_loop_expr_all<'tcx, T: Iterator<Item = &'tcx Expr<'tcx>>>(
     cx: &LateContext<'tcx>,
-    es: &mut T,
-    ignore_ids: &mut Vec<HirId>,
-    main_loop_id: HirId,
-) -> NeverLoopResult {
-    es.map(|e| never_loop_expr(cx, e, ignore_ids, main_loop_id))
-        .fold(NeverLoopResult::Otherwise, combine_seq)
-}
-
-fn never_loop_expr_branch<'tcx, T: Iterator<Item = &'tcx Expr<'tcx>>>(
-    cx: &LateContext<'tcx>,
-    e: &mut T,
-    ignore_ids: &mut Vec<HirId>,
+    es: T,
+    local_labels: &mut Vec<(HirId, bool)>,
     main_loop_id: HirId,
 ) -> NeverLoopResult {
-    e.fold(NeverLoopResult::AlwaysBreak, |a, b| {
-        combine_branches(a, never_loop_expr(cx, b, ignore_ids, main_loop_id), ignore_ids)
-    })
+    combine_seq_many(es.map(|e| never_loop_expr(cx, e, local_labels, main_loop_id)))
 }
 
 fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
diff --git a/tests/ui/crashes/ice-360.rs b/tests/ui/crashes/ice-360.rs
index 28589e1efed..0d10932b098 100644
--- a/tests/ui/crashes/ice-360.rs
+++ b/tests/ui/crashes/ice-360.rs
@@ -3,7 +3,8 @@ fn main() {}
 fn no_panic<T>(slice: &[T]) {
     let mut iter = slice.iter();
     loop {
-        //~^ ERROR: this loop could be written as a `while let` loop
+        //~^ ERROR: this loop never actually loops
+        //~| ERROR: this loop could be written as a `while let` loop
         //~| NOTE: `-D clippy::while-let-loop` implied by `-D warnings`
         let _ = match iter.next() {
             Some(ele) => ele,
diff --git a/tests/ui/crashes/ice-360.stderr b/tests/ui/crashes/ice-360.stderr
index 292b27dd934..73287d231de 100644
--- a/tests/ui/crashes/ice-360.stderr
+++ b/tests/ui/crashes/ice-360.stderr
@@ -1,10 +1,24 @@
+error: this loop never actually loops
+  --> $DIR/ice-360.rs:5:5
+   |
+LL | /     loop {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | |     }
+   | |_____^
+   |
+   = note: `#[deny(clippy::never_loop)]` on by default
+
 error: this loop could be written as a `while let` loop
   --> $DIR/ice-360.rs:5:5
    |
 LL | /     loop {
 LL | |
 LL | |
-LL | |         let _ = match iter.next() {
+LL | |
 ...  |
 LL | |
 LL | |     }
@@ -13,7 +27,7 @@ LL | |     }
    = note: `-D clippy::while-let-loop` implied by `-D warnings`
 
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/ice-360.rs:12:9
+  --> $DIR/ice-360.rs:13:9
    |
 LL |         loop {}
    |         ^^^^^^^
@@ -21,5 +35,5 @@ LL |         loop {}
    = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
    = note: `-D clippy::empty-loop` implied by `-D warnings`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/empty_loop.rs b/tests/ui/empty_loop.rs
index 54e8fb4907c..be347563135 100644
--- a/tests/ui/empty_loop.rs
+++ b/tests/ui/empty_loop.rs
@@ -7,10 +7,12 @@ use proc_macros::{external, inline_macros};
 
 fn should_trigger() {
     loop {}
+    #[allow(clippy::never_loop)]
     loop {
         loop {}
     }
 
+    #[allow(clippy::never_loop)]
     'outer: loop {
         'inner: loop {}
     }
@@ -18,6 +20,7 @@ fn should_trigger() {
 
 #[inline_macros]
 fn should_not_trigger() {
+    #[allow(clippy::never_loop)]
     loop {
         panic!("This is fine")
     }
diff --git a/tests/ui/empty_loop.stderr b/tests/ui/empty_loop.stderr
index 7602412334b..8594f26036e 100644
--- a/tests/ui/empty_loop.stderr
+++ b/tests/ui/empty_loop.stderr
@@ -8,7 +8,7 @@ LL |     loop {}
    = note: `-D clippy::empty-loop` implied by `-D warnings`
 
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/empty_loop.rs:11:9
+  --> $DIR/empty_loop.rs:12:9
    |
 LL |         loop {}
    |         ^^^^^^^
@@ -16,7 +16,7 @@ LL |         loop {}
    = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
 
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/empty_loop.rs:15:9
+  --> $DIR/empty_loop.rs:17:9
    |
 LL |         'inner: loop {}
    |         ^^^^^^^^^^^^^^^
diff --git a/tests/ui/iter_out_of_bounds.rs b/tests/ui/iter_out_of_bounds.rs
index c34eb1be0c5..3cfe6e82fc1 100644
--- a/tests/ui/iter_out_of_bounds.rs
+++ b/tests/ui/iter_out_of_bounds.rs
@@ -8,6 +8,7 @@ fn opaque_empty_iter() -> impl Iterator<Item = ()> {
 }
 
 fn main() {
+    #[allow(clippy::never_loop)]
     for _ in [1, 2, 3].iter().skip(4) {
         //~^ ERROR: this `.skip()` call skips more items than the iterator will produce
         unreachable!();
diff --git a/tests/ui/iter_out_of_bounds.stderr b/tests/ui/iter_out_of_bounds.stderr
index 98ee28fcaf6..f235faec8e5 100644
--- a/tests/ui/iter_out_of_bounds.stderr
+++ b/tests/ui/iter_out_of_bounds.stderr
@@ -1,5 +1,5 @@
 error: this `.skip()` call skips more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:11:14
+  --> $DIR/iter_out_of_bounds.rs:12:14
    |
 LL |     for _ in [1, 2, 3].iter().skip(4) {
    |              ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::iter_out_of_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:15:19
+  --> $DIR/iter_out_of_bounds.rs:16:19
    |
 LL |     for (i, _) in [1, 2, 3].iter().take(4).enumerate() {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |     for (i, _) in [1, 2, 3].iter().take(4).enumerate() {
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:21:14
+  --> $DIR/iter_out_of_bounds.rs:22:14
    |
 LL |     for _ in (&&&&&&[1, 2, 3]).iter().take(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     for _ in (&&&&&&[1, 2, 3]).iter().take(4) {}
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:24:14
+  --> $DIR/iter_out_of_bounds.rs:25:14
    |
 LL |     for _ in [1, 2, 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     for _ in [1, 2, 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:27:14
+  --> $DIR/iter_out_of_bounds.rs:28:14
    |
 LL |     for _ in [1; 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     for _ in [1; 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:33:14
+  --> $DIR/iter_out_of_bounds.rs:34:14
    |
 LL |     for _ in vec![1, 2, 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     for _ in vec![1, 2, 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:36:14
+  --> $DIR/iter_out_of_bounds.rs:37:14
    |
 LL |     for _ in vec![1; 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     for _ in vec![1; 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:40:14
+  --> $DIR/iter_out_of_bounds.rs:41:14
    |
 LL |     for _ in x.iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     for _ in x.iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:44:14
+  --> $DIR/iter_out_of_bounds.rs:45:14
    |
 LL |     for _ in x.iter().skip(n) {}
    |              ^^^^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     for _ in x.iter().skip(n) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:49:14
+  --> $DIR/iter_out_of_bounds.rs:50:14
    |
 LL |     for _ in empty().skip(1) {}
    |              ^^^^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL |     for _ in empty().skip(1) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:52:14
+  --> $DIR/iter_out_of_bounds.rs:53:14
    |
 LL |     for _ in empty().take(1) {}
    |              ^^^^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL |     for _ in empty().take(1) {}
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:55:14
+  --> $DIR/iter_out_of_bounds.rs:56:14
    |
 LL |     for _ in std::iter::once(1).skip(2) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     for _ in std::iter::once(1).skip(2) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:58:14
+  --> $DIR/iter_out_of_bounds.rs:59:14
    |
 LL |     for _ in std::iter::once(1).take(2) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL |     for _ in std::iter::once(1).take(2) {}
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> $DIR/iter_out_of_bounds.rs:61:14
+  --> $DIR/iter_out_of_bounds.rs:62:14
    |
 LL |     for x in [].iter().take(1) {
    |              ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/needless_collect_indirect.rs b/tests/ui/needless_collect_indirect.rs
index 9d66c5f255f..b4a536cb159 100644
--- a/tests/ui/needless_collect_indirect.rs
+++ b/tests/ui/needless_collect_indirect.rs
@@ -260,6 +260,7 @@ mod issue_8553 {
         let w = v.iter().collect::<Vec<_>>();
         //~^ ERROR: avoid using `collect()` when not needed
         // Do lint
+        #[allow(clippy::never_loop)]
         for _ in 0..w.len() {
             todo!();
         }
@@ -270,6 +271,7 @@ mod issue_8553 {
         let v: Vec<usize> = vec.iter().map(|i| i * i).collect();
         let w = v.iter().collect::<Vec<_>>();
         // Do not lint, because w is used.
+        #[allow(clippy::never_loop)]
         for _ in 0..w.len() {
             todo!();
         }
@@ -283,6 +285,7 @@ mod issue_8553 {
         let mut w = v.iter().collect::<Vec<_>>();
         //~^ ERROR: avoid using `collect()` when not needed
         // Do lint
+        #[allow(clippy::never_loop)]
         while 1 == w.len() {
             todo!();
         }
@@ -293,6 +296,7 @@ mod issue_8553 {
         let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
         let mut w = v.iter().collect::<Vec<_>>();
         // Do not lint, because w is used.
+        #[allow(clippy::never_loop)]
         while 1 == w.len() {
             todo!();
         }
@@ -306,6 +310,7 @@ mod issue_8553 {
         let mut w = v.iter().collect::<Vec<_>>();
         //~^ ERROR: avoid using `collect()` when not needed
         // Do lint
+        #[allow(clippy::never_loop)]
         while let Some(i) = Some(w.len()) {
             todo!();
         }
@@ -316,6 +321,7 @@ mod issue_8553 {
         let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
         let mut w = v.iter().collect::<Vec<_>>();
         // Do not lint, because w is used.
+        #[allow(clippy::never_loop)]
         while let Some(i) = Some(w.len()) {
             todo!();
         }
diff --git a/tests/ui/needless_collect_indirect.stderr b/tests/ui/needless_collect_indirect.stderr
index 9337a741242..47048b74125 100644
--- a/tests/ui/needless_collect_indirect.stderr
+++ b/tests/ui/needless_collect_indirect.stderr
@@ -230,11 +230,12 @@ help: take the original Iterator's count instead of collecting it and finding th
 LL ~         
 LL |
 LL |         // Do lint
+LL |         #[allow(clippy::never_loop)]
 LL ~         for _ in 0..v.iter().count() {
    |
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect_indirect.rs:283:30
+  --> $DIR/needless_collect_indirect.rs:285:30
    |
 LL |         let mut w = v.iter().collect::<Vec<_>>();
    |                              ^^^^^^^
@@ -247,11 +248,12 @@ help: take the original Iterator's count instead of collecting it and finding th
 LL ~         
 LL |
 LL |         // Do lint
+LL |         #[allow(clippy::never_loop)]
 LL ~         while 1 == v.iter().count() {
    |
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect_indirect.rs:306:30
+  --> $DIR/needless_collect_indirect.rs:310:30
    |
 LL |         let mut w = v.iter().collect::<Vec<_>>();
    |                              ^^^^^^^
@@ -264,6 +266,7 @@ help: take the original Iterator's count instead of collecting it and finding th
 LL ~         
 LL |
 LL |         // Do lint
+LL |         #[allow(clippy::never_loop)]
 LL ~         while let Some(i) = Some(v.iter().count()) {
    |
 
diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs
index 001b94391ca..33208364f0e 100644
--- a/tests/ui/never_loop.rs
+++ b/tests/ui/never_loop.rs
@@ -337,10 +337,8 @@ pub fn test26() {
 
 pub fn test27() {
     loop {
-        //~^ ERROR: this loop never actually loops
         'label: {
             let x = true;
-            // Lints because we cannot prove it's always `true`
             if x {
                 break 'label;
             }
@@ -349,6 +347,51 @@ pub fn test27() {
     }
 }
 
+// issue 11004
+pub fn test29() {
+    loop {
+        'label: {
+            if true {
+                break 'label;
+            }
+            return;
+        }
+    }
+}
+
+pub fn test30() {
+    'a: loop {
+        'b: {
+            for j in 0..2 {
+                if j == 1 {
+                    break 'b;
+                }
+            }
+            break 'a;
+        }
+    }
+}
+
+pub fn test31(b: bool) {
+    'a: loop {
+        'b: {
+            'c: loop {
+                //~^ ERROR: this loop never actually loops
+                if b { break 'c } else { break 'b }
+            }
+            continue 'a;
+        }
+        break 'a;
+    }
+}
+
+pub fn test32(b: bool) {
+    loop {
+        //~^ ERROR: this loop never actually loops
+        panic!("oh no");
+    }
+}
+
 fn main() {
     test1();
     test2();
diff --git a/tests/ui/never_loop.stderr b/tests/ui/never_loop.stderr
index 6d6d2c8ac52..37ccd63d27c 100644
--- a/tests/ui/never_loop.stderr
+++ b/tests/ui/never_loop.stderr
@@ -153,16 +153,22 @@ LL |             if let Some(_) = (0..20).next() {
    |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: this loop never actually loops
-  --> $DIR/never_loop.rs:339:5
+  --> $DIR/never_loop.rs:378:13
+   |
+LL | /             'c: loop {
+LL | |
+LL | |                 if b { break 'c } else { break 'b }
+LL | |             }
+   | |_____________^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:389:5
    |
 LL | /     loop {
 LL | |
-LL | |         'label: {
-LL | |             let x = true;
-...  |
-LL | |         }
+LL | |         panic!("oh no");
 LL | |     }
    | |_____^
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/similar_names.rs b/tests/ui/similar_names.rs
index c5a941316da..f46af56c6e2 100644
--- a/tests/ui/similar_names.rs
+++ b/tests/ui/similar_names.rs
@@ -3,6 +3,7 @@
     unused,
     clippy::println_empty_string,
     clippy::empty_loop,
+    clippy::never_loop,
     clippy::diverging_sub_expression,
     clippy::let_unit_value
 )]
diff --git a/tests/ui/similar_names.stderr b/tests/ui/similar_names.stderr
index 059e26d5891..00735617bc2 100644
--- a/tests/ui/similar_names.stderr
+++ b/tests/ui/similar_names.stderr
@@ -1,84 +1,84 @@
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:21:9
+  --> $DIR/similar_names.rs:22:9
    |
 LL |     let bpple: i32;
    |         ^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:19:9
+  --> $DIR/similar_names.rs:20:9
    |
 LL |     let apple: i32;
    |         ^^^^^
    = note: `-D clippy::similar-names` implied by `-D warnings`
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:24:9
+  --> $DIR/similar_names.rs:25:9
    |
 LL |     let cpple: i32;
    |         ^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:19:9
+  --> $DIR/similar_names.rs:20:9
    |
 LL |     let apple: i32;
    |         ^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:49:9
+  --> $DIR/similar_names.rs:50:9
    |
 LL |     let bluby: i32;
    |         ^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:48:9
+  --> $DIR/similar_names.rs:49:9
    |
 LL |     let blubx: i32;
    |         ^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:54:9
+  --> $DIR/similar_names.rs:55:9
    |
 LL |     let coke: i32;
    |         ^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:52:9
+  --> $DIR/similar_names.rs:53:9
    |
 LL |     let cake: i32;
    |         ^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:73:9
+  --> $DIR/similar_names.rs:74:9
    |
 LL |     let xyzeabc: i32;
    |         ^^^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:71:9
+  --> $DIR/similar_names.rs:72:9
    |
 LL |     let xyz1abc: i32;
    |         ^^^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:78:9
+  --> $DIR/similar_names.rs:79:9
    |
 LL |     let parsee: i32;
    |         ^^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:76:9
+  --> $DIR/similar_names.rs:77:9
    |
 LL |     let parser: i32;
    |         ^^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:100:16
+  --> $DIR/similar_names.rs:101:16
    |
 LL |         bpple: sprang,
    |                ^^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:99:16
+  --> $DIR/similar_names.rs:100:16
    |
 LL |         apple: spring,
    |                ^^^^^^
diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed
index 3ff2acbe28f..de1eb613ce0 100644
--- a/tests/ui/vec.fixed
+++ b/tests/ui/vec.fixed
@@ -1,5 +1,10 @@
 #![warn(clippy::useless_vec)]
-#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args, unused)]
+#![allow(
+    clippy::nonstandard_macro_braces,
+    clippy::never_loop,
+    clippy::uninlined_format_args,
+    unused
+)]
 
 use std::rc::Rc;
 
diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs
index 2ab025f424a..1da10c28880 100644
--- a/tests/ui/vec.rs
+++ b/tests/ui/vec.rs
@@ -1,5 +1,10 @@
 #![warn(clippy::useless_vec)]
-#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args, unused)]
+#![allow(
+    clippy::nonstandard_macro_braces,
+    clippy::never_loop,
+    clippy::uninlined_format_args,
+    unused
+)]
 
 use std::rc::Rc;
 
diff --git a/tests/ui/vec.stderr b/tests/ui/vec.stderr
index 5cd6d9fa8c7..a4c2b8984e0 100644
--- a/tests/ui/vec.stderr
+++ b/tests/ui/vec.stderr
@@ -1,5 +1,5 @@
 error: useless use of `vec!`
-  --> $DIR/vec.rs:30:14
+  --> $DIR/vec.rs:35:14
    |
 LL |     on_slice(&vec![]);
    |              ^^^^^^^ help: you can use a slice directly: `&[]`
@@ -7,109 +7,109 @@ LL |     on_slice(&vec![]);
    = note: `-D clippy::useless-vec` implied by `-D warnings`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:32:18
+  --> $DIR/vec.rs:37:18
    |
 LL |     on_mut_slice(&mut vec![]);
    |                  ^^^^^^^^^^^ help: you can use a slice directly: `&mut []`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:34:14
+  --> $DIR/vec.rs:39:14
    |
 LL |     on_slice(&vec![1, 2]);
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:36:18
+  --> $DIR/vec.rs:41:18
    |
 LL |     on_mut_slice(&mut vec![1, 2]);
    |                  ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:38:14
+  --> $DIR/vec.rs:43:14
    |
 LL |     on_slice(&vec![1, 2]);
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:40:18
+  --> $DIR/vec.rs:45:18
    |
 LL |     on_mut_slice(&mut vec![1, 2]);
    |                  ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:42:14
+  --> $DIR/vec.rs:47:14
    |
 LL |     on_slice(&vec!(1, 2));
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:44:18
+  --> $DIR/vec.rs:49:18
    |
 LL |     on_mut_slice(&mut vec![1, 2]);
    |                  ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:46:14
+  --> $DIR/vec.rs:51:14
    |
 LL |     on_slice(&vec![1; 2]);
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:48:18
+  --> $DIR/vec.rs:53:18
    |
 LL |     on_mut_slice(&mut vec![1; 2]);
    |                  ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:74:19
+  --> $DIR/vec.rs:79:19
    |
 LL |     let _x: i32 = vec![1, 2, 3].iter().sum();
    |                   ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:77:17
+  --> $DIR/vec.rs:82:17
    |
 LL |     let mut x = vec![1, 2, 3];
    |                 ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:83:22
+  --> $DIR/vec.rs:88:22
    |
 LL |     let _x: &[i32] = &vec![1, 2, 3];
    |                      ^^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:85:14
+  --> $DIR/vec.rs:90:14
    |
 LL |     for _ in vec![1, 2, 3] {}
    |              ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:123:20
+  --> $DIR/vec.rs:128:20
    |
 LL |     for _string in vec![repro!(true), repro!(null)] {
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:140:18
+  --> $DIR/vec.rs:145:18
    |
 LL |     in_macro!(1, vec![1, 2], vec![1; 2]);
    |                  ^^^^^^^^^^ help: you can use an array directly: `[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:140:30
+  --> $DIR/vec.rs:145:30
    |
 LL |     in_macro!(1, vec![1, 2], vec![1; 2]);
    |                              ^^^^^^^^^^ help: you can use an array directly: `[1; 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:159:14
+  --> $DIR/vec.rs:164:14
    |
 LL |     for a in vec![1, 2, 3] {
    |              ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:163:14
+  --> $DIR/vec.rs:168:14
    |
 LL |     for a in vec![String::new(), String::new()] {
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]`