cgen: resolve local fn-ptr callees for variadic arg prep
The wwstage variadic call classification was name-keyed: a fn-ptr FIELD call whose local base shadowed the current module name (lib/log's log.println(log, args...)) picked the module fn's signature — nfixed off by one, the fixed arg boxed into the gather, the spread emitted as zeros — and a no-collision fn-ptr callee missed the registry entirely, leaking the raw N_SPREAD as a single $0 word (SIGSEGV / exit 255 in 8 of 11 logtest tests on the wwstage leg). fnptrcalleetfn resolves a local fn-ptr callee (bare local or struct field) to its N_TFN once, shared by the CALL-target choice, callee_variadic_param (with the []T wrap registry params get from installparams), calleecvariadic, and the widening param lookup, so target and arg prep can never disagree. Graduates the #59.8 logtest pin — DATABYTEID_DIVERGED-era M_DIVERGE count is now zero.
This commit is contained in:
@@ -169,8 +169,17 @@ static const struct ent ents[] = {
|
||||
.mode = M_ID, .cite = "#59.5 graduated by the stamp-keyed recognizers" },
|
||||
/* #59.6 fmt graduated to M_ID above (#129 fix) */
|
||||
/* #59.7 siphash graduated to M_ID above (#61 fix) */
|
||||
/* #59.8 graduated: the wwstage variadic call classification was
|
||||
* name-keyed — a local fn-ptr field callee whose base shadowed the
|
||||
* current module name (lib/log's `log.println(log, args...)`)
|
||||
* picked the module fn's signature (nfixed off by one; the fixed
|
||||
* arg boxed into the gather, the spread emitted as zeros), and a
|
||||
* no-collision fn-ptr callee missed entirely (raw N_SPREAD leaked
|
||||
* as one $0 word). fnptrcalleetfn now resolves local fn-ptr
|
||||
* callees for CALL target and arg prep alike. Runtime pin:
|
||||
* r598_fnptr_field_variadic. */
|
||||
{ .fixture = "lib/log/logtest.ww",
|
||||
.mode = M_DIVERGE, .cite = "#59.8" },
|
||||
.mode = M_ID, .cite = "#59.8 graduated by the local-first callee resolver" },
|
||||
/* #59.9 graduated: the wwstage checker never typed an N_BIN operand
|
||||
* of `as`, so an enum OR-fold reached cgen unstamped and lowered as
|
||||
* a phantom tagged assert (unconditional exit 1). checkisas now
|
||||
|
||||
36
test/wcc/data/r598_fnptr_field_variadic/case.ww
Normal file
36
test/wcc/data/r598_fnptr_field_variadic/case.ww
Normal file
@@ -0,0 +1,36 @@
|
||||
//ww:run
|
||||
// #59.8: a variadic call through a struct fn-pointer FIELD with a
|
||||
// spread-forwarded tail (`v.cb(v, args...)`). The pre-fix wwstage
|
||||
// classified the callee by NAME: with no registry hit the raw
|
||||
// N_SPREAD leaked to pushargsrev as a single $0 word (callee saw
|
||||
// args.ptr=0), and when the base local shadowed the module name it
|
||||
// picked the module fn's signature and mis-counted nfixed.
|
||||
package main;
|
||||
|
||||
type vt = struct {
|
||||
cb: fn(v: *vt, args: i64...) void,
|
||||
acc: i64,
|
||||
};
|
||||
|
||||
fn sum(v: *vt, args: i64...) void = {
|
||||
let i: i32 = 0;
|
||||
for (i < args.len) {
|
||||
v.acc += args[i];
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
fn dispatch(v: *vt, args: i64...) void = {
|
||||
v.cb(v, args...);
|
||||
};
|
||||
|
||||
fn main() i32 = {
|
||||
let v: vt;
|
||||
v.cb = sum;
|
||||
v.acc = 0i64;
|
||||
dispatch(&v, 1i64, 2i64, 3i64);
|
||||
if (v.acc != 6i64) { return 1; };
|
||||
v.cb(&v, 10i64);
|
||||
if (v.acc != 16i64) { return 2; };
|
||||
return 0;
|
||||
};
|
||||
Reference in New Issue
Block a user