Skip to content

Commit 2efd0f4

Browse files
committed
cgen: also materialize parenthesized string-slice sumtype casts via ADDR
The #27548 fix only treated a top-level `IndexExpr` with a `RangeExpr` as an rvalue, but `ast.Expr.is_lvalue()` recurses through `ParExpr`, so a trivially parenthesized slice (`Value((s[1..3]))`) still reported as an lvalue and took the bare `&` path, reproducing the "address of an rvalue" C error. Replace the inline top-level check with a small recursive helper that unwraps parentheses, and add a regression test for the parenthesized form.
1 parent 5d00023 commit 2efd0f4

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

vlib/v/gen/c/cgen.v

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5153,6 +5153,17 @@ fn (mut g Gen) fn_ptr_cast_typ(func ast.FnType) string {
51535153
return g.fn_ptr_decl_str(func, ptr_name).replace_once(ptr_name, '')
51545154
}
51555155

5156+
// expr_is_range_index reports whether expr is a slice (`s[a..b]`), possibly
5157+
// wrapped in parentheses. A slice yields a fresh rvalue with no stable address,
5158+
// so it must be materialized via ADDR rather than `&` in a sumtype cast.
5159+
fn expr_is_range_index(expr ast.Expr) bool {
5160+
return match expr {
5161+
ast.IndexExpr { expr.index is ast.RangeExpr }
5162+
ast.ParExpr { expr_is_range_index(expr.expr) }
5163+
else { false }
5164+
}
5165+
}
5166+
51565167
fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Type, got ast.Type, actual_got ast.Type, exp_styp string,
51575168
got_is_ptr bool, got_is_fn bool, got_styp string) {
51585169
mut rparen_n := 1
@@ -5177,7 +5188,9 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Ty
51775188
// A slice expression (`s[a..b]`) yields a fresh rvalue with no stable
51785189
// address, even though `is_lvalue()` reports it as one. Treat it as an
51795190
// rvalue so the sumtype cast materializes it via ADDR instead of `&`.
5180-
expr.is_lvalue() && !(expr is ast.IndexExpr && expr.index is ast.RangeExpr)
5191+
// `is_lvalue()` recurses through `ParExpr`, so unwrap parens too
5192+
// (`(s[a..b])`).
5193+
expr.is_lvalue() && !expr_is_range_index(expr)
51815194
}
51825195
is_comptime_variant := is_not_ptr_and_fn && expr is ast.Ident
51835196
&& g.comptime.is_comptime_variant_var(expr)

vlib/v/tests/casts/cast_string_rvalue_to_sumtype_test.v

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ fn slice(s string) Value {
77
return Value(s[1..3])
88
}
99

10+
fn paren_slice(s string) Value {
11+
// `is_lvalue()` recurses through parentheses, so a parenthesized slice must
12+
// also be materialized via ADDR.
13+
return Value((s[1..3]))
14+
}
15+
1016
fn concat(a string, b string) Value {
1117
return Value(a + b)
1218
}
@@ -17,6 +23,12 @@ fn test_string_slice_cast_to_sumtype() {
1723
assert (v as string) == 'el'
1824
}
1925

26+
fn test_string_paren_slice_cast_to_sumtype() {
27+
v := paren_slice('hello')
28+
assert v is string
29+
assert (v as string) == 'el'
30+
}
31+
2032
fn test_string_concat_cast_to_sumtype() {
2133
v := concat('foo', 'bar')
2234
assert v is string

0 commit comments

Comments
 (0)