The existing fptest suite is IR-only: tests generate QBE text and grep for
expected strings. That harness missed two runtime bugs — the alloc16 32
exception frame (fixed in 00e44e8) and, now, an EmitDataSection early-exit
that omitted unconditional printf format strings when the program had no
string literals.
cp.test.e2e.pas is a new test unit that compiles Pascal through the full
pipeline (Lexer -> Parser -> Semantic -> CodeGenQBE -> qbe -> cc -> native
binary), executes the result, and asserts on stdout, exit code, or valgrind
output. It walks up from CWD to locate vendor/qbe and rtl so it runs both
from the project root and from compiler/target/ (where PasBuild invokes
TestRunner). Scratch artefacts live under compiler/target/test-e2e/ and
are preserved on failure for post-mortem debugging. Tests Ignore()
gracefully when qbe, the RTL, or valgrind is not available.
Initial cases: bare try/finally, try/finally with locals (stack-corruption
regression for the alloc16 bug), nested try/finally, virtual dispatch in
expression position inside try/finally, Phase 2 milestone stdout, and
Phase 2 milestone valgrind-clean.
On first run the virtual-dispatch case surfaced the latent EmitDataSection
bug: the procedure exited early when FStrLits.Count = 0, skipping the
$__fmt_d_nl / $__fmt_nl definitions that WriteLn(Integer) and bare WriteLn
always reference. Any program that printed an integer without also
containing a string literal failed to link. Fix: emit the format strings
unconditionally; the literals loop is the only block now gated on count.
634/634 tests green, ~0.9 s total.