Initial commit: Go 1.23 release state
This commit is contained in:
75
test/235.go
Normal file
75
test/235.go
Normal 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
728
test/64bit.go
Normal 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
19
test/README.md
Normal 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.
|
||||
73
test/abi/bad_internal_offsets.go
Normal file
73
test/abi/bad_internal_offsets.go
Normal 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
|
||||
}
|
||||
272
test/abi/bad_select_crash.go
Normal file
272
test/abi/bad_select_crash.go
Normal 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
|
||||
}
|
||||
27
test/abi/convF_criteria.go
Normal file
27
test/abi/convF_criteria.go
Normal 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)
|
||||
}
|
||||
2
test/abi/convF_criteria.out
Normal file
2
test/abi/convF_criteria.out
Normal file
@@ -0,0 +1,2 @@
|
||||
{[] -1.25}
|
||||
{[] -7.97 []}
|
||||
25
test/abi/convT64_criteria.go
Normal file
25
test/abi/convT64_criteria.go
Normal 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)
|
||||
}
|
||||
1
test/abi/convT64_criteria.out
Normal file
1
test/abi/convT64_criteria.out
Normal file
@@ -0,0 +1 @@
|
||||
{[] 27 9887 {0}}
|
||||
48
test/abi/defer_aggregate.go
Normal file
48
test/abi/defer_aggregate.go
Normal 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)
|
||||
}
|
||||
36
test/abi/defer_recover_results.go
Normal file
36
test/abi/defer_recover_results.go
Normal 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")
|
||||
}
|
||||
}
|
||||
61
test/abi/double_nested_addressed_struct.go
Normal file
61
test/abi/double_nested_addressed_struct.go
Normal 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)
|
||||
}
|
||||
}
|
||||
53
test/abi/double_nested_struct.go
Normal file
53
test/abi/double_nested_struct.go
Normal 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
38
test/abi/f_ret_z_not.go
Normal 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
1
test/abi/f_ret_z_not.out
Normal file
@@ -0,0 +1 @@
|
||||
7
|
||||
32
test/abi/fibish.go
Normal file
32
test/abi/fibish.go
Normal 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
1
test/abi/fibish.out
Normal file
@@ -0,0 +1 @@
|
||||
f(40)=39088169,126491972
|
||||
33
test/abi/fibish_closure.go
Normal file
33
test/abi/fibish_closure.go
Normal 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)
|
||||
}
|
||||
1
test/abi/fibish_closure.out
Normal file
1
test/abi/fibish_closure.out
Normal file
@@ -0,0 +1 @@
|
||||
f(40)=39088169,126491972
|
||||
39
test/abi/fuzz_trailing_zero_field.go
Normal file
39
test/abi/fuzz_trailing_zero_field.go
Normal 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
97
test/abi/idata.go
Normal 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
1
test/abi/idata.out
Normal file
@@ -0,0 +1 @@
|
||||
s=3.14286
|
||||
35
test/abi/leaf.go
Normal file
35
test/abi/leaf.go
Normal 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
42
test/abi/leaf2.go
Normal 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)
|
||||
}
|
||||
}
|
||||
32
test/abi/many_int_input.go
Normal file
32
test/abi/many_int_input.go
Normal 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)
|
||||
}
|
||||
1
test/abi/many_int_input.out
Normal file
1
test/abi/many_int_input.out
Normal 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
|
||||
44
test/abi/many_intstar_input.go
Normal file
44
test/abi/many_intstar_input.go
Normal 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)
|
||||
}
|
||||
3
test/abi/many_intstar_input.out
Normal file
3
test/abi/many_intstar_input.out
Normal 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
34
test/abi/map.go
Normal 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()
|
||||
}
|
||||
35
test/abi/method_wrapper.go
Normal file
35
test/abi/method_wrapper.go
Normal 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")
|
||||
}
|
||||
}
|
||||
39
test/abi/more_intstar_input.go
Normal file
39
test/abi/more_intstar_input.go
Normal 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)
|
||||
}
|
||||
2
test/abi/more_intstar_input.out
Normal file
2
test/abi/more_intstar_input.out
Normal file
@@ -0,0 +1,2 @@
|
||||
Got this far!
|
||||
Sink = 7
|
||||
90
test/abi/named_results.go
Normal file
90
test/abi/named_results.go
Normal 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)
|
||||
|
||||
}
|
||||
13
test/abi/named_results.out
Normal file
13
test/abi/named_results.out
Normal 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!
|
||||
93
test/abi/named_return_stuff.go
Normal file
93
test/abi/named_return_stuff.go
Normal 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)
|
||||
|
||||
}
|
||||
13
test/abi/named_return_stuff.out
Normal file
13
test/abi/named_return_stuff.out
Normal 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
36
test/abi/open_defer_1.go
Normal 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
48
test/abi/part_live.go
Normal 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
53
test/abi/part_live_2.go
Normal 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
39
test/abi/reg_not_ssa.go
Normal 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
20
test/abi/result_live.go
Normal 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
|
||||
46
test/abi/result_regalloc.go
Normal file
46
test/abi/result_regalloc.go
Normal 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
37
test/abi/return_stuff.go
Normal 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)
|
||||
}
|
||||
3
test/abi/return_stuff.out
Normal file
3
test/abi/return_stuff.out
Normal file
@@ -0,0 +1,3 @@
|
||||
x = 21
|
||||
len(y) = 12
|
||||
y = Hello World!
|
||||
36
test/abi/s_sif_sif.go
Normal file
36
test/abi/s_sif_sif.go
Normal 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
47
test/abi/spills3.go
Normal 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
43
test/abi/spills4.go
Normal 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)
|
||||
}
|
||||
}
|
||||
29
test/abi/store_reg_args.go
Normal file
29
test/abi/store_reg_args.go
Normal 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")
|
||||
}
|
||||
}
|
||||
39
test/abi/struct_3_string_input.go
Normal file
39
test/abi/struct_3_string_input.go
Normal 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)
|
||||
}
|
||||
}
|
||||
0
test/abi/struct_3_string_input.out
Normal file
0
test/abi/struct_3_string_input.out
Normal file
29
test/abi/struct_lower_1.go
Normal file
29
test/abi/struct_lower_1.go
Normal 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}}))
|
||||
}
|
||||
1
test/abi/struct_lower_1.out
Normal file
1
test/abi/struct_lower_1.out
Normal file
@@ -0,0 +1 @@
|
||||
{{1 2 3}}
|
||||
47
test/abi/too_big_to_ssa.go
Normal file
47
test/abi/too_big_to_ssa.go
Normal 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)
|
||||
}
|
||||
}
|
||||
2
test/abi/too_big_to_ssa.out
Normal file
2
test/abi/too_big_to_ssa.out
Normal file
@@ -0,0 +1,2 @@
|
||||
Hello there, World
|
||||
Ahoy there, Matey
|
||||
81
test/abi/uglyfib.go
Normal file
81
test/abi/uglyfib.go
Normal 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
1
test/abi/uglyfib.out
Normal file
@@ -0,0 +1 @@
|
||||
Fib(40)=102334155
|
||||
36
test/abi/wrapdefer_largetmp.go
Normal file
36
test/abi/wrapdefer_largetmp.go
Normal 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() }
|
||||
1
test/abi/wrapdefer_largetmp.out
Normal file
1
test/abi/wrapdefer_largetmp.out
Normal file
@@ -0,0 +1 @@
|
||||
2
|
||||
36
test/abi/zombie_struct_select.go
Normal file
36
test/abi/zombie_struct_select.go
Normal 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
46
test/alg.go
Normal 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
33
test/alias.go
Normal 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
54
test/alias1.go
Normal 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
104
test/alias2.go
Normal 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
42
test/alias3.dir/a.go
Normal 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
26
test/alias3.dir/b.go
Normal 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
25
test/alias3.dir/c.go
Normal 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
7
test/alias3.go
Normal 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
29
test/align.go
Normal 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
254
test/append.go
Normal 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
22
test/append1.go
Normal 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
65
test/arenas/smoke.go
Normal 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
23
test/args.go
Normal 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
179
test/armimm.go
Normal 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
72
test/asmhdr.dir/main.go
Normal 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
30
test/asmhdr.dir/main.s
Normal 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
9
test/asmhdr.go
Normal 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
68
test/assign.go
Normal 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
346
test/assign1.go
Normal 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
45
test/atomicload.go
Normal 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
130
test/bigalg.go
Normal 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
139
test/bigmap.go
Normal 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
189
test/blank.go
Normal 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
32
test/blank1.go
Normal 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
26
test/bom.go
Normal 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
18
test/bombad.go
Normal 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
284
test/bounds.go
Normal 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
33
test/cannotassign.go
Normal 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
87
test/chan/doubleselect.go
Normal 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
56
test/chan/fifo.go
Normal 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
41
test/chan/goroutines.go
Normal 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
282
test/chan/nonblock.go
Normal 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
70
test/chan/perm.go
Normal 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
741
test/chan/powser1.go
Normal 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
755
test/chan/powser2.go
Normal 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
58
test/chan/select.go
Normal 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
54
test/chan/select2.go
Normal 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
226
test/chan/select3.go
Normal 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
31
test/chan/select4.go
Normal 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
481
test/chan/select5.go
Normal 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
34
test/chan/select6.go
Normal 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
Reference in New Issue
Block a user