Skip to content

Commit 8002234

Browse files
authored
checker: error/warn when using defer(fn) inside function-scope and lock stmts (#25681)
1 parent 186d35f commit 8002234

File tree

7 files changed

+68
-32
lines changed

7 files changed

+68
-32
lines changed

vlib/v/checker/checker.v

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,35 +2348,7 @@ fn (mut c Checker) stmt(mut node ast.Stmt) {
23482348
c.inside_const = false
23492349
}
23502350
ast.DeferStmt {
2351-
c.inside_defer = true
2352-
if node.idx_in_fn < 0 && c.table.cur_fn != unsafe { nil } {
2353-
node.idx_in_fn = c.table.cur_fn.defer_stmts.len
2354-
c.table.cur_fn.defer_stmts << unsafe { &node }
2355-
}
2356-
if c.locked_names.len != 0 || c.rlocked_names.len != 0 {
2357-
c.error('defers are not allowed in lock statements', node.pos)
2358-
}
2359-
for i, ident in node.defer_vars {
2360-
mut id := ident
2361-
if mut id.info is ast.IdentVar {
2362-
if id.comptime && (id.tok_kind == .question
2363-
|| id.name in ast.valid_comptime_not_user_defined) {
2364-
node.defer_vars[i] = ast.Ident{
2365-
scope: unsafe { nil }
2366-
name: ''
2367-
}
2368-
continue
2369-
}
2370-
typ := c.ident(mut id)
2371-
if typ == ast.error_type_idx {
2372-
continue
2373-
}
2374-
id.info.typ = typ
2375-
node.defer_vars[i] = id
2376-
}
2377-
}
2378-
c.stmts(mut node.stmts)
2379-
c.inside_defer = false
2351+
c.defer_stmt(mut node)
23802352
}
23812353
ast.EnumDecl {
23822354
c.enum_decl(mut node)
@@ -2449,6 +2421,44 @@ fn (mut c Checker) stmt(mut node ast.Stmt) {
24492421
}
24502422
}
24512423

2424+
fn (mut c Checker) defer_stmt(mut node ast.DeferStmt) {
2425+
c.inside_defer = true
2426+
if node.idx_in_fn < 0 && c.table.cur_fn != unsafe { nil } {
2427+
node.idx_in_fn = c.table.cur_fn.defer_stmts.len
2428+
c.table.cur_fn.defer_stmts << unsafe { &node }
2429+
}
2430+
if node.mode == .function {
2431+
if !isnil(c.fn_scope) && node.scope == c.fn_scope {
2432+
c.warn('`defer` is already in function scope; just use `defer {` instead',
2433+
node.pos)
2434+
}
2435+
if c.locked_names.len != 0 || c.rlocked_names.len != 0 {
2436+
c.error('`defer(fn)`s are not allowed in lock statements', node.pos)
2437+
}
2438+
}
2439+
for i, ident in node.defer_vars {
2440+
mut id := ident
2441+
if mut id.info is ast.IdentVar {
2442+
if id.comptime
2443+
&& (id.tok_kind == .question || id.name in ast.valid_comptime_not_user_defined) {
2444+
node.defer_vars[i] = ast.Ident{
2445+
scope: unsafe { nil }
2446+
name: ''
2447+
}
2448+
continue
2449+
}
2450+
typ := c.ident(mut id)
2451+
if typ == ast.error_type_idx {
2452+
continue
2453+
}
2454+
id.info.typ = typ
2455+
node.defer_vars[i] = id
2456+
}
2457+
}
2458+
c.stmts(mut node.stmts)
2459+
c.inside_defer = false
2460+
}
2461+
24522462
fn (mut c Checker) assert_stmt(mut node ast.AssertStmt) {
24532463
cur_exp_typ := c.expected_type
24542464
c.expected_type = ast.bool_type
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
vlib/v/checker/tests/defer_fn_inside_fn_scope.vv:3:2: warning: `defer` is already in function scope; just use `defer {` instead
2+
1 | fn main() {
3+
2 | defer {} // ok
4+
3 | defer(fn) {} // fail
5+
| ~~~~~~~~~~~~
6+
4 | }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
defer {} // ok
3+
defer(fn) {} // fail
4+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/checker/tests/defer_fn_inside_lock_stmt_err.vv:7:3: error: `defer(fn)`s are not allowed in lock statements
2+
5 | lock x {
3+
6 | defer {} // ok
4+
7 | defer(fn) {} // fail
5+
| ~~~~~~~~~~~~
6+
8 | _ = x
7+
9 | }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
struct St {}
2+
3+
fn main() {
4+
shared x := St{}
5+
lock x {
6+
defer {} // ok
7+
defer(fn) {} // fail
8+
_ = x
9+
}
10+
}

vlib/v/fmt/tests/defer_mode_expected.vv

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ fn main() {
88
}
99
println('exit fn main().scope.1')
1010
}
11-
1211
defer(fn) {
1312
println('defer(fn)')
1413
}

vlib/v/parser/parser.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,7 @@ fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
11281128
}
11291129
.key_defer {
11301130
if !p.inside_defer {
1131+
spos := p.tok.pos()
11311132
p.next()
11321133
mut defer_mode := ast.DeferMode.scoped
11331134
if p.tok.kind == .lpar {
@@ -1145,7 +1146,6 @@ fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
11451146
}
11461147
p.check(.rpar)
11471148
}
1148-
spos := p.tok.pos()
11491149
p.inside_defer = true
11501150
p.defer_vars = []ast.Ident{}
11511151
stmts := p.parse_block()
@@ -1155,7 +1155,7 @@ fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
11551155
scope: p.scope
11561156
stmts: stmts
11571157
defer_vars: p.defer_vars.clone()
1158-
pos: spos.extend_with_last_line(p.tok.pos(), p.prev_tok.line_nr)
1158+
pos: spos.extend_with_last_line(p.prev_tok.pos(), p.prev_tok.line_nr)
11591159
}
11601160
} else {
11611161
return p.error_with_pos('`defer` blocks cannot be nested', p.tok.pos())

0 commit comments

Comments
 (0)