From a3774a8b8c7cdb1f3fa298b8c976e22024802b07 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 15 Apr 2026 05:50:59 +0300 Subject: [PATCH] cgen: fix appending reference to array of sumtype references generating new memory address (fixes #14832) --- vlib/v/gen/c/fn.v | 18 +++++++++------ .../array_of_reference_sumtype_test.v | 23 +++++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 88a353432..8c8a1e883 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -6288,13 +6288,17 @@ fn (mut g Gen) ref_or_deref_arg_ex(arg ast.CallArg, expected_type_ ast.Type, lan || (arg.expr is ast.UnsafeExpr && arg.expr.expr is ast.Nil) { g.write('((void*)0)') } else { - // sumtype conversions call memdup internally, so ADDR is sufficient. - // interface conversions don't, so HEAP is needed to ensure the pointer - // remains valid after the current scope ends. - wrap := if expected_ref_inner_sym.kind == .interface { 'HEAP' } else { 'ADDR' } - g.write('${wrap}(${expected_ref_inner_sym.cname}, ') - g.expr_with_cast(arg.expr, arg_typ, expected_ref_inner_type) - g.write(')') + 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) + } 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.write(')') + } } return } diff --git a/vlib/v/tests/builtin_arrays/array_of_reference_sumtype_test.v b/vlib/v/tests/builtin_arrays/array_of_reference_sumtype_test.v index 88962e12a..09db62488 100644 --- a/vlib/v/tests/builtin_arrays/array_of_reference_sumtype_test.v +++ b/vlib/v/tests/builtin_arrays/array_of_reference_sumtype_test.v @@ -43,3 +43,26 @@ fn test_array_of_reference_sumtype() { assert parent.child_nodes[0].name == 'child' assert ret == 0 } + +fn test_array_of_reference_sumtype_attribute_variant_aliases_original_payload() { + mut parent := &Element{ + name: 'parent' + } + attr := &Attribute{ + name: 'foo' + value: 'bar' + } + parent.append_child(attr) + + attr_node := &Node(attr) + assert parent.has_child(attr_node) == 0 + + if parent.child_nodes[0] is Attribute { + parent.child_nodes[0].value = 'baz' + } else { + assert false + } + + assert attr.value == 'baz' + assert parent.child_nodes[0].name == 'foo' +} -- 2.39.5