cgen: fix assigning fn address (fix #24537) (#25158)

This commit is contained in:
Felipe Pena 2025-08-23 16:57:30 -03:00 committed by GitHub
parent 8bb7f3dd75
commit 7dd91ecef7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 32 additions and 6 deletions

View file

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

View file

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

View file

@ -0,0 +1,2 @@
string (*cb2) (void) = &cb1;
string (*cb3) (void) = &cb2;

View file

@ -0,0 +1,3 @@
true
true
true

12
vlib/v/gen/c/testdata/assign_fn_addr.vv vendored Normal file
View file

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