mirror of
https://github.com/golang/go
synced 2024-11-02 13:42:29 +00:00
bb70f517e9
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: Marvin Stenger <marvin.stenger94@gmail.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
538 lines
8.4 KiB
Go
538 lines
8.4 KiB
Go
// errorcheck
|
|
|
|
// Copyright 2011 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.
|
|
|
|
// Verify goto semantics.
|
|
// Does not compile.
|
|
//
|
|
// Each test is in a separate function just so that if the
|
|
// compiler stops processing after one error, we don't
|
|
// lose other ones.
|
|
|
|
package main
|
|
|
|
var (
|
|
i, n int
|
|
x []int
|
|
c chan int
|
|
m map[int]int
|
|
s string
|
|
)
|
|
|
|
// goto after declaration okay
|
|
func _() {
|
|
x := 1
|
|
goto L
|
|
L:
|
|
_ = x
|
|
}
|
|
|
|
// goto before declaration okay
|
|
func _() {
|
|
goto L
|
|
L:
|
|
x := 1
|
|
_ = x
|
|
}
|
|
|
|
// goto across declaration not okay
|
|
func _() {
|
|
goto L // ERROR "goto L jumps over declaration of x at LINE+1|goto jumps over declaration"
|
|
x := 1 // GCCGO_ERROR "defined here"
|
|
_ = x
|
|
L:
|
|
}
|
|
|
|
// goto across declaration in inner scope okay
|
|
func _() {
|
|
goto L
|
|
{
|
|
x := 1
|
|
_ = x
|
|
}
|
|
L:
|
|
}
|
|
|
|
// goto across declaration after inner scope not okay
|
|
func _() {
|
|
goto L // ERROR "goto L jumps over declaration of x at LINE+5|goto jumps over declaration"
|
|
{
|
|
x := 1
|
|
_ = x
|
|
}
|
|
x := 1 // GCCGO_ERROR "defined here"
|
|
_ = x
|
|
L:
|
|
}
|
|
|
|
// goto across declaration in reverse okay
|
|
func _() {
|
|
L:
|
|
x := 1
|
|
_ = x
|
|
goto L
|
|
}
|
|
|
|
// error shows first offending variable
|
|
func _() {
|
|
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
|
|
_ = y
|
|
L:
|
|
}
|
|
|
|
// goto not okay even if code path is dead
|
|
func _() {
|
|
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
|
|
_ = y
|
|
return
|
|
L:
|
|
}
|
|
|
|
// goto into outer block okay
|
|
func _() {
|
|
{
|
|
goto L
|
|
}
|
|
L:
|
|
}
|
|
|
|
// goto backward into outer block okay
|
|
func _() {
|
|
L:
|
|
{
|
|
goto L
|
|
}
|
|
}
|
|
|
|
// goto into inner block not okay
|
|
func _() {
|
|
goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
|
|
{ // GCCGO_ERROR "block starts here"
|
|
L:
|
|
}
|
|
}
|
|
|
|
// goto backward into inner block still not okay
|
|
func _() {
|
|
{ // GCCGO_ERROR "block starts here"
|
|
L:
|
|
}
|
|
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+3|goto jumps into block"
|
|
{
|
|
{
|
|
{ // GCCGO_ERROR "block starts here"
|
|
L:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// error prefers block diagnostic over declaration diagnostic
|
|
func _() {
|
|
goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
|
|
x := 1
|
|
_ = x
|
|
{ // GCCGO_ERROR "block starts here"
|
|
L:
|
|
}
|
|
}
|
|
|
|
// many kinds of blocks, all invalid to jump into or among,
|
|
// but valid to jump out of
|
|
|
|
// if
|
|
|
|
func _() {
|
|
L:
|
|
if true {
|
|
goto L
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
L:
|
|
if true {
|
|
goto L
|
|
} else {
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
L:
|
|
if false {
|
|
} else {
|
|
goto L
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
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 jumps into block"
|
|
if true { // GCCGO_ERROR "block starts here"
|
|
L:
|
|
} else {
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
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:
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
if false { // GCCGO_ERROR "block starts here"
|
|
L:
|
|
} else {
|
|
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 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 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 jumps into block"
|
|
} else if false { // GCCGO_ERROR "block starts here"
|
|
L:
|
|
} else {
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
// This one is tricky. There is an implicit scope
|
|
// starting at the second if statement, and it contains
|
|
// the final else, so the outermost offending scope
|
|
// 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+2|goto jumps into block"
|
|
} else if false {
|
|
} else { // GCCGO_ERROR "block starts here"
|
|
L:
|
|
}
|
|
}
|
|
|
|
/* Want to enable these tests but gofmt mangles them. Issue 1972.
|
|
|
|
func _() {
|
|
// This one is okay, because the else is in the
|
|
// implicit whole-if block and has no inner block
|
|
// (no { }) around it.
|
|
if true {
|
|
goto L
|
|
} else
|
|
L:
|
|
}
|
|
|
|
func _() {
|
|
// Still not okay.
|
|
if true { //// GCCGO_ERROR "block starts here"
|
|
L:
|
|
} else
|
|
goto L //// ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
|
|
}
|
|
|
|
*/
|
|
|
|
// for
|
|
|
|
func _() {
|
|
for {
|
|
goto L
|
|
}
|
|
L:
|
|
}
|
|
|
|
func _() {
|
|
for {
|
|
goto L
|
|
L:
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
for { // GCCGO_ERROR "block starts here"
|
|
L:
|
|
}
|
|
goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
|
|
}
|
|
|
|
func _() {
|
|
for { // GCCGO_ERROR "block starts here"
|
|
goto L
|
|
L1:
|
|
}
|
|
L:
|
|
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 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 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 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 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 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 jumps into block"
|
|
}
|
|
|
|
// switch
|
|
|
|
func _() {
|
|
L:
|
|
switch i {
|
|
case 0:
|
|
goto L
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
L:
|
|
switch i {
|
|
case 0:
|
|
|
|
default:
|
|
goto L
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
switch i {
|
|
case 0:
|
|
|
|
default:
|
|
L:
|
|
goto L
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
switch i {
|
|
case 0:
|
|
|
|
default:
|
|
goto L
|
|
L:
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
switch i {
|
|
case 0:
|
|
goto L
|
|
L:
|
|
;
|
|
default:
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
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+2|goto jumps into block"
|
|
switch i {
|
|
case 0:
|
|
L: // GCCGO_ERROR "block starts here"
|
|
;
|
|
default:
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
|
|
switch i {
|
|
case 0:
|
|
default:
|
|
L: // GCCGO_ERROR "block starts here"
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
switch i {
|
|
default:
|
|
goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
|
|
case 0:
|
|
L: // GCCGO_ERROR "block starts here"
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
switch i {
|
|
case 0:
|
|
L: // GCCGO_ERROR "block starts here"
|
|
;
|
|
default:
|
|
goto L // ERROR "goto L jumps into block starting at LINE-4|goto jumps into block"
|
|
}
|
|
}
|
|
|
|
// select
|
|
// different from switch. the statement has no implicit block around it.
|
|
|
|
func _() {
|
|
L:
|
|
select {
|
|
case <-c:
|
|
goto L
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
L:
|
|
select {
|
|
case c <- 1:
|
|
|
|
default:
|
|
goto L
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
select {
|
|
case <-c:
|
|
|
|
default:
|
|
L:
|
|
goto L
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
select {
|
|
case c <- 1:
|
|
|
|
default:
|
|
goto L
|
|
L:
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
select {
|
|
case <-c:
|
|
goto L
|
|
L:
|
|
;
|
|
default:
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
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 jumps into block"
|
|
select {
|
|
case c <- 1:
|
|
L: // GCCGO_ERROR "block starts here"
|
|
;
|
|
default:
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
|
|
select {
|
|
case <-c:
|
|
default:
|
|
L: // GCCGO_ERROR "block starts here"
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
select {
|
|
default:
|
|
goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
|
|
case <-c:
|
|
L: // GCCGO_ERROR "block starts here"
|
|
}
|
|
}
|
|
|
|
func _() {
|
|
select {
|
|
case <-c:
|
|
L: // GCCGO_ERROR "block starts here"
|
|
;
|
|
default:
|
|
goto L // ERROR "goto L jumps into block starting at LINE-4|goto jumps into block"
|
|
}
|
|
}
|