gen-c: an array literal argument is a compound literal - #3476
Merged
Conversation
Closes #3475 A bare `{ 1, 2 }` is an INITIALISER, not an operand: C accepts it after `=` in a declaration and nowhere else. Splitting `expected expression` -- the corpus's largest class, 885 -- by the character the caret points at puts 508 of them on `{`, across 496 distinct lines. MEASURED, whole corpus, -ferror-limit=0: errors 12420 -> 12321 (-99) files better/worse 12 / 0 `expected expression` 885 -> 757 fpga_testbench_mac_tb 130 -> 86, igla_race_ternary_inference 259 -> 235 THE ELEMENT TYPE IS THE CALLEE'S, NOT THE ELEMENTS'. The cast is derived from `param_type_to_c`, so it agrees with the parameter's own declaration by construction: a parameter written `const char** acc` takes `(const char*[])`. Nothing is inferred from the literal. THE `return { ... }` HALF IS LEFT LOUD ON PURPOSE, AND THE REASON IS MEASURED: all 131 of those sites have a POINTER return type -- 131 of 131, no exceptions. A compound literal in a `return` is a block-scoped object, so the obvious widening hands back the address of a local (#3445), trading a loud syntax error for a silent dangling pointer. A test pins that limitation so the rule is not widened by someone who has not read why it is narrow. MY PRECONDITION WAS MEASURED ON THE WRONG SIDE OF THE LOWERING. I asked "is the C parameter a pointer?" and counted 170 reachable; the repair asks "is the t27 parameter a slice?", and 124 were removed. The 70 that remain reconcile exactly: 45 `[N]T`, 19 `[T]`, 6 with no declaration in any spec, 2 not arrays at all, 2 declared in another translation unit. A MUTANT THAT IGNORES THE ARGUMENT'S POSITION SURVIVED every test, because every test passed the literal FIRST -- while 63 of the 194 corpus sites pass it later. `take(7, [1,2,3])` kills it. AND THE MUTATION HARNESS REPORTED A FALSE VERDICT: an anchor that matched twice made the edit fail, and the run that followed was the UNMUTATED file, printed as `*** SURVIVED ***`. It now refuses -- `ANCHOR FAILED -- NOT A VERDICT` -- with a deliberately unmatchable anchor as the positive control. One class rose and it is unmasking, checked rather than assumed: `member reference base type 'const char *'` +14, all in igla_race_yosys, all on `sv.len()` where `sv` had no type until its declaration parsed. That file fell 133 -> 128. Neighbouring finding, filed not folded in: `[T]` is a THIRD array spelling, 220 occurrences across 43 specs and 50 element types, which the C backend reads as `[SIZE]Type` with a type where the size goes. Tests: 7 new, full suite 3522 passed 0 failed. 15 stale seals refreshed (12 specs). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gHashTag
enabled auto-merge (squash)
September 8, 2026 09:32
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
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.
gen-c: an array literal argument is a compound literal
Closes #3475
A bare
{ 1, 2 }is an INITIALISER, not an operand: C accepts it after=in a declaration and nowhere else. Splittingexpected expression-- the corpus's largest class, 885 -- by the character the caret points
at puts 508 of them on
{, across 496 distinct lines.MEASURED, whole corpus, -ferror-limit=0:
errors 12420 -> 12321 (-99)
files better/worse 12 / 0
expected expression885 -> 757fpga_testbench_mac_tb 130 -> 86, igla_race_ternary_inference 259 -> 235
THE ELEMENT TYPE IS THE CALLEE'S, NOT THE ELEMENTS'. The cast is derived
from
param_type_to_c, so it agrees with the parameter's owndeclaration by construction: a parameter written
const char** acctakes
(const char*[]). Nothing is inferred from the literal.THE
return { ... }HALF IS LEFT LOUD ON PURPOSE, AND THE REASON ISMEASURED: all 131 of those sites have a POINTER return type -- 131 of
131, no exceptions. A compound literal in a
returnis a block-scopedobject, so the obvious widening hands back the address of a local
(#3445), trading a loud syntax error for a silent dangling pointer. A
test pins that limitation so the rule is not widened by someone who has
not read why it is narrow.
MY PRECONDITION WAS MEASURED ON THE WRONG SIDE OF THE LOWERING. I asked
"is the C parameter a pointer?" and counted 170 reachable; the repair
asks "is the t27 parameter a slice?", and 124 were removed. The 70 that
remain reconcile exactly: 45
[N]T, 19[T], 6 with no declaration inany spec, 2 not arrays at all, 2 declared in another translation unit.
A MUTANT THAT IGNORES THE ARGUMENT'S POSITION SURVIVED every test,
because every test passed the literal FIRST -- while 63 of the 194
corpus sites pass it later.
take(7, [1,2,3])kills it.AND THE MUTATION HARNESS REPORTED A FALSE VERDICT: an anchor that
matched twice made the edit fail, and the run that followed was the
UNMUTATED file, printed as
*** SURVIVED ***. It now refuses --ANCHOR FAILED -- NOT A VERDICT-- with a deliberately unmatchable anchor as thepositive control.
One class rose and it is unmasking, checked rather than assumed:
member reference base type 'const char *'+14, all inigla_race_yosys, all on
sv.len()wheresvhad no type until itsdeclaration parsed. That file fell 133 -> 128.
Neighbouring finding, filed not folded in:
[T]is a THIRD arrayspelling, 220 occurrences across 43 specs and 50 element types, which
the C backend reads as
[SIZE]Typewith a type where the size goes.Tests: 7 new, full suite 3522 passed 0 failed. 15 stale seals refreshed
(12 specs).
🤖 Generated with Claude Code