Skip to content

Commit 6d3e79a

Browse files
committed
zeroed works with array types, with tiny cc compilation bug fixed
1 parent 830170a commit 6d3e79a

3 files changed

Lines changed: 115 additions & 6 deletions

File tree

lang/tests/common/src/main.ch

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,7 @@ public func run_common_tests() {
185185
// Generic instantiation in global variable value
186186
test_generic_in_global_var();
187187

188+
// C codegen compatibility tests (TinyCC patterns)
189+
test_tcc_codegen_compat();
190+
188191
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright (c) Chemical Language Foundation 2026.
2+
//
3+
// Tests for C codegen patterns that may fail with TinyCC.
4+
// TinyCC has limitations with certain C99/C11 features that our
5+
// C codegen may produce. These tests exercise those patterns.
6+
7+
struct TCCBox {
8+
var value : int
9+
10+
@make
11+
func make(val : int) : TCCBox {
12+
return TCCBox { value : val }
13+
}
14+
15+
@delete
16+
func delete(&mut self) {
17+
}
18+
}
19+
20+
struct TCCWrapper {
21+
var box : TCCBox
22+
var label : int
23+
24+
@make
25+
func make(v : int, l : int) : TCCWrapper {
26+
return TCCWrapper { box : TCCBox.make(v), label : l }
27+
}
28+
29+
@delete
30+
func delete(&mut self) {
31+
}
32+
}
33+
34+
func test_tcc_codegen_compat() {
35+
36+
// Test 1: zeroed on array of destructible structs
37+
// This generates ((struct TCCBox[3]){0}) — a compound literal
38+
// that TinyCC doesn't support
39+
test("zeroed array of destructible structs works", () => {
40+
var boxes : [3]TCCBox = zeroed:unsafe<[3]TCCBox>()
41+
boxes[0] = TCCBox.make(10)
42+
boxes[1] = TCCBox.make(20)
43+
boxes[2] = TCCBox.make(30)
44+
return boxes[0].value == 10 && boxes[1].value == 20 && boxes[2].value == 30
45+
})
46+
47+
// Test 2: zeroed on array of non-destructible structs
48+
// Same compound literal pattern but without destructor
49+
test("zeroed array of non-destructible structs works", () => {
50+
var values : [3]int = zeroed<[3]int>()
51+
values[0] = 10
52+
values[1] = 20
53+
values[2] = 30
54+
return values[0] == 10 && values[1] == 20 && values[2] == 30
55+
})
56+
57+
// Test 3: Nested zeroed — wrapper containing destructible field
58+
test("zeroed nested struct with destructible field works", () => {
59+
var w : TCCWrapper = zeroed:unsafe<TCCWrapper>()
60+
w.box = TCCBox.make(42)
61+
w.label = 1
62+
return w.box.value == 42 && w.label == 1
63+
})
64+
65+
// Test 4: Empty destructor bodies
66+
// The C codegen emits __chx__dstctr_clnup_blk__:{ } which TinyCC may reject
67+
test("empty destructor body compiles and runs", () => {
68+
var b = TCCBox.make(99)
69+
return b.value == 99
70+
})
71+
72+
// Test 5: Multiple destructible structs in scope (triggers multiple destructor calls)
73+
test("multiple destructible structs in scope work", () => {
74+
var b1 = TCCBox.make(1)
75+
var b2 = TCCBox.make(2)
76+
var b3 = TCCBox.make(3)
77+
return b1.value + b2.value + b3.value == 6
78+
})
79+
80+
// Test 6: Destructible struct passed to function
81+
test("destructible struct passed to function works", () => {
82+
var b = TCCBox.make(42)
83+
return accept_box(b) == 42
84+
})
85+
86+
// Test 7: Destructible struct returned from function
87+
test("destructible struct returned from function works", () => {
88+
var b = create_box(77)
89+
return b.value == 77
90+
})
91+
}
92+
93+
func accept_box(b : TCCBox) : int {
94+
return b.value
95+
}
96+
97+
func create_box(val : int) : TCCBox {
98+
return TCCBox.make(val)
99+
}

preprocess/2c/2cASTVisitor.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7825,12 +7825,19 @@ void ToCAstVisitor::VisitNullPtrType(NullPtrType* type) {
78257825
}
78267826

78277827
void ToCAstVisitor::VisitZeroedValue(ZeroedValue* value) {
7828-
write("((");
7829-
auto prev = array_types_as_subscript;
7830-
array_types_as_subscript = true;
7831-
visit(value->getType());
7832-
array_types_as_subscript = prev;
7833-
write("){0})");
7828+
auto type = value->getType();
7829+
if(type && type->kind() == BaseTypeKind::Array) {
7830+
// For C array types, use plain {0} instead of a compound literal.
7831+
// TinyCC doesn't support compound literals for array types like (struct T[N]){0}.
7832+
write("{0}");
7833+
} else {
7834+
write("(");
7835+
auto prev = array_types_as_subscript;
7836+
array_types_as_subscript = true;
7837+
visit(type);
7838+
array_types_as_subscript = prev;
7839+
write("){0}");
7840+
}
78347841
}
78357842

78367843
bool ToCBackendContext::forget(ASTNode* targetNode) {

0 commit comments

Comments
 (0)