wcc/cgen: loud-align static-global tagged cast-init (wwstage align to cstage)

A module-global tagged init via cast (`let g: u = true: u;`) silently
emitted tag=0; cstage louds. Route emittaggeddata through flatvariantidx
(the cstage cg_tag_for_variant twin) so an unsupported variant louds while
valid str/slice cast-inits still accept+run. test/wcc/838.
This commit is contained in:
2026-06-09 19:08:12 +09:00
parent 90452a8364
commit 5c28c90837
5 changed files with 277 additions and 3 deletions

View File

@@ -41336,7 +41336,22 @@ fn emittaggeddata(c: *cgen, name: str, module: str, tt: *node, rhs: *node, sz: i
let r: *node = rhs;
for (r != nil && r.kind == nkind.N_CAST) { r = r.lhs; };
if (r == nil) { return false; };
let tag: i32 = taggedvariantindex(c, tt, r);
// E8/#35: select the variant via flatvariantidx — the EXACT twin of
// cstage emit_tagged_data's cg_tag_for_variant (cmd/w6c/cgen.c:15472).
// taggedvariantindex adds a str/slice SHAPE fallback (cgenutil.ww:3054)
// that cstage does NOT run at this site: a same-type/subset CAST init
// (`let g: u = true: u;`) stamps the peeled literal's type_ as the
// union itself, so flatvariantidx finds no variant and returns -1,
// matching cstage's loud (caller emits "unsupported variant init",
// cgen.ww:2818). The shape fallback instead picked the first scalar
// variant (tag 0) -> SILENT miscompile (ran the int arm on a bool
// value, the S1 coincidence trap). A bare-literal init (`= true` / `=
// 7`) keeps its concrete/untyped type and still resolves via
// flatvariantidx pass 1 (byte-id with cstage); a str-literal CAST
// (`"hi": u`) keeps its str type and resolves to the str variant too.
// Faithful tag-remap for a cast-init static global = the deferred
// #23/#40 nominal widen feature.
let tag: i32 = flatvariantidx(c, tt, r);
if (tag < 0) { return false; };
let wide: bool = nodeisstr(c, r) || nodeisslice(c, r);
let i: i32 = 0;

View File

@@ -2473,7 +2473,22 @@ fn emittaggeddata(c: *cgen, name: str, module: str, tt: *node, rhs: *node, sz: i
let r: *node = rhs;
for (r != nil && r.kind == nkind.N_CAST) { r = r.lhs; };
if (r == nil) { return false; };
let tag: i32 = taggedvariantindex(c, tt, r);
// E8/#35: select the variant via flatvariantidx — the EXACT twin of
// cstage emit_tagged_data's cg_tag_for_variant (cmd/w6c/cgen.c:15472).
// taggedvariantindex adds a str/slice SHAPE fallback (cgenutil.ww:3054)
// that cstage does NOT run at this site: a same-type/subset CAST init
// (`let g: u = true: u;`) stamps the peeled literal's type_ as the
// union itself, so flatvariantidx finds no variant and returns -1,
// matching cstage's loud (caller emits "unsupported variant init",
// cgen.ww:2818). The shape fallback instead picked the first scalar
// variant (tag 0) -> SILENT miscompile (ran the int arm on a bool
// value, the S1 coincidence trap). A bare-literal init (`= true` / `=
// 7`) keeps its concrete/untyped type and still resolves via
// flatvariantidx pass 1 (byte-id with cstage); a str-literal CAST
// (`"hi": u`) keeps its str type and resolves to the str variant too.
// Faithful tag-remap for a cast-init static global = the deferred
// #23/#40 nominal widen feature.
let tag: i32 = flatvariantidx(c, tt, r);
if (tag < 0) { return false; };
let wide: bool = nodeisstr(c, r) || nodeisslice(c, r);
let i: i32 = 0;

View File

@@ -41336,7 +41336,22 @@ fn emittaggeddata(c: *cgen, name: str, module: str, tt: *node, rhs: *node, sz: i
let r: *node = rhs;
for (r != nil && r.kind == nkind.N_CAST) { r = r.lhs; };
if (r == nil) { return false; };
let tag: i32 = taggedvariantindex(c, tt, r);
// E8/#35: select the variant via flatvariantidx — the EXACT twin of
// cstage emit_tagged_data's cg_tag_for_variant (cmd/w6c/cgen.c:15472).
// taggedvariantindex adds a str/slice SHAPE fallback (cgenutil.ww:3054)
// that cstage does NOT run at this site: a same-type/subset CAST init
// (`let g: u = true: u;`) stamps the peeled literal's type_ as the
// union itself, so flatvariantidx finds no variant and returns -1,
// matching cstage's loud (caller emits "unsupported variant init",
// cgen.ww:2818). The shape fallback instead picked the first scalar
// variant (tag 0) -> SILENT miscompile (ran the int arm on a bool
// value, the S1 coincidence trap). A bare-literal init (`= true` / `=
// 7`) keeps its concrete/untyped type and still resolves via
// flatvariantidx pass 1 (byte-id with cstage); a str-literal CAST
// (`"hi": u`) keeps its str type and resolves to the str variant too.
// Faithful tag-remap for a cast-init static global = the deferred
// #23/#40 nominal widen feature.
let tag: i32 = flatvariantidx(c, tt, r);
if (tag < 0) { return false; };
let wide: bool = nodeisstr(c, r) || nodeisslice(c, r);
let i: i32 = 0;