Skip to content

match_bool will suggetion will introduce untinitialized binding that still existed in the match arm #15351

@matthiaskrgr

Description

@matthiaskrgr

Using the following flags

--force-warn clippy::match-bool

this code:

#![allow(unused)]

use std::{
    cell::{Cell, RefCell},
    future::Future,
    marker::Unpin,
    panic,
    pin::Pin,
    ptr,
    rc::Rc,
    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};

struct InjectedFailure;

struct Defer<T> {
    ready: bool,
    value: Option<T>,
}

impl<T: Unpin> Future for Defer<T> {
    type Output = T;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        if self.ready {
            Poll::Ready(self.value.take().unwrap())
        } else {
            self.ready = true;
            Poll::Pending
        }
    }
}

/// Allocator tracks the creation and destruction of `Ptr`s.
/// The `failing_op`-th operation will panic.
struct Allocator {
    data: RefCell<Vec<bool>>,
    failing_op: usize,
    cur_ops: Cell<usize>,
}

impl panic::UnwindSafe for Allocator {}
impl panic::RefUnwindSafe for Allocator {}

impl Drop for Allocator {
    fn drop(&mut self) {
        let data = self.data.borrow();
        if data.iter().any(|d| *d) {
            panic!("missing free: {:?}", data);
        }
    }
}

impl Allocator {
    fn new(failing_op: usize) -> Self {
        Allocator { failing_op, cur_ops: Cell::new(0), data: RefCell::new(vec![]) }
    }
    fn alloc(&self) -> impl Future<Output = Ptr<'_>> + '_ {
        self.fallible_operation();

        let mut data = self.data.borrow_mut();

        let addr = data.len();
        data.push(true);
        Defer { ready: false, value: Some(Ptr(addr, self)) }
    }
    fn fallible_operation(&self) {
        self.cur_ops.set(self.cur_ops.get() + 1);

        if self.cur_ops.get() == self.failing_op {
            panic::panic_any(InjectedFailure);
        }
    }
}

// Type that tracks whether it was dropped and can panic when it's created or
// destroyed.
struct Ptr<'a>(usize, &'a Allocator);
impl<'a> Drop for Ptr<'a> {
    fn drop(&mut self) {
        match self.1.data.borrow_mut()[self.0] {
            false => panic!("double free at index {:?}", self.0),
            ref mut d => *d = false,
        }

        self.1.fallible_operation();
    }
}

caused the following diagnostics:

    Checking _a v0.1.0 (/tmp/icemaker_global_tempdir.lAPrPb4j3wVl/icemaker_clippyfix_tempdir.dnKbE3nd6uBx/_a)
warning: `match` on a boolean expression
  --> src/lib.rs:80:9
   |
80 | /         match self.1.data.borrow_mut()[self.0] {
81 | |             false => panic!("double free at index {:?}", self.0),
82 | |             ref mut d => *d = false,
83 | |         }
   | |_________^ help: consider using an `if`/`else` expression: `if !self.1.data.borrow_mut()[self.0] { panic!("double free at index {:?}", self.0) } else { *d = false }`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
   = note: requested on the command line with `--force-warn clippy::match-bool`

warning: `_a` (lib) generated 1 warning (run `cargo clippy --fix --lib -p _a` to apply 1 suggestion)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.40s

However after applying these diagnostics, the resulting code:

#![allow(unused)]

use std::{
    cell::{Cell, RefCell},
    future::Future,
    marker::Unpin,
    panic,
    pin::Pin,
    ptr,
    rc::Rc,
    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};

struct InjectedFailure;

struct Defer<T> {
    ready: bool,
    value: Option<T>,
}

impl<T: Unpin> Future for Defer<T> {
    type Output = T;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        if self.ready {
            Poll::Ready(self.value.take().unwrap())
        } else {
            self.ready = true;
            Poll::Pending
        }
    }
}

/// Allocator tracks the creation and destruction of `Ptr`s.
/// The `failing_op`-th operation will panic.
struct Allocator {
    data: RefCell<Vec<bool>>,
    failing_op: usize,
    cur_ops: Cell<usize>,
}

impl panic::UnwindSafe for Allocator {}
impl panic::RefUnwindSafe for Allocator {}

impl Drop for Allocator {
    fn drop(&mut self) {
        let data = self.data.borrow();
        if data.iter().any(|d| *d) {
            panic!("missing free: {:?}", data);
        }
    }
}

impl Allocator {
    fn new(failing_op: usize) -> Self {
        Allocator { failing_op, cur_ops: Cell::new(0), data: RefCell::new(vec![]) }
    }
    fn alloc(&self) -> impl Future<Output = Ptr<'_>> + '_ {
        self.fallible_operation();

        let mut data = self.data.borrow_mut();

        let addr = data.len();
        data.push(true);
        Defer { ready: false, value: Some(Ptr(addr, self)) }
    }
    fn fallible_operation(&self) {
        self.cur_ops.set(self.cur_ops.get() + 1);

        if self.cur_ops.get() == self.failing_op {
            panic::panic_any(InjectedFailure);
        }
    }
}

// Type that tracks whether it was dropped and can panic when it's created or
// destroyed.
struct Ptr<'a>(usize, &'a Allocator);
impl<'a> Drop for Ptr<'a> {
    fn drop(&mut self) {
        if !self.1.data.borrow_mut()[self.0] { panic!("double free at index {:?}", self.0) } else { *d = false }

        self.1.fallible_operation();
    }
}

no longer compiled:

    Checking _a v0.1.0 (/tmp/icemaker_global_tempdir.lAPrPb4j3wVl/icemaker_clippyfix_tempdir.dnKbE3nd6uBx/_a)
error[E0425]: cannot find value `d` in this scope
  --> src/lib.rs:80:102
   |
80 |         if !self.1.data.borrow_mut()[self.0] { panic!("double free at index {:?}", self.0) } else { *d = false }
   |                                                                                                      ^ not found in this scope

For more information about this error, try `rustc --explain E0425`.
error: could not compile `_a` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
error: could not compile `_a` (lib test) due to 1 previous error

Version:

rustc 1.90.0-nightly (f32b23204 2025-07-26)
binary: rustc
commit-hash: f32b23204a0efe2fe8383ed4be1a30b56c1bbf94
commit-date: 2025-07-26
host: x86_64-unknown-linux-gnu
release: 1.90.0-nightly
LLVM version: 20.1.8

Metadata

Metadata

Assignees

Labels

I-suggestion-causes-errorIssue: The suggestions provided by this Lint cause an ICE/error when applied

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions