wcc+w6c_ww: typed dot-read resolver — kill both silent N_DOT fallbacks (F4)
A typed depth-2+ field chain behind an index/deref spine (threads[0].cap.end, (*p)[i].f.g) aborted the cgdot chain walker (N_IDENT roots only) and fell into the module-qualified-leaf fallback — a silent `MOVQ <leaf>(SB)` global read of a colliding symbol (p6min10 exit 66) or a link error. Single-dot reads behind a deref- index ((*ts)[i].pc, (*p)[i].slicefield) fell into the bottom catch-all instead, which is offset- and header-blind: offset-0 scalars read correctly by COINCIDENCE, nonzero offsets and slice headers were silently wrong in BOTH stages (FA3, pA5). `&threads[0].cap` dropped the address-of silently and SEGFAULTed at the deref (task #6, reviewer-A route). cgplaceaddr (C1) grows an N_IDENT root (local / let / DATA-backed def) and the N_INDEX base gate relaxes to recursion, so indexed-ident and deref-rooted spines resolve; enumerated arms still dispatch first, keeping every pre-C1 shape's asm. case N_DOT routes any TYPED read no arm matched through the resolver (scalar fldloadop, float X0, str/ slice 3-word header, [N]T address); the module-leaf fallback is gated to UNTYPED chains, the catch-all to untyped-str pseudo-fields, and the TK_AMP tail is resolver-or-loud. Leaf kinds without a register convention (tagged, aggregate) and unaddressable shapes die LOUD (rule 7). wwstage mirrors symmetrically; two of its arm gaps must not take the resolver (its sequence differs from cstage's arms — cs!=ww): ident-indexed alias reads loud-cite C3 (task #8) and non-local-rooted ptr-chains loud-cite task #37. A third verdict divergence is comment- documented at the wwstage aggregate gate: cstage's let-init consumes `let c = (*ts)[i].cap` BEFORE its N_DOT tail (emitting NO copy — the F5 bug), so that shape cs-builds/ww-louds until the F5 let-copy lands (task #7); absent from the gate corpus. 806 identroot_dot graduates from BUILD_FAIL: the C2 ident root makes append(h.xs, v) through *holder resolve via C1.5's place consumer (run-verified, byte-id). p6min9/p6min10 read-halves are fixed but the probes stay blocked on the #36 literal under-copy this commit unmasked (struct-ident field rhs copies 8B; repro filed with the task). test/805: +7 rows (typed depth-2 behind ident-index incl the 777 global-collision pin, deref-index, width/float/[N]u8 matrix, FA3 slice-field + .cap-behind-spine, &-route with compound-through- pointer, C1's reject_tail graduated to stores, neutrality pins) and +4 reject rows pinning the new loud texts; the C1.25 raw-byte readbacks graduate to typed depth-2 reads.
This commit is contained in:
@@ -24,6 +24,21 @@
|
||||
* diagnostics — the reject rows pin the exact text on BOTH stages.
|
||||
* Non-DOT lvalue tail residue is task #22.
|
||||
*
|
||||
* C2 (F4 + FA3-cstage, task #6): the READ side. cgplaceaddr grew an
|
||||
* N_IDENT root and recursion-driven N_INDEX bases; case N_DOT routes
|
||||
* every TYPED read no enumerated arm matched through the resolver, and
|
||||
* BOTH silent fallbacks died: the module-leaf `MOVQ <leaf>(SB)` is
|
||||
* gated to UNTYPED chains (pre-C2 it swallowed any unmatched dot chain
|
||||
* — a silent global read of a colliding symbol), and the offset-blind
|
||||
* cgexpr catch-all is gated to untyped-str pseudo-fields (pre-C2 a
|
||||
* nonzero-offset field behind a deref-index spine read element word 0;
|
||||
* offset-0 scalars worked by coincidence). TK_AMP's silent tail is the
|
||||
* same resolver-or-loud (`&threads[0].cap` used to SEGFAULT on deref,
|
||||
* reviewer-A route). The C1.25 raw-byte readbacks graduate to typed
|
||||
* depth-2 reads below. wwstage cgdot/cgun mirror symmetrically; its
|
||||
* name-keyed ident-indexed arm gap stays LOUD (C3/task #8 re-key), as
|
||||
* does the ptr-chained global-root remainder (task #37).
|
||||
*
|
||||
* row | shape | want
|
||||
* --------------------+----------------------------------------+------
|
||||
* store_size_neighbor | (*ts)[1].pc = 9, elem 0 intact | 19
|
||||
@@ -55,7 +70,22 @@
|
||||
* reject_float | f64 field store | BUILD_FAIL
|
||||
* reject_tagged | tagged-union field store | BUILD_FAIL
|
||||
* reject_str_compound | (*ts)[i].name += — str/slice compound | BUILD_FAIL
|
||||
* reject_tail | h.arr[1].pc (resolver-unwired N_DOT) | BUILD_FAIL
|
||||
* arr_field_idx_store | h.arr[1].pc = / += (C1's reject_tail, | 58
|
||||
* | graduated by the C2 resolver arms) |
|
||||
* read_depth2_idx | ts[i].cap.start/.end/.content.len — | 59
|
||||
* | typed depth-2 behind an IDENT index |
|
||||
* read_depth2_deref | (*ts)[i].cap.start + offset-0 .pc | 60
|
||||
* read_widths_spine | i8..u32/f64/f32/[3]u8 behind (*p)[i] | 61
|
||||
* read_slicefield | let h = (*p)[i].xs (FA3/pA5) + .cap | 62
|
||||
* amp_spine | &ts[1].cap / &(*p)[0].cap — deref, | 63
|
||||
* | compound through the pointer |
|
||||
* neutral_reads | ident-root chain, "abc".len, (*p).f — | 64
|
||||
* | untouched-arm asm-neutrality pins |
|
||||
* reject_read_tagged | (*ts)[i].tg read behind spine | BUILD_FAIL
|
||||
* reject_read_callbase| mk()[0].pc read (unaddressable base) | BUILD_FAIL
|
||||
* reject_assign_callbs| mk()[0].pc = (assign-tail text keeps | BUILD_FAIL
|
||||
* | its carrier post arr_field_idx_store) |
|
||||
* reject_addrof_callbs| &mk()[0].pc (TK_AMP loud tail) | BUILD_FAIL
|
||||
*
|
||||
* BUILD_FAIL rows also assert the diagnostic TEXT (stderr substring,
|
||||
* both stages) — a build that fails for any other reason (parse error,
|
||||
@@ -383,14 +413,10 @@ static const struct row rows[] = {
|
||||
* through a FRESH per-use @placescr materialise + word-copy; the
|
||||
* `...` setter pins the autofill zero loop; neighbour element +
|
||||
* sibling field readbacks pin the stride and copy length. */
|
||||
/* Readback is RAW bytes over ts.ptr (the 804 tagged_56b
|
||||
* precedent): a depth-2 read behind an index (ts[1].cap.start)
|
||||
* is the F4 walker gap (task #6) and link-fails today on the
|
||||
* cgen.c:9038 global-leaf fallback — typed readbacks graduate
|
||||
* with the C2 read-walker. Layout: t={pc@0,cap@8}, size 48;
|
||||
* capture={content(str ptr@0,len@8,cap@16),start@24,end@32}.
|
||||
* Elem1 base 48 → content.len byte 64, start 80, end 88;
|
||||
* elem0 → 16/32/40. Stored values fit one byte. */
|
||||
/* Readback was RAW bytes over ts.ptr until C2 — a depth-2 read
|
||||
* behind an index (ts[1].cap.start) was the F4 walker gap (task
|
||||
* #6) and link-failed on the cgen.c global-leaf fallback. C2
|
||||
* graduation: typed depth-2 readbacks (the documented note). */
|
||||
{ "agg_structlit_40b",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
@@ -407,24 +433,23 @@ static const struct row rows[] = {
|
||||
"\tappend(ts, t { pc = 7, cap = z });\n"
|
||||
"\tappend(ts, t { pc = 8, cap = z });\n"
|
||||
"\tsetcap(&ts, 1);\n"
|
||||
"\tlet bp: *u8 = ts.ptr: *u8;\n"
|
||||
"\tif (bp[64] != 3u8) { return 1; };\n"
|
||||
"\tif (bp[80] != 2u8) { return 2; };\n"
|
||||
"\tif (bp[88] != 4u8) { return 3; };\n"
|
||||
"\tif (ts[1].cap.content.len != 3) { return 1; };\n"
|
||||
"\tif (ts[1].cap.start != 2) { return 2; };\n"
|
||||
"\tif (ts[1].cap.end != 4) { return 3; };\n"
|
||||
"\tif (ts[1].pc != 8) { return 4; };\n"
|
||||
"\tif (bp[16] != 0u8) { return 5; };\n"
|
||||
"\tif (ts[0].cap.content.len != 0) { return 5; };\n"
|
||||
"\tif (ts[0].pc != 7) { return 6; };\n"
|
||||
"\tclearcap(&ts, 1);\n"
|
||||
"\tif (bp[64] != 1u8) { return 7; };\n"
|
||||
"\tif (bp[80] != 0u8) { return 8; };\n"
|
||||
"\tif (bp[88] != 0u8) { return 9; };\n"
|
||||
"\tif (ts[1].cap.content.len != 1) { return 7; };\n"
|
||||
"\tif (ts[1].cap.start != 0) { return 8; };\n"
|
||||
"\tif (ts[1].cap.end != 0) { return 9; };\n"
|
||||
"\treturn 52;\n"
|
||||
"};\n",
|
||||
52, NULL },
|
||||
|
||||
/* Addressable aggregate sources via the #265/#268 dispatch:
|
||||
* local ident (LEAQ slot) and deref (*pc). Raw-byte readback per
|
||||
* the agg_structlit_40b layout note (F4 blocks typed depth-2). */
|
||||
* local ident (LEAQ slot) and deref (*pc). Typed depth-2
|
||||
* readbacks since C2 (were raw bytes over ts.ptr). */
|
||||
{ "agg_from_ident_deref",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
@@ -442,16 +467,15 @@ static const struct row rows[] = {
|
||||
"\tappend(ts, t { pc = 8, cap = z });\n"
|
||||
"\tlet a: capture = capture { content = \"ab\", start = 1, end = 3 };\n"
|
||||
"\tcopycap(&ts, 1, a);\n"
|
||||
"\tlet bp: *u8 = ts.ptr: *u8;\n"
|
||||
"\tif (bp[64] != 2u8) { return 1; };\n"
|
||||
"\tif (bp[80] != 1u8) { return 2; };\n"
|
||||
"\tif (bp[88] != 3u8) { return 3; };\n"
|
||||
"\tif (ts[1].cap.content.len != 2) { return 1; };\n"
|
||||
"\tif (ts[1].cap.start != 1) { return 2; };\n"
|
||||
"\tif (ts[1].cap.end != 3) { return 3; };\n"
|
||||
"\tlet b: capture = capture { content = \"wxyz\", start = 5, end = 9 };\n"
|
||||
"\tderefcap(&ts, 0, &b);\n"
|
||||
"\tif (bp[16] != 4u8) { return 4; };\n"
|
||||
"\tif (bp[32] != 5u8) { return 5; };\n"
|
||||
"\tif (bp[40] != 9u8) { return 6; };\n"
|
||||
"\tif (bp[80] != 1u8) { return 7; };\n"
|
||||
"\tif (ts[0].cap.content.len != 4) { return 4; };\n"
|
||||
"\tif (ts[0].cap.start != 5) { return 5; };\n"
|
||||
"\tif (ts[0].cap.end != 9) { return 6; };\n"
|
||||
"\tif (ts[1].cap.start != 1) { return 7; };\n"
|
||||
"\treturn 53;\n"
|
||||
"};\n",
|
||||
53, NULL },
|
||||
@@ -524,13 +548,12 @@ static const struct row rows[] = {
|
||||
"\tappend(ts, t { pc = 7, cap = z });\n"
|
||||
"\tappend(ts, t { pc = 8, cap = z });\n"
|
||||
"\tsettwo(&ts);\n"
|
||||
"\tlet bp: *u8 = ts.ptr: *u8;\n"
|
||||
"\tif (bp[16] != 2u8) { return 1; };\n"
|
||||
"\tif (bp[32] != 1u8) { return 2; };\n"
|
||||
"\tif (bp[40] != 2u8) { return 3; };\n"
|
||||
"\tif (bp[64] != 3u8) { return 4; };\n"
|
||||
"\tif (bp[80] != 3u8) { return 5; };\n"
|
||||
"\tif (bp[88] != 4u8) { return 6; };\n"
|
||||
"\tif (ts[0].cap.content.len != 2) { return 1; };\n"
|
||||
"\tif (ts[0].cap.start != 1) { return 2; };\n"
|
||||
"\tif (ts[0].cap.end != 2) { return 3; };\n"
|
||||
"\tif (ts[1].cap.content.len != 3) { return 4; };\n"
|
||||
"\tif (ts[1].cap.start != 3) { return 5; };\n"
|
||||
"\tif (ts[1].cap.end != 4) { return 6; };\n"
|
||||
"\treturn 56;\n"
|
||||
"};\n",
|
||||
56, NULL },
|
||||
@@ -655,19 +678,239 @@ static const struct row rows[] = {
|
||||
BUILD_FAIL,
|
||||
"assign-resolver: compound on str/slice field not wired (rule-7)" },
|
||||
|
||||
/* An N_DOT lvalue the C1 resolver does not wire (index base is a
|
||||
* dot chain, not a deref) — pre-C1 this was a SILENT no-op store;
|
||||
* the loud dispatch tail is the close-by-construction net. */
|
||||
{ "reject_tail",
|
||||
/* C1's reject_tail (index base is a dot chain), graduated by the
|
||||
* C2 resolver arms (N_IDENT root + recursive N_INDEX bases) —
|
||||
* store, compound, readback, and neighbour-intact pins. */
|
||||
{ "arr_field_idx_store",
|
||||
"package main;\n"
|
||||
"type t = struct { pc: size, matched: bool };\n"
|
||||
"type holder = struct { arr: [3]t, n: i64 };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet h: holder = holder { n = 0, ... };\n"
|
||||
"\th.arr[1].pc = 5;\n"
|
||||
"\th.arr[1].pc += 2;\n"
|
||||
"\tif (h.arr[1].pc != 7) { return 1; };\n"
|
||||
"\tif (h.arr[0].pc != 0) { return 2; };\n"
|
||||
"\tif (h.arr[2].pc != 0) { return 3; };\n"
|
||||
"\treturn 58;\n"
|
||||
"};\n",
|
||||
58, NULL },
|
||||
|
||||
/* C2 (F4): typed depth-2 reads behind an IDENT-indexed root —
|
||||
* the p6min9/p6min10 read shape (nonzero offsets, both elements,
|
||||
* pseudo .len behind the spine, and the global-collision check:
|
||||
* a module global named `end` must NOT be read). Elements are
|
||||
* built with NESTED literals, not `cap = rc1` ident rhs — the
|
||||
* probes' own construction shape is the #36 under-copy (struct-
|
||||
* ident field rhs copies 8B), which keeps p6min9/p6min10
|
||||
* themselves blocked on #36 with their read-half fixed here. */
|
||||
{ "read_depth2_idx",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
"type t = struct { pc: size, cap: capture };\n"
|
||||
"let end: size = 777;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 5, cap = capture { content = \"abc\", start = 11, end = 13 } });\n"
|
||||
"\tappend(ts, t { pc = 6, cap = capture { content = \"wy\", start = 21, end = 23 } });\n"
|
||||
"\tif (ts[0].cap.end == 777) { return 66; };\n"
|
||||
"\tif (ts[0].cap.end != 13) { return 1; };\n"
|
||||
"\tif (ts[0].cap.start != 11) { return 2; };\n"
|
||||
"\tif (ts[1].cap.end != 23) { return 3; };\n"
|
||||
"\tif (ts[1].cap.content.len != 2) { return 4; };\n"
|
||||
"\tif (ts[1].pc != 6) { return 5; };\n"
|
||||
"\treturn 59;\n"
|
||||
"};\n",
|
||||
59, NULL },
|
||||
|
||||
/* C2 (F4): the same chain behind a DEREF-rooted index — plus the
|
||||
* offset-0 scalar (.pc) that pre-C2 cstage read correctly only by
|
||||
* COINCIDENCE through the offset-blind catch-all (ken's FA3
|
||||
* correction); now it routes through the resolver in both
|
||||
* stages. */
|
||||
{ "read_depth2_deref",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
"type t = struct { pc: size, cap: capture };\n"
|
||||
"fn rd(ts: *[]t) i32 = {\n"
|
||||
"\tif ((*ts)[0].pc != 5) { return 1; };\n"
|
||||
"\tif ((*ts)[0].cap.start != 11) { return 2; };\n"
|
||||
"\tif ((*ts)[0].cap.end != 13) { return 3; };\n"
|
||||
"\tif ((*ts)[1].cap.end != 23) { return 4; };\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 5, cap = capture { content = \"abc\", start = 11, end = 13 } });\n"
|
||||
"\tappend(ts, t { pc = 6, cap = capture { content = \"wy\", start = 21, end = 23 } });\n"
|
||||
"\tlet rc: i32 = rd(&ts);\n"
|
||||
"\tif (rc != 0) { return rc; };\n"
|
||||
"\treturn 60;\n"
|
||||
"};\n",
|
||||
60, NULL },
|
||||
|
||||
/* C2 (F4): leaf-kind matrix behind the deref-index spine — narrow
|
||||
* signed/unsigned (fldloadop sign/zero extension), f64/f32 via
|
||||
* X0, and an `[N]u8` field leaf (address semantics, outer index
|
||||
* applies). */
|
||||
{ "read_widths_spine",
|
||||
"package main;\n"
|
||||
"type inner = struct { b: i8, ub: u8, w: i16, uw: u16, d: i32, ud: u32, f: f64, g: f32, arr: [3]u8 };\n"
|
||||
"type box = struct { pad: size, it: inner };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet bs: []box = [];\n"
|
||||
"\tappend(bs, box { pad = 1, it = inner { b = -5i8, ub = 200u8, w = -300i16, uw = 60000u16, d = -70000, ud = 4000000000u32, f = 1.5, g = 2.5f32, arr = [7u8, 8u8, 9u8] } });\n"
|
||||
"\tlet p: *[]box = &bs;\n"
|
||||
"\tif ((*p)[0].it.b != -5i8) { return 1; };\n"
|
||||
"\tif ((*p)[0].it.ub != 200u8) { return 2; };\n"
|
||||
"\tif ((*p)[0].it.w != -300i16) { return 3; };\n"
|
||||
"\tif ((*p)[0].it.uw != 60000u16) { return 4; };\n"
|
||||
"\tif ((*p)[0].it.d != -70000) { return 5; };\n"
|
||||
"\tif ((*p)[0].it.ud != 4000000000u32) { return 6; };\n"
|
||||
"\tif ((*p)[0].it.f != 1.5) { return 7; };\n"
|
||||
"\tif ((*p)[0].it.g != 2.5f32) { return 8; };\n"
|
||||
"\tif ((*p)[0].it.arr[1] != 8u8) { return 9; };\n"
|
||||
"\treturn 61;\n"
|
||||
"};\n",
|
||||
61, NULL },
|
||||
|
||||
/* FA3/pA5 graduated: 24B slice-header field read behind a deref-
|
||||
* index spine — pre-C2 cstage took the offset-blind catch-all
|
||||
* (one wrong-offset MOVQ + stale BX/CX as the header), wwstage
|
||||
* silently emitted NOTHING. Plus the .cap pseudo behind the same
|
||||
* spine (recurses through the resolver). */
|
||||
{ "read_slicefield",
|
||||
"package main;\n"
|
||||
"type box = struct { pc: size, xs: []size };\n"
|
||||
"fn grab(p: *[]box, i: size) i32 = {\n"
|
||||
"\tlet h: []size = (*p)[i].xs;\n"
|
||||
"\tif (len(h) != 2) { return 1; };\n"
|
||||
"\tif (h[0] != (7: size)) { return 2; };\n"
|
||||
"\tif (h[1] != (8: size)) { return 3; };\n"
|
||||
"\tif ((*p)[i].xs.cap < 2) { return 4; };\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet src: []size = [];\n"
|
||||
"\tappend(src, (7: size));\n"
|
||||
"\tappend(src, (8: size));\n"
|
||||
"\tlet bs: []box = [];\n"
|
||||
"\tappend(bs, box { pc = 1, xs = src });\n"
|
||||
"\tlet rc: i32 = grab(&bs, 0);\n"
|
||||
"\tif (rc != 0) { return rc; };\n"
|
||||
"\treturn 62;\n"
|
||||
"};\n",
|
||||
62, NULL },
|
||||
|
||||
/* Reviewer-A route: address-of a field through an indexed /
|
||||
* deref-indexed spine, then deref + compound through the pointer.
|
||||
* Pre-C2 BOTH stages silently dropped the & (stale AX as the
|
||||
* address — gate-blind SEGFAULT). */
|
||||
{ "amp_spine",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
"type t = struct { pc: size, cap: capture };\n"
|
||||
"fn bump(cp: *capture) void = { cp.end += 100; };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 5, cap = capture { content = \"abc\", start = 11, end = 13 } });\n"
|
||||
"\tappend(ts, t { pc = 6, cap = capture { content = \"wy\", start = 21, end = 23 } });\n"
|
||||
"\tlet cp: *capture = &ts[1].cap;\n"
|
||||
"\tif (cp.start != 21) { return 1; };\n"
|
||||
"\tbump(cp);\n"
|
||||
"\tif (ts[1].cap.end != 123) { return 2; };\n"
|
||||
"\tlet pp: *[]t = &ts;\n"
|
||||
"\tlet dp: *capture = &(*pp)[0].cap;\n"
|
||||
"\tif (dp.end != 13) { return 3; };\n"
|
||||
"\treturn 63;\n"
|
||||
"};\n",
|
||||
63, NULL },
|
||||
|
||||
/* Asm-neutrality pins for the arms the C2 gates must NOT disturb:
|
||||
* ident-rooted value chain (chain walker), `(*p).f` retarget,
|
||||
* untyped-str literal pseudo-fields (the gated catch-all's only
|
||||
* legitimate tenant). A tuple-positional pin is blocked by the
|
||||
* pre-existing #33 wwstage tuple-let word-2 drop (filed). */
|
||||
{ "neutral_reads",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
"type t = struct { pc: size, cap: capture };\n"
|
||||
"fn pcof(p: *t) size = { return (*p).pc; };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet x: t = t { pc = 9, cap = capture { content = \"hi\", start = 1, end = 2 } };\n"
|
||||
"\tif (x.cap.start != 1) { return 1; };\n"
|
||||
"\tif (x.cap.content.len != 2) { return 2; };\n"
|
||||
"\tif (pcof(&x) != 9) { return 3; };\n"
|
||||
"\tif (\"abc\".len != 3) { return 4; };\n"
|
||||
"\treturn 64;\n"
|
||||
"};\n",
|
||||
64, NULL },
|
||||
|
||||
/* Tagged leaf behind a spine: no canonical register convention
|
||||
* is emitted by the read-resolver yet — must die LOUD, not load
|
||||
* 8 of 16+ bytes (rule 7). */
|
||||
{ "reject_read_tagged",
|
||||
"package main;\n"
|
||||
"type v = (i64 | bool);\n"
|
||||
"type t = struct { pc: size, tg: v };\n"
|
||||
"fn rd(ts: *[]t, i: size) i64 = {\n"
|
||||
"\tlet x: v = (*ts)[i].tg;\n"
|
||||
"\treturn 1;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\treturn rd(&ts, 0): i32;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL, "read-resolver: tagged field read not wired (rule-7)" },
|
||||
|
||||
/* A call-result index base has no storage address — the resolver
|
||||
* must refuse and the read tail must be LOUD (pre-C2: cstage
|
||||
* emitted an offset-blind garbage read, wwstage nothing). */
|
||||
{ "reject_read_callbase",
|
||||
"package main;\n"
|
||||
"type t = struct { pc: size, matched: bool };\n"
|
||||
"fn mk() []t = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 3, matched = true });\n"
|
||||
"\treturn ts;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tif (mk()[0].pc != 3) { return 1; };\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL, "unsupported field-read shape" },
|
||||
|
||||
/* The assign-tail diagnostic keeps a carrier now that C1's
|
||||
* reject_tail shape (h.arr[1].pc) graduated: a call-base lvalue
|
||||
* is unaddressable. */
|
||||
{ "reject_assign_callbase",
|
||||
"package main;\n"
|
||||
"type t = struct { pc: size, matched: bool };\n"
|
||||
"fn mk() []t = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 3, matched = true });\n"
|
||||
"\treturn ts;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tmk()[0].pc = 2;\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL, "unsupported assign target shape" },
|
||||
|
||||
/* TK_AMP loud tail (the C2 replacement for the silent drop). */
|
||||
{ "reject_addrof_callbase",
|
||||
"package main;\n"
|
||||
"type t = struct { pc: size, matched: bool };\n"
|
||||
"fn mk() []t = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 3, matched = true });\n"
|
||||
"\treturn ts;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet p: *size = &mk()[0].pc;\n"
|
||||
"\treturn (*p): i32;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL, "unsupported address-of shape" },
|
||||
};
|
||||
|
||||
/* errlog_has — the build-failure stderr must carry the row's expected
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
* | — nested indirect append inside the |
|
||||
* | outer's value expr; pins the per-SITE |
|
||||
* | @apphdrscr slot (a shared slot clobbers)|
|
||||
* reject_identroot_dot | h.xs via *holder param (resolver ident | BUILD_FAIL
|
||||
* | root unwired — was silent corruption) |
|
||||
* identroot_dot | h.xs via *holder param — C1.5's reject, | 73
|
||||
* | graduated by C2's resolver ident root |
|
||||
* reject_spread_src | non-ident spread SOURCE through a deref | BUILD_FAIL
|
||||
* | target (the #35 designed boundary) |
|
||||
*
|
||||
@@ -372,20 +372,28 @@ static const struct row rows[] = {
|
||||
"};\n",
|
||||
33, NULL },
|
||||
|
||||
/* Ident-rooted dot target (h.xs through *holder): the resolver
|
||||
* does not wire ident roots (they belong to the enumerated arms;
|
||||
* none exists for append yet) — pre-fix this shape silently
|
||||
* corrupted the frame in cstage; now it must die LOUD. */
|
||||
{ "reject_identroot_dot",
|
||||
/* Ident-rooted dot target (h.xs through *holder): C1.5's loud
|
||||
* boundary (the resolver had no ident root then; pre-FA1 this
|
||||
* shape silently corrupted the frame in cstage), graduated by
|
||||
* C2's cgplaceaddr N_IDENT root — the *holder base derefs once
|
||||
* inside the N_DOT hop and the header place lands on &h.xs.
|
||||
* Readbacks use the .len pseudo, not len(): len() of a non-tuple
|
||||
* N_DOT is the pre-existing F2 enumeration gap (task #10). */
|
||||
{ "identroot_dot",
|
||||
"package main;\n"
|
||||
"type holder = struct { tag: i64, xs: []i64 };\n"
|
||||
"fn addfield(h: *holder, v: i64) void = { append(h.xs, v); };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet hl: holder = holder { tag = 2, xs = [] };\n"
|
||||
"\taddfield(&hl, 9);\n"
|
||||
"\treturn 0;\n"
|
||||
"\taddfield(&hl, 11);\n"
|
||||
"\tif (hl.xs[0] != 9) { return 1; };\n"
|
||||
"\tif (hl.xs[1] != 11) { return 2; };\n"
|
||||
"\tif (hl.xs.len != 2) { return 3; };\n"
|
||||
"\tif (hl.tag != 2) { return 4; };\n"
|
||||
"\treturn 73;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL, "#15: append() target place unsupported (rule-7)" },
|
||||
73, NULL },
|
||||
|
||||
/* The FA4 designed boundary (task #35, old #37): a spread SOURCE that is
|
||||
* not an ident local must stay loud even now that the deref
|
||||
|
||||
Reference in New Issue
Block a user