From 8d745ef69eed77b5fdf5cb84a49881385e585eae Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sun, 19 Apr 2026 02:02:25 +0300 Subject: [PATCH] all: fix more tests --- vlib/v/gen/c/cgen.v | 32 +++++++++++++++++++++--- vlib/v/gen/c/fn.v | 48 ++++++++++++++++++++++++++---------- vlib/v/tests/fns/fn_test.c.v | 2 +- 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 007deda9b..f48070002 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3998,6 +3998,25 @@ fn (mut g Gen) expr_needs_heap_promotion_for_interface_cast(expr ast.Expr) bool } } +fn (g &Gen) interface_cast_requires_field_aliasing(expected_type ast.Type, expr ast.Expr) bool { + if !expr.is_lvalue() { + return false + } + interface_type := if expected_type.is_ptr() { + expected_type.deref() + } else { + expected_type + } + interface_sym := g.table.final_sym(interface_type) + if interface_sym.kind != .interface { + return false + } + return match interface_sym.info { + ast.Interface { interface_sym.info.fields.any(it.is_mut) } + else { false } + } +} + fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Type, got ast.Type, exp_styp string, got_is_ptr bool, got_is_fn bool, got_styp string) { mut rparen_n := 1 @@ -4027,18 +4046,23 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Ty is_primitive_to_interface := is_interface_cast && expr is ast.Ident && g.table.sym(got).kind in [.i8, .i16, .i32, .int, .i64, .isize, .u8, .u16, .u32, .u64, .usize, .f32, .f64, .bool, .rune, .string] + preserve_interface_field_aliasing := is_interface_cast + && g.interface_cast_requires_field_aliasing(exp, expr) // Interface casts must not store pointers into stack-rooted lvalues such as // local variables or fields on by-value fn args (`p.email`). - is_stack_rooted_interface_expr = is_interface_cast && g.interface_expr_needs_heap(expr) + is_stack_rooted_interface_expr = is_interface_cast && !preserve_interface_field_aliasing + && g.interface_expr_needs_heap(expr) // Interface casts must not store pointers into expressions without a // stable address, including stack-rooted lvalues and slice results. - needs_interface_cast_promotion := is_interface_cast + needs_interface_cast_promotion := is_interface_cast && !preserve_interface_field_aliasing && g.expr_needs_heap_promotion_for_interface_cast(expr) // Value-to-interface conversions should preserve value semantics by storing a detached copy. // The only exception is an explicit mutable borrow, which must keep aliasing the original. - needs_interface_value_copy := is_interface_cast && !g.expected_arg_mut && !got_is_ptr - && expr.is_lvalue() + // Interfaces with mutable fields also need to alias the original lvalue so field reads/writes + // stay connected to the concrete value instead of a detached clone. + needs_interface_value_copy := is_interface_cast && !preserve_interface_field_aliasing + && !g.expected_arg_mut && !got_is_ptr && expr.is_lvalue() if !is_cast_fixed_array_init && (is_comptime_variant || !expr.is_lvalue() || (expr is ast.Ident && (expr.obj.is_simple_define_const() diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index a50c7ced9..d3344ae0a 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -6435,30 +6435,52 @@ fn (mut g Gen) ref_or_deref_arg_ex(arg ast.CallArg, expected_type_ ast.Type, lan expected_ref_inner_type := expected_type.deref() expected_ref_inner_sym := g.table.sym(expected_ref_inner_type) if expected_ref_inner_sym.kind in [.interface, .sum_type] { - if arg_typ.is_ptr() && arg_typ.deref() == expected_ref_inner_type { - g.prevent_sum_type_unwrapping_once = g.is_expr_smartcast_to_sumtype(arg.expr, + mut effective_arg_expr := arg.expr + mut effective_arg_typ := arg_typ + if expected_ref_inner_sym.kind == .sum_type && arg.expr is ast.CastExpr { + cast_expr := arg.expr + cast_target_type := g.unwrap_generic(if cast_expr.typ != 0 { + cast_expr.typ + } else { + arg_typ + }) + if cast_target_type.idx() == expected_ref_inner_type.idx() + && cast_expr.expr_type != 0 { + effective_arg_expr = cast_expr.expr + effective_arg_typ = g.unwrap_generic(cast_expr.expr_type) + } + } + effective_arg_sym := g.table.sym(effective_arg_typ) + if effective_arg_typ.is_ptr() && effective_arg_typ.deref() == expected_ref_inner_type { + g.prevent_sum_type_unwrapping_once = g.is_expr_smartcast_to_sumtype(effective_arg_expr, expected_ref_inner_type) - g.expr(arg.expr) - } else if arg_sym.kind == expected_ref_inner_sym.kind - && arg_typ.idx() == expected_ref_inner_type.idx() - && arg.expr in [ast.Ident, ast.SelectorExpr] { - g.prevent_sum_type_unwrapping_once = g.is_expr_smartcast_to_sumtype(arg.expr, + g.expr(effective_arg_expr) + } else if effective_arg_sym.kind == expected_ref_inner_sym.kind + && effective_arg_typ.idx() == expected_ref_inner_type.idx() { + g.prevent_sum_type_unwrapping_once = g.is_expr_smartcast_to_sumtype(effective_arg_expr, expected_ref_inner_type) - g.write('&') - g.expr(arg.expr) - } else if arg_typ == ast.nil_type || arg_typ.is_voidptr() - || (arg.expr is ast.UnsafeExpr && arg.expr.expr is ast.Nil) { + if effective_arg_expr in [ast.Ident, ast.SelectorExpr] { + g.write('&') + g.expr(effective_arg_expr) + } else { + g.write('ADDR(${g.styp(expected_ref_inner_type)}, ') + g.expr_with_cast(effective_arg_expr, effective_arg_typ, expected_ref_inner_type) + g.write(')') + } + } else if effective_arg_typ == ast.nil_type + || effective_arg_typ.is_voidptr() + || (effective_arg_expr is ast.UnsafeExpr && effective_arg_expr.expr is ast.Nil) { g.write('((void*)0)') } else { if expected_ref_inner_sym.kind == .sum_type { // `&Variant` -> `&SumType` needs a stable heap-allocated wrapper and // must preserve aliasing with the original variant payload. - g.expr_with_cast(arg.expr, arg_typ, expected_type) + g.expr_with_cast(effective_arg_expr, effective_arg_typ, expected_type) } else { // interface conversions don't box by reference, so HEAP is needed to // ensure the pointer remains valid after the current scope ends. g.write('HEAP(${expected_ref_inner_sym.cname}, ') - g.expr_with_cast(arg.expr, arg_typ, expected_ref_inner_type) + g.expr_with_cast(effective_arg_expr, effective_arg_typ, expected_ref_inner_type) g.write(')') } } diff --git a/vlib/v/tests/fns/fn_test.c.v b/vlib/v/tests/fns/fn_test.c.v index 8362a81ee..17019d49e 100644 --- a/vlib/v/tests/fns/fn_test.c.v +++ b/vlib/v/tests/fns/fn_test.c.v @@ -51,7 +51,7 @@ interface MyInterface {} type F9 = fn (MyInterface) -fn C.atoi(&u8) i32 +fn C.atoi(const_s &char) i32 fn C.freec(ptr voidptr) @[trusted] -- 2.39.5