Skip to content

Commit

Permalink
cgen: fix generating callexpr to string is actually called twice (fix #…
Browse files Browse the repository at this point in the history
  • Loading branch information
shove70 committed Dec 28, 2023
1 parent 76e1ac3 commit 57cc00d
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 3 deletions.
30 changes: 27 additions & 3 deletions vlib/v/gen/c/str.v
Expand Up @@ -111,12 +111,28 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
is_dump_expr := expr is ast.DumpExpr
is_var_mut := expr.is_auto_deref_var()
str_fn_name := g.get_str_fn(exp_typ)
temp_var_needed := expr is ast.CallExpr && expr.return_type.is_ptr()
mut tmp_var := ''
if temp_var_needed {
tmp_var = g.new_tmp_var()
ret_typ := g.typ(exp_typ)
line := g.go_before_last_stmt().trim_space()
g.empty_line = true
g.write('${ret_typ} ${tmp_var} = ')
g.expr(expr)
g.writeln(';')
g.write(line)
}
if is_ptr && !is_var_mut {
ref_str := '&'.repeat(typ.nr_muls())
g.write('str_intp(1, _MOV((StrIntpData[]){{_SLIT("${ref_str}"), ${si_s_code} ,{.d_s = isnil(')
if typ.has_flag(.option) {
g.write('*(${g.base_type(exp_typ)}*)&')
g.expr(expr)
if temp_var_needed {
g.write(tmp_var)
} else {
g.expr(expr)
}
g.write('.data')
g.write(') ? _SLIT("Option(&nil)") : ')
} else {
Expand All @@ -125,7 +141,11 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
defer {
g.inside_interface_deref = inside_interface_deref_old
}
g.expr(expr)
if temp_var_needed {
g.write(tmp_var)
} else {
g.expr(expr)
}
g.write(') ? _SLIT("nil") : ')
}
}
Expand Down Expand Up @@ -155,7 +175,11 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
if unwrap_option {
g.expr(expr)
} else {
g.expr_with_cast(expr, typ, typ)
if temp_var_needed {
g.write(tmp_var)
} else {
g.expr_with_cast(expr, typ, typ)
}
}

if is_shared {
Expand Down
@@ -0,0 +1,4 @@
It should be printed only once
&Abc{
s: ''
}
@@ -0,0 +1,18 @@
// for issue 20282
// Phenomenon of issue:
// When the expression is CallExpr and the return type is a pointer, cgen generates 2 actual call actions:
// V code: println(call_test())
// C code:
// println(str_intp(1, _MOV((StrIntpData[]){{_SLIT("&"), 0xfe10 ,{.d_s = isnil(call_test()) ? _SLIT("nil") : string_str(*call_test())}}})));
struct Abc {
s string
}

fn str_gen_with_call_and_return_ref() &Abc {
println('It should be printed only once')
return &Abc{}
}

fn main() {
println(str_gen_with_call_and_return_ref())
}

0 comments on commit 57cc00d

Please sign in to comment.