Skip to content

Commit 0e93a12

Browse files
authored
cgen: fix option array push on unwrapped array (fix #24073) (#24079)
1 parent 991b121 commit 0e93a12

File tree

3 files changed

+61
-13
lines changed

3 files changed

+61
-13
lines changed

vlib/v/gen/c/cgen.v

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ mut:
118118
chan_pop_options map[string]string // types for `x := <-ch or {...}`
119119
chan_push_options map[string]string // types for `ch <- x or {...}`
120120
mtxs string // array of mutexes if the `lock` has multiple variables
121+
tmp_var_ptr map[string]bool // indicates if the tmp var passed to or_block() is a ptr
121122
labeled_loops map[string]&ast.Stmt
122123
contains_ptr_cache map[ast.Type]bool
123124
inner_loop &ast.Stmt = unsafe { nil }
@@ -4071,11 +4072,24 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
40714072
stmt_str := g.go_before_last_stmt().trim_space()
40724073
styp := g.styp(g.unwrap_generic(node.typ))
40734074
g.empty_line = true
4075+
is_option_unwrap := node.typ.has_flag(.option)
40744076
tmp_var := g.new_tmp_var()
4075-
g.write('${styp} ${tmp_var} = ')
4077+
g.write('${styp} ')
4078+
if is_option_unwrap {
4079+
g.write('*')
4080+
}
4081+
g.write('${tmp_var} = ')
40764082
if is_ptr {
40774083
g.write('*(')
40784084
}
4085+
needs_addr := is_option_unwrap && node.expr !in [ast.Ident, ast.PrefixExpr]
4086+
if is_option_unwrap {
4087+
if !needs_addr {
4088+
g.write('&')
4089+
} else {
4090+
g.write('ADDR(${styp}, ')
4091+
}
4092+
}
40794093
g.expr(node.expr)
40804094
for i, embed in node.from_embed_types {
40814095
embed_sym := g.table.sym(embed)
@@ -4101,11 +4115,20 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
41014115
if is_ptr {
41024116
g.write(')')
41034117
}
4118+
if needs_addr {
4119+
g.write(')')
4120+
}
4121+
if is_option_unwrap {
4122+
g.tmp_var_ptr[tmp_var] = true
4123+
}
41044124
g.or_block(tmp_var, node.or_block, node.typ)
4125+
if is_option_unwrap {
4126+
g.tmp_var_ptr.delete(tmp_var)
4127+
}
41054128
g.write2(stmt_str, ' ')
41064129
unwrapped_typ := node.typ.clear_option_and_result()
41074130
unwrapped_styp := g.styp(unwrapped_typ)
4108-
g.write('(*(${unwrapped_styp}*)${tmp_var}.data)')
4131+
g.write('(*(${unwrapped_styp}*)${tmp_var}->data)')
41094132
return
41104133
}
41114134

@@ -6924,6 +6947,7 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
69246947
mut is_array_fixed := false
69256948
mut return_wrapped := false
69266949
mut return_is_option := is_option && return_type.has_option_or_result()
6950+
tmp_op := if cvar_name in g.tmp_var_ptr { '->' } else { '.' }
69276951
if is_option {
69286952
is_array_fixed = g.table.final_sym(return_type).kind == .array_fixed
69296953
if !is_array_fixed {
@@ -6935,7 +6959,7 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
69356959
return_wrapped = true
69366960
} else if expr_stmt.expr is ast.CallExpr {
69376961
if expr_stmt.expr.is_return_used {
6938-
g.write('*(${cast_typ}*) ${cvar_name}.data = ')
6962+
g.write('*(${cast_typ}*) ${cvar_name}${tmp_op}data = ')
69396963
}
69406964
} else if g.inside_opt_or_res && return_is_option && g.inside_assign {
69416965
g.write('_option_ok(&(${cast_typ}[]) { ')
@@ -6944,14 +6968,14 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
69446968
g.indent--
69456969
return
69466970
} else {
6947-
g.write('*(${cast_typ}*) ${cvar_name}.data = ')
6971+
g.write('*(${cast_typ}*) ${cvar_name}${tmp_op}data = ')
69486972
}
69496973
}
69506974
} else {
69516975
g.write('${cvar_name} = ')
69526976
}
69536977
if is_array_fixed {
6954-
g.write('memcpy(${cvar_name}.data, (${cast_typ})')
6978+
g.write('memcpy(${cvar_name}${tmp_op}data, (${cast_typ})')
69556979
}
69566980
// return expr or { fn_returns_option() }
69576981
if is_option && g.inside_return && expr_stmt.expr is ast.CallExpr
@@ -6987,6 +7011,7 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
69877011
// Returns the type of the last stmt
69887012
fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Type) {
69897013
cvar_name := c_name(var_name)
7014+
tmp_op := if var_name in g.tmp_var_ptr { '->' } else { '.' }
69907015
if or_block.kind == .block && or_block.stmts.len == 0 {
69917016
// generate nothing, block is empty
69927017
g.write(';\n${util.tabs(g.indent)}(void)${cvar_name};')
@@ -6996,20 +7021,20 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
69967021
is_none_ok := return_type == ast.ovoid_type
69977022
g.writeln(';')
69987023
if is_none_ok {
6999-
g.writeln('if (${cvar_name}.state != 0) {')
7024+
g.writeln('if (${cvar_name}${tmp_op}state != 0) {')
70007025
} else {
70017026
if return_type != 0 && g.table.sym(return_type).kind == .function {
70027027
mr_styp = 'voidptr'
70037028
}
70047029
if return_type.has_flag(.result) {
7005-
g.writeln('if (${cvar_name}.is_error) {')
7030+
g.writeln('if (${cvar_name}${tmp_op}is_error) {')
70067031
} else {
7007-
g.writeln('if (${cvar_name}.state != 0) {')
7032+
g.writeln('if (${cvar_name}${tmp_op}state != 0) {')
70087033
}
70097034
}
70107035
if or_block.kind == .block {
70117036
g.or_expr_return_type = return_type.clear_option_and_result()
7012-
g.writeln('\tIError err = ${cvar_name}.err;')
7037+
g.writeln('\tIError err = ${cvar_name}${tmp_op}err;')
70137038

70147039
g.inside_or_block = true
70157040
defer {
@@ -7029,7 +7054,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
70297054
|| (or_block.kind == .propagate_option && return_type.has_flag(.result)) {
70307055
if g.file.mod.name == 'main' && (g.fn_decl == unsafe { nil } || g.fn_decl.is_main) {
70317056
// In main(), an `opt()!` call is sugar for `opt() or { panic(err) }`
7032-
err_msg := 'IError_name_table[${cvar_name}.err._typ]._method_msg(${cvar_name}.err._object)'
7057+
err_msg := 'IError_name_table[${cvar_name}${tmp_op}err._typ]._method_msg(${cvar_name}${tmp_op}err._object)'
70337058
if g.pref.is_debug {
70347059
paline, pafile, pamod, pafn := g.panic_debug_info(or_block.pos)
70357060
g.writeln('panic_debug(${paline}, tos3("${pafile}"), tos3("${pamod}"), tos3("${pafn}"), ${err_msg});')
@@ -7057,7 +7082,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
70577082
} else if or_block.kind == .propagate_option {
70587083
if g.file.mod.name == 'main' && (g.fn_decl == unsafe { nil } || g.fn_decl.is_main) {
70597084
// In main(), an `opt()?` call is sugar for `opt() or { panic(err) }`
7060-
err_msg := 'IError_name_table[${cvar_name}.err._typ]._method_msg(${cvar_name}.err._object)'
7085+
err_msg := 'IError_name_table[${cvar_name}${tmp_op}err._typ]._method_msg(${cvar_name}${tmp_op}err._object)'
70617086
if g.pref.is_debug {
70627087
paline, pafile, pamod, pafn := g.panic_debug_info(or_block.pos)
70637088
g.writeln('panic_debug(${paline}, tos3("${pafile}"), tos3("${pamod}"), tos3("${pafn}"), ${err_msg}.len == 0 ? _SLIT("option not set ()") : ${err_msg});')

vlib/v/gen/c/cmain.v

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,8 @@ pub fn (mut g Gen) gen_failing_error_propagation_for_test_fn(or_block ast.OrExpr
249249
// `or { cb_propagate_test_error(@LINE, @FILE, @MOD, @FN, err.msg() ) }`
250250
// and the test is considered failed
251251
paline, pafile, pamod, pafn := g.panic_debug_info(or_block.pos)
252-
err_msg := 'IError_name_table[${cvar_name}.err._typ]._method_msg(${cvar_name}.err._object)'
252+
dot_or_ptr := if cvar_name in g.tmp_var_ptr { '->' } else { '.' }
253+
err_msg := 'IError_name_table[${cvar_name}${dot_or_ptr}err._typ]._method_msg(${cvar_name}${dot_or_ptr}err._object)'
253254
g.writeln('\tmain__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, ${paline}, tos3("${pafile}"), tos3("${pamod}"), tos3("${pafn}"), ${err_msg} );')
254255
g.writeln('\tlongjmp(g_jump_buffer, 1);')
255256
}
@@ -259,7 +260,8 @@ pub fn (mut g Gen) gen_failing_return_error_for_test_fn(return_stmt ast.Return,
259260
// `or { err := error('something') cb_propagate_test_error(@LINE, @FILE, @MOD, @FN, err.msg() ) return err }`
260261
// and the test is considered failed
261262
paline, pafile, pamod, pafn := g.panic_debug_info(return_stmt.pos)
262-
err_msg := 'IError_name_table[${cvar_name}.err._typ]._method_msg(${cvar_name}.err._object)'
263+
dot_or_ptr := if cvar_name in g.tmp_var_ptr { '->' } else { '.' }
264+
err_msg := 'IError_name_table[${cvar_name}${dot_or_ptr}err._typ]._method_msg(${cvar_name}${dot_or_ptr}err._object)'
263265
g.writeln('\tmain__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, ${paline}, tos3("${pafile}"), tos3("${pamod}"), tos3("${pafn}"), ${err_msg} );')
264266
g.writeln('\tlongjmp(g_jump_buffer, 1);')
265267
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
pub struct Struct1 {
2+
pub mut:
3+
strings ?[]string
4+
}
5+
6+
fn test_main() {
7+
mut s1 := Struct1{}
8+
assert s1.strings == none
9+
s1.strings = []
10+
assert s1.strings? == []
11+
s1.strings? << ['foo']
12+
s1.strings? << ['bar']
13+
dump(s1)
14+
assert s1.strings? == ['foo', 'bar']
15+
16+
s1.strings = []
17+
assert s1.strings? == []
18+
19+
s1.strings? << ['foo']
20+
assert s1.strings? == ['foo']
21+
}

0 commit comments

Comments
 (0)