From 5ff5f4b4fe3bedba9c3407c93d550775af41d9c4 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Fri, 12 Jun 2026 22:31:09 +0900 Subject: [PATCH] w6c: tagged GLOBAL reassign emits the store cstage silently dropped the store on reassigning a module-global tagged union; mirror the landed wwstage emission (tag+payload to g(SB) via the widener). Closes the cs half of the F8 #263 pair; the repro row flips to cs==ww==correct. Task #41. --- cmd/w6c/cgen.c | 22 +++++++++++++++- test/wcc/989_globtagreassign_run.c | 41 ++++++++++++------------------ 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index 4a50e816..f800503a 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -6909,7 +6909,27 @@ cgexpr(Cg *c, Node *n, Local *locals) if (!rhs_sret_call) { int off = localfind(locals, n->lhs->str); - if (off == 0) break; + if (off == 0) { + /* #41 (#263): a module-global + * tagged ident has no BP slot — + * LEAQ g(SB),BX then store + * tag+payload off BX (mirror the + * global-struct-field tagged arm + * above + the local arm below). + * Pre-fix this break dropped the + * store entirely; ww half landed + * in F8-c5. */ + if (let_islet(n->lhs->str)) { + ins2(c, A_LEAQ, + masym(c, n->lhs->str), + areg(D_BX)); + cg_widen_tagged_store(c, + &locals, lu, n->rhs, + D_BX, 0, + (int)lu->size); + } + break; + } cg_widen_tagged_store(c, &locals, lu, n->rhs, D_BP, off, (int)lu->size); break; diff --git a/test/wcc/989_globtagreassign_run.c b/test/wcc/989_globtagreassign_run.c index 94a43c7f..aa22dcf0 100644 --- a/test/wcc/989_globtagreassign_run.c +++ b/test/wcc/989_globtagreassign_run.c @@ -3,29 +3,20 @@ * module-GLOBAL tagged-union ident (`g = expr`) must store the new tag and * payload, not clobber only one word. * - * THE BUG (cat-A silent miscompile, #263 BOTH-WRONG): cgenexpr.ww cgassign's - * tagged-union reassignment arm delegated to cgwidentaggedstore ONLY for a - * LOCAL ident (localfindnode != nil). A module-global tagged ident (lc==nil) - * had no arm and fell through to the generic scalar store, which wrote one - * word into the tag slot and left the payload stale. cstage is ALSO wrong: - * it drops the store entirely (the new value never reaches g) — so the repro - * is cs≠ww residual until the cstage half lands (ww-core TASK #41). + * THE BUG (cat-A silent miscompile, #263 BOTH-WRONG, now CLOSED both stages): + * cgassign's tagged-union reassignment arm delegated to the widener ONLY for a + * LOCAL ident. A module-global tagged ident had no arm and fell through to the + * generic scalar store (wwstage clobbered the tag word; cstage dropped the + * store entirely). The ww half landed in F8-c5; the cstage half (LEAQ g(SB),BX + * then cg_widen_tagged_store off BX) landed in ww-core TASK #41 — both stages + * now store the full box and the .s is byte-identical. * - * THE WWSTAGE FIX (ww-runtime-correct): add the lc==nil arm — LEAQ g(SB),BX - * then cgwidentaggedstore stores tag+payload off BX (mirrors the local arm - * and the global-struct-field tagged arm). ww now stores the full box. - * cstage stays wrong → the rows assert ww-correct AND pin cstage's - * documented-wrong value (store dropped → g keeps its init), so the residual - * is never misread as a regression. - * - * Rows (per-driver expected — want_cs / want_ww): - * row | shape | cs | ww - * ----------------+----------------------------------------+----+---- - * reassign_i64 | g:(i64|void)=0; g=7; match i64 | 0 | 7 - * reassign_str | g:(str|i64)=0; g="hello"; match str→len | 88 | 5 - * reassign_union | g:(i64|bool)=0; g=5; match i64 | 0 | 5 - * (cstage drops the store → g keeps its init → the i64/void/i64-tag arm; - * #41 closes the cs side, at which point these become cs==ww.) + * Rows (cs==ww after the cstage half landed): + * row | shape | exit + * ----------------+----------------------------------------+----- + * reassign_i64 | g:(i64|void)=0; g=7; match i64 | 7 + * reassign_str | g:(str|i64)=0; g="hello"; match str→len | 5 + * reassign_union | g:(i64|bool)=0; g=5; match i64 | 5 */ #include #include @@ -61,7 +52,7 @@ static const struct row rows[] = { " case void => return 99;\n" " };\n" "};\n", - 0, 7 }, + 7, 7 }, { "reassign_str", "package main;\n" @@ -73,7 +64,7 @@ static const struct row rows[] = { " case i64 => return 88;\n" " };\n" "};\n", - 88, 5 }, + 5, 5 }, { "reassign_union", "package main;\n" @@ -85,7 +76,7 @@ static const struct row rows[] = { " case bool => return 77;\n" " };\n" "};\n", - 0, 5 }, + 5, 5 }, }; /* run_build — build+run `src` via `driver`; returns the binary's exit