← board

A semantic diagnostic in a used unit has no location at all

The measurement, both positions in one run

The same statement — r := p, a Pointer stored into a record, refused by the AN_ASSIGN kind check:

where reported as
line 30 of a program pascal26:30: error: incompatible types: cannot assign Pointer to record
line 18 of a usesd unit pascal26:0: error: incompatible types: cannot assign Pointer to record

A parse error cannot see this defect — it is reported off the lexer's own position and never lost its coordinate — which is why the corpus rungs kept producing usable line numbers right up until one didn't.

Why one field was doing two jobs

AllocNode stamped ASTLine := 0 for any token past DbgMainTokEnd, and the reason is good: the Pascal RTL, pylib and unit bodies nobody wants to step through must contribute no line-table rows, or the whole runtime lands in the table. DbgRecordRow enforced it by testing IRLine[i] = 0.

ErrorAt/ErrorAtRecover take the same field. So the DWARF answer to "should this appear in the line table" was silently answering "where is this?" as well.

Resolution 2026-09-06 — split the two questions

The control, and it is the half that can regress silently

A diagnostic losing its line is loud the first time someone hits it. The RTL leaking into the line table is invisible unless you count — readelf does not complain and gdb resolves happily to the wrong text. Measured with the new guard removed on purpose, on an eight-line program that uses a one-function unit:

line rows highest line claimed
with the guard 6 6
without it 3663 6290

6290 is the RTL's own line number, attributed to a file with eight lines in it. That is now tools/dwarf_smoke.sh T5, with a deliberately loose bound: what it must catch is a flood, and a threshold near the true count would be a maintenance tax on a legitimate extra row.

Fixtures

test/test_a_semantic_diagnostic_in_a_used_unit_has_a_line.pas plus test/pascal_units/{unit,driver}_a_semantic_error_in_a_unit.pas, both positions asserted in the Makefile. The assertion is the COORDINATE, not the message — the text was correct throughout the defect, so a row asserting it passed the whole time.

Log