Initial commit: Go 1.23 release state

This commit is contained in:
Vorapol Rinsatitnon
2024-09-21 23:49:08 +10:00
commit 17cd57a668
13231 changed files with 3114330 additions and 0 deletions

75
test/235.go Normal file
View File

@@ -0,0 +1,75 @@
// run
// Copyright 2009 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.
// Solve the 2,3,5 problem (print all numbers with 2, 3, or 5 as factor) using channels.
// Test the solution, silently.
package main
type T chan uint64
func M(f uint64) (in, out T) {
in = make(T, 100)
out = make(T, 100)
go func(in, out T, f uint64) {
for {
out <- f*<-in
}
}(in, out, f)
return in, out
}
func min(xs []uint64) uint64 {
m := xs[0]
for i := 1; i < len(xs); i++ {
if xs[i] < m {
m = xs[i]
}
}
return m
}
func main() {
F := []uint64{2, 3, 5}
var n = len(F)
OUT := []uint64{
2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36,
40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125,
128, 135, 144, 150, 160, 162, 180, 192, 200, 216, 225, 240, 243, 250,
256, 270, 288, 300, 320, 324, 360, 375, 384, 400, 405, 432, 450, 480,
486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720, 729, 750, 768,
800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125, 1152, 1200, 1215,
1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536, 1600}
x := uint64(1)
ins := make([]T, n)
outs := make([]T, n)
xs := make([]uint64, n)
for i := 0; i < n; i++ {
ins[i], outs[i] = M(F[i])
xs[i] = x
}
for i := 0; i < len(OUT); i++ {
for i := 0; i < n; i++ {
ins[i] <- x
}
for i := 0; i < n; i++ {
if xs[i] == x {
xs[i] = <-outs[i]
}
}
x = min(xs)
if x != OUT[i] {
println("bad: ", x, " should be ", OUT[i])
panic("235")
}
}
}

728
test/64bit.go Normal file
View File

