flan/test/programs/debug.flan
Joseph Ferano 67aa82457d Check the offsets against LLVM, not against the same hand that wrote them
A wrong DWARF member offset does not crash anything. It prints a plausible
value for the wrong field, which is the failure this project has met over and
over at the FFI boundary, and it is the only way the debug info can be wrong
without saying so.

A table of expected offsets written in this test would be wrong in exactly the
ways the code is wrong, so it checks against LLVM instead: ptrtoint of a
getelementptr through a null pointer, over the struct type text lifted out of
the emitted module, folded by llc into a .quad and read back. That is the same
idiom Emit already uses for the size it hands flan_dev_global — it is just not
expressible inside metadata, where offset: must be an integer literal.

Then the same struct again with its fields permuted, and an assertion that the
two disagree. A check that cannot come out differently is not checking
anything: an offset table that ignored declaration order would satisfy either
ordering alone.

It fails when it should. Making a slice 4-byte aligned moves Cell.name from 24
to 20; the test says so by name, and lldb — which is the point — prints
len = 21474836480 for a five-character string.

The lldb cases are the only ones that say a person can debug a Flan program
rather than that the metadata is self-consistent: a breakpoint on a Flan
function by name, a backtrace naming .flan files and lines, and locals with
their own types and values. Skipped where there is no lldb, since it is not a
build dependency.

The --dev case is there because "the stack goes missing under --dev" is the
sort of thing found late. It does not: a cell changes how the callee is found,
not how the frame is laid out.
2026-09-12 03:46:23 +07:00

31 lines
1.2 KiB
Plaintext

;;;; The program the source-level debugging case runs under lldb.
;;;;
;;;; Every field holds a distinct known value of a distinct shape, so a DWARF
;;;; member offset that is wrong prints something obviously wrong rather than
;;;; something plausible — which is the failure mode this whole case exists
;;;; for. debug-permuted.flan is the same program with the fields declared in
;;;; a different order and every value unchanged: the two must print the same
;;;; field/value pairs from different offsets.
;;;;
;;;; alive at 0 (a byte), 7 of padding, heat at 8, id at 16, 4 of padding,
;;;; name at 24 — the slice is the member that moves if the alignment rule is
;;;; wrong, because it is the only one whose own alignment exceeds its first
;;;; member's size.
(defstruct Cell [alive bool heat f64 id i32 name string])
(defn tick [c (Ptr Cell) n i32] i32
(let [bump (+ n 1)]
(set (.heat c) (+ (.heat c) 1.5))
(set (.id c) bump)
bump))
(defn main [] i32
(let [c (Cell {:alive true :heat 3.25 :id 7 :name "grain"})]
(let [r (tick (addr c) 41)]
(print-i64 (i64 r)) (newline)
(print-f64 (.heat c)) (newline)
(print-i64 (i64 (.id c))) (newline)
(print-str (.name c)) (newline)
0)))