rust-lang / rust-lang/rust-clippy

collapsible_match merges conditions when nested condition consumes variable

Open
#16,933 2 comments 0 reactions 1 assignee View on GitHub

@Kokoro2336 is already working on this.

Since May 1, 2026.

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

Description

Summary

In a match, one of my arms has an if inside which consumes a variable. collapsible_match suggests collapsing the if into the match's condition, and even performs the fix, but the fix does not compile, since the if consumes a variable which is referrenced in other arms.

Lint Name

collapsible_match

Reproducer

I tried this code:

    for item in <(pem::SectionKind, Vec<u8>) as PemObject>::pem_file_iter(path)? {
        let (kind, der) = item?;
        match kind {
            pem::SectionKind::Certificate => {
                certs.push(CertificateDer::from(der));
            }
            pem::SectionKind::EcPrivateKey => {
                if raw_key.replace(PrivateKeyDer::Sec1(der.into())).is_some() {
                    bail!("multiple keys found in {}", path.to_string_lossy());
                }
            }
            pem::SectionKind::PrivateKey => {
                if raw_key.replace(PrivateKeyDer::Pkcs8(der.into())).is_some() {
                    bail!("multiple keys found in {}", path.to_string_lossy());
                }
            }
            pem::SectionKind::RsaPrivateKey => {
                if raw_key.replace(PrivateKeyDer::Pkcs1(der.into())).is_some() {
                    bail!("multiple keys found in {}", path.to_string_lossy());
                }
            }
            _ => {}
        }
    }

I saw this happen:

> cargo clippy --allow-dirty --fix
   Compiling pimsync v0.0.0 (/home/hugo/src/git.sr.ht/~whynothugo/pimsync)
warning: failed to automatically apply fixes suggested by rustc to crate `pimsync`

after fixes were automatically applied the compiler reported errors within these files:

  * src/tls.rs

This likely indicates a bug in either rustc or cargo itself,
and we would appreciate a bug report! You're likely to see
a number of compiler warnings after this message which cargo
attempted to fix but failed. If you could open an issue at
https://github.com/rust-lang/rust-clippy/issues
quoting the full output of this command we'd be very appreciative!
Note that you may be able to make some more progress in the near-term
fixing code with the `--broken-code` flag

The following errors were reported:
error[E0382]: use of moved value: `der`
   --> src/tls.rs:183:57
    |
173 |         let (kind, der) = item?;
    |                    ---
    |                    |
    |                    this reinitialization might get skipped
    |                    move occurs because `der` has type `std::vec::Vec<u8>`, which does not implement the `Copy` trait
...
179 |                 if raw_key.replace(PrivateKeyDer::Sec1(der.into())).is_some() => {
    |                                                            ------ `der` moved due to this method call
...
183 |                 if raw_key.replace(PrivateKeyDer::Pkcs8(der.into())).is_some() => {
    |                                                         ^^^ value used here after move
    |
note: `std::convert::Into::into` takes ownership of the receiver `self`, which moves `der`
   --> /rustc/59807616e1fa2540724bfbac14d7976d7e4a3860/library/core/src/convert/mod.rs:455:12
help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
179 |                 if raw_key.replace(PrivateKeyDer::Sec1(der.clone().into())).is_some() => {
    |                                                           ++++++++

error[E0382]: use of moved value: `der`
   --> src/tls.rs:187:57
    |
173 |         let (kind, der) = item?;
    |                    ---
    |                    |
    |                    this reinitialization might get skipped
    |                    move occurs because `der` has type `std::vec::Vec<u8>`, which does not implement the `Copy` trait
...
179 |                 if raw_key.replace(PrivateKeyDer::Sec1(der.into())).is_some() => {
    |                                                            ------ `der` moved due to this method call
...
183 |                 if raw_key.replace(PrivateKeyDer::Pkcs8(der.into())).is_some() => {
    |                                                             ------ `der` moved due to this method call
...
187 |                 if raw_key.replace(PrivateKeyDer::Pkcs1(der.into())).is_some() => {
    |                                                         ^^^ value used here after move
    |
help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
183 |                 if raw_key.replace(PrivateKeyDer::Pkcs8(der.clone().into())).is_some() => {
    |                                                            ++++++++
help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
179 |                 if raw_key.replace(PrivateKeyDer::Sec1(der.clone().into())).is_some() => {
    |                                                           ++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0382`.
Original diagnostics will follow.

warning: this `if` can be collapsed into the outer `match`
   --> src/tls.rs:179:17
    |
179 | /                 if raw_key.replace(PrivateKeyDer::Sec1(der.into())).is_some() {
180 | |                     bail!("multiple keys found in {}", path.to_string_lossy());
181 | |                 }
    | |_________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#collapsible_match
    = note: `#[warn(clippy::collapsible_match)]` on by default
help: collapse nested if block
    |
178 ~             pem::SectionKind::EcPrivateKey
179 ~                 if raw_key.replace(PrivateKeyDer::Sec1(der.into())).is_some() => {
180 |                     bail!("multiple keys found in {}", path.to_string_lossy());
181 ~                 }
    |

warning: this `if` can be collapsed into the outer `match`
   --> src/tls.rs:184:17
    |
184 | /                 if raw_key.replace(PrivateKeyDer::Pkcs8(der.into())).is_some() {
185 | |                     bail!("multiple keys found in {}", path.to_string_lossy());
186 | |                 }
    | |_________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#collapsible_match
help: collapse nested if block
    |
183 ~             pem::SectionKind::PrivateKey
184 ~                 if raw_key.replace(PrivateKeyDer::Pkcs8(der.into())).is_some() => {
185 |                     bail!("multiple keys found in {}", path.to_string_lossy());
186 ~                 }
    |

warning: this `if` can be collapsed into the outer `match`
   --> src/tls.rs:189:17
    |
189 | /                 if raw_key.replace(PrivateKeyDer::Pkcs1(der.into())).is_some() {
190 | |                     bail!("multiple keys found in {}", path.to_string_lossy());
191 | |                 }
    | |_________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#collapsible_match
help: collapse nested if block
    |
188 ~             pem::SectionKind::RsaPrivateKey
189 ~                 if raw_key.replace(PrivateKeyDer::Pkcs1(der.into())).is_some() => {
190 |                     bail!("multiple keys found in {}", path.to_string_lossy());
191 ~                 }
    |

warning: `pimsync` (bin "pimsync") generated 3 warnings (run `cargo clippy --fix --bin "pimsync" -p pimsync -- --no-deps` to apply 3 suggestions)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.10s

I expected to see this happen:

No warning; these conditions cannot be collapsed. This is a false positive, and the "fix" is invalid.

Version
rustc 1.95.0 (59807616e 2026-04-14) (Alpine Linux Rust 1.95.0-r0)
binary: rustc
commit-hash: 59807616e1fa2540724bfbac14d7976d7e4a3860
commit-date: 2026-04-14
host: x86_64-alpine-linux-musl
release: 1.95.0
LLVM version: 22.1.3
Additional Labels

Vaguely similar to https://github.com/rust-lang/rust-clippy/issues/16903, although that issue is about mutable borrows and this one is about the variable being consumed.

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.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.