// 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."
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{}) {
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
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 {
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)
}
}
}
// 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
// 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
// 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:
}
{ // 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"
// 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"
}
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 {
}
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:
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:
}
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:
}
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 {
// 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:
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 _() {
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
}
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"
}
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"
}
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:
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"
}
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"
}
}
}
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"
}
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"
}
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:
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"
}
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"
}
}