Skip to content

Commit 1754094

Browse files
authored
cgen: fix -autofree used for code doing "string ${f(@vexe)} interpolation" (#26521)
1 parent 11bf3dd commit 1754094

9 files changed

Lines changed: 75 additions & 19 deletions

.gitignore

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ vls.log
139139
# ignore Intellij files
140140
.idea/
141141
/*.iml
142+
143+
#ignore generated files:
142144
wasm.v
143-
TAGS
144-
tags
145145

146146
# ignore large GTK *.gir files
147147
Gtk-4.0.gir
@@ -150,6 +150,11 @@ Gtk-4.0.gir
150150
vlib/builtin/js/*.js
151151
vlib/v/tests/*.js
152152

153+
#ignore tags indexes, used by emacs/vim:
154+
ETAGS
155+
TAGS
156+
tags
157+
153158
# ignore the old regexp based v.ctags file (people using universal ctags < 6.1.0, can still benefit from them)
154159
.ctags.d/v.ctags
155160

@@ -160,3 +165,8 @@ bench/vectors/obj
160165
autofuzz.log
161166
.project.gf
162167
.aider*
168+
169+
#ignore common file names for bugs/reproductions
170+
bug*
171+
issue*
172+

vlib/toml/ast/types.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub type Key = Bare | Bool | Null | Number | Quoted
1313
// str returns the string representation of the key. This is implemented
1414
// by all the variants of Key.
1515
pub fn (k Key) str() string {
16-
return k.text
16+
return k.text.clone()
1717
}
1818

1919
// Value is a sumtype representing all possible value types

vlib/v/gen/c/cgen.v

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3868,14 +3868,13 @@ fn (mut g Gen) expr(node_ ast.Expr) {
38683868
}
38693869
g.call_expr(node)
38703870
if g.is_autofree && !g.is_builtin_mod && !g.is_js_call && g.strs_to_free0.len == 0
3871-
&& !g.inside_lambda {
3871+
&& !g.is_autofree_tmp && !g.inside_lambda {
38723872
// if len != 0, that means we are handling call expr inside call expr (arg)
38733873
// and it'll get messed up here, since it's handled recursively in autofree_call_pregen()
38743874
// so just skip it
38753875
g.autofree_call_pregen(node)
38763876
if g.strs_to_free0.len > 0 {
3877-
g.insert_at(stmt_before_call_expr_pos, g.strs_to_free0.join('\n') +
3878-
'/* inserted before */')
3877+
g.insert_at(stmt_before_call_expr_pos, g.strs_to_free0.join('\n'))
38793878
}
38803879
g.strs_to_free0 = []
38813880
}

