Skip to content

gen-c: lower the element type of a local array - #3449

Merged
gHashTag merged 1 commit into
masterfrom
parity/local-position
Sep 8, 2026
Merged

gen-c: lower the element type of a local array#3449
gHashTag merged 1 commit into
masterfrom
parity/local-position

Conversation

@gHashTag

@gHashTag gHashTag commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Closes #3448

var x : [4]GF16;
GF16 x[4];
error: use of undeclared identifier 'GF16'

The same element is lowered everywhere else:

position emitted
parameter uint16_t a[static 4]
struct field uint16_t f[4];
local GF16 x[4];

W583, in a position its own repair never reached

The local path gated on is_primitive. Two hundred lines below, on
param_type_to_c, sits the note retiring exactly that gate:

W583: this used to be gated on is_primitive, which lists only the integer
scalars — so f32, f64, str, string and gf16 took the pass-through
arm and reached C unmapped even after type_to_c learned them.

Same sentence, same file, other position. Two more defects live in the same
eight lines: var x : []u8; emitted uint8_t x[]; (not a definition), and
var x : []const u8; emitted const u8* x (the qualifier lives inside the
element text).

The first slice repair was wrong, and the corpus said so

Rewriting every []T local to a pointer broke T x[] = { … }, which is
legal C and takes its size from the initialiser list: +5 errors, nothing
better
, in the one file carrying the shape. The condition
size.is_empty() && node.children.is_empty() is that measurement kept as code,
and a test holds it.

Every error total I published this session was a floor

This is the finding worth more than the fix.

Clang's default -ferror-limit=20 was censoring the aggregate. 141 files
reach the limit. The corpus emits 15133 errors, not the 3849 I have been
reporting.

before after
this change 15133 15126
#3447, re-measured 15188 15133 — published as 3849 → 3825

The per-file splits were sound — they were counted per file — and the
directions and conclusions stand. The magnitudes were understated.

It surfaced only because a repair that removes real errors showed a zero
delta: three files sitting at exactly 20 before and after.

Three files improve here: math/property_test_template 46→43, nn/hslm 79→76,
numeric/gf16 151→150. Zero files worse.

The tool

tools/backend_parity_table.py gains the fourth position. Its first probe
there measured the wrong thing: var x : T; with no initialiser is declared by
C and Rust and emitted by neither Zig nor Verilog, so the table was reading
their dead-code removal rather than their lowering. Initialising from a
parameter of the same type fixed it; the self-check now covers all four
positions.

Mutation

mutant dead tests
is_primitive gate restored 2
initialiser condition dropped 1
const strip removed 1
slice back to an incomplete array 2

Full suite: 2615 passed, 0 failed. 14 seals refreshed in the same commit.

Closes #3448

    var x : [4]GF16;   ->   GF16 x[4];
                            error: use of undeclared identifier 'GF16'

The same element is `uint16_t` in a parameter (`uint16_t a[static 4]`) and in
a struct field (`uint16_t f[4];`). Only the local path passed the t27 text
through, because it gated on `is_primitive` -- and the note retiring that very
gate sits two hundred lines below, on `param_type_to_c`:

    W583: this used to be gated on `is_primitive`, which lists only the
    integer scalars -- so `f32`, `f64`, `str`, `string` and `gf16` took the
    pass-through arm and reached C unmapped even after `type_to_c` learned
    them.

Same sentence, same file, other position.

Two more defects live in the same eight lines. `var x : []u8;` emitted
`uint8_t x[];`, which is not a definition; and `var x : []const u8;` emitted
`const u8* x`, because the qualifier lives INSIDE the element text and this
path did not strip it.

The first slice repair was wrong, and the corpus said so: rewriting every
`[]T` local to a pointer broke `T x[] = { ... }`, which is legal C and takes
its size from the initialiser list. +5 errors, nothing better, in the one file
carrying the shape. `size.is_empty() && node.children.is_empty()` is that
measurement kept as code.