@@ -0,0 +1,728 @@
// runoutput
// Copyright 2009 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.
// Generate test of 64-bit arithmetic.
// Most synthesized routines have different cases for
// constants vs variables and even the generated code has
// different cases for large and small constants,
// so try a good range of inputs.
package main
import (
"bufio"
"fmt"
"os"
)
var bout *bufio.Writer
// 64-bit math without using 64-bit numbers,
// so that we can generate the test program even
// if the compiler has buggy or missing 64-bit support.
type Uint64 struct {
hi uint32
lo uint32
}
type Int64 struct {
hi int32
lo uint32
}
func (a Uint64) Int64() (c Int64) {
c.hi = int32(a.hi)
c.lo = a.lo
return
}
func (a Uint64) Cmp(b Uint64) int {
switch {
case a.hi < b.hi:
return -1
case a.hi > b.hi:
return 1
case a.lo < b.lo:
return -1
case a.lo > b.lo:
return 1
}
return 0
}
func (a Uint64) LeftShift(b uint) (c Uint64) {
switch {
case b >= 64:
c.hi = 0
c.lo = 0
case b >= 32:
c.hi = a.lo << (b - 32)
c.lo = 0
default:
c.hi = a.hi<<b | a.lo>>(32-b)
c.lo = a.lo << b
}
return
}
func (a Uint64) RightShift(b uint) (c Uint64) {
switch {
case b >= 64:
c.hi = 0
c.lo = a.hi
case b >= 32:
c.hi = 0
c.lo = a.hi >> (b - 32)
default:
c.hi = a.hi >> b
c.lo = a.hi<<(32-b) | a.lo>>b
}
return
}
func (a Uint64) LeftShift64(b Uint64) (c Uint64) {
if b.hi != 0 || b.lo >= 64 {
return
}
return a.LeftShift(uint(b.lo))
}
func (a Uint64) RightShift64(b Uint64) (c Uint64) {
if b.hi != 0 || b.lo >= 64 {
return
}
return a.RightShift(uint(b.lo))
}
func (a Uint64) Plus(b Uint64) (c Uint64) {
var carry uint32
if c.lo = a.lo + b.lo; c.lo < a.lo {
carry = 1
}
c.hi = a.hi + b.hi + carry
return
}
func (a Uint64) Minus(b Uint64) (c Uint64) {
var borrow uint32
if c.lo = a.lo - b.lo; c.lo > a.lo {
borrow = 1
}
c.hi = a.hi - b.hi - borrow
return
}
func (a Uint64) Neg() (c Uint64) {
var zero Uint64
return zero.Minus(a)
}
func (a Uint64) Com() (c Uint64) {
c.hi = ^a.hi
c.lo = ^a.lo
return
}
func (a Uint64) Len() int {
switch {
case a.hi != 0:
for i := 31; i >= 0; i-- {
if a.hi&(1<<uint(i)) != 0 {
return i + 1 + 32
}
}
case a.lo != 0:
for i := 31; i >= 0; i-- {
if a.lo&(1<<uint(i)) != 0 {
return i + 1
}
}
}
return 0
}
func (a Uint64) HasBit(b uint) bool {
switch {
case b >= 64:
return false
case b >= 32:
return a.hi&(1<<(b-32)) != 0
}
return a.lo&(1<<b) != 0
}
func (a Uint64) Times(b Uint64) (c Uint64) {
for i := uint(0); i < 64; i++ {
if b.HasBit(i) {
c = c.Plus(a.LeftShift(i))
}
}
return
}
func (a Uint64) DivMod(b Uint64) (quo, rem Uint64) {
n := a.Len() - b.Len()
if n >= 0 {
b = b.LeftShift(uint(n))
for i := 0; i <= n; i++ {
quo = quo.LeftShift(1)
if b.Cmp(a) <= 0 { // b <= a
quo.lo |= 1
a = a.Minus(b)
}
b = b.RightShift(1)
}
}
rem = a
return
}
func (a Uint64) And(b Uint64) (c Uint64) {
c.hi = a.hi & b.hi
c.lo = a.lo & b.lo
return
}
func (a Uint64) AndNot(b Uint64) (c Uint64) {
c.hi = a.hi &^ b.hi
c.lo = a.lo &^ b.lo
return
}
func (a Uint64) Or(b Uint64) (c Uint64) {
c.hi = a.hi | b.hi
c.lo = a.lo | b.lo
return
}
func (a Uint64) Xor(b Uint64) (c Uint64) {
c.hi = a.hi ^ b.hi
c.lo = a.lo ^ b.lo
return
}
func (a Uint64) String() string { return fmt.Sprintf("%#x%08x", a.hi, a.lo) }
func (a Int64) Uint64() (c Uint64) {
c.hi = uint32(a.hi)
c.lo = a.lo
return
}
func (a Int64) Cmp(b Int64) int {
// Same body as Uint64.Cmp,
// but behaves differently
// because hi is uint32 not int32.
switch {
case a.hi < b.hi:
return -1
case a.hi > b.hi:
return 1
case a.lo < b.lo:
return -1
case a.lo > b.lo:
return 1
}
return 0
}
func (a Int64) LeftShift(b uint) (c Int64) { return a.Uint64().LeftShift(b).Int64() }
func (a Int64) RightShift(b uint) (c Int64) {
switch {
case b >= 64:
c.hi = a.hi >> 31 // sign extend
c.lo = uint32(c.hi)
case b >= 32:
c.hi = a.hi >> 31 // sign extend
c.lo = uint32(a.hi >> (b - 32))
default:
c.hi = a.hi >> b
c.lo = uint32(a.hi<<(32-b)) | a.lo>>b
}
return
}
func (a Int64) LeftShift64(b Uint64) (c Int64) {
if b.hi != 0 || b.lo >= 64 {
return
}
return a.LeftShift(uint(b.lo))
}
func (a Int64) RightShift64(b Uint64) (c Int64) {
if b.hi != 0 || b.lo >= 64 {
return a.RightShift(64)
}
return a.RightShift(uint(b.lo))
}
func (a Int64) Plus(b Int64) (c Int64) { return a.Uint64().Plus(b.Uint64()).Int64() }
func (a Int64) Minus(b Int64) (c Int64) { return a.Uint64().Minus(b.Uint64()).Int64() }
func (a Int64) Neg() (c Int64) { return a.Uint64().Neg().Int64() }
func (a Int64) Com() (c Int64) { return a.Uint64().Com().Int64() }
func (a Int64) Times(b Int64) (c Int64) { return a.Uint64().Times(b.Uint64()).Int64() }
func (a Int64) DivMod(b Int64) (quo Int64, rem Int64) {
var zero Int64
quoSign := +1
remSign := +1
if a.Cmp(zero) < 0 {
quoSign = -1
remSign = -1
a = a.Neg()
}
if b.Cmp(zero) < 0 {
quoSign = -quoSign
b = b.Neg()
}
q, r := a.Uint64().DivMod(b.Uint64())
quo = q.Int64()
rem = r.Int64()
if quoSign < 0 {
quo = quo.Neg()
}
if remSign < 0 {
rem = rem.Neg()
}
return
}
func (a Int64) And(b Int64) (c Int64) { return a.Uint64().And(b.Uint64()).Int64() }
func (a Int64) AndNot(b Int64) (c Int64) { return a.Uint64().AndNot(b.Uint64()).Int64() }
func (a Int64) Or(b Int64) (c Int64) { return a.Uint64().Or(b.Uint64()).Int64() }
func (a Int64) Xor(b Int64) (c Int64) { return a.Uint64().Xor(b.Uint64()).Int64() }
func (a Int64) String() string {
if a.hi < 0 {
return fmt.Sprintf("-%s", a.Neg().Uint64())
}
return a.Uint64().String()
}
var int64Values = []Int64{
Int64{0, 0},
Int64{0, 1},
Int64{0, 2},
Int64{0, 3},
Int64{0, 100},
Int64{0, 10001},
Int64{0, 1<<31 - 1},
Int64{0, 1 << 31},
Int64{0, 1<<31 + 1},
Int64{0, 1<<32 - 1<<30},
Int64{0, 1<<32 - 1},
Int64{1, 0},
Int64{1, 1},
Int64{2, 0},
Int64{1<<31 - 1, 1<<32 - 10000},
Int64{1<<31 - 1, 1<<32 - 1},
Int64{0x789abcde, 0xf0123456},
Int64{-1, 1<<32 - 1},
Int64{-1, 1<<32 - 2},
Int64{-1, 1<<32 - 3},
Int64{-1, 1<<32 - 100},
Int64{-1, 1<<32 - 10001},
Int64{-1, 1<<32 - (1<<31 - 1)},
Int64{-1, 1<<32 - 1<<31},
Int64{-1, 1<<32 - (1<<31 + 1)},
Int64{-1, 1<<32 - (1<<32 - 1<<30)},
Int64{-1, 0},
Int64{-1, 1},
Int64{-2, 0},
Int64{-(1 << 31), 10000},
Int64{-(1 << 31), 1},
Int64{-(1 << 31), 0},
Int64{-0x789abcde, 0xf0123456},
}
var uint64Values = []Uint64{
Uint64{0, 0},
Uint64{0, 1},
Uint64{0, 2},
Uint64{0, 3},
Uint64{0, 100},
Uint64{0, 10001},
Uint64{0, 1<<31 - 1},
Uint64{0, 1 << 31},
Uint64{0, 1<<31 + 1},
Uint64{0, 1<<32 - 1<<30},
Uint64{0, 1<<32 - 1},
Uint64{1, 0},
Uint64{1, 1},
Uint64{2, 0},
Uint64{1<<31 - 1, 1<<32 - 10000},
Uint64{1<<31 - 1, 1<<32 - 1},
Uint64{1<<32 - 1<<30, 0},
Uint64{1<<32 - 1, 0},
Uint64{1<<32 - 1, 1<<32 - 100},
Uint64{1<<32 - 1, 1<<32 - 1},
Uint64{0x789abcde, 0xf0123456},
Uint64{0xfedcba98, 0x76543210},
}
var shiftValues = []Uint64{
Uint64{0, 0},
Uint64{0, 1},
Uint64{0, 2},
Uint64{0, 3},
Uint64{0, 15},
Uint64{0, 16},
Uint64{0, 17},
Uint64{0, 31},
Uint64{0, 32},
Uint64{0, 33},
Uint64{0, 61},
Uint64{0, 62},
Uint64{0, 63},
Uint64{0, 64},
Uint64{0, 65},
Uint64{0, 1<<32 - 1},
Uint64{1, 0},
Uint64{1, 1},
Uint64{1 << 28, 0},
Uint64{1 << 31, 0},
Uint64{1<<32 - 1, 0},
Uint64{1<<32 - 1, 1<<32 - 1},
}
var ntest = 0
// Part 1 is tests of variable operations; generic functions
// called by repetitive code. Could make a table but not worth it.
const prolog = "\n" +
"package main\n" +
"\n" +
"import \"os\"\n" +
"\n" +
"var ok = true\n" +
"\n" +
"func testInt64Unary(a, plus, xor, minus int64) {\n" +
" if n, op, want := +a, `+`, plus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
" if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
" if n, op, want := -a, `-`, minus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
"}\n" +
"\n" +
"func testInt64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot int64, dodiv bool) {\n" +
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if dodiv {\n" +
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
" }\n" +
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
"}\n" +
"\n" +
"func testInt64Shift(a int64, b uint64, left, right int64) {\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
" if uint64(uint(b)) == b {\n" +
" b := uint(b);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
" if uint64(uint32(b)) == b {\n" +
" b := uint32(b);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
" if uint64(uint16(b)) == b {\n" +
" b := uint16(b);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
" if uint64(uint8(b)) == b {\n" +
" b := uint8(b);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
"}\n" +
"\n" +
"func testUint64Unary(a, plus, xor, minus uint64) {\n" +
" if n, op, want := +a, `+`, plus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
" if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
" if n, op, want := -a, `-`, minus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
"}\n" +
"\n" +
"func testUint64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot uint64, dodiv bool) {\n" +
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if dodiv {\n" +
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
" }\n" +
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
"}\n" +
"\n" +
"func testUint64Shift(a, b, left, right uint64) {\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
" if uint64(uint(b)) == b {\n" +
" b := uint(b);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
" if uint64(uint32(b)) == b {\n" +
" b := uint32(b);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
" if uint64(uint16(b)) == b {\n" +
" b := uint16(b);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
" if uint64(uint8(b)) == b {\n" +
" b := uint8(b);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
"}\n" +
"\n"
func varTests() {
fmt.Fprint(bout, prolog)
for _, a := range int64Values {
fmt.Fprintf(bout, "func test%v() {\n", ntest)
ntest++
fmt.Fprintf(bout, "\ttestInt64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
for _, b := range int64Values {
var div, mod Int64
dodiv := false
var zero Int64
if b.Cmp(zero) != 0 { // b != 0
// Can't divide by zero but also can't divide -0x8000...000 by -1.
var bigneg = Int64{-0x80000000, 0}
var minus1 = Int64{-1, ^uint32(0)}
if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
div, mod = a.DivMod(b)
dodiv = true
}
}
fmt.Fprintf(bout, "\ttestInt64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
}
for _, b := range shiftValues {
fmt.Fprintf(bout, "\ttestInt64Shift(%v, %v, %v, %v);\n",
a, b, a.LeftShift64(b), a.RightShift64(b))
}
fmt.Fprintf(bout, "}\n")
}
for _, a := range uint64Values {
fmt.Fprintf(bout, "func test%v() {\n", ntest)
ntest++
fmt.Fprintf(bout, "\ttestUint64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
for _, b := range uint64Values {
var div, mod Uint64
dodiv := false
var zero Uint64
if b.Cmp(zero) != 0 { // b != 0
div, mod = a.DivMod(b)
dodiv = true
}
fmt.Fprintf(bout, "\ttestUint64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
}
for _, b := range shiftValues {
fmt.Fprintf(bout, "\ttestUint64Shift(%v, %v, %v, %v);\n",
a, b, a.LeftShift64(b), a.RightShift64(b))
}
fmt.Fprintf(bout, "}\n")
}
}
// Part 2 is tests of operations involving one variable and one constant.
const binaryConstL = "func test%vBinaryL%v(b, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
" const a %v = %v;\n" +
" const typ = `%s`;\n" +
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
" if dodiv {\n" +
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
" }\n" +
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
"}\n" +
"\n"
const binaryConstR = "func test%vBinaryR%v(a, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
" const b %v = %v;\n" +
" const typ = `%s`;\n" +
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if dodiv {\n" +
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" }\n" +
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
"}\n" +
"\n"
const binaryConstR0 = "func test%vBinaryR%v(a, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
" const b %v = %v;\n" +
" const typ = `%s`;\n" +
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
"}\n" +
"\n"
const shiftConstL = "func test%vShiftL%v(b uint64, left, right %v) {\n" +
" const a %v = %v;\n" +
" const typ = `%s`;\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
" if uint64(uint32(b)) == b {\n" +
" b := uint32(b);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
"}\n"
const shiftConstR = "func test%vShiftR%v(a, left, right %v) {\n" +
" const b uint64 = %v;\n" +
" const typ = `%s`;\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
" if b & 0xffffffff == b {\n" +
" const b = uint32(b & 0xffffffff);\n" +
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
" }\n" +
"}\n"
func constTests() {
for i, a := range int64Values {
fmt.Fprintf(bout, binaryConstL, "Int64", i, "int64", "int64", a, "int64")
if a.hi == 0 && a.lo == 0 {
fmt.Fprintf(bout, binaryConstR0, "Int64", i, "int64", "int64", a, "int64")
} else {
fmt.Fprintf(bout, binaryConstR, "Int64", i, "int64", "int64", a, "int64")
}
fmt.Fprintf(bout, shiftConstL, "Int64", i, "int64", "int64", a, "int64")
}
for i, a := range uint64Values {
fmt.Fprintf(bout, binaryConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
if a.hi == 0 && a.lo == 0 {
fmt.Fprintf(bout, binaryConstR0, "Uint64", i, "uint64", "uint64", a, "uint64")
} else {
fmt.Fprintf(bout, binaryConstR, "Uint64", i, "uint64", "uint64", a, "uint64")
}
fmt.Fprintf(bout, shiftConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
}
for i, a := range shiftValues {
fmt.Fprintf(bout, shiftConstR, "Int64", i, "int64", a, "int64")
fmt.Fprintf(bout, shiftConstR, "Uint64", i, "uint64", a, "uint64")
}
for i, a := range int64Values {
fmt.Fprintf(bout, "func test%v() {\n", ntest)
ntest++
for j, b := range int64Values {
var div, mod Int64
dodiv := false
var zero Int64
if b.Cmp(zero) != 0 { // b != 0
// Can't divide by zero but also can't divide -0x8000...000 by -1.
var bigneg = Int64{-0x80000000, 0}
var minus1 = Int64{-1, ^uint32(0)}
if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
div, mod = a.DivMod(b)
dodiv = true
}
}
fmt.Fprintf(bout, "\ttestInt64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
fmt.Fprintf(bout, "\ttestInt64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
}
for j, b := range shiftValues {
fmt.Fprintf(bout, "\ttestInt64ShiftL%v(%v, %v, %v);\n",
i, b, a.LeftShift64(b), a.RightShift64(b))
fmt.Fprintf(bout, "\ttestInt64ShiftR%v(%v, %v, %v);\n",
j, a, a.LeftShift64(b), a.RightShift64(b))
}
fmt.Fprintf(bout, "}\n")
}
for i, a := range uint64Values {
fmt.Fprintf(bout, "func test%v() {\n", ntest)
ntest++
for j, b := range uint64Values {
var div, mod Uint64
dodiv := false
var zero Uint64
if b.Cmp(zero) != 0 { // b != 0
div, mod = a.DivMod(b)
dodiv = true
}
fmt.Fprintf(bout, "\ttestUint64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
fmt.Fprintf(bout, "\ttestUint64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
}
for j, b := range shiftValues {
fmt.Fprintf(bout, "\ttestUint64ShiftL%v(%v, %v, %v);\n",
i, b, a.LeftShift64(b), a.RightShift64(b))
fmt.Fprintf(bout, "\ttestUint64ShiftR%v(%v, %v, %v);\n",
j, a, a.LeftShift64(b), a.RightShift64(b))
}
fmt.Fprintf(bout, "}\n")
}
}
func main() {
bout = bufio.NewWriter(os.Stdout)
varTests()
constTests()
fmt.Fprintf(bout, "func main() {\n")
for i := 0; i < ntest; i++ {
fmt.Fprintf(bout, "\ttest%v();\n", i)
}
fmt.Fprintf(bout, "\tif !ok { os.Exit(1) }\n")
fmt.Fprintf(bout, "}\n")
bout.Flush()
}

19
test/README.md Normal file
View File

@@ -0,0 +1,19 @@
The test directory contains tests of the Go tool chain and runtime.
It includes black box tests, regression tests, and error output tests.
They are run as part of all.bash.
To run just these tests, execute:
../bin/go test cmd/internal/testdir
To run just tests from specified files in this directory, execute:
../bin/go test cmd/internal/testdir -run='Test/(file1.go|file2.go|...)'
Standard library tests should be written as regular Go tests in the appropriate package.
The tool chain and runtime also have regular Go tests in their packages.
The main reasons to add a new test to this directory are:
* it is most naturally expressed using the test runner; or
* it is also applicable to `gccgo` and other Go tool chains.

View File

@@ -0,0 +1,73 @@
// compile
//go:build !wasm
// Copyright 2021 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 genChecker0
var FailCount int
//go:noinline
func NoteFailure(fidx int, pkg string, pref string, parmNo int, _ uint64) {
FailCount += 1
if FailCount > 10 {
panic("bad")
}
}
//go:noinline
func NoteFailureElem(fidx int, pkg string, pref string, parmNo int, elem int, _ uint64) {
FailCount += 1
if FailCount > 10 {
panic("bad")
}
}
type StructF0S0 struct {
F0 int16
F1 string
F2 StructF0S1
}
type StructF0S1 struct {
_ uint16
}
// 0 returns 3 params
//go:registerparams
//go:noinline
func Test0(p0 uint32, p1 StructF0S0, p2 int32) {
// consume some stack space, so as to trigger morestack
var pad [256]uint64
pad[FailCount]++
if p0 == 0 {
return
}
p1f0c := int16(-3096)
if p1.F0 != p1f0c {
NoteFailureElem(0, "genChecker0", "parm", 1, 0, pad[0])
return
}
p1f1c := "f6ꂅ8ˋ<"
if p1.F1 != p1f1c {
NoteFailureElem(0, "genChecker0", "parm", 1, 1, pad[0])
return
}
p1f2c := StructF0S1{}
if p1.F2 != p1f2c {
NoteFailureElem(0, "genChecker0", "parm", 1, 2, pad[0])
return
}
p2f0c := int32(496713155)
if p2 != p2f0c {
NoteFailureElem(0, "genChecker0", "parm", 2, 0, pad[0])
return
}
// recursive call
Test0(p0-1, p1, p2)
return
// 0 addr-taken params, 0 addr-taken returns
}

View File

@@ -0,0 +1,272 @@
// build -goexperiment regabi,regabiargs
// Copyright 2021 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 main
import (
"fmt"
"os"
"reflect"
)
func main() {
// Only print if there is a problem
Caller2()
if FailCount != 0 {
fmt.Fprintf(os.Stderr, "FAILURES: %d\n", FailCount)
os.Exit(2)
}
}
var ParamFailCount int
var ReturnFailCount int
var FailCount int
var Mode string
type UtilsType int
//go:noinline
func NoteFailure(cm int, pidx int, fidx int, pkg string, pref string, parmNo int, isret bool, _ uint64) {
if isret {
if ParamFailCount != 0 {
return
}
ReturnFailCount++
} else {
ParamFailCount++
}
fmt.Fprintf(os.Stderr, "Error: fail %s |%d|%d|%d| =%s.Test%d= %s %d\n", Mode, cm, pidx, fidx, pkg, fidx, pref, parmNo)
if ParamFailCount+FailCount+ReturnFailCount > 9999 {
os.Exit(1)
}
}
//go:noinline
func NoteFailureElem(cm int, pidx int, fidx int, pkg string, pref string, parmNo int, elem int, isret bool, _ uint64) {
if isret {
if ParamFailCount != 0 {
return
}
ReturnFailCount++
} else {
ParamFailCount++
}
fmt.Fprintf(os.Stderr, "Error: fail %s |%d|%d|%d| =%s.Test%d= %s %d elem %d\n", Mode, cm, pidx, fidx, pkg, fidx, pref, parmNo, elem)
if ParamFailCount+FailCount+ReturnFailCount > 9999 {
os.Exit(1)
}
}
func BeginFcn() {
ParamFailCount = 0
ReturnFailCount = 0
}
func EndFcn() {
FailCount += ParamFailCount
FailCount += ReturnFailCount
}
func Caller2() {
BeginFcn()
c0 := StructF2S0{F0: ArrayF2S1E1{New_3(float64(-0.4418990509835844))}}
c1 := ArrayF2S2E1{StructF2S1{ /* _: "񊶿(z̽|" */ F1: "􂊇񊶿"}}
c2 := int16(4162)
c3 := float32(-7.667096e+37)
c4 := int64(3202175648847048679)
var p0 ArrayF2S0E0
p0 = ArrayF2S0E0{}
var p1 uint8
p1 = uint8(57)
var p2 uint16
p2 = uint16(10920)
var p3 float64
p3 = float64(-1.597256501942112)
Mode = ""
// 5 returns 4 params
r0, r1, r2, r3, r4 := Test2(p0, p1, p2, p3)
if !EqualStructF2S0(r0, c0) {
NoteFailure(9, 42, 2, "genChecker42", "return", 0, true, uint64(0))
}
if r1 != c1 {
NoteFailure(9, 42, 2, "genChecker42", "return", 1, true, uint64(0))
}
if r2 != c2 {
NoteFailure(9, 42, 2, "genChecker42", "return", 2, true, uint64(0))
}
if r3 != c3 {
NoteFailure(9, 42, 2, "genChecker42", "return", 3, true, uint64(0))
}
if r4 != c4 {
NoteFailure(9, 42, 2, "genChecker42", "return", 4, true, uint64(0))
}
// same call via reflection
Mode = "reflect"
rc := reflect.ValueOf(Test2)
rvslice := rc.Call([]reflect.Value{reflect.ValueOf(p0), reflect.ValueOf(p1), reflect.ValueOf(p2), reflect.ValueOf(p3)})
rr0i := rvslice[0].Interface()
rr0v := rr0i.(StructF2S0)
if !EqualStructF2S0(rr0v, c0) {
NoteFailure(9, 42, 2, "genChecker42", "return", 0, true, uint64(0))
}
rr1i := rvslice[1].Interface()
rr1v := rr1i.(ArrayF2S2E1)
if rr1v != c1 {
NoteFailure(9, 42, 2, "genChecker42", "return", 1, true, uint64(0))
}
rr2i := rvslice[2].Interface()
rr2v := rr2i.(int16)
if rr2v != c2 {
NoteFailure(9, 42, 2, "genChecker42", "return", 2, true, uint64(0))
}
rr3i := rvslice[3].Interface()
rr3v := rr3i.(float32)
if rr3v != c3 {
NoteFailure(9, 42, 2, "genChecker42", "return", 3, true, uint64(0))
}
rr4i := rvslice[4].Interface()
rr4v := rr4i.(int64)
if rr4v != c4 {
NoteFailure(9, 42, 2, "genChecker42", "return", 4, true, uint64(0))
}
EndFcn()
}
type StructF0S0 struct {
}
type ArrayF0S0E2 [2]int16
type ArrayF0S1E1 [1]StructF0S0
type StructF1S0 struct {
F0 StructF1S1
_ ArrayF1S0E4
}
type StructF1S1 struct {
}
type StructF1S2 struct {
F0 uint32
F1 uint8
F2 string
F3 string
F4 ArrayF1S1E1
}
type StructF1S3 struct {
F0 float64
}
type StructF1S4 struct {
_ int32
F1 float32
}
type StructF1S5 struct {
F0 uint16
}
type StructF1S6 struct {
F0 uint8
F1 uint32
}
type ArrayF1S0E4 [4]float64
type ArrayF1S1E1 [1]StructF1S3
type ArrayF1S2E2 [2]StructF1S4
type ArrayF1S3E2 [2]StructF1S5
type ArrayF1S4E4 [4]ArrayF1S5E3
type ArrayF1S5E3 [3]string
type ArrayF1S6E1 [1]float64
type StructF2S0 struct {
F0 ArrayF2S1E1
}
// equal func for StructF2S0
//go:noinline
func EqualStructF2S0(left StructF2S0, right StructF2S0) bool {
return EqualArrayF2S1E1(left.F0, right.F0)
}
type StructF2S1 struct {
_ string
F1 string
}
type ArrayF2S0E0 [0]int8
type ArrayF2S1E1 [1]*float64
// equal func for ArrayF2S1E1
//go:noinline
func EqualArrayF2S1E1(left ArrayF2S1E1, right ArrayF2S1E1) bool {
return *left[0] == *right[0]
}
type ArrayF2S2E1 [1]StructF2S1
// 5 returns 4 params
//go:registerparams
//go:noinline
func Test2(p0 ArrayF2S0E0, p1 uint8, _ uint16, p3 float64) (r0 StructF2S0, r1 ArrayF2S2E1, r2 int16, r3 float32, r4 int64) {
// consume some stack space, so as to trigger morestack
var pad [16]uint64
pad[FailCount&0x1]++
rc0 := StructF2S0{F0: ArrayF2S1E1{New_3(float64(-0.4418990509835844))}}
rc1 := ArrayF2S2E1{StructF2S1{ /* _: "񊶿(z̽|" */ F1: "􂊇񊶿"}}
rc2 := int16(4162)
rc3 := float32(-7.667096e+37)
rc4 := int64(3202175648847048679)
p1f0c := uint8(57)
if p1 != p1f0c {
NoteFailureElem(9, 42, 2, "genChecker42", "parm", 1, 0, false, pad[0])
return
}
_ = uint16(10920)
p3f0c := float64(-1.597256501942112)
if p3 != p3f0c {
NoteFailureElem(9, 42, 2, "genChecker42", "parm", 3, 0, false, pad[0])
return
}
defer func(p0 ArrayF2S0E0, p1 uint8) {
// check parm passed
// check parm passed
if p1 != p1f0c {
NoteFailureElem(9, 42, 2, "genChecker42", "parm", 1, 0, false, pad[0])
return
}
// check parm captured
if p3 != p3f0c {
NoteFailureElem(9, 42, 2, "genChecker42", "parm", 3, 0, false, pad[0])
return
}
}(p0, p1)
return rc0, rc1, rc2, rc3, rc4
// 0 addr-taken params, 0 addr-taken returns
}
//go:noinline
func New_3(i float64) *float64 {
x := new(float64)
*x = i
return x
}

View File

@@ -0,0 +1,27 @@
// run
// Copyright 2021 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 main
import "fmt"
type myStruct struct {
F0 [0]struct{}
F1 float32
}
type myStruct2 struct {
F0 [0]struct{}
F1 float32
F2 [0]struct{}
}
func main() {
x := myStruct{F1: -1.25}
fmt.Println(x)
x2 := myStruct2{F1: -7.97}
fmt.Println(x2)
}

View File

@@ -0,0 +1,2 @@
{[] -1.25}
{[] -7.97 []}

View File

@@ -0,0 +1,25 @@
// run
// Copyright 2021 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 main
import (
"fmt"
)
type MyStruct struct {
F0 [0]float64
F1 byte
F2 int16
_ struct {
F0 uint32
}
}
func main() {
p0 := MyStruct{F0: [0]float64{}, F1: byte(27), F2: int16(9887)}
fmt.Println(p0)
}

View File

@@ -0,0 +1 @@
{[] 27 9887 {0}}

View File

@@ -0,0 +1,48 @@
// run
// Copyright 2021 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 main
const p0exp = "foo"
const p1exp = 10101
const p2exp = 3030303
const p3exp = 505050505
const p4exp = 70707070707
//go:noinline
//go:registerparams
func callee(p0 string, p1 uint64, p2 uint64, p3 uint64, p4 uint64) {
if p0 != p0exp {
panic("bad p0")
}
if p1 != p1exp {
panic("bad p1")
}
if p2 != p2exp {
panic("bad p2")
}
if p3 != p3exp {
panic("bad p3")
}
if p4 != p4exp {
panic("bad p4")
}
defer func(p0 string, p2 uint64) {
if p0 != p0exp {
panic("defer bad p0")
}
if p1 != p1exp {
panic("defer bad p1")
}
if p2 != p2exp {
panic("defer bad p2")
}
}(p0, p2)
}
func main() {
callee(p0exp, p1exp, p2exp, p3exp, p4exp)
}

View File

@@ -0,0 +1,36 @@
// run
// Copyright 2021 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 that when a function recovers from a panic, it
// returns the correct results to the caller (in particular,
// setting the result registers correctly).
package main
type S struct {
x uint8
y uint16
z uint32
w float64
}
var a0, b0, c0, d0 = 10, "hello", S{1, 2, 3, 4}, [2]int{111, 222}
//go:noinline
//go:registerparams
func F() (a int, b string, _ int, c S, d [2]int) {
a, b, c, d = a0, b0, c0, d0
defer func() { recover() }()
panic("XXX")
return
}
func main() {
a1, b1, zero, c1, d1 := F()
if a1 != a0 || b1 != b0 || c1 != c0 || d1 != d0 || zero != 0 { // unnamed result gets zero value
panic("FAIL")
}
}

View File

@@ -0,0 +1,61 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import (
"fmt"
)
var sink *string
type stringPair struct {
a, b string
}
type stringPairPair struct {
x, y stringPair
}
// The goal of this test is to be sure that the call arg/result expander works correctly
// for a corner case of passing a 2-nested struct that fits in registers to/from calls.
// AND, the struct has its address taken.
//go:registerparams
//go:noinline
func H(spp stringPairPair) string {
F(&spp)
return spp.x.a + " " + spp.x.b + " " + spp.y.a + " " + spp.y.b
}
//go:registerparams
//go:noinline
func G(d, c, b, a string) stringPairPair {
return stringPairPair{stringPair{a, b}, stringPair{c, d}}
}
//go:registerparams
//go:noinline
func F(spp *stringPairPair) {
spp.x.a, spp.x.b, spp.y.a, spp.y.b = spp.y.b, spp.y.a, spp.x.b, spp.x.a
}
func main() {
spp := G("this", "is", "a", "test")
s := H(spp)
gotVsWant(s, "this is a test")
}
func gotVsWant(got, want string) {
if got != want {
fmt.Printf("FAIL, got %s, wanted %s\n", got, want)
}
}

View File

@@ -0,0 +1,53 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import (
"fmt"
)
var sink *string
type stringPair struct {
a, b string
}
type stringPairPair struct {
x, y stringPair
}
// The goal of this test is to be sure that the call arg/result expander works correctly
// for a corner case of passing a 2-nested struct that fits in registers to/from calls.
//go:registerparams
//go:noinline
func H(spp stringPairPair) string {
return spp.x.a + " " + spp.x.b + " " + spp.y.a + " " + spp.y.b
}
//go:registerparams
//go:noinline
func G(a, b, c, d string) stringPairPair {
return stringPairPair{stringPair{a, b}, stringPair{c, d}}
}
func main() {
spp := G("this", "is", "a", "test")
s := H(spp)
gotVsWant(s, "this is a test")
}
func gotVsWant(got, want string) {
if got != want {
fmt.Printf("FAIL, got %s, wanted %s\n", got, want)
}
}

38
test/abi/f_ret_z_not.go Normal file
View File

@@ -0,0 +1,38 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import "fmt"
type Z struct {
}
type NZ struct {
x, y int
}
//go:noinline
func f(x, y int) (Z, NZ, Z) {
var z Z
return z, NZ{x, y}, z
}
//go:noinline
func g() (Z, NZ, Z) {
a, b, c := f(3, 4)
return c, b, a
}
func main() {
_, b, _ := g()
fmt.Println(b.x + b.y)
}

1
test/abi/f_ret_z_not.out Normal file
View File

@@ -0,0 +1 @@
7

32
test/abi/fibish.go Normal file
View File

@@ -0,0 +1,32 @@
// run
//go:build !wasm
// Copyright 2021 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 main
import "fmt"
// Test that register results are correctly returned (and passed)
//go:registerparams
//go:noinline
func f(x int) (int, int) {
if x < 3 {
return 0, x
}
a, b := f(x - 2)
c, d := f(x - 1)
return a + d, b + c
}
func main() {
x := 40
a, b := f(x)
fmt.Printf("f(%d)=%d,%d\n", x, a, b)
}

1
test/abi/fibish.out Normal file
View File

@@ -0,0 +1 @@
f(40)=39088169,126491972

View File

@@ -0,0 +1,33 @@
// run
//go:build !wasm
// Copyright 2021 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 main
import "fmt"
// Test that register results are correctly returned (and passed)
type MagicLastTypeNameForTestingRegisterABI func(int, MagicLastTypeNameForTestingRegisterABI) (int, int)
//go:noinline
func f(x int, unused MagicLastTypeNameForTestingRegisterABI) (int, int) {
if x < 3 {
return 0, x
}
a, b := f(x-2, unused)
c, d := f(x-1, unused)
return a + d, b + c
}
func main() {
x := 40
a, b := f(x, f)
fmt.Printf("f(%d)=%d,%d\n", x, a, b)
}

View File

@@ -0,0 +1 @@
f(40)=39088169,126491972

View File

@@ -0,0 +1,39 @@
// run
// Copyright 2021 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 main
var p0exp = S1{
F1: complex(float64(2.3640607624715027), float64(-0.2717825524109192)),
F2: S2{F1: 9},
F3: 103050709,
}
type S1 struct {
F1 complex128
F2 S2
F3 uint64
}
type S2 struct {
F1 uint64
F2 empty
}
type empty struct {
}
//go:noinline
//go:registerparams
func callee(p0 S1) {
if p0 != p0exp {
panic("bad p0")
}
}
func main() {
callee(p0exp)
}

97
test/abi/idata.go Normal file
View File

@@ -0,0 +1,97 @@
// run
// Copyright 2021 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.
// Excerpted from go/constant/value.go to capture a bug from there.
package main
import (
"fmt"
"math"
"math/big"
)
type (
unknownVal struct{}
intVal struct{ val *big.Int } // Int values not representable as an int64
ratVal struct{ val *big.Rat } // Float values representable as a fraction
floatVal struct{ val *big.Float } // Float values not representable as a fraction
complexVal struct{ re, im Value }
)
const prec = 512
func (unknownVal) String() string { return "unknown" }
func (x intVal) String() string { return x.val.String() }
func (x ratVal) String() string { return rtof(x).String() }
func (x floatVal) String() string {
f := x.val
// Use exact fmt formatting if in float64 range (common case):
// proceed if f doesn't underflow to 0 or overflow to inf.
if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) {
return fmt.Sprintf("%.6g", x)
}
return "OOPS"
}
func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) }
func newFloat() *big.Float { return new(big.Float).SetPrec(prec) }
//go:noinline
//go:registerparams
func itor(x intVal) ratVal { return ratVal{nil} }
//go:noinline
//go:registerparams
func itof(x intVal) floatVal { return floatVal{nil} }
func rtof(x ratVal) floatVal { return floatVal{newFloat().SetRat(x.val)} }
type Value interface {
String() string
}
//go:noinline
//go:registerparams
func ToFloat(x Value) Value {
switch x := x.(type) {
case intVal:
if smallInt(x.val) {
return itor(x)
}
return itof(x)
case ratVal, floatVal:
return x
case complexVal:
if Sign(x.im) == 0 {
return ToFloat(x.re)
}
}
return unknownVal{}
}
//go:noinline
//go:registerparams
func smallInt(x *big.Int) bool {
return false
}
//go:noinline
//go:registerparams
func Sign(x Value) int {
return 0
}
func main() {
v := ratVal{big.NewRat(22,7)}
s := ToFloat(v).String()
fmt.Printf("s=%s\n", s)
}

1
test/abi/idata.out Normal file
View File

@@ -0,0 +1 @@
s=3.14286

35
test/abi/leaf.go Normal file
View File

@@ -0,0 +1,35 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import "fmt"
type i5f5 struct {
a, b int16
c, d, e int32
r, s, t, u, v float32
}
//go:registerparams
//go:noinline
func F(x i5f5) i5f5 {
return x
}
func main() {
x := i5f5{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
y := x
z := F(x)
if y != z {
fmt.Printf("y=%v, z=%v\n", y, z)
}
}

42
test/abi/leaf2.go Normal file
View File

@@ -0,0 +1,42 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import "fmt"
type i4 struct {
a, b, c, d int
}
//go:registerparams
//go:noinline
func F(x i4) i4 {
ab := x.a + x.b
bc := x.b + x.c
cd := x.c + x.d
ad := x.a + x.d
ba := x.a - x.b
cb := x.b - x.c
dc := x.c - x.d
da := x.a - x.d
return i4{ab*bc + da, cd*ad + cb, ba*cb + ad, dc*da + bc}
}
func main() {
x := i4{1, 2, 3, 4}
y := x
z := F(x)
if (i4{12, 34, 6, 8}) != z {
fmt.Printf("y=%v, z=%v\n", y, z)
}
}

View File

@@ -0,0 +1,32 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import (
"fmt"
)
//go:registerparams
//go:noinline
func F(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int64) {
G(z, y, x, w, v, u, t, s, r, q, p, o, n, m, l, k, j, i, h, g, f, e, d, c, b, a)
}
//go:registerparams
//go:noinline
func G(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int64) {
fmt.Println(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z)
}
func main() {
F(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)
}

View File

@@ -0,0 +1 @@
26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

View File

@@ -0,0 +1,44 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import (
"fmt"
)
var sink int = 3
//go:registerparams
//go:noinline
func F(a, b, c, d, e, f *int) {
G(f, e, d, c, b, a)
sink += *a // *a == 6 after swapping in G
}
//go:registerparams
//go:noinline
func G(a, b, c, d, e, f *int) {
var scratch [1000 * 100]int
scratch[*a] = *f // scratch[6] = 1
fmt.Println(*a, *b, *c, *d, *e, *f) // Forces it to spill b
sink = scratch[*b+1] // scratch[5+1] == 1
*f, *a = *a, *f
*e, *b = *b, *e
*d, *c = *c, *d
}
func main() {
a, b, c, d, e, f := 1, 2, 3, 4, 5, 6
F(&a, &b, &c, &d, &e, &f)
fmt.Println(a, b, c, d, e, f)
fmt.Println(sink)
}

View File

@@ -0,0 +1,3 @@
6 5 4 3 2 1
6 5 4 3 2 1
7

34
test/abi/map.go Normal file
View File

@@ -0,0 +1,34 @@
// run
// Copyright 2021 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 main
import "runtime"
type T [10]int
var m map[*T]int
//go:noinline
func F() {
m = map[*T]int{
K(): V(), // the key temp should be live across call to V
}
}
//go:noinline
func V() int { runtime.GC(); runtime.GC(); runtime.GC(); return 123 }
//go:noinline
func K() *T {
p := new(T)
runtime.SetFinalizer(p, func(*T) { println("FAIL") })
return p
}
func main() {
F()
}

View File

@@ -0,0 +1,35 @@
// run
// Copyright 2021 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 main
type S int
type T struct {
a int
S
}
//go:noinline
func (s *S) M(a int, x [2]int, b float64, y [2]float64) (S, int, [2]int, float64, [2]float64) {
return *s, a, x, b, y
}
var s S = 42
var t = &T{S: s}
var fn = (*T).M // force a method wrapper
func main() {
a := 123
x := [2]int{456, 789}
b := 1.2
y := [2]float64{3.4, 5.6}
s1, a1, x1, b1, y1 := fn(t, a, x, b, y)
if a1 != a || x1 != x || b1 != b || y1 != y || s1 != s {
panic("FAIL")
}
}

View File

@@ -0,0 +1,39 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
var sink int
//go:registerparams
//go:noinline
func F(a, b, c, d, e, f, g, h, i, j, k, l, m *int) {
G(m, l, k, j, i, h, g, f, e, d, c, b, a)
// did the pointers get properly updated?
sink = *a + *m
}
//go:registerparams
//go:noinline
func G(a, b, c, d, e, f, g, h, i, j, k, l, m *int) {
// Do not reference the parameters
var scratch [1000 * 100]int
I := *c - *e - *l // zero.
scratch[I] = *d
println("Got this far!")
sink += scratch[0]
}
func main() {
a, b, c, d, e, f, g, h, i, j, k, l, m := 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
F(&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m)
println("Sink =", sink-7)
}

View File

@@ -0,0 +1,2 @@
Got this far!
Sink = 7

90
test/abi/named_results.go Normal file
View File

@@ -0,0 +1,90 @@
// run
//go:build !wasm
// Copyright 2021 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 main
import (
"fmt"
)
var sink *string
var y int
//go:registerparams
//go:noinline
func F(a, b, c *int) (x int) {
x = *a
G(&x)
x += *b
G(&x)
x += *c
G(&x)
return
}
//go:registerparams
//go:noinline
func G(x *int) {
y += *x
fmt.Println("y = ", y)
}
//go:registerparams
//go:noinline
func X() {
*sink += " !!!!!!!!!!!!!!!"
}
//go:registerparams
//go:noinline
func H(s, t string) (result string) { // result leaks to heap
result = "Aloha! " + s + " " + t
sink = &result
r := ""
if len(s) <= len(t) {
r = "OKAY! "
X()
}
return r + result
}
//go:registerparams
//go:noinline
func K(s, t string) (result string) { // result spills
result = "Aloha! " + s + " " + t
r := ""
if len(s) <= len(t) {
r = "OKAY! "
X()
}
return r + result
}
func main() {
a, b, c := 1, 4, 16
x := F(&a, &b, &c)
fmt.Printf("x = %d\n", x)
y := H("Hello", "World!")
fmt.Println("len(y) =", len(y))
fmt.Println("y =", y)
z := H("Hello", "Pal!")
fmt.Println("len(z) =", len(z))
fmt.Println("z =", z)
fmt.Println()
y = K("Hello", "World!")
fmt.Println("len(y) =", len(y))
fmt.Println("y =", y)
z = K("Hello", "Pal!")
fmt.Println("len(z) =", len(z))
fmt.Println("z =", z)
}

View File

@@ -0,0 +1,13 @@
y = 1
y = 6
y = 27
x = 21
len(y) = 41
y = OKAY! Aloha! Hello World! !!!!!!!!!!!!!!!
len(z) = 17
z = Aloha! Hello Pal!
len(y) = 25
y = OKAY! Aloha! Hello World!
len(z) = 17
z = Aloha! Hello Pal!

View File

@@ -0,0 +1,93 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import (
"fmt"
)
var sink *string
var y int
//go:registerparams
//go:noinline
func F(a, b, c *int) (x int) {
x = *a
G(&x)
x += *b
G(&x)
x += *c
G(&x)
return
}
//go:registerparams
//go:noinline
func G(x *int) {
y += *x
fmt.Println("y = ", y)
}
//go:registerparams
//go:noinline
func X() {
*sink += " !!!!!!!!!!!!!!!"
}
//go:registerparams
//go:noinline
func H(s, t string) (result string) { // result leaks to heap
result = "Aloha! " + s + " " + t
sink = &result
r := ""
if len(s) <= len(t) {
r = "OKAY! "
X()
}
return r + result
}
//go:registerparams
//go:noinline
func K(s, t string) (result string) { // result spills
result = "Aloha! " + s + " " + t
r := ""
if len(s) <= len(t) {
r = "OKAY! "
X()
}
return r + result
}
func main() {
a, b, c := 1, 4, 16
x := F(&a, &b, &c)
fmt.Printf("x = %d\n", x)
y := H("Hello", "World!")
fmt.Println("len(y) =", len(y))
fmt.Println("y =", y)
z := H("Hello", "Pal!")
fmt.Println("len(z) =", len(z))
fmt.Println("z =", z)
fmt.Println()
y = K("Hello", "World!")
fmt.Println("len(y) =", len(y))
fmt.Println("y =", y)
z = K("Hello", "Pal!")
fmt.Println("len(z) =", len(z))
fmt.Println("z =", z)
}

View File

@@ -0,0 +1,13 @@
y = 1
y = 6
y = 27
x = 21
len(y) = 41
y = OKAY! Aloha! Hello World! !!!!!!!!!!!!!!!
len(z) = 17
z = Aloha! Hello Pal!
len(y) = 25
y = OKAY! Aloha! Hello World!
len(z) = 17
z = Aloha! Hello Pal!

36
test/abi/open_defer_1.go Normal file
View File

@@ -0,0 +1,36 @@
// run
// Copyright 2021 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.
// For #45062, miscompilation of open defer of method invocation
package main
func main() {
var x, y, z int = -1, -2, -3
F(x, y, z)
}
//go:noinline
func F(x, y, z int) {
defer i.M(x, y, z)
defer func() { recover() }()
panic("XXX")
}
type T int
func (t *T) M(x, y, z int) {
if x == -1 && y == -2 && z == -3 {
return
}
println("FAIL: Expected -1, -2, -3, but x, y, z =", x, y, z)
}
var t T = 42
type I interface{ M(x, y, z int) }
var i I = &t

48
test/abi/part_live.go Normal file
View File

@@ -0,0 +1,48 @@
// run
// Copyright 2021 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.
// A test for partial liveness / partial spilling / compiler-induced GC failure
package main
import "runtime"
import "unsafe"
//go:registerparams
func F(s []int) {
for i, x := range s {
G(i, x)
}
GC()
G(len(s), cap(s))
GC()
}
//go:noinline
//go:registerparams
func G(int, int) {}
//go:registerparams
func GC() { runtime.GC(); runtime.GC() }
func main() {
s := make([]int, 3)
escape(s)
p := int(uintptr(unsafe.Pointer(&s[2])) + 42) // likely point to unallocated memory
poison([3]int{p, p, p})
F(s)
}
//go:noinline
//go:registerparams
func poison([3]int) {}
//go:noinline
//go:registerparams
func escape(s []int) {
g = s
}
var g []int

53
test/abi/part_live_2.go Normal file
View File

@@ -0,0 +1,53 @@
// run
// Copyright 2021 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.
// A test for partial liveness / partial spilling / compiler-induced GC failure
package main
import "runtime"
import "unsafe"
//go:registerparams
func F(s []int) {
for i, x := range s {
G(i, x)
}
GC()
H(&s[0]) // It's possible that this will make the spill redundant, but there's a bug in spill slot allocation.
G(len(s), cap(s))
GC()
}
//go:noinline
//go:registerparams
func G(int, int) {}
//go:noinline
//go:registerparams
func H(*int) {}
//go:registerparams
func GC() { runtime.GC(); runtime.GC() }
func main() {
s := make([]int, 3)
escape(s)
p := int(uintptr(unsafe.Pointer(&s[2])) + 42) // likely point to unallocated memory
poison([3]int{p, p, p})
F(s)
}
//go:noinline
//go:registerparams
func poison([3]int) {}
//go:noinline
//go:registerparams
func escape(s []int) {
g = s
}
var g []int

39
test/abi/reg_not_ssa.go Normal file
View File

@@ -0,0 +1,39 @@
// run
//go:build !wasm
// Copyright 2023 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 main
// small enough for registers, too large for SSA
type T struct {
a, b, c, d, e int
}
//go:noinline
func F() {
a, b := g(), g()
h(b, b)
h(a, g())
if a.a == 1 {
a = g()
}
h(a, a)
}
//go:noinline
func g() T {
return T{1, 2, 3, 4, 5}
}
//go:noinline
func h(s, t T) {
if s != t {
println("NEQ")
}
}
func main() { F() }

20
test/abi/result_live.go Normal file
View File

@@ -0,0 +1,20 @@
// errorcheck -0 -live
// Copyright 2021 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
type T struct { a, b, c, d string } // pass in registers, not SSA-able
//go:registerparams
func F() (r T) {
r.a = g(1) // ERROR "live at call to g: r"
r.b = g(2) // ERROR "live at call to g: r"
r.c = g(3) // ERROR "live at call to g: r"
r.d = g(4) // ERROR "live at call to g: r"
return
}
func g(int) string

View File

@@ -0,0 +1,46 @@
// run
// Copyright 2021 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.
// Bug: in (*bb).d, the value to be returned was not allocated to
// a register that satisfies its register mask.
package main
type bb struct {
r float64
x []float64
}
//go:noinline
func B(r float64, x []float64) I {
return bb{r, x}
}
func (b bb) d() (int, int) {
if b.r == 0 {
return 0, len(b.x)
}
return len(b.x), len(b.x)
}
type I interface { d() (int, int) }
func D(r I) (int, int) { return r.d() }
//go:noinline
func F() (int, int) {
r := float64(1)
x := []float64{0, 1, 2}
b := B(r, x)
return D(b)
}
func main() {
x, y := F()
if x != 3 || y != 3 {
panic("FAIL")
}
}

37
test/abi/return_stuff.go Normal file
View File

@@ -0,0 +1,37 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import (
"fmt"
)
//go:registerparams
//go:noinline
func F(a, b, c *int) int {
return *a + *b + *c
}
//go:registerparams
//go:noinline
func H(s, t string) string {
return s + " " + t
}
func main() {
a, b, c := 1, 4, 16
x := F(&a, &b, &c)
fmt.Printf("x = %d\n", x)
y := H("Hello", "World!")
fmt.Println("len(y) =", len(y))
fmt.Println("y =", y)
}

View File

@@ -0,0 +1,3 @@
x = 21
len(y) = 12
y = Hello World!

36
test/abi/s_sif_sif.go Normal file
View File

@@ -0,0 +1,36 @@
// run
//go:build !wasm
// Copyright 2021 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 main
// Test ensures that abi information producer and consumer agree about the
// order of registers for inputs. T's registers should be I0, F0, I1, F1.
import "fmt"
type P struct {
a int8
x float64
}
type T struct {
d, e P
}
//go:registerparams
//go:noinline
func G(t T) float64 {
return float64(t.d.a+t.e.a) + t.d.x + t.e.x
}
func main() {
x := G(T{P{10, 20}, P{30, 40}})
if x != 100.0 {
fmt.Printf("FAIL, Expected 100, got %f\n", x)
}
}

47
test/abi/spills3.go Normal file
View File

@@ -0,0 +1,47 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import "fmt"
type i4 struct {
a, b, c, d int
}
//go:noinline
func spills(px *i4) {
}
//go:registerparams
//go:noinline
func F(x i4) i4 {
ab := x.a + x.b
bc := x.b + x.c
cd := x.c + x.d
ad := x.a + x.d
ba := x.a - x.b
cb := x.b - x.c
dc := x.c - x.d
da := x.a - x.d
i := i4{ab*bc + da, cd*ad + cb, ba*cb + ad, dc*da + bc}
spills(&i)
return i
}
func main() {
x := i4{1, 2, 3, 4}
y := x
z := F(x)
if z != (i4{12, 34, 6, 8}) {
fmt.Printf("y=%v, z=%v\n", y, z)
}
}

43
test/abi/spills4.go Normal file
View File

@@ -0,0 +1,43 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import "fmt"
type i5f5 struct {
a, b int16
c, d, e int32
r, s, t, u, v float32
}
//go:noinline
func spills(_ *float32) {
}
//go:registerparams
//go:noinline
func F(x i5f5) i5f5 {
y := x.v
spills(&y)
x.r = y
return x
}
func main() {
x := i5f5{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
y := x
z := F(x)
if (i5f5{1, 2, 3, 4, 5, 10, 7, 8, 9, 10}) != z {
fmt.Printf("y=%v, z=%v\n", y, z)
}
}

View File

@@ -0,0 +1,29 @@
// run
// Copyright 2021 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.
// When the function Store an Arg and also use it in another place,
// be sure not to generate duplicated OpArgXXXReg values, which confuses
// the register allocator.
package main
//go:noinline
//go:registerparams
func F(x, y float32) {
if x < 0 {
panic("FAIL")
}
g = [4]float32{x, y, x, y}
}
var g [4]float32
func main() {
F(1, 2)
if g[0] != 1 || g[1] != 2 || g[2] != 1 || g[3] != 2 {
panic("FAIL")
}
}

View File

@@ -0,0 +1,39 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import (
"fmt"
)
var sink *string
type toobig struct {
a, b, c string
}
//go:registerparams
//go:noinline
func H(x toobig) string {
return x.a + " " + x.b + " " + x.c
}
func main() {
s := H(toobig{"Hello", "there,", "World"})
gotVsWant(s, "Hello there, World")
}
func gotVsWant(got, want string) {
if got != want {
fmt.Printf("FAIL, got %s, wanted %s\n", got, want)
}
}

View File

View File

@@ -0,0 +1,29 @@
// run
//go:build !wasm
// Copyright 2021 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 main
import "fmt"
//go:registerparams
//go:noinline
func passStruct6(a Struct6) Struct6 {
return a
}
type Struct6 struct {
Struct1
}
type Struct1 struct {
A, B, C uint
}
func main() {
fmt.Println(passStruct6(Struct6{Struct1{1, 2, 3}}))
}

View File

@@ -0,0 +1 @@
{{1 2 3}}

View File

@@ -0,0 +1,47 @@
// run
//go:build !wasm
// Copyright 2021 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 main
import (
"fmt"
)
var sink *string
type toobig struct {
// 6 words will not SSA but will fit in registers
a, b, c string
}
//go:registerparams
//go:noinline
func H(x toobig) string {
return x.a + " " + x.b + " " + x.c
}
//go:registerparams
//go:noinline
func I(a, b, c string) toobig {
return toobig{a, b, c}
}
func main() {
s := H(toobig{"Hello", "there,", "World"})
gotVsWant(s, "Hello there, World")
fmt.Println(s)
t := H(I("Ahoy", "there,", "Matey"))
gotVsWant(t, "Ahoy there, Matey")
fmt.Println(t)
}
func gotVsWant(got, want string) {
if got != want {
fmt.Printf("FAIL, got %s, wanted %s\n", got, want)
}
}

View File

@@ -0,0 +1,2 @@
Hello there, World
Ahoy there, Matey

81
test/abi/uglyfib.go Normal file
View File

@@ -0,0 +1,81 @@
// run
//go:build !wasm
// Copyright 2021 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.
// wasm is excluded because the compiler chatter about register abi pragma ends up
// on stdout, and causes the expected output to not match.
package main
import "fmt"
// This test is designed to provoke a stack growth
// in a way that very likely leaves junk in the
// parameter save area if they aren't saved or spilled
// there, as appropriate.
//go:registerparams
//go:noinline
func f(x int, xm1, xm2, p *int) {
var y = [2]int{x - 4, 0}
if x < 2 {
*p += x
return
}
x -= 3
g(*xm1, xm2, &x, p) // xm1 is no longer live.
h(*xm2, &x, &y[0], p) // xm2 is no longer live, but was spilled.
}
//go:registerparams
//go:noinline
func g(x int, xm1, xm2, p *int) {
var y = [3]int{x - 4, 0, 0}
if x < 2 {
*p += x
return
}
x -= 3
k(*xm2, &x, &y[0], p)
h(*xm1, xm2, &x, p)
}
//go:registerparams
//go:noinline
func h(x int, xm1, xm2, p *int) {
var y = [4]int{x - 4, 0, 0, 0}
if x < 2 {
*p += x
return
}
x -= 3
k(*xm1, xm2, &x, p)
f(*xm2, &x, &y[0], p)
}
//go:registerparams
//go:noinline
func k(x int, xm1, xm2, p *int) {
var y = [5]int{x - 4, 0, 0, 0, 0}
if x < 2 {
*p += x
return
}
x -= 3
f(*xm2, &x, &y[0], p)
g(*xm1, xm2, &x, p)
}
func main() {
x := 40
var y int
xm1 := x - 1
xm2 := x - 2
f(x, &xm1, &xm2, &y)
fmt.Printf("Fib(%d)=%d\n", x, y)
}

1
test/abi/uglyfib.out Normal file
View File

@@ -0,0 +1 @@
Fib(40)=102334155

View File

@@ -0,0 +1,36 @@
// run
//go:build !wasm
// Copyright 2021 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 main
//go:noinline
func F() {
b := g()
defer g2(b)
n := g()[20]
println(n)
}
type T [45]int
var x = 0
//go:noinline
func g() T {
x++
return T{20: x}
}
//go:noinline
func g2(t T) {
if t[20] != 1 {
println("FAIL", t[20])
}
}
func main() { F() }

View File

@@ -0,0 +1 @@
2

View File

@@ -0,0 +1,36 @@
// run
// Copyright 2021 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 main
type patchlist struct {
head, tail uint32
}
type frag struct {
i uint32
out patchlist
}
//go:noinline
//go:registerparams
func patch(l patchlist, i uint32) {
}
//go:noinline
//go:registerparams
func badbad(f1, f2 frag) frag {
// concat of failure is failure
if f1.i == 0 || f2.i == 0 { // internal compiler error: 'badbad': incompatible OpArgIntReg [4]: v42 and v26
return frag{}
}
patch(f1.out, f2.i)
return frag{f1.i, f2.out}
}
func main() {
badbad(frag{i: 2}, frag{i: 3})
}

46
test/alg.go Normal file
View File

@@ -0,0 +1,46 @@
// build
// Copyright 2016 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.
// This file tests that required algs are generated,
// even when similar types have been marked elsewhere
// as not needing algs. See CLs 19769 and 19770.
package main
import "fmt"
//go:noinline
func f(m map[[8]string]int) int {
var k [8]string
return m[k]
}
//go:noinline
func g(m map[[8]interface{}]int) int {
var k [8]interface{}
return m[k]
}
//go:noinline
func h(m map[[2]string]int) int {
var k [2]string
return m[k]
}
type T map[string]interface{}
func v(x ...string) string {
return x[0] + x[1]
}
func main() {
fmt.Println(
f(map[[8]string]int{}),
g(map[[8]interface{}]int{}),
h(map[[2]string]int{}),
v("a", "b"),
)
}

33
test/alias.go Normal file
View File

@@ -0,0 +1,33 @@
// 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.
// Test that error messages say what the source file says
// (uint8 vs byte, int32 vs. rune).
// Does not compile.
package main
import (
"fmt"
"unicode/utf8"
)
func f(byte) {}
func g(uint8) {}
func main() {
var x float64
f(x) // ERROR "byte"
g(x) // ERROR "uint8"
// Test across imports.
var ff fmt.Formatter
var fs fmt.State
ff.Format(fs, x) // ERROR "rune"
utf8.RuneStart(x) // ERROR "byte"
}

54
test/alias1.go Normal file
View File

@@ -0,0 +1,54 @@
// run
// 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.
// Test that dynamic interface checks treat byte=uint8
// and rune=int or rune=int32.
package main
func main() {
var x interface{}
x = byte(1)
switch x.(type) {
case uint8:
// ok
default:
panic("byte != uint8")
}
x = uint8(2)
switch x.(type) {
case byte:
// ok
default:
panic("uint8 != byte")
}
rune32 := false
x = rune(3)
switch x.(type) {
case int:
// ok
case int32:
// must be new code
rune32 = true
default:
panic("rune != int and rune != int32")
}
if rune32 {
x = int32(4)
} else {
x = int(5)
}
switch x.(type) {
case rune:
// ok
default:
panic("int (or int32) != rune")
}
}

104
test/alias2.go Normal file
View File

@@ -0,0 +1,104 @@
// errorcheck
// Copyright 2016 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 basic restrictions on type aliases.
package p
import (
"reflect"
. "reflect"
)
type T0 struct{}
// Valid type alias declarations.
type _ = T0
type _ = int
type _ = struct{}
type _ = reflect.Value
type _ = Value
type (
A0 = T0
A1 = int
A2 = struct{}
A3 = reflect.Value
A4 = Value
A5 = Value
N0 A0
)
// Methods can be declared on the original named type and the alias.
func (T0) m1() {} // GCCGO_ERROR "previous"
func (*T0) m1() {} // ERROR "method redeclared: T0\.m1|T0\.m1 already declared|redefinition of .m1."
func (A0) m1() {} // ERROR "T0\.m1 already declared|redefinition of .m1."
func (A0) m1() {} // ERROR "T0\.m1 already declared|redefinition of .m1."
func (A0) m2() {}
// Type aliases and the original type name can be used interchangeably.
var _ A0 = T0{}
var _ T0 = A0{}
// But aliases and original types cannot be used with new types based on them.
var _ N0 = T0{} // ERROR "cannot use T0{} \(value of type T0\) as N0 value in variable declaration"
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of type A0\) as N0 value in variable declaration"
var _ A5 = Value{}
var _ interface {
m1()
m2()
} = T0{}
var _ interface {
m1()
m2()
} = A0{}
func _() {
type _ = T0
type _ = int
type _ = struct{}
type _ = reflect.Value
type _ = Value
type (
A0 = T0
A1 = int
A2 = struct{}
A3 = reflect.Value
A4 = Value
A5 Value
N0 A0
)
var _ A0 = T0{}
var _ T0 = A0{}
var _ N0 = T0{} // ERROR "cannot use T0{} \(value of type T0\) as N0 value in variable declaration"
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of type A0\) as N0 value in variable declaration"
var _ A5 = Value{} // ERROR "cannot use Value{} \(value of type reflect\.Value\) as A5 value in variable declaration"
}
// Invalid type alias declarations.
type _ = reflect.ValueOf // ERROR "reflect.ValueOf .*is not a type|expected type"
func (A1) m() {} // ERROR "cannot define new methods on non-local type|may not define methods on non-local type"
func (A2) m() {} // ERROR "invalid receiver type"
func (A3) m() {} // ERROR "cannot define new methods on non-local type|may not define methods on non-local type"
func (A4) m() {} // ERROR "cannot define new methods on non-local type|may not define methods on non-local type"
type B1 = struct{}
func (B1) m() {} // ERROR "invalid receiver type"
// TODO(gri) expand

42
test/alias3.dir/a.go Normal file
View File

@@ -0,0 +1,42 @@
// Copyright 2017 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 a
import "go/build"
type (
Float64 = float64
Rune = rune
)
type (
Int int
IntAlias = Int
IntAlias2 = IntAlias
S struct {
Int
IntAlias
IntAlias2
}
)
type (
Context = build.Context
)
type (
I1 interface {
M1(IntAlias2) Float64
M2() Context
}
I2 = interface {
M1(Int) float64
M2() build.Context
}
)
var i1 I1
var i2 I2 = i1

26
test/alias3.dir/b.go Normal file
View File

@@ -0,0 +1,26 @@
// Copyright 2017 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 b
import (
"./a"
. "go/build"
)
func F(x float64) a.Float64 {
return x
}
type MyContext = Context // = build.Context
var C a.Context = Default
type S struct{}
func (S) M1(x a.IntAlias) float64 { return a.Float64(x) }
func (S) M2() Context { return Default }
var _ a.I1 = S{}
var _ a.I2 = S{}

25
test/alias3.dir/c.go Normal file
View File

@@ -0,0 +1,25 @@
// Copyright 2017 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 main
import (
"./a"
"./b"
)
func main() {
var _ float64 = b.F(0)
var _ a.Rune = int32(0)
// embedded types can have different names but the same types
var s a.S
s.Int = 1
s.IntAlias = s.Int
s.IntAlias2 = s.Int
// aliases denote identical types across packages
var c a.Context = b.C
var _ b.MyContext = c
}

7
test/alias3.go Normal file
View File

@@ -0,0 +1,7 @@
// rundir
// Copyright 2017 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 ignored

29
test/align.go Normal file
View File

@@ -0,0 +1,29 @@
// run
// Copyright 2018 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 main
// On 32-bit archs, one of the f fields of a [2]T
// will be unaligned (address of 4 mod 8).
// Make sure we can access the f fields successfully,
// particularly for load-add combo instructions
// introduced by CL 102036.
type T struct {
pad uint32
f float64
}
//go:noinline
func f(t, u *T) float64 {
return 3.0 + t.f + u.f
}
func main() {
t := [2]T{{0, 1.0}, {0, 2.0}}
sink = f(&t[0], &t[1])
}
var sink float64

254
test/append.go Normal file
View File

@@ -0,0 +1,254 @@
// run
// Copyright 2010 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.
// Semi-exhaustive test for the append predeclared function.
package main
import (
"fmt"
"reflect"
)
func verify(name string, result, expected interface{}) {
if !reflect.DeepEqual(result, expected) {
panic(name)
}
}
func main() {
for _, t := range tests {
verify(t.name, t.result, t.expected)
}
verifyStruct()
verifyInterface()
verifyType()
}
var (
zero int = 0
one int = 1
)
var tests = []struct {
name string
result, expected interface{}
}{
{"bool a", append([]bool{}), []bool{}},
{"bool b", append([]bool{}, true), []bool{true}},
{"bool c", append([]bool{}, true, false, true, true), []bool{true, false, true, true}},
{"bool d", append([]bool{true, false, true}), []bool{true, false, true}},
{"bool e", append([]bool{true, false, true}, false), []bool{true, false, true, false}},
{"bool f", append([]bool{true, false, true}, false, false, false), []bool{true, false, true, false, false, false}},
{"bool g", append([]bool{}, []bool{true}...), []bool{true}},
{"bool h", append([]bool{}, []bool{true, false, true, false}...), []bool{true, false, true, false}},
{"bool i", append([]bool{true, false, true}, []bool{true}...), []bool{true, false, true, true}},
{"bool j", append([]bool{true, false, true}, []bool{true, true, true}...), []bool{true, false, true, true, true, true}},
{"byte a", append([]byte{}), []byte{}},
{"byte b", append([]byte{}, 0), []byte{0}},
{"byte c", append([]byte{}, 0, 1, 2, 3), []byte{0, 1, 2, 3}},
{"byte d", append([]byte{0, 1, 2}), []byte{0, 1, 2}},
{"byte e", append([]byte{0, 1, 2}, 3), []byte{0, 1, 2, 3}},
{"byte f", append([]byte{0, 1, 2}, 3, 4, 5), []byte{0, 1, 2, 3, 4, 5}},
{"byte g", append([]byte{}, []byte{0}...), []byte{0}},
{"byte h", append([]byte{}, []byte{0, 1, 2, 3}...), []byte{0, 1, 2, 3}},
{"byte i", append([]byte{0, 1, 2}, []byte{3}...), []byte{0, 1, 2, 3}},
{"byte j", append([]byte{0, 1, 2}, []byte{3, 4, 5}...), []byte{0, 1, 2, 3, 4, 5}},
{"bytestr a", append([]byte{}, "0"...), []byte("0")},
{"bytestr b", append([]byte{}, "0123"...), []byte("0123")},
{"bytestr c", append([]byte("012"), "3"...), []byte("0123")},
{"bytestr d", append([]byte("012"), "345"...), []byte("012345")},
{"int16 a", append([]int16{}), []int16{}},
{"int16 b", append([]int16{}, 0), []int16{0}},
{"int16 c", append([]int16{}, 0, 1, 2, 3), []int16{0, 1, 2, 3}},
{"int16 d", append([]int16{0, 1, 2}), []int16{0, 1, 2}},
{"int16 e", append([]int16{0, 1, 2}, 3), []int16{0, 1, 2, 3}},
{"int16 f", append([]int16{0, 1, 2}, 3, 4, 5), []int16{0, 1, 2, 3, 4, 5}},
{"int16 g", append([]int16{}, []int16{0}...), []int16{0}},
{"int16 h", append([]int16{}, []int16{0, 1, 2, 3}...), []int16{0, 1, 2, 3}},
{"int16 i", append([]int16{0, 1, 2}, []int16{3}...), []int16{0, 1, 2, 3}},
{"int16 j", append([]int16{0, 1, 2}, []int16{3, 4, 5}...), []int16{0, 1, 2, 3, 4, 5}},
{"uint32 a", append([]uint32{}), []uint32{}},
{"uint32 b", append([]uint32{}, 0), []uint32{0}},
{"uint32 c", append([]uint32{}, 0, 1, 2, 3), []uint32{0, 1, 2, 3}},
{"uint32 d", append([]uint32{0, 1, 2}), []uint32{0, 1, 2}},
{"uint32 e", append([]uint32{0, 1, 2}, 3), []uint32{0, 1, 2, 3}},
{"uint32 f", append([]uint32{0, 1, 2}, 3, 4, 5), []uint32{0, 1, 2, 3, 4, 5}},
{"uint32 g", append([]uint32{}, []uint32{0}...), []uint32{0}},
{"uint32 h", append([]uint32{}, []uint32{0, 1, 2, 3}...), []uint32{0, 1, 2, 3}},
{"uint32 i", append([]uint32{0, 1, 2}, []uint32{3}...), []uint32{0, 1, 2, 3}},
{"uint32 j", append([]uint32{0, 1, 2}, []uint32{3, 4, 5}...), []uint32{0, 1, 2, 3, 4, 5}},
{"float64 a", append([]float64{}), []float64{}},
{"float64 b", append([]float64{}, 0), []float64{0}},
{"float64 c", append([]float64{}, 0, 1, 2, 3), []float64{0, 1, 2, 3}},
{"float64 d", append([]float64{0, 1, 2}), []float64{0, 1, 2}},
{"float64 e", append([]float64{0, 1, 2}, 3), []float64{0, 1, 2, 3}},
{"float64 f", append([]float64{0, 1, 2}, 3, 4, 5), []float64{0, 1, 2, 3, 4, 5}},
{"float64 g", append([]float64{}, []float64{0}...), []float64{0}},
{"float64 h", append([]float64{}, []float64{0, 1, 2, 3}...), []float64{0, 1, 2, 3}},
{"float64 i", append([]float64{0, 1, 2}, []float64{3}...), []float64{0, 1, 2, 3}},
{"float64 j", append([]float64{0, 1, 2}, []float64{3, 4, 5}...), []float64{0, 1, 2, 3, 4, 5}},
{"complex128 a", append([]complex128{}), []complex128{}},
{"complex128 b", append([]complex128{}, 0), []complex128{0}},
{"complex128 c", append([]complex128{}, 0, 1, 2, 3), []complex128{0, 1, 2, 3}},
{"complex128 d", append([]complex128{0, 1, 2}), []complex128{0, 1, 2}},
{"complex128 e", append([]complex128{0, 1, 2}, 3), []complex128{0, 1, 2, 3}},
{"complex128 f", append([]complex128{0, 1, 2}, 3, 4, 5), []complex128{0, 1, 2, 3, 4, 5}},
{"complex128 g", append([]complex128{}, []complex128{0}...), []complex128{0}},
{"complex128 h", append([]complex128{}, []complex128{0, 1, 2, 3}...), []complex128{0, 1, 2, 3}},
{"complex128 i", append([]complex128{0, 1, 2}, []complex128{3}...), []complex128{0, 1, 2, 3}},
{"complex128 j", append([]complex128{0, 1, 2}, []complex128{3, 4, 5}...), []complex128{0, 1, 2, 3, 4, 5}},
{"string a", append([]string{}), []string{}},
{"string b", append([]string{}, "0"), []string{"0"}},
{"string c", append([]string{}, "0", "1", "2", "3"), []string{"0", "1", "2", "3"}},
{"string d", append([]string{"0", "1", "2"}), []string{"0", "1", "2"}},
{"string e", append([]string{"0", "1", "2"}, "3"), []string{"0", "1", "2", "3"}},
{"string f", append([]string{"0", "1", "2"}, "3", "4", "5"), []string{"0", "1", "2", "3", "4", "5"}},
{"string g", append([]string{}, []string{"0"}...), []string{"0"}},
{"string h", append([]string{}, []string{"0", "1", "2", "3"}...), []string{"0", "1", "2", "3"}},
{"string i", append([]string{"0", "1", "2"}, []string{"3"}...), []string{"0", "1", "2", "3"}},
{"string j", append([]string{"0", "1", "2"}, []string{"3", "4", "5"}...), []string{"0", "1", "2", "3", "4", "5"}},
{"make a", append([]string{}, make([]string, 0)...), []string{}},
{"make b", append([]string(nil), make([]string, 0)...), []string(nil)},
{"make c", append([]struct{}{}, make([]struct{}, 0)...), []struct{}{}},
{"make d", append([]struct{}{}, make([]struct{}, 2)...), make([]struct{}, 2)},
{"make e", append([]int{0, 1}, make([]int, 0)...), []int{0, 1}},
{"make f", append([]int{0, 1}, make([]int, 2)...), []int{0, 1, 0, 0}},
{"make g", append([]*int{&zero, &one}, make([]*int, 0)...), []*int{&zero, &one}},
{"make h", append([]*int{&zero, &one}, make([]*int, 2)...), []*int{&zero, &one, nil, nil}},
}
func verifyStruct() {
type T struct {
a, b, c string
}
type S []T
e := make(S, 100)
for i := range e {
e[i] = T{"foo", fmt.Sprintf("%d", i), "bar"}
}
verify("struct a", append(S{}), S{})
verify("struct b", append(S{}, e[0]), e[0:1])
verify("struct c", append(S{}, e[0], e[1], e[2]), e[0:3])
verify("struct d", append(e[0:1]), e[0:1])
verify("struct e", append(e[0:1], e[1]), e[0:2])
verify("struct f", append(e[0:1], e[1], e[2], e[3]), e[0:4])
verify("struct g", append(e[0:3]), e[0:3])
verify("struct h", append(e[0:3], e[3]), e[0:4])
verify("struct i", append(e[0:3], e[3], e[4], e[5], e[6]), e[0:7])
for i := range e {
verify("struct j", append(S{}, e[0:i]...), e[0:i])
input := make(S, i)
copy(input, e[0:i])
verify("struct k", append(input, e[i:]...), e)
verify("struct k - input modified", input, e[0:i])
}
s := make(S, 10, 20)
r := make(S, len(s)+len(e))
for i, x := range e {
r[len(s)+i] = x
}
verify("struct l", append(s), s)
verify("struct m", append(s, e...), r)
}
func verifyInterface() {
type T interface{}
type S []T
e := make(S, 100)
for i := range e {
switch i % 4 {
case 0:
e[i] = i
case 1:
e[i] = "foo"
case 2:
e[i] = fmt.Sprintf("%d", i)
case 3:
e[i] = float64(i)
}
}
verify("interface a", append(S{}), S{})
verify("interface b", append(S{}, e[0]), e[0:1])
verify("interface c", append(S{}, e[0], e[1], e[2]), e[0:3])
verify("interface d", append(e[0:1]), e[0:1])
verify("interface e", append(e[0:1], e[1]), e[0:2])
verify("interface f", append(e[0:1], e[1], e[2], e[3]), e[0:4])
verify("interface g", append(e[0:3]), e[0:3])
verify("interface h", append(e[0:3], e[3]), e[0:4])
verify("interface i", append(e[0:3], e[3], e[4], e[5], e[6]), e[0:7])
for i := range e {
verify("interface j", append(S{}, e[0:i]...), e[0:i])
input := make(S, i)
copy(input, e[0:i])
verify("interface k", append(input, e[i:]...), e)
verify("interface k - input modified", input, e[0:i])
}
s := make(S, 10, 20)
r := make(S, len(s)+len(e))
for i, x := range e {
r[len(s)+i] = x
}
verify("interface l", append(s), s)
verify("interface m", append(s, e...), r)
}
type T1 []int
type T2 []int
func verifyType() {
// The second argument to append has type []E where E is the
// element type of the first argument. Test that the compiler
// accepts two slice types that meet that requirement but are
// not assignment compatible. The return type of append is
// the type of the first argument.
t1 := T1{1}
t2 := T2{2}
verify("T1", append(t1, t2...), T1{1, 2})
}

22
test/append1.go Normal file
View File

@@ -0,0 +1,22 @@
// errorcheck
// Copyright 2017 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 that append arguments requirements are enforced by the
// compiler.
package main
func main() {
s := make([]int, 8)
_ = append() // ERROR "missing arguments to append|not enough arguments for append"
_ = append(s...) // ERROR "cannot use ... on first argument|not enough arguments in call to append"
_ = append(s, 2, s...) // ERROR "too many arguments to append|too many arguments in call to append"
_ = append(s, make([]int, 0)) // ERROR "cannot use make\(\[\]int, 0\) \(value of type \[\]int\) as int value in argument to append"
_ = append(s, make([]int, -1)...) // ERROR "negative len argument in make|index -1.* must not be negative"
}

65
test/arenas/smoke.go Normal file
View File

@@ -0,0 +1,65 @@
// build -goexperiment arenas
// Copyright 2023 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 main
import (
"arena"
"log"
"reflect"
)
func main() {
a := arena.NewArena()
defer a.Free()
const iValue = 10
i := arena.New[int](a)
*i = iValue
if *i != iValue {
// This test doesn't reasonably expect this to fail. It's more likely
// that *i crashes for some reason. Still, why not check it.
log.Fatalf("bad i value: got %d, want %d", *i, iValue)
}
const wantLen = 125
const wantCap = 1912
sl := arena.MakeSlice[*int](a, wantLen, wantCap)
if len(sl) != wantLen {
log.Fatalf("bad arena slice length: got %d, want %d", len(sl), wantLen)
}
if cap(sl) != wantCap {
log.Fatalf("bad arena slice capacity: got %d, want %d", cap(sl), wantCap)
}
sl = sl[:cap(sl)]
for j := range sl {
sl[j] = i
}
for j := range sl {
if *sl[j] != iValue {
// This test doesn't reasonably expect this to fail. It's more likely
// that sl[j] crashes for some reason. Still, why not check it.
log.Fatalf("bad sl[j] value: got %d, want %d", *sl[j], iValue)
}
}
t := reflect.TypeOf(int(0))
v := reflect.ArenaNew(a, t)
if want := reflect.PointerTo(t); v.Type() != want {
log.Fatalf("unexpected type for arena-allocated value: got %s, want %s", v.Type(), want)
}
i2 := v.Interface().(*int)
*i2 = iValue
if *i2 != iValue {
// This test doesn't reasonably expect this to fail. It's more likely
// that *i crashes for some reason. Still, why not check it.
log.Fatalf("bad i2 value: got %d, want %d", *i2, iValue)
}
}

23
test/args.go Normal file
View File

@@ -0,0 +1,23 @@
// run arg1 arg2
// Copyright 2009 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 os.Args.
package main
import "os"
func main() {
if len(os.Args) != 3 {
panic("argc")
}
if os.Args[1] != "arg1" {
panic("arg1")
}
if os.Args[2] != "arg2" {
panic("arg2")
}
}

179
test/armimm.go Normal file
View File

@@ -0,0 +1,179 @@
// run
// Copyright 2017 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.
// This file tests the splitting of constants into
// multiple immediates on arm.
package main
import "fmt"
const c32a = 0x00aa00dd
const c32s = 0x00ffff00
const c64a = 0x00aa00dd55000066
const c64s = 0x00ffff00004fff00
//go:noinline
func add32a(x uint32) uint32 {
return x + c32a
}
//go:noinline
func add32s(x uint32) uint32 {
return x + c32s
}
//go:noinline
func sub32a(x uint32) uint32 {
return x - c32a
}
//go:noinline
func sub32s(x uint32) uint32 {
return x - c32s
}
//go:noinline
func or32(x uint32) uint32 {
return x | c32a
}
//go:noinline
func xor32(x uint32) uint32 {
return x ^ c32a
}
//go:noinline
func subr32a(x uint32) uint32 {
return c32a - x
}
//go:noinline
func subr32s(x uint32) uint32 {
return c32s - x
}
//go:noinline
func bic32(x uint32) uint32 {
return x &^ c32a
}
//go:noinline
func add64a(x uint64) uint64 {
return x + c64a
}
//go:noinline
func add64s(x uint64) uint64 {
return x + c64s
}
//go:noinline
func sub64a(x uint64) uint64 {
return x - c64a
}
//go:noinline
func sub64s(x uint64) uint64 {
return x - c64s
}
//go:noinline
func or64(x uint64) uint64 {
return x | c64a
}
//go:noinline
func xor64(x uint64) uint64 {
return x ^ c64a
}
//go:noinline
func subr64a(x uint64) uint64 {
return c64a - x
}
//go:noinline
func subr64s(x uint64) uint64 {
return c64s - x
}
//go:noinline
func bic64(x uint64) uint64 {
return x &^ c64a
}
// Note: x-c gets rewritten to x+(-c), so SUB and SBC are not directly testable.
// I disabled that rewrite rule before running this test.
func main() {
test32()
test64()
}
func test32() {
var a uint32 = 0x11111111
var want, got uint32
if want, got = a+c32a, add32a(a); got != want {
panic(fmt.Sprintf("add32a(%x) = %x, want %x", a, got, want))
}
if want, got = a+c32s, add32s(a); got != want {
panic(fmt.Sprintf("add32s(%x) = %x, want %x", a, got, want))
}
if want, got = a-c32a, sub32a(a); got != want {
panic(fmt.Sprintf("sub32a(%x) = %x, want %x", a, got, want))
}
if want, got = a-c32s, sub32s(a); got != want {
panic(fmt.Sprintf("sub32s(%x) = %x, want %x", a, got, want))
}
if want, got = a|c32a, or32(a); got != want {
panic(fmt.Sprintf("or32(%x) = %x, want %x", a, got, want))
}
if want, got = a^c32a, xor32(a); got != want {
panic(fmt.Sprintf("xor32(%x) = %x, want %x", a, got, want))
}
if want, got = c32a-a, subr32a(a); got != want {
panic(fmt.Sprintf("subr32a(%x) = %x, want %x", a, got, want))
}
if want, got = c32s-a, subr32s(a); got != want {
panic(fmt.Sprintf("subr32s(%x) = %x, want %x", a, got, want))
}
if want, got = a&^c32a, bic32(a); got != want {
panic(fmt.Sprintf("bic32(%x) = %x, want %x", a, got, want))
}
}
func test64() {
var a uint64 = 0x1111111111111111
var want, got uint64
if want, got = a+c64a, add64a(a); got != want {
panic(fmt.Sprintf("add64a(%x) = %x, want %x", a, got, want))
}
if want, got = a+c64s, add64s(a); got != want {
panic(fmt.Sprintf("add64s(%x) = %x, want %x", a, got, want))
}
if want, got = a-c64a, sub64a(a); got != want {
panic(fmt.Sprintf("sub64a(%x) = %x, want %x", a, got, want))
}
if want, got = a-c64s, sub64s(a); got != want {
panic(fmt.Sprintf("sub64s(%x) = %x, want %x", a, got, want))
}
if want, got = a|c64a, or64(a); got != want {
panic(fmt.Sprintf("or64(%x) = %x, want %x", a, got, want))
}
if want, got = a^c64a, xor64(a); got != want {
panic(fmt.Sprintf("xor64(%x) = %x, want %x", a, got, want))
}
if want, got = c64a-a, subr64a(a); got != want {
panic(fmt.Sprintf("subr64a(%x) = %x, want %x", a, got, want))
}
if want, got = c64s-a, subr64s(a); got != want {
panic(fmt.Sprintf("subr64s(%x) = %x, want %x", a, got, want))
}
if want, got = a&^c64a, bic64(a); got != want {
panic(fmt.Sprintf("bic64(%x) = %x, want %x", a, got, want))
}
}

72
test/asmhdr.dir/main.go Normal file
View File

@@ -0,0 +1,72 @@
// Copyright 2021 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 main
import "unsafe"
const (
smallInt = 42
// For bigInt, we use a value that's too big for an int64, but still
// fits in uint64. go/constant uses a different representation for
// values larger than int64, but the cmd/asm parser can't parse
// anything bigger than a uint64.
bigInt = 0xffffffffffffffff
stringVal = "test"
longStringVal = "this_is_a_string_constant_longer_than_seventy_characters_which_used_to_fail_see_issue_50253"
)
var (
smallIntAsm int64
bigIntAsm uint64
stringAsm [len(stringVal)]byte
longStringAsm [len(longStringVal)]byte
)
type typ struct {
a uint64
b [100]uint8
c uint8
}
var (
typSize uint64
typA, typB, typC uint64
)
func main() {
if smallInt != smallIntAsm {
println("smallInt", smallInt, "!=", smallIntAsm)
}
if bigInt != bigIntAsm {
println("bigInt", uint64(bigInt), "!=", bigIntAsm)
}
if stringVal != string(stringAsm[:]) {
println("stringVal", stringVal, "!=", string(stringAsm[:]))
}
if longStringVal != string(longStringAsm[:]) {
println("longStringVal", longStringVal, "!=", string(longStringAsm[:]))
}
// We also include boolean consts in go_asm.h, but they're
// defined to be "true" or "false", and it's not clear how to
// use that in assembly.
if want := unsafe.Sizeof(typ{}); want != uintptr(typSize) {
println("typSize", want, "!=", typSize)
}
if want := unsafe.Offsetof(typ{}.a); want != uintptr(typA) {
println("typA", want, "!=", typA)
}
if want := unsafe.Offsetof(typ{}.b); want != uintptr(typB) {
println("typB", want, "!=", typB)
}
if want := unsafe.Offsetof(typ{}.c); want != uintptr(typC) {
println("typC", want, "!=", typC)
}
}

30
test/asmhdr.dir/main.s Normal file
View File

@@ -0,0 +1,30 @@
// Copyright 2021 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.
#include "go_asm.h"
#define RODATA 8
DATA ·smallIntAsm(SB)/8, $const_smallInt
GLOBL ·smallIntAsm(SB),RODATA,$8
DATA ·bigIntAsm(SB)/8, $const_bigInt
GLOBL ·bigIntAsm(SB),RODATA,$8
DATA ·stringAsm(SB)/4, $const_stringVal
GLOBL ·stringAsm(SB),RODATA,$4
DATA ·longStringAsm(SB)/91, $const_longStringVal
GLOBL ·longStringAsm(SB),RODATA,$91
DATA ·typSize(SB)/8, $typ__size
GLOBL ·typSize(SB),RODATA,$8
DATA ·typA(SB)/8, $typ_a
GLOBL ·typA(SB),RODATA,$8
DATA ·typB(SB)/8, $typ_b
GLOBL ·typB(SB),RODATA,$8
DATA ·typC(SB)/8, $typ_c
GLOBL ·typC(SB),RODATA,$8

9
test/asmhdr.go Normal file
View File

@@ -0,0 +1,9 @@
// buildrundir
// Copyright 2021 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 the -asmhdr output of the compiler.
package ignored

68
test/assign.go Normal file
View File

@@ -0,0 +1,68 @@
// errorcheck
// Copyright 2009 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 simple assignment errors are caught by the compiler.
// Does not compile.
package main
import "sync"
type T struct {
int
sync.Mutex
}
func main() {
{
var x, y sync.Mutex
x = y // ok
_ = x
}
{
var x, y T
x = y // ok
_ = x
}
{
var x, y [2]sync.Mutex
x = y // ok
_ = x
}
{
var x, y [2]T
x = y // ok
_ = x
}
{
x := sync.Mutex{0, 0} // ERROR "assignment.*Mutex"
_ = x
}
{
x := sync.Mutex{key: 0} // ERROR "(unknown|assignment).*Mutex"
_ = x
}
{
x := &sync.Mutex{} // ok
var y sync.Mutex // ok
y = *x // ok
*x = y // ok
_ = x
_ = y
}
{
var x = 1
{
x, x := 2, 3 // ERROR ".*x.* repeated on left side of :=|x redeclared in this block"
_ = x
}
_ = x
}
{
a, a := 1, 2 // ERROR ".*a.* repeated on left side of :=|a redeclared in this block"
_ = a
}
}

346
test/assign1.go Normal file
View File

@@ -0,0 +1,346 @@
// errorcheck
// Copyright 2009 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 assignment rules are enforced by the compiler.
// Does not compile.
package main
type (
A [10]int
B []int
C chan int
F func() int
I interface {
m() int
}
M map[int]int
P *int
S struct {
X int
}
A1 [10]int
B1 []int
C1 chan int
F1 func() int
I1 interface {
m() int
}
M1 map[int]int
P1 *int
S1 struct {
X int
}
)
var (
a0 [10]int
b0 []int
c0 chan int
f0 func() int
i0 interface {
m() int
}
m0 map[int]int
p0 *int
s0 struct {
X int
}
a A
b B
c C
f F
i I
m M
p P
s S
a1 A1
b1 B1
c1 C1
f1 F1
i1 I1
m1 M1
p1 P1
s1 S1
pa0 *[10]int
pb0 *[]int
pc0 *chan int
pf0 *func() int
pi0 *interface {
m() int
}
pm0 *map[int]int
pp0 **int
ps0 *struct {
X int
}
pa *A
pb *B
pc *C
pf *F
pi *I
pm *M
pp *P
ps *S
pa1 *A1
pb1 *B1
pc1 *C1
pf1 *F1
pi1 *I1
pm1 *M1
pp1 *P1
ps1 *S1
)
func main() {
a0 = a
a0 = a1
a = a0
a = a1 // ERROR "cannot use"
a1 = a0
a1 = a // ERROR "cannot use"
b0 = b
b0 = b1
b = b0
b = b1 // ERROR "cannot use"
b1 = b0
b1 = b // ERROR "cannot use"
c0 = c
c0 = c1
c = c0
c = c1 // ERROR "cannot use"
c1 = c0
c1 = c // ERROR "cannot use"
f0 = f
f0 = f1
f = f0
f = f1 // ERROR "cannot use"
f1 = f0
f1 = f // ERROR "cannot use"
i0 = i
i0 = i1
i = i0
i = i1
i1 = i0
i1 = i
m0 = m
m0 = m1
m = m0
m = m1 // ERROR "cannot use"
m1 = m0
m1 = m // ERROR "cannot use"
p0 = p
p0 = p1
p = p0
p = p1 // ERROR "cannot use"
p1 = p0
p1 = p // ERROR "cannot use"
s0 = s
s0 = s1
s = s0
s = s1 // ERROR "cannot use"
s1 = s0
s1 = s // ERROR "cannot use"
pa0 = pa // ERROR "cannot use|incompatible"
pa0 = pa1 // ERROR "cannot use|incompatible"
pa = pa0 // ERROR "cannot use|incompatible"
pa = pa1 // ERROR "cannot use|incompatible"
pa1 = pa0 // ERROR "cannot use|incompatible"
pa1 = pa // ERROR "cannot use|incompatible"
pb0 = pb // ERROR "cannot use|incompatible"
pb0 = pb1 // ERROR "cannot use|incompatible"
pb = pb0 // ERROR "cannot use|incompatible"
pb = pb1 // ERROR "cannot use|incompatible"
pb1 = pb0 // ERROR "cannot use|incompatible"
pb1 = pb // ERROR "cannot use|incompatible"
pc0 = pc // ERROR "cannot use|incompatible"
pc0 = pc1 // ERROR "cannot use|incompatible"
pc = pc0 // ERROR "cannot use|incompatible"
pc = pc1 // ERROR "cannot use|incompatible"
pc1 = pc0 // ERROR "cannot use|incompatible"
pc1 = pc // ERROR "cannot use|incompatible"
pf0 = pf // ERROR "cannot use|incompatible"
pf0 = pf1 // ERROR "cannot use|incompatible"
pf = pf0 // ERROR "cannot use|incompatible"
pf = pf1 // ERROR "cannot use|incompatible"
pf1 = pf0 // ERROR "cannot use|incompatible"
pf1 = pf // ERROR "cannot use|incompatible"
pi0 = pi // ERROR "cannot use|incompatible"
pi0 = pi1 // ERROR "cannot use|incompatible"
pi = pi0 // ERROR "cannot use|incompatible"
pi = pi1 // ERROR "cannot use|incompatible"
pi1 = pi0 // ERROR "cannot use|incompatible"
pi1 = pi // ERROR "cannot use|incompatible"
pm0 = pm // ERROR "cannot use|incompatible"
pm0 = pm1 // ERROR "cannot use|incompatible"
pm = pm0 // ERROR "cannot use|incompatible"
pm = pm1 // ERROR "cannot use|incompatible"
pm1 = pm0 // ERROR "cannot use|incompatible"
pm1 = pm // ERROR "cannot use|incompatible"
pp0 = pp // ERROR "cannot use|incompatible"
pp0 = pp1 // ERROR "cannot use|incompatible"
pp = pp0 // ERROR "cannot use|incompatible"
pp = pp1 // ERROR "cannot use|incompatible"
pp1 = pp0 // ERROR "cannot use|incompatible"
pp1 = pp // ERROR "cannot use|incompatible"
ps0 = ps // ERROR "cannot use|incompatible"
ps0 = ps1 // ERROR "cannot use|incompatible"
ps = ps0 // ERROR "cannot use|incompatible"
ps = ps1 // ERROR "cannot use|incompatible"
ps1 = ps0 // ERROR "cannot use|incompatible"
ps1 = ps // ERROR "cannot use|incompatible"
a0 = [10]int(a)
a0 = [10]int(a1)
a = A(a0)
a = A(a1)
a1 = A1(a0)
a1 = A1(a)
b0 = []int(b)
b0 = []int(b1)
b = B(b0)
b = B(b1)
b1 = B1(b0)
b1 = B1(b)
c0 = chan int(c)
c0 = chan int(c1)
c = C(c0)
c = C(c1)
c1 = C1(c0)
c1 = C1(c)
f0 = func() int(f)
f0 = func() int(f1)
f = F(f0)
f = F(f1)
f1 = F1(f0)
f1 = F1(f)
i0 = interface {
m() int
}(i)
i0 = interface {
m() int
}(i1)
i = I(i0)
i = I(i1)
i1 = I1(i0)
i1 = I1(i)
m0 = map[int]int(m)
m0 = map[int]int(m1)
m = M(m0)
m = M(m1)
m1 = M1(m0)
m1 = M1(m)
p0 = (*int)(p)
p0 = (*int)(p1)
p = P(p0)
p = P(p1)
p1 = P1(p0)
p1 = P1(p)
s0 = struct {
X int
}(s)
s0 = struct {
X int
}(s1)
s = S(s0)
s = S(s1)
s1 = S1(s0)
s1 = S1(s)
pa0 = (*[10]int)(pa)
pa0 = (*[10]int)(pa1)
pa = (*A)(pa0)
pa = (*A)(pa1)
pa1 = (*A1)(pa0)
pa1 = (*A1)(pa)
pb0 = (*[]int)(pb)
pb0 = (*[]int)(pb1)
pb = (*B)(pb0)
pb = (*B)(pb1)
pb1 = (*B1)(pb0)
pb1 = (*B1)(pb)
pc0 = (*chan int)(pc)
pc0 = (*chan int)(pc1)
pc = (*C)(pc0)
pc = (*C)(pc1)
pc1 = (*C1)(pc0)
pc1 = (*C1)(pc)
pf0 = (*func() int)(pf)
pf0 = (*func() int)(pf1)
pf = (*F)(pf0)
pf = (*F)(pf1)
pf1 = (*F1)(pf0)
pf1 = (*F1)(pf)
pi0 = (*interface {
m() int
})(pi)
pi0 = (*interface {
m() int
})(pi1)
pi = (*I)(pi0)
pi = (*I)(pi1)
pi1 = (*I1)(pi0)
pi1 = (*I1)(pi)
pm0 = (*map[int]int)(pm)
pm0 = (*map[int]int)(pm1)
pm = (*M)(pm0)
pm = (*M)(pm1)
pm1 = (*M1)(pm0)
pm1 = (*M1)(pm)
pp0 = (**int)(pp)
pp0 = (**int)(pp1)
pp = (*P)(pp0)
pp = (*P)(pp1)
pp1 = (*P1)(pp0)
pp1 = (*P1)(pp)
ps0 = (*struct {
X int
})(ps)
ps0 = (*struct {
X int
})(ps1)
ps = (*S)(ps0)
ps = (*S)(ps1)
ps1 = (*S1)(ps0)
ps1 = (*S1)(ps)
}

45
test/atomicload.go Normal file
View File

@@ -0,0 +1,45 @@
// run
// Copyright 2016 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.
// Check that we do loads exactly once. The SSA backend
// once tried to do the load in f twice, once sign extended
// and once zero extended. This can cause problems in
// racy code, particularly sync/mutex.
package main
func f(p *byte) bool {
x := *p
a := int64(int8(x))
b := int64(uint8(x))
return a == b
}
func main() {
var x byte
const N = 1000000
c := make(chan struct{})
go func() {
for i := 0; i < N; i++ {
x = 1
}
c <- struct{}{}
}()
go func() {
for i := 0; i < N; i++ {
x = 2
}
c <- struct{}{}
}()
for i := 0; i < N; i++ {
if !f(&x) {
panic("non-atomic load!")
}
}
<-c
<-c
}

130
test/bigalg.go Normal file
View File

@@ -0,0 +1,130 @@
// run
// Copyright 2009 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 the internal "algorithms" for objects larger than a word: hashing, equality etc.
package main
type T struct {
a float64
b int64
c string
d byte
}
var a = []int{1, 2, 3}
var NIL []int
func arraycmptest() {
if NIL != nil {
println("fail1:", NIL, "!= nil")
panic("bigalg")
}
if nil != NIL {
println("fail2: nil !=", NIL)
panic("bigalg")
}
if a == nil || nil == a {
println("fail3:", a, "== nil")
panic("bigalg")
}
}
func SameArray(a, b []int) bool {
if len(a) != len(b) || cap(a) != cap(b) {
return false
}
if len(a) > 0 && &a[0] != &b[0] {
return false
}
return true
}
var t = T{1.5, 123, "hello", 255}
var mt = make(map[int]T)
var ma = make(map[int][]int)
func maptest() {
mt[0] = t
t1 := mt[0]
if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
println("fail: map val struct", t1.a, t1.b, t1.c, t1.d)
panic("bigalg")
}
ma[1] = a
a1 := ma[1]
if !SameArray(a, a1) {
println("fail: map val array", a, a1)
panic("bigalg")
}
}
var ct = make(chan T)
var ca = make(chan []int)
func send() {
ct <- t
ca <- a
}
func chantest() {
go send()
t1 := <-ct
if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
println("fail: map val struct", t1.a, t1.b, t1.c, t1.d)
panic("bigalg")
}
a1 := <-ca
if !SameArray(a, a1) {
println("fail: map val array", a, a1)
panic("bigalg")
}
}
type E struct{}
var e E
func interfacetest() {
var i interface{}
i = a
a1 := i.([]int)
if !SameArray(a, a1) {
println("interface <-> []int", a, a1)
panic("bigalg")
}
pa := new([]int)
*pa = a
i = pa
a1 = *i.(*[]int)
if !SameArray(a, a1) {
println("interface <-> *[]int", a, a1)
panic("bigalg")
}
i = t
t1 := i.(T)
if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
println("interface <-> struct", t1.a, t1.b, t1.c, t1.d)
panic("bigalg")
}
i = e
e1 := i.(E)
// nothing to check; just verify it doesn't crash
_ = e1
}
func main() {
arraycmptest()
maptest()
chantest()
interfacetest()
}

139
test/bigmap.go Normal file
View File

@@ -0,0 +1,139 @@
// run
// Copyright 2009 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.
// Internally a map holds elements in up to 255 bytes of key+value.
// When key or value or both are too large, it uses pointers to key+value
// instead. Test all the combinations.
package main
func seq(x, y int) [1000]byte {
var r [1000]byte
for i := 0; i < len(r); i++ {
r[i] = byte(x + i*y)
}
return r
}
func cmp(x, y [1000]byte) {
for i := 0; i < len(x); i++ {
if x[i] != y[i] {
panic("BUG mismatch")
}
}
}
func main() {
m := make(map[int][1000]byte)
m[1] = seq(11, 13)
m[2] = seq(2, 9)
m[3] = seq(3, 17)
cmp(m[1], seq(11, 13))
cmp(m[2], seq(2, 9))
cmp(m[3], seq(3, 17))
{
type T [1]byte
type V [1]byte
m := make(map[T]V)
m[T{}] = V{1}
m[T{1}] = V{2}
if x, y := m[T{}][0], m[T{1}][0]; x != 1 || y != 2 {
println(x, y)
panic("bad map")
}
}
{
type T [100]byte
type V [1]byte
m := make(map[T]V)
m[T{}] = V{1}
m[T{1}] = V{2}
if x, y := m[T{}][0], m[T{1}][0]; x != 1 || y != 2 {
println(x, y)
panic("bad map")
}
}
{
type T [1]byte
type V [100]byte
m := make(map[T]V)
m[T{}] = V{1}
m[T{1}] = V{2}
if x, y := m[T{}][0], m[T{1}][0]; x != 1 || y != 2 {
println(x, y)
panic("bad map")
}
}
{
type T [1000]byte
type V [1]byte
m := make(map[T]V)
m[T{}] = V{1}
m[T{1}] = V{2}
if x, y := m[T{}][0], m[T{1}][0]; x != 1 || y != 2 {
println(x, y)
panic("bad map")
}
}
{
type T [1]byte
type V [1000]byte
m := make(map[T]V)
m[T{}] = V{1}
m[T{1}] = V{2}
if x, y := m[T{}][0], m[T{1}][0]; x != 1 || y != 2 {
println(x, y)
panic("bad map")
}
}
{
type T [1000]byte
type V [1000]byte
m := make(map[T]V)
m[T{}] = V{1}
m[T{1}] = V{2}
if x, y := m[T{}][0], m[T{1}][0]; x != 1 || y != 2 {
println(x, y)
panic("bad map")
}
}
{
type T [200]byte
type V [1]byte
m := make(map[T]V)
m[T{}] = V{1}
m[T{1}] = V{2}
if x, y := m[T{}][0], m[T{1}][0]; x != 1 || y != 2 {
println(x, y)
panic("bad map")
}
}
{
type T [1]byte
type V [200]byte
m := make(map[T]V)
m[T{}] = V{1}
m[T{1}] = V{2}
if x, y := m[T{}][0], m[T{1}][0]; x != 1 || y != 2 {
println(x, y)
panic("bad map")
}
}
{
type T [200]byte
type V [200]byte
m := make(map[T]V)
m[T{}] = V{1}
m[T{1}] = V{2}
if x, y := m[T{}][0], m[T{1}][0]; x != 1 || y != 2 {
println(x, y)
panic("bad map")
}
}
}

189
test/blank.go Normal file
View File

@@ -0,0 +1,189 @@
// run
// Copyright 2009 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 behavior of the blank identifier (_).
package main
import (
"os"
"unsafe"
)
import _ "fmt"
var call string
type T struct {
_, _, _ int
}
func (T) _() {
}
func (T) _() {
}
type U struct {
_ struct{ a, b, c int }
}
const (
c0 = iota
_
_
_
c4
)
var ints = []string{
"1",
"2",
"3",
}
func f() (int, int) {
call += "f"
return 1, 2
}
func g() (float64, float64) {
call += "g"
return 3, 4
}
func h(_ int, _ float64) {
}
func i() int {
call += "i"
return 23
}
var _ = i()
func main() {
if call != "i" {
panic("init did not run")
}
call = ""
_, _ = f()
a, _ := f()
if a != 1 {
panic(a)
}
b, _ := g()
if b != 3 {
panic(b)
}
_, a = f()
if a != 2 {
panic(a)
}
_, b = g()
if b != 4 {
panic(b)
}
_ = i()
if call != "ffgfgi" {
panic(call)
}
if c4 != 4 {
panic(c4)
}
out := ""
for _, s := range ints {
out += s
}
if out != "123" {
panic(out)
}
sum := 0
for s := range ints {
sum += s
}
if sum != 3 {
panic(sum)
}
// go.tools/ssa/interp cannot support unsafe.Pointer.
if os.Getenv("GOSSAINTERP") == "" {
type T1 struct{ x, y, z int }
t1 := *(*T)(unsafe.Pointer(&T1{1, 2, 3}))
t2 := *(*T)(unsafe.Pointer(&T1{4, 5, 6}))
if t1 != t2 {
panic("T{} != T{}")
}
var u1, u2 interface{}
u1 = *(*U)(unsafe.Pointer(&T1{1, 2, 3}))
u2 = *(*U)(unsafe.Pointer(&T1{4, 5, 6}))
if u1 != u2 {
panic("U{} != U{}")
}
}
h(a, b)
m()
}
type I interface {
M(_ int, y int)
}
type TI struct{}
func (_ TI) M(x int, y int) {
if x != y {
println("invalid M call:", x, y)
panic("bad M")
}
}
var fp = func(_ int, y int) {}
func init() {
fp = fp1
}
func fp1(x, y int) {
if x != y {
println("invalid fp1 call:", x, y)
panic("bad fp1")
}
}
func m() {
var i I
i = TI{}
i.M(1, 1)
i.M(2, 2)
fp(1, 1)
fp(2, 2)
}
// useless but legal
var _ int = 1
var _ = 2
var _, _ = 3, 4
const _ = 3
const _, _ = 4, 5
type _ int
func _() {
panic("oops")
}
func ff() {
var _ int = 1
}

32
test/blank1.go Normal file
View File

@@ -0,0 +1,32 @@
// errorcheck
// Copyright 2009 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 that incorrect uses of the blank identifier are caught.
// Does not compile.
package _ // ERROR "invalid package name"
var t struct {
_ int
}
func (x int) _() { // ERROR "methods on non-local type"
println(x)
}
type T struct {
_ []int
}
func main() {
_() // ERROR "cannot use .* as value"
x := _+1 // ERROR "cannot use .* as value"
_ = x
_ = t._ // ERROR "cannot refer to blank field|invalid use of|t._ undefined"
var v1, v2 T
_ = v1 == v2 // ERROR "cannot be compared|non-comparable|cannot compare v1 == v2"
}

26
test/bom.go Normal file
View File

@@ -0,0 +1,26 @@
// runoutput
// 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.
// Test source file beginning with a byte order mark.
package main
import (
"fmt"
"strings"
)
func main() {
prog = strings.Replace(prog, "BOM", "\uFEFF", -1)
fmt.Print(prog)
}
var prog = `BOM
package main
func main() {
}
`

18
test/bombad.go Normal file
View File

@@ -0,0 +1,18 @@
// errorcheck
// Copyright 2012 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.
// Here for reference, but hard to test automatically
// because the BOM muddles the
// processing done by ../run.
package main
func main() {
// There's a bom here. // ERROR "BOM"
// And here. // ERROR "BOM"
/* And here.*/ // ERROR "BOM"
println("hi there") // and here // ERROR "BOM"
}

284
test/bounds.go Normal file
View File

@@ -0,0 +1,284 @@
// errorcheck -0 -m -l
// Copyright 2012 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, using compiler diagnostic flags, that bounds check elimination
// is eliminating the correct checks.
package foo
var (
s []int
a1 [1]int
a1k [1000]int
a100k [100000]int
p1 *[1]int
p1k *[1000]int
p100k *[100000]int
i int
ui uint
i8 int8
ui8 uint8
i16 int16
ui16 uint16
i32 int32
ui32 uint32
i64 int64
ui64 uint64
)
func main() {
// Most things need checks.
use(s[i])
use(a1[i])
use(a1k[i])
use(a100k[i])
use(p1[i])
use(p1k[i])
use(p100k[i])
use(s[ui])
use(a1[ui])
use(a1k[ui])
use(a100k[ui])
use(p1[ui])
use(p1k[ui])
use(p100k[ui])
use(s[i8])
use(a1[i8])
use(a1k[i8])
use(a100k[i8])
use(p1[i8])
use(p1k[i8])
use(p100k[i8])
// Unsigned 8-bit numbers don't need checks for len >= 2⁸.
use(s[ui8])
use(a1[ui8])
use(a1k[ui8]) // ERROR "index bounds check elided"
use(a100k[ui8]) // ERROR "index bounds check elided"
use(p1[ui8])
use(p1k[ui8]) // ERROR "index bounds check elided"
use(p100k[ui8]) // ERROR "index bounds check elided"
use(s[i16])
use(a1[i16])
use(a1k[i16])
use(a100k[i16])
use(p1[i16])
use(p1k[i16])
use(p100k[i16])
// Unsigned 16-bit numbers don't need checks for len >= 2¹⁶.
use(s[ui16])
use(a1[ui16])
use(a1k[ui16])
use(a100k[ui16]) // ERROR "index bounds check elided"
use(p1[ui16])
use(p1k[ui16])
use(p100k[ui16]) // ERROR "index bounds check elided"
use(s[i32])
use(a1[i32])
use(a1k[i32])
use(a100k[i32])
use(p1[i32])
use(p1k[i32])
use(p100k[i32])
use(s[ui32])
use(a1[ui32])
use(a1k[ui32])
use(a100k[ui32])
use(p1[ui32])
use(p1k[ui32])
use(p100k[ui32])
use(s[i64])
use(a1[i64])
use(a1k[i64])
use(a100k[i64])
use(p1[i64])
use(p1k[i64])
use(p100k[i64])
use(s[ui64])
use(a1[ui64])
use(a1k[ui64])
use(a100k[ui64])
use(p1[ui64])
use(p1k[ui64])
use(p100k[ui64])
// Mod truncates the maximum value to one less than the argument,
// but signed mod can be negative, so only unsigned mod counts.
use(s[i%999])
use(a1[i%999])
use(a1k[i%999])
use(a100k[i%999])
use(p1[i%999])
use(p1k[i%999])
use(p100k[i%999])
use(s[ui%999])
use(a1[ui%999])
use(a1k[ui%999]) // ERROR "index bounds check elided"
use(a100k[ui%999]) // ERROR "index bounds check elided"
use(p1[ui%999])
use(p1k[ui%999]) // ERROR "index bounds check elided"
use(p100k[ui%999]) // ERROR "index bounds check elided"
use(s[i%1000])
use(a1[i%1000])
use(a1k[i%1000])
use(a100k[i%1000])
use(p1[i%1000])
use(p1k[i%1000])
use(p100k[i%1000])
use(s[ui%1000])
use(a1[ui%1000])
use(a1k[ui%1000]) // ERROR "index bounds check elided"
use(a100k[ui%1000]) // ERROR "index bounds check elided"
use(p1[ui%1000])
use(p1k[ui%1000]) // ERROR "index bounds check elided"
use(p100k[ui%1000]) // ERROR "index bounds check elided"
use(s[i%1001])
use(a1[i%1001])
use(a1k[i%1001])
use(a100k[i%1001])
use(p1[i%1001])
use(p1k[i%1001])
use(p100k[i%1001])
use(s[ui%1001])
use(a1[ui%1001])
use(a1k[ui%1001])
use(a100k[ui%1001]) // ERROR "index bounds check elided"
use(p1[ui%1001])
use(p1k[ui%1001])
use(p100k[ui%1001]) // ERROR "index bounds check elided"
// Bitwise and truncates the maximum value to the mask value.
// The result (for a positive mask) cannot be negative, so elision
// applies to both signed and unsigned indexes.
use(s[i&999])
use(a1[i&999])
use(a1k[i&999]) // ERROR "index bounds check elided"
use(a100k[i&999]) // ERROR "index bounds check elided"
use(p1[i&999])
use(p1k[i&999]) // ERROR "index bounds check elided"
use(p100k[i&999]) // ERROR "index bounds check elided"
use(s[ui&999])
use(a1[ui&999])
use(a1k[ui&999]) // ERROR "index bounds check elided"
use(a100k[ui&999]) // ERROR "index bounds check elided"
use(p1[ui&999])
use(p1k[ui&999]) // ERROR "index bounds check elided"
use(p100k[ui&999]) // ERROR "index bounds check elided"
use(s[i&1000])
use(a1[i&1000])
use(a1k[i&1000])
use(a100k[i&1000]) // ERROR "index bounds check elided"
use(p1[i&1000])
use(p1k[i&1000])
use(p100k[i&1000]) // ERROR "index bounds check elided"
use(s[ui&1000])
use(a1[ui&1000])
use(a1k[ui&1000])
use(a100k[ui&1000]) // ERROR "index bounds check elided"
use(p1[ui&1000])
use(p1k[ui&1000])
use(p100k[ui&1000]) // ERROR "index bounds check elided"
use(a1[i&^-1]) // ERROR "index bounds check elided"
use(a1[i&^0])
use(a1[i&^-2])
use(a1[i&^1])
use(a1k[i&^-1]) // ERROR "index bounds check elided"
use(a1k[i&^0])
use(a1k[i&^-2]) // ERROR "index bounds check elided"
use(a1k[i&^1])
use(a1k[i8&^0])
use(a1k[i8&^-128]) // ERROR "index bounds check elided"
use(a1k[ui8&^1]) // ERROR "index bounds check elided"
use(a1k[ui16&^0xf000])
use(a1k[ui16&^0xff00]) // ERROR "index bounds check elided"
// Right shift cuts the effective number of bits in the index,
// but only for unsigned (signed stays negative).
use(s[i32>>22])
use(a1[i32>>22])
use(a1k[i32>>22])
use(a100k[i32>>22])
use(p1[i32>>22])
use(p1k[i32>>22])
use(p100k[i32>>22])
use(s[ui32>>22])
use(a1[ui32>>22])
use(a1k[ui32>>22])
use(a100k[ui32>>22]) // ERROR "index bounds check elided"
use(p1[ui32>>22])
use(p1k[ui32>>22])
use(p100k[ui32>>22]) // ERROR "index bounds check elided"
use(s[i32>>23])
use(a1[i32>>23])
use(a1k[i32>>23])
use(a100k[i32>>23])
use(p1[i32>>23])
use(p1k[i32>>23])
use(p100k[i32>>23])
use(s[ui32>>23])
use(a1[ui32>>23])
use(a1k[ui32>>23]) // ERROR "index bounds check elided"
use(a100k[ui32>>23]) // ERROR "index bounds check elided"
use(p1[ui32>>23])
use(p1k[ui32>>23]) // ERROR "index bounds check elided"
use(p100k[ui32>>23]) // ERROR "index bounds check elided"
// Division cuts the range like right shift does.
use(s[i/1e6])
use(a1[i/1e6])
use(a1k[i/1e6])
use(a100k[i/1e6])
use(p1[i/1e6])
use(p1k[i/1e6])
use(p100k[i/1e6])
use(s[ui/1e6])
use(a1[ui/1e6])
use(a1k[ui/1e6])
use(p1[ui/1e6])
use(p1k[ui/1e6])
use(s[i/1e7])
use(a1[i/1e7])
use(a1k[i/1e7])
use(a100k[i/1e7])
use(p1[i/1e7])
use(p1k[i/1e7])
use(p100k[i/1e7])
use(s[ui/1e7])
use(a1[ui/1e7])
use(p1[ui/1e7])
}
var sum int
func use(x int) {
sum += x
}

33
test/cannotassign.go Normal file
View File

@@ -0,0 +1,33 @@
// errorcheck
// Copyright 2020 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 "cannot assign" errors
package main
func main() {
var s string = "hello"
s[1:2] = "a" // ERROR "cannot assign to .* (\(strings are immutable\))?"
s[3] = "b" // ERROR "cannot assign to .* (\(strings are immutable\))?"
const n int = 1
const cs string = "hello"
n = 2 // ERROR "cannot assign to .* (\(declared const\))?"
cs = "hi" // ERROR "cannot assign to .* (\(declared const\))?"
true = false // ERROR "cannot assign to .* (\(declared const\))?"
var m map[int]struct{ n int }
m[0].n = 7 // ERROR "cannot assign to struct field .* in map$"
1 = 7 // ERROR "cannot assign to 1"
"hi" = 7 // ERROR `cannot assign to "hi"`
nil = 7 // ERROR "cannot assign to nil"
len("") = 7 // ERROR `cannot assign to len\(""\)`
[]int{} = nil // ERROR "cannot assign to \[\]int\{\}"
var x int = 7
x + 1 = 7 // ERROR "cannot assign to x \+ 1"
}

87
test/chan/doubleselect.go Normal file
View File

@@ -0,0 +1,87 @@
// run
// Copyright 2009 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 the situation in which two cases of a select can
// both end up running. See http://codereview.appspot.com/180068.
package main
import (
"flag"
"runtime"
)
var iterations *int = flag.Int("n", 100000, "number of iterations")
// sender sends a counter to one of four different channels. If two
// cases both end up running in the same iteration, the same value will be sent
// to two different channels.
func sender(n int, c1, c2, c3, c4 chan<- int) {
defer close(c1)
defer close(c2)
defer close(c3)
defer close(c4)
for i := 0; i < n; i++ {
select {
case c1 <- i:
case c2 <- i:
case c3 <- i:
case c4 <- i:
}
}
}
// mux receives the values from sender and forwards them onto another channel.
// It would be simpler to just have sender's four cases all be the same
// channel, but this doesn't actually trigger the bug.
func mux(out chan<- int, in <-chan int, done chan<- bool) {
for v := range in {
out <- v
}
done <- true
}
// recver gets a steam of values from the four mux's and checks for duplicates.
func recver(in <-chan int) {
seen := make(map[int]bool)
for v := range in {
if _, ok := seen[v]; ok {
println("got duplicate value: ", v)
panic("fail")
}
seen[v] = true
}
}
func main() {
runtime.GOMAXPROCS(2)
flag.Parse()
c1 := make(chan int)
c2 := make(chan int)
c3 := make(chan int)
c4 := make(chan int)
done := make(chan bool)
cmux := make(chan int)
go sender(*iterations, c1, c2, c3, c4)
go mux(cmux, c1, done)
go mux(cmux, c2, done)
go mux(cmux, c3, done)
go mux(cmux, c4, done)
go func() {
<-done
<-done
<-done
<-done
close(cmux)
}()
// We keep the recver because it might catch more bugs in the future.
// However, the result of the bug linked to at the top is that we'll
// end up panicking with: "throw: bad g->status in ready".
recver(cmux)
}

56
test/chan/fifo.go Normal file
View File

@@ -0,0 +1,56 @@
// run
// Copyright 2009 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 that unbuffered channels act as pure fifos.
package main
import "os"
const N = 10
func AsynchFifo() {
ch := make(chan int, N)
for i := 0; i < N; i++ {
ch <- i
}
for i := 0; i < N; i++ {
if <-ch != i {
print("bad receive\n")
os.Exit(1)
}
}
}
func Chain(ch <-chan int, val int, in <-chan int, out chan<- int) {
<-in
if <-ch != val {
panic(val)
}
out <- 1
}
// thread together a daisy chain to read the elements in sequence
func SynchFifo() {
ch := make(chan int)
in := make(chan int)
start := in
for i := 0; i < N; i++ {
out := make(chan int)
go Chain(ch, i, in, out)
in = out
}
start <- 0
for i := 0; i < N; i++ {
ch <- i
}
<-in
}
func main() {
AsynchFifo()
SynchFifo()
}

41
test/chan/goroutines.go Normal file
View File

@@ -0,0 +1,41 @@
// run
// Copyright 2009 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.
// Torture test for goroutines.
// Make a lot of goroutines, threaded together, and tear them down cleanly.
package main
import (
"os"
"strconv"
)
func f(left, right chan int) {
left <- <-right
}
func main() {
var n = 10000
if len(os.Args) > 1 {
var err error
n, err = strconv.Atoi(os.Args[1])
if err != nil {
print("bad arg\n")
os.Exit(1)
}
}
leftmost := make(chan int)
right := leftmost
left := leftmost
for i := 0; i < n; i++ {
right = make(chan int)
go f(left, right)
left = right
}
go func(c chan int) { c <- 1 }(right)
<-leftmost
}

282
test/chan/nonblock.go Normal file
View File

@@ -0,0 +1,282 @@
// run
// Copyright 2009 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 channel operations that test for blocking.
// Use several sizes and types of operands.
package main
import "runtime"
import "time"
func i32receiver(c chan int32, strobe chan bool) {
if <-c != 123 {
panic("i32 value")
}
strobe <- true
}
func i32sender(c chan int32, strobe chan bool) {
c <- 234
strobe <- true
}
func i64receiver(c chan int64, strobe chan bool) {
if <-c != 123456 {
panic("i64 value")
}
strobe <- true
}
func i64sender(c chan int64, strobe chan bool) {
c <- 234567
strobe <- true
}
func breceiver(c chan bool, strobe chan bool) {
if !<-c {
panic("b value")
}
strobe <- true
}
func bsender(c chan bool, strobe chan bool) {
c <- true
strobe <- true
}
func sreceiver(c chan string, strobe chan bool) {
if <-c != "hello" {
panic("s value")
}
strobe <- true
}
func ssender(c chan string, strobe chan bool) {
c <- "hello again"
strobe <- true
}
var ticker = time.Tick(10 * 1000) // 10 us
func sleep() {
<-ticker
<-ticker
runtime.Gosched()
runtime.Gosched()
runtime.Gosched()
}
const maxTries = 10000 // Up to 100ms per test.
func main() {
var i32 int32
var i64 int64
var b bool
var s string
var sync = make(chan bool)
for buffer := 0; buffer < 2; buffer++ {
c32 := make(chan int32, buffer)
c64 := make(chan int64, buffer)
cb := make(chan bool, buffer)
cs := make(chan string, buffer)
select {
case i32 = <-c32:
panic("blocked i32sender")
default:
}
select {
case i64 = <-c64:
panic("blocked i64sender")
default:
}
select {
case b = <-cb:
panic("blocked bsender")
default:
}
select {
case s = <-cs:
panic("blocked ssender")
default:
}
go i32receiver(c32, sync)
try := 0
Send32:
for {
select {
case c32 <- 123:
break Send32
default:
try++
if try > maxTries {
println("i32receiver buffer=", buffer)
panic("fail")
}
sleep()
}
}
<-sync
go i32sender(c32, sync)
if buffer > 0 {
<-sync
}
try = 0
Recv32:
for {
select {
case i32 = <-c32:
break Recv32
default:
try++
if try > maxTries {
println("i32sender buffer=", buffer)
panic("fail")
}
sleep()
}
}
if i32 != 234 {
panic("i32sender value")
}
if buffer == 0 {
<-sync
}
go i64receiver(c64, sync)
try = 0
Send64:
for {
select {
case c64 <- 123456:
break Send64
default:
try++
if try > maxTries {
panic("i64receiver")
}
sleep()
}
}
<-sync
go i64sender(c64, sync)
if buffer > 0 {
<-sync
}
try = 0
Recv64:
for {
select {
case i64 = <-c64:
break Recv64
default:
try++
if try > maxTries {
panic("i64sender")
}
sleep()
}
}
if i64 != 234567 {
panic("i64sender value")
}
if buffer == 0 {
<-sync
}
go breceiver(cb, sync)
try = 0
SendBool:
for {
select {
case cb <- true:
break SendBool
default:
try++
if try > maxTries {
panic("breceiver")
}
sleep()
}
}
<-sync
go bsender(cb, sync)
if buffer > 0 {
<-sync
}
try = 0
RecvBool:
for {
select {
case b = <-cb:
break RecvBool
default:
try++
if try > maxTries {
panic("bsender")
}
sleep()
}
}
if !b {
panic("bsender value")
}
if buffer == 0 {
<-sync
}
go sreceiver(cs, sync)
try = 0
SendString:
for {
select {
case cs <- "hello":
break SendString
default:
try++
if try > maxTries {
panic("sreceiver")
}
sleep()
}
}
<-sync
go ssender(cs, sync)
if buffer > 0 {
<-sync
}
try = 0
RecvString:
for {
select {
case s = <-cs:
break RecvString
default:
try++
if try > maxTries {
panic("ssender")
}
sleep()
}
}
if s != "hello again" {
panic("ssender value")
}
if buffer == 0 {
<-sync
}
}
}

70
test/chan/perm.go Normal file
View File

@@ -0,0 +1,70 @@
// errorcheck
// Copyright 2009 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 various correct and incorrect permutations of send-only,
// receive-only, and bidirectional channels.
// Does not compile.
package main
var (
cr <-chan int
cs chan<- int
c chan int
)
func main() {
cr = c // ok
cs = c // ok
c = cr // ERROR "illegal types|incompatible|cannot"
c = cs // ERROR "illegal types|incompatible|cannot"
cr = cs // ERROR "illegal types|incompatible|cannot"
cs = cr // ERROR "illegal types|incompatible|cannot"
var n int
<-n // ERROR "receive from non-chan|expected channel"
n <- 2 // ERROR "send to non-chan|must be channel"
c <- 0 // ok
<-c // ok
x, ok := <-c // ok
_, _ = x, ok
cr <- 0 // ERROR "send"
<-cr // ok
x, ok = <-cr // ok
_, _ = x, ok
cs <- 0 // ok
<-cs // ERROR "receive"
x, ok = <-cs // ERROR "receive"
_, _ = x, ok
select {
case c <- 0: // ok
case x := <-c: // ok
_ = x
case cr <- 0: // ERROR "send"
case x := <-cr: // ok
_ = x
case cs <- 0: // ok
case x := <-cs: // ERROR "receive"
_ = x
}
for _ = range cs { // ERROR "receive"
}
for range cs { // ERROR "receive"
}
close(c)
close(cs)
close(cr) // ERROR "receive"
close(n) // ERROR "invalid operation.*non-chan type|must be channel|non-channel"
}

741
test/chan/powser1.go Normal file
View File

@@ -0,0 +1,741 @@
// run
// Copyright 2009 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 concurrency primitives: power series.
// Power series package
// A power series is a channel, along which flow rational
// coefficients. A denominator of zero signifies the end.
// Original code in Newsqueak by Doug McIlroy.
// See Squinting at Power Series by Doug McIlroy,
// https://swtch.com/~rsc/thread/squint.pdf
package main
import "os"
type rat struct {
num, den int64 // numerator, denominator
}
func (u rat) pr() {
if u.den == 1 {
print(u.num)
} else {
print(u.num, "/", u.den)
}
print(" ")
}
func (u rat) eq(c rat) bool {
return u.num == c.num && u.den == c.den
}
type dch struct {
req chan int
dat chan rat
nam int
}
type dch2 [2]*dch
var chnames string
var chnameserial int
var seqno int
func mkdch() *dch {
c := chnameserial % len(chnames)
chnameserial++
d := new(dch)
d.req = make(chan int)
d.dat = make(chan rat)
d.nam = c
return d
}
func mkdch2() *dch2 {
d2 := new(dch2)
d2[0] = mkdch()
d2[1] = mkdch()
return d2
}
// split reads a single demand channel and replicates its
// output onto two, which may be read at different rates.
// A process is created at first demand for a rat and dies
// after the rat has been sent to both outputs.
// When multiple generations of split exist, the newest
// will service requests on one channel, which is
// always renamed to be out[0]; the oldest will service
// requests on the other channel, out[1]. All generations but the
// newest hold queued data that has already been sent to
// out[0]. When data has finally been sent to out[1],
// a signal on the release-wait channel tells the next newer
// generation to begin servicing out[1].
func dosplit(in *dch, out *dch2, wait chan int) {
both := false // do not service both channels
select {
case <-out[0].req:
case <-wait:
both = true
select {
case <-out[0].req:
case <-out[1].req:
out[0], out[1] = out[1], out[0]
}
}
seqno++
in.req <- seqno
release := make(chan int)
go dosplit(in, out, release)
dat := <-in.dat
out[0].dat <- dat
if !both {
<-wait
}
<-out[1].req
out[1].dat <- dat
release <- 0
}
func split(in *dch, out *dch2) {
release := make(chan int)
go dosplit(in, out, release)
release <- 0
}
func put(dat rat, out *dch) {
<-out.req
out.dat <- dat
}
func get(in *dch) rat {
seqno++
in.req <- seqno
return <-in.dat
}
// Get one rat from each of n demand channels
func getn(in []*dch) []rat {
n := len(in)
if n != 2 {
panic("bad n in getn")
}
req := new([2]chan int)
dat := new([2]chan rat)
out := make([]rat, 2)
var i int
var it rat
for i = 0; i < n; i++ {
req[i] = in[i].req
dat[i] = nil
}
for n = 2 * n; n > 0; n-- {
seqno++
select {
case req[0] <- seqno:
dat[0] = in[0].dat
req[0] = nil
case req[1] <- seqno:
dat[1] = in[1].dat
req[1] = nil
case it = <-dat[0]:
out[0] = it
dat[0] = nil
case it = <-dat[1]:
out[1] = it
dat[1] = nil
}
}
return out
}
// Get one rat from each of 2 demand channels
func get2(in0 *dch, in1 *dch) []rat {
return getn([]*dch{in0, in1})
}
func copy(in *dch, out *dch) {
for {
<-out.req
out.dat <- get(in)
}
}
func repeat(dat rat, out *dch) {
for {
put(dat, out)
}
}
type PS *dch // power series
type PS2 *[2]PS // pair of power series
var Ones PS
var Twos PS
func mkPS() *dch {
return mkdch()
}
func mkPS2() *dch2 {
return mkdch2()
}
// Conventions
// Upper-case for power series.
// Lower-case for rationals.
// Input variables: U,V,...
// Output variables: ...,Y,Z
// Integer gcd; needed for rational arithmetic
func gcd(u, v int64) int64 {
if u < 0 {
return gcd(-u, v)
}
if u == 0 {
return v
}
return gcd(v%u, u)
}
// Make a rational from two ints and from one int
func i2tor(u, v int64) rat {
g := gcd(u, v)
var r rat
if v > 0 {
r.num = u / g
r.den = v / g
} else {
r.num = -u / g
r.den = -v / g
}
return r
}
func itor(u int64) rat {
return i2tor(u, 1)
}
var zero rat
var one rat
// End mark and end test
var finis rat
func end(u rat) int64 {
if u.den == 0 {
return 1
}
return 0
}
// Operations on rationals
func add(u, v rat) rat {
g := gcd(u.den, v.den)
return i2tor(u.num*(v.den/g)+v.num*(u.den/g), u.den*(v.den/g))
}
func mul(u, v rat) rat {
g1 := gcd(u.num, v.den)
g2 := gcd(u.den, v.num)
var r rat
r.num = (u.num / g1) * (v.num / g2)
r.den = (u.den / g2) * (v.den / g1)
return r
}
func neg(u rat) rat {
return i2tor(-u.num, u.den)
}
func sub(u, v rat) rat {
return add(u, neg(v))
}
func inv(u rat) rat { // invert a rat
if u.num == 0 {
panic("zero divide in inv")
}
return i2tor(u.den, u.num)
}
// print eval in floating point of PS at x=c to n terms
func evaln(c rat, U PS, n int) {
xn := float64(1)
x := float64(c.num) / float64(c.den)
val := float64(0)
for i := 0; i < n; i++ {
u := get(U)
if end(u) != 0 {
break
}
val = val + x*float64(u.num)/float64(u.den)
xn = xn * x
}
print(val, "\n")
}
// Print n terms of a power series
func printn(U PS, n int) {
done := false
for ; !done && n > 0; n-- {
u := get(U)
if end(u) != 0 {
done = true
} else {
u.pr()
}
}
print(("\n"))
}
// Evaluate n terms of power series U at x=c
func eval(c rat, U PS, n int) rat {
if n == 0 {
return zero
}
y := get(U)
if end(y) != 0 {
return zero
}
return add(y, mul(c, eval(c, U, n-1)))
}
// Power-series constructors return channels on which power
// series flow. They start an encapsulated generator that
// puts the terms of the series on the channel.
// Make a pair of power series identical to a given power series
func Split(U PS) *dch2 {
UU := mkdch2()
go split(U, UU)
return UU
}
// Add two power series
func Add(U, V PS) PS {
Z := mkPS()
go func() {
var uv []rat
for {
<-Z.req
uv = get2(U, V)
switch end(uv[0]) + 2*end(uv[1]) {
case 0:
Z.dat <- add(uv[0], uv[1])
case 1:
Z.dat <- uv[1]
copy(V, Z)
case 2:
Z.dat <- uv[0]
copy(U, Z)
case 3:
Z.dat <- finis
}
}
}()
return Z
}
// Multiply a power series by a constant
func Cmul(c rat, U PS) PS {
Z := mkPS()
go func() {
done := false
for !done {
<-Z.req
u := get(U)
if end(u) != 0 {
done = true
} else {
Z.dat <- mul(c, u)
}
}
Z.dat <- finis
}()
return Z
}
// Subtract
func Sub(U, V PS) PS {
return Add(U, Cmul(neg(one), V))
}
// Multiply a power series by the monomial x^n
func Monmul(U PS, n int) PS {
Z := mkPS()
go func() {
for ; n > 0; n-- {
put(zero, Z)
}
copy(U, Z)
}()
return Z
}
// Multiply by x
func Xmul(U PS) PS {
return Monmul(U, 1)
}
func Rep(c rat) PS {
Z := mkPS()
go repeat(c, Z)
return Z
}
// Monomial c*x^n
func Mon(c rat, n int) PS {
Z := mkPS()
go func() {
if c.num != 0 {
for ; n > 0; n = n - 1 {
put(zero, Z)
}
put(c, Z)
}
put(finis, Z)
}()
return Z
}
func Shift(c rat, U PS) PS {
Z := mkPS()
go func() {
put(c, Z)
copy(U, Z)
}()
return Z
}
// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
// Convert array of coefficients, constant term first
// to a (finite) power series
/*
func Poly(a []rat) PS {
Z:=mkPS()
begin func(a []rat, Z PS) {
j:=0
done:=0
for j=len(a); !done&&j>0; j=j-1)
if(a[j-1].num!=0) done=1
i:=0
for(; i<j; i=i+1) put(a[i],Z)
put(finis,Z)
}()
return Z
}
*/
// Multiply. The algorithm is
// let U = u + x*UU
// let V = v + x*VV
// then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
func Mul(U, V PS) PS {
Z := mkPS()
go func() {
<-Z.req
uv := get2(U, V)
if end(uv[0]) != 0 || end(uv[1]) != 0 {
Z.dat <- finis
} else {
Z.dat <- mul(uv[0], uv[1])
UU := Split(U)
VV := Split(V)
W := Add(Cmul(uv[0], VV[0]), Cmul(uv[1], UU[0]))
<-Z.req
Z.dat <- get(W)
copy(Add(W, Mul(UU[1], VV[1])), Z)
}
}()
return Z
}
// Differentiate
func Diff(U PS) PS {
Z := mkPS()
go func() {
<-Z.req
u := get(U)
if end(u) == 0 {
done := false
for i := 1; !done; i++ {
u = get(U)
if end(u) != 0 {
done = true
} else {
Z.dat <- mul(itor(int64(i)), u)
<-Z.req
}
}
}
Z.dat <- finis
}()
return Z
}
// Integrate, with const of integration
func Integ(c rat, U PS) PS {
Z := mkPS()
go func() {
put(c, Z)
done := false
for i := 1; !done; i++ {
<-Z.req
u := get(U)
if end(u) != 0 {
done = true
}
Z.dat <- mul(i2tor(1, int64(i)), u)
}
Z.dat <- finis
}()
return Z
}
// Binomial theorem (1+x)^c
func Binom(c rat) PS {
Z := mkPS()
go func() {
n := 1
t := itor(1)
for c.num != 0 {
put(t, Z)
t = mul(mul(t, c), i2tor(1, int64(n)))
c = sub(c, one)
n++
}
put(finis, Z)
}()
return Z
}
// Reciprocal of a power series
// let U = u + x*UU
// let Z = z + x*ZZ
// (u+x*UU)*(z+x*ZZ) = 1
// z = 1/u
// u*ZZ + z*UU +x*UU*ZZ = 0
// ZZ = -UU*(z+x*ZZ)/u
func Recip(U PS) PS {
Z := mkPS()
go func() {
ZZ := mkPS2()
<-Z.req
z := inv(get(U))
Z.dat <- z
split(Mul(Cmul(neg(z), U), Shift(z, ZZ[0])), ZZ)
copy(ZZ[1], Z)
}()
return Z
}
// Exponential of a power series with constant term 0
// (nonzero constant term would make nonrational coefficients)
// bug: the constant term is simply ignored
// Z = exp(U)
// DZ = Z*DU
// integrate to get Z
func Exp(U PS) PS {
ZZ := mkPS2()
split(Integ(one, Mul(ZZ[0], Diff(U))), ZZ)
return ZZ[1]
}
// Substitute V for x in U, where the leading term of V is zero
// let U = u + x*UU
// let V = v + x*VV
// then S(U,V) = u + VV*S(V,UU)
// bug: a nonzero constant term is ignored
func Subst(U, V PS) PS {
Z := mkPS()
go func() {
VV := Split(V)
<-Z.req
u := get(U)
Z.dat <- u
if end(u) == 0 {
if end(get(VV[0])) != 0 {
put(finis, Z)
} else {
copy(Mul(VV[0], Subst(U, VV[1])), Z)
}
}
}()
return Z
}
// Monomial Substitution: U(c x^n)
// Each Ui is multiplied by c^i and followed by n-1 zeros
func MonSubst(U PS, c0 rat, n int) PS {
Z := mkPS()
go func() {
c := one
for {
<-Z.req
u := get(U)
Z.dat <- mul(u, c)
c = mul(c, c0)
if end(u) != 0 {
Z.dat <- finis
break
}
for i := 1; i < n; i++ {
<-Z.req
Z.dat <- zero
}
}
}()
return Z
}
func Init() {
chnameserial = -1
seqno = 0
chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
zero = itor(0)
one = itor(1)
finis = i2tor(1, 0)
Ones = Rep(one)
Twos = Rep(itor(2))
}
func check(U PS, c rat, count int, str string) {
for i := 0; i < count; i++ {
r := get(U)
if !r.eq(c) {
print("got: ")
r.pr()
print("should get ")
c.pr()
print("\n")
panic(str)
}
}
}
const N = 10
func checka(U PS, a []rat, str string) {
for i := 0; i < N; i++ {
check(U, a[i], 1, str)
}
}
func main() {
Init()
if len(os.Args) > 1 { // print
print("Ones: ")
printn(Ones, 10)
print("Twos: ")
printn(Twos, 10)
print("Add: ")
printn(Add(Ones, Twos), 10)
print("Diff: ")
printn(Diff(Ones), 10)
print("Integ: ")
printn(Integ(zero, Ones), 10)
print("CMul: ")
printn(Cmul(neg(one), Ones), 10)
print("Sub: ")
printn(Sub(Ones, Twos), 10)
print("Mul: ")
printn(Mul(Ones, Ones), 10)
print("Exp: ")
printn(Exp(Ones), 15)
print("MonSubst: ")
printn(MonSubst(Ones, neg(one), 2), 10)
print("ATan: ")
printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
} else { // test
check(Ones, one, 5, "Ones")
check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones") // 1 1 1 1 1
check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
a := make([]rat, N)
d := Diff(Ones)
for i := 0; i < N; i++ {
a[i] = itor(int64(i + 1))
}
checka(d, a, "Diff") // 1 2 3 4 5
in := Integ(zero, Ones)
a[0] = zero // integration constant
for i := 1; i < N; i++ {
a[i] = i2tor(1, int64(i))
}
checka(in, a, "Integ") // 0 1 1/2 1/3 1/4 1/5
check(Cmul(neg(one), Twos), itor(-2), 10, "CMul") // -1 -1 -1 -1 -1
check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos") // -1 -1 -1 -1 -1
m := Mul(Ones, Ones)
for i := 0; i < N; i++ {
a[i] = itor(int64(i + 1))
}
checka(m, a, "Mul") // 1 2 3 4 5
e := Exp(Ones)
a[0] = itor(1)
a[1] = itor(1)
a[2] = i2tor(3, 2)
a[3] = i2tor(13, 6)
a[4] = i2tor(73, 24)
a[5] = i2tor(167, 40)
a[6] = i2tor(4051, 720)
a[7] = i2tor(37633, 5040)
a[8] = i2tor(43817, 4480)
a[9] = i2tor(4596553, 362880)
checka(e, a, "Exp") // 1 1 3/2 13/6 73/24
at := Integ(zero, MonSubst(Ones, neg(one), 2))
for c, i := 1, 0; i < N; i++ {
if i%2 == 0 {
a[i] = zero
} else {
a[i] = i2tor(int64(c), int64(i))
c *= -1
}
}
checka(at, a, "ATan") // 0 -1 0 -1/3 0 -1/5
/*
t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
a[0] = zero
a[1] = itor(1)
a[2] = zero
a[3] = i2tor(1,3)
a[4] = zero
a[5] = i2tor(2,15)
a[6] = zero
a[7] = i2tor(17,315)
a[8] = zero
a[9] = i2tor(62,2835)
checka(t, a, "Tan") // 0 1 0 1/3 0 2/15
*/
}
}

755
test/chan/powser2.go Normal file
View File

@@ -0,0 +1,755 @@
// run
// Copyright 2009 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 concurrency primitives: power series.
// Like powser1.go but uses channels of interfaces.
// Has not been cleaned up as much as powser1.go, to keep
// it distinct and therefore a different test.
// Power series package
// A power series is a channel, along which flow rational
// coefficients. A denominator of zero signifies the end.
// Original code in Newsqueak by Doug McIlroy.
// See Squinting at Power Series by Doug McIlroy,
// https://swtch.com/~rsc/thread/squint.pdf
package main
import "os"
type rat struct {
num, den int64 // numerator, denominator
}
type item interface {
pr()
eq(c item) bool
}
func (u *rat) pr() {
if u.den == 1 {
print(u.num)
} else {
print(u.num, "/", u.den)
}
print(" ")
}
func (u *rat) eq(c item) bool {
c1 := c.(*rat)
return u.num == c1.num && u.den == c1.den
}
type dch struct {
req chan int
dat chan item
nam int
}
type dch2 [2]*dch
var chnames string
var chnameserial int
var seqno int
func mkdch() *dch {
c := chnameserial % len(chnames)
chnameserial++
d := new(dch)
d.req = make(chan int)
d.dat = make(chan item)
d.nam = c
return d
}
func mkdch2() *dch2 {
d2 := new(dch2)
d2[0] = mkdch()
d2[1] = mkdch()
return d2
}
// split reads a single demand channel and replicates its
// output onto two, which may be read at different rates.
// A process is created at first demand for an item and dies
// after the item has been sent to both outputs.
// When multiple generations of split exist, the newest
// will service requests on one channel, which is
// always renamed to be out[0]; the oldest will service
// requests on the other channel, out[1]. All generations but the
// newest hold queued data that has already been sent to
// out[0]. When data has finally been sent to out[1],
// a signal on the release-wait channel tells the next newer
// generation to begin servicing out[1].
func dosplit(in *dch, out *dch2, wait chan int) {
both := false // do not service both channels
select {
case <-out[0].req:
case <-wait:
both = true
select {
case <-out[0].req:
case <-out[1].req:
out[0], out[1] = out[1], out[0]
}
}
seqno++
in.req <- seqno
release := make(chan int)
go dosplit(in, out, release)
dat := <-in.dat
out[0].dat <- dat
if !both {
<-wait
}
<-out[1].req
out[1].dat <- dat
release <- 0
}
func split(in *dch, out *dch2) {
release := make(chan int)
go dosplit(in, out, release)
release <- 0
}
func put(dat item, out *dch) {
<-out.req
out.dat <- dat
}
func get(in *dch) *rat {
seqno++
in.req <- seqno
return (<-in.dat).(*rat)
}
// Get one item from each of n demand channels
func getn(in []*dch) []item {
n := len(in)
if n != 2 {
panic("bad n in getn")
}
req := make([]chan int, 2)
dat := make([]chan item, 2)
out := make([]item, 2)
var i int
var it item
for i = 0; i < n; i++ {
req[i] = in[i].req
dat[i] = nil
}
for n = 2 * n; n > 0; n-- {
seqno++
select {
case req[0] <- seqno:
dat[0] = in[0].dat
req[0] = nil
case req[1] <- seqno:
dat[1] = in[1].dat
req[1] = nil
case it = <-dat[0]:
out[0] = it
dat[0] = nil
case it = <-dat[1]:
out[1] = it
dat[1] = nil
}
}
return out
}
// Get one item from each of 2 demand channels
func get2(in0 *dch, in1 *dch) []item {
return getn([]*dch{in0, in1})
}
func copy(in *dch, out *dch) {
for {
<-out.req
out.dat <- get(in)
}
}
func repeat(dat item, out *dch) {
for {
put(dat, out)
}
}
type PS *dch // power series
type PS2 *[2]PS // pair of power series
var Ones PS
var Twos PS
func mkPS() *dch {
return mkdch()
}
func mkPS2() *dch2 {
return mkdch2()
}
// Conventions
// Upper-case for power series.
// Lower-case for rationals.
// Input variables: U,V,...
// Output variables: ...,Y,Z
// Integer gcd; needed for rational arithmetic
func gcd(u, v int64) int64 {
if u < 0 {
return gcd(-u, v)
}
if u == 0 {
return v
}
return gcd(v%u, u)
}
// Make a rational from two ints and from one int
func i2tor(u, v int64) *rat {
g := gcd(u, v)
r := new(rat)
if v > 0 {
r.num = u / g
r.den = v / g
} else {
r.num = -u / g
r.den = -v / g
}
return r
}
func itor(u int64) *rat {
return i2tor(u, 1)
}
var zero *rat
var one *rat
// End mark and end test
var finis *rat
func end(u *rat) int64 {
if u.den == 0 {
return 1
}
return 0
}
// Operations on rationals
func add(u, v *rat) *rat {
g := gcd(u.den, v.den)
return i2tor(u.num*(v.den/g)+v.num*(u.den/g), u.den*(v.den/g))
}
func mul(u, v *rat) *rat {
g1 := gcd(u.num, v.den)
g2 := gcd(u.den, v.num)
r := new(rat)
r.num = (u.num / g1) * (v.num / g2)
r.den = (u.den / g2) * (v.den / g1)
return r
}
func neg(u *rat) *rat {
return i2tor(-u.num, u.den)
}
func sub(u, v *rat) *rat {
return add(u, neg(v))
}
func inv(u *rat) *rat { // invert a rat
if u.num == 0 {
panic("zero divide in inv")
}
return i2tor(u.den, u.num)
}
// print eval in floating point of PS at x=c to n terms
func Evaln(c *rat, U PS, n int) {
xn := float64(1)
x := float64(c.num) / float64(c.den)
val := float64(0)
for i := 0; i < n; i++ {
u := get(U)
if end(u) != 0 {
break
}
val = val + x*float64(u.num)/float64(u.den)
xn = xn * x
}
print(val, "\n")
}
// Print n terms of a power series
func Printn(U PS, n int) {
done := false
for ; !done && n > 0; n-- {
u := get(U)
if end(u) != 0 {
done = true
} else {
u.pr()
}
}
print(("\n"))
}
func Print(U PS) {
Printn(U, 1000000000)
}
// Evaluate n terms of power series U at x=c
func eval(c *rat, U PS, n int) *rat {
if n == 0 {
return zero
}
y := get(U)
if end(y) != 0 {
return zero
}
return add(y, mul(c, eval(c, U, n-1)))
}
// Power-series constructors return channels on which power
// series flow. They start an encapsulated generator that
// puts the terms of the series on the channel.
// Make a pair of power series identical to a given power series
func Split(U PS) *dch2 {
UU := mkdch2()
go split(U, UU)
return UU
}
// Add two power series
func Add(U, V PS) PS {
Z := mkPS()
go func(U, V, Z PS) {
var uv []item
for {
<-Z.req
uv = get2(U, V)
switch end(uv[0].(*rat)) + 2*end(uv[1].(*rat)) {
case 0:
Z.dat <- add(uv[0].(*rat), uv[1].(*rat))
case 1:
Z.dat <- uv[1]
copy(V, Z)
case 2:
Z.dat <- uv[0]
copy(U, Z)
case 3:
Z.dat <- finis
}
}
}(U, V, Z)
return Z
}
// Multiply a power series by a constant
func Cmul(c *rat, U PS) PS {
Z := mkPS()
go func(c *rat, U, Z PS) {
done := false
for !done {
<-Z.req
u := get(U)
if end(u) != 0 {
done = true
} else {
Z.dat <- mul(c, u)
}
}
Z.dat <- finis
}(c, U, Z)
return Z
}
// Subtract
func Sub(U, V PS) PS {
return Add(U, Cmul(neg(one), V))
}
// Multiply a power series by the monomial x^n
func Monmul(U PS, n int) PS {
Z := mkPS()
go func(n int, U PS, Z PS) {
for ; n > 0; n-- {
put(zero, Z)
}
copy(U, Z)
}(n, U, Z)
return Z
}
// Multiply by x
func Xmul(U PS) PS {
return Monmul(U, 1)
}
func Rep(c *rat) PS {
Z := mkPS()
go repeat(c, Z)
return Z
}
// Monomial c*x^n
func Mon(c *rat, n int) PS {
Z := mkPS()
go func(c *rat, n int, Z PS) {
if c.num != 0 {
for ; n > 0; n = n - 1 {
put(zero, Z)
}
put(c, Z)
}
put(finis, Z)
}(c, n, Z)
return Z
}
func Shift(c *rat, U PS) PS {
Z := mkPS()
go func(c *rat, U, Z PS) {
put(c, Z)
copy(U, Z)
}(c, U, Z)
return Z
}
// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
// Convert array of coefficients, constant term first
// to a (finite) power series
/*
func Poly(a [] *rat) PS{
Z:=mkPS()
begin func(a [] *rat, Z PS){
j:=0
done:=0
for j=len(a); !done&&j>0; j=j-1)
if(a[j-1].num!=0) done=1
i:=0
for(; i<j; i=i+1) put(a[i],Z)
put(finis,Z)
}()
return Z
}
*/
// Multiply. The algorithm is
// let U = u + x*UU
// let V = v + x*VV
// then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
func Mul(U, V PS) PS {
Z := mkPS()
go func(U, V, Z PS) {
<-Z.req
uv := get2(U, V)
if end(uv[0].(*rat)) != 0 || end(uv[1].(*rat)) != 0 {
Z.dat <- finis
} else {
Z.dat <- mul(uv[0].(*rat), uv[1].(*rat))
UU := Split(U)
VV := Split(V)
W := Add(Cmul(uv[0].(*rat), VV[0]), Cmul(uv[1].(*rat), UU[0]))
<-Z.req
Z.dat <- get(W)
copy(Add(W, Mul(UU[1], VV[1])), Z)
}
}(U, V, Z)
return Z
}
// Differentiate
func Diff(U PS) PS {
Z := mkPS()
go func(U, Z PS) {
<-Z.req
u := get(U)
if end(u) == 0 {
done := false
for i := 1; !done; i++ {
u = get(U)
if end(u) != 0 {
done = true
} else {
Z.dat <- mul(itor(int64(i)), u)
<-Z.req
}
}
}
Z.dat <- finis
}(U, Z)
return Z
}
// Integrate, with const of integration
func Integ(c *rat, U PS) PS {
Z := mkPS()
go func(c *rat, U, Z PS) {
put(c, Z)
done := false
for i := 1; !done; i++ {
<-Z.req
u := get(U)
if end(u) != 0 {
done = true
}
Z.dat <- mul(i2tor(1, int64(i)), u)
}
Z.dat <- finis
}(c, U, Z)
return Z
}
// Binomial theorem (1+x)^c
func Binom(c *rat) PS {
Z := mkPS()
go func(c *rat, Z PS) {
n := 1
t := itor(1)
for c.num != 0 {
put(t, Z)
t = mul(mul(t, c), i2tor(1, int64(n)))
c = sub(c, one)
n++
}
put(finis, Z)
}(c, Z)
return Z
}
// Reciprocal of a power series
// let U = u + x*UU
// let Z = z + x*ZZ
// (u+x*UU)*(z+x*ZZ) = 1
// z = 1/u
// u*ZZ + z*UU +x*UU*ZZ = 0
// ZZ = -UU*(z+x*ZZ)/u
func Recip(U PS) PS {
Z := mkPS()
go func(U, Z PS) {
ZZ := mkPS2()
<-Z.req
z := inv(get(U))
Z.dat <- z
split(Mul(Cmul(neg(z), U), Shift(z, ZZ[0])), ZZ)
copy(ZZ[1], Z)
}(U, Z)
return Z
}
// Exponential of a power series with constant term 0
// (nonzero constant term would make nonrational coefficients)
// bug: the constant term is simply ignored
// Z = exp(U)
// DZ = Z*DU
// integrate to get Z
func Exp(U PS) PS {
ZZ := mkPS2()
split(Integ(one, Mul(ZZ[0], Diff(U))), ZZ)
return ZZ[1]
}
// Substitute V for x in U, where the leading term of V is zero
// let U = u + x*UU
// let V = v + x*VV
// then S(U,V) = u + VV*S(V,UU)
// bug: a nonzero constant term is ignored
func Subst(U, V PS) PS {
Z := mkPS()
go func(U, V, Z PS) {
VV := Split(V)
<-Z.req
u := get(U)
Z.dat <- u
if end(u) == 0 {
if end(get(VV[0])) != 0 {
put(finis, Z)
} else {
copy(Mul(VV[0], Subst(U, VV[1])), Z)
}
}
}(U, V, Z)
return Z
}
// Monomial Substitution: U(c x^n)
// Each Ui is multiplied by c^i and followed by n-1 zeros
func MonSubst(U PS, c0 *rat, n int) PS {
Z := mkPS()
go func(U, Z PS, c0 *rat, n int) {
c := one
for {
<-Z.req
u := get(U)
Z.dat <- mul(u, c)
c = mul(c, c0)
if end(u) != 0 {
Z.dat <- finis
break
}
for i := 1; i < n; i++ {
<-Z.req
Z.dat <- zero
}
}
}(U, Z, c0, n)
return Z
}
func Init() {
chnameserial = -1
seqno = 0
chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
zero = itor(0)
one = itor(1)
finis = i2tor(1, 0)
Ones = Rep(one)
Twos = Rep(itor(2))
}
func check(U PS, c *rat, count int, str string) {
for i := 0; i < count; i++ {
r := get(U)
if !r.eq(c) {
print("got: ")
r.pr()
print("should get ")
c.pr()
print("\n")
panic(str)
}
}
}
const N = 10
func checka(U PS, a []*rat, str string) {
for i := 0; i < N; i++ {
check(U, a[i], 1, str)
}
}
func main() {
Init()
if len(os.Args) > 1 { // print
print("Ones: ")
Printn(Ones, 10)
print("Twos: ")
Printn(Twos, 10)
print("Add: ")
Printn(Add(Ones, Twos), 10)
print("Diff: ")
Printn(Diff(Ones), 10)
print("Integ: ")
Printn(Integ(zero, Ones), 10)
print("CMul: ")
Printn(Cmul(neg(one), Ones), 10)
print("Sub: ")
Printn(Sub(Ones, Twos), 10)
print("Mul: ")
Printn(Mul(Ones, Ones), 10)
print("Exp: ")
Printn(Exp(Ones), 15)
print("MonSubst: ")
Printn(MonSubst(Ones, neg(one), 2), 10)
print("ATan: ")
Printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
} else { // test
check(Ones, one, 5, "Ones")
check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones") // 1 1 1 1 1
check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
a := make([]*rat, N)
d := Diff(Ones)
for i := 0; i < N; i++ {
a[i] = itor(int64(i + 1))
}
checka(d, a, "Diff") // 1 2 3 4 5
in := Integ(zero, Ones)
a[0] = zero // integration constant
for i := 1; i < N; i++ {
a[i] = i2tor(1, int64(i))
}
checka(in, a, "Integ") // 0 1 1/2 1/3 1/4 1/5
check(Cmul(neg(one), Twos), itor(-2), 10, "CMul") // -1 -1 -1 -1 -1
check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos") // -1 -1 -1 -1 -1
m := Mul(Ones, Ones)
for i := 0; i < N; i++ {
a[i] = itor(int64(i + 1))
}
checka(m, a, "Mul") // 1 2 3 4 5
e := Exp(Ones)
a[0] = itor(1)
a[1] = itor(1)
a[2] = i2tor(3, 2)
a[3] = i2tor(13, 6)
a[4] = i2tor(73, 24)
a[5] = i2tor(167, 40)
a[6] = i2tor(4051, 720)
a[7] = i2tor(37633, 5040)
a[8] = i2tor(43817, 4480)
a[9] = i2tor(4596553, 362880)
checka(e, a, "Exp") // 1 1 3/2 13/6 73/24
at := Integ(zero, MonSubst(Ones, neg(one), 2))
for c, i := 1, 0; i < N; i++ {
if i%2 == 0 {
a[i] = zero
} else {
a[i] = i2tor(int64(c), int64(i))
c *= -1
}
}
checka(at, a, "ATan") // 0 -1 0 -1/3 0 -1/5
/*
t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
a[0] = zero
a[1] = itor(1)
a[2] = zero
a[3] = i2tor(1,3)
a[4] = zero
a[5] = i2tor(2,15)
a[6] = zero
a[7] = i2tor(17,315)
a[8] = zero
a[9] = i2tor(62,2835)
checka(t, a, "Tan") // 0 1 0 1/3 0 2/15
*/
}
}

58
test/chan/select.go Normal file
View File

@@ -0,0 +1,58 @@
// run
// Copyright 2009 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 simple select.
package main
var counter uint
var shift uint
func GetValue() uint {
counter++
return 1 << shift
}
func Send(a, b chan uint) int {
var i int
LOOP:
for {
select {
case a <- GetValue():
i++
a = nil
case b <- GetValue():
i++
b = nil
default:
break LOOP
}
shift++
}
return i
}
func main() {
a := make(chan uint, 1)
b := make(chan uint, 1)
if v := Send(a, b); v != 2 {
println("Send returned", v, "!= 2")
panic("fail")
}
if av, bv := <-a, <-b; av|bv != 3 {
println("bad values", av, bv)
panic("fail")
}
if v := Send(a, nil); v != 1 {
println("Send returned", v, "!= 1")
panic("fail")
}
if counter != 10 {
println("counter is", counter, "!= 10")
panic("fail")
}
}

54
test/chan/select2.go Normal file
View File

@@ -0,0 +1,54 @@
// run
// Copyright 2010 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 that selects do not consume undue memory.
package main
import "runtime"
func sender(c chan int, n int) {
for i := 0; i < n; i++ {
c <- 1
}
}
func receiver(c, dummy chan int, n int) {
for i := 0; i < n; i++ {
select {
case <-c:
// nothing
case <-dummy:
panic("dummy")
}
}
}
func main() {
runtime.MemProfileRate = 0
c := make(chan int)
dummy := make(chan int)
// warm up
go sender(c, 100000)
receiver(c, dummy, 100000)
runtime.GC()
memstats := new(runtime.MemStats)
runtime.ReadMemStats(memstats)
alloc := memstats.Alloc
// second time shouldn't increase footprint by much
go sender(c, 100000)
receiver(c, dummy, 100000)
runtime.GC()
runtime.ReadMemStats(memstats)
// Be careful to avoid wraparound.
if memstats.Alloc > alloc && memstats.Alloc-alloc > 1.1e5 {
println("BUG: too much memory for 100,000 selects:", memstats.Alloc-alloc)
}
}

226
test/chan/select3.go Normal file
View File

@@ -0,0 +1,226 @@
// run
// Copyright 2010 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 the semantics of the select statement
// for basic empty/non-empty cases.
package main
import "time"
const always = "function did not"
const never = "function did"
func unreachable() {
panic("control flow shouldn't reach here")
}
// Calls f and verifies that f always/never panics depending on signal.
func testPanic(signal string, f func()) {
defer func() {
s := never
if recover() != nil {
s = always // f panicked
}
if s != signal {
panic(signal + " panic")
}
}()
f()
}
// Calls f and empirically verifies that f always/never blocks depending on signal.
func testBlock(signal string, f func()) {
c := make(chan string)
go func() {
f()
c <- never // f didn't block
}()
go func() {
if signal == never {
// Wait a long time to make sure that we don't miss our window by accident on a slow machine.
time.Sleep(10 * time.Second)
} else {
// Wait as short a time as we can without false negatives.
// 10ms should be long enough to catch most failures.
time.Sleep(10 * time.Millisecond)
}
c <- always // f blocked always
}()
if <-c != signal {
panic(signal + " block")
}
}
func main() {
const async = 1 // asynchronous channels
var nilch chan int
closedch := make(chan int)
close(closedch)
// sending/receiving from a nil channel blocks
testBlock(always, func() {
nilch <- 7
})
testBlock(always, func() {
<-nilch
})
// sending/receiving from a nil channel inside a select is never selected
testPanic(never, func() {
select {
case nilch <- 7:
unreachable()
default:
}
})
testPanic(never, func() {
select {
case <-nilch:
unreachable()
default:
}
})
// sending to an async channel with free buffer space never blocks
testBlock(never, func() {
ch := make(chan int, async)
ch <- 7
})
// receiving from a closed channel never blocks
testBlock(never, func() {
for i := 0; i < 10; i++ {
if <-closedch != 0 {
panic("expected zero value when reading from closed channel")
}
if x, ok := <-closedch; x != 0 || ok {
println("closedch:", x, ok)
panic("expected 0, false from closed channel")
}
}
})
// sending to a closed channel panics.
testPanic(always, func() {
closedch <- 7
})
// receiving from a non-ready channel always blocks
testBlock(always, func() {
ch := make(chan int)
<-ch
})
// empty selects always block
testBlock(always, func() {
select {}
})
// selects with only nil channels always block
testBlock(always, func() {
select {
case <-nilch:
unreachable()
}
})
testBlock(always, func() {
select {
case nilch <- 7:
unreachable()
}
})
testBlock(always, func() {
select {
case <-nilch:
unreachable()
case nilch <- 7:
unreachable()
}
})
// selects with non-ready non-nil channels always block
testBlock(always, func() {
ch := make(chan int)
select {
case <-ch:
unreachable()
}
})
// selects with default cases don't block
testBlock(never, func() {
select {
default:
}
})
testBlock(never, func() {
select {
case <-nilch:
unreachable()
default:
}
})
testBlock(never, func() {
select {
case nilch <- 7:
unreachable()
default:
}
})
// selects with ready channels don't block
testBlock(never, func() {
ch := make(chan int, async)
select {
case ch <- 7:
default:
unreachable()
}
})
testBlock(never, func() {
ch := make(chan int, async)
ch <- 7
select {
case <-ch:
default:
unreachable()
}
})
// selects with closed channels behave like ordinary operations
testBlock(never, func() {
select {
case <-closedch:
}
})
testBlock(never, func() {
select {
case x := (<-closedch):
_ = x
}
})
testBlock(never, func() {
select {
case x, ok := (<-closedch):
_, _ = x, ok
}
})
testPanic(always, func() {
select {
case closedch <- 7:
}
})
// select should not get confused if it sees itself
testBlock(always, func() {
c := make(chan int)
select {
case c <- 1:
case <-c:
}
})
}

31
test/chan/select4.go Normal file
View File

@@ -0,0 +1,31 @@
// run
// Copyright 2010 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 that a select statement proceeds when a value is ready.
package main
func f() *int {
println("BUG: called f")
return new(int)
}
func main() {
var x struct {
a int
}
c := make(chan int, 1)
c1 := make(chan int)
c <- 42
select {
case *f() = <-c1:
// nothing
case x.a = <-c:
if x.a != 42 {
println("BUG:", x.a)
}
}
}

481
test/chan/select5.go Normal file
View File

@@ -0,0 +1,481 @@
// runoutput
// 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.
// Generate test of channel operations and simple selects.
// The output of this program is compiled and run to do the
// actual test.
// Each test does only one real send or receive at a time, but phrased
// in various ways that the compiler may or may not rewrite
// into simpler expressions.
package main
import (
"bufio"
"fmt"
"io"
"os"
"text/template"
)
func main() {
out := bufio.NewWriter(os.Stdout)
fmt.Fprintln(out, header)
a := new(arg)
// Generate each test as a separate function to avoid
// hitting the gc optimizer with one enormous function.
// If we name all the functions init we don't have to
// maintain a list of which ones to run.
do := func(t *template.Template) {
for ; next(); a.reset() {
fmt.Fprintln(out, `func init() {`)
run(t, a, out)
fmt.Fprintln(out, `}`)
}
}
do(recv)
do(send)
do(recvOrder)
do(sendOrder)
do(nonblock)
fmt.Fprintln(out, "//", a.nreset, "cases")
out.Flush()
}
func run(t *template.Template, a interface{}, out io.Writer) {
if err := t.Execute(out, a); err != nil {
panic(err)
}
}
type arg struct {
def bool
nreset int
}
func (a *arg) Maybe() bool {
return maybe()
}
func (a *arg) MaybeDefault() bool {
if a.def {
return false
}
a.def = maybe()
return a.def
}
func (a *arg) MustDefault() bool {
return !a.def
}
func (a *arg) reset() {
a.def = false
a.nreset++
}
const header = `// GENERATED BY select5.go; DO NOT EDIT
package main
// channel is buffered so test is single-goroutine.
// we are not interested in the concurrency aspects
// of select, just testing that the right calls happen.
var c = make(chan int, 1)
var nilch chan int
var n = 1
var x int
var i interface{}
var dummy = make(chan int)
var m = make(map[int]int)
var order = 0
func f(p *int) *int {
return p
}
// check order of operations by ensuring that
// successive calls to checkorder have increasing o values.
func checkorder(o int) {
if o <= order {
println("invalid order", o, "after", order)
panic("order")
}
order = o
}
func fc(c chan int, o int) chan int {
checkorder(o)
return c
}
func fp(p *int, o int) *int {
checkorder(o)
return p
}
func fn(n, o int) int {
checkorder(o)
return n
}
func die(x int) {
println("have", x, "want", n)
panic("chan")
}
func main() {
// everything happens in init funcs
}
`
func parse(name, s string) *template.Template {
t, err := template.New(name).Parse(s)
if err != nil {
panic(fmt.Sprintf("%q: %s", name, err))
}
return t
}
var recv = parse("recv", `
{{/* Send n, receive it one way or another into x, check that they match. */}}
c <- n
{{if .Maybe}}
x = <-c
{{else}}
select {
{{/* Blocking or non-blocking, before the receive. */}}
{{/* The compiler implements two-case select where one is default with custom code, */}}
{{/* so test the default branch both before and after the send. */}}
{{if .MaybeDefault}}
default:
panic("nonblock")
{{end}}
{{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
{{if .Maybe}}
case x = <-c:
{{else}}{{if .Maybe}}
case *f(&x) = <-c:
{{else}}{{if .Maybe}}
case y := <-c:
x = y
{{else}}{{if .Maybe}}
case i = <-c:
x = i.(int)
{{else}}
case m[13] = <-c:
x = m[13]
{{end}}{{end}}{{end}}{{end}}
{{/* Blocking or non-blocking again, after the receive. */}}
{{if .MaybeDefault}}
default:
panic("nonblock")
{{end}}
{{/* Dummy send, receive to keep compiler from optimizing select. */}}
{{if .Maybe}}
case dummy <- 1:
panic("dummy send")
{{end}}
{{if .Maybe}}
case <-dummy:
panic("dummy receive")
{{end}}
{{/* Nil channel send, receive to keep compiler from optimizing select. */}}
{{if .Maybe}}
case nilch <- 1:
panic("nilch send")
{{end}}
{{if .Maybe}}
case <-nilch:
panic("nilch recv")
{{end}}
}
{{end}}
if x != n {
die(x)
}
n++
`)
var recvOrder = parse("recvOrder", `
{{/* Send n, receive it one way or another into x, check that they match. */}}
{{/* Check order of operations along the way by calling functions that check */}}
{{/* that the argument sequence is strictly increasing. */}}
order = 0
c <- n
{{if .Maybe}}
{{/* Outside of select, left-to-right rule applies. */}}
{{/* (Inside select, assignment waits until case is chosen, */}}
{{/* so right hand side happens before anything on left hand side. */}}
*fp(&x, 1) = <-fc(c, 2)
{{else}}{{if .Maybe}}
m[fn(13, 1)] = <-fc(c, 2)
x = m[13]
{{else}}
select {
{{/* Blocking or non-blocking, before the receive. */}}
{{/* The compiler implements two-case select where one is default with custom code, */}}
{{/* so test the default branch both before and after the send. */}}
{{if .MaybeDefault}}
default:
panic("nonblock")
{{end}}
{{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
{{if .Maybe}}
case *fp(&x, 100) = <-fc(c, 1):
{{else}}{{if .Maybe}}
case y := <-fc(c, 1):
x = y
{{else}}{{if .Maybe}}
case i = <-fc(c, 1):
x = i.(int)
{{else}}
case m[fn(13, 100)] = <-fc(c, 1):
x = m[13]
{{end}}{{end}}{{end}}
{{/* Blocking or non-blocking again, after the receive. */}}
{{if .MaybeDefault}}
default:
panic("nonblock")
{{end}}
{{/* Dummy send, receive to keep compiler from optimizing select. */}}
{{if .Maybe}}
case fc(dummy, 2) <- fn(1, 3):
panic("dummy send")
{{end}}
{{if .Maybe}}
case <-fc(dummy, 4):
panic("dummy receive")
{{end}}
{{/* Nil channel send, receive to keep compiler from optimizing select. */}}
{{if .Maybe}}
case fc(nilch, 5) <- fn(1, 6):
panic("nilch send")
{{end}}
{{if .Maybe}}
case <-fc(nilch, 7):
panic("nilch recv")
{{end}}
}
{{end}}{{end}}
if x != n {
die(x)
}
n++
`)
var send = parse("send", `
{{/* Send n one way or another, receive it into x, check that they match. */}}
{{if .Maybe}}
c <- n
{{else}}
select {
{{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
{{if .MaybeDefault}}
default:
panic("nonblock")
{{end}}
{{/* Send c <- n. No real special cases here, because no values come back */}}
{{/* from the send operation. */}}
case c <- n:
{{/* Blocking or non-blocking. */}}
{{if .MaybeDefault}}
default:
panic("nonblock")
{{end}}
{{/* Dummy send, receive to keep compiler from optimizing select. */}}
{{if .Maybe}}
case dummy <- 1:
panic("dummy send")
{{end}}
{{if .Maybe}}
case <-dummy:
panic("dummy receive")
{{end}}
{{/* Nil channel send, receive to keep compiler from optimizing select. */}}
{{if .Maybe}}
case nilch <- 1:
panic("nilch send")
{{end}}
{{if .Maybe}}
case <-nilch:
panic("nilch recv")
{{end}}
}
{{end}}
x = <-c
if x != n {
die(x)
}
n++
`)
var sendOrder = parse("sendOrder", `
{{/* Send n one way or another, receive it into x, check that they match. */}}
{{/* Check order of operations along the way by calling functions that check */}}
{{/* that the argument sequence is strictly increasing. */}}
order = 0
{{if .Maybe}}
fc(c, 1) <- fn(n, 2)
{{else}}
select {
{{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
{{if .MaybeDefault}}
default:
panic("nonblock")
{{end}}
{{/* Send c <- n. No real special cases here, because no values come back */}}
{{/* from the send operation. */}}
case fc(c, 1) <- fn(n, 2):
{{/* Blocking or non-blocking. */}}
{{if .MaybeDefault}}
default:
panic("nonblock")
{{end}}
{{/* Dummy send, receive to keep compiler from optimizing select. */}}
{{if .Maybe}}
case fc(dummy, 3) <- fn(1, 4):
panic("dummy send")
{{end}}
{{if .Maybe}}
case <-fc(dummy, 5):
panic("dummy receive")
{{end}}
{{/* Nil channel send, receive to keep compiler from optimizing select. */}}
{{if .Maybe}}
case fc(nilch, 6) <- fn(1, 7):
panic("nilch send")
{{end}}
{{if .Maybe}}
case <-fc(nilch, 8):
panic("nilch recv")
{{end}}
}
{{end}}
x = <-c
if x != n {
die(x)
}
n++
`)
var nonblock = parse("nonblock", `
x = n
{{/* Test various combinations of non-blocking operations. */}}
{{/* Receive assignments must not edit or even attempt to compute the address of the lhs. */}}
select {
{{if .MaybeDefault}}
default:
{{end}}
{{if .Maybe}}
case dummy <- 1:
panic("dummy <- 1")
{{end}}
{{if .Maybe}}
case nilch <- 1:
panic("nilch <- 1")
{{end}}
{{if .Maybe}}
case <-dummy:
panic("<-dummy")
{{end}}
{{if .Maybe}}
case x = <-dummy:
panic("<-dummy x")
{{end}}
{{if .Maybe}}
case **(**int)(nil) = <-dummy:
panic("<-dummy (and didn't crash saving result!)")
{{end}}
{{if .Maybe}}
case <-nilch:
panic("<-nilch")
{{end}}
{{if .Maybe}}
case x = <-nilch:
panic("<-nilch x")
{{end}}
{{if .Maybe}}
case **(**int)(nil) = <-nilch:
panic("<-nilch (and didn't crash saving result!)")
{{end}}
{{if .MustDefault}}
default:
{{end}}
}
if x != n {
die(x)
}
n++
`)
// Code for enumerating all possible paths through
// some logic. The logic should call choose(n) when
// it wants to choose between n possibilities.
// On successive runs through the logic, choose(n)
// will return 0, 1, ..., n-1. The helper maybe() is
// similar but returns true and then false.
//
// Given a function gen that generates an output
// using choose and maybe, code can generate all
// possible outputs using
//
// for next() {
// gen()
// }
type choice struct {
i, n int
}
var choices []choice
var cp int = -1
func maybe() bool {
return choose(2) == 0
}
func choose(n int) int {
if cp >= len(choices) {
// never asked this before: start with 0.
choices = append(choices, choice{0, n})
cp = len(choices)
return 0
}
// otherwise give recorded answer
if n != choices[cp].n {
panic("inconsistent choices")
}
i := choices[cp].i
cp++
return i
}
func next() bool {
if cp < 0 {
// start a new round
cp = 0
return true
}
// increment last choice sequence
cp = len(choices) - 1
for cp >= 0 && choices[cp].i == choices[cp].n-1 {
cp--
}
if cp < 0 {
choices = choices[:0]
return false
}
choices[cp].i++
choices = choices[:cp+1]
cp = 0
return true
}

34
test/chan/select6.go Normal file
View File

@@ -0,0 +1,34 @@
// run
// 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.
// Test for select: Issue 2075
// A bug in select corrupts channel queues of failed cases
// if there are multiple waiters on those channels and the
// select is the last in the queue. If further waits are made
// on the channel without draining it first then those waiters
// will never wake up. In the code below c1 is such a channel.
package main
func main() {
c1 := make(chan bool)
c2 := make(chan bool)
c3 := make(chan bool)
go func() { <-c1 }()
go func() {
select {
case <-c1:
panic("dummy")
case <-c2:
c3 <- true
}
<-c1
}()
go func() { c2 <- true }()
<-c3
c1 <- true
c1 <- true
}

Some files were not shown because too many files have changed in this diff Show More