cmd/compile: correctly import labels, gotos, and fallthroughs

The importer had several bugs with respect to labels and gotos:
- it didn't create a new ONAME node for label names (label dcl,
  goto, continue, and break)
- it overwrote the symbol for gotos with the dclstack
- it didn't set the dclstack for labels

In the process changed export format slightly to always assume
a label name for labels and gotos, and never assume a label for
fallthroughs.

For fallthroughs and switch cases, now also set Xoffset like in
the parser. (Not setting it, i.e., using 0 was ok since this is
only used for verifying correct use of fallthroughs, which was
checked already. But it's an extra level of verification of the
import.)

Fixes #15838.

Change-Id: I3637f6314b8651c918df0c8cd70cd858c92bd483
Reviewed-on: https://go-review.googlesource.com/23445
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Robert Griesemer 2016-05-25 16:38:02 -07:00
parent b9ec0024fb
commit 30282b091d
5 changed files with 100 additions and 10 deletions

View file

@ -1488,19 +1488,18 @@ func (p *exporter) stmt(n *Node) {
p.stmtList(n.List)
p.stmtList(n.Nbody)
case OFALL:
op = OXFALL
fallthrough
case OFALL, OXFALL:
p.op(OXFALL)
case OBREAK, OCONTINUE, OGOTO, OXFALL:
case OBREAK, OCONTINUE:
p.op(op)
p.exprsOrNil(n.Left, nil)
case OEMPTY:
// nothing to emit
case OLABEL:
p.op(OLABEL)
case OGOTO, OLABEL:
p.op(op)
p.expr(n.Left)
default:

View file

@ -1038,6 +1038,7 @@ func (p *importer) node() *Node {
case OXCASE:
markdcl()
n := Nod(OXCASE, nil, nil)
n.Xoffset = int64(block)
n.List.Set(p.exprList())
// TODO(gri) eventually we must declare variables for type switch
// statements (type switch statements are not yet exported)
@ -1048,16 +1049,24 @@ func (p *importer) node() *Node {
// case OFALL:
// unreachable - mapped to OXFALL case below by exporter
case OBREAK, OCONTINUE, OGOTO, OXFALL:
case OXFALL:
n := Nod(OXFALL, nil, nil)
n.Xoffset = int64(block)
return n
case OBREAK, OCONTINUE:
left, _ := p.exprsOrNil()
if left != nil {
left = newname(left.Sym)
}
return Nod(op, left, nil)
// case OEMPTY:
// unreachable - not emitted by exporter
case OLABEL:
n := Nod(OLABEL, p.expr(), nil)
n.Left.Sym = dclstack // context, for goto restrictions
case OGOTO, OLABEL:
n := Nod(op, newname(p.expr().Sym), nil)
n.Sym = dclstack // context, for goto restrictions
return n
case OEND:

View file

@ -0,0 +1,61 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package a
func F1() {
L:
goto L
}
func F2() {
L:
for {
break L
}
}
func F3() {
L:
for {
continue L
}
}
func F4() {
switch {
case true:
fallthrough
default:
}
}
type T struct{}
func (T) M1() {
L:
goto L
}
func (T) M2() {
L:
for {
break L
}
}
func (T) M3() {
L:
for {
continue L
}
}
func (T) M4() {
switch {
case true:
fallthrough
default:
}
}

View file

@ -0,0 +1,9 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package b
import "./a"
type T struct{ a.T }

View file

@ -0,0 +1,12 @@
// compiledir
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test cases for issue #15838, and related failures.
// Make sure the importer correctly sets up nodes for
// label decls, goto, continue, break, and fallthrough
// statements.
package ignored