Skip to content

Commit 4cf14a8

Browse files
authored
autofree: remove duplicate free() calls after a return statement, triggered by error string interpolation (#26592)
1 parent afca235 commit 4cf14a8

3 files changed

Lines changed: 23 additions & 2 deletions

File tree

‎vlib/v/gen/c/cgen.v‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,19 +2232,22 @@ fn is_noreturn_callexpr(expr ast.Expr) bool {
22322232
}
22332233

22342234
// stmts_with_tmp_var is used in `if` or `match` branches.
2235-
// It returns true, if the last statement was a `return`
2235+
// It returns true, if the last statement was a `return` or `branch`
22362236
fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) bool {
22372237
g.indent++
22382238
if g.inside_ternary > 0 {
22392239
g.write('(')
22402240
}
22412241
expected_cast_type := g.expected_cast_type
2242+
// Track if last statement was return or branch (for autofree, both skip scope cleanup)
22422243
mut last_stmt_was_return := false
22432244
for i, stmt in stmts {
22442245
if i == stmts.len - 1 {
22452246
g.expected_cast_type = expected_cast_type
22462247
if stmt is ast.Return {
22472248
last_stmt_was_return = true
2249+
} else if stmt is ast.BranchStmt {
2250+
last_stmt_was_return = true
22482251
}
22492252
}
22502253
if i == stmts.len - 1 && tmp_var != '' {
@@ -2402,7 +2405,7 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) bool {
24022405
if g.inside_ternary > 0 {
24032406
g.write2('', ')')
24042407
}
2405-
if g.is_autofree && !g.inside_vweb_tmpl && stmts.len > 0 {
2408+
if g.is_autofree && !g.inside_vweb_tmpl && stmts.len > 0 && !last_stmt_was_return {
24062409
// use the first stmt to get the scope
24072410
stmt := stmts[0]
24082411
if stmt !is ast.FnDecl && g.inside_ternary == 0 {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// vtest vflags: -autofree
2+
// Test that autofree doesn't generate duplicate free statements
3+
// after return in or blocks with string interpolation
4+
5+
fn main() {
6+
x := 'test'
7+
_ := somefn() or {
8+
msg := 'fail'
9+
println('Error: ${msg}')
10+
return
11+
}
12+
println('Success')
13+
}
14+
15+
fn somefn() !int {
16+
return error('test')
17+
}

‎vlib/v/slow_tests/valgrind/valgrind_test.v‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const skip_compile_files = [
2626
]
2727

2828
const skip_valgrind_files = [
29+
'vlib/v/slow_tests/valgrind/autofree_or_block_string_interp.v',
2930
'vlib/v/slow_tests/valgrind/struct_field.v',
3031
'vlib/v/slow_tests/valgrind/fn_returning_string_param.v',
3132
'vlib/v/slow_tests/valgrind/fn_with_return_should_free_local_vars.v',

0 commit comments

Comments
 (0)