Repository navigation
Conversation
Liveness counts a write such as `s.f = v` as neither a use nor a definition of `s`, so when `s` is never read afterwards it is already dropped where the write happens. In a later basic block the local is unbound and the assignment aborts the analyzer; in the same block a `&mut` stored this way is never dropped, so its lender is havoc'd. Such a write is unobservable, so remove it before computing mutabilities and drop points; its operands are then dropped where they die. Removing a write can make another one dead, so repeat until none is left. Fixes #346. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UTeLTYcpPtuCS816SZ1NJP
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dcf3e1c859
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .into_results_cursor(&self.body); | ||
| let mut dead_writes = Vec::new(); | ||
| for (block, data) in self.body.basic_blocks.iter_enumerated() { | ||
| for (statement_index, statement) in data.statements.iter().enumerate() { |
There was a problem hiding this comment.
Traverse statements in backward analysis order
For functions containing large basic blocks, this forward enumeration drives the ResultsCursor opposite MaybeLiveLocals' backward direction; the cursor only has linear performance when statements are visited in the analysis direction and can otherwise repeatedly replay the block (rustc documentation). That makes each scan quadratic, and the surrounding fixpoint loop can require one scan per link in a chain of partial writes, producing cubic behavior and potentially making verification of generated or otherwise large functions impractically slow. Iterate the statements in reverse while retaining their original indices, or use a results visitor.
Useful? React with 👍 / 👎.
Fixes #346.
Cause
MaybeLiveLocalstreats a write such ass.f = v(a projection with noDeref) as neither a use nor a definition ofs. Whensis never read afterwards, it is already dead, and already dropped, by the time the write runs:sis not a block parameter there.analyze_assignmentthen hitsassert!(lhs.projection.is_empty()).sis not dropped again after it. A&mutstored this way (s.0 = &mut b) is never resolved, sobis havoc'd and a correct program getsUnsat.Fix
local_def::Analyzer::remove_dead_partial_writesruns before mutabilities and drop points are computed. It turns intoNopevery assignment whose place has a projection, does not go through aDeref, and whose local is not live after the statement. Such a write cannot be observed. Once it is gone, its operands die where they are defined and get dropped there, so the stored reborrow is resolved. Removing one write can make another write dead, so the pass repeats until it finds none.Tests
tests/ui/{pass,fail}/dead_field_write.rsretarget a&mutfield of a tuple inside a branch after the tuple's last read. Before this change, both files panic withlhs.projection.is_empty(). After it, the pass file verifies, and the fail file, which breaks the assertion on the newly borrowed referent, isUnsat.I also ran the reproductions from the issue by hand: the
Statsdead store,if c { t.1 = 3; }, and the same-blocks.0 = &mut b. All of them now verify, and the versions with a broken assertion are rejected.cargo testpasses (402 UI tests), along withcargo fmt --checkandcargo clippy -- -D warnings.Generated by Claude Code