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