Commit bb70f517 authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile: report block start for gotos jumping into blocks

Follow-up on https://go-review.googlesource.com/#/c/39998/
which dropped this information.

The reported blocks are the innermost blocks containing a
label jumped to from outside, not the outermost block as
reported originally by cmd/compile.

We could report the outermost block with a slighly more
involved algorithm (need to track containing blocks for
all unresolved forward gotos), but since gccgo also reports
the innermost blocks, the current approach seems good enough.

Change-Id: Ic0235b8fafe8d5f99dc9872b58e90e8d9e72c5db
Reviewed-on: https://go-review.googlesource.com/40980
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarMarvin Stenger <marvin.stenger94@gmail.com>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent 08fe5638
...@@ -25,21 +25,19 @@ func checkBranches(body *BlockStmt, errh ErrorHandler) { ...@@ -25,21 +25,19 @@ func checkBranches(body *BlockStmt, errh ErrorHandler) {
// scope of all labels in this body // scope of all labels in this body
ls := &labelScope{errh: errh} ls := &labelScope{errh: errh}
fwdGo2s := ls.blockBranches(nil, 0, nil, body.List) fwdGo2s := ls.blockBranches(nil, 0, nil, body.Pos(), body.List)
// If there are any forward gotos left, no matching label was // If there are any forward gotos left, no matching label was
// found for them. Either those labels were never defined, or // found for them. Either those labels were never defined, or
// they are inside blocks and not reachable from the gotos. // they are inside blocks and not reachable from the gotos.
for _, go2 := range fwdGo2s { for _, go2 := range fwdGo2s {
var msg string
name := go2.Label.Value name := go2.Label.Value
if alt, found := ls.labels[name]; found { if l := ls.labels[name]; l != nil {
msg = "goto %s jumps into block" l.used = true // avoid "defined and not used" error
alt.used = true // avoid "defined and not used" error ls.err(go2.Label.Pos(), "goto %s jumps into block starting at %s", name, l.parent.start)
} else { } else {
msg = "label %s not defined" ls.err(go2.Label.Pos(), "label %s not defined", name)
} }
ls.err(go2.Label.Pos(), msg, name)
} }
// spec: "It is illegal to define a label that is never used." // spec: "It is illegal to define a label that is never used."
...@@ -64,7 +62,8 @@ type label struct { ...@@ -64,7 +62,8 @@ type label struct {
type block struct { type block struct {
parent *block // immediately enclosing block, or nil parent *block // immediately enclosing block, or nil
lstmt *LabeledStmt // labeled statement to which this block belongs, or nil start src.Pos // start of block
lstmt *LabeledStmt // labeled statement associated with this block, or nil
} }
func (ls *labelScope) err(pos src.Pos, format string, args ...interface{}) { func (ls *labelScope) err(pos src.Pos, format string, args ...interface{}) {
...@@ -128,11 +127,12 @@ const ( ...@@ -128,11 +127,12 @@ const (
continueOk continueOk
) )
// blockBranches processes a block's body and returns the list of unresolved (forward) gotos. // blockBranches processes a block's body starting at start and returns the
// parent is the immediately enclosing block (or nil), context provides information about the // list of unresolved (forward) gotos. parent is the immediately enclosing
// enclosing statements, and lstmt is the labeled statement this body belongs to, or nil. // block (or nil), context provides information about the enclosing statements,
func (ls *labelScope) blockBranches(parent *block, context uint, lstmt *LabeledStmt, body []Stmt) []*BranchStmt { // and lstmt is the labeled statement asociated with this block, or nil.
b := &block{parent: parent, lstmt: lstmt} func (ls *labelScope) blockBranches(parent *block, context uint, lstmt *LabeledStmt, start src.Pos, body []Stmt) []*BranchStmt {
b := &block{parent: parent, start: start, lstmt: lstmt}
var varPos src.Pos var varPos src.Pos
var varName Expr var varName Expr
...@@ -159,8 +159,8 @@ func (ls *labelScope) blockBranches(parent *block, context uint, lstmt *LabeledS ...@@ -159,8 +159,8 @@ func (ls *labelScope) blockBranches(parent *block, context uint, lstmt *LabeledS
return false return false
} }
innerBlock := func(flags uint, body []Stmt) { innerBlock := func(flags uint, start src.Pos, body []Stmt) {
fwdGo2s = append(fwdGo2s, ls.blockBranches(b, context|flags, lstmt, body)...) fwdGo2s = append(fwdGo2s, ls.blockBranches(b, context|flags, lstmt, start, body)...)
} }
for _, stmt := range body { for _, stmt := range body {
...@@ -277,25 +277,25 @@ func (ls *labelScope) blockBranches(parent *block, context uint, lstmt *LabeledS ...@@ -277,25 +277,25 @@ func (ls *labelScope) blockBranches(parent *block, context uint, lstmt *LabeledS
case *BlockStmt: case *BlockStmt:
// Unresolved forward gotos from the nested block // Unresolved forward gotos from the nested block
// become forward gotos for the current block. // become forward gotos for the current block.
innerBlock(0, s.List) innerBlock(0, s.Pos(), s.List)
case *IfStmt: case *IfStmt:
innerBlock(0, s.Then.List) innerBlock(0, s.Then.Pos(), s.Then.List)
if s.Else != nil { if s.Else != nil {
innerBlock(0, []Stmt{s.Else}) innerBlock(0, s.Else.Pos(), []Stmt{s.Else})
} }
case *ForStmt: case *ForStmt:
innerBlock(breakOk|continueOk, s.Body.List) innerBlock(breakOk|continueOk, s.Body.Pos(), s.Body.List)
case *SwitchStmt: case *SwitchStmt:
for _, cc := range s.Body { for _, cc := range s.Body {
innerBlock(breakOk, cc.Body) innerBlock(breakOk, cc.Pos(), cc.Body)
} }
case *SelectStmt: case *SelectStmt:
for _, cc := range s.Body { for _, cc := range s.Body {
innerBlock(breakOk, cc.Body) innerBlock(breakOk, cc.Pos(), cc.Body)
} }
} }
} }
......
...@@ -77,7 +77,7 @@ L: ...@@ -77,7 +77,7 @@ L:
// error shows first offending variable // error shows first offending variable
func _() { func _() {
goto L // ERROR "goto L jumps over declaration of x at LINE+1|goto L jumps over declaration of y at LINE+3|goto jumps over declaration" goto L // ERROR "goto L jumps over declaration of y at LINE+3|goto jumps over declaration"
x := 1 // GCCGO_ERROR "defined here" x := 1 // GCCGO_ERROR "defined here"
_ = x _ = x
y := 1 y := 1
...@@ -87,7 +87,7 @@ L: ...@@ -87,7 +87,7 @@ L:
// goto not okay even if code path is dead // goto not okay even if code path is dead
func _() { func _() {
goto L // ERROR "goto L jumps over declaration of x at LINE+1|goto L jumps over declaration of y at LINE+3|goto jumps over declaration" goto L // ERROR "goto L jumps over declaration of y at LINE+3|goto jumps over declaration"
x := 1 // GCCGO_ERROR "defined here" x := 1 // GCCGO_ERROR "defined here"
_ = x _ = x
y := 1 y := 1
...@@ -114,7 +114,7 @@ L: ...@@ -114,7 +114,7 @@ L:
// goto into inner block not okay // goto into inner block not okay
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
{ // GCCGO_ERROR "block starts here" { // GCCGO_ERROR "block starts here"
L: L:
} }
...@@ -125,12 +125,12 @@ func _() { ...@@ -125,12 +125,12 @@ func _() {
{ // GCCGO_ERROR "block starts here" { // GCCGO_ERROR "block starts here"
L: L:
} }
goto L // ERROR "goto L jumps into block starting at LINE-3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
} }
// error shows first (outermost) offending block // error shows first (outermost) offending block
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
{ {
{ {
{ // GCCGO_ERROR "block starts here" { // GCCGO_ERROR "block starts here"
...@@ -142,7 +142,7 @@ func _() { ...@@ -142,7 +142,7 @@ func _() {
// error prefers block diagnostic over declaration diagnostic // error prefers block diagnostic over declaration diagnostic
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
x := 1 x := 1
_ = x _ = x
{ // GCCGO_ERROR "block starts here" { // GCCGO_ERROR "block starts here"
...@@ -179,14 +179,14 @@ L: ...@@ -179,14 +179,14 @@ L:
} }
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
if true { // GCCGO_ERROR "block starts here" if true { // GCCGO_ERROR "block starts here"
L: L:
} }
} }
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
if true { // GCCGO_ERROR "block starts here" if true { // GCCGO_ERROR "block starts here"
L: L:
} else { } else {
...@@ -194,7 +194,7 @@ func _() { ...@@ -194,7 +194,7 @@ func _() {
} }
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
if true { if true {
} else { // GCCGO_ERROR "block starts here" } else { // GCCGO_ERROR "block starts here"
L: L:
...@@ -205,13 +205,13 @@ func _() { ...@@ -205,13 +205,13 @@ func _() {
if false { // GCCGO_ERROR "block starts here" if false { // GCCGO_ERROR "block starts here"
L: L:
} else { } else {
goto L // ERROR "goto L jumps into block starting at LINE-3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
} }
} }
func _() { func _() {
if true { if true {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
} else { // GCCGO_ERROR "block starts here" } else { // GCCGO_ERROR "block starts here"
L: L:
} }
...@@ -219,7 +219,7 @@ func _() { ...@@ -219,7 +219,7 @@ func _() {
func _() { func _() {
if true { if true {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
} else if false { // GCCGO_ERROR "block starts here" } else if false { // GCCGO_ERROR "block starts here"
L: L:
} }
...@@ -227,7 +227,7 @@ func _() { ...@@ -227,7 +227,7 @@ func _() {
func _() { func _() {
if true { if true {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
} else if false { // GCCGO_ERROR "block starts here" } else if false { // GCCGO_ERROR "block starts here"
L: L:
} else { } else {
...@@ -241,7 +241,7 @@ func _() { ...@@ -241,7 +241,7 @@ func _() {
// really is LINE+1 (like in the previous test), // really is LINE+1 (like in the previous test),
// even though it looks like it might be LINE+3 instead. // even though it looks like it might be LINE+3 instead.
if true { if true {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
} else if false { } else if false {
} else { // GCCGO_ERROR "block starts here" } else { // GCCGO_ERROR "block starts here"
L: L:
...@@ -290,7 +290,7 @@ func _() { ...@@ -290,7 +290,7 @@ func _() {
for { // GCCGO_ERROR "block starts here" for { // GCCGO_ERROR "block starts here"
L: L:
} }
goto L // ERROR "goto L jumps into block starting at LINE-3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
} }
func _() { func _() {
...@@ -299,49 +299,49 @@ func _() { ...@@ -299,49 +299,49 @@ func _() {
L1: L1:
} }
L: L:
goto L1 // ERROR "goto L1 jumps into block starting at LINE-5|goto L1 jumps into block|goto jumps into block" goto L1 // ERROR "goto L1 jumps into block starting at LINE-5|goto jumps into block"
} }
func _() { func _() {
for i < n { // GCCGO_ERROR "block starts here" for i < n { // GCCGO_ERROR "block starts here"
L: L:
} }
goto L // ERROR "goto L jumps into block starting at LINE-3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
} }
func _() { func _() {
for i = 0; i < n; i++ { // GCCGO_ERROR "block starts here" for i = 0; i < n; i++ { // GCCGO_ERROR "block starts here"
L: L:
} }
goto L // ERROR "goto L jumps into block starting at LINE-3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
} }
func _() { func _() {
for i = range x { // GCCGO_ERROR "block starts here" for i = range x { // GCCGO_ERROR "block starts here"
L: L:
} }
goto L // ERROR "goto L jumps into block starting at LINE-3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
} }
func _() { func _() {
for i = range c { // GCCGO_ERROR "block starts here" for i = range c { // GCCGO_ERROR "block starts here"
L: L:
} }
goto L // ERROR "goto L jumps into block starting at LINE-3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
} }
func _() { func _() {
for i = range m { // GCCGO_ERROR "block starts here" for i = range m { // GCCGO_ERROR "block starts here"
L: L:
} }
goto L // ERROR "goto L jumps into block starting at LINE-3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
} }
func _() { func _() {
for i = range s { // GCCGO_ERROR "block starts here" for i = range s { // GCCGO_ERROR "block starts here"
L: L:
} }
goto L // ERROR "goto L jumps into block starting at LINE-3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
} }
// switch // switch
...@@ -395,7 +395,7 @@ func _() { ...@@ -395,7 +395,7 @@ func _() {
} }
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
switch i { switch i {
case 0: case 0:
L: // GCCGO_ERROR "block starts here" L: // GCCGO_ERROR "block starts here"
...@@ -403,7 +403,7 @@ func _() { ...@@ -403,7 +403,7 @@ func _() {
} }
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
switch i { switch i {
case 0: case 0:
L: // GCCGO_ERROR "block starts here" L: // GCCGO_ERROR "block starts here"
...@@ -413,7 +413,7 @@ func _() { ...@@ -413,7 +413,7 @@ func _() {
} }
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
switch i { switch i {
case 0: case 0:
default: default:
...@@ -424,7 +424,7 @@ func _() { ...@@ -424,7 +424,7 @@ func _() {
func _() { func _() {
switch i { switch i {
default: default:
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
case 0: case 0:
L: // GCCGO_ERROR "block starts here" L: // GCCGO_ERROR "block starts here"
} }
...@@ -436,7 +436,7 @@ func _() { ...@@ -436,7 +436,7 @@ func _() {
L: // GCCGO_ERROR "block starts here" L: // GCCGO_ERROR "block starts here"
; ;
default: default:
goto L // ERROR "goto L jumps into block starting at LINE-4|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-4|goto jumps into block"
} }
} }
...@@ -492,7 +492,7 @@ func _() { ...@@ -492,7 +492,7 @@ func _() {
} }
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+2|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
select { select {
case c <- 1: case c <- 1:
L: // GCCGO_ERROR "block starts here" L: // GCCGO_ERROR "block starts here"
...@@ -500,7 +500,7 @@ func _() { ...@@ -500,7 +500,7 @@ func _() {
} }
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+2|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
select { select {
case c <- 1: case c <- 1:
L: // GCCGO_ERROR "block starts here" L: // GCCGO_ERROR "block starts here"
...@@ -510,7 +510,7 @@ func _() { ...@@ -510,7 +510,7 @@ func _() {
} }
func _() { func _() {
goto L // ERROR "goto L jumps into block starting at LINE+3|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
select { select {
case <-c: case <-c:
default: default:
...@@ -521,7 +521,7 @@ func _() { ...@@ -521,7 +521,7 @@ func _() {
func _() { func _() {
select { select {
default: default:
goto L // ERROR "goto L jumps into block starting at LINE+1|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
case <-c: case <-c:
L: // GCCGO_ERROR "block starts here" L: // GCCGO_ERROR "block starts here"
} }
...@@ -533,6 +533,6 @@ func _() { ...@@ -533,6 +533,6 @@ func _() {
L: // GCCGO_ERROR "block starts here" L: // GCCGO_ERROR "block starts here"
; ;
default: default:
goto L // ERROR "goto L jumps into block starting at LINE-4|goto L jumps into block|goto jumps into block" goto L // ERROR "goto L jumps into block starting at LINE-4|goto jumps into block"
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment