respect goto restrictions

R=gri
CC=golang-dev
https://golang.org/cl/4625044
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
index 8ee3422..1f3e5e7 100644
--- a/src/cmd/hgpatch/main.go
+++ b/src/cmd/hgpatch/main.go
@@ -329,15 +329,14 @@
 // It provides input on standard input to the command.
 func run(argv []string, input []byte) (out string, err os.Error) {
 	if len(argv) < 1 {
-		err = os.EINVAL
-		goto Error
+		return "", &runError{dup(argv), os.EINVAL}
 	}
 
 	prog, ok := lookPathCache[argv[0]]
 	if !ok {
 		prog, err = exec.LookPath(argv[0])
 		if err != nil {
-			goto Error
+			return "", &runError{dup(argv), err}
 		}
 		lookPathCache[argv[0]] = prog
 	}
@@ -347,13 +346,10 @@
 		cmd.Stdin = bytes.NewBuffer(input)
 	}
 	bs, err := cmd.CombinedOutput()
-	if err == nil {
-		return string(bs), nil
+	if err != nil {
+		return "", &runError{dup(argv), err}
 	}
-
-Error:
-	err = &runError{dup(argv), err}
-	return
+	return string(bs), nil
 }
 
 // A runError represents an error that occurred while running a command.
diff --git a/src/pkg/crypto/openpgp/packet/signature.go b/src/pkg/crypto/openpgp/packet/signature.go
index 3169bac..123c99f 100644
--- a/src/pkg/crypto/openpgp/packet/signature.go
+++ b/src/pkg/crypto/openpgp/packet/signature.go
@@ -177,7 +177,11 @@
 // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
 func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err os.Error) {
 	// RFC 4880, section 5.2.3.1
-	var length uint32
+	var (
+		length     uint32
+		packetType byte
+		isCritical bool
+	)
 	switch {
 	case subpacket[0] < 192:
 		length = uint32(subpacket[0])
@@ -207,8 +211,8 @@
 		err = error.StructuralError("zero length signature subpacket")
 		return
 	}
-	packetType := subpacket[0] & 0x7f
-	isCritial := subpacket[0]&0x80 == 0x80
+	packetType = subpacket[0] & 0x7f
+	isCritical = subpacket[0]&0x80 == 0x80
 	subpacket = subpacket[1:]
 	switch signatureSubpacketType(packetType) {
 	case creationTimeSubpacket:
@@ -309,7 +313,7 @@
 		}
 
 	default:
-		if isCritial {
+		if isCritical {
 			err = error.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
 			return
 		}
diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
index 84f90c4..c83ef3f 100644
--- a/src/pkg/crypto/tls/key_agreement.go
+++ b/src/pkg/crypto/tls/key_agreement.go
@@ -176,9 +176,11 @@
 	return preMasterSecret, nil
 }
 
+var errServerKeyExchange = os.ErrorString("invalid ServerKeyExchange")
+
 func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
 	if len(skx.key) < 4 {
-		goto Error
+		return errServerKeyExchange
 	}
 	if skx.key[0] != 3 { // named curve
 		return os.ErrorString("server selected unsupported curve")
@@ -198,29 +200,26 @@
 
 	publicLen := int(skx.key[3])
 	if publicLen+4 > len(skx.key) {
-		goto Error
+		return errServerKeyExchange
 	}
 	ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen])
 	if ka.x == nil {
-		goto Error
+		return errServerKeyExchange
 	}
 	serverECDHParams := skx.key[:4+publicLen]
 
 	sig := skx.key[4+publicLen:]
 	if len(sig) < 2 {
-		goto Error
+		return errServerKeyExchange
 	}
 	sigLen := int(sig[0])<<8 | int(sig[1])
 	if sigLen+2 != len(sig) {
-		goto Error
+		return errServerKeyExchange
 	}
 	sig = sig[2:]
 
 	md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams)
 	return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig)
-
-Error:
-	return os.ErrorString("invalid ServerKeyExchange")
 }
 
 func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go
index a33785b..f35365e 100644
--- a/src/pkg/debug/dwarf/type.go
+++ b/src/pkg/debug/dwarf/type.go
@@ -566,12 +566,13 @@
 		goto Error
 	}
 
