Skip to content

Commit db8fb16

Browse files
authored
cgen: fix defer stmts with if exprs and or blocks that return a value (#25651)
1 parent 2ad8339 commit db8fb16

File tree

11 files changed

+90
-11
lines changed

11 files changed

+90
-11
lines changed

vlib/v/gen/c/assign.v

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,22 @@ fn (mut g Gen) expr_with_opt_or_block(expr ast.Expr, expr_typ ast.Type, var_expr
3434
defer {
3535
g.inside_or_block = false
3636
}
37-
stmts := (expr as ast.Ident).or_expr.stmts
37+
or_expr := (expr as ast.Ident).or_expr
38+
stmts := or_expr.stmts
39+
scope := or_expr.scope
3840
// handles stmt block which returns something
3941
// e.g. { return none }
4042
if stmts.len > 0 && stmts.last() is ast.ExprStmt && stmts.last().typ != ast.void_type {
41-
g.gen_or_block_stmts(c_name(var_expr.str()), '', stmts, ret_typ, false)
43+
g.gen_or_block_stmts(c_name(var_expr.str()), '', stmts, ret_typ, false,
44+
scope, expr.pos())
4245
} else {
4346
// handles stmt block which doesn't returns value
4447
// e.g. { return }
4548
g.stmts(stmts)
4649
if stmts.len > 0 && stmts.last() is ast.ExprStmt {
4750
g.writeln(';')
4851
}
52+
g.write_defer_stmts(scope, false, expr.pos())
4953
}
5054
}
5155
g.writeln('}')

vlib/v/gen/c/cgen.v

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7237,7 +7237,7 @@ fn (mut g Gen) sort_structs(typesa []&ast.TypeSymbol) []&ast.TypeSymbol {
72377237
}
72387238

72397239
fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast.Stmt, return_type ast.Type,
7240-
is_option bool) {
7240+
is_option bool, scope &ast.Scope, pos token.Pos) {
72417241
g.indent++
72427242
for i, stmt in stmts {
72437243
if i == stmts.len - 1 {
@@ -7247,6 +7247,7 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
72477247
|| expr_stmt.typ in [ast.none_type, ast.error_type]) {
72487248
// `return foo() or { error('failed') }`
72497249
if g.cur_fn != unsafe { nil } {
7250+
g.write_defer_stmts(scope, true, pos)
72507251
if g.cur_fn.return_type.has_flag(.result) {
72517252
g.write('return ')
72527253
g.gen_result_error(g.cur_fn.return_type, expr_stmt.expr)
@@ -7262,6 +7263,7 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
72627263
g.write('${cvar_name} = ')
72637264
g.gen_option_error(return_type, expr_stmt.expr)
72647265
g.writeln(';')
7266+
g.write_defer_stmts(scope, false, pos)
72657267
} else if return_type == ast.rvoid_type {
72667268
// fn returns !, do not fill var.data
72677269
old_inside_opt_data := g.inside_opt_data
@@ -7318,6 +7320,7 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
73187320
g.write(', sizeof(${cast_typ}))')
73197321
}
73207322
g.writeln(';')
7323+
g.write_defer_stmts(scope, return_wrapped, pos)
73217324
g.stmt_path_pos.delete_last()
73227325
if return_wrapped {
73237326
g.writeln('return ${cvar_name};')
@@ -7376,13 +7379,19 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
73767379
}
73777380
stmts := or_block.stmts
73787381
if stmts.len > 0 && stmts.last() is ast.ExprStmt && stmts.last().typ != ast.void_type {
7379-
g.gen_or_block_stmts(cvar_name, mr_styp, stmts, return_type, true)
7382+
g.gen_or_block_stmts(cvar_name, mr_styp, stmts, return_type, true, or_block.scope,
7383+
or_block.pos)
73807384
} else {
73817385
g.stmts(stmts)
7382-
if stmts.len > 0 && stmts.last() is ast.ExprStmt {
7383-
g.writeln(';')
7386+
if stmts.len > 0 {
7387+
stmt_last := stmts.last()
7388+
if stmt_last is ast.ExprStmt {
7389+
g.writeln(';')
7390+
}
7391+
if stmt_last !in [ast.Return, ast.BranchStmt] {
7392+
g.write_defer_stmts(or_block.scope, false, or_block.pos)
7393+
}
73847394
}
7385-
g.write_defer_stmts(or_block.scope, false, or_block.pos)
73867395
}
73877396
g.or_expr_return_type = ast.void_type
73887397
} else if or_block.kind == .propagate_result

vlib/v/gen/c/if.v

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -484,18 +484,19 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
484484
g.expected_cast_type = node.typ
485485
}
486486
g.stmts_with_tmp_var(branch.stmts, tmp)
487+
g.write_defer_stmts(branch.scope, false, node.pos)
487488
g.expected_cast_type = prev_expected_cast_type
488-
if !is_else && (branch.stmts.len > 0
489-
&& branch.stmts[branch.stmts.len - 1] !in [ast.Return, ast.BranchStmt]) {
489+
if !is_else
490+
&& (branch.stmts.len > 0 && branch.stmts.last() !in [ast.Return, ast.BranchStmt]) {
490491
g.writeln('\tgoto ${exit_label};')
491492
}
492493
} else {
493494
// restore if_expr stmt header pos
494495
stmt_pos := g.nth_stmt_pos(0)
495496
g.stmts(branch.stmts)
497+
g.write_defer_stmts(branch.scope, false, node.pos)
496498
g.stmt_path_pos << stmt_pos
497499
}
498-
g.write_defer_stmts(branch.scope, false, node.pos)
499500
}
500501
if node.branches.len > 0 {
501502
g.writeln('}')

vlib/v/tests/defer/defer_fixed_array_test.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// vtest vflags: -scoped-defer
2+
13
fn foo() {
24
a := [u8(1), 2, 3]!
35
defer {

vlib/v/tests/defer/defer_if_comptime_test.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// vtest vflags: -scoped-defer
2+
13
fn test_main() {
24
defer {
35
$if foo ? {

vlib/v/tests/defer/defer_return_test.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// vtest vflags: -scoped-defer
2+
13
@[heap]
24
struct Hwe {
35
mut:

vlib/v/tests/defer/defer_static_test.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// vtest vflags: -scoped-defer
2+
13
@[unsafe]
24
fn g() {
35
mut static levels := 0

vlib/v/tests/defer/defer_test.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// vtest vflags: -scoped-defer
2+
13
fn foo() string {
24
println('foo()')
35
return 'foo'

vlib/v/tests/defer/defer_use_returned_value_test.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// vtest vflags: -scoped-defer
2+
13
struct Test {
24
mut:
35
a int

vlib/v/tests/defer/defer_with_fn_var_test.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// vtest vflags: -scoped-defer
2+
13
@[has_globals]
24
module main
35

0 commit comments

Comments
 (0)