fix(selfhost/c_backend): emit _Tag + struct wrapper for all enums

Simple enums were emitted as plain C enums, but the rest of the codegen
(and source code) expected them to have a .tag field like algebraic enums.
This caused C compilation errors:
- 'request for member tag in something not a structure or union'
- 'field name not in record or union initializer'

Fix: always emit the _Tag typedef + struct wrapper for every enum.
For simple enums, the struct only contains the tag (no _Data union).
For algebraic enums, keep the existing _Data union + struct behavior.

This matches the bootstrap compiler's enum codegen.
This commit is contained in:
2026-06-08 20:00:58 +03:00
parent 2cb971a483
commit d253a01aa9
+25 -33
View File
@@ -778,44 +778,36 @@ func CBackend_Generate(mod: *HirModule) -> String {
} }
vi = vi + 1; vi = vi + 1;
} }
if !hasData { // Emit tag enum for all enums (simple and algebraic)
// Simple enum: typedef enum { A, B } Name; StringBuilder_Append(&cbe.sb, "typedef enum {\n");
StringBuilder_Append(&cbe.sb, "typedef enum {\n"); vi = 0;
vi = 0; while vi < en.variantCount {
while vi < en.variantCount { StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, " "); StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, en.name); StringBuilder_Append(&cbe.sb, "_");
StringBuilder_Append(&cbe.sb, "_"); StringBuilder_Append(&cbe.sb, en.variants[vi].name);
StringBuilder_Append(&cbe.sb, en.variants[vi].name); if vi < en.variantCount - 1 {
if vi < en.variantCount - 1 { StringBuilder_Append(&cbe.sb, ",");
StringBuilder_Append(&cbe.sb, ",");
}
StringBuilder_Append(&cbe.sb, "\n");
vi = vi + 1;
} }
StringBuilder_Append(&cbe.sb, "\n");
vi = vi + 1;
}
StringBuilder_Append(&cbe.sb, "} ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_Tag;\n\n");
if !hasData {
// Simple enum: struct wrapper with only tag
StringBuilder_Append(&cbe.sb, "typedef struct {\n");
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_Tag tag;\n");
StringBuilder_Append(&cbe.sb, "} "); StringBuilder_Append(&cbe.sb, "} ");
StringBuilder_Append(&cbe.sb, en.name); StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, ";\n\n"); StringBuilder_Append(&cbe.sb, ";\n\n");
} else { } else {
// Algebraic enum: tag enum + data union + struct // Algebraic enum: data union + struct (tag enum already emitted above)
// 1. Tag enum // 1. Data union
StringBuilder_Append(&cbe.sb, "typedef enum {\n");
vi = 0;
while vi < en.variantCount {
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_");
StringBuilder_Append(&cbe.sb, en.variants[vi].name);
if vi < en.variantCount - 1 {
StringBuilder_Append(&cbe.sb, ",");
}
StringBuilder_Append(&cbe.sb, "\n");
vi = vi + 1;
}
StringBuilder_Append(&cbe.sb, "} ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_Tag;\n\n");
// 2. Data union
StringBuilder_Append(&cbe.sb, "typedef union {\n"); StringBuilder_Append(&cbe.sb, "typedef union {\n");
vi = 0; vi = 0;
while vi < en.variantCount { while vi < en.variantCount {