Iterator stack allocation is not split up
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I tried this code (godbolt):
use std::hint::black_box;
type N = u8; // Doesn't matter
#[no_mangle]
pub fn f(n: &N, f: fn(u64)) {
for x in (MyIter { n: *n, base: 999 }) {
f(x);
}
}
struct MyIter {
base: u64,
n: N,
}
impl Iterator for MyIter {
type Item = u64;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
do_next(&mut self.n, self.base)
}
}
#[inline(never)]
fn do_next(n: &mut N, base: u64) -> Option<u64> {
// Doesn't matter
black_box(n);
black_box(base);
black_box(None)
}
I expected to see this happen: self.base is never modified, thus it gets constant-propagated at the f callsite and the only stack allocation that remains is for n
Instead, this happened: base is stored into the iterator allocation, and is loaded for every iteration of the loop even if never modified
This is to illustrate that even if only part of the iterator is ever mutated, LLVM won't recognize that and fail to constant propagate base inside of the loop body, which can have pretty drastic consequences for performance if it's used e.g. for integer division.
This is not specific to iterators, but this is how I noticed the missed optimization in real world code in this PR.
You can see in the godbolt link that we can work around this by creating a new allocation for n and passing that instead will correctly pass base as a constant to do_next.
The type of N and the contents of do_next don't matter. do_next can be fully inlined and the work around will still have its effect.
Meta
rustc --version --verbose:
rustc 1.90.0-nightly (5795086bd 2025-07-16)
binary: rustc
commit-hash: 5795086bdfe7ed988aa53a110bd0692c33d8755b
commit-date: 2025-07-16
host: x86_64-unknown-linux-gnu
release: 1.90.0-nightly
LLVM version: 20.1.8
@rustbot modify labels: +A-LLVM +I-slow +C-optimization -C-bug
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 Rust reproducer and Godbolt link to compare the generated output with the expected constant propagation. Investigate how the iterator allocation and mutable field are represented through optimization, then verify that the unchanged base is passed as a constant while only n remains mutable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100