autofree: fix frees before returns

pull/9433/head
Alexander Medvednikov 2021-03-23 11:03:34 +03:00
parent b9cbb4f177
commit e86c6e024c
2 changed files with 16 additions and 4 deletions

View File

@ -4721,27 +4721,30 @@ fn (mut g Gen) return_statement(node ast.Return) {
if expr is ast.Ident {
g.returned_var_name = expr.name
}
g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
}
// free := g.is_autofree && !g.is_builtin_mod // node.exprs[0] is ast.CallExpr
// Create a temporary variable for the return expression
free := !g.is_builtin_mod // node.exprs[0] is ast.CallExpr
mut gen_tmp_var := !g.is_builtin_mod // node.exprs[0] is ast.CallExpr
mut tmp := ''
if free {
if gen_tmp_var {
// `return foo(a, b, c)`
// `tmp := foo(a, b, c); free(a); free(b); free(c); return tmp;`
// Save return value in a temp var so that all args (a,b,c) can be freed
// Don't use a tmp var if a variable is simply returned: `return x`
if node.exprs[0] !is ast.Ident {
tmp = g.new_tmp_var()
g.write('/*tmp return var*/ ')
g.write(g.typ(g.fn_decl.return_type))
g.write(' ')
g.write(tmp)
g.write(' = ')
} else {
gen_tmp_var = false
g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
g.write('return ')
}
} else {
g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
g.write('return ')
}
if expr0.is_auto_deref_var() {
@ -4755,10 +4758,11 @@ fn (mut g Gen) return_statement(node ast.Return) {
} else {
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
}
if free {
if gen_tmp_var {
g.writeln(';')
has_semicolon = true
if tmp != '' {
g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
g.write('return $tmp')
has_semicolon = false
}

View File

@ -1,4 +1,5 @@
import os
import strings
// This program is built and run via Valgrind to ensure there are no leaks with -autofree
fn simple() {
@ -341,6 +342,12 @@ fn comp_if() {
fn anon_fn() {
}
fn return_sb_str() string {
mut sb := strings.new_builder(100)
sb.write_string('hello')
return sb.str() // sb should be freed, but only after .str() is called
}
fn main() {
println('start')
simple()
@ -364,6 +371,7 @@ fn main() {
free_before_return()
free_before_return_bool()
free_before_break()
s := return_sb_str()
// free_map()
// loop_map()
free_array_except_returned_element()