gen: fix bug where unreached defer is executed (#8594)
parent
de9813233f
commit
fe9d062b41
|
@ -333,6 +333,7 @@ pub:
|
|||
skip_gen bool // this function doesn't need to be generated (for example [if foo])
|
||||
pub mut:
|
||||
stmts []Stmt
|
||||
defer_stmts []DeferStmt
|
||||
return_type table.Type
|
||||
has_return bool
|
||||
comments []Comment // comments *after* the header, but *before* `{`; used for InterfaceDecl
|
||||
|
@ -891,7 +892,8 @@ pub:
|
|||
stmts []Stmt
|
||||
pos token.Position
|
||||
pub mut:
|
||||
ifdef string
|
||||
ifdef string
|
||||
idx_in_fn int = -1 // index in FnDecl.defer_stmts
|
||||
}
|
||||
|
||||
// `(3+4)`
|
||||
|
|
|
@ -3130,6 +3130,10 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
c.inside_const = false
|
||||
}
|
||||
ast.DeferStmt {
|
||||
if node.idx_in_fn < 0 {
|
||||
node.idx_in_fn = c.cur_fn.defer_stmts.len
|
||||
c.cur_fn.defer_stmts << &node
|
||||
}
|
||||
c.stmts(node.stmts)
|
||||
}
|
||||
ast.EnumDecl {
|
||||
|
|
|
@ -994,6 +994,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
ast.DeferStmt {
|
||||
mut defer_stmt := node
|
||||
defer_stmt.ifdef = g.defer_ifdef
|
||||
g.writeln('${g.defer_flag_var(defer_stmt)} = true;')
|
||||
g.defer_stmts << defer_stmt
|
||||
}
|
||||
ast.EnumDecl {
|
||||
|
@ -1280,6 +1281,8 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
fn (mut g Gen) write_defer_stmts() {
|
||||
for defer_stmt in g.defer_stmts {
|
||||
g.writeln('// Defer begin')
|
||||
g.writeln('if (${g.defer_flag_var(defer_stmt)} == true) {')
|
||||
g.indent++
|
||||
if defer_stmt.ifdef.len > 0 {
|
||||
g.writeln(defer_stmt.ifdef)
|
||||
g.stmts(defer_stmt.stmts)
|
||||
|
@ -1290,6 +1293,8 @@ fn (mut g Gen) write_defer_stmts() {
|
|||
g.stmts(defer_stmt.stmts)
|
||||
g.indent++
|
||||
}
|
||||
g.indent--
|
||||
g.writeln('}')
|
||||
g.writeln('// Defer end')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,10 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
|
|||
g.cur_generic_types = []
|
||||
return
|
||||
}
|
||||
cur_fn_save := g.cur_fn
|
||||
defer {
|
||||
g.cur_fn = cur_fn_save
|
||||
}
|
||||
g.cur_fn = node
|
||||
fn_start_pos := g.out.len
|
||||
g.write_v_source_line_info(node.pos)
|
||||
|
@ -131,6 +135,10 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
|
|||
if is_live_wrap {
|
||||
impl_fn_name = 'impl_live_$name'
|
||||
}
|
||||
last_fn_c_name_save := g.last_fn_c_name
|
||||
defer {
|
||||
g.last_fn_c_name = last_fn_c_name_save
|
||||
}
|
||||
g.last_fn_c_name = impl_fn_name
|
||||
//
|
||||
if is_live_wrap {
|
||||
|
@ -179,6 +187,9 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
|
|||
}
|
||||
g.definitions.writeln(');')
|
||||
g.writeln(') {')
|
||||
for defer_stmt in node.defer_stmts {
|
||||
g.writeln('bool ${g.defer_flag_var(defer_stmt)} = false;')
|
||||
}
|
||||
if is_live_wrap {
|
||||
// The live function just calls its implementation dual, while ensuring
|
||||
// that the call is wrapped by the mutex lock & unlock calls.
|
||||
|
@ -258,6 +269,10 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
|
|||
}
|
||||
}
|
||||
|
||||
fn (g &Gen) defer_flag_var(stmt &ast.DeferStmt) string {
|
||||
return '${g.last_fn_c_name}_defer_$stmt.idx_in_fn'
|
||||
}
|
||||
|
||||
fn (mut g Gen) write_defer_stmts_when_needed() {
|
||||
if g.defer_stmts.len > 0 {
|
||||
g.write_defer_stmts()
|
||||
|
|
|
@ -27,8 +27,7 @@ fn set_num(i int, mut n Num) {
|
|||
println('Hi')
|
||||
if i < 5 {
|
||||
return
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
n.val++
|
||||
}
|
||||
}
|
||||
|
@ -60,15 +59,18 @@ fn test_defer_early_exit() {
|
|||
|
||||
fn test_defer_option() {
|
||||
mut ok := Num{0}
|
||||
set_num_opt(mut ok) or {}
|
||||
set_num_opt(mut ok) or { }
|
||||
assert ok.val == 1
|
||||
}
|
||||
|
||||
fn test_defer_with_anon_fn() {
|
||||
mut f := &Num{val: 110}
|
||||
mut f := &Num{
|
||||
val: 110
|
||||
}
|
||||
defer {
|
||||
assert f.add(1) == 111
|
||||
}
|
||||
|
||||
go fn () {
|
||||
defer {
|
||||
println('deferred 1')
|
||||
|
@ -83,3 +85,19 @@ fn test_defer_with_anon_fn() {
|
|||
x()
|
||||
return
|
||||
}
|
||||
|
||||
fn set_num_if(mut n Num, v int, cond bool) {
|
||||
if cond {
|
||||
defer {
|
||||
n.val = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_defer_with_if() {
|
||||
mut n := Num{0}
|
||||
set_num_if(mut n, 10, true)
|
||||
assert n.val == 10
|
||||
set_num_if(mut n, 20, false)
|
||||
assert n.val == 10
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue