From a916066631e113325644cf2c8bc4eb825e0f1de2 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sat, 27 Dec 2025 15:26:42 +0900 Subject: [PATCH] phase29z(p2): return cleanup and null propagation doc alignment --- docs/development/current/main/10-Now.md | 4 +- docs/development/current/main/30-Backlog.md | 6 +-- .../current/main/phases/phase-29z/README.md | 8 ++-- src/bin/rc_insertion_selfcheck.rs | 41 +++++++++++++++++++ src/mir/passes/rc_insertion.rs | 31 ++++++++++++++ 5 files changed, 81 insertions(+), 9 deletions(-) diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index 355b6a57..42559ef3 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -3,11 +3,11 @@ ## Current Focus: Phase 29z P0(RC insertion minimal) **2025-12-27: Phase 29z P1 完了** ✅ -- `src/mir/passes/rc_insertion.rs`: `Store` 上書き + `Store null`(explicit drop)の最小 release 挿入(単一block・安全ガード) +- `src/mir/passes/rc_insertion.rs`: `Store` 上書き + `Store null`(explicit drop)+ Return終端cleanup の最小 release 挿入(単一block・安全ガード) - 既定OFF: Cargo feature `rc-insertion-minimal`(env var 新設なし) - 検証: quick 154/154 PASS 維持 + `cargo run --bin rc_insertion_selfcheck --features rc-insertion-minimal` - 入口: `docs/development/current/main/phases/phase-29z/README.md` -- 次: Phase 29z P2 closeout(残課題=null伝搬強化/スコープ終端cleanupの方針化) +- 次: Phase 29z P2 closeout(残課題=null伝搬強化/Branch&Jump終端cleanup/PHI・loop・early-exitの設計) **2025-12-27: Phase 29y P0 完了** ✅ - docs-first SSOT finalized(ABI/RC insertion/Observability) diff --git a/docs/development/current/main/30-Backlog.md b/docs/development/current/main/30-Backlog.md index 930f9449..097646f6 100644 --- a/docs/development/current/main/30-Backlog.md +++ b/docs/development/current/main/30-Backlog.md @@ -58,13 +58,13 @@ Related: - 次: Phase 29z(RC insertion minimal)または Phase 29x(De-Rust runtime)候補 - **Phase 29z(P2 CLOSEOUT準備中, implementation-minimal): RC insertion minimal** - - 進捗: P1まで完了(上書き+Store null で ReleaseStrong 挿入、単一block・安全ガード付き) + - 進捗: P1まで完了(上書き+Store null+Return終端cleanup で ReleaseStrong 挿入、単一block・安全ガード付き) - ガード: Cargo feature `rc-insertion-minimal`(既定OFF、env var 新設なし) - 検証: quick 154/154 PASS 維持 + `rc_insertion_selfcheck`(opt-in) - 残課題(P2で方針化→次フェーズへ) - null伝搬の精度向上(copy以外の伝搬パターン追加を段階的に) - - スコープ終端の release(block end cleanup)の最小実装検討(単一blockから) - - PHI/loop/early-exit は次フェーズ以降(誤release防止) + - Branch/Jump 終端での cleanup をどう安全に扱うかの設計 + - PHI/loop/early-exit の安全な cleanup 設計(誤release防止) - 入口: `docs/development/current/main/phases/phase-29z/README.md` - 指示書: `docs/development/current/main/phases/phase-29z/P0-RC_INSERTION_MINIMAL-INSTRUCTIONS.md` diff --git a/docs/development/current/main/phases/phase-29z/README.md b/docs/development/current/main/phases/phase-29z/README.md index 7d1e78e3..34778be1 100644 --- a/docs/development/current/main/phases/phase-29z/README.md +++ b/docs/development/current/main/phases/phase-29z/README.md @@ -17,9 +17,9 @@ Verification: Progress: - P0: overwrite release(Store 上書き) - P1: explicit drop(Store null)を最小対応 -- P2: closeout(残課題と次フェーズの入口を明文化) +- P2: closeout(Return終端のcleanup追加、残課題を整理) Next Steps(持ち越し事項): -- null 伝搬の精度向上(copy 以外の伝搬パターンを段階的に追加) -- スコープ終端の release(block end cleanup)の最小実装(単一blockから着手) -- PHI/loop/early-exit は次フェーズ以降で慎重に扱う(誤 release 防止) +- null 伝搬の精度向上(copy以外の伝搬パターンを段階的に追加) +- block終端cleanupの拡張: Return以外(Branch/Jump)で安全に扱えるかの設計 +- PHI/loop/early-exit の安全な cleanup 設計(誤 release 防止) diff --git a/src/bin/rc_insertion_selfcheck.rs b/src/bin/rc_insertion_selfcheck.rs index d24827cb..a8cb7a7c 100644 --- a/src/bin/rc_insertion_selfcheck.rs +++ b/src/bin/rc_insertion_selfcheck.rs @@ -112,5 +112,46 @@ fn main() { let module = build_module_with_block(block, "selfcheck_drop", "selfcheck_mod2"); assert_release_inserted(module, "selfcheck_drop", entry, 1, "explicit_drop"); + // Case 3: Block-end cleanup on Return (remaining tracked values) + let ptr = ValueId::new(300); + let v1 = ValueId::new(20); + + let mut block = BasicBlock::new(BasicBlockId::new(0)); + block.instructions = vec![MirInstruction::Store { value: v1, ptr }]; + block.instruction_spans = vec![Span::unknown()]; + block.terminator = Some(MirInstruction::Return { value: None }); + block.terminator_span = Some(Span::unknown()); + let entry = block.id; + let module = build_module_with_block(block, "selfcheck_return_cleanup", "selfcheck_mod3"); + assert_release_inserted( + module, + "selfcheck_return_cleanup", + entry, + 1, + "return_cleanup", + ); + + // Case 4: Branch terminator should NOT inject block-end cleanup (unsafe cross-block) + let ptr = ValueId::new(400); + let v1 = ValueId::new(30); + + let mut block = BasicBlock::new(BasicBlockId::new(0)); + block.instructions = vec![MirInstruction::Store { value: v1, ptr }]; + block.instruction_spans = vec![Span::unknown()]; + block.terminator = Some(MirInstruction::Jump { + target: BasicBlockId::new(1), + edge_args: None, + }); + block.terminator_span = Some(Span::unknown()); + let entry = block.id; + let module = build_module_with_block(block, "selfcheck_branch_skip", "selfcheck_mod4"); + assert_release_inserted( + module, + "selfcheck_branch_skip", + entry, + 0, + "branch_no_cleanup", + ); + println!("[PASS] rc_insertion_selfcheck"); } diff --git a/src/mir/passes/rc_insertion.rs b/src/mir/passes/rc_insertion.rs index 580cd0b3..6d3fdb8a 100644 --- a/src/mir/passes/rc_insertion.rs +++ b/src/mir/passes/rc_insertion.rs @@ -91,6 +91,8 @@ pub fn insert_rc_instructions(module: &mut MirModule) -> RcInsertionStats { // Take ownership of instructions to rebuild with inserted releases let insts = std::mem::take(&mut block.instructions); let mut spans = std::mem::take(&mut block.instruction_spans); + let terminator = block.terminator.take(); + let terminator_span = block.terminator_span.take(); // SAFETY: Ensure spans match instructions length (fill with Span::unknown() if needed) // instruction_spans and instructions may not always match in length @@ -152,6 +154,35 @@ pub fn insert_rc_instructions(module: &mut MirModule) -> RcInsertionStats { new_spans.push(span); } + // Block-end cleanup (single-block assumption): release remaining tracked values + if let Some(term) = terminator { + if matches!(term, MirInstruction::Return { .. }) && !ptr_to_value.is_empty() { + let release_values: Vec = { + let mut set = HashSet::new(); + for v in ptr_to_value.values() { + set.insert(*v); + } + set.into_iter().collect() + }; + if !release_values.is_empty() { + let span = terminator_span.clone().unwrap_or_else(Span::unknown); + new_insts.push(MirInstruction::ReleaseStrong { + values: release_values, + }); + new_spans.push(span); + stats.release_inserted += 1; + } + } + + // Re-attach terminator (with span alignment) + if let Some(span) = terminator_span { + new_spans.push(span); + } else { + new_spans.push(Span::unknown()); + } + new_insts.push(term); + } + // Replace block instructions with new sequence block.instructions = new_insts; block.instruction_spans = new_spans;