1
2
3
4
5 package types2
6
7 import (
8 "cmd/compile/internal/syntax"
9 )
10
11
12 func (check *Checker) labels(body *syntax.BlockStmt) {
13
14 all := NewScope(nil, body.Pos(), syntax.EndPos(body), "label")
15
16 fwdJumps := check.blockBranches(all, nil, nil, body.List)
17
18
19
20
21
22 for _, jmp := range fwdJumps {
23 var msg string
24 name := jmp.Label.Value
25 if alt := all.Lookup(name); alt != nil {
26 msg = "goto %s jumps into block"
27 alt.(*Label).used = true
28 } else {
29 msg = "label %s not declared"
30 }
31 check.errorf(jmp.Label, msg, name)
32 }
33
34
35 for name, obj := range all.elems {
36 obj = resolve(name, obj)
37 if lbl := obj.(*Label); !lbl.used {
38 check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
39 }
40 }
41 }
42
43
44 type block struct {
45 parent *block
46 lstmt *syntax.LabeledStmt
47 labels map[string]*syntax.LabeledStmt
48 }
49
50
51
52 func (b *block) insert(s *syntax.LabeledStmt) {
53 name := s.Label.Value
54 if debug {
55 assert(b.gotoTarget(name) == nil)
56 }
57 labels := b.labels
58 if labels == nil {
59 labels = make(map[string]*syntax.LabeledStmt)
60 b.labels = labels
61 }
62 labels[name] = s
63 }
64
65
66
67 func (b *block) gotoTarget(name string) *syntax.LabeledStmt {
68 for s := b; s != nil; s = s.parent {
69 if t := s.labels[name]; t != nil {
70 return t
71 }
72 }
73 return nil
74 }
75
76
77
78 func (b *block) enclosingTarget(name string) *syntax.LabeledStmt {
79 for s := b; s != nil; s = s.parent {
80 if t := s.lstmt; t != nil && t.Label.Value == name {
81 return t
82 }
83 }
84 return nil
85 }
86
87
88
89
90 func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *syntax.LabeledStmt, list []syntax.Stmt) []*syntax.BranchStmt {
91 b := &block{parent, lstmt, nil}
92
93 var (
94 varDeclPos syntax.Pos
95 fwdJumps, badJumps []*syntax.BranchStmt
96 )
97
98
99
100
101 recordVarDecl := func(pos syntax.Pos) {
102 varDeclPos = pos
103 badJumps = append(badJumps[:0], fwdJumps...)
104 }
105
106 jumpsOverVarDecl := func(jmp *syntax.BranchStmt) bool {
107 if varDeclPos.IsKnown() {
108 for _, bad := range badJumps {
109 if jmp == bad {
110 return true
111 }
112 }
113 }
114 return false
115 }
116
117 var stmtBranches func(syntax.Stmt)
118 stmtBranches = func(s syntax.Stmt) {
119 switch s := s.(type) {
120 case *syntax.DeclStmt:
121 for _, d := range s.DeclList {
122 if d, _ := d.(*syntax.VarDecl); d != nil {
123 recordVarDecl(d.Pos())
124 }
125 }
126
127 case *syntax.LabeledStmt:
128
129 if name := s.Label.Value; name != "_" {
130 lbl := NewLabel(s.Label.Pos(), check.pkg, name)
131 if alt := all.Insert(lbl); alt != nil {
132 var err error_
133 err.soft = true
134 err.errorf(lbl.pos, "label %s already declared", name)
135 err.recordAltDecl(alt)
136 check.report(&err)
137
138 } else {
139 b.insert(s)
140 check.recordDef(s.Label, lbl)
141 }
142
143 i := 0
144 for _, jmp := range fwdJumps {
145 if jmp.Label.Value == name {
146
147 lbl.used = true
148 check.recordUse(jmp.Label, lbl)
149 if jumpsOverVarDecl(jmp) {
150 check.softErrorf(
151 jmp.Label,
152 "goto %s jumps over variable declaration at line %d",
153 name,
154 varDeclPos.Line(),
155 )
156
157 }
158 } else {
159
160 fwdJumps[i] = jmp
161 i++
162 }
163 }
164 fwdJumps = fwdJumps[:i]
165 lstmt = s
166 }
167 stmtBranches(s.Stmt)
168
169 case *syntax.BranchStmt:
170 if s.Label == nil {
171 return
172 }
173
174
175 name := s.Label.Value
176 switch s.Tok {
177 case syntax.Break:
178
179
180
181 valid := false
182 if t := b.enclosingTarget(name); t != nil {
183 switch t.Stmt.(type) {
184 case *syntax.SwitchStmt, *syntax.SelectStmt, *syntax.ForStmt:
185 valid = true
186 }
187 }
188 if !valid {
189 check.errorf(s.Label, "invalid break label %s", name)
190 return
191 }
192
193 case syntax.Continue:
194
195
196 valid := false
197 if t := b.enclosingTarget(name); t != nil {
198 switch t.Stmt.(type) {
199 case *syntax.ForStmt:
200 valid = true
201 }
202 }
203 if !valid {
204 check.errorf(s.Label, "invalid continue label %s", name)
205 return
206 }
207
208 case syntax.Goto:
209 if b.gotoTarget(name) == nil {
210
211 fwdJumps = append(fwdJumps, s)
212 return
213 }
214
215 default:
216 check.errorf(s, invalidAST+"branch statement: %s %s", s.Tok, name)
217 return
218 }
219
220
221 obj := all.Lookup(name)
222 obj.(*Label).used = true
223 check.recordUse(s.Label, obj)
224
225 case *syntax.AssignStmt:
226 if s.Op == syntax.Def {
227 recordVarDecl(s.Pos())
228 }
229
230 case *syntax.BlockStmt:
231
232
233 fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, s.List)...)
234
235 case *syntax.IfStmt:
236 stmtBranches(s.Then)
237 if s.Else != nil {
238 stmtBranches(s.Else)
239 }
240
241 case *syntax.SwitchStmt:
242 b := &block{b, lstmt, nil}
243 for _, s := range s.Body {
244 fwdJumps = append(fwdJumps, check.blockBranches(all, b, nil, s.Body)...)
245 }
246
247 case *syntax.SelectStmt:
248 b := &block{b, lstmt, nil}
249 for _, s := range s.Body {
250 fwdJumps = append(fwdJumps, check.blockBranches(all, b, nil, s.Body)...)
251 }
252
253 case *syntax.ForStmt:
254 stmtBranches(s.Body)
255 }
256 }
257
258 for _, s := range list {
259 stmtBranches(s)
260 }
261
262 return fwdJumps
263 }
264
View as plain text