selfhost+test: zero-init !void / void-alias let-decl slots (#22)
Wwstage's cglet skipped MOVQ $0 for sz=8 slots that cstage zero-inits unconditionally — !void error types (utf8.invalid) and void-alias variant tags (utf8.done / utf8.more) drifted byte-id post-utf8 + lib/strings; promotes STATUS-3 #22 from latent to bootstrap-blocking. Cstage emits MOVQ $0, -K(BP) in the prologue for any sz=8 let-decl slot via the natural type-fallthrough; wwstage's `typeis8byteprimitive` helper returned false on N_TBANG and on N_TNAME pointing to an alias that resolves to void, so the gate never fired and the slot stayed uninitialised. Polarity catalog: wwstage UNDER — `typeis8byteprimitive` classifier too narrow at N_TBANG and void-alias N_TNAME. Convergence wwstage → cstage's natural sz=8 fallthrough (rule 10). N_TBANG arm recurses on inner type (cmd/wcc/check.c:290 resolve_type copies T's kind, only sets iserror — so !T is 8B iff T is 8B); void-alias N_TNAME resolves through alias- recursion the same way. Tests: - 724_letdecl_zeroinit pins MOVQ $0, -K(BP) presence between function prologue and body on canonical !void and void- alias rows, plus cmp -s byte-id between stages per row. Filed follow-up (NOT in scope here): #25 wwstage 8B struct without rhs still under-emits (structlookup != nil short- circuits the classifier). Same family as STATUS-4 #36 primsize composite-aware sizing. No in-tree consumer. 96/96 ok. 995_self_rebuild stays green (ww2==ww3==ww4 byte-id).
This commit is contained in:
@@ -854,14 +854,36 @@ fn typeis8byteprimitive(c: *cgen, t: *node) bool = {
|
||||
};
|
||||
if (k == nkind.N_TTUPLE) { return false; };
|
||||
if (k == nkind.N_TTAGGED){ return false; };
|
||||
// STATUS-3 #22: `!T` carries the error flag on T's underlying
|
||||
// shape (cmd/wcc/check.c:290 resolve_type N_TBANG copies T's
|
||||
// kind, just sets iserror). cstage's N_LET sizes off lu->kind,
|
||||
// so `!void`/`!i32` land in the sz=8 default and `!str`/`!slice`
|
||||
// keep their composite slot. Defer to the inner type so
|
||||
// `let e: !void;` mirrors cstage's MOVQ $0 while `!str` falls
|
||||
// through to the multi-word fill.
|
||||
if (k == nkind.N_TBANG) { return typeis8byteprimitive(c, t.lhs); };
|
||||
if (k == nkind.N_TNAME) {
|
||||
let nm: str = t.str;
|
||||
if (streq(nm, "str")) { return false; };
|
||||
// Plain `void` slot: cstage sz=8 default → MOVQ $0. The let-
|
||||
// decl is a phantom (a tagged-union variant tag carrier), but
|
||||
// the slot is still 8B and zero-inits like any other prim.
|
||||
if (streq(nm, "void")) { return true; };
|
||||
// Struct alias: not a primitive even if the slot is 8B.
|
||||
if (structlookup(c, nm) != nil) { return false; };
|
||||
// Primitive (i8/u8/.../i64/u64/bool/rune/f32/f64/int/...).
|
||||
// All of these get slot-padded to 8 and zero-init in C.
|
||||
if (primsize(nm) > 0) { return true; };
|
||||
// STATUS-3 #22: alias to `!T` or to `void` (Hare-style error
|
||||
// type / phantom variant). cstage resolves the alias and
|
||||
// lands on sz=8 default. Follow through aliaslookup so
|
||||
// `type invalid = !void;` and `type done = void;` zero-init.
|
||||
if (c != nil) {
|
||||
let aliased: *node = aliaslookup(c, nm);
|
||||
if (aliased != nil) {
|
||||
return typeis8byteprimitive(c, aliased);
|
||||
};
|
||||
};
|
||||
return false;
|
||||
};
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user