-	b, ok := e.Val(AttrByteSize).(int64)
-	if !ok {
-		b = -1
+	{
+		b, ok := e.Val(AttrByteSize).(int64)
+		if !ok {
+			b = -1
+		}
+		typ.Common().ByteSize = b
 	}
-	typ.Common().ByteSize = b
-
 	return typ, nil
 
 Error:
diff --git a/src/pkg/encoding/pem/pem.go b/src/pkg/encoding/pem/pem.go
index c239880..ebe57ed 100644
--- a/src/pkg/encoding/pem/pem.go
+++ b/src/pkg/encoding/pem/pem.go
@@ -86,7 +86,7 @@
 
 	typeLine, rest := getLine(rest)
 	if !bytes.HasSuffix(typeLine, pemEndOfLine) {
-		goto Error
+		return decodeError(data, rest)
 	}
 	typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)]
 
@@ -118,22 +118,23 @@
 
 	i := bytes.Index(rest, pemEnd)
 	if i < 0 {
-		goto Error
+		return decodeError(data, rest)
 	}
 	base64Data := removeWhitespace(rest[0:i])
 
 	p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
 	n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
 	if err != nil {
-		goto Error
+		return decodeError(data, rest)
 	}
 	p.Bytes = p.Bytes[0:n]
 
 	_, rest = getLine(rest[i+len(pemEnd):])
 
 	return
+}
 
-Error:
+func decodeError(data, rest []byte) (*Block, []byte) {
 	// If we get here then we have rejected a likely looking, but
 	// ultimately invalid PEM block. We need to start over from a new
 	// position.  We have consumed the preamble line and will have consumed
@@ -154,11 +155,11 @@
 	//
 	// we've failed to parse using the first BEGIN line
 	// and now will try again, using the second BEGIN line.
-	p, rest = Decode(rest)
+	p, rest := Decode(rest)
 	if p == nil {
 		rest = data
 	}
-	return
+	return p, rest
 }
 
 const pemLineLength = 64
diff --git a/src/pkg/exp/regexp/syntax/parse.go b/src/pkg/exp/regexp/syntax/parse.go
index 0a04222..d04f250 100644
--- a/src/pkg/exp/regexp/syntax/parse.go
+++ b/src/pkg/exp/regexp/syntax/parse.go
@@ -120,10 +120,23 @@
 
 // repeat replaces the top stack element with itself repeated
 // according to op.
-func (p *parser) repeat(op Op, min, max int, flags Flags, opstr string) os.Error {
+func (p *parser) repeat(op Op, min, max int, opstr, t, lastRepeat string) (string, os.Error) {
+	flags := p.flags
+	if p.flags&PerlX != 0 {
+		if len(t) > 0 && t[0] == '?' {
+			t = t[1:]
+			flags ^= NonGreedy
+		}
+		if lastRepeat != "" {
+			// In Perl it is not allowed to stack repetition operators:
+			// a** is a syntax error, not a doubled star, and a++ means
+			// something else entirely, which we don't support!
+			return "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(t)]}
+		}
+	}
 	n := len(p.stack)
 	if n == 0 {
-		return &Error{ErrMissingRepeatArgument, opstr}
+		return "", &Error{ErrMissingRepeatArgument, opstr}
 	}
 	sub := p.stack[n-1]
 	re := &Regexp{
@@ -135,7 +148,7 @@
 	re.Sub = re.Sub0[:1]
 	re.Sub[0] = sub
 	p.stack[n-1] = re
-	return nil
+	return t, nil
 }
 
 // concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation.
@@ -295,35 +308,19 @@
 			case '?':
 				op = OpQuest
 			}
-			repeat = t
-			t = t[1:]
-			goto Repeat
+			if t, err = p.repeat(op, min, max, t[:1], t[1:], lastRepeat); err != nil {
+				return nil, err
+			}
 		case '{':
 			op = OpRepeat
-			n, m, tt, ok := p.parseRepeat(t)
+			min, max, tt, ok := p.parseRepeat(t)
 			if !ok {
 				// If the repeat cannot be parsed, { is a literal.
 				p.literal('{')
 				t = t[1:]
 				break
 			}
-			repeat, t = t, tt
-			min, max = n, m
-		Repeat:
-			flags := p.flags
-			if p.flags&PerlX != 0 {
-				if len(t) > 0 && t[0] == '?' {
-					t = t[1:]
-					flags ^= NonGreedy
-				}
-				if lastRepeat != "" {
-					// In Perl it is not allowed to stack repetition operators:
-					// a** is a syntax error, not a doubled star, and a++ means
-					// something else entirely, which we don't support!
-					return nil, &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(t)]}
-				}
-			}
-			if err = p.repeat(op, min, max, flags, repeat[:len(repeat)-len(t)]); err != nil {
+			if t, err = p.repeat(op, min, max, t[:len(t)-len(tt)], tt, lastRepeat); err != nil {
 				return nil, err
 			}
 		case '\\':
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index dd8548c..b111288 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -945,7 +945,7 @@
 			// For now, can only handle (renamed) []byte.
 			typ := v.Type()
 			if typ.Elem().Kind() != reflect.Uint8 {
-				goto CantHandle
+				s.errorString("Scan: can't handle type: " + val.Type().String())
 			}
 			str := s.convertString(verb)
 			v.Set(reflect.MakeSlice(typ, len(str), len(str)))
@@ -959,7 +959,6 @@
 		case reflect.Complex64, reflect.Complex128:
 			v.SetComplex(s.scanComplex(verb, v.Type().Bits()))
 		default:
-		CantHandle:
 			s.errorString("Scan: can't handle type: " + val.Type().String())
 		}
 	}
