tools/sizelint + CLAUDE.md rule 13: gate hardcoded size literals

Drew's Hare-discipline framing: "no hardcoded size literals anywhere in
the compiler." This session spent 32 commits sweeping after-the-fact
and STILL kept introducing new bypass sites in our own structural
work (A.5's tupleelemslot/fieldslotsize most recently). The cure is a
gate that catches new violations at commit time, not a deeper sweep.

tools/sizelint (sh+gawk):
- Always-on: `.size = NN` / `->size = NN` / `prim(...,"name",NN,...)`.
- Context-gated literals (NN(u64|i64) and `return NN`) in files or fns
  matching size|slot|elem|field|stride|paramfield|tinfo|primtype|
  slotsize|letemit|tagged.
- Allow-list via `// sizelint-ok: <reason>` or `/* sizelint-ok: ... */`.
- Comment strip happens after allow-list match so prose mentions of
  16/24 stay quiet.

Makefile: `test: all sizelint $(TESTS)` so the gate runs before any
binary builds.

CLAUDE.md rule 13 documents the discipline + escape hatch + optional
pre-commit-hook symlink.

Audit caught 3 real cstage bugs (cmd/wcc/check.c resolve_type:1002,
1079, 1531 hardcoded `tt->size = 16` / `= 32` for tagged-with-ptr and
tagged-with-slice payloads — should read `8 + sub.size`). Fixed
inline; behavioral no-op today (pt->size=16, st->size=24, sub.size=24
match the prior literals) but the SSoT seam carries forward through
#1/#34/#65.

8 SSoT-seed allow-lists added (cstage type.c ty_str/ty_slice prim
factories; wwstage primtypesize/tyslicesize; lib/ww/typ.ww tystr +
slice fields + their main.combined.ww mirrors). One amalloc-overalloc
allow-list at lib/ww/typ.ww:273 cites pending #36 (typed amalloc).

#66 filed for extending the filter once #65 routes lib/bytes +
lib/getopt's sizeof(slice) / sizeof(option) literals through SSoT —
naive line-pattern extension would false-positive on 22+ ELF wire-
format sites in dynout.ww.

131/131 + 994 + 995 + bootstrap green with `make sizelint` exit 0.
This commit is contained in:
2026-05-20 15:22:21 +09:00
parent 03b7336cae
commit f80927201b
9 changed files with 162 additions and 25 deletions

View File

@@ -670,14 +670,14 @@ fn primtypesize(nm: str) i64 = {
if (streq(nm, "i32") || streq(nm, "u32") || streq(nm, "f32") || streq(nm, "rune")) { return 4i64; };
if (streq(nm, "i64") || streq(nm, "u64") || streq(nm, "f64")) { return 8i64; };
if (streq(nm, "int") || streq(nm, "uint") || streq(nm, "uintptr")) { return 8i64; };
if (streq(nm, "str")) { return 16i64; };
if (streq(nm, "str")) { return 16i64; }; // sizelint-ok: SSoT for ty_str primtype (#64)
return -1i64;
};
// #43: SSoT for slice header size (ptr+len+cap = 24B today). Mirrors
// cstage cmd/wcc/type.c:103 (ty_slice->size = 24). Bumping a slice's
// header layout in #34 touches only this constant.
fn tyslicesize() i64 = { return 24i64; };
fn tyslicesize() i64 = { return 24i64; }; // sizelint-ok: SSoT for ty_slice header (#64)
// #42: AST-level layout helpers for the size(T)/align(T)/offset(e.f)
// fold. Mirror cstage resolve_type's size/align computation