Commit Graph

2 Commits

Author SHA1 Message Date
ce3a25a0b4 test: contain sepwork scratch per-driver tmpdir, fix /tmp+in-repo leak (#8)
The wcc test drivers ran `ww build <bare-/tmp src>` with no -o, so the
compiler's <stem>.sepwork scratch landed beside the source and was never
cleaned: unbounded /tmp growth (2195 stale dirs observed) that fills tmpfs
and fabricates phantom test failures + silent harness aborts, and for
in-repo fixture builds leaked .sepwork into the tracked tree.

Each leaking build now writes its source + output inside a per-invocation
tmpdir, passes -o <tmpdir>/<stem> so the .sepwork lands inside it, and
rm -rf's the tmpdir on every exit path -- including fopen-fail and the
expected-fail reject builds (scratch is mkdir'd before the build can fail).
`ww run` and explicit-`-o`/byte-id helpers are left as-is; the 990/993
byte-id comparison logic is byte-for-byte unchanged.

Two items filed separately (this commit holds the no-Makefile / no-main.c
rail):
- #13: a stale <src>.s byte-id readback (749) silently no-ops since
  separate-compile emits .s to <ostem>.sepwork/__root.s; documented inline.
- #14: build-system Makefile recipes build selfhost/cmd/*/main.ww with no
  -o and leak main.sepwork in-tree (bounded, gitignored; own commit).

One concern -- sepwork leak hygiene -- across 228 drivers; uniform
transform applied per-file and two-round reviewed. make test: all 402
passed, zero net-new /tmp scratch, zero test-driven in-repo .sepwork.
2026-06-22 23:29:39 +09:00
037d59cf4e wcc/ww: registerstruct field offset is the checker's natural tfield.offset
wwstage carried TWO struct-layout sources. registerstruct (cgenutil.ww)
recomputed each field's `fi.foff` via fieldsize — slot-padded, round-8 —
for the WRITE (construction / field store) path, while the READ path
(cgplaceaddr / dotbaseaddr) used the checker's natural `tfield.offset`.
They diverged iff a struct had a nested sub-8 composite field
(slotsize != size) plus a successor: ww wrote the successor at the
slot-padded offset and read it at the natural offset, mis-addressing its
own field. cstage has no structinfo and reads tfield directly, self-
consistently natural (cmd/w6c/cgen.c).

Fix: make `fi.foff` a VIEW of the checker's already-built natural layout.
Lock-step walk tstruct.list (AST N_TFIELD) and ti.fields (tfield) — both
head-first declared order, both skip non-TFIELD identically — and copy
foff = tf.offset, fsz = tf.type_.size. si.totsize keeps the slot-padded
stack-slot number (ti.slotsize, already 8-rounded at check.ww:2259).
fieldsize is no longer called here (its `*p OP=` scalar-width caller is
untouched). LOUD nil-guards on tstruct.type_ / tichase / a tfield walk
desync — all unreachable post-check, never silent. fi.tnode stays the
AST node (its node-keyed readers need it); repointing the ~60 fi.foff
readers to tfield is the out-of-scope (ii-b) follow-up.

This unifies ww's second source onto the value cstage already emits, so
cs==ww is preserved, not newly created (wwstage-cgen only; no cstage
edit). The shape is corpus-absent — ww uses both sources on its own
structs, so a divergent struct would have broken the bootstrap — hence
gate-blind; 989_nestfield_run is the proof (nested inner{x:u8,y:u8} in
outer{a:u8,p:inner[,z:i64]}, every field read back == written, dual-stage
cs==ww). It also makes 681 ragged_tail_12B genuinely correct: the
predecessor #71 already shrank the whole-struct copy to the source's
natural length, so packing mark at natural offset 12 no longer clobbers.
2026-06-13 13:39:10 +09:00