Skip to content

Declare a C type's static fields beside the struct, not inside it [patch] - #224

Merged
matt-edmondson merged 2 commits into
mainfrom
fix/167-c-static-fields-in-type
Oct 14, 2026
Merged

matt-edmondson merged 2 commits into
mainfrom
fix/167-c-static-fields-in-type

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #167

What was wrong

C has no static data member, but CGenerator wrote every field of a type into the struct body without reading IsStatic. For the issue's Table:

typedef struct Table
{
    int primes[];  // constant, { 2, 3 }
    int instances;  // defaults to 0
    int count;
} Table;
  • gcc -std=c11 rejects this with flexible array member not at end of struct.
  • A static scalar compiles, but you get one copy per instance, its initial value is lost, and sizeof(Table) changes.

Change

  • GenerateClassDeclaration leaves FieldDeclaration { IsStatic: true } members out of the struct body. It writes them after the typedef, at file scope, named Type_member to match how the type's functions are named:
    typedef struct Table
    {
        int count;
    } Table;
    
    static const int Table_primes[] = { 2, 3 };
    static int Table_instances = 0;
  • The file-scope branch of GenerateFieldDeclaration moves into WriteFileScopeField(field, name, code), so both callers share the existing static / static const logic.
  • Instance IsConstant fields keep today's member-plus-note behaviour, as the issue specifies. A type whose only fields are static gets the existing placeholder member.

Tests (CStaticFieldTests)

  • StaticFields_AreDeclaredBesideTheStruct checks both file-scope declarations, and checks that the struct body holds count and neither static.
  • AnInstanceConstant_StaysAMember is a guard: int max; // constant, 9 stays in the struct.
  • StaticFields_CompileAndKeepTheirValues compiles the issue's reproduction (a static constant array before an instance field) with -std=c11 -Wall -Wextra -pedantic-errors. It then runs a driver that reads both statics, increments the counter, and checks that sizeof(Table) == sizeof(int).

With the generator change reverted, the two static-field tests fail (the guard passes either way). With the change, all three pass. Full Coder.Test suite: 1203 passed, 0 failed. Coder.sln builds clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_012VchpTHtFmwcnpAczFFgWq


Generated by Claude Code

…tch]

C has no static data member, but CGenerator wrote every field of a type
into the struct body. A static scalar became one copy per instance, lost
its initial value and changed sizeof, and a static constant table became
a flexible array member that fails to compile unless it is last.

Static fields now leave the struct and are written after the typedef at
file scope as Type_member, through the same static / static const logic
the file-scope field path already used. Instance constants keep their
member and note.

Fixes #167

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012VchpTHtFmwcnpAczFFgWq
…ds-in-type

# Conflicts:
#	Coder/Languages/CGenerator.cs
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 0c7d105 into main Oct 14, 2026
15 checks passed
@matt-edmondson
matt-edmondson deleted the fix/167-c-static-fields-in-type branch October 14, 2026 06:19
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.

C: a static field inside a type becomes a per-instance struct member, and a static constant table becomes a flexible array member that doesn't compile

2 participants