wwstage: resolve deref-store width through type aliases so *(!i32-alias) narrows (#11)

The deref-store *p=v integer arm computed width by name-keying the pointee node (primsize(pe.str)), so a pointer to a !-flagged or otherwise non-primitive-named alias (os.errno = !i32) fell to the MOVQ default where cstage type-resolves to MOVL (cgen.c:4647-4652) -- cs!=ww and a latent 4-byte over-write. Add a primsize-first fallback to the existing typenodeprimresolved (peels N_TBANG/N_TENUM/N_TNAME alias chains to the underlying primitive) so *(!i32-alias) narrows to MOVL. primsize-first preserves *bool/*i32/*u8 byte-id (typenodeprimresolved excludes bool). Adds test/wcc/786 (store through *(!i32-alias) then read an adjacent field -- over-write guard -- plus a plain-*i32 control). The residual name-blind cases (non-ident pointers, str/float/bool aliases, size-2 i16/u16) are routed to #10/#12. Unblocks errno's opaque_ tail store. rule-10 fix-up: wwstage aligned up to cstage.
This commit is contained in:
2026-05-30 05:29:58 +09:00
parent 34c437fd63
commit 0eb3465919
5 changed files with 322 additions and 0 deletions

View File

@@ -22571,6 +22571,20 @@ fn cgassign(c: *cgen, n: *node) void = {
else { if (streq(pe.str, "f32")) { elemfloat = true; elemf32 = true; }
else {
let ps: i32 = primsize(pe.str);
// #11: primsize is name-keyed and
// misses a `!`/enum/name alias
// (`type errno = !i32`); peel it to
// the underlying primitive width so
// the store narrows, as cstage's
// type-resolved pointee does
// (cgen.c:4647-4652). Residual:
// non-ident pointers + str/float-alias
// deref-store widths stay name-blind
// (#10 wwstage->tinfo SSoT).
if (ps == 0) {
let uns: bool = false;
typenodeprimresolved(c, pe, &ps, &uns);
};
if (ps == 1) { storeop = "MOVB"; }
else { if (ps == 4) { storeop = "MOVL"; }; };
}; }; };

View File

@@ -4427,6 +4427,20 @@ fn cgassign(c: *cgen, n: *node) void = {
else { if (streq(pe.str, "f32")) { elemfloat = true; elemf32 = true; }
else {
let ps: i32 = primsize(pe.str);
// #11: primsize is name-keyed and
// misses a `!`/enum/name alias
// (`type errno = !i32`); peel it to
// the underlying primitive width so
// the store narrows, as cstage's
// type-resolved pointee does
// (cgen.c:4647-4652). Residual:
// non-ident pointers + str/float-alias
// deref-store widths stay name-blind
// (#10 wwstage->tinfo SSoT).
if (ps == 0) {
let uns: bool = false;
typenodeprimresolved(c, pe, &ps, &uns);
};
if (ps == 1) { storeop = "MOVB"; }
else { if (ps == 4) { storeop = "MOVL"; }; };
}; }; };

View File

@@ -22571,6 +22571,20 @@ fn cgassign(c: *cgen, n: *node) void = {
else { if (streq(pe.str, "f32")) { elemfloat = true; elemf32 = true; }
else {
let ps: i32 = primsize(pe.str);
// #11: primsize is name-keyed and
// misses a `!`/enum/name alias
// (`type errno = !i32`); peel it to
// the underlying primitive width so
// the store narrows, as cstage's
// type-resolved pointee does
// (cgen.c:4647-4652). Residual:
// non-ident pointers + str/float-alias
// deref-store widths stay name-blind
// (#10 wwstage->tinfo SSoT).
if (ps == 0) {
let uns: bool = false;
typenodeprimresolved(c, pe, &ps, &uns);
};
if (ps == 1) { storeop = "MOVB"; }
else { if (ps == 4) { storeop = "MOVL"; }; };
}; }; };