From 0dbbed7bde734ac9507146619a7341ee8950bb31 Mon Sep 17 00:00:00 2001 From: CreeperFace <165158232+dy-tea@users.noreply.github.com> Date: Tue, 16 Sep 2025 07:14:41 +0200 Subject: [PATCH] cgen,autofree: fix method chaining generating invalid c code (fix #9094) (#25315) --- vlib/v/gen/c/assign.v | 10 ++++++++-- vlib/v/gen/c/cgen.v | 1 + vlib/v/gen/c/fn.v | 15 ++++++++++++++- .../c/testdata/autofree_method_chain.c.must_have | 11 +++++++++++ vlib/v/gen/c/testdata/autofree_method_chain.out | 1 + vlib/v/gen/c/testdata/autofree_method_chain.vv | 15 +++++++++++++++ 6 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 vlib/v/gen/c/testdata/autofree_method_chain.c.must_have create mode 100644 vlib/v/gen/c/testdata/autofree_method_chain.out create mode 100644 vlib/v/gen/c/testdata/autofree_method_chain.vv diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 8f1b9a146..cce7b968f 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -219,8 +219,14 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } // Free the old value assigned to this string var (only if it's `str = [new value]` // or `x.str = [new value]` ) - mut af := g.is_autofree && !g.is_builtin_mod && node.op == .assign && node.left_types.len == 1 - && node.left[0] in [ast.Ident, ast.SelectorExpr] + mut af := g.is_autofree && !g.is_builtin_mod && !g.is_autofree_tmp && node.op == .assign + && node.left_types.len == 1 && node.left[0] in [ast.Ident, ast.SelectorExpr] + if af && node.right.len == 1 && node.right[0] is ast.CallExpr { + call_expr := node.right[0] as ast.CallExpr + if call_expr.is_method && call_expr.left is ast.CallExpr { + af = false + } + } mut sref_name := '' mut type_to_free := '' if af { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 456f4c02a..4988524b1 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -102,6 +102,7 @@ mut: is_shared bool // for initialization of hidden mutex in `[rw]shared` literals is_vlines_enabled bool // is it safe to generate #line directives when -g is passed is_autofree bool // false, inside the bodies of fns marked with [manualfree], otherwise === g.pref.autofree + is_autofree_tmp bool // when generating autofree temporary variables is_builtin_mod bool is_json_fn bool // inside json.encode() is_js_call bool // for handling a special type arg #1 `json.decode(User, ...)` diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 72bb96735..ea1d4c542 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -2345,7 +2345,20 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) { }) s = 'string ${t} = ' } - s += g.expr_string(arg.expr) + g.is_autofree_tmp = true + pos_before := g.out.len + + old_is_autofree := g.is_autofree + if arg.expr is ast.CallExpr && arg.expr.is_method && arg.expr.left is ast.CallExpr { + g.is_autofree = false + } + + g.expr(arg.expr) + expr_code := g.out.cut_to(pos_before).trim_space() + + g.is_autofree = old_is_autofree + g.is_autofree_tmp = false + s += expr_code s += ';// new af2 pre' g.strs_to_free0 << s // This tmp arg var will be freed with the rest of the vars at the end of the scope. diff --git a/vlib/v/gen/c/testdata/autofree_method_chain.c.must_have b/vlib/v/gen/c/testdata/autofree_method_chain.c.must_have new file mode 100644 index 000000000..15bd7342a --- /dev/null +++ b/vlib/v/gen/c/testdata/autofree_method_chain.c.must_have @@ -0,0 +1,11 @@ +void main__Test_set_tags(main__Test* t, string tags) { +string _arg_expr_split_0_169 = builtin__string_trim_space(builtin__string_replace(builtin__string_to_lower(tags), _S(","), _S(" ")));// new af2 pre/* inserted before */ + t->tags = builtin__string_split(/*af receiver arg*/_arg_expr_split_0_169, _S(" ")); + builtin__string_free(&_arg_expr_split_0_169); // autofreed var main false +} +VV_LOC void main__main(void) { + main__Test test = ((main__Test){.tags = builtin____new_array(0, 0, sizeof(string)),}); + main__Test_set_tags(&test, _S("Hello, World")); + string _t1 = Array_string_str(test.tags); builtin__println(_t1); builtin__string_free(&_t1); + ; +} \ No newline at end of file diff --git a/vlib/v/gen/c/testdata/autofree_method_chain.out b/vlib/v/gen/c/testdata/autofree_method_chain.out new file mode 100644 index 000000000..85fa360ac --- /dev/null +++ b/vlib/v/gen/c/testdata/autofree_method_chain.out @@ -0,0 +1 @@ +['hello', '', 'world'] diff --git a/vlib/v/gen/c/testdata/autofree_method_chain.vv b/vlib/v/gen/c/testdata/autofree_method_chain.vv new file mode 100644 index 000000000..406ec1702 --- /dev/null +++ b/vlib/v/gen/c/testdata/autofree_method_chain.vv @@ -0,0 +1,15 @@ +// vtest vflags: -autofree +pub struct Test { +mut: + tags []string +} + +pub fn (mut t Test) set_tags(tags string) { + t.tags = tags.to_lower().replace(',', ' ').trim_space().split(' ') +} + +fn main() { + mut test := Test{} + test.set_tags('Hello, World') + println(test.tags) +} -- 2.39.5