← board

What

A try/except is ONE statement, so a by-value managed-record or interface temp built inside a handler had its finalize emitted after the merge and ran on the NORMAL path — the path where nothing was raised and the handler never executed.

Fourth statement kind to need the IRFlushPostCallIntf boundary, after AN_IF's arms (bug-a-managed-temps-for-an-untaken-branch-are-still-init-and-finalized), the three loop bodies and AN_CASE's arms (both closed today, 1308ef1f8 and a289b5529).

Measured — the control is the other spelling again

5M calls of a try whose handler never runs:

time
on E: Exception do TakeR(MkR(k)), pre-fix 0.52 0.54 0.51 s
same, fixed 0.08 0.07 0.08 s
on E: Exception do if k >= 0 then TakeR(MkR(k)), pre-fix 0.07 0.08 0.07 s

sink=5000000 on all three. The if-wrapped spelling was already fast before the fix, because AN_IF supplies the flush and changes nothing else — so the handler paid ~6.5x for work the wrapped spelling never emitted, and the fix lands on the wrapped timing rather than past it.

Tests, and why one row is absent

test/test_except_arm_temp_finalize.pas covers the two leave paths an if arm does not have — a bare raise; re-raise and an exception escaping the handler — with the temp built BEFORE the leave, plus a handled arm and a never-raised arm. Output matches FPC; clean under -dPXX_HEAP_DEBUG.

No assert_no_leak row on it, deliberately. Per arm, 500 trips: Handled 2666/2664 live=2, NotRaised 1/0 live=1, ReRaised 2666/2664 live=2, Escaped 3799/2820 live=979. The Escaped arm is bug-a-an-exception-that-escapes-its-handler-or-is-bare-re-raised-still-leaks-its-object, open and blocked on a Track U decision — a bound there would measure that ticket. The Makefile says so where the row would go, and says to add it when that closes.

The discriminating guard is test/test_except_arm_finalize_shape.pas plus its Makefile assertion over PXXDBG=a.ir:Hot: AFTER-MERGE on the pre-fix binary, IN-ARM on the fixed one, and NO-FINALIZE-EMITTED treated as a failure of aim rather than a pass.

try BODY and finally block were checked at the same time and were already IN-ARM; only the handler arms were missing the flush.

Log