gen-c, gen: a module-level var is mutable (Refs #2161) - #2730
Merged
Conversation
The parser records mutability in `extra_mutable`, and both backends
already branch on it for function LOCALS -- Zig `var` vs `const`, Rust
`let mut` vs `let`. The module-level paths never read it, so a `var` at
module scope was emitted as a constant:
gen-c #define counter 0 -> `counter = counter + 1` becomes
`0 = (0 + 1)`, which is not C
gen const counter: u32 -> Zig refuses the assignment
gen-verilog reg [31:0] counter correct all along
gen-c now emits `static <type> <name> = <init>;` for a mutable
module-level declaration and keeps `#define` / `static const` for real
constants. Zig writes `var` instead of `const`.
Measured over the 42 specs whose C output this changes:
C compile errors (cc -fsyntax-only -std=c11) 537 -> 277
specs whose generated C is clean 0 -> 19
specs/fpga/bpsk.t27 -- the BPSK modem merged in #1250 -- goes 7 errors to
0. A probe spec compiles and RUNS: two calls to a function that
increments a module-level counter print `1 2`.
Immutable constants are untouched: `const K: u32 = 7` still emits
`#define K 7`.
gen-rust is NOT fixed here, and the reason is a language question rather
than an oversight. Rust has no safe module-level mutable: `static mut`
needs `unsafe` at every access, `AtomicU32` changes the access API to
load/store, and `thread_local!` changes the semantics. All three alter
the generated interface, so which one t27 means belongs to whoever owns
the datapath. Measured first: all 43 of these specs already produce Rust
that does not compile, for reasons beyond this one, so nothing regresses
by leaving it.
Parse count unchanged at 620/746; t27c tests unchanged at 1629 passed /
6 failed.
FROZEN_HASH resealed in the same commit (M5).
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
PR DashboardGenerated at: 2026-08-27 17:32:09 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.
The parser records mutability in
extra_mutable, and both backends already branch on it for function locals — Zigvar/const, Rustlet mut/let. The module-level paths never read it.gen-cnow emitsstatic <type> <name> = <init>;for a mutable module-level declaration and keeps#define/static constfor real constants. Zig writesvar.Measured over the 42 specs whose C output this changes
cc -fsyntax-only -std=c11)specs/fpga/bpsk.t27— the BPSK modem merged in #1250 — goes 7 errors to 0.A probe spec compiles and runs: two calls to a function that increments a module-level counter print
1 2.Immutable constants are untouched:
const K: u32 = 7still emits#define K 7.gen-rustis deliberately not fixed hereRust has no safe module-level mutable, and the three candidate lowerings each change the generated interface:
static mut— needsunsafeat every access siteAtomicU32— turns every read and write intoload/storethread_local!— changes the semanticsWhich one t27 means is a datapath decision, not an oversight, so it belongs to whoever owns it. Measured before deciding: all 43 of these specs already produce Rust that does not compile, for reasons beyond this one, so nothing regresses by leaving it. Filed separately.
No regressions
Parse count unchanged at 620/746; t27c tests unchanged at 1629 passed / 6 failed; RATCHET: CLEAN; width baseline 2 known, 0 new.
Refs #2161