vlib/v/gen/c/fn.v

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,7 +2405,7 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
24052405
g.is_autofree = old_is_autofree
24062406
g.is_autofree_tmp = false
24072407
s += expr_code
2408-
s += ';// new af2 pre'
2408+
s += ';'
24092409
g.strs_to_free0 << s
24102410
// This tmp arg var will be freed with the rest of the vars at the end of the scope.
24112411
}
@@ -2630,18 +2630,22 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
26302630
// some c fn definitions dont have args (cfns.v) or are not updated in checker
26312631
// when these are fixed we wont need this check
26322632
if i < expected_types.len {
2633-
if use_tmp_var_autofree {
2634-
if arg.is_tmp_autofree { // && !g.is_js_call {
2635-
// We saved expressions in temp variables so that they can be freed later.
2636-
// `foo(str + str2) => x := str + str2; foo(x); x.free()`
2637-
// g.write('_arg_expr_${g.called_fn_name}_${i}')
2638-
// Use these variables here.
2639-
fn_name := node.name.replace('.', '_')
2640-
// name := '_tt${g.tmp_count_af}_arg_expr_${fn_name}_${i}'
2641-
name := '_arg_expr_${fn_name}_${i + 1}_${node.pos.pos}'
2633+
mut wrote_tmp_arg := false
2634+
if use_tmp_var_autofree && arg.is_tmp_autofree { // && !g.is_js_call {
2635+
// We saved expressions in temp variables so that they can be freed later.
2636+
// `foo(str + str2) => x := str + str2; foo(x); x.free()`
2637+
// g.write('_arg_expr_${g.called_fn_name}_${i}')
2638+
// Use these variables here.
2639+
fn_name := node.name.replace('.', '_')
2640+
// name := '_tt${g.tmp_count_af}_arg_expr_${fn_name}_${i}'
2641+
name := '_arg_expr_${fn_name}_${i + 1}_${node.pos.pos}'
2642+
scope := g.file.scope.innermost(node.pos.pos)
2643+
if !g.is_autofree_tmp || scope.known_var(name) {
26422644
g.write('/*autofree arg*/' + name)
2645+
wrote_tmp_arg = true
26432646
}
2644-
} else {
2647+
}
2648+
if !wrote_tmp_arg {
26452649
g.ref_or_deref_arg(arg, expected_types[i], node.language, is_smartcast)
26462650
}
26472651
} else {

vlib/v/gen/c/str_intp.v

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,32 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int, fmts []u8) {
208208
g.expr(expr)
209209
g.write(')')
210210
} else {
211+
if g.is_autofree_tmp && g.is_autofree
212+
&& expr !in [ast.Ident, ast.StringLiteral, ast.SelectorExpr, ast.ComptimeSelector] {
213+
if expr is ast.CallExpr {
214+
old_is_autofree_tmp := g.is_autofree_tmp
215+
g.autofree_call_pregen(expr)
216+
g.is_autofree_tmp = old_is_autofree_tmp
217+
}
218+
tmp := g.new_tmp_var()
219+
tmp_pos := expr.pos()
220+
mut scope := g.file.scope.innermost(tmp_pos.pos)
221+
scope.register(ast.Var{
222+
name: tmp
223+
typ: ast.string_type
224+
is_autofree_tmp: true
225+
pos: tmp_pos
226+
})
227+
pos_before := g.out.len
228+
if expr.is_auto_deref_var() && fmt != `p` {
229+
g.write('*')
230+
}
231+
g.expr(expr)
232+
expr_code := g.out.cut_to(pos_before).trim_space()
233+
g.strs_to_free0 << 'string ${tmp} = ${expr_code};'
234+
g.write(tmp)
235+
return
236+
}
211237
if expr.is_auto_deref_var() && fmt != `p` {
212238
g.write('*')
213239
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
void main__Test_set_tags(main__Test* t, string tags) {
2-
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 */
2+
string _arg_expr_split_0_169 = builtin__string_trim_space(builtin__string_replace(builtin__string_to_lower(tags), _S(","), _S(" ")));
33
t->tags = builtin__string_split(/*af receiver arg*/_arg_expr_split_0_169, _S(" "));
44
builtin__string_free(&_arg_expr_split_0_169); // autofreed var main false
55
}
@@ -8,4 +8,4 @@ VV_LOC void main__main(void) {
88
main__Test_set_tags(&test, _S("Hello, World"));
99
string _t1 = Array_string_str(test.tags); builtin__println(_t1); builtin__string_free(&_t1);
1010
;
11-
}
11+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
string _arg_expr_os_execute_1_
2+
= builtin__str_intp
3+
os__Result res = os__execute(/*autofree arg*/_arg_expr_os_execute_1_
4+
string _arg_expr_println_1_
5+
= builtin__string_trim_space(res.output);
6+
builtin__println(/*autofree arg*/_arg_expr_println_1_
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
0
2+
123
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// vtest vflags: -autofree
2+
import os
3+
4+
fn main() {
5+
name := ' println(123)'
6+
res := os.execute('${os.quoted_path(@VEXE)} -e "${name[2..]}" ')
7+
println(res.exit_code)
8+
println(res.output.trim_space())
9+
}

0 commit comments

Comments
 (0)