Skip to content

Track drop points by MIR Place, splitting partially-moved locals (fix #121, #122)#155

Draft
coord-e wants to merge 2 commits into
mainfrom
claude/pr-154-mergeable-vt1l0f
Draft

Track drop points by MIR Place, splitting partially-moved locals (fix #121, #122)#155
coord-e wants to merge 2 commits into
mainfrom
claude/pr-154-mergeable-vt1l0f

Conversation

@coord-e

@coord-e coord-e commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Supersedes #154 and #124. Fixes #121 and #122.

Motivation

Description

  • DropPoints is generic over the MIR lifetime and stores mir::Place<'tcx> in before_statements, after_statements, after_terminator, and after_terminator_extra. Liveness-derived Local sets are converted to Places in the builder, and the basic-block Analyzer routes all implicit-drop handling through drop_place/drop_after_terminator working on mir::Place<'tcx>.
  • The fix lives in the drop-point production, not the env drop-walk. partial_moves collects the sub-places moved out of each local somewhere in the body; expand_owned_places then splits a to-be-dropped local along its type into the maximal still-owned sub-places, carving out moved-out subtrees while still dropping their owned siblings. A wholly-moved place expands to nothing; a place with no moved-out descendant is emitted whole (preserving prior behavior). Reference-typed moves are left in place, since ReborrowVisitor/RustCallVisitor turn them into reborrows and the source keeps owning its prophecy.
  • Drop-point places are collected into HashSet instead of Vec, removing the manual dedup bookkeeping.

Testing

🤖 Generated with Claude Code


Generated by Claude Code

@coord-e coord-e force-pushed the claude/pr-154-mergeable-vt1l0f branch 3 times, most recently from 440988e to 915afc5 Compare June 29, 2026 05:27
coord-e and others added 2 commits June 29, 2026 05:34
Replace the Local-only drop-point representation with MIR `Place` so
implicit drops are tracked at the right granularity. Drop points are stored
as `HashSet<Place>` (a whole-local drop is just a place with an empty
projection), and the analyzer drops them through a single `drop_places`
helper.
A local with a partial field move (e.g. `move (_2.0)`) was still dropped
wholesale, so dropping it walked into the moved-out sub-place and resolved
the `&mut` prophecy it owns a second time. The two resolutions contradict,
making the clause body unsatisfiable, after which any assertion -- including
false ones -- "verifies" (#121, #122).

`Moves::collect` gathers all non-reference `move`d operands in one body
traversal: whole-local moves (keyed by location, where the local also dies,
for the per-statement drop-set subtraction) and the set of locals with a
partial field move. A partially-moved local stays live until its remaining
parts die later, so dropping it wholesale at that point would re-resolve the
moved-out sub-place's prophecy; it is therefore excluded from dropping
entirely, just like a whole-local move. Reference-typed moves are skipped:
reborrows keep the source owning its prophecy.

Adds regression tests for both shapes (partial move into a local, and a
`&mut`-bearing field moved into a call).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NU1g7aHMxcSEZgeKProDr1
@coord-e coord-e force-pushed the claude/pr-154-mergeable-vt1l0f branch from 915afc5 to 12b6c5f Compare June 29, 2026 05:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unsoundness: partially-moved locals are still implicitly dropped, resolving prophecies of moved-out &mut borrows

2 participants