C: invalid symbol in lea lowering sqlite amalgamation
- Type: bug (C frontend → IR lowering) — Track C (+ A if the fault is in shared symtab/IR)
- Status: backlog
- Owner: unassigned
- Found / Opened: 2026-06-27, M5 sqlite bring-up ([[feature-c-desktop-lua-sqlite-path]]).
Symptom
Compiling the sqlite 3.46.0 amalgamation (library_candidates/sqlite/sqlite3.c,
fetch via tools/install_lib_candidates.sh sqlite) fails the IR validation pass:
pascal26:22272: error: invalid symbol in lea ()
Raised at ir.inc:296 (the IR_LEA arm of the IR verifier):
IR_LEA:
if (IRA[i] < 0) or (IRA[i] >= SymCount) then
Error('invalid symbol in lea');
So some C construct lowers to an IR_LEA whose IRA (symbol index) is out of
[0, SymCount) — almost certainly negative / an unresolved-or-placeholder sym.
Ruled out
- Not capacity (
SymCountoverflow). Sym allocation is guarded (symtab.incSymCount >= MAX_SYMS -> Error('too many symbols')); we'd see that message, not this one. (Reached only after theMAX_TOKENS512K→2M bump, see [[chore-sqlite-static-capacity-bumps]].) - Not the obvious string-pointer-array path.
static const char * const opts[] = { #ifdef… "A", "B" };withopts[0][0]compiles and runs fine — so it is not the plainPendingInitKind=1global init.
Position is unreliable
The reported 22272 lands inside a dead #ifdef block (azCompileOpt[]). The
verifier runs after lowering, so the printed line is just the last-set
counter, not the offending construct. Do not trust it.
Next step (diagnosis plan)
- Instrument
ir.inc:296to printi,IRA[i],SymCount, and the current proc/node context instead of bailing — recompile sqlite, capture the bad sym value (negative? a sentinel like -1? a specific large index?). - From the value, find the emit site: grep the C→IR lowering for
IR_LEAemission where the sym can be unresolved (extern not yet bound? address-of a not-yet-allocated global? a function/label sym used as a data sym?). - Reduce to a minimal C repro once the construct is known; add to
test/.
Acceptance
- The offending construct identified, fixed at the lowering (or symtab) site.
- A minimal C repro in
test/(exit-code oracle) compiles + runs. - sqlite advances past this wall (next wall filed separately).
- self-host byte-identical + cross unaffected (or, if shared IR/symtab touched, full gate green).
Log
- 2026-06-27 - Found during M5 sqlite first-compile (after the MAX_TOKENS bump cleared the token-overflow wall). Characterized as a genuine bad-sym IR_LEA, not capacity; simple string-array repro negative; position stale. Needs instrumentation — parked for a focused debug session.
Diagnosis (2026-06-27, session 2)
Instrumented the IR_LEA verifier and IRLowerAddress (reverted after). Chain:
IRLowerAddress(ir.inc:587) is called on anAN_INT_LIT(value 0, ASTTk=tyInteger) node → no lvalue case matches → falls through toIR_UNSUPPORTED(ir.inc:878). The caller wraps that result inIR_LEAwith sym = -1 (0xffffffff) →IRVerify(ir.inc:296) rejects it.- Verifier dump at failure:
IRA=-1,SymCount=0x24c (588),iridx=0x2f; IR context showsIR_UNSUPPORTED(a=AN_INT_LIT)thenIR_ARGthen the badIR_LEA. So it is a function/init body taking the address of an integer literal. - The offending node's
ASTLine = 22225, inside thesqlite3azCompileOpt[]const char * const []global array initializer (def line 21934). That array is densely#ifdef-guarded; with no-Ddefines most entries vanish and the survivors useCTIMEOPT_VAL(...)stringify + adjacent string-literal concatenation (e.g."COMPILER=gcc-" __VERSION__,"THREADSAFE=" CTIMEOPT_VAL (THREADSAFE)). One surviving element is being lowered as an integer literal 0 instead of achar*, and the global array-pointer-init path then takes its address.
Not yet reduced
Isolated repros that did NOT trigger it: plain string-concat element
({"A=" "B"}), stringify of a numeric macro, a 0/null element in a char*[],
&global[const]. So the trigger is specific to pxx's expansion of a surviving
azCompileOpt entry. Next probe: dump pxx's preprocessed view of that array
(no -E/preprocess-dump flag exists — add one, or instrument cpreproc), or log
IRLowerAddress's caller to capture the parent expression that wraps an int
literal in an address-of.
Log
- 2026-06-27 (s2) - Traced to
IRLowerAddress(AN_INT_LIT 0)-> IR_UNSUPPORTED -> IR_LEA(-1), node at azCompileOpt[] init (~line 22225). Minimal repro still elusive (macro-expansion-specific). Separate offset bug found: [[bug-c-addr-of-global-array-element-const-index-wrong-offset]].
REJECTED (2026-06-27, session 3) — not a bug, missing -Ilib/crtl/include
Root cause: sqlite was compiled without -Ilib/crtl/include, so
#include <stdarg.h> resolved to the system header whose va_arg does not
map to pxx's __builtin_va_arg desugar. That is the exact shape of the
already-fixed [[track-c-va-arg-nonint-lea]] (va_arg -> *(T*)__pxx_va_arg(&ap),
IRLowerAddress of an int-literal). The Makefile C tests all pass -Ilib/crtl/ include; my manual sqlite invocations did not.
With -Ilib/crtl/include:
test/cvarargs_int_b49.cpasses (42).- sqlite advances past the lea crash to a new, genuine wall:
pascal26:19490: error: unexpected tokennearsqlite3Config/int (*xAltLocaltime)(const void*,void*)— a function-pointer struct field.
So this ticket is rejected (operator error). The real findings from the
investigation are kept: [[bug-c-addr-of-global-array-element-const-index-wrong-offset]],
[[bug-c-sizeof-array-yields-element-size]], the --dump-cpp flag, and the new
function-pointer-struct-field wall (see [[feature-c-desktop-lua-sqlite-path]] M5).
LESSON: C compiles need -Ilib/crtl/include for pxx's crtl headers. Consider
auto-adding it for .c inputs (filed as a note in the M5 log).