cmd/gc: support x[i:j:k]

Design doc at golang.org/s/go12slice.
This is an experimental feature and may not be included in the release.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/10743046
diff --git a/test/fixedbugs/issue4251.go b/test/fixedbugs/issue4251.go
index a14e089..4adec2b 100644
--- a/test/fixedbugs/issue4251.go
+++ b/test/fixedbugs/issue4251.go
@@ -9,13 +9,13 @@
 package p
 
 func F1(s []byte) []byte {
-	return s[2:1]		// ERROR "inverted"
+	return s[2:1]		// ERROR "invalid slice index"
 }
 
 func F2(a [10]byte) []byte {
-	return a[2:1]		// ERROR "inverted"
+	return a[2:1]		// ERROR "invalid slice index"
 }
 
 func F3(s string) string {
-	return s[2:1]		// ERROR "inverted"
+	return s[2:1]		// ERROR "invalid slice index"
 }
diff --git a/test/slice3.go b/test/slice3.go
new file mode 100644
index 0000000..3cf34b5
--- /dev/null
+++ b/test/slice3.go
@@ -0,0 +1,156 @@
+// runoutput
+
+// Copyright 2013 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.
+
+// Test run-time behavior of 3-index slice expressions.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"strconv"
+)
+
+var bout *bufio.Writer
+
+func main() {
+	bout = bufio.NewWriter(os.Stdout)
+	
+	fmt.Fprintf(bout, "%s", programTop)
+	fmt.Fprintf(bout, "func main() {\n")
+	
+	index := []string{
+		"0",
+		"1",
+		"2",
+		"3",
+		"10",
+		"20",
+		"vminus1",
+		"v0",
+		"v1",
+		"v2",
+		"v3",
+		"v10",
+		"v20",
+	}
+	
+	parse := func(s string) (n int, isconst bool) {
+		if s == "vminus1" {
+			return -1, false
+		}
+		isconst = true
+		if s[0] == 'v' {
+			isconst = false
+			s = s[1:]
+		}
+		n, _ = strconv.Atoi(s)
+		return n, isconst
+	}
+
+	const Cap = 10 // cap of slice, array
+
+	for _, base := range []string{"array", "slice"} {
+		for _, i := range index {
+			iv, iconst := parse(i)
+			for _, j := range index {
+				jv, jconst := parse(j)
+				for _, k := range index {
+					kv, kconst := parse(k)
+					// Avoid errors that would make the program not compile.
+					// Those are tested by slice3err.go.
+					switch {
+					case iconst && jconst && iv > jv,
+						jconst && kconst && jv > kv,
+						iconst && kconst && iv > kv,
+						iconst && base == "array" && iv > Cap,
+						jconst && base == "array" && jv > Cap,
+						kconst && base == "array" && kv > Cap:				
+						continue
+					}
+
+					expr := base + "[" + i + ":" + j + ":" + k + "]"
+					var xbase, xlen, xcap int
+					if iv > jv || jv > kv || kv > Cap || iv < 0 || jv < 0 || kv < 0 {
+						xbase, xlen, xcap = -1, -1, -1
+					} else {
+						xbase = iv
+						xlen = jv - iv
+						xcap = kv - iv
+					}
+					fmt.Fprintf(bout, "\tcheckSlice(%q, func() []byte { return %s }, %d, %d, %d)\n", expr, expr, xbase, xlen, xcap)									
+				}
+			}
+		}
+	}
+
+	fmt.Fprintf(bout, "\tif !ok { os.Exit(1) }\n")
+	fmt.Fprintf(bout, "}\n")
+	bout.Flush()
+}
+
+var programTop = `
+package main
+
+import (
+	"fmt"
+	"os"
+	"unsafe"
+)
+
+var ok = true
+
+var (
+	array = new([10]byte)
+	slice = array[:]
+
+	vminus1 = -1
+	v0 = 0
+	v1 = 1
+	v2 = 2
+	v3 = 3
+	v4 = 4
+	v5 = 5
+	v10 = 10
+	v20 = 20
+)
+
+func notOK() {
+	if ok {
+		println("BUG:")
+		ok = false
+	}
+}
+
+func checkSlice(desc string, f func() []byte, xbase, xlen, xcap int) {
+	defer func() {
+		if err := recover(); err != nil {
+			if xbase >= 0 {
+				notOK()
+				println(desc, " unexpected panic: ", fmt.Sprint(err))
+			}
+		}
+		// "no panic" is checked below
+	}()
+	
+	x := f()
+
+	arrayBase := uintptr(unsafe.Pointer(array))
+	raw := *(*[3]uintptr)(unsafe.Pointer(&x))
+	base, len, cap := raw[0] - arrayBase, raw[1], raw[2]
+	if xbase < 0 {
+		notOK()
+		println(desc, "=", base, len, cap, "want panic")
+		return
+	}
+	if base != uintptr(xbase) || len != uintptr(xlen) || cap != uintptr(xcap) {
+		notOK()
+		println(desc, "=", base, len, cap, "want", xbase, xlen, xcap)
+	}
+}
+
+`
diff --git a/test/slice3err.go b/test/slice3err.go
new file mode 100644
index 0000000..c48ebfe
--- /dev/null
+++ b/test/slice3err.go
@@ -0,0 +1,121 @@
+// errorcheck
+
+// Copyright 2013 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.
+
+package p
+
+var array *[10]int
+var slice []int
+var str string
+var i, j, k int
+
+func f() {
+	// check what missing arguments are allowed
+	_ = array[:]
+	_ = array[i:]
+	_ = array[:j]
+	_ = array[i:j]
+	_ = array[::] // ERROR "middle index required in 3-index slice" "final index required in 3-index slice"
+	_ = array[i::] // ERROR "middle index required in 3-index slice" "final index required in 3-index slice"
+	_ = array[:j:] // ERROR "final index required in 3-index slice"
+	_ = array[i:j:] // ERROR  "final index required in 3-index slice"
+	_ = array[::k] // ERROR "middle index required in 3-index slice"
+	_ = array[i::k] // ERROR "middle index required in 3-index slice"
+	_ = array[:j:k]
+	_ = array[i:j:k]
+	
+	_ = slice[:]
+	_ = slice[i:]
+	_ = slice[:j]
+	_ = slice[i:j]
+	_ = slice[::] // ERROR "middle index required in 3-index slice" "final index required in 3-index slice"
+	_ = slice[i::] // ERROR "middle index required in 3-index slice" "final index required in 3-index slice"
+	_ = slice[:j:] // ERROR "final index required in 3-index slice"
+	_ = slice[i:j:] // ERROR "final index required in 3-index slice"
+	_ = slice[::k] // ERROR "middle index required in 3-index slice"
+	_ = slice[i::k] // ERROR "middle index required in 3-index slice"
+	_ = slice[:j:k]
+	_ = slice[i:j:k]
+	
+	_ = str[:]
+	_ = str[i:]
+	_ = str[:j]
+	_ = str[i:j]
+	_ = str[::] // ERROR "3-index slice of string" "middle index required in 3-index slice" "final index required in 3-index slice"
+	_ = str[i::] // ERROR "3-index slice of string" "middle index required in 3-index slice" "final index required in 3-index slice"
+	_ = str[:j:] // ERROR "3-index slice of string" "final index required in 3-index slice"
+	_ = str[i:j:] // ERROR "3-index slice of string" "final index required in 3-index slice"
+	_ = str[::k] // ERROR "3-index slice of string" "middle index required in 3-index slice"
+	_ = str[i::k] // ERROR "3-index slice of string" "middle index required in 3-index slice"
+	_ = str[:j:k] // ERROR "3-index slice of string"
+	_ = str[i:j:k] // ERROR "3-index slice of string"
+
+	// check invalid indices
+	_ = array[1:2]
+	_ = array[2:1] // ERROR "invalid slice index"
+	_ = array[2:2]
+	_ = array[i:1]
+	_ = array[1:j]
+	_ = array[1:2:3]
+	_ = array[1:3:2] // ERROR "invalid slice index"
+	_ = array[2:1:3] // ERROR "invalid slice index"
+	_ = array[2:3:1] // ERROR "invalid slice index"
+	_ = array[3:1:2] // ERROR "invalid slice index"
+	_ = array[3:2:1] // ERROR "invalid slice index"
+	_ = array[i:1:2]
+	_ = array[i:2:1] // ERROR "invalid slice index"
+	_ = array[1:j:2]
+	_ = array[2:j:1] // ERROR "invalid slice index"
+	_ = array[1:2:k]
+	_ = array[2:1:k] // ERROR "invalid slice index"
+	
+	_ = slice[1:2]
+	_ = slice[2:1] // ERROR "invalid slice index"
+	_ = slice[2:2]
+	_ = slice[i:1]
+	_ = slice[1:j]
+	_ = slice[1:2:3]
+	_ = slice[1:3:2] // ERROR "invalid slice index"
+	_ = slice[2:1:3] // ERROR "invalid slice index"
+	_ = slice[2:3:1] // ERROR "invalid slice index"
+	_ = slice[3:1:2] // ERROR "invalid slice index"
+	_ = slice[3:2:1] // ERROR "invalid slice index"
+	_ = slice[i:1:2]
+	_ = slice[i:2:1] // ERROR "invalid slice index"
+	_ = slice[1:j:2]
+	_ = slice[2:j:1] // ERROR "invalid slice index"
+	_ = slice[1:2:k]
+	_ = slice[2:1:k] // ERROR "invalid slice index"
+	
+	_ = str[1:2]
+	_ = str[2:1] // ERROR "invalid slice index"
+	_ = str[2:2]
+	_ = str[i:1]
+	_ = str[1:j]
+
+	// check out of bounds indices on array
+	_ = array[11:11] // ERROR "out of bounds for 10-element array"
+	_ = array[11:12] // ERROR "out of bounds for 10-element array"
+	_ = array[11:] // ERROR "out of bounds for 10-element array"
+	_ = array[:11] // ERROR "out of bounds for 10-element array"
+	_ = array[1:11] // ERROR "out of bounds for 10-element array"
+	_ = array[1:11:12] // ERROR "out of bounds for 10-element array"
+	_ = array[1:2:11] // ERROR "out of bounds for 10-element array"
+	_ = array[1:11:3] // ERROR "out of bounds for 10-element array"
+	_ = array[11:2:3] // ERROR "out of bounds for 10-element array"
+	_ = array[11:12:13] // ERROR "out of bounds for 10-element array"
+
+	// slice bounds not checked
+	_ = slice[11:11]
+	_ = slice[11:12]
+	_ = slice[11:]
+	_ = slice[:11]
+	_ = slice[1:11]
+	_ = slice[1:11:12]
+	_ = slice[1:2:11]
+	_ = slice[1:11:3] // ERROR "invalid slice index"
+	_ = slice[11:2:3] // ERROR "invalid slice index"
+	_ = slice[11:12:13]
+}