cgen: B5-c2 #73 graduation — the 6 tripwired field gates chase, tripwire deleted

Close-by-construction replacing containment — the designed graduation
path from F1-c1's commit body. The 6 fld_alias_tripwire call sites
(indexed-elem field store/read, heap struct-lit field fill, tuple-elem
read, ptr-chain field read, static struct-lit emit) chase their fu
through type_chase_named; the 6 tripwire calls AND the helper itself
(incl. its :447 peel) are DELETED. Raw `->under` in cgen.c 69→62.
#73 CLOSES.

TRAIN INVARIANT holds: cs-only; w6c_ww/ww_ww bit-identical to the
bcd948d baseline md5s (28ad889042bad8006f1997cbcec94805 /
4e9ca8741f19e1f68219ff799a5e5a14). ZERO new corpus movers vs the c1
tip (kb*/kna corpus + five mains byte-NEUTRAL — the chased gates only
fire on 2+-level alias aggregate fields, none in corpus).

Gate-arm graduations (pre = loud "#73" fatal on cs, ww ok/0; post =
0/0 BYTE-ID): slice/str/tagged arms at the indexed STORE gate
(g73_idxstore/g73_strfield/g73_tagfield), slice arm at the indexed
READ / ptr-chain READ / tuple-elem READ gates (g73_idxread/g73_ptrread/
g73_tupread), nested-struct arm at the static emit gate
(g73_static_struct). The existing 944_alias_accept_run tripwire bound
row graduates K_BUILDERR_CS → K_RUN.

Two arms cannot pin the full 0/0 byte-id cell — documented, not silent:
  - heap fill (g73_heapfill, COMPILE-only pin): bare /tmp programs
    never link malloc (both stages, pre-existing infra) and ww's
    deref-field READ carries the #24-kin field(SB) leak; the chased
    FILL bytes verified byte-id by hand against the plain (non-alias)
    control — divergence shape identical, all of it in the pre-existing
    read sites.
  - str-field static emit (g73_static_str): the #73 fatal gave way to
    the pre-existing #129 A.2 foldability loud on cs — now both-loud
    twin texts (fill0 class), pinned as K_BUILDERR.
  - struct-copy arm: NO runnable repro reaches these gates — indexed
    whole-struct field reads take the (already chased, byte-id) address
    spine, and tuple-of-struct louds upstream on BOTH stages (#54-kin
    "aggregate init from unhandled rhs shape"). The arm's only carrier
    was the heap gate, covered by the compile pin above.

944_alias_cgen_b5_run grows 16→25 rows (65 checks); all 944-family
suites green; sizelint 0.
This commit is contained in:
2026-06-06 02:19:39 +09:00
parent 1cc663f494
commit e36af4fe7e
3 changed files with 219 additions and 56 deletions

View File

@@ -433,32 +433,6 @@ fldstoreop(Type *t, int sz)
return A_MOVQ;
}
/* fld_alias_tripwire — #73 guard at the single-peel field gates this
* fold did NOT chase. The #5-F1 acceptance admits 2+-level alias field
* types everywhere; a still-NAMED type after one peel skips a gate's
* multi-word arms (slice/str 3-word, tagged widener, struct copy) for
* a word0 scalar tail — accept-and-corrupt. Loud over silent (rule 7);
* chase + per-arm probes are task #73. Fires ONLY on 2+-level chains
* over an aggregate base: <=1-level (the entire pre-#5-F1-legal set)
* and scalar/float bases (width-driven tails, depth-safe) never fire. */
static void
fld_alias_tripwire(Type *ft, const char *site)
{
Type *u = (ft && ft->kind == TY_NAMED) ? ft->under : ft;
if (u == NULL || u->kind != TY_NAMED) return;
Type *base = type_chase_named(u);
if (base == NULL) return;
switch (base->kind) {
case TY_SLICE: case TY_STR: case TY_TAGGED:
case TY_STRUCT: case TY_TUPLE: case TY_ARRAY:
fatal("%s: 2+-level alias field type '%s' at unswept "
"single-peel gate (#73)", site,
ft->name ? ft->name : "?");
default:
return;
}
}
/* castsrcprim — structural (size, unsigned) of an N_CAST's source
* expression, mirroring wwstage's exprprimresolved in
* selfhost/cmd/wcc/cgenutil.ww. The cgen-stage match has to be
@@ -5079,10 +5053,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
if (f != NULL && (is_arr || is_sl || is_ptr)
&& off != 0) {
Type *ft = f->type;
fld_alias_tripwire(ft,
"indexed-elem field store");
Type *fu = (ft && ft->kind == TY_NAMED)
? ft->under : ft;
Type *fu = type_chase_named(ft);
int fsz = (int)(ft ? ft->size : 8);
int store_op = fldstoreop(ft, fsz);
int foff = (int)f->offset;
@@ -7870,10 +7841,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
* CX=cap). Route the heap base through DX so all
* three survive — CX now holds cap, BX holds len
* (#1/Phase 3). */
fld_alias_tripwire(ftype,
"heap struct-lit field fill");
Type *fu = (ftype && ftype->kind == TY_NAMED)
? ftype->under : ftype;
Type *fu = type_chase_named(ftype);
if (fu && fu->kind == TY_STR) {
ins2(c, A_MOVQ, amem(D_SP, 0), areg(D_DX));
ins2(c, A_MOVQ, areg(D_AX),
@@ -10657,10 +10625,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
}
if (tp != NULL) {
int fsz = (int)(tp->type ? tp->type->size : 8);
fld_alias_tripwire(tp->type,
"tuple-elem read");
Type *fu = (tp->type && tp->type->kind == TY_NAMED)
? tp->type->under : tp->type;
Type *fu = type_chase_named(tp->type);
int op = fldloadop(tp->type, fsz);
int off = localfind(locals, n->lhs->str);
/* C-t3 (#48): GLOBAL tuple base — LEAQ the
@@ -10990,10 +10955,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
if (strcmp(f->name, n->str) != 0) continue;
cgexpr(c, n->lhs, locals); /* AX = inner ptr */
Type *ft = f->type;
fld_alias_tripwire(ft,
"ptr-chain field read");
Type *fu = (ft && ft->kind == TY_NAMED)
? ft->under : ft;
Type *fu = type_chase_named(ft);
/* tagged leaf (#38a): AX holds the *struct
* base and the tagged cursor targets AX
* (tag) — stage the base in BX, then the
@@ -11149,10 +11111,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
areg(D_AX));
int foff = (int)f->offset;
Type *ft = f->type;
fld_alias_tripwire(ft,
"indexed-elem field read");
Type *fu = (ft && ft->kind == TY_NAMED)
? ft->under : ft;
Type *fu = type_chase_named(ft);
/* #270-1a: an `[N]T`-typed field of an
* array element (`a[i].m[j]`) — leave the
* field's ADDRESS, a base for the outer
@@ -14283,9 +14242,7 @@ emit_struct_lit_bytes(FILE *out, Cg *c, Type *t, Node *rhs, u64 base)
}
Node *vr = v;
while (vr != NULL && vr->kind == N_CAST) vr = vr->lhs;
fld_alias_tripwire(f->type, "static struct-lit emit");
Type *fu = (f->type && f->type->kind == TY_NAMED)
? f->type->under : f->type;
Type *fu = type_chase_named(f->type);
if (fu && fu->kind == TY_STRUCT) {
/* Recurse into nested struct lit. Pre-#145 the parser/
* checker has its own gap on inner-N_STRUCTLIT field