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

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-slowIssue: Problems and improvements with respect to performance of generated code.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions