Skip to content

Commit 8d745ef

Browse files
committed
all: fix more tests
1 parent 3c0c279 commit 8d745ef

3 files changed

Lines changed: 64 additions & 18 deletions

File tree

vlib/v/gen/c/cgen.v

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3998,6 +3998,25 @@ fn (mut g Gen) expr_needs_heap_promotion_for_interface_cast(expr ast.Expr) bool
39983998
}
39993999
}
40004000

4001+
fn (g &Gen) interface_cast_requires_field_aliasing(expected_type ast.Type, expr ast.Expr) bool {
4002+
if !expr.is_lvalue() {
4003+
return false
4004+
}
4005+
interface_type := if expected_type.is_ptr() {
4006+
expected_type.deref()
4007+
} else {
4008+
expected_type
4009+
}
4010+
interface_sym := g.table.final_sym(interface_type)
4011+
if interface_sym.kind != .interface {
4012+
return false
4013+
}
4014+
return match interface_sym.info {
4015+
ast.Interface { interface_sym.info.fields.any(it.is_mut) }
4016+
else { false }
4017+
}
4018+
}
4019+
40014020
fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Type, got ast.Type, exp_styp string,
40024021
got_is_ptr bool, got_is_fn bool, got_styp string) {
40034022
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
40274046

40284047
is_primitive_to_interface := is_interface_cast && expr is ast.Ident
40294048
&& g.table.sym(got).kind in [.i8, .i16, .i32, .int, .i64, .isize, .u8, .u16, .u32, .u64, .usize, .f32, .f64, .bool, .rune, .string]
4049+
preserve_interface_field_aliasing := is_interface_cast
4050+
&& g.interface_cast_requires_field_aliasing(exp, expr)
40304051

40314052
// Interface casts must not store pointers into stack-rooted lvalues such as
40324053
// local variables or fields on by-value fn args (`p.email`).
4033-
is_stack_rooted_interface_expr = is_interface_cast && g.interface_expr_needs_heap(expr)
4054+
is_stack_rooted_interface_expr = is_interface_cast && !preserve_interface_field_aliasing
4055+
&& g.interface_expr_needs_heap(expr)
40344056
// Interface casts must not store pointers into expressions without a
40354057
// stable address, including stack-rooted lvalues and slice results.
4036-
needs_interface_cast_promotion := is_interface_cast
4058+
needs_interface_cast_promotion := is_interface_cast && !preserve_interface_field_aliasing
40374059
&& g.expr_needs_heap_promotion_for_interface_cast(expr)
40384060
// Value-to-interface conversions should preserve value semantics by storing a detached copy.
40394061
// The only exception is an explicit mutable borrow, which must keep aliasing the original.
4040-
needs_interface_value_copy := is_interface_cast && !g.expected_arg_mut && !got_is_ptr
4041-
&& expr.is_lvalue()
4062+
// Interfaces with mutable fields also need to alias the original lvalue so field reads/writes
4063+
// stay connected to the concrete value instead of a detached clone.
4064+
needs_interface_value_copy := is_interface_cast && !preserve_interface_field_aliasing
4065+
&& !g.expected_arg_mut && !got_is_ptr && expr.is_lvalue()
40424066

40434067
if !is_cast_fixed_array_init && (is_comptime_variant || !expr.is_lvalue()
40444068
|| (expr is ast.Ident && (expr.obj.is_simple_define_const()

vlib/v/gen/c/fn.v

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6435,30 +6435,52 @@ fn (mut g Gen) ref_or_deref_arg_ex(arg ast.CallArg, expected_type_ ast.Type, lan
64356435
expected_ref_inner_type := expected_type.deref()
64366436
expected_ref_inner_sym := g.table.sym(expected_ref_inner_type)
64376437
if expected_ref_inner_sym.kind in [.interface, .sum_type] {
6438-
if arg_typ.is_ptr() && arg_typ.deref() == expected_ref_inner_type {
6439-
g.prevent_sum_type_unwrapping_once = g.is_expr_smartcast_to_sumtype(arg.expr,
6438+
mut effective_arg_expr := arg.expr
6439+
mut effective_arg_typ := arg_typ
6440+
if expected_ref_inner_sym.kind == .sum_type && arg.expr is ast.CastExpr {
6441+
cast_expr := arg.expr
6442+
cast_target_type := g.unwrap_generic(if cast_expr.typ != 0 {
6443+
cast_expr.typ
6444+
} else {
6445+
arg_typ
6446+
})
6447+
if cast_target_type.idx() == expected_ref_inner_type.idx()
6448+
&& cast_expr.expr_type != 0 {
6449+
effective_arg_expr = cast_expr.expr
6450+
effective_arg_typ = g.unwrap_generic(cast_expr.expr_type)
6451+
}
6452+
}
6453+
effective_arg_sym := g.table.sym(effective_arg_typ)
6454+
if effective_arg_typ.is_ptr() && effective_arg_typ.deref() == expected_ref_inner_type {
6455+
g.prevent_sum_type_unwrapping_once = g.is_expr_smartcast_to_sumtype(effective_arg_expr,
64406456
expected_ref_inner_type)
6441-
g.expr(arg.expr)
6442-
} else if arg_sym.kind == expected_ref_inner_sym.kind
6443-
&& arg_typ.idx() == expected_ref_inner_type.idx()
6444-
&& arg.expr in [ast.Ident, ast.SelectorExpr] {
6445-
g.prevent_sum_type_unwrapping_once = g.is_expr_smartcast_to_sumtype(arg.expr,
6457+
g.expr(effective_arg_expr)
6458+
} else if effective_arg_sym.kind == expected_ref_inner_sym.kind
6459+
&& effective_arg_typ.idx() == expected_ref_inner_type.idx() {
6460+
g.prevent_sum_type_unwrapping_once = g.is_expr_smartcast_to_sumtype(effective_arg_expr,
64466461
expected_ref_inner_type)
6447-
g.write('&')
6448-
g.expr(arg.expr)
6449-
} else if arg_typ == ast.nil_type || arg_typ.is_voidptr()
6450-
|| (arg.expr is ast.UnsafeExpr && arg.expr.expr is ast.Nil) {
6462+
if effective_arg_expr in [ast.Ident, ast.SelectorExpr] {
6463+
g.write('&')
6464+
g.expr(effective_arg_expr)
6465+
} else {
6466+
g.write('ADDR(${g.styp(expected_ref_inner_type)}, ')
6467+
g.expr_with_cast(effective_arg_expr, effective_arg_typ, expected_ref_inner_type)
6468+
g.write(')')
6469+
}
6470+
} else if effective_arg_typ == ast.nil_type
6471+
|| effective_arg_typ.is_voidptr()
6472+
|| (effective_arg_expr is ast.UnsafeExpr && effective_arg_expr.expr is ast.Nil) {
64516473
g.write('((void*)0)')
64526474
} else {
64536475
if expected_ref_inner_sym.kind == .sum_type {
64546476
// `&Variant` -> `&SumType` needs a stable heap-allocated wrapper and
64556477
// must preserve aliasing with the original variant payload.
6456-
g.expr_with_cast(arg.expr, arg_typ, expected_type)
6478+
g.expr_with_cast(effective_arg_expr, effective_arg_typ, expected_type)
64576479
} else {
64586480
// interface conversions don't box by reference, so HEAP is needed to
64596481
// ensure the pointer remains valid after the current scope ends.
64606482
g.write('HEAP(${expected_ref_inner_sym.cname}, ')
6461-
g.expr_with_cast(arg.expr, arg_typ, expected_ref_inner_type)
6483+
g.expr_with_cast(effective_arg_expr, effective_arg_typ, expected_ref_inner_type)
64626484
g.write(')')
64636485
}
64646486
}

vlib/v/tests/fns/fn_test.c.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ interface MyInterface {}
5151

5252
type F9 = fn (MyInterface)
5353

54-
fn C.atoi(&u8) i32
54+
fn C.atoi(const_s &char) i32
5555
fn C.freec(ptr voidptr)
5656

5757
@[trusted]

0 commit comments

Comments
 (0)