cstage+selfhost+test: fix (*p).f silent drop in N_DOT lhs (read+write)
Pre-existing landmine surfaced by #5 (whole-STRUCT N_ASSIGN). Both stages' N_DOT dispatch gated on `lhs->lhs->kind == N_IDENT`; the parser produces N_UN(STAR, IDENT(p)) for `(*p).f`, so both sides fell off: - Write side (cgassign N_DOT base): emitted nothing, store dropped. - Read side (case N_DOT pointer-auto-deref): cgexpr derefed the pointer as a scalar, AX = first qword of struct, field offset dropped. Fix: retarget base / dot_lhs to the inner IDENT when shape is N_UN(STAR, IDENT). The existing via_ptr branch fires identically to `p.f`. v1 scope is bare-IDENT inner only; `(*expr).f` (non-IDENT pointer expression) is tracked separately as task #19. 702 covers 7 rows: write_i64/i32/str, read_i64/i32/str_len, roundtrip
This commit is contained in:
@@ -9825,6 +9825,26 @@ fn cgmatch(c: *cgen, n: *node) void = {
|
||||
fn cgdot(c: *cgen, n: *node) void = {
|
||||
let lhs: *node = n.lhs;
|
||||
let fld: str = n.str;
|
||||
// `(*p).f` read retarget: parser produces n.lhs = N_UN(STAR,
|
||||
// IDENT(p)). Substitute the inner IDENT as dotlhs so the
|
||||
// pointer-auto-deref branch (lhs.kind == N_IDENT && N_TPTR
|
||||
// tnode) fires the same as `p.f`. Mirror of the N_ASSIGN N_DOT
|
||||
// lhs retarget in cgassign. v1 scope: N_IDENT inner only;
|
||||
// (*expr).f follow-up task pending. Enum-leaf lookup above and
|
||||
// chained-N_DOT branches below keep checking raw lhs since
|
||||
// (*p) is neither shape.
|
||||
let dotlhs: *node = lhs;
|
||||
if (dotlhs != nil) {
|
||||
if (dotlhs.kind == nkind.N_UN) {
|
||||
if (dotlhs.op == tkind.TK_STAR) {
|
||||
if (dotlhs.lhs != nil) {
|
||||
if (dotlhs.lhs.kind == nkind.N_IDENT) {
|
||||
dotlhs = dotlhs.lhs;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
// Enum member access: `EnumName.MEMBER` or `pkg.EnumName.MEMBER`
|
||||
// → inline the pre-computed constant. With driver-side
|
||||
// concatenation, both forms key off the leaf type name.
|
||||
@@ -9854,9 +9874,9 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
let nm: str = lhs.str;
|
||||
if (dotlhs != nil) {
|
||||
if (dotlhs.kind == nkind.N_IDENT) {
|
||||
let nm: str = dotlhs.str;
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
@@ -12362,12 +12382,24 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
// Struct/ptr-to-struct field assignment: `s.f = expr;` or
|
||||
// `p.f = expr;`. Only plain `=` is wired (compound on field
|
||||
// is rare and not yet needed by our fixtures).
|
||||
// is rare and not yet needed by our fixtures). Base accepts the
|
||||
// explicit-deref form `(*p).f = ...` (parser N_UN(STAR, IDENT))
|
||||
// by retargeting to the inner IDENT so the via_ptr branch fires
|
||||
// the same as auto-deref `p.f = v`. v1 scope: bare-IDENT inner.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_DOT) {
|
||||
let base: *node = lhs.lhs;
|
||||
let fld: str = lhs.str;
|
||||
if (base != nil) {
|
||||
if (base.kind == nkind.N_UN) {
|
||||
if (base.op == tkind.TK_STAR) {
|
||||
if (base.lhs != nil) {
|
||||
if (base.lhs.kind == nkind.N_IDENT) {
|
||||
base = base.lhs;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (base.kind == nkind.N_IDENT) {
|
||||
let bn: str = base.str;
|
||||
let lc: *local = localfindnode(c, bn);
|
||||
|
||||
Reference in New Issue
Block a user