wcc: #5 F1 promote type_chase_named + transitive-peel acceptance align-cs-up
Promote type_chase_named from cmd/w6c/cgen.c (static) to cmd/wcc/type.c (exported via ww.h) and re-route every checker single-NAMED-peel through it: check.c's ~28 inline ternaries + 3 ad-hoc loops, type.c's assignability/untyped/borrow/opaque peels. type_eq's nominal identity (check.c:114) and the resolve machinery guards stay untouched. The re-route IS the acceptance align-up — cstage loud-rejected alias shapes wwstage accepts AND runs Hare-right (F0 census, harec dealiases at every consumer): - #54 binop alias-vs-base: unify_arith gains the harec type_promote arm (ref/harec/src/check.c:1083-1105) — one-sided alias + dealias-equal promotes to the ALIAS side; alias-vs-alias stays rejected. - alias-cond family: if/for/&&/||/! chase-then-bool (harec check.c:2141/2515/3229/3572). assert stays loud (F0 2a symmetric). - #70 field access through 2-level alias chains (ken c3_chain3). - assignability through the full chain (harec types.c:989-996 dealias-both): return/init/assign legs, F0 8b idx/slice walls. - alias-of-ptr deref (harec types.c:19-22 type_dereference). The widening reaches cgen arms whose own single peels then misbehaved — both classes are closed IN THIS COMMIT so no intermediate state ships a loud->silent flip (bisect no-silent invariant): - index family: the 8b acceptance hit ptr-load base + esz=1 (SEGV / prefix-luck) — idx_eff + the N_INDEX read / index-write / &base[i] / N_SLICE (expr + call-arg) / N_FORRANGE / aggarg_srcaddr-index / castsrcprim-dot / match-field base classifies chase. - kind classifiers (ken #61-root-verify v3 find): a 2-level f64 alias param reached cg_isfloat's single peel and classified INT — silent wrong-register-class. cg_isfloat / type_isf32 / fld_isfloat / type_isstr / type_isslice chase. ken's v3 row is pinned with credit. Bootstrap asm is byte-identical before/after (w6c on every main.combined.ww cmp-equal vs a pristine738d7f4scratch; 989 lib_byteid pins unchanged): 2-level chains were checker-walled pre-F1, so no previously-accepted program changes shape. test: 944_alias_accept_run (20 rows): acceptance graduations pinned runtime + byte-id both stages; idx/slice/range/slice-param rows cs-only until the wwstage #60 esz family lands (F2 batch 1); cs-only harec-parity loud pin for alias-vs-alias binop; assert stays-loud row; ken-v3 + f64/str/slice kind rows. Mutation-checked at738d7f4. reviewer-F1 fold — the same invariant, outside the F0 census: this commit ADMITS 2+-level alias slice/str/aggregate types in STRUCT FIELD position, therefore this commit must keep them correct-or-loud. The cgen FIELD-TYPE gates single-peeled, so the slice/str 3-word arms fell to word0-only scalar tails — accept-and-corrupt, ww correct, every shape loud at the pristine base. Chased (probe-proven, byte-id graduations): single-dot field store + via-ptr twin, struct-lit fill, chained store-walk LEAF (the #71 walk chases hops, not leaves), chained-ptr-field store, single-dot / via-ptr / chained-walk field reads (clobber-probed — word0 reads luck-passed on stale BX/CX). The six unprobed sibling gates (indexed-elem store/read, ptr-chain read, heap fill, tuple-elem read, static emit) hard-error via fld_alias_tripwire on a 2+-level alias over an aggregate base, citing task #73 (the family's scheduled chase); <=1-level and scalar bases never fire — zero behavior change for any pre-#5-legal program (five selfhost mains cmp-identical vs the pristine738d7f4scratch). test: 944 +11 rows (9 K_RUN byte-id, wholeread K_RUN_CS [#60 ww half + pre-existing 1-level read-spine divergence], #73 tripwire K_BUILDERR_CS pin); 1-level controls per gate in /tmp/revF1.
This commit is contained in:
165
cmd/w6c/cgen.c
165
cmd/w6c/cgen.c
@@ -176,25 +176,18 @@ static int nyields;
|
||||
static int
|
||||
cg_isfloat(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
if (t->kind == TY_NAMED) t = t->under;
|
||||
/* Transitive chase (#5 F1): the acceptance align opened 2-level
|
||||
* float/str/slice aliases to these kind classifiers — a single
|
||||
* peel mis-classed them scalar/INT (ken v3: f64-alias param read
|
||||
* the wrong register class once the checker admitted it). */
|
||||
t = type_chase_named(t);
|
||||
if (t == NULL) return 0;
|
||||
return t->kind == TY_F32 || t->kind == TY_F64
|
||||
|| t->kind == TY_UNTYPED_FLOAT;
|
||||
}
|
||||
|
||||
/* type_chase_named — walk the TY_NAMED.under chain to the deepest non-
|
||||
* named type. Chain-of-aliases (#22): `type b = a; type a = struct;`
|
||||
* stacks two TY_NAMED layers — a single peel leaves `t` pointing at
|
||||
* the inner alias (still TY_NAMED), so kind-gated arms (TY_STRUCT,
|
||||
* TY_SLICE, TY_TAGGED, TY_PTR) miss and the codegen silently falls
|
||||
* through to a scalar shape. Mirror of wwstage's structlookupchain. */
|
||||
static Type *
|
||||
type_chase_named(Type *t)
|
||||
{
|
||||
while (t && t->kind == TY_NAMED) t = t->under;
|
||||
return t;
|
||||
}
|
||||
/* type_chase_named lives in cmd/wcc/type.c since the #5 alias arc — the
|
||||
* checker's acceptance sites share the transitive peel with cgen. */
|
||||
|
||||
/* cg_sret_retsize — sret classifier; defined after the tuple register-
|
||||
* return helpers (tuple_rseq / tuple_eslot / fld_isfloat) it consults
|
||||
@@ -211,8 +204,7 @@ node_isfloat(Node *n)
|
||||
static int
|
||||
type_isstr(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
if (t->kind == TY_NAMED) t = t->under;
|
||||
t = type_chase_named(t);
|
||||
if (t == NULL) return 0;
|
||||
return t->kind == TY_STR || t->kind == TY_UNTYPED_STR;
|
||||
}
|
||||
@@ -226,8 +218,7 @@ node_isstr(Node *n)
|
||||
static int
|
||||
type_isslice(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
if (t->kind == TY_NAMED) t = t->under;
|
||||
t = type_chase_named(t);
|
||||
return t && t->kind == TY_SLICE;
|
||||
}
|
||||
|
||||
@@ -317,8 +308,7 @@ tuple_eslot(Type *t)
|
||||
static int
|
||||
type_isf32(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
if (t->kind == TY_NAMED) t = t->under;
|
||||
t = type_chase_named(t);
|
||||
return t && t->kind == TY_F32;
|
||||
}
|
||||
|
||||
@@ -350,8 +340,7 @@ static int
|
||||
fld_isfloat(Type *t, int *isf32)
|
||||
{
|
||||
if (isf32) *isf32 = 0;
|
||||
if (t == NULL) return 0;
|
||||
if (t->kind == TY_NAMED) t = t->under;
|
||||
t = type_chase_named(t);
|
||||
if (t == NULL) return 0;
|
||||
if (t->kind == TY_F64) return 1;
|
||||
if (t->kind == TY_UNTYPED_FLOAT) return 1;
|
||||
@@ -444,6 +433,32 @@ 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
|
||||
@@ -502,11 +517,9 @@ castsrcprim(Node *n, int *sz, int *unsignd)
|
||||
/* Real struct field only. .len / .cap / .ptr on str /
|
||||
* slice / array are pseudo-fields wwstage doesn't see. */
|
||||
Type *bt = n->lhs ? n->lhs->type : NULL;
|
||||
Type *bu = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
|
||||
if (bu && bu->kind == TY_PTR) {
|
||||
Type *st = bu->sub;
|
||||
bu = (st && st->kind == TY_NAMED) ? st->under : st;
|
||||
}
|
||||
Type *bu = type_chase_named(bt);
|
||||
if (bu && bu->kind == TY_PTR)
|
||||
bu = type_chase_named(bu->sub);
|
||||
if (bu && bu->kind == TY_STRUCT) {
|
||||
t = n->type;
|
||||
}
|
||||
@@ -1250,9 +1263,12 @@ static Type *
|
||||
idx_eff(Type *t)
|
||||
{
|
||||
if (t == NULL) return NULL;
|
||||
Type *u = type_unwrap(t);
|
||||
/* Transitive chase (#5 alias arc): the checker now admits index
|
||||
* bases through 2-level alias chains (F0 8b); a single unwrap left
|
||||
* eff TY_NAMED → sub NULL → esz=1 byte loads off the chain. */
|
||||
Type *u = type_chase_named(t);
|
||||
if (u && u->kind == TY_PTR && u->sub) {
|
||||
Type *p = type_unwrap(u->sub);
|
||||
Type *p = type_chase_named(u->sub);
|
||||
if (p && p->kind == TY_ARRAY) return p;
|
||||
}
|
||||
return u;
|
||||
@@ -2100,7 +2116,7 @@ aggarg_srcaddr(Cg *c, Node *src, int dst, Local *locals)
|
||||
Node *base = src->lhs;
|
||||
Node *idx = src->rhs;
|
||||
Type *bt = base ? base->type : NULL;
|
||||
Type *bu = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
|
||||
Type *bu = type_chase_named(bt);
|
||||
if (base && base->kind == N_IDENT && bu
|
||||
&& bu->kind == TY_ARRAY) {
|
||||
int esz = (bu->sub) ? (int)bu->sub->size : 1;
|
||||
@@ -3032,7 +3048,11 @@ cg_structlit_fill(Cg *c, Local **locals_p, Type *lu, Node *lit,
|
||||
break;
|
||||
}
|
||||
}
|
||||
Type *fu = (ft && ft->kind == TY_NAMED) ? ft->under : ft;
|
||||
/* Transitive chase (#5-F1 fold): a 2-level-alias slice/str
|
||||
* field fell past every kind arm to the word0-only scalar
|
||||
* tail — silent, reachable only via this commit's
|
||||
* acceptance (reviewer-F1 s1 probe). */
|
||||
Type *fu = type_chase_named(ft);
|
||||
if (fu && fu->kind == TY_TAGGED) {
|
||||
/* Tagged store: reload BX first (if non-BP) so the
|
||||
* widener sees a valid base reg. The widener itself
|
||||
@@ -4132,8 +4152,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
Node *base = opnd->lhs;
|
||||
Node *idx = opnd->rhs;
|
||||
Type *bt = base ? base->type : NULL;
|
||||
Type *bu = (bt && bt->kind == TY_NAMED)
|
||||
? bt->under : bt;
|
||||
Type *bu = type_chase_named(bt);
|
||||
Type *eff = idx_eff(bt);
|
||||
int esz = (eff && eff->sub)
|
||||
? (int)eff->sub->size : 1;
|
||||
@@ -4703,8 +4722,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* work cleanly.
|
||||
* - else: struct local, BP-relative. */
|
||||
Type *ft = f->type;
|
||||
Type *fu = (ft && ft->kind == TY_NAMED)
|
||||
? ft->under : ft;
|
||||
/* Transitive chase (#5-F1 fold): 2-level alias
|
||||
* slice/str field skipped the 3-word arm — ptr
|
||||
* word stored, len/cap dropped (reviewer-F1
|
||||
* ix2/s2/s3 probes; c1-acceptance-reached). */
|
||||
Type *fu = type_chase_named(ft);
|
||||
/* Tagged-union field — full slot rewrite via the
|
||||
* shared widener so every rhs shape (whole-tagged
|
||||
* ident or expr with tag-remap, concrete-variant
|
||||
@@ -4749,8 +4771,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
int is_global = (boff == 0 && !via_ptr
|
||||
&& let_islet(base->str));
|
||||
int foff = (int)f->offset;
|
||||
Type *str_fu = (f->type && f->type->kind == TY_NAMED)
|
||||
? f->type->under : f->type;
|
||||
Type *str_fu = type_chase_named(f->type);
|
||||
/* str/slice field: str IS []u8, so both store the full
|
||||
* 3-word {ptr,len,cap} that rhs cgexpr leaves in
|
||||
* (AX,BX,CX) at field+0/+8/+16. Address scratch must
|
||||
@@ -5025,6 +5046,8 @@ 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;
|
||||
int fsz = (int)(ft ? ft->size : 8);
|
||||
@@ -5272,8 +5295,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
{ f = fl; break; }
|
||||
if (f != NULL) {
|
||||
Type *ft = f->type;
|
||||
Type *fu = (ft && ft->kind == TY_NAMED)
|
||||
? ft->under : ft;
|
||||
/* Transitive chase (#5-F1 fold):
|
||||
* 2-level alias slice/str field
|
||||
* skipped the 3-word arm
|
||||
* (reviewer-F1 p1 probe). */
|
||||
Type *fu = type_chase_named(ft);
|
||||
int fsz = (int)(ft ? ft->size : 8);
|
||||
int store_op = fldstoreop(ft, fsz);
|
||||
int foff = (int)f->offset;
|
||||
@@ -5576,9 +5602,12 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
break;
|
||||
}
|
||||
Type *fu = (leaf_type
|
||||
&& leaf_type->kind == TY_NAMED)
|
||||
? leaf_type->under : leaf_type;
|
||||
/* Transitive chase (#5-F1 fold): the walk
|
||||
* HOPS chase (#71) but the LEAF gate
|
||||
* single-peeled — 2-level alias slice leaf
|
||||
* fell to the scalar tail (reviewer-F1 s4
|
||||
* probe). */
|
||||
Type *fu = type_chase_named(leaf_type);
|
||||
int fsz = (int)(leaf_type
|
||||
? leaf_type->size : 8);
|
||||
int store_op = fldstoreop(leaf_type, fsz);
|
||||
@@ -5881,7 +5910,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (n->lhs->kind == N_INDEX && n->lhs->lhs && !place_slit) {
|
||||
Node *base = n->lhs->lhs;
|
||||
Type *bt = base->type;
|
||||
Type *u = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
|
||||
Type *u = type_chase_named(bt);
|
||||
int is_arr = u && u->kind == TY_ARRAY;
|
||||
int is_sl = u && u->kind == TY_SLICE;
|
||||
int is_ptr = u && u->kind == TY_PTR;
|
||||
@@ -7805,6 +7834,8 @@ 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;
|
||||
if (fu && fu->kind == TY_STR) {
|
||||
@@ -8642,8 +8673,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
Node *lo = args[i]->rhs;
|
||||
Node *hi = args[i]->cond;
|
||||
Type *bt = base ? base->type : NULL;
|
||||
Type *bu = (bt && bt->kind == TY_NAMED) ?
|
||||
bt->under : bt;
|
||||
Type *bu = type_chase_named(bt);
|
||||
/* esz from the type table for an N_IDENT base
|
||||
* (#76) or an N_DOT array/slice-field base
|
||||
* (#257: scale by the field's element width via
|
||||
@@ -9394,7 +9424,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* value words at +8/+16) is contiguous within the struct,
|
||||
* so no spill is needed. */
|
||||
Type *bt = s->lhs->type;
|
||||
Type *bu = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
|
||||
Type *bu = type_chase_named(bt);
|
||||
Tfield *f = NULL;
|
||||
if (bu && bu->kind == TY_STRUCT) {
|
||||
for (Tfield *fl = bu->fields; fl; fl = fl->next) {
|
||||
@@ -10372,9 +10402,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
areg(D_AX));
|
||||
goto dot_done;
|
||||
}
|
||||
Type *fu = (leaf_type
|
||||
&& leaf_type->kind == TY_NAMED)
|
||||
? leaf_type->under : leaf_type;
|
||||
/* Transitive chase (#5-F1 fold):
|
||||
* read twin of the store-walk
|
||||
* leaf gate (reviewer-F1 r2b
|
||||
* clobber probe). */
|
||||
Type *fu = type_chase_named(leaf_type);
|
||||
/* tagged leaf (#38a): load the box into
|
||||
* the tagged cursor (AX=tag, DX=val0,
|
||||
* R8=val2 before CX=val1 — base_reg may
|
||||
@@ -10588,6 +10620,8 @@ 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;
|
||||
int op = fldloadop(tp->type, fsz);
|
||||
@@ -10742,8 +10776,12 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* folds onto the slice arm (#1/Phase 3 collapse).
|
||||
* base_reg may be CX for globals; load .cap LAST so
|
||||
* the base survives the earlier reads. */
|
||||
Type *str_fu = (f->type && f->type->kind == TY_NAMED)
|
||||
? f->type->under : f->type;
|
||||
/* Transitive chase (#5-F1 fold): the slice half
|
||||
* single-peeled while the str half (type_isstr)
|
||||
* recursed — a 2-level alias slice field read
|
||||
* loaded ptr only, len/cap rode stale registers
|
||||
* (reviewer-F1 r1b clobber probe). */
|
||||
Type *str_fu = type_chase_named(f->type);
|
||||
if ((str_fu && str_fu->kind == TY_SLICE) ||
|
||||
type_isstr(f->type)) {
|
||||
ins2(c, A_MOVQ,
|
||||
@@ -10860,8 +10898,10 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* pointer, so load .len LAST — the earlier loads
|
||||
* still index off the original base. str folds
|
||||
* onto the slice arm (#1/Phase 3 collapse). */
|
||||
Type *str_fu = (f->type && f->type->kind == TY_NAMED)
|
||||
? f->type->under : f->type;
|
||||
/* Transitive chase (#5-F1 fold): via-ptr twin
|
||||
* of the BP-base read gate (reviewer-F1 r3
|
||||
* clobber probe). */
|
||||
Type *str_fu = type_chase_named(f->type);
|
||||
if ((str_fu && str_fu->kind == TY_SLICE) ||
|
||||
type_isstr(f->type)) {
|
||||
ins2(c, A_MOVQ,
|
||||
@@ -10913,6 +10953,8 @@ 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;
|
||||
/* tagged leaf (#38a): AX holds the *struct
|
||||
@@ -11070,6 +11112,8 @@ 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;
|
||||
/* #270-1a: an `[N]T`-typed field of an
|
||||
@@ -11232,7 +11276,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
&& let_islet(n->lhs->str)) {
|
||||
bt = let_var_type(n->lhs->str);
|
||||
}
|
||||
Type *u = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
|
||||
Type *u = type_chase_named(bt);
|
||||
Type *eff = idx_eff(bt);
|
||||
int esz = 1;
|
||||
if (eff && eff->sub) esz = (int)eff->sub->size;
|
||||
@@ -11419,7 +11463,8 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
Node *lo = n->rhs;
|
||||
Node *hi = n->cond;
|
||||
Type *bt = base ? base->type : NULL;
|
||||
Type *bu = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
|
||||
/* Transitive chase (#5 alias arc) — see the N_INDEX twin. */
|
||||
Type *bu = type_chase_named(bt);
|
||||
/* esz from the type table for an N_IDENT base (#76) or an
|
||||
* N_DOT array/slice-field base (#252: a struct-field slice
|
||||
* `s.obuf[lo:hi]` must scale by the field's element width, not
|
||||
@@ -13173,10 +13218,13 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
* or pulls each tuple field into its respective local. */
|
||||
Node *slc = n->lhs;
|
||||
Type *st = slc ? slc->type : NULL;
|
||||
Type *u = (st && st->kind == TY_NAMED) ? st->under : st;
|
||||
/* Transitive chase (#5 alias arc): the checker admits range
|
||||
* bases through 2-level alias chains (F0 8b); the single peel
|
||||
* left u TY_NAMED → esz=1 + the non-array base arm (MOVQ of
|
||||
* array words as a pointer — SEGV). */
|
||||
Type *u = type_chase_named(st);
|
||||
int esz = (u && u->sub) ? (int)u->sub->size : 1;
|
||||
Type *etu = (u && u->sub && u->sub->kind == TY_NAMED)
|
||||
? u->sub->under : (u ? u->sub : NULL);
|
||||
Type *etu = type_chase_named(u ? u->sub : NULL);
|
||||
int destruct = (n->list != NULL);
|
||||
|
||||
/* allocate temp slots: _i (8B), _len (8B). #70: a NON-IDENT
|
||||
@@ -14191,6 +14239,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;
|
||||
if (fu && fu->kind == TY_STRUCT) {
|
||||
|
||||
Reference in New Issue
Block a user