Skip to content

Missed optimization: re-checking enum variants after std::mem::replace is not eliminated (somtimes) #142951

Open
@oxalica

Description

@oxalica

Minified example: (godbolt)

use std::task::{Poll, Waker};

pub enum State<T> {
    Inactive,
    Active(Waker),
    Signalled(T),
}

#[unsafe(no_mangle)]
pub fn poll_state(st: &mut State<String>, w: &Waker) -> Poll<String> { // a
    match st {
        State::Signalled(_) => {
            // Just checked the variant, take the value out.
            let State::Signalled(v) = std::mem::replace(st, State::Inactive) else {
                unreachable!() // This panic should be eliminated.
            };
            Poll::Ready(v)
        }
        _ => {
            *st = State::Active(w.clone()); // b
            Poll::Pending
        }
    }
}

The optimization is fragile. If we remove the state assignment on the second branch (b), or change function signature to operate on State<u8>, then the unreachable panic in the first branch will be correctly eliminated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions