1
0
mirror of https://github.com/golang/go synced 2024-11-15 00:50:32 -07:00
go/test/goto.go
Robert Griesemer bb70f517e9 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: Marvin Stenger <marvin.stenger94@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-19 02:27:58 +00:00

539 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"
}
}