diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 2b580452a60eb..e571636dfbf1a 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -89,6 +89,59 @@ declare_lint! { } declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]); +#[derive(Debug)] +enum LogicPredicts { + Unknown, + True, + False, + Diverging, +} + +fn is_never_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { + if cx.typeck_results().expr_ty(e).is_never() { + return true; + } + match e.kind { + rustc_hir::ExprKind::Block(ref inner, _) => { + if let Some(ein) = inner.expr { + return is_never_expr(cx, ein); + } + return false; + } + _ => false, + } +} + +fn predicte_logic_operation(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> LogicPredicts { + if is_never_expr(cx, e) { + return LogicPredicts::Diverging; + } + let result = match e.kind { + hir::ExprKind::Binary(bin_op, e1, e2) => match bin_op.node { + hir::BinOpKind::And => match predicte_logic_operation(cx, e1) { + LogicPredicts::False => LogicPredicts::False, + LogicPredicts::True => predicte_logic_operation(cx, e2), + LogicPredicts::Diverging => LogicPredicts::Diverging, + LogicPredicts::Unknown => match predicte_logic_operation(cx, e2) { + LogicPredicts::Diverging | LogicPredicts::False => LogicPredicts::False, + _ => LogicPredicts::Unknown, + }, + }, + hir::BinOpKind::Or => match predicte_logic_operation(cx, e1) { + LogicPredicts::True => LogicPredicts::True, + LogicPredicts::False => predicte_logic_operation(cx, e2), + LogicPredicts::Diverging => LogicPredicts::Diverging, + LogicPredicts::Unknown => match predicte_logic_operation(cx, e2) { + LogicPredicts::Diverging | LogicPredicts::True => LogicPredicts::True, + _ => LogicPredicts::Unknown, + }, + }, + _ => LogicPredicts::Unknown, + }, + _ => LogicPredicts::Unknown, + }; + result +} impl<'tcx> LateLintPass<'tcx> for UnusedResults { fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { @@ -147,7 +200,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { | hir::BinOpKind::Div | hir::BinOpKind::Mul | hir::BinOpKind::Rem => Some("arithmetic operation"), - hir::BinOpKind::And | hir::BinOpKind::Or => Some("logical operation"), + hir::BinOpKind::And | hir::BinOpKind::Or => { + match predicte_logic_operation(cx, expr) { + LogicPredicts::Unknown => Some("logical operation"), + _ => None, + } + } hir::BinOpKind::BitXor | hir::BinOpKind::BitAnd | hir::BinOpKind::BitOr diff --git a/src/test/ui/lint/unused/issue-85913.rs b/src/test/ui/lint/unused/issue-85913.rs index 7f3817b6ef1cc..7692f4f7d9e20 100644 --- a/src/test/ui/lint/unused/issue-85913.rs +++ b/src/test/ui/lint/unused/issue-85913.rs @@ -1,8 +1,47 @@ #![deny(unused_must_use)] +fn fire_missiles() -> bool { + true +} + +fn is_missiles_ready() -> bool { + true +} + +fn bang() -> ! { + loop {} +} + pub fn fun() -> i32 { function() && return 1; + is_missiles_ready() && fire_missiles(); + //~^ ERROR: unused logical operation that must be used + !is_missiles_ready() || fire_missiles(); + //~^ ERROR: unused logical operation that must be used + fire_missiles() || panic!("failed"); + fire_missiles() && bang(); + fire_missiles() || { panic!("failed"); }; + fire_missiles() && { bang(); }; + fire_missiles() || { panic!("failed") }; + fire_missiles() && { bang() }; + is_missiles_ready() && fire_missiles() || panic!("failed"); + !is_missiles_ready() || fire_missiles() && panic!("booom"); + //~^ ERROR: unused logical operation that must be used + is_missiles_ready() && fire_missiles() || return 5; + !is_missiles_ready() || { + fire_missiles(); + panic!("booom"); + }; + !is_missiles_ready() || { //~^ ERROR: unused logical operation that must be used + if fire_missiles() { + panic!("booom"); + } + println!("failed"); + false + }; + fire_missiles() && fire_missiles() && panic!("2x booom"); + fire_missiles() && fire_missiles() || panic!("2x booom"); return 0; } diff --git a/src/test/ui/lint/unused/issue-85913.stderr b/src/test/ui/lint/unused/issue-85913.stderr index 8234ed3b1678c..edef94c42a4a8 100644 --- a/src/test/ui/lint/unused/issue-85913.stderr +++ b/src/test/ui/lint/unused/issue-85913.stderr @@ -1,8 +1,8 @@ error: unused logical operation that must be used - --> $DIR/issue-85913.rs:4:5 + --> $DIR/issue-85913.rs:17:5 | -LL | function() && return 1; - | ^^^^^^^^^^^^^^^^^^^^^^ the logical operation produces a value +LL | is_missiles_ready() && fire_missiles(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the logical operation produces a value | note: the lint level is defined here --> $DIR/issue-85913.rs:1:9 @@ -11,8 +11,47 @@ LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ help: use `let _ = ...` to ignore the resulting value | -LL | let _ = function() && return 1; +LL | let _ = is_missiles_ready() && fire_missiles(); | +++++++ -error: aborting due to previous error +error: unused logical operation that must be used + --> $DIR/issue-85913.rs:19:5 + | +LL | !is_missiles_ready() || fire_missiles(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the logical operation produces a value + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = !is_missiles_ready() || fire_missiles(); + | +++++++ + +error: unused logical operation that must be used + --> $DIR/issue-85913.rs:28:5 + | +LL | !is_missiles_ready() || fire_missiles() && panic!("booom"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the logical operation produces a value + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = !is_missiles_ready() || fire_missiles() && panic!("booom"); + | +++++++ + +error: unused logical operation that must be used + --> $DIR/issue-85913.rs:35:5 + | +LL | / !is_missiles_ready() || { +LL | | +LL | | if fire_missiles() { +LL | | panic!("booom"); +... | +LL | | false +LL | | }; + | |_____^ the logical operation produces a value + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = !is_missiles_ready() || { + | +++++++ + +error: aborting due to 4 previous errors