cgen: B7 emitter elem chases + tools/peellint gate — #5 alias-arc cs side closed by construction
The last four raw `->under` reads outside the whitelist were the
static-DATA emitters' ELEMENT-type single peels (the outer type already
chased): emit_array_lit_bytes:14356, emit_strarray_data:14574,
emit_slice_data:14788, let_pre_intern:15088 -> type_chase_named.
:15088 is the :14574 row's label-order leg and must flip in the same
commit or _S_ labels intern in emit order, not decl order (the in-tree
comment at the site); the strarr row's byte-id is the coupling proof.
Behavior moves (ken B7 first-position oracle + impl pre-state, all
pre-observed at 05f7af7):
- [N]alias-struct + [N]alias-str globals graduate cs link-ERR
("undefined reference") -> 0/0 BYTE-ID (cs emits ww's DATAW).
- zero-consumer latent silence closed: a never-referenced
2-level-elem-alias global silently lacked DATA (no reference, no
link error); now emits, pinned by the byte-id cell.
- []alias-str diagnostic routing: the alias escaped the 3-way
slice-of-{str,slice,tagged} fatal onto the downstream "not a
foldable constant" text — now the intended 3-way text (== control).
- []alias-tagged DESIGNED NARROWING: the alias dodged the 3-way fatal
ENTIRELY — cs silently accepted + RAN WRONG for reachable consumer
shapes (review-verified at base: a len+payload-read probe exits 1;
the len-only row was luck-correct). Now loud with the 3-way text;
widen what the gate SEES, never what it ACCEPTS (B6-c2 precedent).
- kb7_slc/slc0 scalar legs byte-NEUTRAL (the synthesized-array
choke-point already handled them); full kb corpus sweep: movers are
exactly the two graduation shapes, nothing else.
tools/peellint (sizelint clone, dep of test/test-unit): character-scan
strips comments and string/char literals, then matches the under-token
accessor-spelling-wide — `->under`/`.under` in C (deref-dot is the
same peel), `.under` in ww, optional whitespace after the operator,
and the line-split continuation (operator at EOL, `under` next line).
Scope cmd/wcc + cmd/w6c + selfhost/cmd/wcc + lib/ww (lib/ww/typ.ww
ruled IN — it is type.c's ww mirror, the accessor layer itself);
`peel-ok`/`peellint-ok` annotations exempt a 10-line window. Green at
this tip = zero unwhitelisted raw peels survive; the gate lands in the
commit that deletes the last raw read (the-funnel-completing-commit-
carries-the-gate; sizelint precedent). Whitelist, 27 entries:
cmd/wcc/type.c :78 :141 construction, :162 chase body,
:180 :193 :214 recursive chase
cmd/wcc/check.c :102 :2572 resolve-state probes, :2586 construction
cmd/w6c/cgen.c :731 probe-cleared scan peel (B5-c1),
:813/:814 :834/:835 peel-ok #218 variant-match
lib/ww/typ.ww :316 construction, :374 :385 :410 :437 :447 :463
:475 :488 :514 recursive chase
selfhost/cmd/wcc/cgenutil.ww :1302 chase body (tichase),
:2759 probe-cleared peel
selfhost/cmd/wcc/check.ww :1815 construction (peellint-ok)
Negative validation wired into 944_peellint_gate (B4 precedent):
re-introduced raw peel (C and ww spellings) REDS the lint; corrupted
annotation (peel-okk-…, token-bounded matcher) REDS the lint; the
check.ww:3683 "io.underread" prose, a code read of a longer field, and
comment-quoted tokens are pinned green regression rows; real tree must
lint clean. 944_alias_emit_b7_run pins all four emit paths
table-driven (14 rows / 36 checks) incl. ken's ww observation cells
(ww checker rejects slice-literal globals, "let: not assignable" —
unmoved; plain []str louds at ww's own emitslicedata 3-way, pinned by
the shared needle).
REVIEW AMENDMENT (reviewer-B7, fix-what-you-find): the frozen tip's
regex matcher passed five compiling evasion spellings green — `t ->
under` spacing, `t->`/EOL + `under` next-line (both stages; ww parses
`t.`/EOL too), C deref-dot `(*t).under`, ww `t. under`, and a string
literal containing a block-comment opener that blinded the regex
comment-strip for the rest of the file. The matcher is now a
character scan (comments + string/char literals stripped before
matching) with the widened token rule above; all six spellings are
pinned RED rows in 944_peellint_gate (checks 10 -> 16). The 10-line
annotation window stays as designed (a peel within an annotation's
window is exempt by construction — the window IS the exemption
mechanism). Lint + test bytes only; zero compiler-source bytes moved
in review.
What this does NOT close, said out loud (f2-ruling): a consumer that
never spells `under` at all — a switch on t->kind that simply never
peels — has no token for the lint to see. The accessor+lint closes the
WRONG-PEEL class (single-peel where chase was needed) by construction;
the NO-PEEL class is closed only at sites where classification routes
through the internalized chasing helpers, and contained elsewhere by
the acceptance-commit-carries-tripwires doctrine, which stays standing
for every future acceptance widening. The gate does not make alias
bugs impossible; it makes the four-times-burned shape unwritable.
Rule-11 note: forced fuse — the four conversions ARE the last raw-read
deletions; peellint cannot be green one commit earlier (consumer-graph
-forces-the-fuse precedent, #61).
Invariants: cs asm byte-NEUTRAL on the whole bootstrap corpus (five
mains + smoke, base-input pre==post); five mains cs==ww byte-id at
tip; _ww binary quartet bit-identical to the W2 baseline (ww changes
are comment-only annotation bytes — codegen-inert, proven by the md5
hold); w6c_ww+wwdump main.combined.ww regen'd via make, idempotent;
989 lib ratchet zero flips (31 byte-id / 9 pinned-divergent / 3
pinned-wwreject across 43 units); sizelint 0; peellint 0;
make test-unit "all 294 tests passed" (292 + the two new suites).
This commit is contained in:
@@ -14353,7 +14353,7 @@ emit_array_lit_bytes(FILE *out, Cg *c, Type *t, Node *rhs, int emit_phase)
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_ARRAY) return 0;
|
||||
Type *etype = u->sub;
|
||||
Type *eu = (etype && etype->kind == TY_NAMED) ? etype->under : etype;
|
||||
Type *eu = type_chase_named(etype);
|
||||
int esz = etype ? (int)etype->size : 1;
|
||||
int alen = (int)u->alen;
|
||||
|
||||
@@ -14571,7 +14571,7 @@ emit_strarray_data(FILE *out, Cg *c, const char *directive,
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_ARRAY) return 0;
|
||||
Type *etype = u->sub;
|
||||
Type *eu = (etype && etype->kind == TY_NAMED) ? etype->under : etype;
|
||||
Type *eu = type_chase_named(etype);
|
||||
if (eu == NULL || eu->kind != TY_STR) return 0;
|
||||
if (strcmp(directive, "DATAW") != 0) return 0;
|
||||
int esz = (int)etype->size;
|
||||
@@ -14785,7 +14785,7 @@ emit_slice_data(FILE *out, Cg *c, const char *directive, const char *name,
|
||||
"writable `let` (DATAR holder must be DATAW, w6a "
|
||||
"asm.c:362); read-only `def` unsupported (#10, rule 7)");
|
||||
Type *etype = u->sub;
|
||||
Type *eu = (etype && etype->kind == TY_NAMED) ? etype->under : etype;
|
||||
Type *eu = type_chase_named(etype);
|
||||
if (eu && (eu->kind == TY_STR || eu->kind == TY_SLICE
|
||||
|| eu->kind == TY_TAGGED))
|
||||
fatal("emit_slice_data: slice-of-{str,slice,tagged} literal "
|
||||
@@ -15084,8 +15084,7 @@ let_pre_intern(Cg *c, Node *file)
|
||||
Type *u = type_chase_named(d->type);
|
||||
if (u != NULL && u->kind == TY_ARRAY
|
||||
&& r != NULL && r->kind == N_ARRLIT) {
|
||||
Type *eu = (u->sub && u->sub->kind == TY_NAMED)
|
||||
? u->sub->under : u->sub;
|
||||
Type *eu = type_chase_named(u->sub);
|
||||
if (eu != NULL && eu->kind == TY_STR) {
|
||||
int alen = (int)u->alen;
|
||||
int cnt = 0;
|
||||
|
||||
@@ -98,6 +98,7 @@ resolve_typename(Checker *c, Node *n)
|
||||
* handing its type out; no consumer may ever see the size-0
|
||||
* placeholder. Mirrors wwstage's demand-driven tinfofornode, the
|
||||
* measured order-independent side. */
|
||||
/* peel-ok: under==NULL probes resolve state, not a dealias */
|
||||
if (s->type && s->type->kind == TY_NAMED && s->type->under == NULL
|
||||
&& s->decl && s->decl->kind == N_TYPEDECL)
|
||||
resolve_typedecl(c, s->decl);
|
||||
@@ -2567,6 +2568,7 @@ static void
|
||||
resolve_typedecl(Checker *c, Node *d)
|
||||
{
|
||||
Type *t = d->type;
|
||||
/* peel-ok: under!=NULL probes resolve state, not a dealias */
|
||||
if (t == NULL || t->under != NULL || t->resolving) return;
|
||||
t->resolving = 1;
|
||||
const char *save = c->cur_mod;
|
||||
@@ -2581,7 +2583,7 @@ resolve_typedecl(Checker *c, Node *d)
|
||||
if (circular_named(c, under, d->pos))
|
||||
under = ty_err;
|
||||
t->resolving = 0;
|
||||
t->under = under;
|
||||
t->under = under; /* peel-ok: construction */
|
||||
if (under) {
|
||||
t->size = under->size;
|
||||
t->align = under->align;
|
||||
|
||||
@@ -75,7 +75,7 @@ typesinit(Arena *a)
|
||||
* the same way a user-declared alias would. */
|
||||
ty_nomem = newtype(a, TY_NAMED);
|
||||
ty_nomem->name = "nomem";
|
||||
ty_nomem->under = ty_void;
|
||||
ty_nomem->under = ty_void; /* peel-ok: construction */
|
||||
ty_nomem->size = ty_void->size;
|
||||
ty_nomem->align = ty_void->align;
|
||||
ty_nomem->iserror = 1;
|
||||
@@ -138,7 +138,7 @@ type_named(Arena *a, const char *name, Type *under)
|
||||
{
|
||||
Type *t = newtype(a, TY_NAMED);
|
||||
t->name = name;
|
||||
t->under = under;
|
||||
t->under = under; /* peel-ok: construction */
|
||||
if (under) {
|
||||
t->size = under->size;
|
||||
t->align = under->align;
|
||||
@@ -159,7 +159,7 @@ type_named(Arena *a, const char *name, Type *under)
|
||||
Type *
|
||||
type_chase_named(Type *t)
|
||||
{
|
||||
while (t && t->kind == TY_NAMED) t = t->under;
|
||||
while (t && t->kind == TY_NAMED) t = t->under; /* peel-ok: chase body */
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,8 @@ type_isint(Type *t)
|
||||
case TY_UNTYPED_RUNE:
|
||||
return 1;
|
||||
case TY_ENUM: return type_isint(t->sub);
|
||||
case TY_NAMED: return type_isint(t->under);
|
||||
case TY_NAMED: /* peel-ok: recursive chase */
|
||||
return type_isint(t->under);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
@@ -188,7 +189,8 @@ type_isfloat(Type *t)
|
||||
switch (t->kind) {
|
||||
case TY_F32: case TY_F64: case TY_UNTYPED_FLOAT:
|
||||
return 1;
|
||||
case TY_NAMED: return type_isfloat(t->under);
|
||||
case TY_NAMED: /* peel-ok: recursive chase */
|
||||
return type_isfloat(t->under);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
@@ -208,7 +210,8 @@ type_isunsigned(Type *t)
|
||||
case TY_UINT: case TY_UINTPTR: case TY_SIZE:
|
||||
case TY_RUNE:
|
||||
return 1;
|
||||
case TY_NAMED: return type_isunsigned(t->under);
|
||||
case TY_NAMED: /* peel-ok: recursive chase */
|
||||
return type_isunsigned(t->under);
|
||||
case TY_ENUM: return type_isunsigned(t->sub);
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user