diff --git a/src/pkg/http/url.go b/src/pkg/http/url.go
index 05b1662..394c87d0 100644
--- a/src/pkg/http/url.go
+++ b/src/pkg/http/url.go
@@ -348,6 +348,11 @@
 // in which case only absolute URLs or path-absolute relative URLs are allowed.
 // If viaRequest is false, all forms of relative URLs are allowed.
 func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) {
+	var (
+		leadingSlash bool
+		path         string
+	)
+
 	if rawurl == "" {
 		err = os.ErrorString("empty url")
 		goto Error
@@ -357,12 +362,10 @@
 
 	// Split off possible leading "http:", "mailto:", etc.
 	// Cannot contain escaped characters.
-	var path string
 	if url.Scheme, path, err = getscheme(rawurl); err != nil {
 		goto Error
 	}
-
-	leadingSlash := strings.HasPrefix(path, "/")
+	leadingSlash = strings.HasPrefix(path, "/")
 
 	if url.Scheme != "" && !leadingSlash {
 		// RFC 2396:
diff --git a/src/pkg/net/dnsmsg.go b/src/pkg/net/dnsmsg.go
index 0ba69a0..ade1bb3 100644
--- a/src/pkg/net/dnsmsg.go
+++ b/src/pkg/net/dnsmsg.go
@@ -394,7 +394,6 @@
 		f := val.Type().Field(i)
 		switch fv := val.Field(i); fv.Kind() {
 		default:
-		BadType:
 			fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
 			return len(msg), false
 		case reflect.Struct:
@@ -419,7 +418,8 @@
 			off += 4
 		case reflect.Array:
 			if fv.Type().Elem().Kind() != reflect.Uint8 {
-				goto BadType
+				fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+				return len(msg), false
 			}
 			n := fv.Len()
 			if off+n > len(msg) {
@@ -471,7 +471,6 @@
 		f := val.Type().Field(i)
 		switch fv := val.Field(i); fv.Kind() {
 		default:
-		BadType:
 			fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
 			return len(msg), false
 		case reflect.Struct:
@@ -492,7 +491,8 @@
 			off += 4
 		case reflect.Array:
 			if fv.Type().Elem().Kind() != reflect.Uint8 {
-				goto BadType
+				fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+				return len(msg), false
 			}
 			n := fv.Len()
 			if off+n > len(msg) {
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 0b8c388..5d56520 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -270,12 +270,16 @@
 
 // Convert "host:port" into IP address and port.
 func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
+	var (
+		addr IP
+		p, i int
+		ok   bool
+	)
 	host, port, err := SplitHostPort(hostport)
 	if err != nil {
 		goto Error
 	}
 
-	var addr IP
 	if host != "" {
 		// Try as an IP address.
 		addr = ParseIP(host)
@@ -302,7 +306,7 @@
 		}
 	}
 
-	p, i, ok := dtoi(port, 0)
+	p, i, ok = dtoi(port, 0)
 	if !ok || i != len(port) {
 		p, err = LookupPort(net, port)
 		if err != nil {
diff --git a/src/pkg/net/newpollserver.go b/src/pkg/net/newpollserver.go
index fff54db..4272087 100644
--- a/src/pkg/net/newpollserver.go
+++ b/src/pkg/net/newpollserver.go
@@ -18,12 +18,7 @@
 	}
 	var e int
 	if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
-	Errno:
-		err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
-	Error:
-		s.pr.Close()
-		s.pw.Close()
-		return nil, err
+		goto Errno
 	}
 	if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
 		goto Errno
@@ -38,4 +33,11 @@
 	s.pending = make(map[int]*netFD)
 	go s.Run()
 	return s, nil
+
+Errno:
+	err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+Error:
+	s.pr.Close()
+	s.pw.Close()
+	return nil, err
 }
diff --git a/src/pkg/patch/textdiff.go b/src/pkg/patch/textdiff.go
index c7e693f..482bd67 100644
--- a/src/pkg/patch/textdiff.go
+++ b/src/pkg/patch/textdiff.go
@@ -17,6 +17,8 @@
 }
 
 func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
+	var chunkHeader []byte
+
 	// Copy raw so it is safe to keep references to slices.
 	_, chunks := sections(raw, "@@ -")
 	delta := 0
@@ -26,13 +28,12 @@
 
 		// Parse start line: @@ -oldLine,oldCount +newLine,newCount @@ junk
 		chunk := splitLines(raw)
-		chunkHeader := chunk[0]
+		chunkHeader = chunk[0]
 		var ok bool
 		var oldLine, oldCount, newLine, newCount int
 		s := chunkHeader
 		if oldLine, s, ok = atoi(s, "@@ -", 10); !ok {
-		ErrChunkHdr:
-			return nil, SyntaxError("unexpected chunk header line: " + string(chunkHeader))
+			goto ErrChunkHdr
 		}
 		if len(s) == 0 || s[0] != ',' {
 			oldCount = 1
@@ -145,6 +146,9 @@
 		}
 	}
 	return diff, nil
+
+ErrChunkHdr:
+	return nil, SyntaxError("unexpected chunk header line: " + string(chunkHeader))
 }
 
 var ErrPatchFailure = os.NewError("patch did not apply cleanly")
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index f7b8456..1dfaaa6 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -42,6 +42,8 @@
 // digits, err.Error = os.EINVAL; if the value corresponding
 // to s cannot be represented by a uint64, err.Error = os.ERANGE.
 func Btoui64(s string, b int) (n uint64, err os.Error) {
+	var cutoff uint64
+
 	s0 := s
 	switch {
 	case len(s) < 1:
@@ -73,7 +75,7 @@
 	}
 
 	n = 0
-	cutoff := cutoff64(b)
+	cutoff = cutoff64(b)
 
 	for i := 0; i < len(s); i++ {
 		var v byte
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
index 98b19d3..05e49d3 100644
--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -24,7 +24,10 @@
 			rune, width = utf8.DecodeRuneInString(s)
 		}
 		if width == 1 && rune == utf8.RuneError {
-			goto printEscX
+			buf.WriteString(`\x`)
+			buf.WriteByte(lowerhex[s[0]>>4])
+			buf.WriteByte(lowerhex[s[0]&0xF])
+			continue
 		}
 		if rune == int(quote) || rune == '\\' { // always backslashed
 			buf.WriteByte('\\')
@@ -58,7 +61,6 @@
 		default:
 			switch {
 			case rune < ' ':
-			printEscX:
 				buf.WriteString(`\x`)
 				buf.WriteByte(lowerhex[s[0]>>4])
 				buf.WriteByte(lowerhex[s[0]&0xF])
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
index 31bed92..a6ac398 100644
--- a/src/pkg/syscall/exec_unix.go
+++ b/src/pkg/syscall/exec_unix.go
@@ -337,13 +337,7 @@
 	// Kick off child.
 	pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
 	if err != 0 {
-	error:
-		if p[0] >= 0 {
-			Close(p[0])
-			Close(p[1])
-		}
-		ForkLock.Unlock()
-		return 0, err
+		goto error
 	}
 	ForkLock.Unlock()
 
@@ -370,6 +364,14 @@
 
 	// Read got EOF, so pipe closed on exec, so exec succeeded.
 	return pid, 0
+
+error:
+	if p[0] >= 0 {
+		Close(p[0])
+		Close(p[1])
+	}
+	ForkLock.Unlock()
+	return 0, err
 }
 
 // Combination of fork and exec, careful to be thread safe.
diff --git a/test/fixedbugs/bug140.go b/test/fixedbugs/bug140.go
index e27b370..441c57a 100644
--- a/test/fixedbugs/bug140.go
+++ b/test/fixedbugs/bug140.go
@@ -10,14 +10,14 @@
 	if true {
 	} else {
 	L1:
+		goto L1
 	}
 	if true {
 	} else {
+		goto L2
 	L2:
 		main()
 	}
-	goto L1
-	goto L2
 }
 
 /*
diff --git a/test/fixedbugs/bug178.go b/test/fixedbugs/bug178.go
index 2059610..a7ff09d 100644
--- a/test/fixedbugs/bug178.go
+++ b/test/fixedbugs/bug178.go
@@ -14,6 +14,9 @@
 			break L
 		}
 		panic("BUG: not reached - break")
+		if false {
+			goto L1
+		}
 	}
 
 L2:
@@ -23,11 +26,8 @@
 			continue L2
 		}
 		panic("BUG: not reached - continue")
-	}
-	if false {
-		goto L1
-	}
-	if false {
-		goto L3
+		if false {
+			goto L3
+		}
 	}
 }