autofree: tmp arg var frees fixes

pull/5997/head
Alexander Medvednikov 2020-08-27 11:30:28 +02:00
parent 3b03edd7cb
commit 15bdb8f7cd
6 changed files with 41 additions and 16 deletions

View File

@ -18,4 +18,5 @@
- vfmt: fix common errors automatically to save time (make vars mutable and vice versa, add missing imports etc) - vfmt: fix common errors automatically to save time (make vars mutable and vice versa, add missing imports etc)
- method expressions with an explicit receiver as the first argument - method expressions with an explicit receiver as the first argument
- fix all remaining generics issues (`foo(5)` instead of `foo<int>(5)` etc) - fix all remaining generics issues (`foo(5)` instead of `foo<int>(5)` etc)
- merge v.c and v_win.c

View File

@ -128,7 +128,8 @@ pub fn cp_all(osource_path, odest_path string, overwrite bool) ? {
} }
// single file copy // single file copy
if !os.is_dir(source_path) { if !os.is_dir(source_path) {
adjusted_path := if os.is_dir(dest_path) {os.join_path(dest_path,os.file_name(source_path)) } else { dest_path } adjusted_path := if os.is_dir(dest_path) {
os.join_path(dest_path,os.file_name(source_path)) } else { dest_path }
if os.exists(adjusted_path) { if os.exists(adjusted_path) {
if overwrite { if overwrite {
os.rm(adjusted_path) os.rm(adjusted_path)

View File

@ -106,8 +106,9 @@ mut:
comptime_var_type_map map[string]table.Type comptime_var_type_map map[string]table.Type
match_sumtype_exprs []ast.Expr match_sumtype_exprs []ast.Expr
match_sumtype_syms []table.TypeSymbol match_sumtype_syms []table.TypeSymbol
tmp_idxs []int tmp_arg_vars_to_free []string
called_fn_name string called_fn_name string
cur_mod string
} }
const ( const (
@ -932,6 +933,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
} }
ast.Module { ast.Module {
g.is_builtin_mod = node.name == 'builtin' g.is_builtin_mod = node.name == 'builtin'
g.cur_mod = node.name
} }
ast.Return { ast.Return {
g.write_defer_stmts_when_needed() g.write_defer_stmts_when_needed()

View File

@ -462,7 +462,6 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
if is_json_encode { if is_json_encode {
g.gen_json_for_type(node.args[0].typ) g.gen_json_for_type(node.args[0].typ)
json_type_str = g.table.get_type_symbol(node.args[0].typ).name json_type_str = g.table.get_type_symbol(node.args[0].typ).name
// `json__encode` => `json__encode_User` // `json__encode` => `json__encode_User`
encode_name := c_name(name) + '_' + util.no_dots(json_type_str) encode_name := c_name(name) + '_' + util.no_dots(json_type_str)
g.writeln('// json.encode') g.writeln('// json.encode')
@ -517,9 +516,10 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
*/ */
// Create a temporary var for each argument in order to free it (only if it's a complex expression, // Create a temporary var for each argument in order to free it (only if it's a complex expression,
// like `foo(get_string())` or `foo(a + b)` // like `foo(get_string())` or `foo(a + b)`
free_tmp_arg_vars := g.autofree && g.pref.experimental && node.args.len > 0 && !node.args[0].typ.has_flag(.optional) free_tmp_arg_vars := g.autofree && g.pref.experimental && !g.is_builtin_mod && g.cur_mod !=
'os' && node.args.len > 0 && !node.args[0].typ.has_flag(.optional)
if free_tmp_arg_vars { if free_tmp_arg_vars {
g.tmp_idxs = []int{cap: 10} // TODO perf g.tmp_arg_vars_to_free = []string{cap: 10} // TODO perf
for i, arg in node.args { for i, arg in node.args {
if arg.typ != table.string_type { if arg.typ != table.string_type {
continue continue
@ -527,7 +527,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
if arg.expr is ast.Ident || arg.expr is ast.StringLiteral { if arg.expr is ast.Ident || arg.expr is ast.StringLiteral {
continue continue
} }
t := '_arg_expr_${name}_$i' // g.new_tmp_var() t := g.new_tmp_var() + '_arg_expr_${name}_$i' // g.new_tmp_var()
g.called_fn_name = name g.called_fn_name = name
/* /*
g.write('string $t = ') g.write('string $t = ')
@ -535,12 +535,12 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
g.writeln('; // to free $i ') g.writeln('; // to free $i ')
*/ */
str_expr := g.write_expr_to_string(arg.expr) str_expr := g.write_expr_to_string(arg.expr)
g.insert_before_stmt('string $t = $str_expr; // to free $i ') g.insert_before_stmt('string $t = $str_expr; // new. to free $i ')
g.tmp_idxs << i g.tmp_arg_vars_to_free << t // i
} }
} }
// Handle `print(x)` // Handle `print(x)`
if is_print && node.args[0].typ != table.string_type { if is_print && node.args[0].typ != table.string_type && !free_tmp_arg_vars {
typ := node.args[0].typ typ := node.args[0].typ
mut styp := g.typ(typ) mut styp := g.typ(typ)
sym := g.table.get_type_symbol(typ) sym := g.table.get_type_symbol(typ)
@ -609,8 +609,14 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
} }
g.is_c_call = false g.is_c_call = false
g.is_json_fn = false g.is_json_fn = false
if free_tmp_arg_vars { if free_tmp_arg_vars && g.tmp_arg_vars_to_free.len > 0 {
g.tmp_idxs.clear() // Now free the tmp arg vars right after the function call
g.writeln(';')
for tmp in g.tmp_arg_vars_to_free {
g.writeln('string_free(&$tmp);')
}
g.writeln('')
g.tmp_arg_vars_to_free.clear()
} }
} }
@ -640,10 +646,15 @@ fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
if is_interface { if is_interface {
g.expr(arg.expr) g.expr(arg.expr)
} else if g.autofree && g.pref.experimental && arg.typ == table.string_type && } else if g.autofree && g.pref.experimental && arg.typ == table.string_type &&
g.tmp_idxs.len > 0 && i in g.tmp_idxs { g.tmp_arg_vars_to_free.len > 0 { // && g.tmp_arg_vars_to_free.contains('_$i') { // && i in g.tmp_idxs {
// Save expressions in temp variables so that they can be freed later. for name in g.tmp_arg_vars_to_free {
// `foo(str + str2) => x := str + str2; foo(x); x.free()` // Save expressions in temp variables so that they can be freed later.
g.write('_arg_expr_${g.called_fn_name}_$i') // `foo(str + str2) => x := str + str2; foo(x); x.free()`
// g.write('_arg_expr_${g.called_fn_name}_$i')
if name.contains('_$i') {
g.write(name)
}
}
} else { } else {
g.ref_or_deref_arg(arg, expected_types[i]) g.ref_or_deref_arg(arg, expected_types[i])
} }

View File

@ -194,7 +194,8 @@ fn (mut g Gen) string_inter_literal_sb_optimized(call_expr ast.CallExpr) {
fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
mut cur_line := '' mut cur_line := ''
mut tmp := '' mut tmp := ''
free := g.pref.autofree && g.inside_call && !g.inside_return && g.inside_ternary == 0 && !g.inside_const free := !g.pref.experimental && g.pref.autofree && g.inside_call && !g.inside_return &&
g.inside_ternary == 0 && !g.inside_const
// && g.cur_fn != 0 && // && g.cur_fn != 0 &&
// g.cur_fn.name != '' // g.cur_fn.name != ''
if free { if free {

View File

@ -15,6 +15,14 @@ fn foo() {
// nums.free() // this should result in a double free and a CI error // nums.free() // this should result in a double free and a CI error
} }
fn handle_strings(s, p string) {
}
fn str_expr() {
println('a' + 'b') // tmp expression result must be freed
handle_strings('c' + 'd', 'e' + 'f')
}
fn str_replace() { fn str_replace() {
s := 'hello world' s := 'hello world'
r := s.replace('hello', 'hi') r := s.replace('hello', 'hi')
@ -27,6 +35,7 @@ fn str_replace() {
fn main() { fn main() {
println('start') println('start')
foo() foo()
// str_expr()
// str_replace() // str_replace()
println('end') println('end')
} }