rust-lang / rust-lang/rust-clippy

`nonminimal_bool` reorders operands, changing behavior

Open
#8,050 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

Summary

In some cases (not sure if this is an actual minimal repro or if it's more complicated than needed, I don't really understand what's going on here), nonminimal_bool will reorder the operands to logical && and || operators, changing behavior if the operands have side effects. I hit this in real-world code, and got lucky that I noticed it after quickly applying clippy's fix - my code was of the form ok_to_insert() && hash_set.insert(...), which would be really bad if flipped.

Reproducer

I tried this code:

fn f() -> bool {
    println!("f() called");
    false
}

fn main() {
    let a = 5;
    let _ = !(a == 2 && !f() || a == 3 && !f());
}

I expected to see a suggestion to rewrite to the following:

let _ = (a != 2 || f()) && (a != 3 || f());

Instead, this happened:

warning: this boolean expression can be simplified
 --> src/main.rs:8:13
  |
8 |     let _ = !(a == 2 && !f() || a == 3 && !f());
  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f() || a != 3) && (f() || a != 2)`
  |
  = note: `#[warn(clippy::nonminimal_bool)]` on by default
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool

This changes the behavior of the program, due to changing the order of short-circuiting operators: the program now prints f() called twice, whereas originally it didn't print anything at all.

Version
rustc 1.56.1 (59eed8a2a 2021-11-01)
binary: rustc
commit-hash: 59eed8a2aac0230a8b53e89d4e99d55912ba6b35
commit-date: 2021-11-01
host: x86_64-unknown-linux-gnu
release: 1.56.1
LLVM version: 13.0.0
Additional Labels

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the nonminimal_bool lint entry point and run the supplied Rust reproducer to observe the operand reordering and side effects. Trace how the suggestion is built, then add a regression case that preserves short-circuit evaluation and verify the lint output no longer changes behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.