From 864845bccde53bb452103bed937ef4285de5dc77 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sun, 17 Nov 2024 05:12:43 -0300 Subject: [PATCH] cgen: fix array fixed code generation for more than 1 dimension (fix #22866) (#22876) --- vlib/v/gen/c/cgen.v | 23 ++++++- vlib/v/gen/c/struct.v | 74 ++++++++++++++------- vlib/v/tests/fixed_array_2_dims_init_test.v | 22 ++++++ 3 files changed, 92 insertions(+), 27 deletions(-) create mode 100644 vlib/v/tests/fixed_array_2_dims_init_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index a4db565e429e6c..f01dd7358a2aa4 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2559,6 +2559,7 @@ fn (mut g Gen) expr_with_var(expr ast.Expr, got_type_raw ast.Type, expected_type g.empty_line = true tmp_var := g.new_tmp_var() styp := g.styp(expected_type) + g.writeln('${styp} ${tmp_var};') g.write('memcpy(&${tmp_var}, ') g.expr(expr) @@ -2567,6 +2568,24 @@ fn (mut g Gen) expr_with_var(expr ast.Expr, got_type_raw ast.Type, expected_type return tmp_var } +// expr_with_fixed_array generates code for fixed array initialization with expr which requires tmp var +fn (mut g Gen) expr_with_fixed_array(expr ast.ArrayInit, got_type_raw ast.Type, expected_type ast.Type) string { + stmt_str := g.go_before_last_stmt().trim_space() + g.empty_line = true + tmp_var := g.new_tmp_var() + styp := g.styp(expected_type) + g.writeln('${styp} ${tmp_var};') + // [ foo(), foo() ]! + val_typ := g.table.value_type(got_type_raw) + for i, item_expr in expr.exprs { + g.write('memcpy(${tmp_var}[${i}], ') + g.expr(item_expr) + g.writeln(', sizeof(${g.styp(val_typ)}));') + } + g.write(stmt_str) + return tmp_var +} + // use instead of expr() when you need to cast to a different type fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_type ast.Type) { got_type := ast.mktyp(got_type_raw) @@ -2620,7 +2639,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ // Do not allocate for `Interface(unsafe{nil})` casts is_nil_cast := expr is ast.UnsafeExpr && expr.expr is ast.Nil if is_nil_cast { - g.write2('/*nili*/', '((void*)0)') + g.write2('/*nil*/', '((void*)0)') return } } @@ -6901,7 +6920,7 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) { base)};') } } - } else { + } else if !(elem_sym.info is ast.ArrayFixed && elem_sym.info.is_fn_ret) { g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];') } } diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index 418e2e7b87bb93..206d7b93f048d3 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -680,33 +680,57 @@ fn (mut g Gen) struct_init_field(sfield ast.StructInitField, language ast.Langua field_unwrap_typ := g.unwrap_generic(sfield.typ) field_unwrap_sym := g.table.final_sym(field_unwrap_typ) - if field_unwrap_sym.kind == .array_fixed && sfield.expr in [ast.Ident, ast.SelectorExpr] { - info := field_unwrap_sym.info as ast.ArrayFixed - g.fixed_array_var_init(g.expr_string(sfield.expr), sfield.expr.is_auto_deref_var(), - info.elem_type, info.size) - } else if field_unwrap_sym.kind == .array_fixed && (sfield.expr is ast.CallExpr - || (sfield.expr is ast.ArrayInit && sfield.expr.has_index)) { - info := field_unwrap_sym.info as ast.ArrayFixed - tmp_var := g.expr_with_var(sfield.expr, sfield.typ, sfield.expected_type) - g.fixed_array_var_init(tmp_var, false, info.elem_type, info.size) - } else { - if field_unwrap_typ != ast.voidptr_type && field_unwrap_typ != ast.nil_type - && (sfield.expected_type.is_ptr() && !sfield.expected_type.has_flag(.shared_f)) - && !sfield.expected_type.has_flag(.option) - && !field_unwrap_typ.is_any_kind_of_pointer() && !field_unwrap_typ.is_number() { - g.write('/* autoref */&') - } - - if (sfield.expected_type.has_flag(.option) && !field_unwrap_typ.has_flag(.option)) - || (sfield.expected_type.has_flag(.result) && !field_unwrap_typ.has_flag(.result)) { - g.expr_with_opt(sfield.expr, field_unwrap_typ, sfield.expected_type) - } else if sfield.expr is ast.LambdaExpr && sfield.expected_type.has_flag(.option) { - g.expr_opt_with_cast(sfield.expr, field_unwrap_typ, sfield.expected_type) - } else { - g.left_is_opt = true - g.expr_with_cast(sfield.expr, field_unwrap_typ, sfield.expected_type) + is_auto_deref_var := sfield.expr.is_auto_deref_var() + if field_unwrap_sym.info is ast.ArrayFixed { + match sfield.expr { + ast.Ident, ast.SelectorExpr { + g.fixed_array_var_init(g.expr_string(sfield.expr), is_auto_deref_var, + field_unwrap_sym.info.elem_type, field_unwrap_sym.info.size) + } + ast.CallExpr { + tmp_var := g.expr_with_var(sfield.expr, sfield.typ, sfield.expected_type) + g.fixed_array_var_init(tmp_var, false, field_unwrap_sym.info.elem_type, + field_unwrap_sym.info.size) + } + ast.ArrayInit { + if sfield.expr.has_index { + tmp_var := g.expr_with_var(sfield.expr, sfield.typ, sfield.expected_type) + g.fixed_array_var_init(tmp_var, false, field_unwrap_sym.info.elem_type, + field_unwrap_sym.info.size) + } else if sfield.expr.exprs.len > 0 && sfield.expr.exprs.any(it is ast.CallExpr) { + tmp_var := g.expr_with_fixed_array(sfield.expr, sfield.typ, sfield.expected_type) + g.fixed_array_var_init(tmp_var, false, field_unwrap_sym.info.elem_type, + field_unwrap_sym.info.size) + } else { + g.struct_init_field_default(field_unwrap_typ, sfield) + } + } + else { + g.struct_init_field_default(field_unwrap_typ, sfield) + } } + } else { + g.struct_init_field_default(field_unwrap_typ, sfield) } g.inside_cast_in_heap = inside_cast_in_heap // restore value for further struct inits } } + +fn (mut g Gen) struct_init_field_default(field_unwrap_typ ast.Type, sfield &ast.StructInitField) { + if field_unwrap_typ != ast.voidptr_type && field_unwrap_typ != ast.nil_type + && (sfield.expected_type.is_ptr() && !sfield.expected_type.has_flag(.shared_f)) + && !sfield.expected_type.has_flag(.option) && !field_unwrap_typ.is_any_kind_of_pointer() + && !field_unwrap_typ.is_number() { + g.write('/* autoref */&') + } + + if (sfield.expected_type.has_flag(.option) && !field_unwrap_typ.has_flag(.option)) + || (sfield.expected_type.has_flag(.result) && !field_unwrap_typ.has_flag(.result)) { + g.expr_with_opt(sfield.expr, field_unwrap_typ, sfield.expected_type) + } else if sfield.expr is ast.LambdaExpr && sfield.expected_type.has_flag(.option) { + g.expr_opt_with_cast(sfield.expr, field_unwrap_typ, sfield.expected_type) + } else { + g.left_is_opt = true + g.expr_with_cast(sfield.expr, field_unwrap_typ, sfield.expected_type) + } +} diff --git a/vlib/v/tests/fixed_array_2_dims_init_test.v b/vlib/v/tests/fixed_array_2_dims_init_test.v new file mode 100644 index 00000000000000..919e57cdf002ab --- /dev/null +++ b/vlib/v/tests/fixed_array_2_dims_init_test.v @@ -0,0 +1,22 @@ +module main + +struct Uniforms { + lights [2][4]f32 +} + +fn r() [4]f32 { + return [f32(1.1), 1.2, 1.3, 1.4]! +} + +fn test_main() { + v := Uniforms{ + lights: [ + r(), + r(), + ]! + } + assert v.lights[0][0] == f32(1.1) + assert v.lights[0][1] == f32(1.2) + assert v.lights[0][2] == f32(1.3) + assert v.lights[0][3] == f32(1.4) +}