wcc/cgen: #8 def str-array element load — emit + pre-intern def-twin + ww load (both stages)
def C:[N]str; C[i] was loud (undefined main.C) both stages. Three folded fixes, one commit (splitting would ship a bisect point where wwstage silently returns an element address instead of .len): P0: the str-array static-init emitter dropped its vestigial directive =="DATAW" gate so a def table rides the same DATAW-header + DATAR-reloc path as let. A def str/slice table lives in DATAW by w6a's A_DATAR-holder constraint -- placement only; def immutability stays checker-enforced. P1: let_pre_intern / letpreintern walked N_LET only, so a def str-array's element string-literals were never interned (dangling _S_n). Extracted a pre_intern_strarray SSoT helper, called for a def str-array arm too, both stages. Scoped to str fixed arrays; def []T / def [N][]T stay loud (#270). P2: wwstage cgenexpr lacked a defvartnode fallback in the indexed-element classify, so a def str-array element load returned the element address instead of the slice header -- a silent miscompile. One line, aligning wwstage up to cstage (which was correct). C[1].len now = 3 both stages, byte-identical. byte-id 990-997 8/8; w6c/w6c_ww move. test/wcc/819 table-driven. The def-global scalar str index sibling (def S:str; S[0]) stays task #14.
This commit is contained in:
@@ -23401,6 +23401,17 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
etn = idxelemtn(bl.tnode);
|
||||
} else {
|
||||
etn = idxelemtn(letvartnode(c, base.str));
|
||||
// #8/GAP-B: a def-global str/slice-array base lives
|
||||
// in c.defs, not c.lets — letvartnode misses it →
|
||||
// etn nil → elem mis-classified scalar, dropping the
|
||||
// 3-word slice-header load (returns element ADDR not
|
||||
// .len; cstage's Type-based classify loads the full
|
||||
// header, the proven let form). defvartnode is the
|
||||
// def-side sister — same fallback as the base-address
|
||||
// resolution at cgenexpr.ww:1762.
|
||||
if (etn == nil) {
|
||||
etn = idxelemtn(defvartnode(c, base.str));
|
||||
};
|
||||
};
|
||||
// #60: an alias-NAMED base has no element tnode
|
||||
// (idxelemtn sees the N_TNAME leaf, nil) — classify
|
||||
@@ -39618,6 +39629,48 @@ fn emitdatawbyte(b: u8) void = {
|
||||
emitbytes( bb.ptr, 1u64);
|
||||
};
|
||||
|
||||
// preinternstrarray — SSoT for the #18 [N]str element-strlit intern
|
||||
// ORDER (element order, then `...` repeat-fill). Shared by letpreintern's
|
||||
// let arm and the #8/GAP-B def arm so both intern labels in the SAME
|
||||
// order emitstrarraydata references them by — a divergent order would
|
||||
// mis-pair the DATAR rows with their _S_ rodata. au is the chased
|
||||
// TY_ARRAY tinfo, r the N_ARRLIT rhs; caller verified the element is str.
|
||||
fn preinternstrarray(c: *cgen, au: *tinfo, r: *node) void = {
|
||||
let alen: i32 = au.alen: i32;
|
||||
let cnt: i32 = 0;
|
||||
let last_ev: *node = nil;
|
||||
let repeat: bool = false;
|
||||
let e: *node = r.list;
|
||||
for (e != nil && cnt < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
break;
|
||||
};
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev == nil) { break; };
|
||||
if (ev.kind != nkind.N_STRLIT) { break; };
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
last_ev = ev;
|
||||
cnt += 1;
|
||||
e = e.next;
|
||||
};
|
||||
if (repeat && last_ev != nil) {
|
||||
if (last_ev.str.len > 0) {
|
||||
for (cnt < alen) {
|
||||
internstrlit(c, last_ev.str);
|
||||
cnt += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// letpreintern — intern strlits referenced from top-level str-let
|
||||
// initialisers BEFORE emitdatasection runs. Mirrors cmd/w6c/cgen.c
|
||||
// let_pre_intern: emitletdataw later looks up the same label, and
|
||||
@@ -39628,6 +39681,29 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
if (file == nil) { return; };
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
// #8/GAP-B: a `def [N]str` needs the SAME element-strlit
|
||||
// pre-interning as the let [N]str arm (the #18 ordering
|
||||
// contract) so emitstrarraydata's DATAR rows find their _S_
|
||||
// rodata. letpreintern walked only N_LET; a def's labels were
|
||||
// allocated too late (emitdefconstants pass) → dangling _S_.
|
||||
// Str-array ONLY — def tuple/slice/tagged/scalar-str stay out
|
||||
// of scope (#10/#270 / inline-Sdef).
|
||||
if (d.kind == nkind.N_DEF) {
|
||||
let dr: *node = d.rhs;
|
||||
for (dr != nil && dr.kind == nkind.N_CAST) {
|
||||
dr = dr.lhs;
|
||||
};
|
||||
if (d.lhs != nil && dr != nil
|
||||
&& dr.kind == nkind.N_ARRLIT) {
|
||||
let dau: *tinfo = tichase(d.lhs.type_: *tinfo);
|
||||
if (dau != nil && dau.kind == tykind.TY_ARRAY) {
|
||||
let deu: *tinfo = tichase(dau.sub);
|
||||
if (deu != nil && deu.kind == tykind.TY_STR) {
|
||||
preinternstrarray(c, dau, dr);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (d.kind == nkind.N_LET) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
@@ -39650,39 +39726,7 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
let eu: *tinfo = tichase(au.sub);
|
||||
if (eu != nil && eu.kind == tykind.TY_STR) {
|
||||
handled = true;
|
||||
let alen: i32 = au.alen: i32;
|
||||
let cnt: i32 = 0;
|
||||
let last_ev: *node = nil;
|
||||
let repeat: bool = false;
|
||||
let e: *node = r.list;
|
||||
for (e != nil && cnt < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
break;
|
||||
};
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev == nil) { break; };
|
||||
if (ev.kind != nkind.N_STRLIT) { break; };
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
last_ev = ev;
|
||||
cnt += 1;
|
||||
e = e.next;
|
||||
};
|
||||
if (repeat && last_ev != nil) {
|
||||
if (last_ev.str.len > 0) {
|
||||
for (cnt < alen) {
|
||||
internstrlit(c, last_ev.str);
|
||||
cnt += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
preinternstrarray(c, au, r);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -40342,9 +40386,11 @@ fn emitarraylitbytes(c: *cgen, arrt: *tinfo, rhs: *node,
|
||||
// pattern (DATAW header with a zero ptr placeholder + inline LE len,
|
||||
// then a per-element DATAR) at offset idx*esz. Each strlit was pre-
|
||||
// interned by letpreintern so its _S_ rodata row exists before this
|
||||
// row's DATAR references it. Scoped to DATAW (writable `let`): A_DATAR
|
||||
// requires a DATAW holder, so a read-only `def [N]str` can't carry the
|
||||
// relocs (#18 follow-up). Returns false when the element type isn't str.
|
||||
// row's DATAR references it. Always emits into DATAW (writable): A_DATAR
|
||||
// requires a DATAW holder, so both `let` and a read-only `def [N]str`
|
||||
// (#8/GAP-B) park their backing here — the section bit is the reloc-
|
||||
// holder constraint, not a mutability grant (def immutability stays
|
||||
// checker-enforced). Returns false when the element type isn't str.
|
||||
fn emitstrarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
arrt: *tinfo, rhs: *node) bool = {
|
||||
let au: *tinfo = arrt;
|
||||
@@ -40355,7 +40401,17 @@ fn emitstrarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
eu = tichase(eu);
|
||||
if (eu == nil) { return false; };
|
||||
if (eu.kind != tykind.TY_STR) { return false; };
|
||||
if (!streq(directive, "DATAW")) { return false; };
|
||||
// #8/GAP-B: a str-element array's backing ALWAYS lives in DATAW
|
||||
// (writable section), regardless of the caller's let/def directive —
|
||||
// each element carries an A_DATAR ptr-reloc to its _S_ rodata row, and
|
||||
// w6a requires a DATAR holder be a DATAW slot (asm.c:362). The passed
|
||||
// directive ("DATA" for a def, "DATAW" for a let) is therefore IGNORED
|
||||
// here; the emit below hardcodes DATAW. A `def [N]str` stays immutable
|
||||
// — the checker rejects writes to a def; DATAW is only the reloc-holder
|
||||
// placement, not a mutability grant (rule-8 placement detail). Pre-fix
|
||||
// this gate skipped the def path → no DATA block → w6l undefined
|
||||
// 'main.C' (#270 lineage; int-def is plain DATA, no holder constraint,
|
||||
// so it was unaffected).
|
||||
let esz: i32 = au.sub.size: i32;
|
||||
let alen: i32 = au.alen: i32;
|
||||
|
||||
|
||||
@@ -1350,6 +1350,48 @@ fn emitdatawbyte(b: u8) void = {
|
||||
emitbytes( bb.ptr, 1u64);
|
||||
};
|
||||
|
||||
// preinternstrarray — SSoT for the #18 [N]str element-strlit intern
|
||||
// ORDER (element order, then `...` repeat-fill). Shared by letpreintern's
|
||||
// let arm and the #8/GAP-B def arm so both intern labels in the SAME
|
||||
// order emitstrarraydata references them by — a divergent order would
|
||||
// mis-pair the DATAR rows with their _S_ rodata. au is the chased
|
||||
// TY_ARRAY tinfo, r the N_ARRLIT rhs; caller verified the element is str.
|
||||
fn preinternstrarray(c: *cgen, au: *tinfo, r: *node) void = {
|
||||
let alen: i32 = au.alen: i32;
|
||||
let cnt: i32 = 0;
|
||||
let last_ev: *node = nil;
|
||||
let repeat: bool = false;
|
||||
let e: *node = r.list;
|
||||
for (e != nil && cnt < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
break;
|
||||
};
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev == nil) { break; };
|
||||
if (ev.kind != nkind.N_STRLIT) { break; };
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
last_ev = ev;
|
||||
cnt += 1;
|
||||
e = e.next;
|
||||
};
|
||||
if (repeat && last_ev != nil) {
|
||||
if (last_ev.str.len > 0) {
|
||||
for (cnt < alen) {
|
||||
internstrlit(c, last_ev.str);
|
||||
cnt += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// letpreintern — intern strlits referenced from top-level str-let
|
||||
// initialisers BEFORE emitdatasection runs. Mirrors cmd/w6c/cgen.c
|
||||
// let_pre_intern: emitletdataw later looks up the same label, and
|
||||
@@ -1360,6 +1402,29 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
if (file == nil) { return; };
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
// #8/GAP-B: a `def [N]str` needs the SAME element-strlit
|
||||
// pre-interning as the let [N]str arm (the #18 ordering
|
||||
// contract) so emitstrarraydata's DATAR rows find their _S_
|
||||
// rodata. letpreintern walked only N_LET; a def's labels were
|
||||
// allocated too late (emitdefconstants pass) → dangling _S_.
|
||||
// Str-array ONLY — def tuple/slice/tagged/scalar-str stay out
|
||||
// of scope (#10/#270 / inline-Sdef).
|
||||
if (d.kind == nkind.N_DEF) {
|
||||
let dr: *node = d.rhs;
|
||||
for (dr != nil && dr.kind == nkind.N_CAST) {
|
||||
dr = dr.lhs;
|
||||
};
|
||||
if (d.lhs != nil && dr != nil
|
||||
&& dr.kind == nkind.N_ARRLIT) {
|
||||
let dau: *tinfo = tichase(d.lhs.type_: *tinfo);
|
||||
if (dau != nil && dau.kind == tykind.TY_ARRAY) {
|
||||
let deu: *tinfo = tichase(dau.sub);
|
||||
if (deu != nil && deu.kind == tykind.TY_STR) {
|
||||
preinternstrarray(c, dau, dr);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (d.kind == nkind.N_LET) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
@@ -1382,39 +1447,7 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
let eu: *tinfo = tichase(au.sub);
|
||||
if (eu != nil && eu.kind == tykind.TY_STR) {
|
||||
handled = true;
|
||||
let alen: i32 = au.alen: i32;
|
||||
let cnt: i32 = 0;
|
||||
let last_ev: *node = nil;
|
||||
let repeat: bool = false;
|
||||
let e: *node = r.list;
|
||||
for (e != nil && cnt < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
break;
|
||||
};
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev == nil) { break; };
|
||||
if (ev.kind != nkind.N_STRLIT) { break; };
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
last_ev = ev;
|
||||
cnt += 1;
|
||||
e = e.next;
|
||||
};
|
||||
if (repeat && last_ev != nil) {
|
||||
if (last_ev.str.len > 0) {
|
||||
for (cnt < alen) {
|
||||
internstrlit(c, last_ev.str);
|
||||
cnt += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
preinternstrarray(c, au, r);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -2074,9 +2107,11 @@ fn emitarraylitbytes(c: *cgen, arrt: *tinfo, rhs: *node,
|
||||
// pattern (DATAW header with a zero ptr placeholder + inline LE len,
|
||||
// then a per-element DATAR) at offset idx*esz. Each strlit was pre-
|
||||
// interned by letpreintern so its _S_ rodata row exists before this
|
||||
// row's DATAR references it. Scoped to DATAW (writable `let`): A_DATAR
|
||||
// requires a DATAW holder, so a read-only `def [N]str` can't carry the
|
||||
// relocs (#18 follow-up). Returns false when the element type isn't str.
|
||||
// row's DATAR references it. Always emits into DATAW (writable): A_DATAR
|
||||
// requires a DATAW holder, so both `let` and a read-only `def [N]str`
|
||||
// (#8/GAP-B) park their backing here — the section bit is the reloc-
|
||||
// holder constraint, not a mutability grant (def immutability stays
|
||||
// checker-enforced). Returns false when the element type isn't str.
|
||||
fn emitstrarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
arrt: *tinfo, rhs: *node) bool = {
|
||||
let au: *tinfo = arrt;
|
||||
@@ -2087,7 +2122,17 @@ fn emitstrarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
eu = tichase(eu);
|
||||
if (eu == nil) { return false; };
|
||||
if (eu.kind != tykind.TY_STR) { return false; };
|
||||
if (!streq(directive, "DATAW")) { return false; };
|
||||
// #8/GAP-B: a str-element array's backing ALWAYS lives in DATAW
|
||||
// (writable section), regardless of the caller's let/def directive —
|
||||
// each element carries an A_DATAR ptr-reloc to its _S_ rodata row, and
|
||||
// w6a requires a DATAR holder be a DATAW slot (asm.c:362). The passed
|
||||
// directive ("DATA" for a def, "DATAW" for a let) is therefore IGNORED
|
||||
// here; the emit below hardcodes DATAW. A `def [N]str` stays immutable
|
||||
// — the checker rejects writes to a def; DATAW is only the reloc-holder
|
||||
// placement, not a mutability grant (rule-8 placement detail). Pre-fix
|
||||
// this gate skipped the def path → no DATA block → w6l undefined
|
||||
// 'main.C' (#270 lineage; int-def is plain DATA, no holder constraint,
|
||||
// so it was unaffected).
|
||||
let esz: i32 = au.sub.size: i32;
|
||||
let alen: i32 = au.alen: i32;
|
||||
|
||||
|
||||
@@ -1881,6 +1881,17 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
etn = idxelemtn(bl.tnode);
|
||||
} else {
|
||||
etn = idxelemtn(letvartnode(c, base.str));
|
||||
// #8/GAP-B: a def-global str/slice-array base lives
|
||||
// in c.defs, not c.lets — letvartnode misses it →
|
||||
// etn nil → elem mis-classified scalar, dropping the
|
||||
// 3-word slice-header load (returns element ADDR not
|
||||
// .len; cstage's Type-based classify loads the full
|
||||
// header, the proven let form). defvartnode is the
|
||||
// def-side sister — same fallback as the base-address
|
||||
// resolution at cgenexpr.ww:1762.
|
||||
if (etn == nil) {
|
||||
etn = idxelemtn(defvartnode(c, base.str));
|
||||
};
|
||||
};
|
||||
// #60: an alias-NAMED base has no element tnode
|
||||
// (idxelemtn sees the N_TNAME leaf, nil) — classify
|
||||
|
||||
@@ -23401,6 +23401,17 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
etn = idxelemtn(bl.tnode);
|
||||
} else {
|
||||
etn = idxelemtn(letvartnode(c, base.str));
|
||||
// #8/GAP-B: a def-global str/slice-array base lives
|
||||
// in c.defs, not c.lets — letvartnode misses it →
|
||||
// etn nil → elem mis-classified scalar, dropping the
|
||||
// 3-word slice-header load (returns element ADDR not
|
||||
// .len; cstage's Type-based classify loads the full
|
||||
// header, the proven let form). defvartnode is the
|
||||
// def-side sister — same fallback as the base-address
|
||||
// resolution at cgenexpr.ww:1762.
|
||||
if (etn == nil) {
|
||||
etn = idxelemtn(defvartnode(c, base.str));
|
||||
};
|
||||
};
|
||||
// #60: an alias-NAMED base has no element tnode
|
||||
// (idxelemtn sees the N_TNAME leaf, nil) — classify
|
||||
@@ -39618,6 +39629,48 @@ fn emitdatawbyte(b: u8) void = {
|
||||
emitbytes( bb.ptr, 1u64);
|
||||
};
|
||||
|
||||
// preinternstrarray — SSoT for the #18 [N]str element-strlit intern
|
||||
// ORDER (element order, then `...` repeat-fill). Shared by letpreintern's
|
||||
// let arm and the #8/GAP-B def arm so both intern labels in the SAME
|
||||
// order emitstrarraydata references them by — a divergent order would
|
||||
// mis-pair the DATAR rows with their _S_ rodata. au is the chased
|
||||
// TY_ARRAY tinfo, r the N_ARRLIT rhs; caller verified the element is str.
|
||||
fn preinternstrarray(c: *cgen, au: *tinfo, r: *node) void = {
|
||||
let alen: i32 = au.alen: i32;
|
||||
let cnt: i32 = 0;
|
||||
let last_ev: *node = nil;
|
||||
let repeat: bool = false;
|
||||
let e: *node = r.list;
|
||||
for (e != nil && cnt < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
break;
|
||||
};
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev == nil) { break; };
|
||||
if (ev.kind != nkind.N_STRLIT) { break; };
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
last_ev = ev;
|
||||
cnt += 1;
|
||||
e = e.next;
|
||||
};
|
||||
if (repeat && last_ev != nil) {
|
||||
if (last_ev.str.len > 0) {
|
||||
for (cnt < alen) {
|
||||
internstrlit(c, last_ev.str);
|
||||
cnt += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// letpreintern — intern strlits referenced from top-level str-let
|
||||
// initialisers BEFORE emitdatasection runs. Mirrors cmd/w6c/cgen.c
|
||||
// let_pre_intern: emitletdataw later looks up the same label, and
|
||||
@@ -39628,6 +39681,29 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
if (file == nil) { return; };
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
// #8/GAP-B: a `def [N]str` needs the SAME element-strlit
|
||||
// pre-interning as the let [N]str arm (the #18 ordering
|
||||
// contract) so emitstrarraydata's DATAR rows find their _S_
|
||||
// rodata. letpreintern walked only N_LET; a def's labels were
|
||||
// allocated too late (emitdefconstants pass) → dangling _S_.
|
||||
// Str-array ONLY — def tuple/slice/tagged/scalar-str stay out
|
||||
// of scope (#10/#270 / inline-Sdef).
|
||||
if (d.kind == nkind.N_DEF) {
|
||||
let dr: *node = d.rhs;
|
||||
for (dr != nil && dr.kind == nkind.N_CAST) {
|
||||
dr = dr.lhs;
|
||||
};
|
||||
if (d.lhs != nil && dr != nil
|
||||
&& dr.kind == nkind.N_ARRLIT) {
|
||||
let dau: *tinfo = tichase(d.lhs.type_: *tinfo);
|
||||
if (dau != nil && dau.kind == tykind.TY_ARRAY) {
|
||||
let deu: *tinfo = tichase(dau.sub);
|
||||
if (deu != nil && deu.kind == tykind.TY_STR) {
|
||||
preinternstrarray(c, dau, dr);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (d.kind == nkind.N_LET) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
@@ -39650,39 +39726,7 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
let eu: *tinfo = tichase(au.sub);
|
||||
if (eu != nil && eu.kind == tykind.TY_STR) {
|
||||
handled = true;
|
||||
let alen: i32 = au.alen: i32;
|
||||
let cnt: i32 = 0;
|
||||
let last_ev: *node = nil;
|
||||
let repeat: bool = false;
|
||||
let e: *node = r.list;
|
||||
for (e != nil && cnt < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
break;
|
||||
};
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev == nil) { break; };
|
||||
if (ev.kind != nkind.N_STRLIT) { break; };
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
last_ev = ev;
|
||||
cnt += 1;
|
||||
e = e.next;
|
||||
};
|
||||
if (repeat && last_ev != nil) {
|
||||
if (last_ev.str.len > 0) {
|
||||
for (cnt < alen) {
|
||||
internstrlit(c, last_ev.str);
|
||||
cnt += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
preinternstrarray(c, au, r);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -40342,9 +40386,11 @@ fn emitarraylitbytes(c: *cgen, arrt: *tinfo, rhs: *node,
|
||||
// pattern (DATAW header with a zero ptr placeholder + inline LE len,
|
||||
// then a per-element DATAR) at offset idx*esz. Each strlit was pre-
|
||||
// interned by letpreintern so its _S_ rodata row exists before this
|
||||
// row's DATAR references it. Scoped to DATAW (writable `let`): A_DATAR
|
||||
// requires a DATAW holder, so a read-only `def [N]str` can't carry the
|
||||
// relocs (#18 follow-up). Returns false when the element type isn't str.
|
||||
// row's DATAR references it. Always emits into DATAW (writable): A_DATAR
|
||||
// requires a DATAW holder, so both `let` and a read-only `def [N]str`
|
||||
// (#8/GAP-B) park their backing here — the section bit is the reloc-
|
||||
// holder constraint, not a mutability grant (def immutability stays
|
||||
// checker-enforced). Returns false when the element type isn't str.
|
||||
fn emitstrarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
arrt: *tinfo, rhs: *node) bool = {
|
||||
let au: *tinfo = arrt;
|
||||
@@ -40355,7 +40401,17 @@ fn emitstrarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
eu = tichase(eu);
|
||||
if (eu == nil) { return false; };
|
||||
if (eu.kind != tykind.TY_STR) { return false; };
|
||||
if (!streq(directive, "DATAW")) { return false; };
|
||||
// #8/GAP-B: a str-element array's backing ALWAYS lives in DATAW
|
||||
// (writable section), regardless of the caller's let/def directive —
|
||||
// each element carries an A_DATAR ptr-reloc to its _S_ rodata row, and
|
||||
// w6a requires a DATAR holder be a DATAW slot (asm.c:362). The passed
|
||||
// directive ("DATA" for a def, "DATAW" for a let) is therefore IGNORED
|
||||
// here; the emit below hardcodes DATAW. A `def [N]str` stays immutable
|
||||
// — the checker rejects writes to a def; DATAW is only the reloc-holder
|
||||
// placement, not a mutability grant (rule-8 placement detail). Pre-fix
|
||||
// this gate skipped the def path → no DATA block → w6l undefined
|
||||
// 'main.C' (#270 lineage; int-def is plain DATA, no holder constraint,
|
||||
// so it was unaffected).
|
||||
let esz: i32 = au.sub.size: i32;
|
||||
let alen: i32 = au.alen: i32;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user