From aca535806145daf57e91a69e9c2049cf11fc6e6e Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Mon, 18 Nov 2024 14:37:59 -0300 Subject: [PATCH] cgen: fix codegen for returning a fixed array as a result (fix #22894) (#22896) --- vlib/v/gen/c/cgen.v | 65 ++++++++++--------- .../fns/fixed_array_result_return_test.v | 40 ++++++++++++ 2 files changed, 75 insertions(+), 30 deletions(-) create mode 100644 vlib/v/tests/fns/fixed_array_result_return_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index d5c90c9f6b..9147393314 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -5527,7 +5527,9 @@ fn (mut g Gen) return_stmt(node ast.Return) { fn_return_is_multi := sym.kind == .multi_return fn_return_is_option := fn_ret_type.has_flag(.option) fn_return_is_result := fn_ret_type.has_flag(.result) - fn_return_is_fixed_array := sym.is_array_fixed() && !fn_ret_type.has_option_or_result() + fn_return_is_fixed_array := sym.is_array_fixed() + fn_return_is_fixed_array_non_result := fn_return_is_fixed_array + && !fn_ret_type.has_option_or_result() mut has_semicolon := false if node.exprs.len == 0 { @@ -5573,7 +5575,7 @@ fn (mut g Gen) return_stmt(node ast.Return) { mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0 || g.cur_lock.lockeds.len > 0 || (fn_return_is_multi && node.exprs.len >= 1 && fn_return_is_option) - || fn_return_is_fixed_array + || fn_return_is_fixed_array_non_result || (fn_return_is_multi && node.types.any(g.table.final_sym(it).kind == .array_fixed)) // handle promoting none/error/function returning _option' if fn_return_is_option { @@ -5788,17 +5790,12 @@ fn (mut g Gen) return_stmt(node ast.Return) { g.write('*') } } - for i, expr in node.exprs { - if return_sym.kind == .array_fixed && expr !is ast.ArrayInit { - info := return_sym.info as ast.ArrayFixed - g.fixed_array_var_init(g.expr_string(expr), expr.is_auto_deref_var(), - info.elem_type, info.size) - } else { - g.expr_with_cast(expr, node.types[i], fn_ret_type.clear_option_and_result()) - } - if i < node.exprs.len - 1 { - g.write(', ') - } + if return_sym.kind == .array_fixed && expr0 !is ast.ArrayInit { + info := return_sym.info as ast.ArrayFixed + g.fixed_array_var_init(g.expr_string(expr0), expr0.is_auto_deref_var(), + info.elem_type, info.size) + } else { + g.expr_with_cast(expr0, node.types[0], fn_ret_type.clear_option_and_result()) } g.writeln(' }, (${option_name}*)(&${tmpvar}), sizeof(${styp}));') g.write_defer_stmts_when_needed() @@ -5815,29 +5812,37 @@ fn (mut g Gen) return_stmt(node ast.Return) { } } if fn_return_is_result && !expr_type_is_result && return_sym.name != result_name { - styp := g.base_type(fn_ret_type) - g.writeln('${ret_typ} ${tmpvar};') - g.write('_result_ok(&(${styp}[]) { ') - if !fn_ret_type.is_ptr() && node.types[0].is_ptr() { - if !((node.exprs[0] is ast.Ident && !g.is_amp) || sym.kind == .interface) { - g.write('*') + g.writeln('${ret_typ} ${tmpvar} = {0};') + if fn_return_is_fixed_array && expr0 !is ast.ArrayInit + && g.table.final_sym(node.types[0]).kind == .array_fixed { + styp := g.styp(fn_ret_type.clear_option_and_result()) + g.write('memcpy(${tmpvar}.data, ') + if expr0 in [ast.CallExpr, ast.StructInit] { + g.expr_with_opt(expr0, node.types[0], fn_ret_type) + g.write('.data') + } else { + g.expr(expr0) + } + g.writeln(', sizeof(${styp}));') + } else { + styp := g.base_type(fn_ret_type) + g.write('_result_ok(&(${styp}[]) { ') + if !fn_ret_type.is_ptr() && node.types[0].is_ptr() { + if !((node.exprs[0] is ast.Ident && !g.is_amp) || sym.kind == .interface) { + g.write('*') + } } - } - for i, expr in node.exprs { if fn_ret_type.has_flag(.option) { - g.expr_with_opt(expr, node.types[i], fn_ret_type.clear_flag(.result)) - } else if return_sym.kind == .array_fixed && expr !is ast.ArrayInit { + g.expr_with_opt(expr0, node.types[0], fn_ret_type.clear_flag(.result)) + } else if return_sym.kind == .array_fixed && expr0 !is ast.ArrayInit { info := return_sym.info as ast.ArrayFixed - g.fixed_array_var_init(g.expr_string(expr), expr.is_auto_deref_var(), + g.fixed_array_var_init(g.expr_string(expr0), expr0.is_auto_deref_var(), info.elem_type, info.size) } else { - g.expr_with_cast(expr, node.types[i], fn_ret_type.clear_flag(.result)) - } - if i < node.exprs.len - 1 { - g.write(', ') + g.expr_with_cast(expr0, node.types[0], fn_ret_type.clear_flag(.result)) } + g.writeln(' }, (${result_name}*)(&${tmpvar}), sizeof(${styp}));') } - g.writeln(' }, (${result_name}*)(&${tmpvar}), sizeof(${styp}));') g.write_defer_stmts_when_needed() g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true) g.writeln('return ${tmpvar};') @@ -7180,7 +7185,7 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast mut is_array_fixed := false mut return_wrapped := false if is_option { - is_array_fixed = expr_stmt.expr is ast.ArrayInit + is_array_fixed = expr_stmt.expr in [ast.ArrayInit, ast.CastExpr] && g.table.final_sym(return_type).kind == .array_fixed if !is_array_fixed { if g.inside_return && !g.inside_struct_init diff --git a/vlib/v/tests/fns/fixed_array_result_return_test.v b/vlib/v/tests/fns/fixed_array_result_return_test.v new file mode 100644 index 0000000000..8e0e36c277 --- /dev/null +++ b/vlib/v/tests/fns/fixed_array_result_return_test.v @@ -0,0 +1,40 @@ +module main + +type Foo = [4]u8 + +fn Foo.new(el []u8) !Foo { + if el.len != 4 { + return error('el must have 4 members') + } + mut bytes := [4]u8{} + for i := 0; i < 4; i++ { + bytes[i] = el[i] + } + return Foo(bytes) +} + +fn Foo.new_no_err(el []u8) Foo { + mut bytes := [4]u8{} + for i := 0; i < 4; i++ { + bytes[i] = el[i] + } + return Foo(bytes) +} + +fn (f Foo) str() string { + return '${f[0]}, ${f[1]}, ${f[2]}, ${f[3]}' +} + +fn test_main() { + a := Foo.new_no_err([u8(5), 4, 3, 2]) + println(a) + assert a == [u8(5), 4, 3, 2]! + + b := Foo.new([u8(1), 2, 3, 4])! + println(b) + assert b == [u8(1), 2, 3, 4]! + + c := Foo.new([u8(1), 2, 3, 4]) or { Foo([u8(0), 0, 0, 0]!) } + println(c) + assert c == [u8(1), 2, 3, 4]! +}