RExprRecId breaks the FPC bootstrap seed
Found by frankA (Track A) while gating an unrelated symtab.inc fix — the gate
went RED on this and only this. Not filed as a Track A change: the fix is one
line in compiler/rparser.inc, which is Track R's file, and Rust work looked
live there (fcfe1cba1), so it is handed over rather than taken.
rparser.inc(1293,12) Error: Identifier not found "RExprRecId"
compiler.pas(2111) Fatal: There were 1 errors compiling module, stopping
RExprRecId is used at rparser.inc:1293 and defined at :1507.
Why nothing caught it before the gate
This is the exact class CLAUDE.md warns about: pxx resolves names across a
whole unit, FPC resolves them in source order, and FPC is what bootstraps this
compiler. So make compiler/pascal26 — the documented per-fix loop, and a real
byte-identical self-host fixedpoint — is green while the seed build is broken.
The loop cannot see it by construction.
Severity is "master cannot be built from a clean FPC bootstrap", not "master is
broken": every existing binary keeps working, self-host keeps converging, and
--tier quick passes. It blocks bootstrapping from source and it fails any lane's
gate.sh quick, which is required before a pin — so nobody can pin until this
lands.
Fix
Add function RExprRecId(...): Integer; forward; above the first caller in the
same file, matching the existing convention (pasparser_generic.inc carries a
block of these with a comment explaining why). Keep it above the first caller,
not merely somewhere in the file — a forward that a later refactor lifts a caller
above is re-broken and reads as already handled.
Verify with the linter, not the error message
python3 tools/forwardlint.py expands compiler.pas's include chain in FPC's
order and reports every such call in one pass; it takes ~4 seconds. FPC
reports one batch and aborts, so fixing exactly the names it printed and
rebuilding is whack-a-mole — measured on 2026-08-29, four missing forwards took
three RED gate cycles that way and one lint pass to finish. Run the lint to zero
FAILs rather than rebuilding until the message goes away.
Related: [[bug-a-fpc-seed-drift-emitasmx64-forward]], [[decide-should-the-fpc-seed-canary-be-in-the-mandatory-loop]] (this is a fourth measured instance for that decision).
<<<<<<<< HEAD:devdocs/progress/done/bug-r-rexprrecid-breaks-the-fpc-bootstrap-seed.md
DUPLICATE — same bug as bug-r-rparser-calls-rexprrecid-before-declaring-it-so-the-fpc-bootstrap-seed-does-not-compile
Two independent filings minutes apart, both p80, both Track R, both correct.
Kept rather than deleted: two people finding the same repo-wide break by two
routes within minutes is the system working, and the line numbers differ between
them (:1293/:1507 vs :1416/:1754) because they were measured against
different shas — which is itself worth preserving.
Authoritative at e05286f44: call at rparser.inc:1416, declaration at
:1754, five siblings already forwarded at :63-67.
Resolve both, citing the same sha.
Log
- 2026-08-29 — resolved, commit 9d14b759d.
========
REJECTED as a duplicate, 2026-08-29 (frankA — its own filer). Same defect,
same file, same one-line fix as
[[bug-r-rparser-calls-rexprrecid-before-declaring-it-so-the-fpc-bootstrap-seed-does-not-compile]],
filed by frankwasm within hours of this one and pushed as
81a343358. That ticket is the survivor: it names the landing commit68dac6d2aand the five existing forwards atrparser.inc:63-67. The two facts unique to this one — the forwardlint/canary pair, and why the canary's single-identifier message is a trap — have been appended there, so nothing is lost by rejecting this.
Not a bad file, a coordination miss: two lanes hit the same broken seed within hours because the FPC canary is not in the mandatory per-fix loop, so each discovered it independently the moment it ran a wider gate. That is the argument the decision ticket is already weighing.
90ba74a14 (docs(progress): fold the duplicate RExprRecId seed ticket into frankwasm's):devdocs/progress/rejected/bug-r-rexprrecid-breaks-the-fpc-bootstrap-seed.md