From 3431880389779152dc83e9e831a50af06e9bd8a4 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 15 Apr 2026 02:20:50 +0300 Subject: [PATCH] cgen: fix struct or union expected error (fixes #26837) --- vlib/v/gen/c/cgen.v | 20 +++++++++++++++---- ...rface_match_string_slice_regression_test.v | 20 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 vlib/v/tests/interfaces/interface_match_string_slice_regression_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 05903b220..9810b500d 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3941,6 +3941,9 @@ fn (mut g Gen) expr_has_stable_interface_cast_address(expr ast.Expr) bool { return g.expr_has_stable_interface_cast_address(expr.expr) } ast.IndexExpr { + if expr.index is ast.RangeExpr { + return false + } if expr.left_type.is_ptr() { return true } @@ -3996,11 +3999,15 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Ty // 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) + // 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 + && g.expr_needs_heap_promotion_for_interface_cast(expr) if !is_cast_fixed_array_init && (is_comptime_variant || !expr.is_lvalue() || (expr is ast.Ident && (expr.obj.is_simple_define_const() || (expr.obj is ast.Var && expr.obj.is_index_var))) - || is_primitive_to_interface || is_stack_rooted_interface_expr) { + || is_primitive_to_interface || needs_interface_cast_promotion) { // Note: the `_to_sumtype_` family of functions do call memdup internally, making // another duplicate with the HEAP macro is redundant, so use ADDR instead: if expr.is_as_cast() { @@ -6466,9 +6473,10 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { } mut is_interface_smartcast_selector := false if node.expr is ast.SelectorExpr { - if node.expr.expr is ast.Ident && node.expr.expr.obj is ast.Var - && node.expr.field_name.starts_with('_') - && g.table.is_interface_smartcast(node.expr.expr.obj) { + base_selector_type := g.unwrap_generic(g.resolved_expr_type(node.expr.expr, + node.expr.expr_type)) + if node.expr.field_name.starts_with('_') + && g.table.final_sym(base_selector_type).kind == .interface { is_interface_smartcast_selector = true } } @@ -6637,10 +6645,14 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { } interface_smartcast_expr_is_dereferenced := is_interface_smartcast_expr && smartcast_expr_var.smartcasts.last().nr_muls() == exposed_interface_smartcast_type.nr_muls() + 1 + interface_smartcast_selector_emits_ptr := is_interface_smartcast_selector + || (is_interface_smartcast_expr + && g.table.final_sym(g.unwrap_generic(smartcast_expr_var.smartcasts.last())).kind != .interface) left_is_ptr := if expr_is_unwrapped_autoheap_option { false } else { field_is_opt || expr_is_auto_heap + || interface_smartcast_selector_emits_ptr || (is_interface_smartcast_lhs && !interface_smartcast_expr_is_dereferenced) || (((!is_dereferenced && !is_interface_smartcast_lhs && unwrapped_expr_type.is_ptr()) || sym.kind == .chan || alias_to_ptr) && node.from_embed_types.len == 0) diff --git a/vlib/v/tests/interfaces/interface_match_string_slice_regression_test.v b/vlib/v/tests/interfaces/interface_match_string_slice_regression_test.v new file mode 100644 index 000000000..4296763f2 --- /dev/null +++ b/vlib/v/tests/interfaces/interface_match_string_slice_regression_test.v @@ -0,0 +1,20 @@ +interface Value {} + +fn parse_verb(v Value) !Value { + match v { + string { + if v.len < 4 || (v.len >= 4 && v[3] != `:`) { + return error('bad verb') + } + return v[4..] + } + else { + return v + } + } +} + +fn test_interface_match_string_slice_regression() { + got := parse_verb('txt:hello') or { panic(err) } + assert got as string == 'hello' +} -- 2.39.5