C test-corpus expansion: c-testsuite → zlib → tcc (+ csmith fuzz harness)
- Type: feature (C frontend validation) — Track A/C.
- Status: done
- Step 1 DONE 2026-07-06: c-testsuite vendored (install_lib_candidates.sh
c-testsuite), runner
tools/run_c_conformance.sh+make test-c-conformance. Baseline 172/220 pass on pristine master; all 48 fails are recorded ticket-by-ticket intest/c-conformance/pxx.skipand filed as 22 backlog tickets (bug-c-init-designated-and-nested is the big cluster — 9 tests, silent wrong values). NOTE: a prior session drafted 3 inline fixes without tickets; per workflow they were REVERTED into tickets (draft approach recorded in each): feature-c-crtl-bind-hand-declared-prototypes, bug-c-string-literal-binop-decay, bug-c-ptrdiff-of-addr-elem — the last because the draft regressed test-core b133. Next inside step 1: burn down the skip list ticket by ticket; then step 2 (zlib). - 2026-07-09 — NEXT RUNGS scoped: ladder so far c-testsuite/zlib/cjson/lua/sqlite/tcc all green (tcc self-compiles, pxx/gcc lineages converge). Next new-muscle targets filed with kickoff prompts: [[feature-c-corpus-chess]] (perft, compiler-independent oracle, cross-validates Rust chess — DO FIRST) then [[feature-c-corpus-duktape]] (JS engine, GC + IEEE-754). GNU Pascal / gcc rejected (gcc front-end / C++ / generated-code bootstrap — not standalone C).
- 2026-07-09 — DUKTAPE COMPILES END-TO-END (pinned v191): four bring-up walls cleared —
__STDC_VERSION__predefine, macro-arg string-literal paren, crtl breadth (gmtime_r/strptime/gettimeofday/cbrt), and the real blocker: block-comment\-continuation splicing inCPReadLine(C phase-2 before phase-3), which truncated duktape's refzero macros. Now blocked on a runtime segfault in the first JS eval ([[bug-c-duktape-double-formatting]], setjmp/longjmp suspect). Also filed the constants→dynarrays compiler port ([[feature-c-compiler-dynarrays]]) — raised prio, we're an all-in-RAM compiler. - 2026-07-09 — DUKTAPE parked at wall #1: bring-up attempt hit the first cfront gap immediately — pxx doesn't predefine
__STDC_VERSION__, so duktape's C99<inttypes.h>gate never fires andduk_uintptr_tstays undeclared (cast parses as a call). Filed [[bug-c-preproc-missing-stdc-version-predefine]] (Track C); duktape resumes once it lands. gcc oracle smoke (incl. exact float formatting) is green, so the target is reachable behind that fix. - 2026-07-09 — CHESS LANDED GREEN (zero compiler fixes): VICE perft (
make test-chess-perft) — all canonical counts match depth 1..5 (startpos + Kiwipete + positions 3-6), first build, no blocker loop. 64-bit bitboard masks / bit-shift movegen / deep recursion / array-of-struct movelists all correct out of the box. Same oracle astest_rust_chess_perft.rs→ C+Rust triangulated. See [[feature-c-corpus-chess]] resolution. Next rung: [[feature-c-corpus-duktape]]. - 2026-07-09 — STEP 1 COMPLETE: c-testsuite 220/220 pass, 0 fail, 0 skip. The last skip (00216) is byte-identical to gcc after 7 fixes (compound literals, form-feed whitespace, anonymous members, struct identity cast, fn-ptr range-array length, flexible-array-member sizeof, file-scope struct CL init) — see [[feature-c-compound-literals]]. pxx.skip is empty. Next: step 2 (zlib).
- 2026-07-09 — conformance at 219/220 pass, 1 skip (only 00216). Compound literals landed (RECORD form: base + postfix + nested/whole-value + file-scope global array; [[feature-c-compound-literals]]), clearing 00216's compound-literal blocker. 00216 is NOT yet green: two further PRE-EXISTING, non-CL bugs remain — anonymous struct/union member braced-designated init ([[bug-c-anonymous-member-designated-init]]) and a full-file cumulative parser desync ([[bug-c-fullfile-cumulative-parser-desync]]). Step 1 completes (220/220) when both land and 00216 drops from pxx.skip.
- Context: corpus today = lua 5.4 + sqlite 3.46, both green and byte-identical to same-version gcc oracles on all targets. Recorded lesson (v185): big feature suites hide whole feature classes behind green CRUD — breadth beats depth.
The plan, ranked by variation-per-effort
1. c-testsuite (FIRST — cheapest, broadest)
- https://github.com/c-testsuite/c-testsuite — exactly 220 single-file
conformance programs (
tests/single-exec/00001.c..00220.c), each isolating one C corner (promotion edges, struct passing, bitfields, declarators). - No toolchain dependency (verified 2026-07-06 against the repo tree): the
suite is pure DATA. Contract:
mainis the entry point, andNNN.c.expectedmust match the test's stdout+stderr (220 .c / 220 .expected, 1:1). The repo's own runner infra (POSIX sh + Python3 + TAP + TMSU tag queries) is only THEIR multi-compiler CI for the daily results page — we bypass it. Their per-compiler runners are ~10-lineCC=xshell wrappers around a genericrunners/single-exec/posixscript, paired with a<name>.skipfile — we can mirror that shape (pxx runner + pxx.skip) or write our own loop; either is trivial. - Each test also has
NNN.c.tagsmetadata (C-standard level, portability, arch assumptions) — ready-made input for the explicit skip-list, no guessing why a test is out of scope. No silent skips. - Graduate later to gcc c-torture
execute/(~1500 tests) once green.
2. zlib (quick win, new workload class) — STARTED 2026-07-06
See [[feature-c-corpus-zlib]]: vendored (v1.3.1), test/zlib/runner.c +
make test-zlib, gcc oracle green. Two compiler blockers filed
([[bug-c-typedef-name-as-uninitialized-local]] + a zlib.h gzgetc macro parse
bug). libc-gap collector: [[feature-crtl-implement-libc-assumptions]].
- Bit-twiddling, huffman tables, CRC loops, unsigned saturation, fn-ptr dispatch — different muscle than lua/sqlite. ~25k LOC.
- Oracle: round-trip +
minigzip/example.coutput byte-compare vs gcc build. - Bonus cross-validation: same vectors against our existing PASCAL zlib in lib-test — two implementations, one truth.
- Vendor via tools/install_lib_candidates.sh pattern (gitignored, PROVENANCE.md).
3. tcc — Tiny C Compiler (the milestone)
- Stresses what nothing else does: setjmp/longjmp error recovery, giant switch dispatch, token machinery, its own ELF writer doing raw pointer surgery.
- Ladder: pxx-built tcc runs → compiles hello.c → compiles TCC ITSELF → byte-identical to gcc-built-tcc-compiling-tcc. Compiler-compiling-compiler.
- Earned side effect: tcc becomes a SECOND oracle for the whole C corpus (triangulate gcc). Multi-session effort.
4. csmith differential fuzzing (parallel, ongoing harness)
- Random C generator; run pxx-vs-gcc binaries, diff outputs; creduce minimizes hits. Finds miscompiles automatically, forever. One-time harness, then it runs overnight. Start once (1) lands.
5. Duktape (later, if appetite)
- JS engine, sqlite-style single-file amalgamation, portable C89/99, no computed-goto dependency (QuickJS/micropython want computed goto — their fallbacks are slow paths). New class: GC + IEEE-754 edge semantics (would have caught the v186 float-literal bug from another angle).
COPY-PASTE KICKOFF PROMPT (fresh session)
You are Track A/C (compiler + C frontend), master. Task: land step 1 of the C corpus expansion — the c-testsuite conformance battery — per devdocs/progress/backlog/feature-c-corpus-expansion.md (read it first; order and rationale are settled with the user, do not re-litigate).
Verified facts (2026-07-06, do NOT re-derive): the suite is pure data — exactly
220 tests tests/single-exec/00001.c..00220.c, contract = main entry +
NNN.c.expected matches stdout+stderr, plus NNN.c.tags metadata (C-standard
level, portability, arch). The repo's own runner infra (sh/Python3/TAP/TMSU) is
their CI only — bypass it; their per-compiler runners are 10-line CC=x
wrappers + a .skip script, nothing more.
- Vendor https://github.com/c-testsuite/c-testsuite via the tools/install_lib_candidates.sh pattern (gitignored vendor source like sqlite/lua, PROVENANCE.md with upstream commit hash).
- Write OUR OWN runner (tools/ script +
make test-c-conformance): for each test, compile./compiler/pascal26 -Ilib/crtl/include -Ilib/crtl/src NNN.c, run with timeout, compare stdout+stderr against NNN.c.expected (byte-exact) and exit code 0. TAP output not needed; summary line pass/fail/skip. - Triage every failure: (a) cfront/codegen bug — reduce to minimal repro
(compare vs gcc), fix or file per lane rules (shared internals = Track A
ticket; as A/C combined you may self-resolve); (b) legit unsupported
feature — add to an EXPLICIT skip-list file (mirror their
<name>.skipidea) with one-line reason sourced from the test's .tags where possible. No silent skips. Bug fixes >> skips; skip only what is genuinely out of scope (e.g. features we have consciously deferred). - Gate: runner green (skips documented), make test + self-host byte-identical,
test-lua-cross 24/24, sqlite suite still byte-identical vs same-version gcc
oracle (oracle needs extra TU
const char sqlite3_version[]="3.46.0";— see done/bug-c-create-trigger-huge-alloc-oom.md for why). If compiler bugs were fixed: make stabilize + make pin (watch pin.log — a stabilize flake makes pin silently re-bless the OLD binary; verify VERSION advanced). - Commit runner + skip-list + any fixes with regression tests; wire into make test only if fast (<~30s), else standalone target noted in this ticket. Update this ticket (step 1 done-notes), regenerate BOARD.md, push.
Steps 2 (zlib) and 3 (tcc) are separate sessions — do not start them unless step 1 lands early and all gates are green.
Cross-target skip lists CLEARED 2026-07-08 (A+C session)
All three 32-bit per-target skip lists (pxx.skip.{i386,arm32,riscv32}) are now EMPTY — every c-testsuite test that passes on x86-64 also passes cross. Fixed this session:
- 00174/00175 float→double default-arg promotion for variadic args on 32-bit softfloat targets (648dfd5b).
- 00120 enum-const-in-anon-struct return on i386 (fixed by 197899d3, enforced).
- 00189 variadic call through a function pointer (
&fprintf) — fnptr type signature now carries ProcVariadic + i386 IR_CALL_IND mirrors the direct variadic marshalling (f8e4ecfd). Base (x86-64) skip list still has 15 entries — all genuine deep language features (compound literals, statement-exprs, _Generic, VLA, wide strings, Duff's device, fnptr-returning declarators, pointer-to-array, HFA-float ABI 00204, pathological goto-shadowing). Each is its own focused-session ticket.
Skip list burned down to 3 — 2026-07-09 (cfront-agent, A+B+C)
x86-64 conformance now 217 pass / 0 fail / 3 skip (was 213 at session start, 172 baseline). Cleared this session, each with a regression test + self-host byte-identical:
- 00124 fn returning fn-pointer (bug-c-function-returning-fnptr-declarator)
- 00130 pointer-to-array
char (*p)[4](bug-c-pointer-to-array-declarator) - 00051 + 00143 switch non-compound body + Duff's device (bug-c-switch-nonblock-and-duffs-device)
- 00213 GNU dead-code-suppression torture (feature-c-statement-expressions — fell out of the switch-as-labels rework) Plus non-conformance: multidim-float global brace init, UClass field-window fix.
Only 3 skips remain, all deep multi-session features:
- 00204 HFA float-aggregate ABI — SysV eightbyte classification (INTEGER vs SSE per 8-byte chunk), XMM arg regs + struct return in xmm0(:xmm1). Pure Track A codegen, no parse fragility. (unfinished/bug-c-abi-battery-00204)
- 00216 designated-init cluster — GNU range designators
[a ... b]=, flex-array members, anonymous/unnamed struct/union members, empty structs. Parse-heavy, self-host-fragile; needs the brace-init factor-out. (feature-c-compound-literals / bug-c-init-designated-and-nested) - 00219 C11
_Generic— needs a richer C type model (const-qual, pointer-const, integer-width distinctions). Largest, lowest prio. (feature-c-generic-selection)
Step 1 essentially COMPLETE — 219/220, only 00216 left — 2026-07-09 (A+B+C agent)
Conformance is now 219 pass / 0 fail / 1 skip (v180). Cleared this session, each self-host byte-identical + gcc-verified + regression test wired into test-core:
- 00204 variadic struct passing +
va_arg(struct)(v178) — the gap was ONLY the varargs path; structs travel as one by-pointer GP slot,va_arg(struct)just needed a double-deref. tstate confirmed the FULL matrix GREEN. - 00219 C11
_Generic(v179) — the "richer type model" fear was overstated: most distinctions already live in TTypeKind; only long-vs-long-long + pointee-const needed adding, via an on-demandcgXxxdescriptor built inside _Generic (no per-symbol type-table growth). Plus an l/L literal-suffix the lexer had been eating. - partial 00216: GNU range designators
[lo ... hi]landed in the aggregate walker (v180).
Only 00216 remains — and it needs FILE-SCOPE compound literals in array
initializers (struct Wrap g[] = {((struct Wrap){f}), f} desyncs the top-level
parser before any other 00216 feature is even reached). That is the large,
self-host-fragile keystone; full 5-path map in feature-c-compound-literals.
Step 1 is done bar this one deferred feature. Steps 2 (zlib) / 3 (tcc) unchanged.
2026-07-13 — step 4 (csmith) BLOCKED on a one-line install; everything else on the ladder is done
Steps 1-3 are complete (c-testsuite 220/220, zlib byte-identical to the gcc oracle, tcc self-compiles and the pxx/gcc lineages converge). Duktape is parked on [[bug-c-duktape-double-formatting]]. That leaves step 4, the csmith differential fuzzer — the highest-leverage item left here, because it is a one-time harness that then finds miscompiles on its own, overnight, forever.
It cannot be started unattended: csmith is not installed and sudo requires a password.
One command unblocks it (user):
sudo apt install csmith creduce # csmith 2.3.0 is in the archive; creduce minimises hits
Once that is in, the harness is small: generate with csmith --output t.c, compile the same
file with gcc -O2 -I/usr/include/csmith and with pxx, run both, diff stdout; on a
mismatch, creduce down to a minimal repro and file it. csmith programs are self-checking
(they print a checksum of all globals), so the oracle is just "same checksum", and its
output is UB-free by construction, so a difference is always a real miscompile in one of
the two compilers.
- 2026-07-19 (backlog sweep) RESOLVED. Umbrella complete: c-testsuite 220/220, zlib + tcc done, csmith harness live, chess green (608cb971 split the follow-on rungs into their own tickets: duktape, quickjs, gcc-torture).
Log
- 2026-07-19 — resolved, commit 608cb971.