Repository navigation
t27b: array literals the reference prints as @constCast(&[_]E{ ... }) get one writable static per type and value, from a t27 plan (Closes #7680) - #7694
Merged
Conversation
…loses #7680) specs/tri/t27b/conformance/static_slice_literal.t27 pins what the reference does with an array literal t27c prints as @constcast(&[_]E{ ... }): a slice field of a named struct literal (topological_sort.t27, graph.t27) and a constant returned as a mutable slice (bellman_ford.t27). With zig 0.16.0's default x86_64 Debug backend the array is one interned, writable object per element type and value: a write through the slice is read by the next evaluation of the same literal and of an equal literal at another site, a []const one too. Each test of t27c test-report is its own process, so every test starts from the constants. t27c test-report: 8/8 pass, 0 vacuous, 21 runtime asserts. Sealed on the t27c lab (seal --save, then --verify: all hashes MATCH). Part of #6063. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e static per type and value, from a t27 plan (Closes #7680) The decisions are specs/tri/t27b/slice_lit_plan.t27, mounted through t27c gen-rust (gen/rust/tri/t27b/slice_lit_plan.rs). Compile-time elements of a slice field in a named struct literal, or of a slice return (mutable or not), go into a t27b global interned by array type and bytes: written at load and reset on every host entry, as a module-level var is, because each reference test runs in its own process. A typed literal with no elements (`[]usize`) is an empty slice, as the reference prints it. Dropped refusals: ExprArrayLiteral(to slice field) for constants, and ExprArrayLiteral(constant to mutable slice), whose claim that a write faults in the reference is not true of the backend the lab runs. Kept: run-time elements (a frame address in the reference, #7550), an anonymous struct literal's field, a slice of arrays, a repeat, and a typed literal with a dimension and no elements. Glue: lower/arraylit.rs +39 (slice_lit replaces slice_literal_return), lower.rs +7 (the mount, the intern table, two call sites; slice_field deleted). Tests: the refusal test becomes a run of the conformance spec; the field rejection case now uses a run-time element. Part of #6063. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tic (Closes #7680) static_pair32() returns [0, 1] as []u32 and static_wide() returns [4294967296] as []usize: the same eight bytes. A write through the first must not show through the second, because Zig interns by type and value. This pins the type half of t27b's intern key. t27c test-report: 8/8 pass, 0 vacuous, 23 runtime asserts. Resealed on the t27c lab (seal --save, then --verify: all hashes MATCH). Part of #6063. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Closes #7680) A plan mutant that took STATIC only from two elements survived the nine tests; one_element_wins_over_size_text kills it. 20 of 20 plan mutants are now killed under t27c test-report (10/10 pass, 0 vacuous). gen-rust regenerated (its header counts the tests) and the plan resealed on the t27c lab (seal --verify: all hashes MATCH). Part of #6063. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oses #7680) A t27b static is bytes written before the program runs, and a string's address is not known then. Such a literal used to fall through to the static writer and come back as `ConstDecl(str field)`, "str field in a module-level struct constant", which is not what happened. The plan now asks whether the element type holds a str and refuses it as ExprArrayLiteral(to slice field) or ExprArrayLiteral(string slice return). wrapup-auto.t27's `files_modified: ["..."]` is the corpus case. Plan: 11/11 pass under t27c test-report, 0 vacuous; 26 of 26 plan mutants killed. gen-rust regenerated (byte-identical over 3 runs), plan resealed (seal --verify: all hashes MATCH). Glue: one line changed in arraylit.rs. Part of #6063. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…7680) docs/reports/t27b_expectations.json: `tri t27b ratchet --bless` of the branch run 482a434, composed onto master ef26684's ledger with only the rows whose verdict this branch changes: two new rows, both pass (conformance/static_slice_literal.t27, slice_lit_plan.t27). pass 875 -> 877, max_not_pass stays 51. The three graph specs only MOVED (still blocked, by ExprCall and type mismatch), so their rows stay master's. AGENTS.md: `wc -l` of cli/t27b/src/*.rs 14919 -> 14885 and cli/t27b/tests/*.rs 7874 -> 7866. Part of #6063. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGENTS.md conflicted on the t27b remainder line: both sides kept. #7673's entry (14876 plus 7874) comes first, then this branch's, re-measured with `wc -l` on the merge: cli/t27b/src/*.rs 14842, cli/t27b/tests/*.rs 7866, -34 and -8 on master 3d71306's 14876 plus 7874. Part of #6063. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
This was referenced Oct 8, 2026
This was referenced Oct 8, 2026
gHashTag
pushed a commit
that referenced
this pull request
Oct 8, 2026
From master's side (#7470's module vars, and policy and verified commits). docs/reports/t27b_expectations.json: master's ledger plus this branch's six rows, recomposed as before: pass 898 -> 901, max_not_pass 39 -> 40. AGENTS.md: this branch's clause re-measured with `wc -l` over master 1f2448e: 14967 -> 14998 and 7987 -> 8005. Merged-tree checks on the t27c lab: cargo test --release -p t27b 120 passed, 0 failed; under `t27b test --check` the four new specs, #7470's two conformance specs and static_slice_literal.t27 (#7694) pass, and frame_address_return.t27 (#7660), frame_address_store.t27, gen_lockfree_stack.t27 and tool-registry.t27 are refused by name as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gHashTag
added a commit
that referenced
this pull request
Oct 8, 2026
…}) is refused by name, not encoded, from a t27 plan (Closes #7765) (#7786) * t27b: a write through an array literal printed @constcast(&[_]E{ ... }) is refused by name, not encoded (Closes #7765) #7694 let a write through such a slice succeed and be read back by the next evaluation of an equal literal, as zig 0.16's x86_64 Debug backend does. Writing that comptime constant is undefined behaviour in Zig: on the native aarch64 job (LLVM) four tests of static_slice_literal.t27 fail (run 37758574293, master 209ab18: REFFAIL, 4 REFDISAGREE, STALE). specs/tri/t27b/slice_lit_plan.t27 now decides a write check: the glue logs each STATIC literal whose destination is a mutable slice, and each WRITE, a store through an element of a mutable slice or its address taken (`lvalue` sets `writing`; `slice_index` reports), in code the reference analyzes. After every body, a WRITE whose element type a STATIC backs is refused as StmtAssign(write through an array literal), at the write. Reads keep their static storage. The conformance spec keeps its read-only tests (5, 22 runtime asserts, 0 vacuous under t27c test-report on the t27c lab) and drops the four that wrote; cli/t27b/tests/arraylit.rs checks the refusal through a callee, a struct element, an address and a derived slice, and that a write through another element type's slice still runs. Plan: 13/13 pass, 0 vacuous; 14 of 14 new plan mutants killed, 11 of 11 conformance assert mutants, 6 of 6 glue mutants (cargo test). gen-rust regenerated; both specs resealed (seal --save, --verify: all MATCH). cargo test --release -p t27b: all pass (t27c lab). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * AGENTS.md: t27b's Rust remainder after #7765's write check (Closes #7765) `wc -l` of cli/t27b/src/*.rs 14905 -> 14922 (+17, lower.rs) and cli/t27b/tests/*.rs 7942 -> 7964 (+22, arraylit.rs) on master 01de65c. The write check's decisions are specs/tri/t27b/slice_lit_plan.t27. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <claude@anthropic.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #7680. Part of #6063 (t27b coverage), which is item C10 of #6488.
What the refusals guarded
t27c's Zig backend prints an array literal as
@constCast(&[_]E{ ... })in two places: a slice field of a named struct literal, and the value of a fn that returns a slice. E is the element type of the destination. t27b refused two shapes of it.ExprArrayLiteral(to slice field)(slice_fieldincli/t27b/src/lower.rs, from 4f14eda, t27b: array literals typed by their use (str args, tuple locals, empty slice fields) #6369). It took only an untyped empty literal, and refused every other one, a bare typed[]usizeincluded. Its stated reason: "A non-empty one points at a constant in the reference, which outlives any frame t27b could build it in." t27b had frame temporaries, which die with the frame, and read-only data. It had no storage with the reference's lifetime that a program could also write.ExprArrayLiteral(constant to mutable slice)(slice_literal_returnincli/t27b/src/lower/arraylit.rs, from 6600bd3, feat(t27b): array literals returned as constant slices and literal locals passed by address (Closes #6866) #6938). It applied to a constant returned as a mutable[]Efrom a fn that a test reaches. Its stated reason: "a write through it faults in the reference". t27b kept such a constant in read-only data. A store there is an IR defect in t27b: its interpreter faults, and its JIT segfaults.Both stated reasons are about the reference, so I measured the reference.
Setup: the t27c Railway lab, zig 0.16.0, with the default x86_64 Debug backend that
t27c test-reportbuilds with. The input was a Zig file of these shapes.[_]usize{ 0, 1, 2, 3 }printed the same address. So did a[]constsite with no@constCast.[_]u64against[_]usize, and for equal bytes of two types.-fllvmthe same write segfaults (read-only memory);t27c test-reportruns each test in its own process (bootstrap/src/test_report.rs, "Runs one test per process"). So every test starts from the constants.The first refusal guarded a storage question. The second guarded a claim that is false for the backend the lab uses.
The refusal that does guard the frame address stays. That is
ExprArrayLiteral(run-time slice return), which matches the policy of #7660 / #7550. Run-time elements live in the frame of the fn that writes them, and a returned slice of them dangles. This PR keeps that refusal, and refuses run-time elements in a slice field too, because such a field would dangle once a struct holding it is returned.Decision
A literal of compile-time elements becomes one writable static object per array type and value. It is a t27b global, exactly the storage of a module-level
var:eval.rsreset_globals,jit.rscall_fp);The slice field or the returned slice points at that object. A literal with no elements and no size text is a zero-length slice;
.nodes = []usizeis@constCast(&[_]usize{ })in the reference.This is the reference's lifetime (the process, which is the test), its storage (one object per type and value, writable) and its mutability (the destination's const-ness does not matter).
Still refused, by name:
ExprArrayLiteral(to slice field)ExprArrayLiteral(run-time slice return)strExprArrayLiteral(to slice field)/ExprArrayLiteral(string slice return)ExprArrayLiteral(to slice).{ ... }, which Zig refuses for a sliceExprArrayLiteral(to slice)[v; n], fieldExprArrayLiteral(to slice field)ExprArrayLiteral(to slice field)ExprArrayLiteral(reference empty typed)names)A return that the plan does not take goes on to t27b's other return paths, exactly as before.
Known limit. t27b's types do not tell
usizefromu64, orisizefromi64. So a usize literal and a u64 literal of one value share an object in t27b, while Zig makes two. Only a test that writes through one and reads the other can tell. No corpus spec does.Where the decisions live. They are a t27 plan,
specs/tri/t27b/slice_lit_plan.t27, with 11 tests.t27c gen-rustturns it intogen/rust/tri/t27b/slice_lit_plan.rs, andlower.rsmounts that file with#[path], as it mountswide_plan.rs(#7657) andbuiltin_plan.rs(#7614). The plan covers:PARSE);The glue in
lower/arraylit.rs(slice_lit) only reads the shape, asksplan, and builds the answer: a zero-length temporary, or the interned global. One function now serves both the field (it replacesslice_field) and the return (it replacesslice_literal_return). A[]constreturn of a constant now uses the same static instead of read-only data, so it sees a write through an equal mutable literal, as Zig's does.ExprArrayLiteralinternary_gates.t27andultra_engine_v70_ultimate.t27is not the same mechanism. The reference prints those as an untyped tuple local,const vals = .{ ... };, that a test indexes. They are not@constCast(&[_]E{ ... }). Nor isExprArrayLiteral(reference empty typed)internary_mac_synth.t27. That is the reference's own printing defect, and #7404 fixes the spec. All three are untouched.Conformance spec first
specs/tri/t27b/conformance/static_slice_literal.t27has 8 tests in the shapes of the three graph specs:.order = []usize{ 0, 1, 2, 3 }in a named struct literal;.items = []usize;return []StaticHop{ .{ ... }, ... }from-> []StaticHop.It pins the reference's semantics, writes included:
[]constreturn included;[0, 1]as[]u32against[4294967296]as[]usize) are other objects;t27c test-reportseal --save, then--verify: all hashes MATCH)ExprArrayLiteral(to slice field)test --check, aarch64 under qemuMutants
t27c test-reportGlue mutants, run as
cargo test --release -p t27b --test arraylit --test sourceon the t27c lab (x86_64, interpreter only). All 8 are killed:ConstDeclname.What this does not do
The three graph specs move from
ExprArrayLiteralto their next blockers. None of them passes yet:graph.t27ExprCall(when result = add_node(&graph), a void fn used as a value)bellman_ford.t27ExprCall(the same construct)topological_sort.t27type mismatchtopological_sort.t27'stype mismatchcomes from the reference's W585 scaffold:given graph = default_input()is printedconst graph = undefined;, and the call is never made. #7690 is a separate mechanism in five reference-passing specs.No reference pass in this family comes from reading dead memory. The scaffold's
undefinedis never read:sortignores its parameter.specs/automation/wrapup-auto.t27is blocked first byStmtAssign(#7404). Its second blocker is now the named strings refusal.Lines (
git diff --numstat --no-renames origin/master...HEAD)cli/t27b/src/lower/arraylit.rscli/t27b/src/lower.rscli/t27b/tests/arraylit.rscli/t27b/tests/source.rsgen/rust/tri/t27b/slice_lit_plan.rst27c gen-rust, not hand-editedspecs/tri/t27b/slice_lit_plan.t27specs/tri/t27b/conformance/static_slice_literal.t27.trinity/seals/*.json(2)t27c seal --savedocs/reports/t27b_expectations.jsonAGENTS.mdHand-written foreign code: 57 added lines and 105 deleted.
src: 46 added (39 inarraylit.rs, 7 inlower.rs).tools/policy/foreign-exceptions.txt; this PR does not change that file and needs no label.Test changes:
tests/arraylit.rs: the refusal test for a constant returned as a mutable slice becomesstatic_conformance_spec_passes, which runs the conformance spec through both the JIT and the interpreter.tests/source.rs: the slice-field rejection case now uses a run-time element.AGENTS.md, re-measured with
wc -lon the merged head:cli/t27b/src/*.rsgoes from 14876 to 14842, andcli/t27b/tests/*.rsfrom 7874 to 7866. That is -34 and -8 on master 3d71306, after #7673's entry.src/lower/*.rsis outside that glob, as before:arraylit.rsis -6.Gates
Both gates ran on the t27c Railway lab, from master 3d71306's
gen/c/policy/own_language.cwithlefthook.yml's one-line C main, over the merged head.check_budget()overgit diff --numstat --no-renames origin/master...HEAD: exit 0.lower.rs, and this diff plus 30 more test lines.check_all()withorigin/master:tools/policy/foreign-exceptions.txt, in the--(pre-push) and--ciforms: exit 0.Other checks:
tools/l2_regen_check.py --base ef26684a1 --head HEAD:t27c gen-rustreproduces the plan's generated file byte for byte, and gave the same bytes over 3 runs.tools/check_seal_currency.py: 0 stale generated-code hashes.tools/check_seal_coverage.py: OK. Both new seals:seal --verifygives all hashes MATCH.tools/check_assertionless_spec_tests.py: ok, 3761 in 30, as on the baseline.StaticOrder,StaticBagandStaticHophave no other definition inspecs/.t27b lab: full corpus with the reference
Both columns are private runs of the deployed lab.
/tmpdirectory on the t27b lab imported/opt/t27b-lab/lab.py(lab_py_sha 94254f63f) and ran itslab_run.T27_SRVandT27_WORKpointed at that directory, so the lab's/srvand/workwere not touched.--jobs 12, 3 reference workers, fuzz off.qemu-aarch64 t27b corpus specs --json --runner qemu-aarch64 --timeout-ms 60000 --jobs 12. The reference verdicts come fromt27c test-report.specs/fpga/testbench/*_tb.t27)cargo test --release -p t27b(aarch64, qemu)Per file, master against branch:
graph.t27:ExprArrayLiteral(to slice field)becomesExprCall;topological_sort.t27:ExprArrayLiteral(to slice field)becomestype mismatch;bellman_ford.t27:ExprArrayLiteral(constant to mutable slice)becomesExprCall;igla/coder/bench_proxy.t27, which the reference blocks: becomesExprArrayLiteral(string slice return).The merged head, measured again. The head is ca978fe, with master 3d71306 merged in. The t27b lab was redeployed during the work, and the new deployment has lab_py_sha a39cc460b. Both columns below are private runs of that deployment, with the same settings as above. The run JSONs' sha256 prefixes are 3978d762 (master) and 93dd6178 (branch).
cargo test --release -p t27b(aarch64, qemu)The per-file comparison is the same as on the base:
Against this PR's ledger, the merged run's ratchet findings are master's own run's findings plus the three informational MOVED rows.
Ledger
The rows come from
tri t27b ratchet --blessof the 482a434 run, composed onto master's ledger. Only the rows whose verdict this branch changes are taken, which here means two new rows:specs/tri/t27b/conformance/static_slice_literal.t27: pass;specs/tri/t27b/slice_lit_plan.t27: pass.Counts: pass 875 -> 877, not_pass 51, max_not_pass 51. The ledger has 1078 rows and no duplicate path.
Ratchet result. Against the new ledger, the branch run shows master's own findings (UNLISTED 18, UNEXPECTED PASS 2, STALE 1), plus three informational MOVED rows for the graph specs. Their verdict stays blocked, so their rows stay master's.
gen-rust gaps
None. gen-rust expressed the whole plan: decisions over
u8,boolandusize, andstrresults with nostrparameters, which keeps clear of #7449.Generated with Claude Code