cgen: address module-global str/slice pseudo-field stores via the symbol

A module-global base has no frame slot; treating its local-lookup miss
as offset zero wrote .ptr/.len/.cap at the caller return address. LEAQ
the symbol like the struct-field global arms do. Both stages.
This commit is contained in:
2026-08-07 23:00:08 +09:00
parent 7dc3150b65
commit 5ddada94e5
3 changed files with 67 additions and 3 deletions

View File

@@ -11170,9 +11170,9 @@ fn cgassign(c: *cgen, n: *syntax.node) void = {
};
};
};
// Top-level struct global field assignment: `g.f = expr;` and
// `g.f += expr;` for a scalar/str field. Reached when the local
// lookup miss but the IDENT base is a registered struct `let`.
// Top-level global field assignment: `g.f = expr;` and `g.f += expr;`
// for a struct field or str/slice pseudo-field. Reached when the local
// lookup misses but the IDENT base is a registered module `let`.
// LEAQ name(SB) into BX/CX takes the place of the frame slot
// addressing the local branches use. Compound (PLUSEQ/MINUSEQ)
// follows the same load → push → eval → combine → store shape
@@ -11185,6 +11185,37 @@ fn cgassign(c: *cgen, n: *syntax.node) void = {
if (base.kind == syntax.nkind.N_IDENT) {
let bn: str = base.str;
if (localfindnode(c, bn) == nil) {
let btype: *syntax.tinfo = base.type_: *syntax.tinfo;
if (isletvar(c, bn) &&
(syntax.typeisstr(btype) || syntax.typeisslice(btype))) {
let delta: i32 = -1;
if (syntax.streq(fld, "ptr")) { delta = 0; };
if (syntax.streq(fld, "len")) { delta = 8; };
if (syntax.streq(fld, "cap")) { delta = 16; };
if (delta >= 0) {
if (n.op != syntax.tkind.TK_ASSIGN) {
emitline("\tLEAQ\t");
emitsymname(c, bn);
emitline("(SB), BX\n");
emitline("\tMOVQ\t");
emitdispreg(delta: i64, "BX");
emitline(", BX\n");
emitline("\tPUSHQ\tBX\n");
};
cgexpr(c, n.rhs);
if (n.op != syntax.tkind.TK_ASSIGN) {
emitline("\tPOPQ\tBX\n");
cgdotfieldcombine(c, n.op, false);
};
emitline("\tLEAQ\t");
emitsymname(c, bn);
emitline("(SB), BX\n");
emitline("\tMOVQ\tAX, ");
emitdispreg(delta: i64, "BX");
emitline("\n");
return;
};
};
// #31: resolve the global value-struct field OFFSET + type
// off the checker-STAMPED receiver tinfo (tichase(base.type_)),
// NOT the name-keyed global-struct leaf lookup. A global decl