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.
31 lines
1.2 KiB
Plaintext
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)))
|