Skip to content

Commit d8abccb

Browse files
authored
checker, cgen: fix fixed array struct initialization (#27959)
1 parent bdaf88c commit d8abccb

7 files changed

Lines changed: 75 additions & 5 deletions

vlib/v/checker/struct.v

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,10 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
11561156
c.mark_as_referenced(mut &init_field.expr, true)
11571157
}
11581158
}
1159+
} else if c.table.final_sym(exp_type).kind == .array_fixed && got_type.is_ptr()
1160+
&& !exp_type.is_any_kind_of_pointer() && !init_field.expr.is_auto_deref_var() {
1161+
c.error('cannot assign to field `${field_info.name}`: ${c.expected_msg(got_type,
1162+
exp_type)}', init_field.pos)
11591163
} else if got_type != ast.void_type && got_type_sym.kind != .placeholder
11601164
&& !exp_type.has_flag(.generic) {
11611165
mut needs_sum_type_cast := false
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/checker/tests/struct_field_init_ref_to_fixed_array_alias_err.vv:14:3: error: cannot assign to field `arr`: expected `Arr`, not `&Arr`
2+
12 | original := Original{}
3+
13 | _ := Copy{
4+
14 | arr: &original.arr
5+
| ~~~~~~
6+
15 | }
7+
16 | }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
type Arr = [8]u8
2+
3+
struct Original {
4+
arr Arr
5+
}
6+
7+
struct Copy {
8+
arr Arr
9+
}
10+
11+
fn main() {
12+
original := Original{}
13+
_ := Copy{
14+
arr: &original.arr
15+
}
16+
}

vlib/v/gen/c/struct.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
524524
}
525525

526526
if !initialized && !is_generic_default {
527-
if nr_fields > 0 {
527+
if nr_fields > 0 && !sym.is_empty_struct_array() {
528528
g.write('0')
529529
} else {
530530
g.write('E_STRUCT')

vlib/v/tests/aliases/alias_fixed_array_of_struct_test.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ fn test_fixed_array_alias_of_empty_struct() {
4040
assert nested[0].len == 2
4141
}
4242

43+
fn test_direct_fixed_array_alias_of_empty_struct_init() {
44+
fixed := EmptyFixed{}
45+
assert fixed.len == 2
46+
}
47+
4348
fn test_nested_fixed_array_alias_in_struct_init() {
4449
v_box := Box{}
4550
assert v_box.len == 2

vlib/v3/tests/fixed_array_local_zero_init_codegen_test.v

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ fn test_local_fixed_array_zero_init_declarations_use_direct_c_arrays() {
2222
2323
type Handle = voidptr
2424
25+
struct Empty {}
26+
27+
type EmptyFixed = [2]Empty
28+
2529
fn local_score() int {
2630
mut direct := [4]int{}
2731
direct[0] = 1
@@ -31,8 +35,9 @@ fn local_score() int {
3135
handles[0] = voidptr(0)
3236
mut nested := unsafe { [2][3]int{} }
3337
nested[1][2] = 3
38+
empty := EmptyFixed{}
3439
handle_score := if handles[0] == voidptr(0) { 4 } else { 0 }
35-
return direct[0] + wrapped[1] + nested[1][2] + handle_score
40+
return direct[0] + wrapped[1] + nested[1][2] + empty.len + handle_score
3641
}
3742
3843
fn main() {
@@ -46,7 +51,7 @@ fn main() {
4651
assert compile.exit_code == 0, compile.output
4752
run := os.execute(bin)
4853
assert run.exit_code == 0, run.output
49-
assert run.output.trim_space() == '10'
54+
assert run.output.trim_space() == '12'
5055
generated := os.read_file(bin + '.c') or { panic(err) }
5156
compact := generated.replace('\t', '').replace(' ', '').replace('\n', '')
5257
assert compact.contains('intdirect[4]={0};')
@@ -61,3 +66,32 @@ fn main() {
6166
assert !generated.contains(' = (Array_fixed_'), generated
6267
assert !generated.contains('Array_fixed_voidptr_32 handles'), generated
6368
}
69+
70+
fn test_struct_field_rejects_pointer_to_fixed_array_alias() {
71+
v3_bin := local_fixed_array_build_v3()
72+
src := os.join_path(os.temp_dir(), 'v3_fixed_array_struct_field_${os.getpid()}.v')
73+
os.write_file(src, 'module main
74+
75+
type Arr = [2]int
76+
77+
struct Foo {
78+
arr Arr
79+
}
80+
81+
fn main() {
82+
a := Arr{}
83+
foo := Foo{
84+
arr: &a
85+
}
86+
println(foo.arr.len)
87+
}
88+
') or {
89+
panic(err)
90+
}
91+
bin := os.join_path(os.temp_dir(), 'v3_fixed_array_struct_field_${os.getpid()}')
92+
compile := os.execute('${v3_bin} -nocache ${src} -b c -o ${bin}')
93+
assert compile.exit_code != 0, compile.output
94+
assert compile.output.contains('cannot initialize field `arr` with `&Arr`; expected `Arr`'), compile.output
95+
96+
assert !compile.output.contains('C compilation failed'), compile.output
97+
}

vlib/v3/types/checker.v

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22460,9 +22460,13 @@ fn (mut tc TypeChecker) check_struct_init(id flat.NodeId, node flat.Node) {
2246022460
actual = semantic_mut_param
2246122461
}
2246222462
}
22463-
if !tc.expr_compatible(value_id, actual, expected)
22463+
pointer_to_value_fixed_array := actual is Pointer
22464+
&& unalias_type(actual.base_type) is ArrayFixed
22465+
&& unalias_type(expected) is ArrayFixed
22466+
if pointer_to_value_fixed_array
22467+
|| (!tc.expr_compatible(value_id, actual, expected)
2246422468
&& !tc.method_value_matches_voidptr_callback(value_id, actual, expected)
22465-
&& !tc.pointer_value_compatible(actual, expected) {
22469+
&& !tc.pointer_value_compatible(actual, expected)) {
2246622470
tc.type_mismatch(.assignment_mismatch,
2246722471
'cannot initialize field `${field.value}` with `${actual.name()}`; expected `${expected.name()}`',
2246822472
field_id)

0 commit comments

Comments
 (0)