cgen: peel *fn field types for local struct-field callees
fnptrcalleetfn's N_DOT arm accepted only a bare N_TFN field tnode, so a call through a field declared `cb: *fn(...)` missed, fell through to the name registry, and emitted CALL cb(SB) — an undefined symbol (loud at link; cstage calls the stamped ptr-to-fn indirectly). Same TPTR peel the N_IDENT arm already had. Fixture fnptrfield_call covers the by-value and via-pointer shapes; corpus pin 1478/2956.
This commit is contained in:
@@ -32,9 +32,9 @@ categories out of the ordinary developer target.
|
||||
| Fixed point and self-host | `test-bootstrap` |
|
||||
| Host linker/platform behavior | `test-platform` |
|
||||
|
||||
The live declarative compiler corpus has 1,477 fixtures and 2,954 C/WW cells:
|
||||
The live declarative compiler corpus has 1,478 fixtures and 2,956 C/WW cells:
|
||||
335 expected rejections (311 shared and 24 stage-specific), 17 compile-only
|
||||
successes, 191 exit-zero programs, and 934 explicit-exit programs.
|
||||
successes, 191 exit-zero programs, and 935 explicit-exit programs.
|
||||
|
||||
147 native C carriers remain. They are partitioned exactly once as five
|
||||
in-process units, 24 byte/artifact gates, six bootstrap gates, one platform
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package wwfixture;
|
||||
|
||||
def protocolversion: i32 = 1;
|
||||
def corpuscount: i32 = 1477;
|
||||
def corpuscount: i32 = 1478;
|
||||
def errorcount: i32 = 335;
|
||||
def compilecount: i32 = 17;
|
||||
def runcount: i32 = 191;
|
||||
def runexitcount: i32 = 934;
|
||||
def nativecount: i32 = 2954;
|
||||
def corpushash: str = "64258f4de9ac7d71c4ad6221dd2ae7338a38cd5c620fc4ce22c1105021559e83";
|
||||
def runexitcount: i32 = 935;
|
||||
def nativecount: i32 = 2956;
|
||||
def corpushash: str = "2ac2342a80c4148968250bf4ce93852b78cdefb6af96622fa533eea4a68837c6";
|
||||
|
||||
type directive = enum i32 {
|
||||
ERROR = 0,
|
||||
|
||||
@@ -108,6 +108,18 @@ fn fnptrcalleetfn(c: *cgen, callee: *syntax.node) *syntax.node = {
|
||||
let ft: *syntax.node = fi.tnode;
|
||||
if (ft != nil) {
|
||||
if (ft.kind == syntax.nkind.N_TFN) { return ft; };
|
||||
// `cb: *fn(...)` — same TPTR peel as the N_IDENT
|
||||
// arm above; without it the field-call fell through
|
||||
// to the name registry and emitted CALL <leaf>(SB)
|
||||
// (undefined symbol — loud at link, but cstage
|
||||
// resolves the stamped ptr-to-fn and calls indirect).
|
||||
if (ft.kind == syntax.nkind.N_TPTR) {
|
||||
if (ft.lhs != nil) {
|
||||
if (ft.lhs.kind == syntax.nkind.N_TFN) {
|
||||
return ft.lhs;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
return nil;
|
||||
};
|
||||
|
||||
22
test/wcc/data/fnptrfield_call/case.ww
Normal file
22
test/wcc/data/fnptrfield_call/case.ww
Normal file
@@ -0,0 +1,22 @@
|
||||
//ww:run-exit 36
|
||||
package main;
|
||||
|
||||
// A call through a struct field declared `*fn(...)`, by value and via
|
||||
// pointer. The wwstage fnptrcalleetfn N_DOT arm lacked the TPTR peel
|
||||
// its N_IDENT arm had, so the callee fell through to the name registry
|
||||
// and emitted CALL cb(SB) — an undefined symbol.
|
||||
|
||||
type cbs = struct {
|
||||
cb: *fn(x: i32) i32,
|
||||
k: i32,
|
||||
};
|
||||
|
||||
fn twice(x: i32) i32 = { return x * 2; };
|
||||
|
||||
fn main() i32 = {
|
||||
let o: cbs;
|
||||
o.cb = &twice;
|
||||
o.k = 4;
|
||||
let p: *cbs = &o;
|
||||
return o.cb(10) + p.cb(6) + o.k;
|
||||
};
|
||||
Reference in New Issue
Block a user