From 805da2325f8d2102b19c07b4b4a0210f1a5790df Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Tue, 8 Dec 2020 14:21:19 +1100 Subject: [PATCH] cgen: defer was broken in presence of anon fn. fixed #7171 --- vlib/v/gen/fn.v | 9 ++++++++- vlib/v/tests/defer_test.v | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index f63d8d8bf0..c115a5d66d 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -149,11 +149,19 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) { if g.pref.is_prof { g.profile_fn(it) } + // we could be in an anon fn so save outer fn defer stmts + prev_defer_stmts := g.defer_stmts + g.defer_stmts = [] g.stmts(it.stmts) // if it.return_type == table.void_type { g.write_defer_stmts_when_needed() } + if it.is_anon { + g.defer_stmts = prev_defer_stmts + } else { + g.defer_stmts = [] + } if it.return_type != table.void_type && it.stmts.len > 0 && it.stmts.last() !is ast.Return { default_expr := g.type_default(it.return_type) // TODO: perf? @@ -164,7 +172,6 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) { } } g.writeln('}') - g.defer_stmts = [] if g.pref.printfn_list.len > 0 && g.last_fn_c_name in g.pref.printfn_list { println(g.out.after(fn_start_pos)) } diff --git a/vlib/v/tests/defer_test.v b/vlib/v/tests/defer_test.v index 684dc9f6e7..1289d228a6 100644 --- a/vlib/v/tests/defer_test.v +++ b/vlib/v/tests/defer_test.v @@ -45,6 +45,10 @@ mut: val int } +fn (n Num) add(i int) int { + return n.val + i +} + fn test_defer_early_exit() { mut sum := Num{0} for i in 0 .. 10 { @@ -59,3 +63,23 @@ fn test_defer_option() { set_num_opt(mut ok) or {} assert ok.val == 1 } + +fn test_defer_with_anon_fn() { + mut f := &Num{val: 110} + defer { + assert f.add(1) == 111 + } + go fn () { + defer { + println('deferred 1') + } + }() + x := fn () { + defer { + println('defered 2') + } + return + } + x() + return +} \ No newline at end of file