Skip to content

Commit fe01b59

Browse files
authored
cgen: drop the ! of nested fixed array literals in const initializers (#28911)
1 parent f708887 commit fe01b59

2 files changed

Lines changed: 188 additions & 0 deletions

File tree

‎vlib/v/gen/c/cleanc.v‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14747,6 +14747,16 @@ fn (mut g FlatGen) const_expr_to_string(id flat.NodeId, seen []string) string {
1474714747
child := g.const_expr_to_string(g.a.child(&node, 0), seen)
1474814748
'(${child})'
1474914749
}
14750+
.postfix {
14751+
// The `!` of a nested `[...]!` fixed array literal (e.g. a struct field value
14752+
// in a const fixed array) is V syntax only; the C initializer is the literal.
14753+
if node.op == .not && node.children_count == 1
14754+
&& g.a.child_node(&node, 0).kind == .array_literal {
14755+
g.const_expr_to_string(g.a.child(&node, 0), seen)
14756+
} else {
14757+
g.expr_to_string(id)
14758+
}
14759+
}
1475014760
.cast_expr {
1475114761
target_type := g.tc.parse_type(node.value)
1475214762
mut ct := if node.value.starts_with('fn_ptr:') {
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// Regression test for https://github.com/vlang/v/issues/28900 .
2+
// The `!` of `[...]!` fixed array literals used as struct field values
3+
// must not leak into the C initializer of a const fixed array of structs.
4+
@[has_globals]
5+
module main
6+
7+
struct Foo {
8+
a [4]u8
9+
b [4]u8
10+
}
11+
12+
struct Grid {
13+
cells [2][3]int
14+
id int
15+
}
16+
17+
struct Inner {
18+
a [2]u8
19+
n int
20+
}
21+
22+
struct Outer {
23+
items [2]Inner
24+
tag int
25+
}
26+
27+
struct Named {
28+
names [2]string
29+
inner Foo
30+
}
31+
32+
fn runtime_n() int {
33+
return 5
34+
}
35+
36+
const foos = [
37+
Foo{
38+
a: [u8(0), 0, 0, 0]!
39+
b: [u8(255), 255, 255, 255]!
40+
},
41+
Foo{
42+
a: [u8(1), 2, 3, 4]!
43+
b: [u8(5), 6, 7, 8]!
44+
},
45+
]!
46+
47+
const single_foo = Foo{
48+
a: [u8(9), 8, 7, 6]!
49+
b: [u8(5), 4, 3, 2]!
50+
}
51+
52+
const dynamic_foos = [
53+
Foo{
54+
a: [u8(10), 20, 30, 40]!
55+
b: [u8(50), 60, 70, 80]!
56+
},
57+
]
58+
59+
const grids = [
60+
Grid{
61+
cells: [[1, 2, 3]!, [4, 5, 6]!]!
62+
id: 7
63+
},
64+
Grid{
65+
id: 8
66+
},
67+
]!
68+
69+
const base = u8(10)
70+
const fixed_b = [u8(7), 6, 5, 4]!
71+
72+
const foos_from_consts = [
73+
Foo{
74+
a: [base, base + 1, base * 2, base - 1]!
75+
b: fixed_b
76+
},
77+
]!
78+
79+
const outers = [
80+
Outer{
81+
items: [Inner{
82+
a: [u8(11), 12]!
83+
n: 13
84+
}, Inner{
85+
a: [u8(14), 15]!
86+
n: 16
87+
}]!
88+
tag: 1
89+
},
90+
]!
91+
92+
// Elements that need runtime initialization must not break the static ones.
93+
const mixed = [
94+
Inner{
95+
a: [u8(1), 2]!
96+
n: runtime_n()
97+
},
98+
Inner{
99+
a: [u8(3), 4]!
100+
n: 6
101+
},
102+
]!
103+
104+
const named = [
105+
Named{
106+
names: ['a', 'bc']!
107+
inner: Foo{
108+
a: [u8(31), 32, 33, 34]!
109+
b: [u8(35), 36, 37, 38]!
110+
}
111+
},
112+
]!
113+
114+
__global g_foos = [
115+
Foo{
116+
a: [u8(21), 22, 23, 24]!
117+
b: [u8(25), 26, 27, 28]!
118+
},
119+
]!
120+
121+
fn test_const_fixed_array_of_structs_with_fixed_array_fields() {
122+
assert foos.len == 2
123+
assert foos[0].a == [u8(0), 0, 0, 0]!
124+
assert foos[0].b == [u8(255), 255, 255, 255]!
125+
assert foos[1].a == [u8(1), 2, 3, 4]!
126+
assert foos[1].b == [u8(5), 6, 7, 8]!
127+
}
128+
129+
fn test_const_struct_with_fixed_array_fields() {
130+
assert single_foo.a == [u8(9), 8, 7, 6]!
131+
assert single_foo.b == [u8(5), 4, 3, 2]!
132+
}
133+
134+
fn test_const_dynamic_array_of_structs_with_fixed_array_fields() {
135+
assert dynamic_foos.len == 1
136+
assert dynamic_foos[0].a == [u8(10), 20, 30, 40]!
137+
assert dynamic_foos[0].b == [u8(50), 60, 70, 80]!
138+
}
139+
140+
fn test_const_fixed_array_of_structs_with_nested_fixed_array_fields() {
141+
assert grids[0].cells == [[1, 2, 3]!, [4, 5, 6]!]!
142+
assert grids[0].id == 7
143+
assert grids[1].cells == [[0, 0, 0]!, [0, 0, 0]!]!
144+
assert grids[1].id == 8
145+
}
146+
147+
fn test_const_fixed_array_of_structs_with_const_expr_fields() {
148+
assert foos_from_consts[0].a == [u8(10), 11, 20, 9]!
149+
assert foos_from_consts[0].b == [u8(7), 6, 5, 4]!
150+
}
151+
152+
fn test_const_fixed_array_of_structs_with_fixed_arrays_of_structs() {
153+
item0 := outers[0].items[0]
154+
item1 := outers[0].items[1]
155+
assert item0.a == [u8(11), 12]!
156+
assert item0.n == 13
157+
assert item1.a == [u8(14), 15]!
158+
assert item1.n == 16
159+
assert outers[0].tag == 1
160+
}
161+
162+
fn test_const_fixed_array_of_structs_with_runtime_and_static_elements() {
163+
assert mixed[0].a == [u8(1), 2]!
164+
assert mixed[0].n == 5
165+
assert mixed[1].a == [u8(3), 4]!
166+
assert mixed[1].n == 6
167+
}
168+
169+
fn test_const_fixed_array_of_structs_with_string_and_nested_struct_fields() {
170+
assert named[0].names == ['a', 'bc']!
171+
assert named[0].inner.a == [u8(31), 32, 33, 34]!
172+
assert named[0].inner.b == [u8(35), 36, 37, 38]!
173+
}
174+
175+
fn test_global_fixed_array_of_structs_with_fixed_array_fields() {
176+
assert g_foos[0].a == [u8(21), 22, 23, 24]!
177+
assert g_foos[0].b == [u8(25), 26, 27, 28]!
178+
}

0 commit comments

Comments
 (0)