feat(t27b): structs, field access, pointers and struct results - #6044
Merged
Merged
Conversation
Lower struct declarations, struct literals, field reads and writes,
`&x` / `p.*` / `*T`, struct parameters and struct results to the memory
primitives of the previous change. Structs always live in memory:
- A struct local or temporary lives in a frame slot. Its literal is built
in place when the destination is fresh and its address is pure;
otherwise it is built in a temporary and copied.
- A struct parameter is the caller's memory, passed by address and
never written.
- A struct result is built through a hidden last pointer parameter.
Such functions are listed in `Program.internal_abi`, and `t27b build`
does not export them (it prints a note).
- A module struct constant goes to read-only data. A scalar field of it
folds to a constant (`const OX: i32 = ORIGIN.x`).
- Layout follows the C rules and is computed on first use. A pointee is
only named, so `next: *const Node` works. A struct that contains
itself by value is rejected, and so is a generic struct.
- An address-taken scalar local or parameter lives in a slot.
- Compound assignment through an impure address evaluates the address
once.
Every rejection is precise: a missing, unknown or duplicate field, a
positional initializer, an anonymous `.{}` with no result type, a write
through a constant, a struct or pointer operand, a non-value `X.y`, and
a struct that contains itself.
IR: new `ExprKind::Seq { stmts, value }` (stores and copies, then a
value), so a struct temporary is built exactly where its argument is
evaluated. The interpreter and the code generator both implement it, and
the random differential generator now emits it.
Corpus (specs/, --jobs 6): 47 -> 70 files supported with every test
passing, 0 JIT/interpreter mismatches.
- One newly reached file fails one test (fpga/verification/build_verify,
module count 33 vs 31). t27c gen + zig test fails the same assertion,
so the reference fails here too.
- Two files time out in the t27c parse phase alone at a load average
near 780.
Refs #5977
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 4, 2026
6 tasks
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.
Stacked on #6007 (memory primitives). The base is
claude/t27b-memory; retarget it tomasteronce #6007 lands.What
t27b now lowers structs onto the memory primitives from #6007:
b.a.y = 9,p.x += 1).&x,p.*,*Tand*const T, plus field access through a pointer. Self-referential pointees work (next: *const Node).Program.internal_abi).t27b builddoes not export them and prints a note saying so.__const, and a scalar field folds to a constant.Every refusal is precise. The cases are a missing, unknown or duplicate field, a positional initializer, an anonymous
.{}with no result type, a write through a constant, a struct or pointer operand, a non-valueX.y, a struct that contains itself, and a generic struct.IR. New
ExprKind::Seq { stmts, value }builds a struct temporary at the exact point where its argument is evaluated. Both the interpreter (the oracle) and the code generator implement it, and the random differential generator now emitsSeqwith stores and copies, with temporaries live around it.Corpus (
t27b corpus specs --jobs 6, 1185 files)specs/fpga/verification/build_verify.t27,test_module_count:t27c gen+zig testaborts on the same assertion (TOTAL_FPGA_MODULESis 33, the test expects 31). The reference fails here too, so this does not count against t27b.igla/coder/_tmp_pipeline_import.t27andigla/race/backend.t27, are rejections. At a load average near 780, the t27c front-end parse alone took 10 s and 2 s on them. Both were 0 in the feat(t27b): memory primitives -- frame slots, loads/stores, rodata, bounds (Refs #5977) #6007 run.str389, EnumDecl 104,[]const u871, f64 53, BenchBlock 48. EnumDecl and f64 belong to the scalar lane; arrays, slices and strings come next in this lane.Checks
cargo test --release -p t27b: all pass, including the newstructs_fields_pointers_and_resultsandstruct_rejections_are_precisetests, plus the differential run withSeq.cargo check --release --target x86_64-unknown-linux-gnu -p t27b --all-targets: ok. The only warnings are from the sealedbootstrap/src/compiler.rs.docs/now/2026-10-04-t27b-structs.md, whichcheck_now_entry_shape.pyaccepts.Refs #5977
🤖 Generated with Claude Code