cgen,autofree: fix method chaining generating invalid c code (fix #9094) (#25315)

This commit is contained in:
CreeperFace 2025-09-16 07:14:41 +02:00 committed by GitHub
parent d2174e47a5
commit 0dbbed7bde
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 50 additions and 3 deletions

View File

@ -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 {

View File

@ -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, ...)`

View File

@ -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.

View File

@ -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);
;
}

View File

@ -0,0 +1 @@
['hello', '', 'world']

View File

@ -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)
}