Skip to content

Commit

Permalink
cgen: fix array fixed comparison from fn return (fix #23071) (#23114)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp authored Dec 9, 2024
1 parent 025150d commit f773416
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 11 deletions.
3 changes: 2 additions & 1 deletion vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -2302,7 +2302,8 @@ pub:
typ Type // the type of the original expression
is_ptr bool // whether the type is a pointer
pub mut:
orig Expr // the original expression, which produced the C temp variable; used by x.str()
orig Expr // the original expression, which produced the C temp variable; used by x.str()
is_fixed_ret bool // it is an array fixed returned from call
}

pub fn (node Node) pos() token.Pos {
Expand Down
8 changes: 6 additions & 2 deletions vlib/v/gen/c/auto_eq_methods.v
Original file line number Diff line number Diff line change
Expand Up @@ -426,13 +426,17 @@ fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string {
elem_info := left_typ.sym.array_fixed_info()
elem := g.unwrap(elem_info.elem_type)
size := elem_info.size
g.definitions.writeln('static bool ${ptr_styp}_arr_eq(${ptr_styp} a, ${ptr_styp} b); // auto')
mut arg_styp := ptr_styp
if elem_info.is_fn_ret {
arg_styp = ptr_styp[3..] // removes the _v_ prefix for returning fixed array
}
g.definitions.writeln('static bool ${ptr_styp}_arr_eq(${arg_styp} a, ${arg_styp} b); // auto')

left := if left_type.has_flag(.option) { 'a.data' } else { 'a' }
right := if left_type.has_flag(.option) { 'b.data' } else { 'b' }

mut fn_builder := strings.new_builder(512)
fn_builder.writeln('static inline bool ${ptr_styp}_arr_eq(${ptr_styp} a, ${ptr_styp} b) {')
fn_builder.writeln('static inline bool ${ptr_styp}_arr_eq(${arg_styp} a, ${arg_styp} b) {')
fn_builder.writeln('\tfor (int i = 0; i < ${size}; ++i) {')
// compare every pair of elements of the two fixed arrays
if elem.sym.kind == .string {
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -3598,6 +3598,9 @@ fn (mut g Gen) expr(node_ ast.Expr) {
}
ast.CTempVar {
g.write(node.name)
if node.is_fixed_ret {
g.write('.ret_arr')
}
}
ast.DumpExpr {
g.dump_expr(node)
Expand Down
22 changes: 15 additions & 7 deletions vlib/v/gen/c/ctempvars.v
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,26 @@ fn (mut g Gen) new_ctemp_var(expr ast.Expr, expr_type ast.Type) ast.CTempVar {
}

fn (mut g Gen) new_ctemp_var_then_gen(expr ast.Expr, expr_type ast.Type) ast.CTempVar {
x := g.new_ctemp_var(expr, expr_type)
g.gen_ctemp_var(x)
mut x := g.new_ctemp_var(expr, expr_type)
g.gen_ctemp_var(mut x)
return x
}

fn (mut g Gen) gen_ctemp_var(tvar ast.CTempVar) {
fn (mut g Gen) gen_ctemp_var(mut tvar ast.CTempVar) {
styp := g.styp(tvar.typ)
if g.table.final_sym(tvar.typ).kind == .array_fixed {
final_sym := g.table.final_sym(tvar.typ)
if final_sym.info is ast.ArrayFixed {
tvar.is_fixed_ret = final_sym.info.is_fn_ret
g.writeln('${styp} ${tvar.name};')
g.write('memcpy(&${tvar.name}, &')
g.expr(tvar.orig)
g.writeln(' , sizeof(${styp}));')
if tvar.is_fixed_ret {
g.write('memcpy(${tvar.name}.ret_arr, ')
g.expr(tvar.orig)
g.writeln(' , sizeof(${styp[3..]}));')
} else {
g.write('memcpy(&${tvar.name}, ')
g.expr(tvar.orig)
g.writeln(' , sizeof(${styp}));')
}
} else {
g.write('${styp} ${tvar.name} = ')
g.expr(tvar.orig)
Expand Down
21 changes: 20 additions & 1 deletion vlib/v/gen/c/infix.v
Original file line number Diff line number Diff line change
Expand Up @@ -1170,14 +1170,33 @@ fn (mut g Gen) gen_plain_infix_expr(node ast.InfixExpr) {
g.inside_interface_deref = inside_interface_deref_old
}
}
is_ctemp_fixed_ret := node.op in [.eq, .ne] && node.left is ast.CTempVar
&& node.left.is_fixed_ret
if is_ctemp_fixed_ret {
if node.op == .eq {
g.write('!')
}
g.write('memcmp(')
}
g.expr(node.left)
g.write(' ${node.op.str()} ')
if !is_ctemp_fixed_ret {
g.write(' ${node.op.str()} ')
} else {
g.write(', ')
}

if is_ctemp_fixed_ret {
g.write('(${g.styp(node.right_type)})')
}
if node.right_type.is_ptr() && node.right.is_auto_deref_var() && !node.left_type.is_pointer() {
g.write('*')
g.expr(node.right)
} else {
g.expr_with_cast(node.right, node.right_type, node.left_type)
}
if is_ctemp_fixed_ret {
g.write(', sizeof(${g.styp(node.right_type)}))')
}
if needs_cast {
g.write(')')
}
Expand Down
19 changes: 19 additions & 0 deletions vlib/v/tests/aliases/alias_fixed_array_compare_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
type Arr = [4]u8

fn (a Arr) u8_array_fixed() [4]u8 {
return a
}

fn test_main() {
a := Arr{}
b := Arr{}
assert a.u8_array_fixed() == [u8(0), 0, 0, 0]!
assert b.u8_array_fixed() == [u8(0), 0, 0, 0]!
assert a == b

a_ := a.u8_array_fixed()
b_ := b.u8_array_fixed()
assert a_ == b_

assert a.u8_array_fixed() == b.u8_array_fixed()
}

0 comments on commit f773416

Please sign in to comment.