From 839a409dd0e4e9481ad286689437467c954f5838 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 5 Jun 2026 04:02:32 +0300 Subject: [PATCH] cgen: fix heap struct init hoist positions (#27349) --- vlib/v/gen/c/struct.v | 13 ++-- .../heap_struct_init_order.c.must_have | 8 +++ .../gen/c/testdata/heap_struct_init_order.out | 1 + .../gen/c/testdata/heap_struct_init_order.vv | 68 +++++++++++++++++++ 4 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 vlib/v/gen/c/testdata/heap_struct_init_order.c.must_have create mode 100644 vlib/v/gen/c/testdata/heap_struct_init_order.out create mode 100644 vlib/v/gen/c/testdata/heap_struct_init_order.vv diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index e63386407..9a45d0926 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -555,7 +555,8 @@ fn (mut g Gen) struct_init(node ast.StructInit) { fn (mut g Gen) can_use_direct_heap_struct_init(node ast.StructInit, sym ast.TypeSymbol, aligned int, const_msvc_init bool) bool { if g.is_shared || g.inside_cast_in_heap > 0 || g.inside_cinit || g.inside_const || g.inside_global_decl || aligned != 0 || const_msvc_init || node.typ.has_flag(.option) - || node.has_update_expr || sym.kind != .struct { + || node.has_update_expr || sym.kind != .struct || g.cur_fn == unsafe { nil } + || g.stmt_path_pos.len <= g.inside_ternary { return false } if sym.info !is ast.Struct { @@ -579,11 +580,8 @@ fn (mut g Gen) can_use_direct_heap_struct_init(node ast.StructInit, sym ast.Type } fn (mut g Gen) direct_heap_struct_init(node ast.StructInit, styp string, info ast.Struct, language ast.Language) { - stmt_str := if g.inside_ternary > 0 { - g.go_before_ternary().trim_space() - } else { - g.go_before_last_stmt().trim_space() - } + stmt_pos_idx := g.stmt_path_pos.len - (1 + g.inside_ternary) + stmt_str := g.out.cut_to(g.stmt_path_pos[stmt_pos_idx]).trim_space() g.empty_line = true tmp_var := g.new_tmp_var() if info.is_empty_struct() { @@ -631,7 +629,8 @@ fn (mut g Gen) direct_heap_struct_init(node ast.StructInit, styp string, info as g.struct_init_ptr_field(tmp_var, resolved_field, language) g.writeln(';') } - g.set_current_pos_as_last_stmt_pos() + // Keep the cut position current without leaving stale entries for later hoists. + g.stmt_path_pos[stmt_pos_idx] = g.out.len g.write2(stmt_str, ' ') g.write(tmp_var) } diff --git a/vlib/v/gen/c/testdata/heap_struct_init_order.c.must_have b/vlib/v/gen/c/testdata/heap_struct_init_order.c.must_have new file mode 100644 index 000000000..58b5d4470 --- /dev/null +++ b/vlib/v/gen/c/testdata/heap_struct_init_order.c.must_have @@ -0,0 +1,8 @@ +builtin___v_malloc(sizeof(main__Issue27329Object) == 0 ? 1 : sizeof(main__Issue27329Object)); +->kind = _const_main__issue_27329_kind_false; +->kind = _const_main__issue_27329_kind_true; +->kind = _const_main__issue_27329_kind_len; +volatile main__Issue27329Object* +return builtin__new_array_from_c_array(3, 3, sizeof(main__Issue27329Object*) +->child = _t +// THE END. diff --git a/vlib/v/gen/c/testdata/heap_struct_init_order.out b/vlib/v/gen/c/testdata/heap_struct_init_order.out new file mode 100644 index 000000000..9766475a4 --- /dev/null +++ b/vlib/v/gen/c/testdata/heap_struct_init_order.out @@ -0,0 +1 @@ +ok diff --git a/vlib/v/gen/c/testdata/heap_struct_init_order.vv b/vlib/v/gen/c/testdata/heap_struct_init_order.vv new file mode 100644 index 000000000..18e02040b --- /dev/null +++ b/vlib/v/gen/c/testdata/heap_struct_init_order.vv @@ -0,0 +1,68 @@ +const issue_27329_kind_false = 0 +const issue_27329_kind_true = 1 +const issue_27329_kind_len = 2 + +struct Issue27329Object { + kind int + ival int + len_val int + child &Issue27329Object +} + +fn (obj &Issue27329Object) truthy() bool { + return if obj.kind == issue_27329_kind_true { + true + } else if obj.kind == issue_27329_kind_len { + obj.len_val > 0 + } else { + false + } +} + +fn issue_27329_objects() []&Issue27329Object { + return [ + &Issue27329Object{ + kind: issue_27329_kind_false + ival: 0 + len_val: 0 + child: unsafe { nil } + }, + &Issue27329Object{ + kind: issue_27329_kind_true + ival: 1 + len_val: 0 + child: unsafe { nil } + }, + &Issue27329Object{ + kind: issue_27329_kind_len + ival: 2 + len_val: 3 + child: unsafe { nil } + }, + ] +} + +fn issue_27329_nested() &Issue27329Object { + return &Issue27329Object{ + kind: issue_27329_kind_len + ival: 7 + len_val: 1 + child: &Issue27329Object{ + kind: issue_27329_kind_false + ival: 8 + len_val: 0 + child: unsafe { nil } + } + } +} + +fn main() { + objects := issue_27329_objects() + nested := issue_27329_nested() + assert !objects[0].truthy() + assert objects[1].truthy() + assert objects[2].truthy() + assert nested.truthy() + assert !nested.child.truthy() + println('ok') +} -- 2.39.5