cgen: resolve chained-DOT fn-ptr field callees
fnptrcalleetfn's N_DOT arm required an N_IDENT base, so a.b.cb(...) fell to the name registry with an empty module hint and emitted CALL cb(SB) (undefined symbol; cstage calls the stamped ptr indirect). dotbasestructinfo resolves the base chain through the struct registry — each link a struct- or *struct-typed field — and the single-dot path routes through the same resolver unchanged. Closes the last open shape of the #59.8 name-keyed callee family. Fixture fnptrfield_chain; corpus pin 1487/2974.
This commit is contained in:
@@ -32,9 +32,9 @@ categories out of the ordinary developer target.
|
|||||||
| Fixed point and self-host | `test-bootstrap` |
|
| Fixed point and self-host | `test-bootstrap` |
|
||||||
| Host linker/platform behavior | `test-platform` |
|
| Host linker/platform behavior | `test-platform` |
|
||||||
|
|
||||||
The live declarative compiler corpus has 1,486 fixtures and 2,972 C/WW cells:
|
The live declarative compiler corpus has 1,487 fixtures and 2,974 C/WW cells:
|
||||||
338 expected rejections (314 shared and 24 stage-specific), 17 compile-only
|
338 expected rejections (314 shared and 24 stage-specific), 17 compile-only
|
||||||
successes, 191 exit-zero programs, and 940 explicit-exit programs.
|
successes, 191 exit-zero programs, and 941 explicit-exit programs.
|
||||||
|
|
||||||
147 native C carriers remain. They are partitioned exactly once as five
|
147 native C carriers remain. They are partitioned exactly once as five
|
||||||
in-process units, 24 byte/artifact gates, six bootstrap gates, one platform
|
in-process units, 24 byte/artifact gates, six bootstrap gates, one platform
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package wwfixture;
|
package wwfixture;
|
||||||
|
|
||||||
def protocolversion: i32 = 1;
|
def protocolversion: i32 = 1;
|
||||||
def corpuscount: i32 = 1486;
|
def corpuscount: i32 = 1487;
|
||||||
def errorcount: i32 = 338;
|
def errorcount: i32 = 338;
|
||||||
def compilecount: i32 = 17;
|
def compilecount: i32 = 17;
|
||||||
def runcount: i32 = 191;
|
def runcount: i32 = 191;
|
||||||
def runexitcount: i32 = 940;
|
def runexitcount: i32 = 941;
|
||||||
def nativecount: i32 = 2972;
|
def nativecount: i32 = 2974;
|
||||||
def corpushash: str = "ab4b1d1ffc078b23de0a70911740511e873cd8d6f76009c4719d704bb36e6133";
|
def corpushash: str = "2520ada0b1687fab6eed6073a263c620fa4cbab6dc8156f7d51bcf8b14a9ec4a";
|
||||||
|
|
||||||
type directive = enum i32 {
|
type directive = enum i32 {
|
||||||
ERROR = 0,
|
ERROR = 0,
|
||||||
|
|||||||
@@ -64,6 +64,53 @@ fn findvariadicparam(ps: *syntax.node, nfixed_out: *i32) *syntax.node = {
|
|||||||
// lookup missed entirely and the raw N_SPREAD leaked to pushargsrev
|
// lookup missed entirely and the raw N_SPREAD leaked to pushargsrev
|
||||||
// as a single $0 word). Cstage mirror: cgcall's callee_params from
|
// as a single $0 word). Cstage mirror: cgcall's callee_params from
|
||||||
// the checker-stamped n->lhs->type (cmd/w6c/cgen.c TY_FN cu->params).
|
// the checker-stamped n->lhs->type (cmd/w6c/cgen.c TY_FN cu->params).
|
||||||
|
// dotbasestructinfo — the struct registry entry for a DOT base: a
|
||||||
|
// local ident (struct value or *struct), or a nested field chain
|
||||||
|
// (`a.b.cb(...)` — each link a struct- or *struct-typed field). The
|
||||||
|
// chained form previously fell to the name registry with an empty
|
||||||
|
// module hint (the #59.8 family's last open shape) and emitted
|
||||||
|
// CALL <leaf>(SB).
|
||||||
|
fn dotbasestructinfo(c: *cgen, base: *syntax.node) *structinfo = {
|
||||||
|
if (base == nil) { return nil; };
|
||||||
|
if (base.kind == syntax.nkind.N_IDENT) {
|
||||||
|
let lc: *local = localfindnode(c, base.str);
|
||||||
|
if (lc == nil) { return nil; };
|
||||||
|
let tn: *syntax.node = lc.tnode;
|
||||||
|
if (tn == nil) { return nil; };
|
||||||
|
let sname: str;
|
||||||
|
sname.ptr = nil; sname.len = 0;
|
||||||
|
if (tn.kind == syntax.nkind.N_TNAME) { sname = tn.str; };
|
||||||
|
if (tn.kind == syntax.nkind.N_TPTR) {
|
||||||
|
if (tn.lhs != nil) {
|
||||||
|
if (tn.lhs.kind == syntax.nkind.N_TNAME) {
|
||||||
|
sname = tn.lhs.str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (sname.len == 0) { return nil; };
|
||||||
|
return structlookup(c, sname);
|
||||||
|
};
|
||||||
|
if (base.kind != syntax.nkind.N_DOT) { return nil; };
|
||||||
|
let outer: *structinfo = dotbasestructinfo(c, base.lhs);
|
||||||
|
if (outer == nil) { return nil; };
|
||||||
|
let fi: *fieldinfo = outer.fields;
|
||||||
|
for (fi != nil) {
|
||||||
|
if (syntax.streq(fi.fname, base.str)) {
|
||||||
|
let ft: *syntax.node = fi.tnode;
|
||||||
|
if (ft == nil) { return nil; };
|
||||||
|
if (ft.kind == syntax.nkind.N_TPTR) {
|
||||||
|
if (ft.lhs != nil) { ft = ft.lhs; };
|
||||||
|
};
|
||||||
|
if (ft.kind == syntax.nkind.N_TNAME) {
|
||||||
|
return structlookup(c, ft.str);
|
||||||
|
};
|
||||||
|
return nil;
|
||||||
|
};
|
||||||
|
fi = fi.finext;
|
||||||
|
};
|
||||||
|
return nil;
|
||||||
|
};
|
||||||
|
|
||||||
fn fnptrcalleetfn(c: *cgen, callee: *syntax.node) *syntax.node = {
|
fn fnptrcalleetfn(c: *cgen, callee: *syntax.node) *syntax.node = {
|
||||||
if (callee == nil) { return nil; };
|
if (callee == nil) { return nil; };
|
||||||
if (callee.kind == syntax.nkind.N_IDENT) {
|
if (callee.kind == syntax.nkind.N_IDENT) {
|
||||||
@@ -82,25 +129,7 @@ fn fnptrcalleetfn(c: *cgen, callee: *syntax.node) *syntax.node = {
|
|||||||
return nil;
|
return nil;
|
||||||
};
|
};
|
||||||
if (callee.kind != syntax.nkind.N_DOT) { return nil; };
|
if (callee.kind != syntax.nkind.N_DOT) { return nil; };
|
||||||
let base: *syntax.node = callee.lhs;
|
let si: *structinfo = dotbasestructinfo(c, callee.lhs);
|
||||||
if (base == nil) { return nil; };
|
|
||||||
if (base.kind != syntax.nkind.N_IDENT) { return nil; };
|
|
||||||
let lc: *local = localfindnode(c, base.str);
|
|
||||||
if (lc == nil) { return nil; };
|
|
||||||
let tn: *syntax.node = lc.tnode;
|
|
||||||
if (tn == nil) { return nil; };
|
|
||||||
let sname: str;
|
|
||||||
sname.ptr = nil; sname.len = 0;
|
|
||||||
if (tn.kind == syntax.nkind.N_TNAME) { sname = tn.str; };
|
|
||||||
if (tn.kind == syntax.nkind.N_TPTR) {
|
|
||||||
if (tn.lhs != nil) {
|
|
||||||
if (tn.lhs.kind == syntax.nkind.N_TNAME) {
|
|
||||||
sname = tn.lhs.str;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (sname.len == 0) { return nil; };
|
|
||||||
let si: *structinfo = structlookup(c, sname);
|
|
||||||
if (si == nil) { return nil; };
|
if (si == nil) { return nil; };
|
||||||
let fi: *fieldinfo = si.fields;
|
let fi: *fieldinfo = si.fields;
|
||||||
for (fi != nil) {
|
for (fi != nil) {
|
||||||
|
|||||||
27
test/wcc/data/fnptrfield_chain/case.ww
Normal file
27
test/wcc/data/fnptrfield_chain/case.ww
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//ww:run-exit 36
|
||||||
|
package main;
|
||||||
|
|
||||||
|
// A call through a chained-DOT fn-ptr field (a.b.cb(...)). The wwstage
|
||||||
|
// callee resolver only accepted an N_IDENT base, so the chained shape
|
||||||
|
// fell to the name registry with an empty module hint and emitted
|
||||||
|
// CALL cb(SB) — the last open shape of the #59.8 name-keyed family.
|
||||||
|
|
||||||
|
type bstr = struct {
|
||||||
|
cb: *fn(x: i32) i32,
|
||||||
|
pad: i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
type astr = struct {
|
||||||
|
n: i32,
|
||||||
|
b: bstr,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn twice(x: i32) i32 = { return x * 2; };
|
||||||
|
|
||||||
|
fn main() i32 = {
|
||||||
|
let a: astr;
|
||||||
|
a.n = 1;
|
||||||
|
a.b.cb = &twice;
|
||||||
|
a.b.pad = 2;
|
||||||
|
return a.b.cb(20) + a.n + a.b.pad - 7;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user