selfhost: alias-aware istaggedtype for nested-union match

`type error = !(invalid | overflow)` miscompiled — istaggedtype
only matched N_TTAGGED directly, so an `e: error` param spilled
as 8B scalar and the match's slot+8 read trailed into saved BP.

Mirror isstrtype's alias+bang unwrap; add resolvetagged() for
is/as/match sites that need the inner N_TTAGGED. Frame scan
counts via slotsize so wwstage stays byte-identical to cstage.
Unblocks lib/strconv.strerror.
This commit is contained in:
2026-05-13 04:23:31 +09:00
parent e16634baec
commit 6e7c9e0df4
9 changed files with 893 additions and 59 deletions

View File

@@ -142,7 +142,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
// For other variants, cgexpr leaves AX, shuffle DX←AX.
// Nullable folded `(*T | void)`: just one word; AX is
// already the pointer (or 0). No shuffle, no tag.
if (istaggedtype(c.fnret)) {
if (istaggedtype(c, c.fnret)) {
// Forwarding a fallible call: `return f();` where f
// also returns a tagged union. The result is already
// in (AX=tag, DX=v0, CX=v1) — no shuffle, no tag.
@@ -158,7 +158,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
if (callee.kind == nkind.N_DOT) { calleename = callee.str; };
if (calleename.len > 0) {
let rt: *node = fnretlookup(c, calleename);
if (istaggedtype(rt)) { forwardtagged = true; };
if (istaggedtype(c, rt)) { forwardtagged = true; };
};
};
};
@@ -199,7 +199,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
// Bare `return;` from a tagged-union-returning fn is
// the void variant: emit its tag. Payload is undefined
// (void has size 0). Otherwise zero AX for determinism.
if (istaggedtype(c.fnret)) {
if (istaggedtype(c, c.fnret)) {
if (isnullabletype(c.fnret)) {
// null = void variant; AX = 0.
emitline("\tMOVQ\t$0, AX\n");
@@ -253,7 +253,7 @@ fn cglet(c: *cgen, n: *node) void = {
// just spill all three.
// - Otherwise rhs is a bare variant value: pack tag +
// value(s).
if (istaggedtype(tn)) {
if (istaggedtype(c, tn)) {
let nullable: bool = isnullabletype(tn);
let rhsreturnstagged: bool = false;
if (rhs.kind == nkind.N_CALL) {
@@ -265,7 +265,7 @@ fn cglet(c: *cgen, n: *node) void = {
if (callee.kind == nkind.N_DOT) { calleename = callee.str; };
if (calleename.len > 0) {
let rt: *node = fnretlookup(c, calleename);
if (istaggedtype(rt)) { rhsreturnstagged = true; };
if (istaggedtype(c, rt)) { rhsreturnstagged = true; };
};
};
};