checker: check goto label exists (#8523)
parent
82482167ce
commit
de37b52d4b
|
@ -337,6 +337,7 @@ pub mut:
|
|||
next_comments []Comment // coments that are one line after the decl; used for InterfaceDecl
|
||||
source_file &File = 0
|
||||
scope &Scope
|
||||
label_names []string
|
||||
}
|
||||
|
||||
pub struct GenericParam {
|
||||
|
|
|
@ -3273,6 +3273,9 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
}
|
||||
ast.GotoLabel {}
|
||||
ast.GotoStmt {
|
||||
if node.name !in c.cur_fn.label_names {
|
||||
c.error('unknown label `$node.name`', node.pos)
|
||||
}
|
||||
// TODO: check label doesn't bypass variable declarations
|
||||
}
|
||||
ast.HashStmt {
|
||||
|
@ -5281,7 +5284,6 @@ pub fn (mut c Checker) offset_of(node ast.OffsetOf) table.Type {
|
|||
c.error('first argument of __offsetof must be struct', node.pos)
|
||||
return table.u32_type
|
||||
}
|
||||
|
||||
if !c.table.struct_has_field(node.struct_type, node.field) {
|
||||
c.error('struct `$sym.name` has no field called `$node.field`', node.pos)
|
||||
}
|
||||
|
@ -5540,7 +5542,6 @@ fn (mut c Checker) fetch_and_verify_orm_fields(info table.Struct, pos token.Posi
|
|||
fn (mut c Checker) post_process_generic_fns() {
|
||||
// Loop thru each generic function concrete type.
|
||||
// Check each specific fn instantiation.
|
||||
|
||||
for i in 0 .. c.file.generic_fns.len {
|
||||
if c.table.fn_gen_types.len == 0 {
|
||||
// no concrete types, so just skip:
|
||||
|
@ -5689,7 +5690,6 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||
}
|
||||
c.fn_scope = node.scope
|
||||
c.stmts(node.stmts)
|
||||
|
||||
if c.fn_mut_arg_names.len > 0 {
|
||||
c.fn_mut_arg_names.clear()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
vlib/v/checker/tests/goto_label.vv:5:7: error: unknown label `a1`
|
||||
3 | goto f2
|
||||
4 | f1:
|
||||
5 | goto a1
|
||||
| ~~
|
||||
6 | _ = fn(){
|
||||
7 | goto f1
|
||||
vlib/v/checker/tests/goto_label.vv:7:8: error: unknown label `f1`
|
||||
5 | goto a1
|
||||
6 | _ = fn(){
|
||||
7 | goto f1
|
||||
| ~~
|
||||
8 | goto f2
|
||||
9 | goto a1
|
||||
vlib/v/checker/tests/goto_label.vv:8:8: error: unknown label `f2`
|
||||
6 | _ = fn(){
|
||||
7 | goto f1
|
||||
8 | goto f2
|
||||
| ~~
|
||||
9 | goto a1
|
||||
10 | a1:
|
||||
vlib/v/checker/tests/goto_label.vv:14:7: error: unknown label `a1`
|
||||
12 | }
|
||||
13 | f2:
|
||||
14 | goto a1
|
||||
| ~~
|
||||
15 | goto f1 // back
|
||||
16 | goto f2
|
||||
vlib/v/checker/tests/goto_label.vv:22:7: error: unknown label `f1`
|
||||
20 | goto g1 // forward
|
||||
21 | g1:
|
||||
22 | goto f1
|
||||
| ~~
|
||||
23 | goto a1
|
||||
24 | goto g1 // back
|
||||
vlib/v/checker/tests/goto_label.vv:23:7: error: unknown label `a1`
|
||||
21 | g1:
|
||||
22 | goto f1
|
||||
23 | goto a1
|
||||
| ~~
|
||||
24 | goto g1 // back
|
||||
25 | goto undefined
|
||||
vlib/v/checker/tests/goto_label.vv:25:7: error: unknown label `undefined`
|
||||
23 | goto a1
|
||||
24 | goto g1 // back
|
||||
25 | goto undefined
|
||||
| ~~~~~~~~~
|
||||
26 | }
|
||||
27 |
|
|
@ -0,0 +1,32 @@
|
|||
fn f() {
|
||||
goto f1 // forward
|
||||
goto f2
|
||||
f1:
|
||||
goto a1
|
||||
_ = fn(){
|
||||
goto f1
|
||||
goto f2
|
||||
goto a1
|
||||
a1:
|
||||
goto a1
|
||||
}
|
||||
f2:
|
||||
goto a1
|
||||
goto f1 // back
|
||||
goto f2
|
||||
}
|
||||
|
||||
fn g() {
|
||||
goto g1 // forward
|
||||
g1:
|
||||
goto f1
|
||||
goto a1
|
||||
goto g1 // back
|
||||
goto undefined
|
||||
}
|
||||
|
||||
// implicit main
|
||||
goto m1
|
||||
m1:
|
||||
goto m1
|
||||
|
|
@ -427,7 +427,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
|||
is_builtin: p.builtin_mod || p.mod in util.builtin_module_parts
|
||||
attrs: p.attrs
|
||||
scope: p.scope
|
||||
label_names: p.label_names
|
||||
}
|
||||
p.label_names = []
|
||||
p.close_scope()
|
||||
return fn_decl
|
||||
}
|
||||
|
@ -514,8 +516,13 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
|||
p.error_with_pos('unexpected `$p.tok.kind` after anonymous function signature, expecting `{`',
|
||||
p.tok.position())
|
||||
}
|
||||
mut label_names := []string{}
|
||||
if p.tok.kind == .lcbr {
|
||||
tmp := p.label_names
|
||||
p.label_names = []
|
||||
stmts = p.parse_block_no_scope(false)
|
||||
label_names = p.label_names
|
||||
p.label_names = tmp
|
||||
}
|
||||
p.close_scope()
|
||||
mut func := table.Fn{
|
||||
|
@ -542,6 +549,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
|||
pos: pos.extend(p.prev_tok.position())
|
||||
file: p.file_name
|
||||
scope: p.scope
|
||||
label_names: label_names
|
||||
}
|
||||
typ: typ
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ mut:
|
|||
warnings []errors.Warning
|
||||
vet_errors []vet.Error
|
||||
cur_fn_name string
|
||||
label_names []string
|
||||
in_generic_params bool // indicates if parsing between `<` and `>` of a method/function
|
||||
name_error bool // indicates if the token is not a name or the name is on another line
|
||||
}
|
||||
|
@ -552,6 +553,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
|
|||
file: p.file_name
|
||||
return_type: table.void_type
|
||||
scope: p.scope
|
||||
label_names: p.label_names
|
||||
}
|
||||
} else if p.pref.is_fmt {
|
||||
return p.stmt(false)
|
||||
|
@ -656,6 +658,10 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
|||
// `label:`
|
||||
spos := p.tok.position()
|
||||
name := p.check_name()
|
||||
if name in p.label_names {
|
||||
p.error_with_pos('duplicate label `$name`', spos)
|
||||
}
|
||||
p.label_names << name
|
||||
p.next()
|
||||
if p.tok.kind == .key_for {
|
||||
mut stmt := p.stmt(is_top_level)
|
||||
|
|
Loading…
Reference in New Issue