Actually it already worked since the spec only requires that
the one immediately preceding a for/switch/... be usable as
the target of a break or continue statement.
Added a test.
Also: allocate Function.lblocks on first use.
R=gri
CC=golang-dev
https://golang.org/cl/
7365058
// target is always set; its _break and _continue are set only
// within the body of switch/typeswitch/select/for/range.
// It is effectively an additional default-nil parameter of stmt().
- // TODO(adonovan): fix: handle multiple labels on the same stmt.
var label *lblock
start:
switch s := _s.(type) {
lb := f.lblocks[label.Obj]
if lb == nil {
lb = &lblock{_goto: f.newBasicBlock(label.Name)}
+ if f.lblocks == nil {
+ f.lblocks = make(map[*ast.Object]*lblock)
+ }
f.lblocks[label.Obj] = lb
}
return lb
if f.syntax == nil {
return // synthetic function; no syntax tree
}
- f.lblocks = make(map[*ast.Object]*lblock)
// Receiver (at most one inner iteration).
if f.syntax.recvField != nil {
panic("I.f not called twice")
}
}
+
+// Multiple labels on same statement.
+func multipleLabels() {
+ var trace []int
+ i := 0
+one:
+two:
+ for ; i < 3; i++ {
+ trace = append(trace, i)
+ switch i {
+ case 0:
+ continue two
+ case 1:
+ i++
+ goto one
+ case 2:
+ break two
+ }
+ }
+ if x := fmt.Sprint(trace); x != "[0 1 2]" {
+ panic(x)
+ }
+}
+
+func init() {
+ multipleLabels()
+}