wcc: for-range destructure copies the full str/slice binding, both stages

The per-binding copy loop moved ONE word of a 24B str/slice binding —
.len and .cap read zero/garbage in BOTH stages (byte-identical, the
deepest both-wrong-identical of the drain: the F7-era stride fix
asserted convergence without re-measuring the absolute). Copy the full
extent for an sz>8 str/slice binding; the rewritten 989_tupfieldsize
pins all three header words with sliced caps so cap!=len has teeth.
The tagged-binding arm remains open as task #53 (wwstage
paramfieldsize). Review-era task #40, recategorized #263 fused.

Both stages move in one commit: one emission contract; splitting
would leave the byte-id gates red between the halves.
This commit is contained in:
2026-06-12 22:52:20 +09:00
parent 77747061c6
commit 2a2ac49c64
5 changed files with 252 additions and 25 deletions

View File

@@ -14344,6 +14344,50 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
}
} else {
for (int b = 0; b < nbinds; b++) {
/* #40 (#263): a str/slice/struct destructure
* binding (24B header / aggregate, sz>8) copies
* its FULL extent — the single fldloadop word
* truncated a slice binding to its .ptr, dropping
* .len/.cap (both stages identically, byte-id-
* WRONG; F7-c4 fixed only the STRIDE). Same
* word-run + sized-tail idiom as the non-
* destructure aggregate copy above. */
int bsz = binds[b].sz;
if (bsz > 8) {
int k = 0;
for (; k + 8 <= bsz; k += 8) {
ins2(c, A_MOVQ,
amem(D_BX, binds[b].foff + k),
areg(D_AX));
ins2(c, A_MOVQ, areg(D_AX),
amem(D_BP, binds[b].off + k));
}
if (k + 4 <= bsz) {
ins2(c, A_MOVL,
amem(D_BX, binds[b].foff + k),
areg(D_AX));
ins2(c, A_MOVL, areg(D_AX),
amem(D_BP, binds[b].off + k));
k += 4;
}
if (k + 2 <= bsz) {
ins2(c, A_MOVW,
amem(D_BX, binds[b].foff + k),
areg(D_AX));
ins2(c, A_MOVW, areg(D_AX),
amem(D_BP, binds[b].off + k));
k += 2;
}
if (k + 1 <= bsz) {
ins2(c, A_MOVB,
amem(D_BX, binds[b].foff + k),
areg(D_AX));
ins2(c, A_MOVB, areg(D_AX),
amem(D_BP, binds[b].off + k));
k += 1;
}
continue;
}
int op = fldloadop(binds[b].ftype, binds[b].sz);
ins2(c, op, amem(D_BX, binds[b].foff),
areg(D_AX));