From 7dd91ecef7a80b12a9e175f14a3e40b150949a06 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 23 Aug 2025 16:57:30 -0300 Subject: [PATCH] cgen: fix assigning fn address (fix #24537) (#25158) --- vlib/v/gen/c/assign.v | 14 +++++++++++--- vlib/v/gen/c/cgen.v | 7 ++++--- vlib/v/gen/c/testdata/assign_fn_addr.c.must_have | 2 ++ vlib/v/gen/c/testdata/assign_fn_addr.out | 3 +++ vlib/v/gen/c/testdata/assign_fn_addr.vv | 12 ++++++++++++ 5 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 vlib/v/gen/c/testdata/assign_fn_addr.c.must_have create mode 100644 vlib/v/gen/c/testdata/assign_fn_addr.out create mode 100644 vlib/v/gen/c/testdata/assign_fn_addr.vv diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 685ccd4f78..9f5d7f94e6 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -289,6 +289,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { for i, mut left in node.left { mut is_auto_heap := false + mut is_fn_var := false mut var_type := node.left_types[i] mut val_type := node.right_types[i] val := node.right[i] @@ -432,6 +433,9 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } } is_auto_heap = left.obj.is_auto_heap + if left.obj.typ != 0 && val is ast.PrefixExpr { + is_fn_var = g.table.final_sym(left.obj.typ).kind == .function + } } } else if mut left is ast.ComptimeSelector { if left.typ_key != '' { @@ -964,14 +968,14 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } else { is_option_unwrapped := val is ast.Ident && val.or_expr.kind != .absent is_option_auto_heap := is_auto_heap && is_option_unwrapped - if is_auto_heap { + if is_auto_heap && !is_fn_var { if aligned != 0 { g.write('HEAP_align(${styp}, (') } else { g.write('HEAP(${styp}, (') } } - if val.is_auto_deref_var() && !is_option_unwrapped { + if !is_fn_var && val.is_auto_deref_var() && !is_option_unwrapped { g.write('*') } if (var_type.has_flag(.option) && val !in [ast.Ident, ast.SelectorExpr]) @@ -997,9 +1001,13 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { g.fixed_array_var_init(tmp_var, false, unaliased_right_sym.info.elem_type, unaliased_right_sym.info.size) } else { + old_inside_assign_fn_var := g.inside_assign_fn_var + g.inside_assign_fn_var = val is ast.PrefixExpr && val.op == .amp + && is_fn_var g.expr(val) + g.inside_assign_fn_var = old_inside_assign_fn_var } - if is_auto_heap && !is_option_auto_heap { + if !is_fn_var && is_auto_heap && !is_option_auto_heap { if aligned != 0 { g.write('), ${aligned})') } else { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index ccaa55df57..a498b51c3c 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -163,6 +163,7 @@ mut: inside_cinit bool inside_global_decl bool inside_interface_deref bool + inside_assign_fn_var bool last_tmp_call_var []string last_if_option_type ast.Type // stores the expected if type on nested if expr loop_depth int @@ -5360,7 +5361,7 @@ fn (mut g Gen) ident(node ast.Ident) { if node.obj is ast.Var { is_auto_heap = node.obj.is_auto_heap && (!g.is_assign_lhs || g.assign_op != .decl_assign) - if is_auto_heap { + if is_auto_heap && !g.inside_assign_fn_var { g.write('(*(') } is_option = is_option || node.obj.orig_type.has_flag(.option) @@ -5478,7 +5479,7 @@ fn (mut g Gen) ident(node ast.Ident) { } g.write(')') } - if is_auto_heap { + if is_auto_heap && !g.inside_assign_fn_var { g.write('))') } return @@ -5502,7 +5503,7 @@ fn (mut g Gen) ident(node ast.Ident) { } } g.write(g.get_ternary_name(name)) - if is_auto_heap { + if is_auto_heap && !g.inside_assign_fn_var { g.write('))') if is_option && node.or_expr.kind != .absent { g.write('.data') diff --git a/vlib/v/gen/c/testdata/assign_fn_addr.c.must_have b/vlib/v/gen/c/testdata/assign_fn_addr.c.must_have new file mode 100644 index 0000000000..4433816d08 --- /dev/null +++ b/vlib/v/gen/c/testdata/assign_fn_addr.c.must_have @@ -0,0 +1,2 @@ +string (*cb2) (void) = &cb1; +string (*cb3) (void) = &cb2; \ No newline at end of file diff --git a/vlib/v/gen/c/testdata/assign_fn_addr.out b/vlib/v/gen/c/testdata/assign_fn_addr.out new file mode 100644 index 0000000000..b979d62f4f --- /dev/null +++ b/vlib/v/gen/c/testdata/assign_fn_addr.out @@ -0,0 +1,3 @@ +true +true +true diff --git a/vlib/v/gen/c/testdata/assign_fn_addr.vv b/vlib/v/gen/c/testdata/assign_fn_addr.vv new file mode 100644 index 0000000000..08218594df --- /dev/null +++ b/vlib/v/gen/c/testdata/assign_fn_addr.vv @@ -0,0 +1,12 @@ +const hello = 'hello world!' + +fn main() { + cb1 := fn () string { + return hello + } + cb2 := &cb1 + cb3 := &cb2 + println(voidptr(cb1) != voidptr(cb2)) + println(voidptr(cb2) != voidptr(cb3)) + println(voidptr(cb1) != voidptr(cb3)) +}