From 624a3edc2c5cb43673dd34a7e4e4f06cafb4fb0f Mon Sep 17 00:00:00 2001 From: shove70 Date: Fri, 26 Jan 2024 10:13:27 +0800 Subject: [PATCH] cgen: fix several issues with autofree(fix #20635) --- vlib/v/gen/c/cgen.v | 25 +++++++++------- vlib/v/tests/autofree_test.v | 58 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 vlib/v/tests/autofree_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 63d80db3ba3951..1938446b5ed3dd 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2873,7 +2873,8 @@ fn (mut g Gen) get_ternary_name(name string) string { } fn (mut g Gen) gen_clone_assignment(val ast.Expr, typ ast.Type, add_eq bool) bool { - if val !in [ast.Ident, ast.SelectorExpr] { + if val !in [ast.Ident, ast.SelectorExpr, ast.CallExpr, ast.MatchExpr, ast.IfExpr, ast.IndexExpr, + ast.ParExpr, ast.UnsafeExpr] { return false } right_sym := g.table.sym(typ) @@ -2978,6 +2979,11 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int // TODO: free options continue } + is_result := obj.typ.has_flag(.result) + if is_result { + // TODO: free result + continue + } g.autofree_variable(obj) } else {} @@ -5348,6 +5354,14 @@ fn (mut g Gen) return_stmt(node ast.Return) { node.types[0].has_flag(.option) } } + // autofree before `return` + // set free_parent_scopes to true, since all variables defined in parent + // scopes need to be freed before the return + if g.is_autofree { + if expr0 is ast.Ident { + g.returned_var_name = expr0.name + } + } if fn_return_is_option && !expr_type_is_opt && return_sym.name != c.option_name { styp := g.base_type(fn_ret_type) g.writeln('${ret_typ} ${tmpvar};') @@ -5408,15 +5422,6 @@ fn (mut g Gen) return_stmt(node ast.Return) { g.writeln('return ${tmpvar};') return } - // autofree before `return` - // set free_parent_scopes to true, since all variables defined in parent - // scopes need to be freed before the return - if g.is_autofree { - expr := node.exprs[0] - if expr is ast.Ident { - g.returned_var_name = expr.name - } - } // free := g.is_autofree && !g.is_builtin_mod // node.exprs[0] is ast.CallExpr // Create a temporary variable for the return expression if use_tmp_var || !g.is_builtin_mod { diff --git a/vlib/v/tests/autofree_test.v b/vlib/v/tests/autofree_test.v new file mode 100644 index 00000000000000..6bb45bdd1dcb7d --- /dev/null +++ b/vlib/v/tests/autofree_test.v @@ -0,0 +1,58 @@ +// vtest vflags: -autofree + +fn return_array_with_result() ![]int { + mut arr := []int{} + arr << 123 + return arr +} + +fn return_array_with_option() ?[]int { + mut arr := []int{} + arr << 123 + return arr +} + +fn return_strng(s string) string { + return s +} + +fn test_main() { + arr1 := return_array_with_result()! + assert arr1 == [123] + arr2 := return_array_with_option()? + assert arr2 == [123] + + // test ident + str1 := '${'123'}abc' + str2 := str1 + assert str2 == '123abc' + + // test CallExpr + str3 := return_strng(str1) + assert str3 == '123abc' + + // test MatchExpr + str4 := match true { + true { + str1 + } + else { + str1 + } + } + assert str4 == '123abc' + + // test IfExpr + str5 := if true { str1 } else { str1 } + assert str5 == '123abc' + + // test ParExpr + // vfmt off + str6 := (str1) + // vfmt on + assert str6 == '123abc' + + // test UnsafeExpr + str7 := unsafe { str1 } + assert str7 == '123abc' +}