Section 01: ARC merge-edge scoped cleanup
Status: In Progress Goal: Edge-scoped ARC cleanup must preserve every escaping projected child across merge edges, including multiple fields projected from the same parent aggregate on the same outgoing edge.
Context: CI exposed a macOS AOT failure in arc::test_rc_project_merge_edge_scoped_cleanup, and commit 9d323f30 fixed the first-order bug by scoping DeferredDec to the correct successor edge. Review of the current implementation found a remaining aggregate-projection hole in the same path. The section stays open until escaping projections are tracked precisely enough to protect all live children.
Depends on: None.
01.1 Merge-edge deferred dec scoping
File(s): compiler/ori_arc/src/aims/realize/emit_unified.rs, compiler/ori_llvm/tests/aot/arc.rs
The original merge-edge cleanup fix is in place, but the current projection bookkeeping still folds all escaping children from the same aggregate parent into a single compensation destination. This subsection remains open until the projection escape model is widened to preserve each escaping child separately and the regression suite proves it.
- Preserve escaping projections by arg identity or
(parent, child)identity instead of a singleparent -> project_dstslot inemit_unified.rs. Done: Changedfind_edge_decced_project_parents()to returnFxHashSet<ArcVarId>(doomed parent set) instead ofFxHashMap<ArcVarId, ArcVarId>. Each arg now gets its ownRcInckeyed to its own identity, not a shared project_dst from the parent. - Add a regression in
compiler/ori_llvm/tests/aot/arc.rswhere one edge passes two distinct projected fields from the same parent aggregate and both remain alive after edge cleanup. Done: Addedtest_rc_project_merge_edge_two_fields_escapewith 3 cases — struct destructuring (2 fields), conditional merge, and 3-field variant. - Re-run the existing merge-edge ARC tests plus the new multi-field projection test. Done: All 13,649 tests pass (0 failures).
01.R Third Party Review Findings
-
[TPR-01-001][high]compiler/ori_arc/src/aims/realize/emit_unified.rs:358— Multi-field escapes from the same parent aggregate are still unsound. Evidence:find_edge_decced_project_parents()stores a singleparent -> Project dstentry, andemit_project_escape_incs()reuses that oneproject_dstfor every outgoing arg tied to the same parent. If botha.firstanda.secondescape, the laterProjectoverwrites the former and only one child is compensated. The current regression coverage only exercises one projected field per parent. Impact: Edge cleanup can still free an escaping child field while the successor keeps using it, which reintroduces use-after-free or double-dec behavior on multi-field aggregates. Required plan update: Track escaping projections per arg or per(parent, child)pair, then add an AOT regression covering two escaping projected fields from the same parent on the same merge edge. Resolved: Validated against codebase on 2026-03-23 — confirmedFxHashMap<ArcVarId, ArcVarId>overwrites on duplicate parent. Implementation tasks integrated into 01.1.
01.N Completion Checklist
-
TPR-01-001is resolved in code, with the accepted fix reflected in01.1. -
cargo test -p ori_llvm test_rc_project_merge_two_distinct_parents -- --nocapturepasses. - A new regression covering two escaping fields from one aggregate parent passes.
-
cargo test -p ori_llvm test_rc_project_merge_edge_scoped_cleanup -- --nocapturepasses without modification.
Exit Criteria: Merge-edge ARC cleanup preserves all escaping children on every successor edge, including multiple projected fields from the same aggregate parent, and the dedicated AOT regressions pass with no new RC failures in the surrounding ARC suite.