MEASURED, and this is the part that matters beyond this commit.

CLANG'S DEFAULT -ferror-limit=20 HAS BEEN CENSORING EVERY TOTAL I HAVE
PUBLISHED THIS SESSION. 141 files reach the limit. The corpus emits 15133
errors, not the 3849 reported. The per-file splits were sound, because they
were counted per file; the totals were floors.

    this change      15133 -> 15126   3 files better, 0 worse
    #3447, re-measured   15188 -> 15133   published as 3849 -> 3825

The direction and the per-file conclusions stand; the magnitudes were
understated. It surfaced because a repair that removes real errors showed a
ZERO delta -- three files sitting at exactly 20 before and after.

tools/backend_parity_table.py gains the fourth position. Its first probe there
measured the wrong thing: `var x : T;` with no initialiser is declared by C and
Rust and emitted by NEITHER Zig nor Verilog, so the table was reading their
dead-code removal. Initialising from a parameter of the same type fixed it, and
the self-check now covers all four positions.

Four mutants, four dead. 14 seals refreshed in the same commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gHashTag
gHashTag enabled auto-merge (squash) September 8, 2026 02:03
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@gHashTag
gHashTag merged commit 1223968 into master Sep 8, 2026
29 of 33 checks passed
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-09-08 02:03:57 UTC

Summary

Status Count
Total Open PRs 16
PRs with Failing Checks 14
PRs with All Checks Green 2
READY 2
FAILING 14
PENDING 0
NO CHECKS YET 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=911a664330ef != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

gHashTag added a commit that referenced this pull request Sep 8, 2026
Closes #3450
Refs #3448

One instrument had been censoring its own totals -- clang's default
`-ferror-limit=20`, which made every C error count published for this
repository a floor. The obvious next question is whether the others do the
same, and nobody had asked.

Planting 50 known errors per language:

    clang (default)            20   TRUNCATES
    clang (-ferror-limit=0)    50   complete
    rustc                      50   complete
    zig                        50   complete
    iverilog                   50   complete (TWO diagnostic lines per error)
    yosys                       1   ABORTS on the first error

yosys is not capped, it stops. An error COUNT from it is 0 or 1 and means
nothing; only its pass/fail is a measurement.

THE FIXTURES WERE THE HARD PART, and two of the five were wrong in ways that
read as findings about the compiler rather than about me:

  * the Zig fixture named its functions `f16` and `f32`, which SHADOW ZIG
    PRIMITIVES, so it failed with 2 errors of a different kind before reaching
    the undefined names -- indistinguishable from a cap;
  * the Verilog fixture used implicitly declared identifiers, which yosys
    treats as a WARNING, so it reported zero -- indistinguishable from silence.

`--self-check` therefore requires each fixture to produce the expected KIND of
diagnostic before its count is believed.

WHAT IS NOT AFFECTED, measured rather than hoped:

  * acceptance counts. Clang's exit code is 1 with and without the limit on a
    failing file, and 0 on a clean one, so a count of FILES that compile cannot
    be censored by a per-file cap. Every `cc accepts N` figure stands.
  * the repository's gates. The only tool invoking `cc` is
    check_duplicate_agreement.py, and it reads `returncode`.
  * the Rust totals, since rustc reports completely.

What was wrong is exactly the C error totals in my own reports: 3849 was
15188, 3825 was 15133, and after #3449 it is 15126.

The tool DEGRADES rather than lying. A runner without zig or yosys checks the
compilers it has and NAMES what it skipped; only a run with nothing available
exits 2. That matters because the CI runner carries neither, and a gate that
cannot run must say so rather than fail forever.

Four controls: a planted truncation reddens it, a one-compiler PATH passes
while naming four skips, an empty PATH exits 2, and a fixture that stops
producing its error fails the self-check.

Wired into Spec Guards, under a second.

Co-authored-by: lab <lab@example.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gen-c: the element type of a LOCAL array is passed through unmapped (W583, second position)

1 participant