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
This commit is contained in:
commit
b9906aca5a
@ -1,6 +1,5 @@
|
|||||||
use super::utils::make_iterator_snippet;
|
use super::utils::make_iterator_snippet;
|
||||||
use super::NEVER_LOOP;
|
use super::NEVER_LOOP;
|
||||||
use clippy_utils::consts::{constant, Constant};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::higher::ForLoop;
|
use clippy_utils::higher::ForLoop;
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
@ -18,7 +17,7 @@ pub(super) fn check<'tcx>(
|
|||||||
for_loop: Option<&ForLoop<'_>>,
|
for_loop: Option<&ForLoop<'_>>,
|
||||||
) {
|
) {
|
||||||
match never_loop_block(cx, block, &mut Vec::new(), loop_id) {
|
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| {
|
span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
|
||||||
if let Some(ForLoop {
|
if let Some(ForLoop {
|
||||||
arg: iterator,
|
arg: iterator,
|
||||||
@ -39,67 +38,76 @@ pub(super) fn check<'tcx>(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
|
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Normal => (),
|
||||||
NeverLoopResult::IgnoreUntilEnd(_) => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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)]
|
#[derive(Copy, Clone)]
|
||||||
enum NeverLoopResult {
|
enum NeverLoopResult {
|
||||||
// A break/return always get triggered but not necessarily for the main loop.
|
/// A continue may occur for the main loop.
|
||||||
AlwaysBreak,
|
|
||||||
// A continue may occur for the main loop.
|
|
||||||
MayContinueMainLoop,
|
MayContinueMainLoop,
|
||||||
// Ignore everything until the end of the block with this id
|
/// We have not encountered any main loop continue,
|
||||||
IgnoreUntilEnd(HirId),
|
/// but we are diverging (subsequent control flow is not reachable)
|
||||||
Otherwise,
|
Diverging,
|
||||||
|
/// We have not encountered any main loop continue,
|
||||||
|
/// and subsequent control flow is (possibly) reachable
|
||||||
|
Normal,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
|
fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
|
||||||
match arg {
|
match arg {
|
||||||
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
|
NeverLoopResult::Diverging | NeverLoopResult::Normal => NeverLoopResult::Normal,
|
||||||
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
|
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
|
||||||
NeverLoopResult::IgnoreUntilEnd(id) => NeverLoopResult::IgnoreUntilEnd(id),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine two results for parts that are called in order.
|
// Combine two results for parts that are called in order.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
|
fn combine_seq(first: NeverLoopResult, second: impl FnOnce() -> NeverLoopResult) -> NeverLoopResult {
|
||||||
match first {
|
match first {
|
||||||
NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop | NeverLoopResult::IgnoreUntilEnd(_) => {
|
NeverLoopResult::Diverging | NeverLoopResult::MayContinueMainLoop => first,
|
||||||
first
|
NeverLoopResult::Normal => second(),
|
||||||
},
|
|
||||||
NeverLoopResult::Otherwise => 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.
|
// Combine two results where only one of the part may have been executed.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirId]) -> NeverLoopResult {
|
fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
|
||||||
match (b1, b2) {
|
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::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>(
|
fn never_loop_block<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
block: &Block<'tcx>,
|
block: &Block<'tcx>,
|
||||||
ignore_ids: &mut Vec<HirId>,
|
local_labels: &mut Vec<(HirId, bool)>,
|
||||||
main_loop_id: HirId,
|
main_loop_id: HirId,
|
||||||
) -> NeverLoopResult {
|
) -> NeverLoopResult {
|
||||||
let iter = block
|
let iter = block
|
||||||
@ -107,15 +115,21 @@ fn never_loop_block<'tcx>(
|
|||||||
.iter()
|
.iter()
|
||||||
.filter_map(stmt_to_expr)
|
.filter_map(stmt_to_expr)
|
||||||
.chain(block.expr.map(|expr| (expr, None)));
|
.chain(block.expr.map(|expr| (expr, None)));
|
||||||
|
combine_seq_many(iter.map(|(e, els)| {
|
||||||
iter.map(|(e, els)| {
|
let e = never_loop_expr(cx, e, local_labels, 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 is an else block in a let...else binding
|
||||||
els.map_or(e, |els| {
|
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>>)> {
|
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>(
|
fn never_loop_expr<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
expr: &Expr<'tcx>,
|
expr: &Expr<'tcx>,
|
||||||
ignore_ids: &mut Vec<HirId>,
|
local_labels: &mut Vec<(HirId, bool)>,
|
||||||
main_loop_id: HirId,
|
main_loop_id: HirId,
|
||||||
) -> NeverLoopResult {
|
) -> NeverLoopResult {
|
||||||
match expr.kind {
|
let result = match expr.kind {
|
||||||
ExprKind::Unary(_, e)
|
ExprKind::Unary(_, e)
|
||||||
| ExprKind::Cast(e, _)
|
| ExprKind::Cast(e, _)
|
||||||
| ExprKind::Type(e, _)
|
| ExprKind::Type(e, _)
|
||||||
| ExprKind::Field(e, _)
|
| ExprKind::Field(e, _)
|
||||||
| ExprKind::AddrOf(_, _, e)
|
| ExprKind::AddrOf(_, _, e)
|
||||||
| ExprKind::Repeat(e, _)
|
| ExprKind::Repeat(e, _)
|
||||||
| ExprKind::DropTemps(e) => never_loop_expr(cx, e, 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, ignore_ids, 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, &mut es.iter(), ignore_ids, 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(
|
ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all(
|
||||||
cx,
|
cx,
|
||||||
&mut std::iter::once(receiver).chain(es.iter()),
|
std::iter::once(receiver).chain(es.iter()),
|
||||||
ignore_ids,
|
local_labels,
|
||||||
main_loop_id,
|
main_loop_id,
|
||||||
),
|
),
|
||||||
ExprKind::Struct(_, fields, base) => {
|
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 {
|
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 {
|
} else {
|
||||||
fields
|
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::Binary(_, e1, e2)
|
||||||
| ExprKind::Assign(e1, e2, _)
|
| ExprKind::Assign(e1, e2, _)
|
||||||
| ExprKind::AssignOp(_, e1, e2)
|
| ExprKind::AssignOp(_, e1, e2)
|
||||||
| ExprKind::Index(e1, e2, _) => {
|
| ExprKind::Index(e1, e2, _) => never_loop_expr_all(cx, [e1, e2].iter().copied(), local_labels, main_loop_id),
|
||||||
never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id)
|
|
||||||
},
|
|
||||||
ExprKind::Loop(b, _, _, _) => {
|
ExprKind::Loop(b, _, _, _) => {
|
||||||
// Break can come from the inner loop so remove them.
|
// We don't attempt to track reachability after a loop,
|
||||||
absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id))
|
// 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) => {
|
ExprKind::If(e, e2, e3) => {
|
||||||
let e1 = never_loop_expr(cx, e, ignore_ids, main_loop_id);
|
let e1 = never_loop_expr(cx, e, local_labels, main_loop_id);
|
||||||
let e2 = never_loop_expr(cx, e2, ignore_ids, main_loop_id);
|
combine_seq(e1, || {
|
||||||
// If we know the `if` condition evaluates to `true`, don't check everything past it; it
|
let e2 = never_loop_expr(cx, e2, local_labels, main_loop_id);
|
||||||
// should just return whatever's evaluated for `e1` and `e2` since `e3` is unreachable
|
let e3 = e3.as_ref().map_or(NeverLoopResult::Normal, |e| {
|
||||||
if let Some(Constant::Bool(true)) = constant(cx, cx.typeck_results(), e) {
|
never_loop_expr(cx, e, local_labels, main_loop_id)
|
||||||
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))
|
combine_branches(e2, e3)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
ExprKind::Match(e, arms, _) => {
|
ExprKind::Match(e, arms, _) => {
|
||||||
let e = never_loop_expr(cx, e, ignore_ids, main_loop_id);
|
let e = never_loop_expr(cx, e, local_labels, main_loop_id);
|
||||||
if arms.is_empty() {
|
combine_seq(e, || {
|
||||||
e
|
arms.iter().fold(NeverLoopResult::Diverging, |a, b| {
|
||||||
} else {
|
combine_branches(a, never_loop_expr(cx, b.body, local_labels, 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)
|
})
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ExprKind::Block(b, l) => {
|
ExprKind::Block(b, l) => {
|
||||||
if l.is_some() {
|
if l.is_some() {
|
||||||
ignore_ids.push(b.hir_id);
|
local_labels.push((b.hir_id, false));
|
||||||
}
|
|
||||||
let ret = never_loop_block(cx, b, ignore_ids, main_loop_id);
|
|
||||||
if l.is_some() {
|
|
||||||
ignore_ids.pop();
|
|
||||||
}
|
}
|
||||||
|
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 {
|
match ret {
|
||||||
NeverLoopResult::IgnoreUntilEnd(a) if a == b.hir_id => NeverLoopResult::Otherwise,
|
NeverLoopResult::Diverging if jumped_to => NeverLoopResult::Normal,
|
||||||
_ => ret,
|
_ => ret,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -211,74 +218,67 @@ fn never_loop_expr<'tcx>(
|
|||||||
if id == main_loop_id {
|
if id == main_loop_id {
|
||||||
NeverLoopResult::MayContinueMainLoop
|
NeverLoopResult::MayContinueMainLoop
|
||||||
} else {
|
} else {
|
||||||
NeverLoopResult::AlwaysBreak
|
NeverLoopResult::Diverging
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
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
|
// checks if break targets a block instead of a loop
|
||||||
ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
|
if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind {
|
||||||
.map_or(NeverLoopResult::IgnoreUntilEnd(t), |e| {
|
if let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t) {
|
||||||
never_loop_expr(cx, e, ignore_ids, main_loop_id)
|
*reachable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NeverLoopResult::Diverging
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ExprKind::Become(e) => combine_seq(never_loop_expr(cx, e, local_labels, main_loop_id), || {
|
||||||
|
NeverLoopResult::Diverging
|
||||||
}),
|
}),
|
||||||
ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
|
ExprKind::InlineAsm(asm) => combine_seq_many(asm.operands.iter().map(|(o, _)| match o {
|
||||||
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, .. } => {
|
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
|
||||||
never_loop_expr(cx, expr, ignore_ids, main_loop_id)
|
never_loop_expr(cx, expr, local_labels, main_loop_id)
|
||||||
},
|
},
|
||||||
InlineAsmOperand::Out { expr, .. } => {
|
InlineAsmOperand::Out { expr, .. } => {
|
||||||
never_loop_expr_all(cx, &mut expr.iter().copied(), ignore_ids, main_loop_id)
|
never_loop_expr_all(cx, expr.iter().copied(), local_labels, main_loop_id)
|
||||||
},
|
},
|
||||||
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
|
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
|
||||||
cx,
|
cx,
|
||||||
&mut once(*in_expr).chain(out_expr.iter().copied()),
|
once(*in_expr).chain(out_expr.iter().copied()),
|
||||||
ignore_ids,
|
local_labels,
|
||||||
main_loop_id,
|
main_loop_id,
|
||||||
),
|
),
|
||||||
InlineAsmOperand::Const { .. }
|
InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => {
|
||||||
| InlineAsmOperand::SymFn { .. }
|
NeverLoopResult::Normal
|
||||||
| InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
|
},
|
||||||
})
|
})),
|
||||||
.fold(NeverLoopResult::Otherwise, combine_seq),
|
|
||||||
ExprKind::OffsetOf(_, _)
|
ExprKind::OffsetOf(_, _)
|
||||||
| ExprKind::Yield(_, _)
|
| ExprKind::Yield(_, _)
|
||||||
| ExprKind::Closure { .. }
|
| ExprKind::Closure { .. }
|
||||||
| ExprKind::Path(_)
|
| ExprKind::Path(_)
|
||||||
| ExprKind::ConstBlock(_)
|
| ExprKind::ConstBlock(_)
|
||||||
| ExprKind::Lit(_)
|
| 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>>>(
|
fn never_loop_expr_all<'tcx, T: Iterator<Item = &'tcx Expr<'tcx>>>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
es: &mut T,
|
es: T,
|
||||||
ignore_ids: &mut Vec<HirId>,
|
local_labels: &mut Vec<(HirId, bool)>,
|
||||||
main_loop_id: HirId,
|
main_loop_id: HirId,
|
||||||
) -> NeverLoopResult {
|
) -> NeverLoopResult {
|
||||||
es.map(|e| never_loop_expr(cx, e, ignore_ids, main_loop_id))
|
combine_seq_many(es.map(|e| never_loop_expr(cx, e, local_labels, 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>,
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
|
fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
|
||||||
|
@ -3,7 +3,8 @@ fn main() {}
|
|||||||
fn no_panic<T>(slice: &[T]) {
|
fn no_panic<T>(slice: &[T]) {
|
||||||
let mut iter = slice.iter();
|
let mut iter = slice.iter();
|
||||||
loop {
|
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`
|
//~| NOTE: `-D clippy::while-let-loop` implied by `-D warnings`
|
||||||
let _ = match iter.next() {
|
let _ = match iter.next() {
|
||||||
Some(ele) => ele,
|
Some(ele) => ele,
|
||||||
|
@ -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
|
error: this loop could be written as a `while let` loop
|
||||||
--> $DIR/ice-360.rs:5:5
|
--> $DIR/ice-360.rs:5:5
|
||||||
|
|
|
|
||||||
LL | / loop {
|
LL | / loop {
|
||||||
LL | |
|
LL | |
|
||||||
LL | |
|
LL | |
|
||||||
LL | | let _ = match iter.next() {
|
LL | |
|
||||||
... |
|
... |
|
||||||
LL | |
|
LL | |
|
||||||
LL | | }
|
LL | | }
|
||||||
@ -13,7 +27,7 @@ LL | | }
|
|||||||
= note: `-D clippy::while-let-loop` implied by `-D warnings`
|
= note: `-D clippy::while-let-loop` implied by `-D warnings`
|
||||||
|
|
||||||
error: empty `loop {}` wastes CPU cycles
|
error: empty `loop {}` wastes CPU cycles
|
||||||
--> $DIR/ice-360.rs:12:9
|
--> $DIR/ice-360.rs:13:9
|
||||||
|
|
|
|
||||||
LL | loop {}
|
LL | loop {}
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
@ -21,5 +35,5 @@ LL | loop {}
|
|||||||
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
|
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
|
||||||
= note: `-D clippy::empty-loop` implied by `-D warnings`
|
= note: `-D clippy::empty-loop` implied by `-D warnings`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
@ -7,10 +7,12 @@ use proc_macros::{external, inline_macros};
|
|||||||
|
|
||||||
fn should_trigger() {
|
fn should_trigger() {
|
||||||
loop {}
|
loop {}
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
loop {
|
loop {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
'inner: loop {}
|
'inner: loop {}
|
||||||
}
|
}
|
||||||
@ -18,6 +20,7 @@ fn should_trigger() {
|
|||||||
|
|
||||||
#[inline_macros]
|
#[inline_macros]
|
||||||
fn should_not_trigger() {
|
fn should_not_trigger() {
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
loop {
|
loop {
|
||||||
panic!("This is fine")
|
panic!("This is fine")
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ LL | loop {}
|
|||||||
= note: `-D clippy::empty-loop` implied by `-D warnings`
|
= note: `-D clippy::empty-loop` implied by `-D warnings`
|
||||||
|
|
||||||
error: empty `loop {}` wastes CPU cycles
|
error: empty `loop {}` wastes CPU cycles
|
||||||
--> $DIR/empty_loop.rs:11:9
|
--> $DIR/empty_loop.rs:12:9
|
||||||
|
|
|
|
||||||
LL | loop {}
|
LL | loop {}
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
@ -16,7 +16,7 @@ LL | loop {}
|
|||||||
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
|
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
|
||||||
|
|
||||||
error: empty `loop {}` wastes CPU cycles
|
error: empty `loop {}` wastes CPU cycles
|
||||||
--> $DIR/empty_loop.rs:15:9
|
--> $DIR/empty_loop.rs:17:9
|
||||||
|
|
|
|
||||||
LL | 'inner: loop {}
|
LL | 'inner: loop {}
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
@ -8,6 +8,7 @@ fn opaque_empty_iter() -> impl Iterator<Item = ()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
for _ in [1, 2, 3].iter().skip(4) {
|
for _ in [1, 2, 3].iter().skip(4) {
|
||||||
//~^ ERROR: this `.skip()` call skips more items than the iterator will produce
|
//~^ ERROR: this `.skip()` call skips more items than the iterator will produce
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: this `.skip()` call skips more items than the iterator will produce
|
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) {
|
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
|
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() {
|
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
|
= 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
|
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) {}
|
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
|
= 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
|
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) {}
|
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
|
= note: this operation is useless and will create an empty iterator
|
||||||
|
|
||||||
error: this `.skip()` call skips more items than the iterator will produce
|
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) {}
|
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
|
= note: this operation is useless and will create an empty iterator
|
||||||
|
|
||||||
error: this `.skip()` call skips more items than the iterator will produce
|
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) {}
|
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
|
= note: this operation is useless and will create an empty iterator
|
||||||
|
|
||||||
error: this `.skip()` call skips more items than the iterator will produce
|
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) {}
|
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
|
= note: this operation is useless and will create an empty iterator
|
||||||
|
|
||||||
error: this `.skip()` call skips more items than the iterator will produce
|
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) {}
|
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
|
= note: this operation is useless and will create an empty iterator
|
||||||
|
|
||||||
error: this `.skip()` call skips more items than the iterator will produce
|
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) {}
|
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
|
= note: this operation is useless and will create an empty iterator
|
||||||
|
|
||||||
error: this `.skip()` call skips more items than the iterator will produce
|
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) {}
|
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
|
= note: this operation is useless and will create an empty iterator
|
||||||
|
|
||||||
error: this `.take()` call takes more items than the iterator will produce
|
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) {}
|
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
|
= 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
|
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) {}
|
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
|
= note: this operation is useless and will create an empty iterator
|
||||||
|
|
||||||
error: this `.take()` call takes more items than the iterator will produce
|
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) {}
|
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
|
= 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
|
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) {
|
LL | for x in [].iter().take(1) {
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
@ -260,6 +260,7 @@ mod issue_8553 {
|
|||||||
let w = v.iter().collect::<Vec<_>>();
|
let w = v.iter().collect::<Vec<_>>();
|
||||||
//~^ ERROR: avoid using `collect()` when not needed
|
//~^ ERROR: avoid using `collect()` when not needed
|
||||||
// Do lint
|
// Do lint
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
for _ in 0..w.len() {
|
for _ in 0..w.len() {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
@ -270,6 +271,7 @@ mod issue_8553 {
|
|||||||
let v: Vec<usize> = vec.iter().map(|i| i * i).collect();
|
let v: Vec<usize> = vec.iter().map(|i| i * i).collect();
|
||||||
let w = v.iter().collect::<Vec<_>>();
|
let w = v.iter().collect::<Vec<_>>();
|
||||||
// Do not lint, because w is used.
|
// Do not lint, because w is used.
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
for _ in 0..w.len() {
|
for _ in 0..w.len() {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
@ -283,6 +285,7 @@ mod issue_8553 {
|
|||||||
let mut w = v.iter().collect::<Vec<_>>();
|
let mut w = v.iter().collect::<Vec<_>>();
|
||||||
//~^ ERROR: avoid using `collect()` when not needed
|
//~^ ERROR: avoid using `collect()` when not needed
|
||||||
// Do lint
|
// Do lint
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
while 1 == w.len() {
|
while 1 == w.len() {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
@ -293,6 +296,7 @@ mod issue_8553 {
|
|||||||
let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
|
let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
|
||||||
let mut w = v.iter().collect::<Vec<_>>();
|
let mut w = v.iter().collect::<Vec<_>>();
|
||||||
// Do not lint, because w is used.
|
// Do not lint, because w is used.
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
while 1 == w.len() {
|
while 1 == w.len() {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
@ -306,6 +310,7 @@ mod issue_8553 {
|
|||||||
let mut w = v.iter().collect::<Vec<_>>();
|
let mut w = v.iter().collect::<Vec<_>>();
|
||||||
//~^ ERROR: avoid using `collect()` when not needed
|
//~^ ERROR: avoid using `collect()` when not needed
|
||||||
// Do lint
|
// Do lint
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
while let Some(i) = Some(w.len()) {
|
while let Some(i) = Some(w.len()) {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
@ -316,6 +321,7 @@ mod issue_8553 {
|
|||||||
let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
|
let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
|
||||||
let mut w = v.iter().collect::<Vec<_>>();
|
let mut w = v.iter().collect::<Vec<_>>();
|
||||||
// Do not lint, because w is used.
|
// Do not lint, because w is used.
|
||||||
|
#[allow(clippy::never_loop)]
|
||||||
while let Some(i) = Some(w.len()) {
|
while let Some(i) = Some(w.len()) {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
@ -230,11 +230,12 @@ help: take the original Iterator's count instead of collecting it and finding th
|
|||||||
LL ~
|
LL ~
|
||||||
LL |
|
LL |
|
||||||
LL | // Do lint
|
LL | // Do lint
|
||||||
|
LL | #[allow(clippy::never_loop)]
|
||||||
LL ~ for _ in 0..v.iter().count() {
|
LL ~ for _ in 0..v.iter().count() {
|
||||||
|
|
|
|
||||||
|
|
||||||
error: avoid using `collect()` when not needed
|
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<_>>();
|
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 |
|
LL |
|
||||||
LL | // Do lint
|
LL | // Do lint
|
||||||
|
LL | #[allow(clippy::never_loop)]
|
||||||
LL ~ while 1 == v.iter().count() {
|
LL ~ while 1 == v.iter().count() {
|
||||||
|
|
|
|
||||||
|
|
||||||
error: avoid using `collect()` when not needed
|
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<_>>();
|
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 |
|
LL |
|
||||||
LL | // Do lint
|
LL | // Do lint
|
||||||
|
LL | #[allow(clippy::never_loop)]
|
||||||
LL ~ while let Some(i) = Some(v.iter().count()) {
|
LL ~ while let Some(i) = Some(v.iter().count()) {
|
||||||
|
|
|
|
||||||
|
|
||||||
|
@ -337,10 +337,8 @@ pub fn test26() {
|
|||||||
|
|
||||||
pub fn test27() {
|
pub fn test27() {
|
||||||
loop {
|
loop {
|
||||||
//~^ ERROR: this loop never actually loops
|
|
||||||
'label: {
|
'label: {
|
||||||
let x = true;
|
let x = true;
|
||||||
// Lints because we cannot prove it's always `true`
|
|
||||||
if x {
|
if x {
|
||||||
break 'label;
|
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() {
|
fn main() {
|
||||||
test1();
|
test1();
|
||||||
test2();
|
test2();
|
||||||
|
@ -153,16 +153,22 @@ LL | if let Some(_) = (0..20).next() {
|
|||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: this loop never actually loops
|
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 | / loop {
|
||||||
LL | |
|
LL | |
|
||||||
LL | | 'label: {
|
LL | | panic!("oh no");
|
||||||
LL | | let x = true;
|
|
||||||
... |
|
|
||||||
LL | | }
|
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
||||||
error: aborting due to 14 previous errors
|
error: aborting due to 15 previous errors
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
unused,
|
unused,
|
||||||
clippy::println_empty_string,
|
clippy::println_empty_string,
|
||||||
clippy::empty_loop,
|
clippy::empty_loop,
|
||||||
|
clippy::never_loop,
|
||||||
clippy::diverging_sub_expression,
|
clippy::diverging_sub_expression,
|
||||||
clippy::let_unit_value
|
clippy::let_unit_value
|
||||||
)]
|
)]
|
||||||
|
@ -1,84 +1,84 @@
|
|||||||
error: binding's name is too similar to existing binding
|
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;
|
LL | let bpple: i32;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
note: existing binding defined here
|
note: existing binding defined here
|
||||||
--> $DIR/similar_names.rs:19:9
|
--> $DIR/similar_names.rs:20:9
|
||||||
|
|
|
|
||||||
LL | let apple: i32;
|
LL | let apple: i32;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
= note: `-D clippy::similar-names` implied by `-D warnings`
|
= note: `-D clippy::similar-names` implied by `-D warnings`
|
||||||
|
|
||||||
error: binding's name is too similar to existing binding
|
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;
|
LL | let cpple: i32;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
note: existing binding defined here
|
note: existing binding defined here
|
||||||
--> $DIR/similar_names.rs:19:9
|
--> $DIR/similar_names.rs:20:9
|
||||||
|
|
|
|
||||||
LL | let apple: i32;
|
LL | let apple: i32;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: binding's name is too similar to existing binding
|
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;
|
LL | let bluby: i32;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
note: existing binding defined here
|
note: existing binding defined here
|
||||||
--> $DIR/similar_names.rs:48:9
|
--> $DIR/similar_names.rs:49:9
|
||||||
|
|
|
|
||||||
LL | let blubx: i32;
|
LL | let blubx: i32;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: binding's name is too similar to existing binding
|
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;
|
LL | let coke: i32;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
note: existing binding defined here
|
note: existing binding defined here
|
||||||
--> $DIR/similar_names.rs:52:9
|
--> $DIR/similar_names.rs:53:9
|
||||||
|
|
|
|
||||||
LL | let cake: i32;
|
LL | let cake: i32;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: binding's name is too similar to existing binding
|
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;
|
LL | let xyzeabc: i32;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
note: existing binding defined here
|
note: existing binding defined here
|
||||||
--> $DIR/similar_names.rs:71:9
|
--> $DIR/similar_names.rs:72:9
|
||||||
|
|
|
|
||||||
LL | let xyz1abc: i32;
|
LL | let xyz1abc: i32;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: binding's name is too similar to existing binding
|
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;
|
LL | let parsee: i32;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
note: existing binding defined here
|
note: existing binding defined here
|
||||||
--> $DIR/similar_names.rs:76:9
|
--> $DIR/similar_names.rs:77:9
|
||||||
|
|
|
|
||||||
LL | let parser: i32;
|
LL | let parser: i32;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: binding's name is too similar to existing binding
|
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,
|
LL | bpple: sprang,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
note: existing binding defined here
|
note: existing binding defined here
|
||||||
--> $DIR/similar_names.rs:99:16
|
--> $DIR/similar_names.rs:100:16
|
||||||
|
|
|
|
||||||
LL | apple: spring,
|
LL | apple: spring,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#![warn(clippy::useless_vec)]
|
#![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;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#![warn(clippy::useless_vec)]
|
#![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;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:30:14
|
--> $DIR/vec.rs:35:14
|
||||||
|
|
|
|
||||||
LL | on_slice(&vec![]);
|
LL | on_slice(&vec![]);
|
||||||
| ^^^^^^^ help: you can use a slice directly: `&[]`
|
| ^^^^^^^ help: you can use a slice directly: `&[]`
|
||||||
@ -7,109 +7,109 @@ LL | on_slice(&vec![]);
|
|||||||
= note: `-D clippy::useless-vec` implied by `-D warnings`
|
= note: `-D clippy::useless-vec` implied by `-D warnings`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:32:18
|
--> $DIR/vec.rs:37:18
|
||||||
|
|
|
|
||||||
LL | on_mut_slice(&mut vec![]);
|
LL | on_mut_slice(&mut vec![]);
|
||||||
| ^^^^^^^^^^^ help: you can use a slice directly: `&mut []`
|
| ^^^^^^^^^^^ help: you can use a slice directly: `&mut []`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:34:14
|
--> $DIR/vec.rs:39:14
|
||||||
|
|
|
|
||||||
LL | on_slice(&vec![1, 2]);
|
LL | on_slice(&vec![1, 2]);
|
||||||
| ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
|
| ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:36:18
|
--> $DIR/vec.rs:41:18
|
||||||
|
|
|
|
||||||
LL | on_mut_slice(&mut vec![1, 2]);
|
LL | on_mut_slice(&mut vec![1, 2]);
|
||||||
| ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
|
| ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:38:14
|
--> $DIR/vec.rs:43:14
|
||||||
|
|
|
|
||||||
LL | on_slice(&vec![1, 2]);
|
LL | on_slice(&vec![1, 2]);
|
||||||
| ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
|
| ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:40:18
|
--> $DIR/vec.rs:45:18
|
||||||
|
|
|
|
||||||
LL | on_mut_slice(&mut vec![1, 2]);
|
LL | on_mut_slice(&mut vec![1, 2]);
|
||||||
| ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
|
| ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:42:14
|
--> $DIR/vec.rs:47:14
|
||||||
|
|
|
|
||||||
LL | on_slice(&vec!(1, 2));
|
LL | on_slice(&vec!(1, 2));
|
||||||
| ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
|
| ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:44:18
|
--> $DIR/vec.rs:49:18
|
||||||
|
|
|
|
||||||
LL | on_mut_slice(&mut vec![1, 2]);
|
LL | on_mut_slice(&mut vec![1, 2]);
|
||||||
| ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
|
| ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:46:14
|
--> $DIR/vec.rs:51:14
|
||||||
|
|
|
|
||||||
LL | on_slice(&vec![1; 2]);
|
LL | on_slice(&vec![1; 2]);
|
||||||
| ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]`
|
| ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:48:18
|
--> $DIR/vec.rs:53:18
|
||||||
|
|
|
|
||||||
LL | on_mut_slice(&mut vec![1; 2]);
|
LL | on_mut_slice(&mut vec![1; 2]);
|
||||||
| ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]`
|
| ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
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();
|
LL | let _x: i32 = vec![1, 2, 3].iter().sum();
|
||||||
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
|
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:77:17
|
--> $DIR/vec.rs:82:17
|
||||||
|
|
|
|
||||||
LL | let mut x = vec![1, 2, 3];
|
LL | let mut x = vec![1, 2, 3];
|
||||||
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
|
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:83:22
|
--> $DIR/vec.rs:88:22
|
||||||
|
|
|
|
||||||
LL | let _x: &[i32] = &vec![1, 2, 3];
|
LL | let _x: &[i32] = &vec![1, 2, 3];
|
||||||
| ^^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]`
|
| ^^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:85:14
|
--> $DIR/vec.rs:90:14
|
||||||
|
|
|
|
||||||
LL | for _ in vec![1, 2, 3] {}
|
LL | for _ in vec![1, 2, 3] {}
|
||||||
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
|
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:123:20
|
--> $DIR/vec.rs:128:20
|
||||||
|
|
|
|
||||||
LL | for _string in vec![repro!(true), repro!(null)] {
|
LL | for _string in vec![repro!(true), repro!(null)] {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
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]);
|
LL | in_macro!(1, vec![1, 2], vec![1; 2]);
|
||||||
| ^^^^^^^^^^ help: you can use an array directly: `[1, 2]`
|
| ^^^^^^^^^^ help: you can use an array directly: `[1, 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
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]);
|
LL | in_macro!(1, vec![1, 2], vec![1; 2]);
|
||||||
| ^^^^^^^^^^ help: you can use an array directly: `[1; 2]`
|
| ^^^^^^^^^^ help: you can use an array directly: `[1; 2]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:159:14
|
--> $DIR/vec.rs:164:14
|
||||||
|
|
|
|
||||||
LL | for a in vec![1, 2, 3] {
|
LL | for a in vec![1, 2, 3] {
|
||||||
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
|
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
|
||||||
|
|
||||||
error: useless use of `vec!`
|
error: useless use of `vec!`
|
||||||
--> $DIR/vec.rs:163:14
|
--> $DIR/vec.rs:168:14
|
||||||
|
|
|
|
||||||
LL | for a in vec![String::new(), String::new()] {
|
LL | for a in vec![String::new(), String::new()] {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user