Auto merge of #11005 - Centri3:never_loop, r=giraffate
Check if `if` conditions always evaluate to true in `never_loop` This fixes the example provided in #11004, but it shouldn't be closed as this is still an issue on like ```rust let x = true; if x { /* etc */ }` ``` This also makes `clippy_utils::consts::constant` handle `ConstBlock` and `DropTemps`. changelog: [`never_loop`]: Check if `if` conditions always evaluate to true
This commit is contained in:
commit
407bfd483a
@ -1,22 +1,23 @@
|
||||
use super::utils::make_iterator_snippet;
|
||||
use super::NEVER_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::consts::constant;
|
||||
use clippy_utils::higher::ForLoop;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{consts::Constant, diagnostics::span_lint_and_then};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
use std::iter::{once, Iterator};
|
||||
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
block: &Block<'_>,
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
block: &Block<'tcx>,
|
||||
loop_id: HirId,
|
||||
span: Span,
|
||||
for_loop: Option<&ForLoop<'_>>,
|
||||
) {
|
||||
match never_loop_block(block, &mut Vec::new(), loop_id) {
|
||||
match never_loop_block(cx, block, &mut Vec::new(), loop_id) {
|
||||
NeverLoopResult::AlwaysBreak => {
|
||||
span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
|
||||
if let Some(ForLoop {
|
||||
@ -95,7 +96,12 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirI
|
||||
}
|
||||
}
|
||||
|
||||
fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
fn never_loop_block<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
block: &Block<'tcx>,
|
||||
ignore_ids: &mut Vec<HirId>,
|
||||
main_loop_id: HirId,
|
||||
) -> NeverLoopResult {
|
||||
let iter = block
|
||||
.stmts
|
||||
.iter()
|
||||
@ -103,10 +109,10 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
|
||||
.chain(block.expr.map(|expr| (expr, None)));
|
||||
|
||||
iter.map(|(e, els)| {
|
||||
let e = never_loop_expr(e, ignore_ids, main_loop_id);
|
||||
let e = never_loop_expr(cx, e, ignore_ids, main_loop_id);
|
||||
// els is an else block in a let...else binding
|
||||
els.map_or(e, |els| {
|
||||
combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id), ignore_ids)
|
||||
combine_branches(e, never_loop_block(cx, els, ignore_ids, main_loop_id), ignore_ids)
|
||||
})
|
||||
})
|
||||
.fold(NeverLoopResult::Otherwise, combine_seq)
|
||||
@ -122,7 +128,12 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
fn never_loop_expr<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &Expr<'tcx>,
|
||||
ignore_ids: &mut Vec<HirId>,
|
||||
main_loop_id: HirId,
|
||||
) -> NeverLoopResult {
|
||||
match expr.kind {
|
||||
ExprKind::Unary(_, e)
|
||||
| ExprKind::Cast(e, _)
|
||||
@ -130,45 +141,51 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||
| ExprKind::Field(e, _)
|
||||
| ExprKind::AddrOf(_, _, e)
|
||||
| ExprKind::Repeat(e, _)
|
||||
| ExprKind::DropTemps(e) => never_loop_expr(e, ignore_ids, main_loop_id),
|
||||
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, ignore_ids, main_loop_id),
|
||||
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), ignore_ids, main_loop_id),
|
||||
| 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::MethodCall(_, receiver, es, _) => never_loop_expr_all(
|
||||
cx,
|
||||
&mut std::iter::once(receiver).chain(es.iter()),
|
||||
ignore_ids,
|
||||
main_loop_id,
|
||||
),
|
||||
ExprKind::Struct(_, fields, base) => {
|
||||
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
|
||||
let fields = never_loop_expr_all(cx, &mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
|
||||
if let Some(base) = base {
|
||||
combine_seq(fields, never_loop_expr(base, ignore_ids, main_loop_id))
|
||||
combine_seq(fields, never_loop_expr(cx, base, ignore_ids, main_loop_id))
|
||||
} else {
|
||||
fields
|
||||
}
|
||||
},
|
||||
ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), ignore_ids, main_loop_id),
|
||||
ExprKind::Call(e, es) => never_loop_expr_all(cx, &mut once(e).chain(es.iter()), ignore_ids, main_loop_id),
|
||||
ExprKind::Binary(_, e1, e2)
|
||||
| ExprKind::Assign(e1, e2, _)
|
||||
| ExprKind::AssignOp(_, e1, e2)
|
||||
| ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
|
||||
| ExprKind::Index(e1, e2) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
|
||||
ExprKind::Loop(b, _, _, _) => {
|
||||
// Break can come from the inner loop so remove them.
|
||||
absorb_break(never_loop_block(b, ignore_ids, main_loop_id))
|
||||
absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id))
|
||||
},
|
||||
ExprKind::If(e, e2, e3) => {
|
||||
let e1 = never_loop_expr(e, ignore_ids, main_loop_id);
|
||||
let e2 = never_loop_expr(e2, ignore_ids, main_loop_id);
|
||||
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(e, ignore_ids, main_loop_id)
|
||||
never_loop_expr(cx, e, ignore_ids, main_loop_id)
|
||||
});
|
||||
combine_seq(e1, combine_branches(e2, e3, ignore_ids))
|
||||
},
|
||||
ExprKind::Match(e, arms, _) => {
|
||||
let e = never_loop_expr(e, ignore_ids, main_loop_id);
|
||||
let e = never_loop_expr(cx, e, ignore_ids, main_loop_id);
|
||||
if arms.is_empty() {
|
||||
e
|
||||
} else {
|
||||
let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id);
|
||||
let arms = never_loop_expr_branch(cx, &mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id);
|
||||
combine_seq(e, arms)
|
||||
}
|
||||
},
|
||||
@ -176,7 +193,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||
if l.is_some() {
|
||||
ignore_ids.push(b.hir_id);
|
||||
}
|
||||
let ret = never_loop_block(b, ignore_ids, main_loop_id);
|
||||
let ret = never_loop_block(cx, b, ignore_ids, main_loop_id);
|
||||
if l.is_some() {
|
||||
ignore_ids.pop();
|
||||
}
|
||||
@ -198,11 +215,11 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||
// 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(e, ignore_ids, main_loop_id)
|
||||
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(e, ignore_ids, main_loop_id),
|
||||
never_loop_expr(cx, e, ignore_ids, main_loop_id),
|
||||
NeverLoopResult::AlwaysBreak,
|
||||
)
|
||||
}),
|
||||
@ -211,12 +228,13 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||
.iter()
|
||||
.map(|(o, _)| match o {
|
||||
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
|
||||
never_loop_expr(expr, ignore_ids, main_loop_id)
|
||||
never_loop_expr(cx, expr, ignore_ids, main_loop_id)
|
||||
},
|
||||
InlineAsmOperand::Out { expr, .. } => {
|
||||
never_loop_expr_all(&mut expr.iter().copied(), ignore_ids, main_loop_id)
|
||||
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,
|
||||
@ -236,22 +254,24 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||
}
|
||||
}
|
||||
|
||||
fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
|
||||
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(e, ignore_ids, main_loop_id))
|
||||
es.map(|e| never_loop_expr(cx, e, ignore_ids, main_loop_id))
|
||||
.fold(NeverLoopResult::Otherwise, combine_seq)
|
||||
}
|
||||
|
||||
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
|
||||
fn never_loop_expr_branch<'tcx, T: Iterator<Item = &'tcx Expr<'tcx>>>(
|
||||
cx: &LateContext<'tcx>,
|
||||
e: &mut T,
|
||||
ignore_ids: &mut Vec<HirId>,
|
||||
main_loop_id: HirId,
|
||||
) -> NeverLoopResult {
|
||||
e.fold(NeverLoopResult::AlwaysBreak, |a, b| {
|
||||
combine_branches(a, never_loop_expr(b, ignore_ids, main_loop_id), ignore_ids)
|
||||
combine_branches(a, never_loop_expr(cx, b, ignore_ids, main_loop_id), ignore_ids)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
use rustc_ast::ast::{self, LitFloatType, LitKind};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
|
||||
use rustc_hir::{AnonConst, BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
|
||||
use rustc_lexer::tokenize;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir;
|
||||
@ -344,6 +344,8 @@ fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>)
|
||||
/// Simple constant folding: Insert an expression, get a constant or none.
|
||||
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
match e.kind {
|
||||
ExprKind::ConstBlock(AnonConst { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
|
||||
ExprKind::DropTemps(e) => self.expr(e),
|
||||
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
|
||||
ExprKind::Block(block, _) => self.block(block),
|
||||
ExprKind::Lit(lit) => {
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![feature(generators)]
|
||||
#![warn(clippy::large_futures)]
|
||||
#![allow(clippy::never_loop)]
|
||||
#![allow(clippy::future_not_send)]
|
||||
#![allow(clippy::manual_async_fn)]
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: large future with a size of 16385 bytes
|
||||
--> $DIR/large_futures.rs:10:9
|
||||
--> $DIR/large_futures.rs:11:9
|
||||
|
|
||||
LL | big_fut([0u8; 1024 * 16]).await;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))`
|
||||
@ -7,37 +7,37 @@ LL | big_fut([0u8; 1024 * 16]).await;
|
||||
= note: `-D clippy::large-futures` implied by `-D warnings`
|
||||
|
||||
error: large future with a size of 16386 bytes
|
||||
--> $DIR/large_futures.rs:12:5
|
||||
--> $DIR/large_futures.rs:13:5
|
||||
|
|
||||
LL | f.await
|
||||
| ^ help: consider `Box::pin` on it: `Box::pin(f)`
|
||||
|
||||
error: large future with a size of 16387 bytes
|
||||
--> $DIR/large_futures.rs:16:9
|
||||
--> $DIR/large_futures.rs:17:9
|
||||
|
|
||||
LL | wait().await;
|
||||
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
|
||||
|
||||
error: large future with a size of 16387 bytes
|
||||
--> $DIR/large_futures.rs:20:13
|
||||
--> $DIR/large_futures.rs:21:13
|
||||
|
|
||||
LL | wait().await;
|
||||
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
|
||||
|
||||
error: large future with a size of 65540 bytes
|
||||
--> $DIR/large_futures.rs:27:5
|
||||
--> $DIR/large_futures.rs:28:5
|
||||
|
|
||||
LL | foo().await;
|
||||
| ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())`
|
||||
|
||||
error: large future with a size of 49159 bytes
|
||||
--> $DIR/large_futures.rs:28:5
|
||||
--> $DIR/large_futures.rs:29:5
|
||||
|
|
||||
LL | calls_fut(fut).await;
|
||||
| ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))`
|
||||
|
||||
error: large future with a size of 65540 bytes
|
||||
--> $DIR/large_futures.rs:40:5
|
||||
--> $DIR/large_futures.rs:41:5
|
||||
|
|
||||
LL | / async {
|
||||
LL | | let x = [0i32; 1024 * 16];
|
||||
@ -56,7 +56,7 @@ LL + })
|
||||
|
|
||||
|
||||
error: large future with a size of 65540 bytes
|
||||
--> $DIR/large_futures.rs:51:13
|
||||
--> $DIR/large_futures.rs:52:13
|
||||
|
|
||||
LL | / async {
|
||||
LL | | let x = [0i32; 1024 * 16];
|
||||
|
@ -1,4 +1,6 @@
|
||||
#![feature(inline_const)]
|
||||
#![allow(
|
||||
clippy::eq_op,
|
||||
clippy::single_match,
|
||||
unused_assignments,
|
||||
unused_variables,
|
||||
@ -295,6 +297,42 @@ pub fn test24() {
|
||||
}
|
||||
}
|
||||
|
||||
// Do not lint, we can evaluate `true` to always succeed thus can short-circuit before the `return`
|
||||
pub fn test25() {
|
||||
loop {
|
||||
'label: {
|
||||
if const { true } {
|
||||
break 'label;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test26() {
|
||||
loop {
|
||||
'label: {
|
||||
if 1 == 1 {
|
||||
break 'label;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test27() {
|
||||
loop {
|
||||
'label: {
|
||||
let x = true;
|
||||
// Lints because we cannot prove it's always `true`
|
||||
if x {
|
||||
break 'label;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test1();
|
||||
test2();
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:10:5
|
||||
--> $DIR/never_loop.rs:12:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | | // clippy::never_loop
|
||||
@ -13,7 +13,7 @@ LL | | }
|
||||
= note: `#[deny(clippy::never_loop)]` on by default
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:32:5
|
||||
--> $DIR/never_loop.rs:34:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | | // never loops
|
||||
@ -23,7 +23,7 @@ LL | | }
|
||||
| |_____^
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:52:5
|
||||
--> $DIR/never_loop.rs:54:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | | // never loops
|
||||
@ -35,7 +35,7 @@ LL | | }
|
||||
| |_____^
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:54:9
|
||||
--> $DIR/never_loop.rs:56:9
|
||||
|
|
||||
LL | / while i == 0 {
|
||||
LL | | // never loops
|
||||
@ -44,7 +44,7 @@ LL | | }
|
||||
| |_________^
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:66:9
|
||||
--> $DIR/never_loop.rs:68:9
|
||||
|
|
||||
LL | / loop {
|
||||
LL | | // never loops
|
||||
@ -56,7 +56,7 @@ LL | | }
|
||||
| |_________^
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:102:5
|
||||
--> $DIR/never_loop.rs:104:5
|
||||
|
|
||||
LL | / while let Some(y) = x {
|
||||
LL | | // never loops
|
||||
@ -65,7 +65,7 @@ LL | | }
|
||||
| |_____^
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:109:5
|
||||
--> $DIR/never_loop.rs:111:5
|
||||
|
|
||||
LL | / for x in 0..10 {
|
||||
LL | | // never loops
|
||||
@ -82,7 +82,7 @@ LL | if let Some(x) = (0..10).next() {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:157:5
|
||||
--> $DIR/never_loop.rs:159:5
|
||||
|
|
||||
LL | / 'outer: while a {
|
||||
LL | | // never loops
|
||||
@ -94,7 +94,7 @@ LL | | }
|
||||
| |_____^
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:172:9
|
||||
--> $DIR/never_loop.rs:174:9
|
||||
|
|
||||
LL | / while false {
|
||||
LL | | break 'label;
|
||||
@ -102,7 +102,7 @@ LL | | }
|
||||
| |_________^
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:223:13
|
||||
--> $DIR/never_loop.rs:225:13
|
||||
|
|
||||
LL | let _ = loop {
|
||||
| _____________^
|
||||
@ -115,7 +115,7 @@ LL | | };
|
||||
| |_____^
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:244:5
|
||||
--> $DIR/never_loop.rs:246:5
|
||||
|
|
||||
LL | / 'a: loop {
|
||||
LL | | 'b: {
|
||||
@ -127,7 +127,7 @@ LL | | }
|
||||
| |_____^
|
||||
|
||||
error: sub-expression diverges
|
||||
--> $DIR/never_loop.rs:247:17
|
||||
--> $DIR/never_loop.rs:249:17
|
||||
|
|
||||
LL | break 'a;
|
||||
| ^^^^^^^^
|
||||
@ -135,7 +135,7 @@ LL | break 'a;
|
||||
= note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:278:13
|
||||
--> $DIR/never_loop.rs:280:13
|
||||
|
|
||||
LL | / for _ in 0..20 {
|
||||
LL | | break 'block;
|
||||
@ -147,5 +147,17 @@ help: if you need the first element of the iterator, try writing
|
||||
LL | if let Some(_) = (0..20).next() {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:324:5
|
||||
|
|
||||
LL | / loop {
|
||||
LL | | 'label: {
|
||||
LL | | let x = true;
|
||||
LL | | // Lints because we cannot prove it's always `true`
|
||||
... |
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user