diff --git a/src/cmd/compile/internal/syntax/branches.go b/src/cmd/compile/internal/syntax/branches.go index b54a2c7567..a6b533319a 100644 --- a/src/cmd/compile/internal/syntax/branches.go +++ b/src/cmd/compile/internal/syntax/branches.go @@ -25,21 +25,19 @@ func checkBranches(body *BlockStmt, errh ErrorHandler) { // scope of all labels in this body 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 // found for them. Either those labels were never defined, or // they are inside blocks and not reachable from the gotos. for _, go2 := range fwdGo2s { - var msg string name := go2.Label.Value - if alt, found := ls.labels[name]; found { - msg = "goto %s jumps into block" - alt.used = true // avoid "defined and not used" error + if l := ls.labels[name]; l != nil { + l.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 { - 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." @@ -64,7 +62,8 @@ type label struct { type block struct { 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{}) { @@ -128,11 +127,12 @@ const ( continueOk ) -// blockBranches processes a block's body and returns the list of unresolved (forward) gotos. -// parent is the immediately enclosing block (or nil), context provides information about the -// enclosing statements, and lstmt is the labeled statement this body belongs to, or nil. -func (ls *labelScope) blockBranches(parent *block, context uint, lstmt *LabeledStmt, body []Stmt) []*BranchStmt { - b := &block{parent: parent, lstmt: lstmt} +// blockBranches processes a block's body starting at start and returns the +// list of unresolved (forward) gotos. parent is the immediately enclosing +// block (or nil), context provides information about the enclosing statements, +// and lstmt is the labeled statement asociated with this block, or nil. +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 varName Expr @@ -159,8 +159,8 @@ func (ls *labelScope) blockBranches(parent *block, context uint, lstmt *LabeledS return false } - innerBlock := func(flags uint, body []Stmt) { - fwdGo2s = append(fwdGo2s, ls.blockBranches(b, context|flags, lstmt, body)...) + innerBlock := func(flags uint, start src.Pos, body []Stmt) { + fwdGo2s = append(fwdGo2s, ls.blockBranches(b, context|flags, lstmt, start, body)...) } for _, stmt := range body { @@ -277,25 +277,25 @@ func (ls *labelScope) blockBranches(parent *block, context uint, lstmt *LabeledS case *BlockStmt: // Unresolved forward gotos from the nested block // become forward gotos for the current block. - innerBlock(0, s.List) + innerBlock(0, s.Pos(), s.List) case *IfStmt: - innerBlock(0, s.Then.List) + innerBlock(0, s.Then.Pos(), s.Then.List) if s.Else != nil { - innerBlock(0, []Stmt{s.Else}) + innerBlock(0, s.Else.Pos(), []Stmt{s.Else}) } case *ForStmt: - innerBlock(breakOk|continueOk, s.Body.List) + innerBlock(breakOk|continueOk, s.Body.Pos(), s.Body.List) case *SwitchStmt: for _, cc := range s.Body { - innerBlock(breakOk, cc.Body) + innerBlock(breakOk, cc.Pos(), cc.Body) } case *SelectStmt: for _, cc := range s.Body { - innerBlock(breakOk, cc.Body) + innerBlock(breakOk, cc.Pos(), cc.Body) } } } diff --git a/test/goto.go b/test/goto.go index 6630fb7e34..d660c9ce62 100644 --- a/test/goto.go +++ b/test/goto.go @@ -77,7 +77,7 @@ L: // error shows first offending variable 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 y := 1 @@ -87,7 +87,7 @@ L: // goto not okay even if code path is dead 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 y := 1 @@ -114,7 +114,7 @@ L: // goto into inner block not okay 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" L: } @@ -125,12 +125,12 @@ func _() { { // GCCGO_ERROR "block starts here" 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 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" @@ -142,7 +142,7 @@ func _() { // error prefers block diagnostic over declaration diagnostic 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 { // GCCGO_ERROR "block starts here" @@ -179,14 +179,14 @@ L: } 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" L: } } 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" L: } else { @@ -194,7 +194,7 @@ 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 { } else { // GCCGO_ERROR "block starts here" L: @@ -205,13 +205,13 @@ func _() { if false { // GCCGO_ERROR "block starts here" L: } 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 _() { 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" L: } @@ -219,7 +219,7 @@ func _() { func _() { 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" L: } @@ -227,7 +227,7 @@ func _() { func _() { 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" L: } else { @@ -241,7 +241,7 @@ func _() { // really is LINE+1 (like in the previous test), // even though it looks like it might be LINE+3 instead. 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 { // GCCGO_ERROR "block starts here" L: @@ -290,7 +290,7 @@ func _() { for { // GCCGO_ERROR "block starts here" 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 _() { @@ -299,49 +299,49 @@ func _() { L1: } 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 _() { for i < n { // GCCGO_ERROR "block starts here" 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 _() { for i = 0; i < n; i++ { // GCCGO_ERROR "block starts here" 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 _() { for i = range x { // GCCGO_ERROR "block starts here" 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 _() { for i = range c { // GCCGO_ERROR "block starts here" 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 _() { for i = range m { // GCCGO_ERROR "block starts here" 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 _() { for i = range s { // GCCGO_ERROR "block starts here" 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 @@ -395,7 +395,7 @@ 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 { case 0: L: // GCCGO_ERROR "block starts here" @@ -403,7 +403,7 @@ 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 { case 0: L: // GCCGO_ERROR "block starts here" @@ -413,7 +413,7 @@ 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 { case 0: default: @@ -424,7 +424,7 @@ func _() { func _() { switch i { 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: L: // GCCGO_ERROR "block starts here" } @@ -436,7 +436,7 @@ func _() { L: // GCCGO_ERROR "block starts here" ; 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 _() { } 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 { case c <- 1: L: // GCCGO_ERROR "block starts here" @@ -500,7 +500,7 @@ 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 { case c <- 1: L: // GCCGO_ERROR "block starts here" @@ -510,7 +510,7 @@ 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 { case <-c: default: @@ -521,7 +521,7 @@ func _() { func _() { select { 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: L: // GCCGO_ERROR "block starts here" } @@ -533,6 +533,6 @@ func _() { L: // GCCGO_ERROR "block starts here" ; 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" } }