selfhost+test: bump wwstage varargseq per cgcall (#8)
Latent surface from #15: cgcall variadic-gather block read seq from n.uval, which post-#15 is always 0 because scanlocals (which used to stamp it during pre-pass) was deleted. Every variadic callsite in a fn aliased to @vararg_d_0 / @vararg_sl_0. When two callsites in one fn had differing arities, the second hit #15's first-use+fail-loud guard ("localadd: @-prefix slot grew within fn") — correctly, since the slot was being asked to grow mid-fn. Fix: read seq from c.varargseq + bump in cgcall's gather branch. Mirrors cstage's mklabel("vararg_d/sl") natural seq bump. cgeninit zeroes c.varargseq per-fn (existing), so the counter is correctly per-fn scoped. cgen.ww varargseq comment refreshed — replaces stale "bumped only at emit time" misclaim with the post-#15 per-call shape + the #15 grow-on-pin discipline that surfaced the wedge. 751_vararg_seq_percall: table-driven 3 rows x 2 stages = 6 fixtures. mixed_arity_two_calls (the wedge), same_arity_two_calls (no-regress), three_arity_drift (1/2/3 mints @vararg_d_0/1/2). make test 125/125; ww2==ww3==ww4 byte-id holds via 995_self_rebuild. Surfaced by worker-strcontains2 attempting strings.contains tagged- variadic graduation — mixed-arity spec test rows triggered the wedge. Unblocks #9 + #10 (strings/bytes.contains).
This commit is contained in:
@@ -13906,8 +13906,9 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
// of the call machinery sees one slice slot for the variadic.
|
||||
// Forwarding shape (`xs...`) skips the gather: the spread's
|
||||
// inner slice expression replaces the wrapper in place. Empty
|
||||
// (no trailing args) writes a {nil, 0, 0} descriptor. The seq
|
||||
// matches the one cgcall stamped on n.uval at first emit.
|
||||
// (no trailing args) writes a {nil, 0, 0} descriptor. Per-call
|
||||
// seq comes from c.varargseq bumped at gather emit (mirrors
|
||||
// cstage's mklabel("vararg_d/sl") freshness).
|
||||
{
|
||||
let nfixed_v: i32 = 0;
|
||||
let varp: *node = callee_variadic_param(c, callee, &nfixed_v);
|
||||
@@ -13945,7 +13946,8 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
if (prev == nil) { n.list = inner; }
|
||||
else { prev.next = inner; };
|
||||
} else {
|
||||
let seq: i32 = n.uval: i32;
|
||||
let seq: i32 = c.varargseq;
|
||||
c.varargseq += 1;
|
||||
let dname: str = mkvarargname(c, "@vararg_d_", seq);
|
||||
let sname: str = mkvarargname(c, "@vararg_sl_", seq);
|
||||
// Use raw element size, not stack-padded
|
||||
@@ -19083,10 +19085,12 @@ type cgen = struct {
|
||||
yieldbuf: *str, // stack of match end labels for yield
|
||||
defertop: i32,
|
||||
deferbuf: **node, // stack of deferred exprs (LIFO at return)
|
||||
// Variadic-call gather state. cgcall assigns per-call scratch
|
||||
// names `@vararg_d_N` / `@vararg_sl_N` using this counter;
|
||||
// post #15 the seq is bumped only at emit time so a single
|
||||
// sequence is observed (the scanlocals pre-pass was dropped).
|
||||
// Variadic-call gather state. cgcall bumps this on each gather
|
||||
// emit and uses it to mint `@vararg_d_N` / `@vararg_sl_N` per
|
||||
// callsite; mirrors cstage's mklabel("vararg_d/sl") freshness
|
||||
// so two variadic callsites with different arities in one fn
|
||||
// get distinct slots (the shared slot fail-louds under #15's
|
||||
// @-prefix grow-on-pin discipline).
|
||||
varargseq: i32,
|
||||
// System V AMD64 sret discipline (#23). Plain TY_STRUCT returns
|
||||
// with size > 24B are passed via a hidden first-arg pointer
|
||||
|
||||
@@ -469,10 +469,12 @@ type cgen = struct {
|
||||
yieldbuf: *str, // stack of match end labels for yield
|
||||
defertop: i32,
|
||||
deferbuf: **node, // stack of deferred exprs (LIFO at return)
|
||||
// Variadic-call gather state. cgcall assigns per-call scratch
|
||||
// names `@vararg_d_N` / `@vararg_sl_N` using this counter;
|
||||
// post #15 the seq is bumped only at emit time so a single
|
||||
// sequence is observed (the scanlocals pre-pass was dropped).
|
||||
// Variadic-call gather state. cgcall bumps this on each gather
|
||||
// emit and uses it to mint `@vararg_d_N` / `@vararg_sl_N` per
|
||||
// callsite; mirrors cstage's mklabel("vararg_d/sl") freshness
|
||||
// so two variadic callsites with different arities in one fn
|
||||
// get distinct slots (the shared slot fail-louds under #15's
|
||||
// @-prefix grow-on-pin discipline).
|
||||
varargseq: i32,
|
||||
// System V AMD64 sret discipline (#23). Plain TY_STRUCT returns
|
||||
// with size > 24B are passed via a hidden first-arg pointer
|
||||
|
||||
@@ -2940,8 +2940,9 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
// of the call machinery sees one slice slot for the variadic.
|
||||
// Forwarding shape (`xs...`) skips the gather: the spread's
|
||||
// inner slice expression replaces the wrapper in place. Empty
|
||||
// (no trailing args) writes a {nil, 0, 0} descriptor. The seq
|
||||
// matches the one cgcall stamped on n.uval at first emit.
|
||||
// (no trailing args) writes a {nil, 0, 0} descriptor. Per-call
|
||||
// seq comes from c.varargseq bumped at gather emit (mirrors
|
||||
// cstage's mklabel("vararg_d/sl") freshness).
|
||||
{
|
||||
let nfixed_v: i32 = 0;
|
||||
let varp: *node = callee_variadic_param(c, callee, &nfixed_v);
|
||||
@@ -2979,7 +2980,8 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
if (prev == nil) { n.list = inner; }
|
||||
else { prev.next = inner; };
|
||||
} else {
|
||||
let seq: i32 = n.uval: i32;
|
||||
let seq: i32 = c.varargseq;
|
||||
c.varargseq += 1;
|
||||
let dname: str = mkvarargname(c, "@vararg_d_", seq);
|
||||
let sname: str = mkvarargname(c, "@vararg_sl_", seq);
|
||||
// Use raw element size, not stack-padded
|
||||
|
||||
@@ -13906,8 +13906,9 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
// of the call machinery sees one slice slot for the variadic.
|
||||
// Forwarding shape (`xs...`) skips the gather: the spread's
|
||||
// inner slice expression replaces the wrapper in place. Empty
|
||||
// (no trailing args) writes a {nil, 0, 0} descriptor. The seq
|
||||
// matches the one cgcall stamped on n.uval at first emit.
|
||||
// (no trailing args) writes a {nil, 0, 0} descriptor. Per-call
|
||||
// seq comes from c.varargseq bumped at gather emit (mirrors
|
||||
// cstage's mklabel("vararg_d/sl") freshness).
|
||||
{
|
||||
let nfixed_v: i32 = 0;
|
||||
let varp: *node = callee_variadic_param(c, callee, &nfixed_v);
|
||||
@@ -13945,7 +13946,8 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
if (prev == nil) { n.list = inner; }
|
||||
else { prev.next = inner; };
|
||||
} else {
|
||||
let seq: i32 = n.uval: i32;
|
||||
let seq: i32 = c.varargseq;
|
||||
c.varargseq += 1;
|
||||
let dname: str = mkvarargname(c, "@vararg_d_", seq);
|
||||
let sname: str = mkvarargname(c, "@vararg_sl_", seq);
|
||||
// Use raw element size, not stack-padded
|
||||
@@ -19083,10 +19085,12 @@ type cgen = struct {
|
||||
yieldbuf: *str, // stack of match end labels for yield
|
||||
defertop: i32,
|
||||
deferbuf: **node, // stack of deferred exprs (LIFO at return)
|
||||
// Variadic-call gather state. cgcall assigns per-call scratch
|
||||
// names `@vararg_d_N` / `@vararg_sl_N` using this counter;
|
||||
// post #15 the seq is bumped only at emit time so a single
|
||||
// sequence is observed (the scanlocals pre-pass was dropped).
|
||||
// Variadic-call gather state. cgcall bumps this on each gather
|
||||
// emit and uses it to mint `@vararg_d_N` / `@vararg_sl_N` per
|
||||
// callsite; mirrors cstage's mklabel("vararg_d/sl") freshness
|
||||
// so two variadic callsites with different arities in one fn
|
||||
// get distinct slots (the shared slot fail-louds under #15's
|
||||
// @-prefix grow-on-pin discipline).
|
||||
varargseq: i32,
|
||||
// System V AMD64 sret discipline (#23). Plain TY_STRUCT returns
|
||||
// with size > 24B are passed via a hidden first-arg pointer
|
||||
|
||||
Reference in New Issue
Block a user