w6c+wwstage: store struct-literal array-field init (#249 BUG A)
A struct literal initialising an array-typed field as a local
(`e{ encmap = [..] }`) silently dropped the initializer: cg_structlit_fill
(cstage) / cgstructlitfill (wwstage) had no TY_ARRAY field arm, so the
array field fell to the generic scalar tail — cgexpr the N_ARRLIT (→ AX≈0)
then store one sized word — losing every element. cstage returned 0;
wwstage emitted byte-identical wrong code. (The GLOBAL literal-init path
is unaffected: it goes through emit_struct_lit_bytes, already correct via
#129 A.3.)
Both stages now element-wise store the N_ARRLIT at base+field_off+i*esz,
reusing the proven N_LET array-init shape (cgen.c:8467 / cgenstmt.ww:1393)
for int and float elements plus its `...` repeat fill; esz routes through
the type table (rule 13). str/slice/struct/tagged ELEMENT arrays are the
N_LET path's documented multi-word gap (cgen.c:8462) — converted from the
silent drop to a LOUD rule-7 error in both stages, not left silent.
Symmetric both stages (rule 10), byte-identical .s.
The `...` repeat in a struct-literal array field is checker-unreachable
today (the field type-check rejects `[v...]` length inference — a
separate checker gap); the arm mirrors N_LET's repeat for symmetry.
Test 949_structlit_arrfield_run: +local literal-init reads (idx 0 / last
element), cstage run + cs==ww byte-id.
This commit is contained in:
@@ -19036,6 +19036,140 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
emitline("\n");
|
||||
};
|
||||
fi = nil;
|
||||
} else if (fi.tnode != nil
|
||||
&& fi.tnode.kind == nkind.N_TARRAY
|
||||
&& fieldnode.lhs != nil
|
||||
&& fieldnode.lhs.kind == nkind.N_ARRLIT) {
|
||||
// #249: array field from an N_ARRLIT. Without this
|
||||
// the generic tail below cgexprs the N_ARRLIT (→ AX)
|
||||
// and stores one sized word, silently DROPPING every
|
||||
// element. Store element-wise at disp+foff+i*esz,
|
||||
// mirroring the N_LET array-init path
|
||||
// (cgenstmt.ww:1393). int/float elements only;
|
||||
// str/slice/struct/tagged elements are the N_LET
|
||||
// multi-word gap — loud rule-7 error (cstage
|
||||
// cg_structlit_fill twin).
|
||||
let elemn: *node = fi.tnode.lhs;
|
||||
let isstrel: bool = isstrtype(c, elemn);
|
||||
let istagel: bool = istaggedtype(c, elemn);
|
||||
let issliceel: bool = false;
|
||||
let isstructel: bool = false;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TSLICE) {
|
||||
issliceel = true;
|
||||
};
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
if (primsize(elemn.str) == 0) {
|
||||
if (structlookup(c, elemn.str) != nil) {
|
||||
isstructel = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (isstrel || issliceel || isstructel || istagel) {
|
||||
let e1: str = "ww: struct-literal array field '";
|
||||
os.write(2, e1.ptr, e1.len: u64);
|
||||
os.write(2, fname.ptr, fname.len: u64);
|
||||
let e2: str = "' has a str/slice/struct/tagged element — multi-word element store out of #249 scope (N_LET array-init gap)\n";
|
||||
os.write(2, e2.ptr, e2.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let esz: i32 = 8;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
let isfloatel: bool = isfloattype(c, elemn);
|
||||
let fmov: str = "MOVSD";
|
||||
if (isf32type(c, elemn)) { fmov = "MOVSS"; };
|
||||
let idx: i32 = 0;
|
||||
let repeat: bool = false;
|
||||
let e: *node = fieldnode.lhs.list;
|
||||
for (e != nil) {
|
||||
let isellip: bool = false;
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
isellip = true;
|
||||
};
|
||||
};
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat) {
|
||||
let total: i32 = idx;
|
||||
if (fi.tnode.rhs != nil) {
|
||||
if (fi.tnode.rhs.kind == nkind.N_INTLIT) {
|
||||
total = fi.tnode.rhs.uval: i32;
|
||||
};
|
||||
};
|
||||
for (idx < total) {
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
};
|
||||
};
|
||||
fi = nil;
|
||||
} else {
|
||||
cgexpr(c, fieldnode.lhs);
|
||||
// For non-BP modes, cgexpr just clobbered
|
||||
|
||||
@@ -3743,6 +3743,140 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
emitline("\n");
|
||||
};
|
||||
fi = nil;
|
||||
} else if (fi.tnode != nil
|
||||
&& fi.tnode.kind == nkind.N_TARRAY
|
||||
&& fieldnode.lhs != nil
|
||||
&& fieldnode.lhs.kind == nkind.N_ARRLIT) {
|
||||
// #249: array field from an N_ARRLIT. Without this
|
||||
// the generic tail below cgexprs the N_ARRLIT (→ AX)
|
||||
// and stores one sized word, silently DROPPING every
|
||||
// element. Store element-wise at disp+foff+i*esz,
|
||||
// mirroring the N_LET array-init path
|
||||
// (cgenstmt.ww:1393). int/float elements only;
|
||||
// str/slice/struct/tagged elements are the N_LET
|
||||
// multi-word gap — loud rule-7 error (cstage
|
||||
// cg_structlit_fill twin).
|
||||
let elemn: *node = fi.tnode.lhs;
|
||||
let isstrel: bool = isstrtype(c, elemn);
|
||||
let istagel: bool = istaggedtype(c, elemn);
|
||||
let issliceel: bool = false;
|
||||
let isstructel: bool = false;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TSLICE) {
|
||||
issliceel = true;
|
||||
};
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
if (primsize(elemn.str) == 0) {
|
||||
if (structlookup(c, elemn.str) != nil) {
|
||||
isstructel = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (isstrel || issliceel || isstructel || istagel) {
|
||||
let e1: str = "ww: struct-literal array field '";
|
||||
os.write(2, e1.ptr, e1.len: u64);
|
||||
os.write(2, fname.ptr, fname.len: u64);
|
||||
let e2: str = "' has a str/slice/struct/tagged element — multi-word element store out of #249 scope (N_LET array-init gap)\n";
|
||||
os.write(2, e2.ptr, e2.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let esz: i32 = 8;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
let isfloatel: bool = isfloattype(c, elemn);
|
||||
let fmov: str = "MOVSD";
|
||||
if (isf32type(c, elemn)) { fmov = "MOVSS"; };
|
||||
let idx: i32 = 0;
|
||||
let repeat: bool = false;
|
||||
let e: *node = fieldnode.lhs.list;
|
||||
for (e != nil) {
|
||||
let isellip: bool = false;
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
isellip = true;
|
||||
};
|
||||
};
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat) {
|
||||
let total: i32 = idx;
|
||||
if (fi.tnode.rhs != nil) {
|
||||
if (fi.tnode.rhs.kind == nkind.N_INTLIT) {
|
||||
total = fi.tnode.rhs.uval: i32;
|
||||
};
|
||||
};
|
||||
for (idx < total) {
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
};
|
||||
};
|
||||
fi = nil;
|
||||
} else {
|
||||
cgexpr(c, fieldnode.lhs);
|
||||
// For non-BP modes, cgexpr just clobbered
|
||||
|
||||
@@ -19036,6 +19036,140 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
emitline("\n");
|
||||
};
|
||||
fi = nil;
|
||||
} else if (fi.tnode != nil
|
||||
&& fi.tnode.kind == nkind.N_TARRAY
|
||||
&& fieldnode.lhs != nil
|
||||
&& fieldnode.lhs.kind == nkind.N_ARRLIT) {
|
||||
// #249: array field from an N_ARRLIT. Without this
|
||||
// the generic tail below cgexprs the N_ARRLIT (→ AX)
|
||||
// and stores one sized word, silently DROPPING every
|
||||
// element. Store element-wise at disp+foff+i*esz,
|
||||
// mirroring the N_LET array-init path
|
||||
// (cgenstmt.ww:1393). int/float elements only;
|
||||
// str/slice/struct/tagged elements are the N_LET
|
||||
// multi-word gap — loud rule-7 error (cstage
|
||||
// cg_structlit_fill twin).
|
||||
let elemn: *node = fi.tnode.lhs;
|
||||
let isstrel: bool = isstrtype(c, elemn);
|
||||
let istagel: bool = istaggedtype(c, elemn);
|
||||
let issliceel: bool = false;
|
||||
let isstructel: bool = false;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TSLICE) {
|
||||
issliceel = true;
|
||||
};
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
if (primsize(elemn.str) == 0) {
|
||||
if (structlookup(c, elemn.str) != nil) {
|
||||
isstructel = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (isstrel || issliceel || isstructel || istagel) {
|
||||
let e1: str = "ww: struct-literal array field '";
|
||||
os.write(2, e1.ptr, e1.len: u64);
|
||||
os.write(2, fname.ptr, fname.len: u64);
|
||||
let e2: str = "' has a str/slice/struct/tagged element — multi-word element store out of #249 scope (N_LET array-init gap)\n";
|
||||
os.write(2, e2.ptr, e2.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let esz: i32 = 8;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
let isfloatel: bool = isfloattype(c, elemn);
|
||||
let fmov: str = "MOVSD";
|
||||
if (isf32type(c, elemn)) { fmov = "MOVSS"; };
|
||||
let idx: i32 = 0;
|
||||
let repeat: bool = false;
|
||||
let e: *node = fieldnode.lhs.list;
|
||||
for (e != nil) {
|
||||
let isellip: bool = false;
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
isellip = true;
|
||||
};
|
||||
};
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat) {
|
||||
let total: i32 = idx;
|
||||
if (fi.tnode.rhs != nil) {
|
||||
if (fi.tnode.rhs.kind == nkind.N_INTLIT) {
|
||||
total = fi.tnode.rhs.uval: i32;
|
||||
};
|
||||
};
|
||||
for (idx < total) {
|
||||
if (mode == 1) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(srcoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
if (mode == 2) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
let eoff: i32 = disp + fi.foff + idx * esz;
|
||||
if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
};
|
||||
if (mode == 0) {
|
||||
emitoff(eoff: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitdispreg(eoff: i64, basereg);
|
||||
emitline("\n");
|
||||
};
|
||||
idx += 1;
|
||||
};
|
||||
};
|
||||
fi = nil;
|
||||
} else {
|
||||
cgexpr(c, fieldnode.lhs);
|
||||
// For non-BP modes, cgexpr just clobbered
|
||||
|
||||
Reference in New Issue
Block a user