cgen: fix codegen for returning a fixed array as a result (fix #22894) (#22896)

This commit is contained in:
Felipe Pena 2024-11-18 14:37:59 -03:00 committed by GitHub
parent 61e38b9bf1
commit aca5358061
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 75 additions and 30 deletions

View File

@ -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

View File

@ -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]!
}