rust-lang / rust-lang/rust-clippy
`nonminimal_bool` reorders operands, changing behavior
Nobody has claimed this yet.
- 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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