C: null pointer literal call arg lowers as address in sqlite
- Type: bug (C frontend / IR lowering / call arguments) — Track C
- Status: DONE (2026-06-27)
- Owner: Track C+A
- Found / Opened: 2026-06-27, M5 sqlite bring-up
([[feature-c-desktop-lua-sqlite-path]]), after block-scope function-pointer
typedefs in
va_argwere fixed.
Symptom
sqlite now advances to:
Unsupported linear node in IR codegen! Kind=10 node=749 IRA=1 IRB=-1 IRC=-1 IRIVal=0
pascal26:142434: error: Unsupported linear node in IR codegen ()
IRA=1 is AN_INT_LIT.
Preprocessed source at the current line:
static int openDatabase(
const char *zFilename,
sqlite3 **ppDb,
unsigned int flags,
const char *zVfs
);
int sqlite3_open(const char *zFilename, sqlite3 **ppDb){
return openDatabase(zFilename, ppDb, 0x00000002 | 0x00000004, 0);
}
Notes
The fourth argument is literal 0 for a const char * parameter. The IR error
indicates an address-lowering path received an integer literal, likely treating
the pointer parameter as needing an addressable argument instead of a pointer
value. This should reduce to an internal C function call with a pointer parameter
and 0/NULL as the actual argument.
Acceptance
- Passing
0/NULLto a pointer parameter lowers as a null pointer value, not as the address of an integer literal. - Add a focused regression around an internal C function with a
const char *parameter called with literal0. - sqlite advances past
sqlite3_open.
Resolution (2026-06-27, Track C+A)
Root cause was not the literal-0 argument — that path was already correct
(reductions passed). The crash came from openDatabase's body indexing the
file-scope function-pointer array sqlite3BuiltinExtensions[i](db). The
inline declarator static int (*const arr[])(T) is fully consumed by
ParseCDeclType (name → CTypeFnPtrName, the [..] dimension → new
CTypeFnPtrArrLen), so ParseCGlobalVarDecl's name loop saw =/; instead of
an identifier and never registered the global — every arr[i] reference
folded to a bare 0, and IRLowerAddress(AN_INT_LIT) (via the AN_INDEX base)
fell through to IR_UNSUPPORTED.
Fixes (all C-frontend; self-host byte-identical, make test green):
cparser.incParseCDeclType — capture the(*name[N])array dimension into a new globalCTypeFnPtrArrLen(defs.inc); stash it in a local across the param-list recursion (which resets the global) and restore it with the name, mirroringCTypeFnPtrName.cparser.incParseCGlobalVarDecl — a new branch registers the inline fn-ptr (array) global as anAllocArrayof callable pointers (or a scalar pointer), guarded bybaseTk = tyPointerso a struct/union global whose last member is a fn pointer (struct { void (*f)(void); } g;, e.g. sqlite'ssqlite3Hooks) — which leavesCTypeFnPtrNameset as leftover but yieldsbaseTk = tyRecord— falls through to the normal record-var path. The brace initializer is materialised as per-element proc-addressPendingInits (PendingInitKind = 2→AN_PROCADDR). Element callability is carried onSymElemProcSig(NOTSymProcSig, which would mark the array variable itself a proc value and corrupt indexing).cparser.incCNodeProcSig — resolvearr[i](args)through the base array sym'sSymElemProcSigso the call lowers toAN_CALL_IND.cparser.incParseCSizeof —sizeof(arr[i])/sizeof(p[i])now yields ONE element's size (subscript follows the ident), not the whole array. This pre-existing bug made the ubiquitousArraySize(x)idiomsizeof(x)/sizeof(x[0])fold to1, so the built-in-extension loop ran a single iteration.
Result: sqlite3.c fully lowers; with a main it links + runs through
sqlite3_open. Regression test/cglobal_fnptr_array_b109.c (exit 42) exercises
the indexed-call loop + static proc-address init + the struct-field guard.
Next wall (separate): running sqlite3_open(":memory:") now hits a runtime
undefined symbol: sqlite3MemSetDefault — a memory-subsystem function
referenced but compiled out under the current config. Filed as
[[bug-c-sqlite-undefined-symbol-memsetdefault]].