Missed optimization: re-checking enum variants after `std::mem::replace` is not eliminated (somtimes)
Open
Nobody has claimed this yet.
A-LLVM
C-optimization
I-slow
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
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.
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 with the minimized poll_state example and its Godbolt reproduction. Compare the generated behavior when the second-branch state assignment is present or removed, and when State becomes State. Done means the unreachable panic after std::mem::replace is eliminated consistently for the reported case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100