Since rustc 1.93 (likely #147827), initializing newtype wrapper of a struct that contains an integer type and a MaybeUninit field generates code to initialize the entire struct at -O2, instead of writing only the initialized integer field.
First bad nightly: nightly-2025-11-24 (commit c23ed3e)
Last good nightly: nightly-2025-11-23 (commit 94b49fd)
Still broken as of: 1.98.0-nightly (2026-06-11, LLVM 22.1.6)
Real-world impact: this caused a 22% performance regression in a specific test in the Firefox performance suite, as reported in https://bugzilla.mozilla.org/show_bug.cgi?id=2046376.
The hot call site creates a struct of three empty SmallVecs (from the smallvec crate with the union feature enabled). With rustc 1.93 the hot path now calls memset for 1224-bytes instead of three 8-byte stores.
Minimal reproducer
use std::mem::MaybeUninit;
pub struct Vec { cap: usize, data: MaybeUninit<[u64; 2]> }
pub struct Wrap(Vec);
#[no_mangle]
#[inline(never)]
pub fn make() -> Wrap {
Wrap(Vec { cap: 0, data: MaybeUninit::uninit() })
}
https://godbolt.org/z/KnarEEon8
1.92 generates:
make:
movq %rdi, %rax
movq $0, 16(%rdi)
retq
1.93 generates:
make:
movq %rdi, %rax
xorps %xmm0, %xmm0
movups %xmm0, (%rdi)
movq $0, 16(%rdi)
retq
With larger arrays in the MaybeUninit, more movups happen, up to the point where it may choose to use memset instead.
IOW, 19.3 is initializing the whole struct instead. Without the wrapping, the MaybeUninit is properly not initialized.
Since rustc 1.93 (likely #147827), initializing newtype wrapper of a struct that contains an integer type and a MaybeUninit field generates code to initialize the entire struct at -O2, instead of writing only the initialized integer field.
First bad nightly: nightly-2025-11-24 (commit c23ed3e)
Last good nightly: nightly-2025-11-23 (commit 94b49fd)
Still broken as of: 1.98.0-nightly (2026-06-11, LLVM 22.1.6)
Real-world impact: this caused a 22% performance regression in a specific test in the Firefox performance suite, as reported in https://bugzilla.mozilla.org/show_bug.cgi?id=2046376.
The hot call site creates a struct of three empty SmallVecs (from the smallvec crate with the union feature enabled). With rustc 1.93 the hot path now calls memset for 1224-bytes instead of three 8-byte stores.
Minimal reproducer
https://godbolt.org/z/KnarEEon8
1.92 generates:
1.93 generates:
With larger arrays in the MaybeUninit, more movups happen, up to the point where it may choose to use memset instead.
IOW, 19.3 is initializing the whole struct instead. Without the wrapping, the MaybeUninit is properly not initialized.