← board


prio: 55 # auto

C functions returning function pointers: typedef'd return type + full declarator

Status 2026-07-08 (cfront-agent) — 00089 already GREEN; 00124 root-caused, parked

Failing tests

Gate

Drop 00089.c/00124.c from test/c-conformance/pxx.skip; runner green.

Triage note (2026-07-06)

00089: fty go() where fty is a typedef for a fn-pointer — go is not registered as a function ("call to undeclared function: go"), so the fn-def detector mis-handles a typedef-fnptr RETURN type (likely treats go as a fn-pointer variable via the typedef proc-signature). 00124: full inline declarator int (*f1(int,int))(int,int) compiles but the double-indirect call returns garbage (85). Both are C declarator-grammar work (function returning function pointer), a focused session.

Pinned 2026-07-07

00089 core reduced: typedef int (*fty)(void); fty go(void){...} -> CERR "expected C expression". A LOCAL fty f = &zero; works (ParseCLocalDeclAST has the CTypeFnPtrName inline-fnptr branch). ParseCSubroutine's return-type path (retType := ParseCDeclType at cparser.inc:5013) does NOT handle a fnptr-typedef return type — after consuming fty (tyPointer + CTypeProcSig set), the name/param reading derails. Fix: mirror the local fnptr-typedef handling for a function's RETURN type (register go with retType tyPointer + the fnptr proc signature, read name+params normally). 00124 separately needs the inline full declarator int (*f(int,int))(int,int). Bounded-ish declarator work, focused session.

Further pinning 2026-07-07 — a fnptr-typedef declarator cluster

Probed the fnptr-typedef (typedef int (*fty)(void)) in several positions:

Progress 2026-07-07 — two sub-fixes landed; remaining gaps pinned

Resolved parts of the cluster (both gated, self-host green):

00124 finding 2026-07-07

00124's inline declarator int (*f1(int,int))(int,int) PARSES (compiles) — the remaining issue is the nested double-indirect call (*(*p)(0,2))(2,2) mis-lowers (runs 85, want 0). So both remaining cases are fn-pointer CODEGEN, not parser: 00089 = fnptr-field call on a call result (SIGSEGV); 00124 = chained deref+indirect-call value. Deep codegen, focused session.

Deeper layers pinned 2026-07-07 (3 sub-fixes now landed)

Landed this stretch: fnptr-typedef global (a386edce), go()() (cfebdbbb), &func struct fn-ptr field init (81400021). Remaining for 00089 isolated to the fnptr typedef whose return type is a STRUCT POINTER:

Codegen wall 2026-07-07

go()()->v (fty = struct-ptr-returning fn pointer) SIGSEGVs in the DOUBLE- INDIRECT CALL codegen — go()() itself returns a wrong pointer, so ->v derefs garbage (record resolution is a red herring; adding AN_CALL_IND to ResolveNodeRec did not help and was reverted). So the last of 00089/00124 is fn-pointer call CODEGEN: (a) go()() (call-of-call-result) returning a struct pointer, (b) 00124's (*(*p)(0,2))(2,2) chain. Deep backend work — focused session. The three parser- level sub-fixes (typedef global, go()() parse, &func struct field) are landed.

Progress 2026-07-08 (a-agent) — 00089 FIXED, 00124 remains

Root cause of 00089 was three-fold, all around a fn-pointer typedef whose RETURN type is a struct pointer (typedef struct S *(*fty)();):

  1. ParseCTypedef routing — the leading struct sent it down the aggregate fast-path (typedef struct Tag *Name;), which finds ( instead of a plain name and registers NOTHING → fty stayed undefined ("stray token"). Added CTypedefAggFnPtrDeclarator lookahead: a struct/union typedef whose declarator is (*name)(...) now routes through the general ParseCDeclType path.
  2. Signature lost its result record — the $cfnptr sig registered at the fn-ptr declarator never set ProcRetPtrElemTk/Rec, so an indirect call's result had no pointed-at record. Now captured before the param recursion and set on the sig.
  3. p()->field IR gapCNodeIsPointer had no AN_CALL_IND case, so the arrow never wrapped the call result in AN_DEREF and built AN_FIELD(AN_CALL_IND) → IRLowerAddress hit IR_UNSUPPORTED. Added AN_CALL_IND to CNodeIsPointer and to both node-record resolvers (CNodePtrElemTk/Rec).

00089 green. Conformance 209 pass / 0 fail / 11 skip. Self-host byte-identical, quick tier + lua/core green. Dropped 00089 from pxx.skip.

Remaining (ticket stays open): 00124 — int (*f1(int,int))(int,int) (a FUNCTION returning a fnptr, full inline declarator) still compiles but exits 85: the double-indirect call (*(*p)(0,2))(2,2) returns garbage. Separate from the typedef-fnptr-return path above — a fn-returning-fnptr codegen/declarator bug.

Log