gen-rust: std macros keep their bang -- assert!, assert_eq!, assert_ne!, panic!, unreachable! (Closes #5987) - #6103
Merged
Merged
Conversation
…ert_ne!, panic!, unreachable! (Closes #5987) gen-rust printed a t27 `assert(c)` in a function body as `assert((c));`, a call to a FUNCTION named `assert`, which Rust does not have; rustc refused the file with E0423 (expected function, found macro `assert`). The generic call arm prints `name(args)` for any call it does not know, and the identifier arm prints the name, so `assert_eq`, `assert_ne`, `panic`, Zig's `@panic` and a bare `unreachable` lost their `!` too. - `std_macro_call_to_rust` lowers assert/assert_eq/assert_ne/panic to the macros; a message argument goes through "{}", never as the format string (non-literal messages are an error in edition 2021, and a literal holding braces would be read as a format directive). - `@panic(m)` lowers to `panic!("{}", m)` in `zig_builtin_to_rust`. - A bare `unreachable` identifier lowers to `unreachable!()`. - `module_declares`: a spec that gives the name its own meaning (fn, typed param or local, typed const, module var) keeps its own call. - `expect`, `expectEqual`, `std.testing.*` are deliberately unchanged. Measured over 1184 specs: 17 specs change their Rust output; rustc --edition 2021 --crate-type lib accepts 646 -> 647; found-macro diagnostics in the changed files 109 -> 9 (the 9 left are `print`). Tests: tests_5987_rust_std_macro_bang (8). FROZEN_HASH re-pinned; 25 seals of 14 specs re-sealed for their new gen_hash_rust. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts: bootstrap/stage0/FROZEN_HASH (re-pinned to the merged compiler.rs), .trinity/seals/Lstm.json and recurrent_Lstm.json (master's version taken, then re-sealed with the merged t27c: master's Rust backend changes and this branch's assert! both move gen_hash_rust). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 4, 2026
…_HASH, re-seal Merged and re-sealed on the Railway t27c lab, not the workstation (owner rule, 2026-10-04). Conflicts: - bootstrap/src/compiler.rs: one hunk at the end of the file, where this branch appended tests_5987_rust_std_macro_bang and master (#6003) appended tests_5984_gen_zig_discard_call. Resolved as both modules, this branch's first. The merged file's changes against master's side are exactly this branch's changes against the merge base (same +/- lines). - bootstrap/stage0/FROZEN_HASH: recomputed as the sha256 of the merged compiler.rs (c2d70f5c90ef...). - Five seal files: each took master's side; then every seal a t27c built from this merge reads as newly stale (3: specs/igla/race/backend.t27, specs/port/tools/builtin_parity_table.t27, specs/tri/graph/graph_bfs.t27) was re-sealed with `t27c seal --save` (zig 0.16.0 on PATH) and `tri seals sync-twins`. On the lab, before committing: `cargo test --release -p t27c tests_59` 14 passed; tools/check_seal_currency.py rc 0; no seal says "zig not on PATH". Refs #5987, Refs #6092 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
This was referenced Oct 4, 2026
9 tasks
This was referenced Oct 4, 2026
Merged
compiler.rs: both sides added test modules after the same `#[cfg(test)]`; kept tests_5987 and gave master's tests_5923/5949/5968 their own `#[cfg(test)]`. FROZEN_HASH refrozen. Refs #6092 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The master merge brought specs/auth/config.t27's seals, made before gen-rust printed `assert!`; re-sealed on the t27c lab with zig 0.16.0. Refs #6092 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
PR DashboardGenerated at: 2026-10-04 16:17:02 UTC
Summary
Seal Status
|
Contributor
PR DashboardGenerated at: 2026-10-04 16:23:08 UTC
Summary
Seal Status
|
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 #5987
Refs #6092
What was wrong
gen-rust lowered a t27
assert(cond)in a FUNCTION body toassert((cond));. That calls a function namedassert, and Rust has no such function:assertis a macro. rustc refused the file witherror[E0423]: expected function, found macro 'assert'.RustCodegen::expr_to_rusthas a generic call arm that printsname(args)for any call it does not recognise, and an identifier arm that prints the bare name. So every Rust std macro that t27 shares by name came out without its!. I ran one reproducer per name throught27c gen-rustandrustc --edition 2021 --crate-type lib:assert(c)assert((c));assertassert!((c));assert(c, "m {x}")assert((c), "m {x}");assert!((c), "{}", "m {x}");assert_eq(a, b)assert_eq(a, b);assert_eq!(a, b);assert_ne(a, b)assert_ne(a, b);assert_ne!(a, b);unreachable;unreachable;unreachable!();if (c) unreachable else a{ unreachable }{ unreachable!() }panic("m")panic("m");panic!("{}", "m");@panic(msg)@panic(msg);@panic!("{}", msg);The task text pointed at the
self.write("assert(")sites. Those are in the C backend (gen_c_expr, forstd.testing.expect*), andassert(...)is valid C there, so they are not changed. See "Seen and not fixed here" for the missing#include.The fix
All of it is in
bootstrap/src/compiler.rs, inRustCodegen:std_macro_call_to_rust, called from the ExprCall arm right afterzig_builtin_to_rust, maps:assert/1toassert!assert/2,assert_eq/2,3andassert_ne/2,3to the matching macrospanic/0,1topanic!A MESSAGE argument goes through
"{}", never as the format string. In edition 2021 a non-literal message is an error, and a literal containing{/}would be read as a format directive. The reproducer"a too big {x}"covers this case.zig_builtin_to_rust:@panic(m)becomespanic!("{}", m).Identifier arm: a bare
unreachablebecomesunreachable!(), both as a statement and as a branch ofif .. else.module_declares(name)is the guard. If the spec gives the name its own meaning, nothing is rewritten. That covers:Rust resolves
assert(c)to the spec's ownfn assert, because functions and macros live in separate namespaces. That plain call already compiles, and rewriting it would call the wrong thing. On 2026-10-04 no spec in the corpus declared any of these names. An untyped local is not tracked by this guard.Deliberately NOT mapped:
expect,expectEqualandstd.testing.*. Rust has no macro with those names (expectis a lint attribute), so nothing is missing a!. Mapping them ontoassert!would mean choosing semantics, since Zig'sexpectreturns an error rather than aborting.Unit tests: module
tests_5987_rust_std_macro_bangat the end ofcompiler.rs, 8 tests.fn assertandfn panic, a parameter namedunreachable, a constant namedunreachable, andexpect.FROZEN_HASH is re-pinned.
25 seals (14 specs) are re-sealed for their new
gen_hash_rust. After the master merge,Lstm.jsonandrecurrent_Lstm.jsonwere re-sealed again on the merged compiler.Misread shape: not added
I did not add this to
cli/tri/src/misread.rs, for three reasons.ExprCall. The defect is in the emitter, not a misreading.tri misreadwould refuse to run.Numbers (measured)
How I measured. These are local measurements, made before the owner rule moved compile work to the Railway lab. The lab's gates do not include a rustc acceptance census, so this table does not come from the lab run. The lab run, linked under "Gates run locally", confirms the gates on the merged head.
git ls-files specs/minusspecs/scratch/, 1184 specs.t27c gen-rustand thenrustc --edition 2021 --crate-type lib --crate-name m -A warnings, overwriting a single /tmp rlib path each time.^errorlines, excluding the "aborting due to" summary line.Results.
assertunreachableprint(not touched)@" in those filesspecs/tri/search/match.t27. No spec went from accepted to refused: I diffed the two accepted sets.assert(lines in function bodies across 9 specs. rustc reported 94 E0423 for them, because the 95th sits in a file whose parse stops first.assert!linespanic!sites (3 from@panic, 1 frompanic)unreachable!sitesport/browseros/.../queen-public-leaderboardwent from 4 to 11 errors. Once itsassert!compiled, rustc reached the type check, which reports indexing anOption<&str>. That error was already there, hidden behind the earlier ones.The changed specs:
Gates run locally
The lab results come first, then the local runs.
Railway lab, merged head
9835bee1: verdict green, no red gates.Run: https://t27c-lab-production.up.railway.app/runs/9835bee1165c38227dc4f509ff0696af8396cfde.json
cargo build --release -p t27c -p trioksuite --corpus-only --ratchet: RATCHET CLEANicarus_lowerable corpus_classifier_matches_lean_completeness: 1 passedLocal runs, before the owner rule moved builds to the lab.
cargo test --release -p t27c tests_5987_rust_std_macro_bang: 8 passed. Run on9aa0aa729and again on the merged tree.t27c suite --repo-root . --corpus-only --ratchet --json /tmp/assert_suite.jsonon9aa0aa729: RATCHET: CLEAN. GATE FAILURES 0, DISCARD WORSENED 0, DISCARD UNPINNED 0.tools/check_seal_currency.py:9aa0aa729: 25 STALE, allgen_hash_rust, covering 14 specs (the changed specs that have seals). I re-sealed them witht27c seal <spec> --save, and the rerun showed 0 stale.Lstmtwins), re-sealed, then 0 stale.tools/check_seal_coverage.py: OK, on both trees.tools/check_specs_generate.py: OK, on both trees.tools/ci/check_specs_still_parse.py --base origin/master: "ok: this change touches no .t27 file".cargo test --release -p t27c --test icarus_lowerable corpus_classifier_matches_lean_completeness: 1 passed, on both trees.tools/check_now_entry_shape.py: OK, 1 entry, well formed.scripts/ci/now-sync-gate-diff.sh: passed.cargo test --release -p tri misread: not run, becausecli/tri/src/misread.rsis not touched._why_key was added. The suite reported no drift.suitegate above covers that tree.Merge state. This branch merged origin/master once (
9835bee11). Since then master has moved 24 more commits.git merge-treeshowsbootstrap/src/compiler.rsauto-merging cleanly.bootstrap/stage0/FROZEN_HASHand in 5 seals:Backend.jsonTriGraphBfs.jsongraph_TriGraphBfs.jsonrace_igla-race-backend.jsontools_specs::port::tools::builtin_parity_table.jsonSeen and not fixed here
asserthas no include. gen-c writesassert(...)without#include <assert.h>, soccrefuses it as an undeclared function. Seen with the same/tmp/pa.t27.unreachable. The Zig backend writes@"unreachable"for anunreachablestatement or expression. That is an identifier lookup, not the keyword. The re-seal ofspecs/tri/search/match.t27records it: "use of undeclared identifier 'unreachable'".print(...). 189 lines in 11 specs, and 9 E0423 in the changed files. One spec declares its ownfn print. Rust hasprint!, but t27'sprintin the ported tools means a LINE, so choosingprint!orprintln!is a semantic decision, not a missing bang.undefined.assert((x != undefined))intri/io/zip:undefinedis not Rust (E0425). The C backend writes a W585 comment for the same case.@compileError(7 sites ingraph/knowledge_graph, not one of the changed specs)++string concatenation (check_graph_law8)try (try (allocator.alloc(..))), which rustc refuses as the reserved keywordtry(segment_tree)expectand friends.expect,expectEqualandstd.testing.*in function bodies remain unlowered for Rust (E0423 / E0425). This is intentional; see "The fix".🤖 Generated with Claude Code