@@ -16,8 +16,8 @@ type builder struct {
16
16
cfg * CFG
17
17
mayReturn func (* ast.CallExpr ) bool
18
18
current * Block
19
- lblocks map [* ast. Object ]* lblock // labeled blocks
20
- targets * targets // linked stack of branch targets
19
+ lblocks map [string ]* lblock // labeled blocks
20
+ targets * targets // linked stack of branch targets
21
21
}
22
22
23
23
func (b * builder ) stmt (_s ast.Stmt ) {
42
42
b .add (s )
43
43
if call , ok := s .X .(* ast.CallExpr ); ok && ! b .mayReturn (call ) {
44
44
// Calls to panic, os.Exit, etc, never return.
45
- b .current = b .newBlock ("unreachable.call" )
45
+ b .current = b .newBlock (KindUnreachable , s )
46
46
}
47
47
48
48
case * ast.DeclStmt :
@@ -57,15 +57,15 @@ start:
57
57
}
58
58
59
59
case * ast.LabeledStmt :
60
- label = b .labeledBlock (s .Label )
60
+ label = b .labeledBlock (s .Label , s )
61
61
b .jump (label ._goto )
62
62
b .current = label ._goto
63
63
_s = s .Stmt
64
64
goto start // effectively: tailcall stmt(g, s.Stmt, label)
65
65
66
66
case * ast.ReturnStmt :
67
67
b .add (s )
68
- b .current = b .newBlock ("unreachable.return" )
68
+ b .current = b .newBlock (KindUnreachable , s )
69
69
70
70
case * ast.BranchStmt :
71
71
b .branchStmt (s )
@@ -77,11 +77,11 @@ start:
77
77
if s .Init != nil {
78
78
b .stmt (s .Init )
79
79
}
80
- then := b .newBlock ("if.then" )
81
- done := b .newBlock ("if.done" )
80
+ then := b .newBlock (KindIfThen , s )
81
+ done := b .newBlock (KindIfDone , s )
82
82
_else := done
83
83
if s .Else != nil {
84
- _else = b .newBlock ("if.else" )
84
+ _else = b .newBlock (KindIfElse , s )
85
85
}
86
86
b .add (s .Cond )
87
87
b .ifelse (then , _else )
@@ -128,7 +128,7 @@ func (b *builder) branchStmt(s *ast.BranchStmt) {
128
128
switch s .Tok {
129
129
case token .BREAK :
130
130
if s .Label != nil {
131
- if lb := b .labeledBlock (s .Label ); lb != nil {
131
+ if lb := b .labeledBlock (s .Label , nil ); lb != nil {
132
132
block = lb ._break
133
133
}
134
134
} else {
@@ -139,7 +139,7 @@ func (b *builder) branchStmt(s *ast.BranchStmt) {
139
139
140
140
case token .CONTINUE :
141
141
if s .Label != nil {
142
- if lb := b .labeledBlock (s .Label ); lb != nil {
142
+ if lb := b .labeledBlock (s .Label , nil ); lb != nil {
143
143
block = lb ._continue
144
144
}
145
145
} else {
@@ -155,14 +155,14 @@ func (b *builder) branchStmt(s *ast.BranchStmt) {
155
155
156
156
case token .GOTO :
157
157
if s .Label != nil {
158
- block = b .labeledBlock (s .Label )._goto
158
+ block = b .labeledBlock (s .Label , nil )._goto
159
159
}
160
160
}
161
- if block == nil {
162
- block = b .newBlock ("undefined.branch" )
161
+ if block == nil { // ill-typed (e.g. undefined label)
162
+ block = b .newBlock (KindUnreachable , s )
163
163
}
164
164
b .jump (block )
165
- b .current = b .newBlock ("unreachable.branch" )
165
+ b .current = b .newBlock (KindUnreachable , s )
166
166
}
167
167
168
168
func (b * builder ) switchStmt (s * ast.SwitchStmt , label * lblock ) {
@@ -172,7 +172,7 @@ func (b *builder) switchStmt(s *ast.SwitchStmt, label *lblock) {
172
172
if s .Tag != nil {
173
173
b .add (s .Tag )
174
174
}
175
- done := b .newBlock ("switch.done" )
175
+ done := b .newBlock (KindSwitchDone , s )
176
176
if label != nil {
177
177
label ._break = done
178
178
}
@@ -188,13 +188,13 @@ func (b *builder) switchStmt(s *ast.SwitchStmt, label *lblock) {
188
188
for i , clause := range s .Body .List {
189
189
body := fallthru
190
190
if body == nil {
191
- body = b .newBlock ("switch.body" ) // first case only
191
+ body = b .newBlock (KindSwitchCaseBody , clause ) // first case only
192
192
}
193
193
194
194
// Preallocate body block for the next case.
195
195
fallthru = done
196
196
if i + 1 < ncases {
197
- fallthru = b .newBlock ("switch.body" )
197
+ fallthru = b .newBlock (KindSwitchCaseBody , s . Body . List [ i + 1 ] )
198
198
}
199
199
200
200
cc := clause .(* ast.CaseClause )
@@ -208,7 +208,7 @@ func (b *builder) switchStmt(s *ast.SwitchStmt, label *lblock) {
208
208
209
209
var nextCond * Block
210
210
for _ , cond := range cc .List {
211
- nextCond = b .newBlock ("switch.next" )
211
+ nextCond = b .newBlock (KindSwitchNextCase , cc )
212
212
b .add (cond ) // one half of the tag==cond condition
213
213
b .ifelse (body , nextCond )
214
214
b .current = nextCond
@@ -247,7 +247,7 @@ func (b *builder) typeSwitchStmt(s *ast.TypeSwitchStmt, label *lblock) {
247
247
b .add (s .Assign )
248
248
}
249
249
250
- done := b .newBlock ("typeswitch.done" )
250
+ done := b .newBlock (KindSwitchDone , s )
251
251
if label != nil {
252
252
label ._break = done
253
253
}
@@ -258,10 +258,10 @@ func (b *builder) typeSwitchStmt(s *ast.TypeSwitchStmt, label *lblock) {
258
258
default_ = cc
259
259
continue
260
260
}
261
- body := b .newBlock ("typeswitch.body" )
261
+ body := b .newBlock (KindSwitchCaseBody , cc )
262
262
var next * Block
263
263
for _ , casetype := range cc .List {
264
- next = b .newBlock ("typeswitch.next" )
264
+ next = b .newBlock (KindSwitchNextCase , cc )
265
265
// casetype is a type, so don't call b.add(casetype).
266
266
// This block logically contains a type assertion,
267
267
// x.(casetype), but it's unclear how to represent x.
@@ -300,7 +300,7 @@ func (b *builder) selectStmt(s *ast.SelectStmt, label *lblock) {
300
300
}
301
301
}
302
302
303
- done := b .newBlock ("select.done" )
303
+ done := b .newBlock (KindSelectDone , s )
304
304
if label != nil {
305
305
label ._break = done
306
306
}
@@ -312,8 +312,8 @@ func (b *builder) selectStmt(s *ast.SelectStmt, label *lblock) {
312
312
defaultBody = & clause .Body
313
313
continue
314
314
}
315
- body := b .newBlock ("select.body" )
316
- next := b .newBlock ("select.next" )
315
+ body := b .newBlock (KindSelectCaseBody , clause )
316
+ next := b .newBlock (KindSelectAfterCase , clause )
317
317
b .ifelse (body , next )
318
318
b .current = body
319
319
b .targets = & targets {
@@ -358,15 +358,15 @@ func (b *builder) forStmt(s *ast.ForStmt, label *lblock) {
358
358
if s .Init != nil {
359
359
b .stmt (s .Init )
360
360
}
361
- body := b .newBlock ("for.body" )
362
- done := b .newBlock ("for.done" ) // target of 'break'
363
- loop := body // target of back-edge
361
+ body := b .newBlock (KindForBody , s )
362
+ done := b .newBlock (KindForDone , s ) // target of 'break'
363
+ loop := body // target of back-edge
364
364
if s .Cond != nil {
365
- loop = b .newBlock ("for.loop" )
365
+ loop = b .newBlock (KindForLoop , s )
366
366
}
367
367
cont := loop // target of 'continue'
368
368
if s .Post != nil {
369
- cont = b .newBlock ("for.post" )
369
+ cont = b .newBlock (KindForPost , s )
370
370
}
371
371
if label != nil {
372
372
label ._break = done
@@ -414,12 +414,12 @@ func (b *builder) rangeStmt(s *ast.RangeStmt, label *lblock) {
414
414
// jump loop
415
415
// done: (target of break)
416
416
417
- loop := b .newBlock ("range.loop" )
417
+ loop := b .newBlock (KindRangeLoop , s )
418
418
b .jump (loop )
419
419
b .current = loop
420
420
421
- body := b .newBlock ("range.body" )
422
- done := b .newBlock ("range.done" )
421
+ body := b .newBlock (KindRangeBody , s )
422
+ done := b .newBlock (KindRangeDone , s )
423
423
b .ifelse (body , done )
424
424
b .current = body
425
425
@@ -461,14 +461,19 @@ type lblock struct {
461
461
462
462
// labeledBlock returns the branch target associated with the
463
463
// specified label, creating it if needed.
464
- func (b * builder ) labeledBlock (label * ast.Ident ) * lblock {
465
- lb := b .lblocks [label .Obj ]
464
+ func (b * builder ) labeledBlock (label * ast.Ident , stmt * ast. LabeledStmt ) * lblock {
465
+ lb := b .lblocks [label .Name ]
466
466
if lb == nil {
467
- lb = & lblock {_goto : b .newBlock (label . Name )}
467
+ lb = & lblock {_goto : b .newBlock (KindLabel , nil )}
468
468
if b .lblocks == nil {
469
- b .lblocks = make (map [* ast. Object ]* lblock )
469
+ b .lblocks = make (map [string ]* lblock )
470
470
}
471
- b .lblocks [label .Obj ] = lb
471
+ b .lblocks [label .Name ] = lb
472
+ }
473
+ // Fill in the label later (in case of forward goto).
474
+ // Stmt may be set already if labels are duplicated (ill-typed).
475
+ if stmt != nil && lb ._goto .Stmt == nil {
476
+ lb ._goto .Stmt = stmt
472
477
}
473
478
return lb
474
479
}
@@ -477,11 +482,12 @@ func (b *builder) labeledBlock(label *ast.Ident) *lblock {
477
482
// slice and returns it.
478
483
// It does not automatically become the current block.
479
484
// comment is an optional string for more readable debugging output.
480
- func (b * builder ) newBlock (comment string ) * Block {
485
+ func (b * builder ) newBlock (kind BlockKind , stmt ast. Stmt ) * Block {
481
486
g := b .cfg
482
487
block := & Block {
483
- Index : int32 (len (g .Blocks )),
484
- comment : comment ,
488
+ Index : int32 (len (g .Blocks )),
489
+ Kind : kind ,
490
+ Stmt : stmt ,
485
491
}
486
492
block .Succs = block .succs2 [:0 ]
487
493
g .Blocks = append (g .Blocks , block )
0 commit comments