wcc: nullable-global storage is a loud reject pending #15, both stages
A module-level nullable `(*T | void)` GLOBAL has no storage path in either stage: let_emit_size / letemitsize returned 0 for the nullable TY_TAGGED, so let_collect skipped registration and emit_lets skipped DATA. The three READ paths then miscompiled SILENTLY and identically- wrong (a #263-class both-wrong gap, not a wwstage align-up): match read 0(BP) = saved BP via the let_islet-gated #87 arm falling to localfind; `g is *T` / `g as *T` emitted MOVQ name(SB) for a symbol with no DATA → w6l undefined-reference. cstage's #87 match arm was itself `!is_nullable`- gated, so both stages were wrong. This is the silent→loud bridge: die loud at the size/storage layer the instant a nullable global is declared, so all three read paths hit one diagnostic instead of a silent miscompile. A silent gap here is exactly what "stable before CSP" forbids — CSP's process/handle/chan singletons (`let c: *Chan | void`) are THE canonical nullable-global consumer. The full storage + read-class arc (real DATA, nil/void/address-of init, let- registration, the three SB-resolution read arms) is deferred to task #15 (CSP-prereq); the `&`-init sub-problem additionally couples to the #48 static address-of relocation gap (which already bites a plain `*T` global init the same way). Diagnostic core text is identical both stages ("nullable-global storage unimplemented (task #15)"); cstage's fatal() adds the harness-wide "ww: " err.c prefix err.ww does not, the same per-stage asymmetry every existing both-stage reject carries. Byte-id-neutral: the corpus declares zero nullable globals (grep-verified), so the loud path is unreached in self- compile and the emitted asm is zero-move; the embedded w6c/wwdump combined.ww amalgamations are regenerated for the cgen.ww source change. New 989_nullableglobal_reject: 6 reject rows (match/is/as on a &gv init, plus nil-init and void-init match, plus an inline non-aliased nullable form) prove rc!=0 + the shared diagnostic on both stages, init- and form-invariant; 2 controls (non-nullable tagged global, plain nil-init *T global) prove the reject is keyed on the nullable TY_TAGGED and the #87 storage path is untouched.
This commit is contained in:
@@ -41821,11 +41821,22 @@ fn letemitsize(c: *cgen, d: *node) i32 = {
|
||||
return tsum;
|
||||
};
|
||||
// #87: non-nullable tagged-union global — box size (tag word +
|
||||
// max payload, mirror of the runtime local). Nullable stays 0 so
|
||||
// the (*T|void) one-word fold keeps the 8B scalar arm in
|
||||
// emitletdataw. Mirrors cstage let_emit_size TY_TAGGED.
|
||||
// max payload, mirror of the runtime local). Mirrors cstage
|
||||
// let_emit_size TY_TAGGED.
|
||||
if (t.kind == nkind.N_TTAGGED) {
|
||||
if (isnullabletype(t)) { return 0; };
|
||||
// #45 (silent→loud bridge, task #15): a nullable (*T|void)
|
||||
// GLOBAL has no storage path. Returning 0 here made
|
||||
// letcollect + emitletdataw silently skip the decl (no DATA,
|
||||
// no let-registration), so a later match/is/as resolved
|
||||
// 0(BP) or an undefined symbol — a silent miscompile in the
|
||||
// CSP handle-singleton substrate. Die loud at the size/
|
||||
// storage layer so all three read paths hit one diagnostic;
|
||||
// the full storage + read-class arc is task #15 (CSP-prereq).
|
||||
if (isnullabletype(t)) {
|
||||
let mng: str = "nullable-global storage unimplemented (task #15)\n";
|
||||
os.write(2, mng.ptr, mng.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
return slotsize(c, t);
|
||||
};
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
|
||||
@@ -1047,11 +1047,22 @@ fn letemitsize(c: *cgen, d: *node) i32 = {
|
||||
return tsum;
|
||||
};
|
||||
// #87: non-nullable tagged-union global — box size (tag word +
|
||||
// max payload, mirror of the runtime local). Nullable stays 0 so
|
||||
// the (*T|void) one-word fold keeps the 8B scalar arm in
|
||||
// emitletdataw. Mirrors cstage let_emit_size TY_TAGGED.
|
||||
// max payload, mirror of the runtime local). Mirrors cstage
|
||||
// let_emit_size TY_TAGGED.
|
||||
if (t.kind == nkind.N_TTAGGED) {
|
||||
if (isnullabletype(t)) { return 0; };
|
||||
// #45 (silent→loud bridge, task #15): a nullable (*T|void)
|
||||
// GLOBAL has no storage path. Returning 0 here made
|
||||
// letcollect + emitletdataw silently skip the decl (no DATA,
|
||||
// no let-registration), so a later match/is/as resolved
|
||||
// 0(BP) or an undefined symbol — a silent miscompile in the
|
||||
// CSP handle-singleton substrate. Die loud at the size/
|
||||
// storage layer so all three read paths hit one diagnostic;
|
||||
// the full storage + read-class arc is task #15 (CSP-prereq).
|
||||
if (isnullabletype(t)) {
|
||||
let mng: str = "nullable-global storage unimplemented (task #15)\n";
|
||||
os.write(2, mng.ptr, mng.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
return slotsize(c, t);
|
||||
};
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
|
||||
@@ -41821,11 +41821,22 @@ fn letemitsize(c: *cgen, d: *node) i32 = {
|
||||
return tsum;
|
||||
};
|
||||
// #87: non-nullable tagged-union global — box size (tag word +
|
||||
// max payload, mirror of the runtime local). Nullable stays 0 so
|
||||
// the (*T|void) one-word fold keeps the 8B scalar arm in
|
||||
// emitletdataw. Mirrors cstage let_emit_size TY_TAGGED.
|
||||
// max payload, mirror of the runtime local). Mirrors cstage
|
||||
// let_emit_size TY_TAGGED.
|
||||
if (t.kind == nkind.N_TTAGGED) {
|
||||
if (isnullabletype(t)) { return 0; };
|
||||
// #45 (silent→loud bridge, task #15): a nullable (*T|void)
|
||||
// GLOBAL has no storage path. Returning 0 here made
|
||||
// letcollect + emitletdataw silently skip the decl (no DATA,
|
||||
// no let-registration), so a later match/is/as resolved
|
||||
// 0(BP) or an undefined symbol — a silent miscompile in the
|
||||
// CSP handle-singleton substrate. Die loud at the size/
|
||||
// storage layer so all three read paths hit one diagnostic;
|
||||
// the full storage + read-class arc is task #15 (CSP-prereq).
|
||||
if (isnullabletype(t)) {
|
||||
let mng: str = "nullable-global storage unimplemented (task #15)\n";
|
||||
os.write(2, mng.ptr, mng.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
return slotsize(c, t);
|
||||
};
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
|
||||
Reference in New Issue
Block a user