wcc/cgen: #140 !void error-singleton variant as value — skip absent void payload load, emit tag-only (cstage, align up)

A void (size-0) error-singleton type-name used as a VALUE (return / let-init /
assign / call-arg) all share the N_IDENT non-local global-value load; the load
emitted MOVQ main.<singleton>(SB),AX for a payload symbol that never exists →
w6l undefined reference. Guard TY_VOID && !let && !def at the non-local
fallthrough so nothing is emitted; the enclosing widen arm stamps the variant
tag. wwstage was already tag-only correct — this aligns cstage up to it.

Pin test/wcc/949_void_error_singleton_run.c (6 rows, teeth = link-fail
pre-fix). cgen-first blocker for the path::buffer arc (error.ha is all !void).
This commit is contained in:
2026-06-08 00:18:26 +09:00
parent d0a1e2a221
commit 620e733444
3 changed files with 320 additions and 0 deletions

View File

@@ -4062,6 +4062,26 @@ cgexpr(Cg *c, Node *n, Local *locals)
ins2(c, op, amem(D_CX, 0), areg(D_X0));
goto ident_done;
}
/* #140: a `!void` error-singleton spelled as a value
* (`return too_long`, `let e = too_long`,
* `e = too_long`, `f(too_long)`) is a tag-only variant:
* the void payload has size 0 and no storage, so it is
* neither a let nor a def — it reaches this generic
* global-value fallthrough as a bare type-name. Emit
* NOTHING; the enclosing widen arm (N_RETURN scalar arm
* / cg_widen_tagged_store) stamps the variant tag.
* Without this guard the load below emitted
* `MOVQ main.<name>(SB),AX` for a payload symbol that is
* never defined → w6l undefined-reference. wwstage emits
* tag-only already (the runtime-correct reference; align
* cs UP). ken-139 oracle. */
{
Type *vu = type_chase_named(n->type);
if (vu && vu->kind == TY_VOID
&& !let_islet(n->str)
&& !def_isanydef(n->str))
goto ident_done;
}
/* Top-level lets can be the target of `*p` deref-stores
* (via `&letname: *iN`), so a signed-narrow scalar let
* needs MOVSXD/MOVSWQ/MOVSBQ on the read. Defs are