diff --git a/doc/asm.html b/doc/asm.html
index cce2fe2b8d..392af174c2 100644
--- a/doc/asm.html
+++ b/doc/asm.html
@@ -621,6 +621,15 @@ These modes accept only 1, 2, 4, and 8 as scale factors.
+
+When using the compiler and assembler's
+-dynlink or -shared modes,
+any load or store of a fixed memory location such as a global variable
+must be assumed to overwrite CX.
+Therefore, to be safe for use with these modes,
+assembly sources should typically avoid CX except between memory references.
+
+
64-bit Intel 386 (a.k.a. amd64)
diff --git a/doc/contribute.html b/doc/contribute.html
index a321a8646f..4619c81124 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -198,9 +198,13 @@ prints help text, not an error.
-Note to Git aficionados: The git-codereview command is not required to
+Note to Git aficionados:
+The git-codereview command is not required to
upload and manage Gerrit code reviews. For those who prefer plain Git, the text
-below gives the Git equivalent of each git-codereview command. If you do use plain
+below gives the Git equivalent of each git-codereview command.
+
+
+If you do use plain
Git, note that you still need the commit hooks that the git-codereview command
configures; those hooks add a Gerrit Change-Id line to the commit
message and check that all Go source files have been formatted with gofmt. Even
@@ -208,6 +212,12 @@ if you intend to use plain Git for daily work, install the hooks in a new Git
checkout by running git-codereview hooks.
+
+The workflow described below assumes a single change per branch.
+It is also possible to prepare a sequence of (usually related) changes in a single branch.
+See the git-codereview documentation for details.
+
+
Set up git aliases
diff --git a/doc/devel/release.html b/doc/devel/release.html
index ad060a8ce6..e0c2ac0219 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -30,6 +30,13 @@ to fix critical security problems in both Go 1.4 and Go 1.5 as they arise.
See the security policy for more details.
+go1.6 (released 2016/02/17)
+
+
+Go 1.6 is a major release of Go.
+Read the Go 1.6 Release Notes for more information.
+
+
go1.5 (released 2015/08/19)
diff --git a/doc/go1.6.html b/doc/go1.6.html
index 6e3710cbad..17c3536aeb 100644
--- a/doc/go1.6.html
+++ b/doc/go1.6.html
@@ -1,5 +1,5 @@
@@ -13,13 +13,6 @@ Edit .,s;^([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .
ul li { margin: 0.5em 0; }
-
-NOTE: This is a DRAFT of the Go 1.6 release notes, prepared for the Go 1.6 beta.
-Go 1.6 has NOT yet been released.
-By our regular schedule, it is expected some time in February 2016.
-
-
-
Introduction to Go 1.6
@@ -70,9 +63,12 @@ On NaCl, Go 1.5 required SDK version pepper-41.
Go 1.6 adds support for later SDK versions.
-
-TODO: CX no longer available on 386 assembly? (https://golang.org/cl/16386)
-
+
+On 32-bit x86 systems using the -dynlink or -shared compilation modes,
+the register CX is now overwritten by certain memory references and should
+be avoided in hand-written assembly.
+See the assembly documentation for details.
+
@@ -248,7 +244,7 @@ Some programs may run faster, some slower.
On average the programs in the Go 1 benchmark suite run a few percent faster in Go 1.6
than they did in Go 1.5.
The garbage collector's pauses are even lower than in Go 1.5,
-although the effect is likely only noticeable for programs using
+especially for programs using
a large amount of memory.
@@ -569,7 +565,7 @@ The debug/elf package
adds support for general compressed ELF sections.
User code needs no updating: the sections are decompressed automatically when read.
However, compressed
-Section's do not support random access:
+Sections do not support random access:
they have a nil ReaderAt field.
@@ -632,7 +628,6 @@ In previous releases, the argument to * was required to have type <
Also in the fmt package,
Scanf can now scan hexadecimal strings using %X, as an alias for %x.
Both formats accept any mix of upper- and lower-case hexadecimal.
-TODO: Keep?
@@ -717,9 +712,6 @@ Second, DNS lookup functions such as
LookupAddr
now return rooted domain names (with a trailing dot)
on Plan 9 and Windows, to match the behavior of Go on Unix systems.
-TODO: Third, lookups satisfied from /etc/hosts now add a trailing dot as well,
-so that looking up 127.0.0.1 typically now returns “localhost.” not “localhost”.
-This is arguably a mistake but is not yet fixed. See https://golang.org/issue/13564.
diff --git a/doc/go1.7.txt b/doc/go1.7.txt
new file mode 100644
index 0000000000..15efa287ce
--- /dev/null
+++ b/doc/go1.7.txt
@@ -0,0 +1,14 @@
+Tools:
+
+cmd/go: GO15VENDOREXPERIMENT gone, assumed on (CL 19615)
+cmd/link: "-X name value" form gone (CL 19614)
+
+Ports:
+
+SOMETHING WILL HAPPEN
+
+API additions and behavior changes:
+
+SOMETHING WILL HAPPEN
+
+
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 6b6e75c7c9..437fc066bb 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
@@ -2443,9 +2443,8 @@ PrimaryExpr =
Selector = "." identifier .
Index = "[" Expression "]" .
-Slice = "[" ( [ Expression ] ":" [ Expression ] ) |
- ( [ Expression ] ":" Expression ":" Expression )
- "]" .
+Slice = "[" [ Expression ] ":" [ Expression ] "]" |
+ "[" [ Expression ] ":" Expression ":" Expression "]" .
TypeAssertion = "." "(" Type ")" .
Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
diff --git a/misc/cgo/test/issue13930.go b/misc/cgo/test/issue13930.go
new file mode 100644
index 0000000000..3a22459e68
--- /dev/null
+++ b/misc/cgo/test/issue13930.go
@@ -0,0 +1,13 @@
+// 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.
+
+// Issue 13930. Test that cgo's multiple-value special form for
+// C function calls works in variable declaration statements.
+
+package cgotest
+
+// #include
+import "C"
+
+var _, _ = C.abs(0)
diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto
index b51e8da5c7..dcb156350a 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -27,6 +27,18 @@ go src=..
internal
objfile
objfile.go
+ unvendor
+ golang.org
+ x
+ arch
+ arm
+ armasm
+ testdata
+ +
+ x86
+ x86asm
+ testdata
+ +
gofmt
gofmt.go
gofmt_test.go
@@ -35,18 +47,6 @@ go src=..
newlink
testdata
+
- vendor
- golang.org
- x
- arch
- arm
- armasm
- testdata
- +
- x86
- x86asm
- testdata
- +
archive
tar
testdata
diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go
index 5ce66e6be5..3a9292e380 100644
--- a/src/archive/zip/writer.go
+++ b/src/archive/zip/writer.go
@@ -52,7 +52,7 @@ func (w *Writer) Flush() error {
}
// Close finishes writing the zip file by writing the central directory.
-// It does not (and can not) close the underlying writer.
+// It does not (and cannot) close the underlying writer.
func (w *Writer) Close() error {
if w.last != nil && !w.last.closed {
if err := w.last.close(); err != nil {
diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go
index ddaba3bff3..f135b46959 100644
--- a/src/bytes/buffer.go
+++ b/src/bytes/buffer.go
@@ -17,7 +17,7 @@ import (
type Buffer struct {
buf []byte // contents are the bytes buf[off : len(buf)]
off int // read at &buf[off], write at &buf[len(buf)]
- runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
+ runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each call to WriteRune
bootstrap [64]byte // memory to hold first slice; helps small buffers (Printf) avoid allocation.
lastRead readOp // last read operation, so that Unread* can work correctly.
}
diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go
index 1d2cc9ac82..a3fe0efedc 100644
--- a/src/cmd/api/goapi_test.go
+++ b/src/cmd/api/goapi_test.go
@@ -178,7 +178,7 @@ func BenchmarkAll(b *testing.B) {
for _, context := range contexts {
w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
for _, name := range pkgNames {
- if name != "unsafe" && !strings.HasPrefix(name, "cmd/") {
+ if name != "unsafe" && !strings.HasPrefix(name, "cmd/") && !internalPkg.MatchString(name) {
pkg, _ := w.Import(name)
w.export(pkg)
}
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
index c14a13cdb1..f9436cb7f2 100644
--- a/src/cmd/asm/internal/arch/arch.go
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -162,8 +162,6 @@ func archX86(linkArch *obj.LinkArch) *Arch {
instructions["MOVDQ2Q"] = x86.AMOVQ
instructions["MOVNTDQ"] = x86.AMOVNTO
instructions["MOVOA"] = x86.AMOVO
- instructions["PF2ID"] = x86.APF2IL
- instructions["PI2FD"] = x86.API2FL
instructions["PSLLDQ"] = x86.APSLLO
instructions["PSRLDQ"] = x86.APSRLO
instructions["PADDD"] = x86.APADDL
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index c3a24c2b76..4c5dc9a23d 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -447,7 +447,11 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
case *ast.ImportSpec:
case *ast.ValueSpec:
f.walk(&n.Type, "type", visit)
- f.walk(n.Values, "expr", visit)
+ if len(n.Names) == 2 && len(n.Values) == 1 {
+ f.walk(&n.Values[0], "as2", visit)
+ } else {
+ f.walk(n.Values, "expr", visit)
+ }
case *ast.TypeSpec:
f.walk(&n.Type, "type", visit)
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index bd38a5c153..90c2584c7f 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -133,7 +133,7 @@ C's union types are represented as a Go byte array with the same length.
Go structs cannot embed fields with C types.
-Go code can not refer to zero-sized fields that occur at the end of
+Go code cannot refer to zero-sized fields that occur at the end of
non-empty C structs. To get the address of such a field (which is the
only operation you can do with a zero-sized field) you must take the
address of the struct and add the size of the struct.
@@ -148,8 +148,9 @@ assignment context to retrieve both the return value (if any) and the
C errno variable as an error (use _ to skip the result value if the
function returns void). For example:
- n, err := C.sqrt(-1)
+ n, err = C.sqrt(-1)
_, err := C.voidFunc()
+ var n, err = C.sqrt(1)
Calling C function pointers is currently not supported, however you can
declare Go variables which hold C function pointers and pass them
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index fb5049c1a1..5bfdef785c 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -432,7 +432,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fmt.Fprintf(&b, "\t0,\n")
}
}
- // for the last entry, we can not use 0, otherwise
+ // for the last entry, we cannot use 0, otherwise
// in case all __cgodebug_data is zero initialized,
// LLVM-based gcc will place the it in the __DATA.__common
// zero-filled section (our debug/macho doesn't support
@@ -2025,7 +2025,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
// We can't permit that, because then the size of the Go
// struct will not be the same as the size of the C struct.
// Our only option in such a case is to remove the field,
- // which means that it can not be referenced from Go.
+ // which means that it cannot be referenced from Go.
for off > 0 && sizes[len(sizes)-1] == 0 {
n := len(sizes)
fld = fld[0 : n-1]
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index 3adb8e8783..52ca160ad9 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -8,6 +8,7 @@ import (
"bytes"
"fmt"
"go/token"
+ "io/ioutil"
"os"
"os/exec"
)
@@ -16,6 +17,43 @@ import (
// It returns the output to standard output and standard error.
// ok indicates whether the command exited successfully.
func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
+ if i := find(argv, "-xc"); i >= 0 && argv[len(argv)-1] == "-" {
+ // Some compilers have trouble with standard input.
+ // Others have trouble with -xc.
+ // Avoid both problems by writing a file with a .c extension.
+ f, err := ioutil.TempFile("", "cgo-gcc-input-")
+ if err != nil {
+ fatalf("%s", err)
+ }
+ name := f.Name()
+ f.Close()
+ if err := ioutil.WriteFile(name+".c", stdin, 0666); err != nil {
+ os.Remove(name)
+ fatalf("%s", err)
+ }
+ defer os.Remove(name)
+ defer os.Remove(name + ".c")
+
+ // Build new argument list without -xc and trailing -.
+ new := append(argv[:i:i], argv[i+1:len(argv)-1]...)
+
+ // Since we are going to write the file to a temporary directory,
+ // we will need to add -I . explicitly to the command line:
+ // any #include "foo" before would have looked in the current
+ // directory as the directory "holding" standard input, but now
+ // the temporary directory holds the input.
+ // We've also run into compilers that reject "-I." but allow "-I", ".",
+ // so be sure to use two arguments.
+ // This matters mainly for people invoking cgo -godefs by hand.
+ new = append(new, "-I", ".")
+
+ // Finish argument list with path to C file.
+ new = append(new, name+".c")
+
+ argv = new
+ stdin = nil
+ }
+
p := exec.Command(argv[0], argv[1:]...)
p.Stdin = bytes.NewReader(stdin)
var bout, berr bytes.Buffer
@@ -30,6 +68,15 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
return
}
+func find(argv []string, target string) int {
+ for i, arg := range argv {
+ if arg == target {
+ return i
+ }
+ }
+ return -1
+}
+
func lineno(pos token.Pos) string {
return fset.Position(pos).String()
}
diff --git a/src/cmd/compile/internal/arm/prog.go b/src/cmd/compile/internal/arm/prog.go
index 81be77a5b0..49a329b535 100644
--- a/src/cmd/compile/internal/arm/prog.go
+++ b/src/cmd/compile/internal/arm/prog.go
@@ -98,11 +98,11 @@ var progtable = [arm.ALAST]obj.ProgInfo{
arm.AMOVH: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move},
arm.AMOVW: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
- // In addtion, duffzero reads R0,R1 and writes R1. This fact is
+ // In addition, duffzero reads R0,R1 and writes R1. This fact is
// encoded in peep.c
obj.ADUFFZERO: {Flags: gc.Call},
- // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is
+ // In addition, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is
// encoded in peep.c
obj.ADUFFCOPY: {Flags: gc.Call},
diff --git a/src/cmd/compile/internal/big/example_rat_test.go b/src/cmd/compile/internal/big/example_rat_test.go
new file mode 100644
index 0000000000..ef0649785a
--- /dev/null
+++ b/src/cmd/compile/internal/big/example_rat_test.go
@@ -0,0 +1,65 @@
+// Copyright 2015 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 big_test
+
+import (
+ "cmd/compile/internal/big"
+ "fmt"
+)
+
+// Use the classic continued fraction for e
+// e = [1; 0, 1, 1, 2, 1, 1, ... 2n, 1, 1, ...]
+// i.e., for the nth term, use
+// 1 if n mod 3 != 1
+// (n-1)/3 * 2 if n mod 3 == 1
+func recur(n, lim int64) *big.Rat {
+ term := new(big.Rat)
+ if n%3 != 1 {
+ term.SetInt64(1)
+ } else {
+ term.SetInt64((n - 1) / 3 * 2)
+ }
+
+ if n > lim {
+ return term
+ }
+
+ // Directly initialize frac as the fractional
+ // inverse of the result of recur.
+ frac := new(big.Rat).Inv(recur(n+1, lim))
+
+ return term.Add(term, frac)
+}
+
+// This example demonstrates how to use big.Rat to compute the
+// first 15 terms in the sequence of rational convergents for
+// the constant e (base of natural logarithm).
+func Example_eConvergents() {
+ for i := 1; i <= 15; i++ {
+ r := recur(0, int64(i))
+
+ // Print r both as a fraction and as a floating-point number.
+ // Since big.Rat implements fmt.Formatter, we can use %-13s to
+ // get a left-aligned string representation of the fraction.
+ fmt.Printf("%-13s = %s\n", r, r.FloatString(8))
+ }
+
+ // Output:
+ // 2/1 = 2.00000000
+ // 3/1 = 3.00000000
+ // 8/3 = 2.66666667
+ // 11/4 = 2.75000000
+ // 19/7 = 2.71428571
+ // 87/32 = 2.71875000
+ // 106/39 = 2.71794872
+ // 193/71 = 2.71830986
+ // 1264/465 = 2.71827957
+ // 1457/536 = 2.71828358
+ // 2721/1001 = 2.71828172
+ // 23225/8544 = 2.71828184
+ // 25946/9545 = 2.71828182
+ // 49171/18089 = 2.71828183
+ // 517656/190435 = 2.71828183
+}
diff --git a/src/cmd/compile/internal/big/floatmarsh.go b/src/cmd/compile/internal/big/floatmarsh.go
new file mode 100644
index 0000000000..44987ee03a
--- /dev/null
+++ b/src/cmd/compile/internal/big/floatmarsh.go
@@ -0,0 +1,33 @@
+// Copyright 2015 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 implements encoding/decoding of Floats.
+
+package big
+
+import "fmt"
+
+// MarshalText implements the encoding.TextMarshaler interface.
+// Only the Float value is marshaled (in full precision), other
+// attributes such as precision or accuracy are ignored.
+func (x *Float) MarshalText() (text []byte, err error) {
+ if x == nil {
+ return []byte(""), nil
+ }
+ var buf []byte
+ return x.Append(buf, 'g', -1), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// The result is rounded per the precision and rounding mode of z.
+// If z's precision is 0, it is changed to 64 before rounding takes
+// effect.
+func (z *Float) UnmarshalText(text []byte) error {
+ // TODO(gri): get rid of the []byte/string conversion
+ _, _, err := z.Parse(string(text), 0)
+ if err != nil {
+ err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err)
+ }
+ return err
+}
diff --git a/src/cmd/compile/internal/big/floatmarsh_test.go b/src/cmd/compile/internal/big/floatmarsh_test.go
new file mode 100644
index 0000000000..d7ef2fca68
--- /dev/null
+++ b/src/cmd/compile/internal/big/floatmarsh_test.go
@@ -0,0 +1,54 @@
+// Copyright 2015 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 big
+
+import (
+ "encoding/json"
+ "testing"
+)
+
+var floatVals = []string{
+ "0",
+ "1",
+ "0.1",
+ "2.71828",
+ "1234567890",
+ "3.14e1234",
+ "3.14e-1234",
+ "0.738957395793475734757349579759957975985497e100",
+ "0.73895739579347546656564656573475734957975995797598589749859834759476745986795497e100",
+ "inf",
+ "Inf",
+}
+
+func TestFloatJSONEncoding(t *testing.T) {
+ for _, test := range floatVals {
+ for _, sign := range []string{"", "+", "-"} {
+ for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} {
+ x := sign + test
+ var tx Float
+ _, _, err := tx.SetPrec(prec).Parse(x, 0)
+ if err != nil {
+ t.Errorf("parsing of %s (prec = %d) failed (invalid test case): %v", x, prec, err)
+ continue
+ }
+ b, err := json.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %v (prec = %d) failed: %v", &tx, prec, err)
+ continue
+ }
+ var rx Float
+ rx.SetPrec(prec)
+ if err := json.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %v (prec = %d) failed: %v", &tx, prec, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("JSON encoding of %v (prec = %d) failed: got %v want %v", &tx, prec, &rx, &tx)
+ }
+ }
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/big/intmarsh.go b/src/cmd/compile/internal/big/intmarsh.go
new file mode 100644
index 0000000000..4ff57b6464
--- /dev/null
+++ b/src/cmd/compile/internal/big/intmarsh.go
@@ -0,0 +1,74 @@
+// Copyright 2015 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 implements encoding/decoding of Ints.
+
+package big
+
+import "fmt"
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const intGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (x *Int) GobEncode() ([]byte, error) {
+ if x == nil {
+ return nil, nil
+ }
+ buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
+ i := x.abs.bytes(buf) - 1 // i >= 0
+ b := intGobVersion << 1 // make space for sign bit
+ if x.neg {
+ b |= 1
+ }
+ buf[i] = b
+ return buf[i:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Int) GobDecode(buf []byte) error {
+ if len(buf) == 0 {
+ // Other side sent a nil or default value.
+ *z = Int{}
+ return nil
+ }
+ b := buf[0]
+ if b>>1 != intGobVersion {
+ return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
+ }
+ z.neg = b&1 != 0
+ z.abs = z.abs.setBytes(buf[1:])
+ return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (x *Int) MarshalText() (text []byte, err error) {
+ if x == nil {
+ return []byte(""), nil
+ }
+ return x.abs.itoa(x.neg, 10), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (z *Int) UnmarshalText(text []byte) error {
+ // TODO(gri): get rid of the []byte/string conversion
+ if _, ok := z.SetString(string(text), 0); !ok {
+ return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+ }
+ return nil
+}
+
+// The JSON marshallers are only here for API backward compatibility
+// (programs that explicitly look for these two methods). JSON works
+// fine with the TextMarshaler only.
+
+// MarshalJSON implements the json.Marshaler interface.
+func (x *Int) MarshalJSON() ([]byte, error) {
+ return x.MarshalText()
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (z *Int) UnmarshalJSON(text []byte) error {
+ return z.UnmarshalText(text)
+}
diff --git a/src/cmd/compile/internal/big/intmarsh_test.go b/src/cmd/compile/internal/big/intmarsh_test.go
new file mode 100644
index 0000000000..f82956ceaf
--- /dev/null
+++ b/src/cmd/compile/internal/big/intmarsh_test.go
@@ -0,0 +1,121 @@
+// Copyright 2015 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 big
+
+import (
+ "bytes"
+ "encoding/gob"
+ "encoding/json"
+ "encoding/xml"
+ "testing"
+)
+
+var encodingTests = []string{
+ "0",
+ "1",
+ "2",
+ "10",
+ "1000",
+ "1234567890",
+ "298472983472983471903246121093472394872319615612417471234712061",
+}
+
+func TestIntGobEncoding(t *testing.T) {
+ var medium bytes.Buffer
+ enc := gob.NewEncoder(&medium)
+ dec := gob.NewDecoder(&medium)
+ for _, test := range encodingTests {
+ for _, sign := range []string{"", "+", "-"} {
+ x := sign + test
+ medium.Reset() // empty buffer for each test case (in case of failures)
+ var tx Int
+ tx.SetString(x, 10)
+ if err := enc.Encode(&tx); err != nil {
+ t.Errorf("encoding of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Int
+ if err := dec.Decode(&rx); err != nil {
+ t.Errorf("decoding of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+ }
+}
+
+// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilIntInSlice(t *testing.T) {
+ buf := new(bytes.Buffer)
+ enc := gob.NewEncoder(buf)
+ dec := gob.NewDecoder(buf)
+
+ var in = make([]*Int, 1)
+ err := enc.Encode(&in)
+ if err != nil {
+ t.Errorf("gob encode failed: %q", err)
+ }
+ var out []*Int
+ err = dec.Decode(&out)
+ if err != nil {
+ t.Fatalf("gob decode failed: %q", err)
+ }
+ if len(out) != 1 {
+ t.Fatalf("wrong len; want 1 got %d", len(out))
+ }
+ var zero Int
+ if out[0].Cmp(&zero) != 0 {
+ t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out)
+ }
+}
+
+func TestIntJSONEncoding(t *testing.T) {
+ for _, test := range encodingTests {
+ for _, sign := range []string{"", "+", "-"} {
+ x := sign + test
+ var tx Int
+ tx.SetString(x, 10)
+ b, err := json.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Int
+ if err := json.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+ }
+}
+
+func TestIntXMLEncoding(t *testing.T) {
+ for _, test := range encodingTests {
+ for _, sign := range []string{"", "+", "-"} {
+ x := sign + test
+ var tx Int
+ tx.SetString(x, 0)
+ b, err := xml.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Int
+ if err := xml.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/big/ratconv.go b/src/cmd/compile/internal/big/ratconv.go
index 4566ff4e39..57df124e88 100644
--- a/src/cmd/compile/internal/big/ratconv.go
+++ b/src/cmd/compile/internal/big/ratconv.go
@@ -15,7 +15,7 @@ import (
)
func ratTok(ch rune) bool {
- return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+ return strings.ContainsRune("+-/0123456789.eE", ch)
}
// Scan is a support routine for fmt.Scanner. It accepts the formats
@@ -25,7 +25,7 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
if err != nil {
return err
}
- if strings.IndexRune("efgEFGv", ch) < 0 {
+ if !strings.ContainsRune("efgEFGv", ch) {
return errors.New("Rat.Scan: invalid verb")
}
if _, ok := z.SetString(string(tok)); !ok {
diff --git a/src/cmd/compile/internal/big/ratmarsh.go b/src/cmd/compile/internal/big/ratmarsh.go
new file mode 100644
index 0000000000..b82e8d4ae8
--- /dev/null
+++ b/src/cmd/compile/internal/big/ratmarsh.go
@@ -0,0 +1,73 @@
+// Copyright 2015 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 implements encoding/decoding of Rats.
+
+package big
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+)
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const ratGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (x *Rat) GobEncode() ([]byte, error) {
+ if x == nil {
+ return nil, nil
+ }
+ buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+ i := x.b.abs.bytes(buf)
+ j := x.a.abs.bytes(buf[:i])
+ n := i - j
+ if int(uint32(n)) != n {
+ // this should never happen
+ return nil, errors.New("Rat.GobEncode: numerator too large")
+ }
+ binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
+ j -= 1 + 4
+ b := ratGobVersion << 1 // make space for sign bit
+ if x.a.neg {
+ b |= 1
+ }
+ buf[j] = b
+ return buf[j:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Rat) GobDecode(buf []byte) error {
+ if len(buf) == 0 {
+ // Other side sent a nil or default value.
+ *z = Rat{}
+ return nil
+ }
+ b := buf[0]
+ if b>>1 != ratGobVersion {
+ return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
+ }
+ const j = 1 + 4
+ i := j + binary.BigEndian.Uint32(buf[j-4:j])
+ z.a.neg = b&1 != 0
+ z.a.abs = z.a.abs.setBytes(buf[j:i])
+ z.b.abs = z.b.abs.setBytes(buf[i:])
+ return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (x *Rat) MarshalText() (text []byte, err error) {
+ // TODO(gri): get rid of the []byte/string conversion
+ return []byte(x.RatString()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (z *Rat) UnmarshalText(text []byte) error {
+ // TODO(gri): get rid of the []byte/string conversion
+ if _, ok := z.SetString(string(text)); !ok {
+ return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
+ }
+ return nil
+}
diff --git a/src/cmd/compile/internal/big/ratmarsh_test.go b/src/cmd/compile/internal/big/ratmarsh_test.go
new file mode 100644
index 0000000000..351d109f8d
--- /dev/null
+++ b/src/cmd/compile/internal/big/ratmarsh_test.go
@@ -0,0 +1,125 @@
+// Copyright 2015 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 big
+
+import (
+ "bytes"
+ "encoding/gob"
+ "encoding/json"
+ "encoding/xml"
+ "testing"
+)
+
+func TestRatGobEncoding(t *testing.T) {
+ var medium bytes.Buffer
+ enc := gob.NewEncoder(&medium)
+ dec := gob.NewDecoder(&medium)
+ for _, test := range encodingTests {
+ medium.Reset() // empty buffer for each test case (in case of failures)
+ var tx Rat
+ tx.SetString(test + ".14159265")
+ if err := enc.Encode(&tx); err != nil {
+ t.Errorf("encoding of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Rat
+ if err := dec.Decode(&rx); err != nil {
+ t.Errorf("decoding of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+}
+
+// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilRatInSlice(t *testing.T) {
+ buf := new(bytes.Buffer)
+ enc := gob.NewEncoder(buf)
+ dec := gob.NewDecoder(buf)
+
+ var in = make([]*Rat, 1)
+ err := enc.Encode(&in)
+ if err != nil {
+ t.Errorf("gob encode failed: %q", err)
+ }
+ var out []*Rat
+ err = dec.Decode(&out)
+ if err != nil {
+ t.Fatalf("gob decode failed: %q", err)
+ }
+ if len(out) != 1 {
+ t.Fatalf("wrong len; want 1 got %d", len(out))
+ }
+ var zero Rat
+ if out[0].Cmp(&zero) != 0 {
+ t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out)
+ }
+}
+
+var ratNums = []string{
+ "-141592653589793238462643383279502884197169399375105820974944592307816406286",
+ "-1415926535897932384626433832795028841971",
+ "-141592653589793",
+ "-1",
+ "0",
+ "1",
+ "141592653589793",
+ "1415926535897932384626433832795028841971",
+ "141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+var ratDenoms = []string{
+ "1",
+ "718281828459045",
+ "7182818284590452353602874713526624977572",
+ "718281828459045235360287471352662497757247093699959574966967627724076630353",
+}
+
+func TestRatJSONEncoding(t *testing.T) {
+ for _, num := range ratNums {
+ for _, denom := range ratDenoms {
+ var tx Rat
+ tx.SetString(num + "/" + denom)
+ b, err := json.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Rat
+ if err := json.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+ }
+}
+
+func TestRatXMLEncoding(t *testing.T) {
+ for _, num := range ratNums {
+ for _, denom := range ratDenoms {
+ var tx Rat
+ tx.SetString(num + "/" + denom)
+ b, err := xml.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Rat
+ if err := xml.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index b49f0fb552..ff0465f64c 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -877,7 +877,7 @@ func (p *exporter) byte(b byte) {
// tracef is like fmt.Printf but it rewrites the format string
// to take care of indentation.
func (p *exporter) tracef(format string, args ...interface{}) {
- if strings.IndexAny(format, "<>\n") >= 0 {
+ if strings.ContainsAny(format, "<>\n") {
var buf bytes.Buffer
for i := 0; i < len(format); i++ {
// no need to deal with runes
@@ -1035,6 +1035,9 @@ func predeclared() []*Type {
// package unsafe
Types[TUNSAFEPTR],
+
+ // any type, for builtin export data
+ Types[TANY],
}
}
return predecl
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index 7f2e80b52f..4a6e56fe47 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -3,7 +3,7 @@
package gc
const runtimeimport = "" +
- "package runtime\n" +
+ "package runtime safe\n" +
"func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n" +
"func @\"\".panicindex ()\n" +
"func @\"\".panicslice ()\n" +
@@ -44,7 +44,7 @@ const runtimeimport = "" +
"func @\"\".stringtoslicerune (? *[32]rune, ? string) (? []rune)\n" +
"func @\"\".stringiter (? string, ? int) (? int)\n" +
"func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n" +
- "func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n" +
+ "func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr \"unsafe-uintptr\") (? int)\n" +
"func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n" +
"func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n" +
"func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" +
@@ -66,8 +66,6 @@ const runtimeimport = "" +
"func @\"\".panicdottype (@\"\".have·1 *byte, @\"\".want·2 *byte, @\"\".iface·3 *byte)\n" +
"func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" +
"func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" +
- "func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" +
- "func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" +
"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" +
"func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" +
"func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" +
@@ -91,31 +89,31 @@ const runtimeimport = "" +
"func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
"func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
"func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
- "func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
- "func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
+ "func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" +
"func @\"\".typedmemmove (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" +
"func @\"\".typedslicecopy (@\"\".typ·2 *byte, @\"\".dst·3 any, @\"\".src·4 any) (? int)\n" +
"func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" +
@@ -131,9 +129,9 @@ const runtimeimport = "" +
"func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n" +
"func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".cap·4 int) (@\"\".ary·1 []any)\n" +
"func @\"\".growslice_n (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int) (@\"\".ary·1 []any)\n" +
- "func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n" +
- "func @\"\".memclr (@\"\".ptr·1 *byte, @\"\".length·2 uintptr)\n" +
- "func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n" +
+ "func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr \"unsafe-uintptr\")\n" +
+ "func @\"\".memclr (@\"\".ptr·1 *byte, @\"\".length·2 uintptr \"unsafe-uintptr\")\n" +
+ "func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr \"unsafe-uintptr\") (? bool)\n" +
"func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
"func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
"func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
@@ -148,15 +146,14 @@ const runtimeimport = "" +
"func @\"\".int64tofloat64 (? int64) (? float64)\n" +
"func @\"\".uint64tofloat64 (? uint64) (? float64)\n" +
"func @\"\".complex128div (@\"\".num·2 complex128, @\"\".den·3 complex128) (@\"\".quo·1 complex128)\n" +
- "func @\"\".racefuncenter (? uintptr)\n" +
- "func @\"\".racefuncenterfp (? *int32)\n" +
+ "func @\"\".racefuncenter (? uintptr \"unsafe-uintptr\")\n" +
"func @\"\".racefuncexit ()\n" +
- "func @\"\".raceread (? uintptr)\n" +
- "func @\"\".racewrite (? uintptr)\n" +
- "func @\"\".racereadrange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
- "func @\"\".racewriterange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
- "func @\"\".msanread (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
- "func @\"\".msanwrite (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
+ "func @\"\".raceread (? uintptr \"unsafe-uintptr\")\n" +
+ "func @\"\".racewrite (? uintptr \"unsafe-uintptr\")\n" +
+ "func @\"\".racereadrange (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" +
+ "func @\"\".racewriterange (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" +
+ "func @\"\".msanread (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" +
+ "func @\"\".msanwrite (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" +
"\n" +
"$$\n"
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index 70663eeee4..0fe6242e74 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -8,7 +8,7 @@
// +build ignore
-package PACKAGE
+package runtime
// emitted by compiler, not referred to by go programs
@@ -83,8 +83,6 @@ func panicdottype(have, want, iface *byte)
func ifaceeq(i1 any, i2 any) (ret bool)
func efaceeq(i1 any, i2 any) (ret bool)
-func ifacethash(i1 any) (ret uint32)
-func efacethash(i1 any) (ret uint32)
// *byte is really *runtime.Type
func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any)
@@ -192,7 +190,6 @@ func complex128div(num complex128, den complex128) (quo complex128)
// race detection
func racefuncenter(uintptr)
-func racefuncenterfp(*int32)
func racefuncexit()
func raceread(uintptr)
func racewrite(uintptr)
diff --git a/src/cmd/compile/internal/gc/builtin/unsafe.go b/src/cmd/compile/internal/gc/builtin/unsafe.go
index ce508692eb..a7fc8aa53e 100644
--- a/src/cmd/compile/internal/gc/builtin/unsafe.go
+++ b/src/cmd/compile/internal/gc/builtin/unsafe.go
@@ -8,7 +8,7 @@
// +build ignore
-package PACKAGE
+package unsafe
type Pointer uintptr // not really; filled in by compiler
diff --git a/src/cmd/compile/internal/gc/builtin_test.go b/src/cmd/compile/internal/gc/builtin_test.go
new file mode 100644
index 0000000000..94111e640d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/builtin_test.go
@@ -0,0 +1,31 @@
+// 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.
+
+package gc_test
+
+import (
+ "bytes"
+ "internal/testenv"
+ "io/ioutil"
+ "os/exec"
+ "testing"
+)
+
+func TestBuiltin(t *testing.T) {
+ testenv.MustHaveGoRun(t)
+
+ old, err := ioutil.ReadFile("builtin.go")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ new, err := exec.Command("go", "run", "mkbuiltin.go", "-stdout").Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Equal(old, new) {
+ t.Fatal("builtin.go out of date; run mkbuiltin.go")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index ff983e717e..1a5a433eeb 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -576,6 +576,12 @@ func esc(e *EscState, n *Node, up *Node) {
if n == nil {
return
}
+ if n.Type != nil && n.Type.Etype == TFIELD {
+ // This is the left side of x:y in a struct literal.
+ // x is syntax, not an expression.
+ // See #14405.
+ return
+ }
lno := int(setlineno(n))
@@ -602,9 +608,10 @@ func esc(e *EscState, n *Node, up *Node) {
// Big stuff escapes unconditionally
// "Big" conditions that were scattered around in walk have been gathered here
- if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize ||
- n.Op == ONEW && n.Type.Type.Width >= 1<<16 ||
- n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
+ if n.Esc != EscHeap && n.Type != nil &&
+ (n.Type.Width > MaxStackVarSize ||
+ n.Op == ONEW && n.Type.Type.Width >= 1<<16 ||
+ n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
if Debug['m'] > 1 {
Warnl(int(n.Lineno), "%v is too large for stack", n)
}
@@ -962,7 +969,7 @@ func escassign(e *EscState, dst *Node, src *Node) {
dst = &e.theSink
}
- case ODOT: // treat "dst.x = src" as "dst = src"
+ case ODOT: // treat "dst.x = src" as "dst = src"
escassign(e, dst.Left, src)
return
@@ -1042,7 +1049,6 @@ func escassign(e *EscState, dst *Node, src *Node) {
ODOTMETH,
// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
- ODOTTYPE,
ODOTTYPE2,
OSLICE,
OSLICE3,
@@ -1052,6 +1058,12 @@ func escassign(e *EscState, dst *Node, src *Node) {
// Conversions, field access, slice all preserve the input value.
escassign(e, dst, src.Left)
+ case ODOTTYPE:
+ if src.Type != nil && !haspointers(src.Type) {
+ break
+ }
+ escassign(e, dst, src.Left)
+
case OAPPEND:
// Append returns first argument.
// Subsequent arguments are already leaked because they are operands to append.
@@ -1549,9 +1561,9 @@ func escflows(e *EscState, dst *Node, src *Node) {
// finding an OADDR just means we're following the upstream of a dereference,
// so this address doesn't leak (yet).
// If level == 0, it means the /value/ of this node can reach the root of this flood.
-// so if this node is an OADDR, it's argument should be marked as escaping iff
-// it's currfn/e->loopdepth are different from the flood's root.
-// Once an object has been moved to the heap, all of it's upstream should be considered
+// so if this node is an OADDR, its argument should be marked as escaping iff
+// its currfn/e->loopdepth are different from the flood's root.
+// Once an object has been moved to the heap, all of its upstream should be considered
// escaping to the global scope.
func escflood(e *EscState, dst *Node) {
switch dst.Op {
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index e50cf383d7..1b61d7f228 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -442,7 +442,7 @@ func importsym(s *Sym, op Op) *Sym {
// mark the symbol so it is not reexported
if s.Def == nil {
- if exportname(s.Name) || initname(s.Name) {
+ if Debug['A'] != 0 || exportname(s.Name) || initname(s.Name) {
s.Flags |= SymExport
} else {
s.Flags |= SymPackage // package scope
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index dbd8db16e5..69022814ef 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -749,7 +749,13 @@ func typefmt(t *Type, flag int) string {
if name != "" {
str = name + " " + typ
}
- if flag&obj.FmtShort == 0 && !fmtbody && t.Note != nil {
+
+ // The fmtbody flag is intended to suppress escape analysis annotations
+ // when printing a function type used in a function body.
+ // (The escape analysis tags do not apply to func vars.)
+ // But it must not suppress struct field tags.
+ // See golang.org/issue/13777 and golang.org/issue/14331.
+ if flag&obj.FmtShort == 0 && (!fmtbody || !t.Funarg) && t.Note != nil {
str += " " + strconv.Quote(*t.Note)
}
return str
@@ -1537,7 +1543,7 @@ func nodedump(n *Node, flag int) string {
} else {
fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
}
- if recur && n.Type == nil && n.Name.Param.Ntype != nil {
+ if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
indent(&buf)
fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype)
}
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index 60b93ef805..721ef31247 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -838,7 +838,7 @@ func gen(n *Node) {
Cgen_as_wb(n.Left, n.Right, true)
case OAS2DOTTYPE:
- cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, false)
+ cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, needwritebarrier(n.List.N, n.Rlist.N))
case OCALLMETH:
cgen_callmeth(n, 0)
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index 08442a415b..f721fabfd7 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -28,30 +28,21 @@ const (
const (
// These values are known by runtime.
- // The MEMx and NOEQx values must run in parallel. See algtype.
- AMEM = iota
+ ANOEQ = iota
AMEM0
AMEM8
AMEM16
AMEM32
AMEM64
AMEM128
- ANOEQ
- ANOEQ0
- ANOEQ8
- ANOEQ16
- ANOEQ32
- ANOEQ64
- ANOEQ128
ASTRING
AINTER
ANILINTER
- ASLICE
AFLOAT32
AFLOAT64
ACPLX64
ACPLX128
- AUNK = 100
+ AMEM = 100
)
const (
@@ -329,8 +320,7 @@ const (
const (
// types of channel
- // must match ../../pkg/nreflect/type.go:/Chandir
- Cxxx = 0
+ // must match ../../../../reflect/type.go:/ChanDir
Crecv = 1 << 0
Csend = 1 << 1
Cboth = Crecv | Csend
@@ -385,27 +375,10 @@ type Sig struct {
offset int32
}
-type Io struct {
- infile string
- bin *obj.Biobuf
- cp string // used for content when bin==nil
- last int
- peekc int
- peekc1 int // second peekc for ...
- nlsemi bool
- eofnl bool
- importsafe bool
-}
-
type Dlist struct {
field *Type
}
-type Idir struct {
- link *Idir
- dir string
-}
-
// argument passing to/from
// smagic and umagic
type Magic struct {
@@ -452,10 +425,6 @@ var sizeof_String int // runtime sizeof(String)
var dotlist [10]Dlist // size is max depth of embeddeds
-var curio Io
-
-var pushedio Io
-
var lexlineno int32
var lineno int32
@@ -493,8 +462,6 @@ var debugstr string
var Debug_checknil int
var Debug_typeassert int
-var importmyname *Sym // my name for package
-
var localpkg *Pkg // package being compiled
var importpkg *Pkg // package being imported
@@ -527,8 +494,6 @@ var Tptr EType // either TPTR32 or TPTR64
var myimportpath string
-var idirs *Idir
-
var localimport string
var asmhdr string
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index 64afd67438..a445f712e2 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -7,7 +7,7 @@
// saves a copy of the body. Then inlcalls walks each function body to
// expand calls to inlinable functions.
//
-// The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1,
+// The debug['l'] flag controls the aggressiveness. Note that main() swaps level 0 and 1,
// making 1 the default and -l disable. -ll and more is useful to flush out bugs.
// These additional levels (beyond -l) may be buggy and are not supported.
// 0: disabled
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index e4ce9c796b..51ad6162bf 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:generate go run mkbuiltin.go runtime unsafe
+//go:generate go run mkbuiltin.go
package gc
@@ -257,7 +257,7 @@ func Main() {
msanpkg.Name = "msan"
}
if flag_race != 0 && flag_msan != 0 {
- log.Fatal("can not use both -race and -msan")
+ log.Fatal("cannot use both -race and -msan")
} else if flag_race != 0 || flag_msan != 0 {
instrumenting = true
}
@@ -313,6 +313,8 @@ func Main() {
lexlineno = 1
const BOM = 0xFEFF
+ loadsys()
+
for _, infile = range flag.Args() {
if trace && Debug['x'] != 0 {
fmt.Printf("--- %s ---\n", infile)
@@ -320,23 +322,15 @@ func Main() {
linehistpush(infile)
- curio.infile = infile
- var err error
- curio.bin, err = obj.Bopenr(infile)
+ bin, err := obj.Bopenr(infile)
if err != nil {
fmt.Printf("open %s: %v\n", infile, err)
errorexit()
}
- curio.peekc = 0
- curio.peekc1 = 0
- curio.nlsemi = false
- curio.eofnl = false
- curio.last = 0
-
// Skip initial BOM if present.
- if obj.Bgetrune(curio.bin) != BOM {
- obj.Bungetrune(curio.bin)
+ if obj.Bgetrune(bin) != BOM {
+ obj.Bungetrune(bin)
}
block = 1
@@ -344,15 +338,18 @@ func Main() {
imported_unsafe = false
- parse_file()
+ parse_file(bin)
if nsyntaxerrors != 0 {
errorexit()
}
+ // Instead of converting EOF into '\n' in getc and count it as an extra line
+ // for the line history to work, and which then has to be corrected elsewhere,
+ // just add a line here.
+ lexlineno++
+
linehistpop()
- if curio.bin != nil {
- obj.Bterm(curio.bin)
- }
+ obj.Bterm(bin)
}
testdclstack()
@@ -571,17 +568,12 @@ func skiptopkgdef(b *obj.Biobuf) bool {
return true
}
-func addidir(dir string) {
- if dir == "" {
- return
- }
+var idirs []string
- var pp **Idir
- for pp = &idirs; *pp != nil; pp = &(*pp).link {
+func addidir(dir string) {
+ if dir != "" {
+ idirs = append(idirs, dir)
}
- *pp = new(Idir)
- (*pp).link = nil
- (*pp).dir = dir
}
// is this path a local name? begins with ./ or ../ or /
@@ -620,12 +612,12 @@ func findpkg(name string) (file string, ok bool) {
return "", false
}
- for p := idirs; p != nil; p = p.link {
- file = fmt.Sprintf("%s/%s.a", p.dir, name)
+ for _, dir := range idirs {
+ file = fmt.Sprintf("%s/%s.a", dir, name)
if _, err := os.Stat(file); err == nil {
return file, true
}
- file = fmt.Sprintf("%s/%s.o", p.dir, name)
+ file = fmt.Sprintf("%s/%s.o", dir, name)
if _, err := os.Stat(file); err == nil {
return file, true
}
@@ -658,27 +650,45 @@ func findpkg(name string) (file string, ok bool) {
return "", false
}
-func fakeimport() {
- importpkg = mkpkg("fake")
- cannedimports("fake.o", "$$\n")
+// loadsys loads the definitions for the low-level runtime and unsafe functions,
+// so that the compiler can generate calls to them,
+// but does not make the names "runtime" or "unsafe" visible as packages.
+func loadsys() {
+ if Debug['A'] != 0 {
+ return
+ }
+
+ block = 1
+ iota_ = -1000000
+ incannedimport = 1
+
+ importpkg = Runtimepkg
+ parse_import(obj.Binitr(strings.NewReader(runtimeimport)), nil)
+
+ importpkg = unsafepkg
+ parse_import(obj.Binitr(strings.NewReader(unsafeimport)), nil)
+
+ importpkg = nil
+ incannedimport = 0
}
-// TODO(gri) line argument doesn't appear to be used
-func importfile(f *Val, line int) {
- if _, ok := f.U.(string); !ok {
+func importfile(f *Val, indent []byte) {
+ if importpkg != nil {
+ Fatalf("importpkg not nil")
+ }
+
+ path_, ok := f.U.(string)
+ if !ok {
Yyerror("import statement not a string")
- fakeimport()
return
}
- if len(f.U.(string)) == 0 {
+ if len(path_) == 0 {
Yyerror("import path is empty")
- fakeimport()
return
}
- if isbadimport(f.U.(string)) {
- fakeimport()
+ if isbadimport(path_) {
return
}
@@ -686,18 +696,16 @@ func importfile(f *Val, line int) {
// but we reserve the import path "main" to identify
// the main package, just as we reserve the import
// path "math" to identify the standard math package.
- if f.U.(string) == "main" {
+ if path_ == "main" {
Yyerror("cannot import \"main\"")
errorexit()
}
- if myimportpath != "" && f.U.(string) == myimportpath {
- Yyerror("import %q while compiling that package (import cycle)", f.U.(string))
+ if myimportpath != "" && path_ == myimportpath {
+ Yyerror("import %q while compiling that package (import cycle)", path_)
errorexit()
}
- path_ := f.U.(string)
-
if mapped, ok := importMap[path_]; ok {
path_ = mapped
}
@@ -708,8 +716,7 @@ func importfile(f *Val, line int) {
errorexit()
}
- importpkg = mkpkg(f.U.(string))
- cannedimports("unsafe.o", unsafeimport)
+ importpkg = unsafepkg
imported_unsafe = true
return
}
@@ -717,7 +724,6 @@ func importfile(f *Val, line int) {
if islocalname(path_) {
if path_[0] == '/' {
Yyerror("import path cannot be absolute path")
- fakeimport()
return
}
@@ -725,48 +731,33 @@ func importfile(f *Val, line int) {
if localimport != "" {
prefix = localimport
}
- cleanbuf := prefix
- cleanbuf += "/"
- cleanbuf += path_
- cleanbuf = path.Clean(cleanbuf)
- path_ = cleanbuf
+ path_ = path.Join(prefix, path_)
if isbadimport(path_) {
- fakeimport()
return
}
}
file, found := findpkg(path_)
if !found {
- Yyerror("can't find import: %q", f.U.(string))
+ Yyerror("can't find import: %q", path_)
errorexit()
}
importpkg = mkpkg(path_)
- // If we already saw that package, feed a dummy statement
- // to the lexer to avoid parsing export data twice.
if importpkg.Imported {
- tag := ""
- if importpkg.Safe {
- tag = "safe"
- }
-
- p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag)
- cannedimports(file, p)
return
}
importpkg.Imported = true
- var err error
- var imp *obj.Biobuf
- imp, err = obj.Bopenr(file)
+ imp, err := obj.Bopenr(file)
if err != nil {
- Yyerror("can't open import: %q: %v", f.U.(string), err)
+ Yyerror("can't open import: %q: %v", path_, err)
errorexit()
}
+ defer obj.Bterm(imp)
if strings.HasSuffix(file, ".a") {
if !skiptopkgdef(imp) {
@@ -822,76 +813,21 @@ func importfile(f *Val, line int) {
switch c {
case '\n':
// old export format
- pushedio = curio
-
- curio.bin = imp
- curio.peekc = 0
- curio.peekc1 = 0
- curio.infile = file
- curio.nlsemi = false
- typecheckok = true
-
- push_parser()
+ parse_import(imp, indent)
case 'B':
// new export format
obj.Bgetc(imp) // skip \n after $$B
Import(imp)
- // continue as if the package was imported before (see above)
- tag := ""
- if importpkg.Safe {
- tag = "safe"
- }
- p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag)
- cannedimports(file, p)
- // Reset incannedimport flag (we are not truly in a
- // canned import) - this will cause importpkg.Direct to
- // be set via parser.import_package (was issue #13977).
- //
- // TODO(gri) Remove this global variable and convoluted
- // code in the process of streamlining the import code.
- incannedimport = 0
-
default:
- Yyerror("no import in %q", f.U.(string))
- }
-}
-
-func unimportfile() {
- pop_parser()
-
- if curio.bin != nil {
- obj.Bterm(curio.bin)
- curio.bin = nil
- } else {
- lexlineno-- // re correct sys.6 line number
+ Yyerror("no import in %q", path_)
+ errorexit()
}
- curio = pushedio
-
- pushedio.bin = nil
- incannedimport = 0
- typecheckok = false
-}
-
-func cannedimports(file string, cp string) {
- lexlineno++ // if sys.6 is included on line 1,
-
- pushedio = curio
-
- curio.bin = nil
- curio.peekc = 0
- curio.peekc1 = 0
- curio.infile = file
- curio.cp = cp
- curio.nlsemi = false
- curio.importsafe = false
-
- typecheckok = true
- incannedimport = 1
-
- push_parser()
+ if safemode != 0 && !importpkg.Safe {
+ Yyerror("cannot import unsafe package %q", importpkg.Path)
+ }
}
func isSpace(c int) bool {
@@ -899,7 +835,7 @@ func isSpace(c int) bool {
}
func isAlpha(c int) bool {
- return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+ return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
}
func isDigit(c int) bool {
@@ -933,10 +869,19 @@ func isfrog(c int) bool {
return false
}
-type yySymType struct {
- sym *Sym
- val Val
- op Op
+type lexer struct {
+ // source
+ bin *obj.Biobuf
+ peekc int
+ peekc1 int // second peekc for ...
+
+ nlsemi bool // if set, '\n' and EOF translate to ';'
+
+ // current token
+ tok int32
+ sym_ *Sym // valid if tok == LNAME
+ val Val // valid if tok == LLITERAL
+ op Op // valid if tok == LASOP
}
const (
@@ -987,7 +932,7 @@ const (
LRSH
)
-func _yylex(yylval *yySymType) int32 {
+func (l *lexer) next() {
var c1 int
var op Op
var escflag int
@@ -998,27 +943,31 @@ func _yylex(yylval *yySymType) int32 {
prevlineno = lineno
+ nlsemi := l.nlsemi
+ l.nlsemi = false
+
l0:
- c := getc()
- if isSpace(c) {
- if c == '\n' && curio.nlsemi {
- ungetc(c)
+ // skip white space
+ c := l.getc()
+ for isSpace(c) {
+ if c == '\n' && nlsemi {
+ l.ungetc(c)
if Debug['x'] != 0 {
fmt.Printf("lex: implicit semi\n")
}
- return ';'
+ l.tok = ';'
+ return
}
-
- goto l0
+ c = l.getc()
}
- lineno = lexlineno // start of token
+ // start of token
+ lineno = lexlineno
if c >= utf8.RuneSelf {
// all multibyte runes are alpha
cp = &lexbuf
cp.Reset()
-
goto talph
}
@@ -1034,7 +983,7 @@ l0:
if c != '0' {
for {
cp.WriteByte(byte(c))
- c = getc()
+ c = l.getc()
if isDigit(c) {
continue
}
@@ -1052,11 +1001,11 @@ l0:
}
cp.WriteByte(byte(c))
- c = getc()
+ c = l.getc()
if c == 'x' || c == 'X' {
for {
cp.WriteByte(byte(c))
- c = getc()
+ c = l.getc()
if isDigit(c) {
continue
}
@@ -1089,7 +1038,7 @@ l0:
c1 = 1 // not octal
}
cp.WriteByte(byte(c))
- c = getc()
+ c = l.getc()
}
if c == '.' {
@@ -1110,8 +1059,18 @@ l0:
switch c {
case EOF:
lineno = prevlineno
- ungetc(EOF)
- return -1
+ l.ungetc(EOF)
+ // Treat EOF as "end of line" for the purposes
+ // of inserting a semicolon.
+ if nlsemi {
+ if Debug['x'] != 0 {
+ fmt.Printf("lex: implicit semi\n")
+ }
+ l.tok = ';'
+ return
+ }
+ l.tok = -1
+ return
case '_':
cp = &lexbuf
@@ -1119,7 +1078,7 @@ l0:
goto talph
case '.':
- c1 = getc()
+ c1 = l.getc()
if isDigit(c1) {
cp = &lexbuf
cp.Reset()
@@ -1129,13 +1088,13 @@ l0:
}
if c1 == '.' {
- c1 = getc()
+ c1 = l.getc()
if c1 == '.' {
c = LDDD
goto lx
}
- ungetc(c1)
+ l.ungetc(c1)
c1 = '.'
}
@@ -1148,7 +1107,7 @@ l0:
cp.Reset()
for {
- if escchar('"', &escflag, &v) {
+ if l.escchar('"', &escflag, &v) {
break
}
if v < utf8.RuneSelf || escflag != 0 {
@@ -1169,7 +1128,7 @@ l0:
cp.Reset()
for {
- c = int(getr())
+ c = int(l.getr())
if c == '\r' {
continue
}
@@ -1188,40 +1147,42 @@ l0:
// '.'
case '\'':
- if escchar('\'', &escflag, &v) {
+ if l.escchar('\'', &escflag, &v) {
Yyerror("empty character literal or unescaped ' in character literal")
v = '\''
}
- if !escchar('\'', &escflag, &v) {
+ if !l.escchar('\'', &escflag, &v) {
Yyerror("missing '")
- ungetc(int(v))
+ l.ungetc(int(v))
}
x := new(Mpint)
- yylval.val.U = x
+ l.val.U = x
Mpmovecfix(x, v)
x.Rune = true
if Debug['x'] != 0 {
fmt.Printf("lex: codepoint literal\n")
}
litbuf = "string literal"
- return LLITERAL
+ l.nlsemi = true
+ l.tok = LLITERAL
+ return
case '/':
- c1 = getc()
+ c1 = l.getc()
if c1 == '*' {
nl := false
for {
- c = int(getr())
+ c = int(l.getr())
if c == '\n' {
nl = true
}
for c == '*' {
- c = int(getr())
+ c = int(l.getr())
if c == '/' {
if nl {
- ungetc('\n')
+ l.ungetc('\n')
}
goto l0
}
@@ -1239,14 +1200,14 @@ l0:
}
if c1 == '/' {
- c = getlinepragma()
+ c = l.getlinepragma()
for {
if c == '\n' || c == EOF {
- ungetc(c)
+ l.ungetc(c)
goto l0
}
- c = int(getr())
+ c = int(l.getr())
}
}
@@ -1256,29 +1217,30 @@ l0:
}
case ':':
- c1 = getc()
+ c1 = l.getc()
if c1 == '=' {
c = int(LCOLAS)
goto lx
}
case '*':
- c1 = getc()
+ c1 = l.getc()
if c1 == '=' {
op = OMUL
goto asop
}
case '%':
- c1 = getc()
+ c1 = l.getc()
if c1 == '=' {
op = OMOD
goto asop
}
case '+':
- c1 = getc()
+ c1 = l.getc()
if c1 == '+' {
+ l.nlsemi = true
c = int(LINC)
goto lx
}
@@ -1289,8 +1251,9 @@ l0:
}
case '-':
- c1 = getc()
+ c1 = l.getc()
if c1 == '-' {
+ l.nlsemi = true
c = int(LDEC)
goto lx
}
@@ -1301,10 +1264,10 @@ l0:
}
case '>':
- c1 = getc()
+ c1 = l.getc()
if c1 == '>' {
c = int(LRSH)
- c1 = getc()
+ c1 = l.getc()
if c1 == '=' {
op = ORSH
goto asop
@@ -1321,10 +1284,10 @@ l0:
c = int(LGT)
case '<':
- c1 = getc()
+ c1 = l.getc()
if c1 == '<' {
c = int(LLSH)
- c1 = getc()
+ c1 = l.getc()
if c1 == '=' {
op = OLSH
goto asop
@@ -1346,21 +1309,21 @@ l0:
c = int(LLT)
case '=':
- c1 = getc()
+ c1 = l.getc()
if c1 == '=' {
c = int(LEQ)
goto lx
}
case '!':
- c1 = getc()
+ c1 = l.getc()
if c1 == '=' {
c = int(LNE)
goto lx
}
case '&':
- c1 = getc()
+ c1 = l.getc()
if c1 == '&' {
c = int(LANDAND)
goto lx
@@ -1368,7 +1331,7 @@ l0:
if c1 == '^' {
c = int(LANDNOT)
- c1 = getc()
+ c1 = l.getc()
if c1 == '=' {
op = OANDNOT
goto asop
@@ -1383,7 +1346,7 @@ l0:
}
case '|':
- c1 = getc()
+ c1 = l.getc()
if c1 == '|' {
c = int(LOROR)
goto lx
@@ -1395,17 +1358,21 @@ l0:
}
case '^':
- c1 = getc()
+ c1 = l.getc()
if c1 == '=' {
op = OXOR
goto asop
}
+ case ')', ']', '}':
+ l.nlsemi = true
+ goto lx
+
default:
goto lx
}
- ungetc(c1)
+ l.ungetc(c1)
lx:
if Debug['x'] != 0 {
@@ -1425,22 +1392,24 @@ lx:
goto l0
}
- return int32(c)
+ l.tok = int32(c)
+ return
asop:
- yylval.op = op
+ l.op = op
if Debug['x'] != 0 {
fmt.Printf("lex: TOKEN ASOP %s=\n", goopnames[op])
}
- return LASOP
+ l.tok = LASOP
+ return
// cp is set to lexbuf and some
// prefix has been stored
talph:
for {
if c >= utf8.RuneSelf {
- ungetc(c)
- r := rune(getr())
+ l.ungetc(c)
+ r := rune(l.getr())
// 0xb7 · is used for internal names
if !unicode.IsLetter(r) && !unicode.IsDigit(r) && (importpkg == nil || r != 0xb7) {
@@ -1455,11 +1424,11 @@ talph:
} else {
cp.WriteByte(byte(c))
}
- c = getc()
+ c = l.getc()
}
cp = nil
- ungetc(c)
+ l.ungetc(c)
s = LookupBytes(lexbuf.Bytes())
if s.Lexical == LIGNORE {
@@ -1469,31 +1438,38 @@ talph:
if Debug['x'] != 0 {
fmt.Printf("lex: %s %s\n", s, lexname(int(s.Lexical)))
}
- yylval.sym = s
- return int32(s.Lexical)
+ l.sym_ = s
+ switch s.Lexical {
+ case LNAME, LRETURN, LBREAK, LCONTINUE, LFALL:
+ l.nlsemi = true
+ }
+ l.tok = int32(s.Lexical)
+ return
ncu:
cp = nil
- ungetc(c)
+ l.ungetc(c)
str = lexbuf.String()
- yylval.val.U = new(Mpint)
- mpatofix(yylval.val.U.(*Mpint), str)
- if yylval.val.U.(*Mpint).Ovf {
+ l.val.U = new(Mpint)
+ mpatofix(l.val.U.(*Mpint), str)
+ if l.val.U.(*Mpint).Ovf {
Yyerror("overflow in constant")
- Mpmovecfix(yylval.val.U.(*Mpint), 0)
+ Mpmovecfix(l.val.U.(*Mpint), 0)
}
if Debug['x'] != 0 {
fmt.Printf("lex: integer literal\n")
}
litbuf = "literal " + str
- return LLITERAL
+ l.nlsemi = true
+ l.tok = LLITERAL
+ return
casedot:
for {
cp.WriteByte(byte(c))
- c = getc()
+ c = l.getc()
if !isDigit(c) {
break
}
@@ -1513,10 +1489,10 @@ caseep:
Yyerror("malformed floating point constant")
}
cp.WriteByte(byte(c))
- c = getc()
+ c = l.getc()
if c == '+' || c == '-' {
cp.WriteByte(byte(c))
- c = getc()
+ c = l.getc()
}
if !isDigit(c) {
@@ -1524,7 +1500,7 @@ caseep:
}
for isDigit(c) {
cp.WriteByte(byte(c))
- c = getc()
+ c = l.getc()
}
if c == 'i' {
@@ -1537,56 +1513,60 @@ casei:
cp = nil
str = lexbuf.String()
- yylval.val.U = new(Mpcplx)
- Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0)
- mpatoflt(&yylval.val.U.(*Mpcplx).Imag, str)
- if yylval.val.U.(*Mpcplx).Imag.Val.IsInf() {
+ l.val.U = new(Mpcplx)
+ Mpmovecflt(&l.val.U.(*Mpcplx).Real, 0.0)
+ mpatoflt(&l.val.U.(*Mpcplx).Imag, str)
+ if l.val.U.(*Mpcplx).Imag.Val.IsInf() {
Yyerror("overflow in imaginary constant")
- Mpmovecflt(&yylval.val.U.(*Mpcplx).Imag, 0.0)
+ Mpmovecflt(&l.val.U.(*Mpcplx).Imag, 0.0)
}
if Debug['x'] != 0 {
fmt.Printf("lex: imaginary literal\n")
}
litbuf = "literal " + str
- return LLITERAL
+ l.nlsemi = true
+ l.tok = LLITERAL
+ return
caseout:
cp = nil
- ungetc(c)
+ l.ungetc(c)
str = lexbuf.String()
- yylval.val.U = newMpflt()
- mpatoflt(yylval.val.U.(*Mpflt), str)
- if yylval.val.U.(*Mpflt).Val.IsInf() {
+ l.val.U = newMpflt()
+ mpatoflt(l.val.U.(*Mpflt), str)
+ if l.val.U.(*Mpflt).Val.IsInf() {
Yyerror("overflow in float constant")
- Mpmovecflt(yylval.val.U.(*Mpflt), 0.0)
+ Mpmovecflt(l.val.U.(*Mpflt), 0.0)
}
if Debug['x'] != 0 {
fmt.Printf("lex: floating literal\n")
}
litbuf = "literal " + str
- return LLITERAL
+ l.nlsemi = true
+ l.tok = LLITERAL
+ return
strlit:
- yylval.val.U = internString(cp.Bytes())
+ l.val.U = internString(cp.Bytes())
if Debug['x'] != 0 {
fmt.Printf("lex: string literal\n")
}
litbuf = "string literal"
- return LLITERAL
+ l.nlsemi = true
+ l.tok = LLITERAL
}
var internedStrings = map[string]string{}
func internString(b []byte) string {
s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
- if ok {
- return s
+ if !ok {
+ s = string(b)
+ internedStrings[s] = s
}
- s = string(b)
- internedStrings[s] = s
return s
}
@@ -1603,16 +1583,16 @@ func more(pp *string) bool {
// //line parse.y:15
// as a discontinuity in sequential line numbers.
// the next line of input comes from parse.y:15
-func getlinepragma() int {
+func (l *lexer) getlinepragma() int {
var cmd, verb, name string
- c := int(getr())
+ c := int(l.getr())
if c == 'g' {
cp := &lexbuf
cp.Reset()
cp.WriteByte('g') // already read
for {
- c = int(getr())
+ c = int(l.getr())
if c == EOF || c >= utf8.RuneSelf {
return c
}
@@ -1704,7 +1684,7 @@ func getlinepragma() int {
return c
}
for i := 1; i < 5; i++ {
- c = int(getr())
+ c = int(l.getr())
if c != int("line "[i]) {
return c
}
@@ -1714,7 +1694,7 @@ func getlinepragma() int {
cp.Reset()
linep := 0
for {
- c = int(getr())
+ c = int(l.getr())
if c == EOF {
return c
}
@@ -1895,113 +1875,57 @@ func pragcgo(text string) {
}
}
-func yylex(yylval *yySymType) int32 {
- lx := _yylex(yylval)
-
- if curio.nlsemi && lx == EOF {
- // Treat EOF as "end of line" for the purposes
- // of inserting a semicolon.
- lx = ';'
- }
-
- switch lx {
- case LNAME,
- LLITERAL,
- LBREAK,
- LCONTINUE,
- LFALL,
- LRETURN,
- LINC,
- LDEC,
- ')',
- '}',
- ']':
- curio.nlsemi = true
-
- default:
- curio.nlsemi = false
- }
-
- return lx
-}
-
-func getc() int {
- c := curio.peekc
+func (l *lexer) getc() int {
+ c := l.peekc
if c != 0 {
- curio.peekc = curio.peekc1
- curio.peekc1 = 0
+ l.peekc = l.peekc1
+ l.peekc1 = 0
goto check
}
- if curio.bin == nil {
- if len(curio.cp) == 0 {
- c = 0
- } else {
- c = int(curio.cp[0])
- curio.cp = curio.cp[1:]
+loop:
+ c = obj.Bgetc(l.bin)
+ // recognize BOM (U+FEFF): UTF-8 encoding is 0xef 0xbb 0xbf
+ if c == 0xef {
+ buf, err := l.bin.Peek(2)
+ if err != nil {
+ yyerrorl(int(lexlineno), "illegal UTF-8 sequence ef % x followed by read error (%v)", string(buf), err)
+ errorexit()
}
- } else {
- loop:
- c = obj.Bgetc(curio.bin)
- // recognize BOM (U+FEFF): UTF-8 encoding is 0xef 0xbb 0xbf
- if c == 0xef {
- buf, err := curio.bin.Peek(2)
- if err != nil {
- yyerrorl(int(lexlineno), "illegal UTF-8 sequence ef % x followed by read error (%v)", string(buf), err)
- errorexit()
- }
- if buf[0] == 0xbb && buf[1] == 0xbf {
- yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
+ if buf[0] == 0xbb && buf[1] == 0xbf {
+ yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
- // consume BOM bytes
- obj.Bgetc(curio.bin)
- obj.Bgetc(curio.bin)
- goto loop
- }
+ // consume BOM bytes
+ obj.Bgetc(l.bin)
+ obj.Bgetc(l.bin)
+ goto loop
}
}
check:
- switch c {
- case 0:
- if curio.bin != nil {
- Yyerror("illegal NUL byte")
- break
- }
- fallthrough
-
- // insert \n at EOF
- case EOF:
- if curio.eofnl || curio.last == '\n' {
- return EOF
- }
- curio.eofnl = true
- c = '\n'
- fallthrough
-
- case '\n':
- if pushedio.bin == nil {
- lexlineno++
- }
+ if c == 0 {
+ Yyerror("illegal NUL byte")
+ return 0
+ }
+ if c == '\n' && importpkg == nil {
+ lexlineno++
}
-
- curio.last = c
return c
}
-func ungetc(c int) {
- curio.peekc1 = curio.peekc
- curio.peekc = c
- if c == '\n' && pushedio.bin == nil {
+func (l *lexer) ungetc(c int) {
+ l.peekc1 = l.peekc
+ l.peekc = c
+ if c == '\n' && importpkg == nil {
lexlineno--
}
}
-func getr() int32 {
+func (l *lexer) getr() int32 {
var buf [utf8.UTFMax]byte
for i := 0; ; i++ {
- c := getc()
+ c := l.getc()
if i == 0 && c < utf8.RuneSelf {
return int32(c)
}
@@ -2020,10 +1944,10 @@ func getr() int32 {
}
}
-func escchar(e int, escflg *int, val *int64) bool {
+func (l *lexer) escchar(e int, escflg *int, val *int64) bool {
*escflg = 0
- c := int(getr())
+ c := int(l.getr())
switch c {
case EOF:
Yyerror("eof in string")
@@ -2045,7 +1969,7 @@ func escchar(e int, escflg *int, val *int64) bool {
}
u := 0
- c = int(getr())
+ c = int(l.getr())
var i int
switch c {
case 'x':
@@ -2072,23 +1996,23 @@ func escchar(e int, escflg *int, val *int64) bool {
'6',
'7':
*escflg = 1 // it's a byte
- l := int64(c) - '0'
+ x := int64(c) - '0'
for i := 2; i > 0; i-- {
- c = getc()
+ c = l.getc()
if c >= '0' && c <= '7' {
- l = l*8 + int64(c) - '0'
+ x = x*8 + int64(c) - '0'
continue
}
Yyerror("non-octal character in escape sequence: %c", c)
- ungetc(c)
+ l.ungetc(c)
}
- if l > 255 {
- Yyerror("octal escape value > 255: %d", l)
+ if x > 255 {
+ Yyerror("octal escape value > 255: %d", x)
}
- *val = l
+ *val = x
return false
case 'a':
@@ -2118,35 +2042,35 @@ func escchar(e int, escflg *int, val *int64) bool {
return false
hex:
- l := int64(0)
+ x := int64(0)
for ; i > 0; i-- {
- c = getc()
+ c = l.getc()
if c >= '0' && c <= '9' {
- l = l*16 + int64(c) - '0'
+ x = x*16 + int64(c) - '0'
continue
}
if c >= 'a' && c <= 'f' {
- l = l*16 + int64(c) - 'a' + 10
+ x = x*16 + int64(c) - 'a' + 10
continue
}
if c >= 'A' && c <= 'F' {
- l = l*16 + int64(c) - 'A' + 10
+ x = x*16 + int64(c) - 'A' + 10
continue
}
Yyerror("non-hex character in escape sequence: %c", c)
- ungetc(c)
+ l.ungetc(c)
break
}
- if u != 0 && (l > utf8.MaxRune || (0xd800 <= l && l < 0xe000)) {
- Yyerror("invalid Unicode code point in escape sequence: %#x", l)
- l = utf8.RuneError
+ if u != 0 && (x > utf8.MaxRune || (0xd800 <= x && x < 0xe000)) {
+ Yyerror("invalid Unicode code point in escape sequence: %#x", x)
+ x = utf8.RuneError
}
- *val = l
+ *val = x
return false
}
diff --git a/src/cmd/compile/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go
index b1e4458692..13cde5e8aa 100644
--- a/src/cmd/compile/internal/gc/mkbuiltin.go
+++ b/src/cmd/compile/internal/gc/mkbuiltin.go
@@ -4,95 +4,90 @@
// +build ignore
-// Generate builtin.go from builtin/runtime.go and builtin/unsafe.go
-// (passed as arguments on the command line by a go:generate comment).
+// Generate builtin.go from builtin/runtime.go and builtin/unsafe.go.
// Run this after changing builtin/runtime.go and builtin/unsafe.go
// or after changing the export metadata format in the compiler.
// Either way, you need to have a working compiler binary first.
package main
import (
- "bufio"
+ "bytes"
+ "flag"
"fmt"
"io"
+ "io/ioutil"
"log"
"os"
"os/exec"
- "strings"
)
+var stdout = flag.Bool("stdout", false, "write to stdout instead of builtin.go")
+
func main() {
- f, err := os.Create("builtin.go")
+ flag.Parse()
+
+ var b bytes.Buffer
+ fmt.Fprintln(&b, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT")
+ fmt.Fprintln(&b, "")
+ fmt.Fprintln(&b, "package gc")
+
+ mkbuiltin(&b, "runtime")
+ mkbuiltin(&b, "unsafe")
+
+ var err error
+ if *stdout {
+ _, err = os.Stdout.Write(b.Bytes())
+ } else {
+ err = ioutil.WriteFile("builtin.go", b.Bytes(), 0666)
+ }
if err != nil {
log.Fatal(err)
}
- defer f.Close()
- w := bufio.NewWriter(f)
-
- fmt.Fprintln(w, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT")
- fmt.Fprintln(w, "")
- fmt.Fprintln(w, "package gc")
-
- for _, name := range os.Args[1:] {
- mkbuiltin(w, name)
- }
-
- if err := w.Flush(); err != nil {
- log.Fatal(err)
- }
}
-// Compile .go file, import data from .6 file, and write Go string version.
+// Compile .go file, import data from .o file, and write Go string version.
func mkbuiltin(w io.Writer, name string) {
- if err := exec.Command("go", "tool", "compile", "-A", "builtin/"+name+".go").Run(); err != nil {
+ args := []string{"tool", "compile", "-A"}
+ if name == "runtime" {
+ args = append(args, "-u")
+ }
+ args = append(args, "builtin/"+name+".go")
+
+ if err := exec.Command("go", args...).Run(); err != nil {
log.Fatal(err)
}
obj := name + ".o"
defer os.Remove(obj)
- r, err := os.Open(obj)
+ b, err := ioutil.ReadFile(obj)
if err != nil {
log.Fatal(err)
}
- defer r.Close()
- scanner := bufio.NewScanner(r)
// Look for $$ that introduces imports.
- for scanner.Scan() {
- if strings.Contains(scanner.Text(), "$$") {
- goto Begin
- }
+ i := bytes.Index(b, []byte("\n$$\n"))
+ if i < 0 {
+ log.Fatal("did not find beginning of imports")
}
- log.Fatal("did not find beginning of imports")
+ i += 4
-Begin:
- initfunc := fmt.Sprintf("init_%s_function", name)
-
- fmt.Fprintf(w, "\nconst %simport = \"\" +\n", name)
-
- // sys.go claims to be in package PACKAGE to avoid
- // conflicts during "go tool compile sys.go". Rename PACKAGE to $2.
- replacer := strings.NewReplacer("PACKAGE", name)
-
- // Process imports, stopping at $$ that closes them.
- for scanner.Scan() {
- p := scanner.Text()
- if strings.Contains(p, "$$") {
- goto End
- }
+ // Look for $$ that closes imports.
+ j := bytes.Index(b[i:], []byte("\n$$\n"))
+ if j < 0 {
+ log.Fatal("did not find end of imports")
+ }
+ j += i + 4
+ // Process and reformat imports.
+ fmt.Fprintf(w, "\nconst %simport = \"\"", name)
+ for _, p := range bytes.SplitAfter(b[i:j], []byte("\n")) {
// Chop leading white space.
- p = strings.TrimLeft(p, " \t")
-
- // Cut out decl of init_$1_function - it doesn't exist.
- if strings.Contains(p, initfunc) {
+ p = bytes.TrimLeft(p, " \t")
+ if len(p) == 0 {
continue
}
- fmt.Fprintf(w, "\t%q +\n", replacer.Replace(p)+"\n")
+ fmt.Fprintf(w, " +\n\t%q", p)
}
- log.Fatal("did not find end of imports")
-
-End:
- fmt.Fprintf(w, "\t\"$$\\n\"\n")
+ fmt.Fprintf(w, "\n")
}
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index 66549be5c4..0a96da61fa 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -233,8 +233,7 @@ func stringsym(s string) (hdr, data *Sym) {
off = dsname(symdata, off, s[n:n+m])
}
- off = duint8(symdata, off, 0) // terminating NUL for runtime
- off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment
+ off = duint8(symdata, off, 0) // terminating NUL for runtime
ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
return symhdr, symdata
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 05cd53af41..12405d5f38 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -42,8 +42,7 @@ import (
// Order holds state during the ordering process.
type Order struct {
out *NodeList // list of generated statements
- temp *NodeList // head of stack of temporary variables
- free *NodeList // free list of NodeList* structs (for use in temp)
+ temp []*Node // stack of temporary variables
}
// Order rewrites fn->nbody to apply the ordering constraints
@@ -68,14 +67,7 @@ func ordertemp(t *Type, order *Order, clear bool) *Node {
order.out = list(order.out, a)
}
- l := order.free
- if l == nil {
- l = new(NodeList)
- }
- order.free = l.Next
- l.Next = order.temp
- l.N = var_
- order.temp = l
+ order.temp = append(order.temp, var_)
return var_
}
@@ -215,42 +207,35 @@ func orderaddrtemp(np **Node, order *Order) {
*np = ordercopyexpr(n, n.Type, order, 0)
}
+type ordermarker int
+
// Marktemp returns the top of the temporary variable stack.
-func marktemp(order *Order) *NodeList {
- return order.temp
+func marktemp(order *Order) ordermarker {
+ return ordermarker(len(order.temp))
}
// Poptemp pops temporaries off the stack until reaching the mark,
// which must have been returned by marktemp.
-func poptemp(mark *NodeList, order *Order) {
- var l *NodeList
-
- for {
- l = order.temp
- if l == mark {
- break
- }
- order.temp = l.Next
- l.Next = order.free
- order.free = l
- }
+func poptemp(mark ordermarker, order *Order) {
+ order.temp = order.temp[:mark]
}
// Cleantempnopop emits to *out VARKILL instructions for each temporary
// above the mark on the temporary stack, but it does not pop them
// from the stack.
-func cleantempnopop(mark *NodeList, order *Order, out **NodeList) {
+func cleantempnopop(mark ordermarker, order *Order, out **NodeList) {
var kill *Node
- for l := order.temp; l != mark; l = l.Next {
- if l.N.Name.Keepalive {
- l.N.Name.Keepalive = false
- l.N.Addrtaken = true // ensure SSA keeps the l.N variable
- kill = Nod(OVARLIVE, l.N, nil)
+ for i := len(order.temp) - 1; i >= int(mark); i-- {
+ n := order.temp[i]
+ if n.Name.Keepalive {
+ n.Name.Keepalive = false
+ n.Addrtaken = true // ensure SSA keeps the n variable
+ kill = Nod(OVARLIVE, n, nil)
typecheck(&kill, Etop)
*out = list(*out, kill)
}
- kill = Nod(OVARKILL, l.N, nil)
+ kill = Nod(OVARKILL, n, nil)
typecheck(&kill, Etop)
*out = list(*out, kill)
}
@@ -258,7 +243,7 @@ func cleantempnopop(mark *NodeList, order *Order, out **NodeList) {
// Cleantemp emits VARKILL instructions for each temporary above the
// mark on the temporary stack and removes them from the stack.
-func cleantemp(top *NodeList, order *Order) {
+func cleantemp(top ordermarker, order *Order) {
cleantempnopop(top, order, &order.out)
poptemp(top, order)
}
@@ -290,13 +275,7 @@ func orderexprinplace(np **Node, outer *Order) {
// insert new temporaries from order
// at head of outer list.
- lp := &order.temp
-
- for *lp != nil {
- lp = &(*lp).Next
- }
- *lp = outer.temp
- outer.temp = order.temp
+ outer.temp = append(outer.temp, order.temp...)
*np = n
}
diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go
index 054cf73656..fbc5a5e1eb 100644
--- a/src/cmd/compile/internal/gc/parser.go
+++ b/src/cmd/compile/internal/gc/parser.go
@@ -5,7 +5,7 @@
package gc
// The recursive-descent parser is built around a slighty modified grammar
-// of Go to accomodate for the constraints imposed by strict one token look-
+// of Go to accommodate for the constraints imposed by strict one token look-
// ahead, and for better error handling. Subsequent checks of the constructed
// syntax tree restrict the language accepted by the compiler to proper Go.
//
@@ -13,6 +13,7 @@ package gc
// to handle optional commas and semicolons before a closing ) or } .
import (
+ "cmd/internal/obj"
"fmt"
"strconv"
"strings"
@@ -20,81 +21,31 @@ import (
const trace = false // if set, parse tracing can be enabled with -x
-// TODO(gri) Once we handle imports w/o redirecting the underlying
-// source of the lexer we can get rid of these. They are here for
-// compatibility with the existing yacc-based parser setup (issue 13242).
-var thenewparser parser // the parser in use
-var savedstate []parser // saved parser state, used during import
-
-func push_parser() {
- // Indentation (for tracing) must be preserved across parsers
- // since we are changing the lexer source (and parser state)
- // under foot, in the middle of productions. This won't be
- // needed anymore once we fix issue 13242, but neither will
- // be the push/pop_parser functionality.
- // (Instead we could just use a global variable indent, but
- // but eventually indent should be parser-specific anyway.)
- indent := thenewparser.indent
- savedstate = append(savedstate, thenewparser)
- thenewparser = parser{indent: indent} // preserve indentation
- thenewparser.next()
+// parse_import parses the export data of a package that is imported.
+func parse_import(bin *obj.Biobuf, indent []byte) {
+ newparser(bin, indent).import_package()
}
-func pop_parser() {
- indent := thenewparser.indent
- n := len(savedstate) - 1
- thenewparser = savedstate[n]
- thenewparser.indent = indent // preserve indentation
- savedstate = savedstate[:n]
-}
-
-// parse_file sets up a new parser and parses a single Go source file.
-func parse_file() {
- thenewparser = parser{}
- thenewparser.loadsys()
- thenewparser.next()
- thenewparser.file()
-}
-
-// loadsys loads the definitions for the low-level runtime functions,
-// so that the compiler can generate calls to them,
-// but does not make the name "runtime" visible as a package.
-func (p *parser) loadsys() {
- if trace && Debug['x'] != 0 {
- defer p.trace("loadsys")()
- }
-
- importpkg = Runtimepkg
-
- if Debug['A'] != 0 {
- cannedimports("runtime.Builtin", "package runtime\n\n$$\n\n")
- } else {
- cannedimports("runtime.Builtin", runtimeimport)
- }
- curio.importsafe = true
-
- p.import_package()
- p.import_there()
-
- importpkg = nil
+// parse_file parses a single Go source file.
+func parse_file(bin *obj.Biobuf) {
+ newparser(bin, nil).file()
}
type parser struct {
- tok int32 // next token (one-token look-ahead)
- op Op // valid if tok == LASOP
- val Val // valid if tok == LLITERAL
- sym_ *Sym // valid if tok == LNAME
- fnest int // function nesting level (for error handling)
- xnest int // expression nesting level (for complit ambiguity resolution)
- yy yySymType // for temporary use by next
- indent []byte // tracing support
+ lexer
+ fnest int // function nesting level (for error handling)
+ xnest int // expression nesting level (for complit ambiguity resolution)
+ indent []byte // tracing support
}
-func (p *parser) next() {
- p.tok = yylex(&p.yy)
- p.op = p.yy.op
- p.val = p.yy.val
- p.sym_ = p.yy.sym
+// newparser returns a new parser ready to parse from src.
+// indent is the initial indentation for tracing output.
+func newparser(src *obj.Biobuf, indent []byte) *parser {
+ var p parser
+ p.bin = src
+ p.indent = indent
+ p.next()
+ return &p
}
func (p *parser) got(tok int32) bool {
@@ -347,108 +298,87 @@ func (p *parser) import_() {
p.want(LIMPORT)
if p.got('(') {
for p.tok != EOF && p.tok != ')' {
- p.import_stmt()
+ p.importdcl()
if !p.osemi(')') {
break
}
}
p.want(')')
} else {
- p.import_stmt()
- }
-}
-
-func (p *parser) import_stmt() {
- if trace && Debug['x'] != 0 {
- defer p.trace("import_stmt")()
- }
-
- line := int32(p.import_here())
- if p.tok == LPACKAGE {
- p.import_package()
- p.import_there()
-
- ipkg := importpkg
- my := importmyname
- importpkg = nil
- importmyname = nil
-
- if my == nil {
- my = Lookup(ipkg.Name)
- }
-
- pack := Nod(OPACK, nil, nil)
- pack.Sym = my
- pack.Name.Pkg = ipkg
- pack.Lineno = line
-
- if strings.HasPrefix(my.Name, ".") {
- importdot(ipkg, pack)
- return
- }
- if my.Name == "init" {
- lineno = line
- Yyerror("cannot import package as init - init must be a func")
- return
- }
- if my.Name == "_" {
- return
- }
- if my.Def != nil {
- lineno = line
- redeclare(my, "as imported package name")
- }
- my.Def = pack
- my.Lastlineno = line
- my.Block = 1 // at top level
-
- return
- }
-
- p.import_there()
- // When an invalid import path is passed to importfile,
- // it calls Yyerror and then sets up a fake import with
- // no package statement. This allows us to test more
- // than one invalid import statement in a single file.
- if nerrors == 0 {
- Fatalf("phase error in import")
+ p.importdcl()
}
}
// ImportSpec = [ "." | PackageName ] ImportPath .
// ImportPath = string_lit .
-//
-// import_here switches the underlying lexed source to the export data
-// of the imported package.
-func (p *parser) import_here() int {
+func (p *parser) importdcl() {
if trace && Debug['x'] != 0 {
- defer p.trace("import_here")()
+ defer p.trace("importdcl")()
}
- importmyname = nil
+ var my *Sym
switch p.tok {
case LNAME, '@', '?':
// import with given name
- importmyname = p.sym()
+ my = p.sym()
case '.':
// import into my name space
- importmyname = Lookup(".")
+ my = Lookup(".")
p.next()
}
- var path Val
- if p.tok == LLITERAL {
- path = p.val
- p.next()
- } else {
+ if p.tok != LLITERAL {
p.syntax_error("missing import path; require quoted string")
p.advance(';', ')')
+ return
}
- line := parserline()
- importfile(&path, line)
- return line
+ line := int32(parserline())
+ path := p.val
+ p.next()
+
+ importfile(&path, p.indent)
+ if importpkg == nil {
+ if nerrors == 0 {
+ Fatalf("phase error in import")
+ }
+ return
+ }
+
+ ipkg := importpkg
+ importpkg = nil
+
+ ipkg.Direct = true
+
+ if my == nil {
+ my = Lookup(ipkg.Name)
+ }
+
+ pack := Nod(OPACK, nil, nil)
+ pack.Sym = my
+ pack.Name.Pkg = ipkg
+ pack.Lineno = line
+
+ if strings.HasPrefix(my.Name, ".") {
+ importdot(ipkg, pack)
+ return
+ }
+ if my.Name == "init" {
+ lineno = line
+ Yyerror("cannot import package as init - init must be a func")
+ return
+ }
+ if my.Name == "_" {
+ return
+ }
+ if my.Def != nil {
+ lineno = line
+ redeclare(my, "as imported package name")
+ }
+ my.Def = pack
+ my.Lastlineno = line
+ my.Block = 1 // at top level
}
// import_package parses the header of an imported package as exported
@@ -467,9 +397,10 @@ func (p *parser) import_package() {
p.import_error()
}
+ importsafe := false
if p.tok == LNAME {
if p.sym_.Name == "safe" {
- curio.importsafe = true
+ importsafe = true
}
p.next()
}
@@ -481,23 +412,9 @@ func (p *parser) import_package() {
} else if importpkg.Name != name {
Yyerror("conflicting names %s and %s for package %q", importpkg.Name, name, importpkg.Path)
}
- if incannedimport == 0 {
- importpkg.Direct = true
- }
- importpkg.Safe = curio.importsafe
-
- if safemode != 0 && !curio.importsafe {
- Yyerror("cannot import unsafe package %q", importpkg.Path)
- }
-}
-
-// import_there parses the imported package definitions and then switches
-// the underlying lexed source back to the importing package.
-func (p *parser) import_there() {
- if trace && Debug['x'] != 0 {
- defer p.trace("import_there")()
- }
+ importpkg.Safe = importsafe
+ typecheckok = true
defercheckwidth()
p.hidden_import_list()
@@ -508,7 +425,7 @@ func (p *parser) import_there() {
}
resumecheckwidth()
- unimportfile()
+ typecheckok = false
}
// Declaration = ConstDecl | TypeDecl | VarDecl .
@@ -1136,65 +1053,16 @@ func (p *parser) if_stmt() *Node {
stmt.Nbody = p.loop_body("if clause")
- l := p.elseif_list_else() // does markdcl
-
- n := stmt
- popdcl()
- for nn := l; nn != nil; nn = nn.Next {
- if nn.N.Op == OIF {
- popdcl()
- }
- n.Rlist = list1(nn.N)
- n = nn.N
- }
-
- return stmt
-}
-
-func (p *parser) elseif() *NodeList {
- if trace && Debug['x'] != 0 {
- defer p.trace("elseif")()
- }
-
- // LELSE LIF already consumed
- markdcl() // matching popdcl in if_stmt
-
- stmt := p.if_header()
- if stmt.Left == nil {
- Yyerror("missing condition in if statement")
- }
-
- stmt.Nbody = p.loop_body("if clause")
-
- return list1(stmt)
-}
-
-func (p *parser) elseif_list_else() (l *NodeList) {
- if trace && Debug['x'] != 0 {
- defer p.trace("elseif_list_else")()
- }
-
- for p.got(LELSE) {
- if p.got(LIF) {
- l = concat(l, p.elseif())
+ if p.got(LELSE) {
+ if p.tok == LIF {
+ stmt.Rlist = list1(p.if_stmt())
} else {
- l = concat(l, p.else_())
- break
+ stmt.Rlist = list1(p.compound_stmt(true))
}
}
- return l
-}
-
-func (p *parser) else_() *NodeList {
- if trace && Debug['x'] != 0 {
- defer p.trace("else")()
- }
-
- l := &NodeList{N: p.compound_stmt(true)}
- l.End = l
- return l
-
+ popdcl()
+ return stmt
}
// switch_stmt parses both expression and type switch statements.
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index f90f89a805..987da2bfdd 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -187,21 +187,12 @@ func emitptrargsmap() {
// the top of the stack and increasing in size.
// Non-autos sort on offset.
func cmpstackvarlt(a, b *Node) bool {
- if a.Class != b.Class {
- if a.Class == PAUTO {
- return false
- }
- return true
+ if (a.Class == PAUTO) != (b.Class == PAUTO) {
+ return b.Class == PAUTO
}
if a.Class != PAUTO {
- if a.Xoffset < b.Xoffset {
- return true
- }
- if a.Xoffset > b.Xoffset {
- return false
- }
- return false
+ return a.Xoffset < b.Xoffset
}
if a.Used != b.Used {
@@ -220,11 +211,8 @@ func cmpstackvarlt(a, b *Node) bool {
return ap
}
- if a.Type.Width < b.Type.Width {
- return false
- }
- if a.Type.Width > b.Type.Width {
- return true
+ if a.Type.Width != b.Type.Width {
+ return a.Type.Width > b.Type.Width
}
return a.Sym.Name < b.Sym.Name
diff --git a/src/cmd/compile/internal/gc/pgen_test.go b/src/cmd/compile/internal/gc/pgen_test.go
index ebc9101135..909b8a9507 100644
--- a/src/cmd/compile/internal/gc/pgen_test.go
+++ b/src/cmd/compile/internal/gc/pgen_test.go
@@ -40,6 +40,16 @@ func TestCmpstackvar(t *testing.T) {
Node{Class: PFUNC, Xoffset: 10},
false,
},
+ {
+ Node{Class: PPARAM, Xoffset: 10},
+ Node{Class: PPARAMOUT, Xoffset: 20},
+ true,
+ },
+ {
+ Node{Class: PPARAMOUT, Xoffset: 10},
+ Node{Class: PPARAM, Xoffset: 20},
+ true,
+ },
{
Node{Class: PAUTO, Used: true},
Node{Class: PAUTO, Used: false},
@@ -101,6 +111,10 @@ func TestCmpstackvar(t *testing.T) {
if got != d.lt {
t.Errorf("want %#v < %#v", d.a, d.b)
}
+ // If we expect a < b to be true, check that b < a is false.
+ if d.lt && cmpstackvarlt(&d.b, &d.a) {
+ t.Errorf("unexpected %#v < %#v", d.b, d.a)
+ }
}
}
diff --git a/src/cmd/compile/internal/gc/popt.go b/src/cmd/compile/internal/gc/popt.go
index 4d71ab643d..b708222845 100644
--- a/src/cmd/compile/internal/gc/popt.go
+++ b/src/cmd/compile/internal/gc/popt.go
@@ -241,6 +241,19 @@ var flowmark int
// will not have flow graphs and consequently will not be optimized.
const MaxFlowProg = 50000
+var ffcache []Flow // reusable []Flow, to reduce allocation
+
+func growffcache(n int) {
+ if n > cap(ffcache) {
+ n = (n * 5) / 4
+ if n > MaxFlowProg {
+ n = MaxFlowProg
+ }
+ ffcache = make([]Flow, n)
+ }
+ ffcache = ffcache[:n]
+}
+
func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
// Count and mark instructions to annotate.
nf := 0
@@ -268,7 +281,9 @@ func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
// Allocate annotations and assign to instructions.
graph := new(Graph)
- ff := make([]Flow, nf)
+
+ growffcache(nf)
+ ff := ffcache
start := &ff[0]
id := 0
var last *Flow
@@ -331,6 +346,10 @@ func Flowend(graph *Graph) {
f.Prog.Info.Flags = 0 // drop cached proginfo
f.Prog.Opt = nil
}
+ clear := ffcache[:graph.Num]
+ for i := range clear {
+ clear[i] = Flow{}
+ }
}
// find looping structure
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index f6dd75ec4a..37c3bc9e6d 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -45,7 +45,7 @@ func siglt(a, b *Sig) bool {
// the given map type. This type is not visible to users -
// we include only enough information to generate a correct GC
// program for it.
-// Make sure this stays in sync with ../../runtime/hashmap.go!
+// Make sure this stays in sync with ../../../../runtime/hashmap.go!
const (
BUCKETSIZE = 8
MAXKEYSIZE = 128
@@ -149,7 +149,7 @@ func mapbucket(t *Type) *Type {
}
// Builds a type representing a Hmap structure for the given map type.
-// Make sure this stays in sync with ../../runtime/hashmap.go!
+// Make sure this stays in sync with ../../../../runtime/hashmap.go!
func hmap(t *Type) *Type {
if t.Hmap != nil {
return t.Hmap
@@ -186,7 +186,7 @@ func hiter(t *Type) *Type {
}
// build a struct:
- // hash_iter {
+ // hiter {
// key *Key
// val *Value
// t *MapType
@@ -200,7 +200,7 @@ func hiter(t *Type) *Type {
// bucket uintptr
// checkBucket uintptr
// }
- // must match ../../runtime/hashmap.go:hash_iter.
+ // must match ../../../../runtime/hashmap.go:hiter.
var field [12]*Type
field[0] = makefield("key", Ptrto(t.Down))
@@ -473,7 +473,7 @@ func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
}
// uncommonType
-// ../../runtime/type.go:/uncommonType
+// ../../../../runtime/type.go:/uncommonType
func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
m := methods(t)
if t.Sym == nil && len(m) == 0 {
@@ -513,7 +513,7 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
// methods
for _, a := range m {
// method
- // ../../runtime/type.go:/method
+ // ../../../../runtime/type.go:/method
ot = dgostringptr(s, ot, a.name)
ot = dgopkgpath(s, ot, a.pkg)
@@ -710,21 +710,21 @@ func dcommontype(s *Sym, ot int, t *Type) int {
gcsym, useGCProg, ptrdata := dgcsym(t)
- // ../../pkg/reflect/type.go:/^type.commonType
+ // ../../../../reflect/type.go:/^type.rtype
// actual type structure
- // type commonType struct {
+ // type rtype struct {
// size uintptr
- // ptrsize uintptr
+ // ptrdata uintptr
// hash uint32
// _ uint8
// align uint8
// fieldAlign uint8
// kind uint8
- // alg unsafe.Pointer
- // gcdata unsafe.Pointer
+ // alg *typeAlg
+ // gcdata *byte
// string *string
- // *extraType
- // ptrToThis *Type
+ // *uncommonType
+ // ptrToThis *rtype
// }
ot = duintptr(s, ot, uint64(t.Width))
ot = duintptr(s, ot, uint64(ptrdata))
@@ -1010,7 +1010,7 @@ ok:
case TARRAY:
if t.Bound >= 0 {
- // ../../runtime/type.go:/ArrayType
+ // ../../../../runtime/type.go:/arrayType
s1 := dtypesym(t.Type)
t2 := typ(TARRAY)
@@ -1023,7 +1023,7 @@ ok:
ot = dsymptr(s, ot, s2, 0)
ot = duintptr(s, ot, uint64(t.Bound))
} else {
- // ../../runtime/type.go:/SliceType
+ // ../../../../runtime/type.go:/sliceType
s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t)
@@ -1031,7 +1031,7 @@ ok:
ot = dsymptr(s, ot, s1, 0)
}
- // ../../runtime/type.go:/ChanType
+ // ../../../../runtime/type.go:/chanType
case TCHAN:
s1 := dtypesym(t.Type)
@@ -1090,7 +1090,7 @@ ok:
dtypesym(a.type_)
}
- // ../../../runtime/type.go:/InterfaceType
+ // ../../../../runtime/type.go:/interfaceType
ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr
@@ -1098,14 +1098,14 @@ ok:
ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint)
for _, a := range m {
- // ../../../runtime/type.go:/imethod
+ // ../../../../runtime/type.go:/imethod
ot = dgostringptr(s, ot, a.name)
ot = dgopkgpath(s, ot, a.pkg)
ot = dsymptr(s, ot, dtypesym(a.type_), 0)
}
- // ../../../runtime/type.go:/MapType
+ // ../../../../runtime/type.go:/mapType
case TMAP:
s1 := dtypesym(t.Down)
@@ -1140,20 +1140,20 @@ ok:
case TPTR32, TPTR64:
if t.Type.Etype == TANY {
- // ../../runtime/type.go:/UnsafePointerType
+ // ../../../../runtime/type.go:/UnsafePointerType
ot = dcommontype(s, ot, t)
break
}
- // ../../runtime/type.go:/PtrType
+ // ../../../../runtime/type.go:/ptrType
s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr
ot = dsymptr(s, ot, s1, 0)
- // ../../runtime/type.go:/StructType
+ // ../../../../runtime/type.go:/structType
// for security, only the exported fields.
case TSTRUCT:
n := 0
@@ -1169,7 +1169,7 @@ ok:
ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint)
for t1 := t.Type; t1 != nil; t1 = t1.Down {
- // ../../runtime/type.go:/structField
+ // ../../../../runtime/type.go:/structField
if t1.Sym != nil && t1.Embedded == 0 {
ot = dgostringptr(s, ot, t1.Sym.Name)
if exportname(t1.Sym.Name) {
@@ -1349,7 +1349,7 @@ func dalgsym(t *Type) *Sym {
ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
}
- // ../../runtime/alg.go:/typeAlg
+ // ../../../../runtime/alg.go:/typeAlg
ot := 0
ot = dsymptr(s, ot, hashfunc, 0)
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 19fda373bf..13d8663706 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -561,7 +561,7 @@ func (s *state) stmt(n *Node) {
case OAS2DOTTYPE:
res, resok := s.dottype(n.Rlist.N, true)
- s.assign(n.List.N, res, false, false, n.Lineno)
+ s.assign(n.List.N, res, needwritebarrier(n.List.N, n.Rlist.N), false, n.Lineno)
s.assign(n.List.Next.N, resok, false, false, n.Lineno)
return
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 0d25ddf2af..b6a26489e6 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -116,12 +116,6 @@ func Yyerror(format string, args ...interface{}) {
if strings.HasPrefix(msg, "syntax error") {
nsyntaxerrors++
- // An unexpected EOF caused a syntax error. Use the previous
- // line number since getc generated a fake newline character.
- if curio.eofnl {
- lexlineno = prevlineno
- }
-
// only one syntax error per line
if int32(yyerror_lastsyntax) == lexlineno {
return
@@ -465,6 +459,15 @@ func algtype1(t *Type, bad **Type) int {
return a
}
+ switch t.Bound {
+ case 0:
+ // We checked above that the element type is comparable.
+ return AMEM
+ case 1:
+ // Single-element array is same as its lone element.
+ return a
+ }
+
return -1 // needs special compare
case TSTRUCT:
@@ -500,28 +503,20 @@ func algtype1(t *Type, bad **Type) int {
func algtype(t *Type) int {
a := algtype1(t, nil)
- if a == AMEM || a == ANOEQ {
- if Isslice(t) {
- return ASLICE
- }
+ if a == AMEM {
switch t.Width {
case 0:
- return a + AMEM0 - AMEM
-
+ return AMEM0
case 1:
- return a + AMEM8 - AMEM
-
+ return AMEM8
case 2:
- return a + AMEM16 - AMEM
-
+ return AMEM16
case 4:
- return a + AMEM32 - AMEM
-
+ return AMEM32
case 8:
- return a + AMEM64 - AMEM
-
+ return AMEM64
case 16:
- return a + AMEM128 - AMEM
+ return AMEM128
}
}
@@ -2640,17 +2635,13 @@ func genhash(sym *Sym, t *Type) {
safemode = old_safemode
}
-// Return node for
-// if p.field != q.field { return false }
+// eqfield returns the node
+// p.field == q.field
func eqfield(p *Node, q *Node, field *Node) *Node {
nx := Nod(OXDOT, p, field)
ny := Nod(OXDOT, q, field)
- nif := Nod(OIF, nil, nil)
- nif.Left = Nod(ONE, nx, ny)
- r := Nod(ORETURN, nil, nil)
- r.List = list(r.List, Nodbool(false))
- nif.Nbody = list(nif.Nbody, r)
- return nif
+ ne := Nod(OEQ, nx, ny)
+ return ne
}
func eqmemfunc(size int64, type_ *Type, needsize *int) *Node {
@@ -2671,8 +2662,8 @@ func eqmemfunc(size int64, type_ *Type, needsize *int) *Node {
return fn
}
-// Return node for
-// if !memequal(&p.field, &q.field [, size]) { return false }
+// eqmem returns the node
+// memequal(&p.field, &q.field [, size])
func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
var needsize int
@@ -2690,15 +2681,11 @@ func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
call.List = list(call.List, Nodintconst(size))
}
- nif := Nod(OIF, nil, nil)
- nif.Left = Nod(ONOT, call, nil)
- r := Nod(ORETURN, nil, nil)
- r.List = list(r.List, Nodbool(false))
- nif.Nbody = list(nif.Nbody, r)
- return nif
+ return call
}
-// Generate a helper function to check equality of two values of type t.
+// geneq generates a helper function to
+// check equality of two values of type t.
func geneq(sym *Sym, t *Type) {
if Debug['r'] != 0 {
fmt.Printf("geneq %v %v\n", sym, t)
@@ -2768,12 +2755,18 @@ func geneq(sym *Sym, t *Type) {
nrange.Nbody = list(nrange.Nbody, nif)
fn.Nbody = list(fn.Nbody, nrange)
- // Walk the struct using memequal for runs of AMEM
+ // return true
+ ret := Nod(ORETURN, nil, nil)
+ ret.List = list(ret.List, Nodbool(true))
+ fn.Nbody = list(fn.Nbody, ret)
+
+ // Walk the struct using memequal for runs of AMEM
// and calling specific equality tests for the others.
// Skip blank-named fields.
case TSTRUCT:
var first *Type
+ var conjuncts []*Node
offend := int64(0)
var size int64
for t1 := t.Type; ; t1 = t1.Down {
@@ -2796,17 +2789,17 @@ func geneq(sym *Sym, t *Type) {
// cross-package unexported fields.
if first != nil {
if first.Down == t1 {
- fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym)))
+ conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
} else if first.Down.Down == t1 {
- fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym)))
+ conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
first = first.Down
if !isblanksym(first.Sym) {
- fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym)))
+ conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
}
} else {
// More than two fields: use memequal.
size = offend - first.Width // first->width is offset
- fn.Nbody = list(fn.Nbody, eqmem(np, nq, newname(first.Sym), size))
+ conjuncts = append(conjuncts, eqmem(np, nq, newname(first.Sym), size))
}
first = nil
@@ -2820,16 +2813,27 @@ func geneq(sym *Sym, t *Type) {
}
// Check this field, which is not just memory.
- fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(t1.Sym)))
+ conjuncts = append(conjuncts, eqfield(np, nq, newname(t1.Sym)))
}
+
+ var and *Node
+ switch len(conjuncts) {
+ case 0:
+ and = Nodbool(true)
+ case 1:
+ and = conjuncts[0]
+ default:
+ and = Nod(OANDAND, conjuncts[0], conjuncts[1])
+ for _, conjunct := range conjuncts[2:] {
+ and = Nod(OANDAND, and, conjunct)
+ }
+ }
+
+ ret := Nod(ORETURN, nil, nil)
+ ret.List = list(ret.List, and)
+ fn.Nbody = list(fn.Nbody, ret)
}
- // return true
- r := Nod(ORETURN, nil, nil)
-
- r.List = list(r.List, Nodbool(true))
- fn.Nbody = list(fn.Nbody, r)
-
if Debug['r'] != 0 {
dumplist("geneq body", fn.Nbody)
}
@@ -2847,10 +2851,18 @@ func geneq(sym *Sym, t *Type) {
// for a struct containing a reflect.Value, which itself has
// an unexported field of type unsafe.Pointer.
old_safemode := safemode
-
safemode = 0
+
+ // Disable checknils while compiling this code.
+ // We are comparing a struct or an array,
+ // neither of which can be nil, and our comparisons
+ // are shallow.
+ Disable_checknil++
+
funccompile(fn)
+
safemode = old_safemode
+ Disable_checknil--
}
func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase int) *Type {
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index f0433f3df7..661b3ee5a9 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -549,20 +549,6 @@ func (s *typeSwitch) walk(sw *Node) {
// set up labels and jumps
casebody(sw, s.facename)
- // calculate type hash
- t := cond.Right.Type
- if isnilinter(t) {
- a = syslook("efacethash", 1)
- } else {
- a = syslook("ifacethash", 1)
- }
- substArgTypes(a, t)
- a = Nod(OCALL, a, nil)
- a.List = list1(s.facename)
- a = Nod(OAS, s.hashname, a)
- typecheck(&a, Etop)
- cas = list(cas, a)
-
cc := caseClauses(sw, switchKindType)
sw.List = nil
var def *Node
@@ -572,22 +558,66 @@ func (s *typeSwitch) walk(sw *Node) {
} else {
def = Nod(OBREAK, nil, nil)
}
+ var typenil *Node
+ if len(cc) > 0 && cc[0].typ == caseKindTypeNil {
+ typenil = cc[0].node.Right
+ cc = cc[1:]
+ }
+
+ // For empty interfaces, do:
+ // if e._type == nil {
+ // do nil case if it exists, otherwise default
+ // }
+ // h := e._type.hash
+ // Use a similar strategy for non-empty interfaces.
+
+ // Get interface descriptor word.
+ typ := Nod(OITAB, s.facename, nil)
+
+ // Check for nil first.
+ i := Nod(OIF, nil, nil)
+ i.Left = Nod(OEQ, typ, nodnil())
+ if typenil != nil {
+ // Do explicit nil case right here.
+ i.Nbody = list1(typenil)
+ } else {
+ // Jump to default case.
+ lbl := newCaseLabel()
+ i.Nbody = list1(Nod(OGOTO, lbl, nil))
+ // Wrap default case with label.
+ blk := Nod(OBLOCK, nil, nil)
+ blk.List = list(list1(Nod(OLABEL, lbl, nil)), def)
+ def = blk
+ }
+ typecheck(&i.Left, Erv)
+ cas = list(cas, i)
+
+ if !isnilinter(cond.Right.Type) {
+ // Load type from itab.
+ typ = Nod(ODOTPTR, typ, nil)
+ typ.Type = Ptrto(Types[TUINT8])
+ typ.Typecheck = 1
+ typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
+ typ.Bounded = true // guaranteed not to fault
+ }
+ // Load hash from type.
+ h := Nod(ODOTPTR, typ, nil)
+ h.Type = Types[TUINT32]
+ h.Typecheck = 1
+ h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
+ h.Bounded = true // guaranteed not to fault
+ a = Nod(OAS, s.hashname, h)
+ typecheck(&a, Etop)
+ cas = list(cas, a)
// insert type equality check into each case block
for _, c := range cc {
n := c.node
switch c.typ {
- case caseKindTypeNil:
- var v Val
- v.U = new(NilVal)
- a = Nod(OIF, nil, nil)
- a.Left = Nod(OEQ, s.facename, nodlit(v))
- typecheck(&a.Left, Erv)
- a.Nbody = list1(n.Right) // if i==nil { goto l }
- n.Right = a
-
case caseKindTypeVar, caseKindTypeConst:
n.Right = s.typeone(n)
+ default:
+ Fatalf("typeSwitch with bad kind: %d", c.typ)
}
}
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index f74bb334aa..8fd6f85575 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -936,7 +936,6 @@ OpSwitch:
n.Type = n.Right.Type
n.Right = nil
if n.Type == nil {
- n.Type = nil
return
}
}
diff --git a/src/cmd/compile/internal/gc/util.go b/src/cmd/compile/internal/gc/util.go
index 7ed3b39b83..18e990a91a 100644
--- a/src/cmd/compile/internal/gc/util.go
+++ b/src/cmd/compile/internal/gc/util.go
@@ -1,3 +1,7 @@
+// Copyright 2015 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 gc
import (
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index dddcb689ed..45b85b9b02 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -3193,6 +3193,21 @@ func walkcompare(np **Node, init **NodeList) {
return
}
+ if t.Etype == TARRAY {
+ // Zero- or single-element array, of any type.
+ switch t.Bound {
+ case 0:
+ finishcompare(np, n, Nodbool(n.Op == OEQ), init)
+ return
+ case 1:
+ l0 := Nod(OINDEX, l, Nodintconst(0))
+ r0 := Nod(OINDEX, r, Nodintconst(0))
+ a := Nod(n.Op, l0, r0)
+ finishcompare(np, n, a, init)
+ return
+ }
+ }
+
if t.Etype == TSTRUCT && countfield(t) <= 4 {
// Struct of four or fewer fields.
// Inline comparisons.
diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go
index 31ec434546..c5d1682651 100644
--- a/src/cmd/cover/cover.go
+++ b/src/cmd/cover/cover.go
@@ -181,6 +181,10 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
}
n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace.
case *ast.IfStmt:
+ if n.Init != nil {
+ ast.Walk(f, n.Init)
+ }
+ ast.Walk(f, n.Cond)
ast.Walk(f, n.Body)
if n.Else == nil {
return nil
@@ -219,11 +223,21 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
case *ast.SwitchStmt:
// Don't annotate an empty switch - creates a syntax error.
if n.Body == nil || len(n.Body.List) == 0 {
+ if n.Init != nil {
+ ast.Walk(f, n.Init)
+ }
+ if n.Tag != nil {
+ ast.Walk(f, n.Tag)
+ }
return nil
}
case *ast.TypeSwitchStmt:
// Don't annotate an empty type switch - creates a syntax error.
if n.Body == nil || len(n.Body.List) == 0 {
+ if n.Init != nil {
+ ast.Walk(f, n.Init)
+ }
+ ast.Walk(f, n.Assign)
return nil
}
}
diff --git a/src/cmd/cover/testdata/test.go b/src/cmd/cover/testdata/test.go
index 9013950a2b..c4c0e15b0b 100644
--- a/src/cmd/cover/testdata/test.go
+++ b/src/cmd/cover/testdata/test.go
@@ -24,6 +24,7 @@ func testAll() {
testSelect2()
testPanic()
testEmptySwitches()
+ testFunctionLiteral()
}
// The indexes of the counters in testPanic are known to main.go
@@ -216,3 +217,32 @@ func testEmptySwitches() {
<-c
check(LINE, 1)
}
+
+func testFunctionLiteral() {
+ a := func(f func()) error {
+ f()
+ f()
+ return nil
+ }
+
+ b := func(f func()) bool {
+ f()
+ f()
+ return true
+ }
+
+ check(LINE, 1)
+ a(func() {
+ check(LINE, 2)
+ })
+
+ if err := a(func() {
+ check(LINE, 2)
+ }); err != nil {
+ }
+
+ switch b(func() {
+ check(LINE, 2)
+ }) {
+ }
+}
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 39a88ccab5..7f2f75341f 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -754,7 +754,7 @@ func matchtag(tag string) bool {
}
return !matchtag(tag[1:])
}
- return tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
+ return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
}
// shouldbuild reports whether we should build this file.
@@ -798,10 +798,15 @@ func shouldbuild(file, dir string) bool {
if p == "" {
continue
}
- if strings.Contains(p, "package documentation") {
+ code := p
+ i := strings.Index(code, "//")
+ if i > 0 {
+ code = strings.TrimSpace(code[:i])
+ }
+ if code == "package documentation" {
return false
}
- if strings.Contains(p, "package main") && dir != "cmd/go" && dir != "cmd/cgo" {
+ if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
return false
}
if !strings.HasPrefix(p, "//") {
@@ -810,11 +815,11 @@ func shouldbuild(file, dir string) bool {
if !strings.Contains(p, "+build") {
continue
}
- fields := splitfields(p)
- if len(fields) < 2 || fields[1] != "+build" {
+ fields := splitfields(p[2:])
+ if len(fields) < 1 || fields[0] != "+build" {
continue
}
- for _, p := range fields[2:] {
+ for _, p := range fields[1:] {
if matchfield(p) {
goto fieldmatch
}
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 156b868109..36c829d1b9 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -947,6 +947,11 @@ func (t *tester) raceTest(dt *distTest) error {
t.addCmd(dt, "src", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec")
t.addCmd(dt, "src", "go", "test", "-race", "-run=Output", "runtime/race")
t.addCmd(dt, "src", "go", "test", "-race", "-short", "-run=TestParse|TestEcho", "flag", "os/exec")
+ // We don't want the following line, because it
+ // slows down all.bash (by 10 seconds on my laptop).
+ // The race builder should catch any error here, but doesn't.
+ // TODO(iant): Figure out how to catch this.
+ // t.addCmd(dt, "src", "go", "test", "-race", "-run=TestParallelTest", "cmd/go")
if t.cgoEnabled {
env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-race", "-short")
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index ed1d0e7c79..20b61702b4 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -221,6 +221,7 @@ var tests = []test{
`type ExportedType struct`, // Type definition.
`Comment before exported field.*\n.*ExportedField +int` +
`.*Comment on line with exported field.`,
+ `ExportedEmbeddedType.*Comment on line with exported embedded field.`,
`Has unexported fields`,
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
@@ -228,6 +229,7 @@ var tests = []test{
},
[]string{
`unexportedField`, // No unexported field.
+ `int.*embedded`, // No unexported embedded field.
`Comment about exported method.`, // No comment about exported method.
`unexportedMethod`, // No unexported method.
`unexportedTypedConstant`, // No unexported constant.
@@ -241,7 +243,11 @@ var tests = []test{
`Comment about exported type`, // Include comment.
`type ExportedType struct`, // Type definition.
`Comment before exported field.*\n.*ExportedField +int`,
- `unexportedField int.*Comment on line with unexported field.`,
+ `unexportedField.*int.*Comment on line with unexported field.`,
+ `ExportedEmbeddedType.*Comment on line with exported embedded field.`,
+ `\*ExportedEmbeddedType.*Comment on line with exported embedded \*field.`,
+ `unexportedType.*Comment on line with unexported embedded field.`,
+ `\*unexportedType.*Comment on line with unexported embedded \*field.`,
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
`unexportedTypedConstant`,
},
@@ -448,7 +454,6 @@ var trimTests = []trimTest{
{"", "", "", true},
{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
{"/usr/gopher/bar", "/usr/gopher", "bar", true},
- {"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
{"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
{"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
}
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index 0b07f7cc7c..a14ccdb59b 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -487,9 +487,27 @@ func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList {
trimmed := false
list := make([]*ast.Field, 0, len(fields.List))
for _, field := range fields.List {
+ names := field.Names
+ if len(names) == 0 {
+ // Embedded type. Use the name of the type. It must be of type ident or *ident.
+ // Nothing else is allowed.
+ switch ident := field.Type.(type) {
+ case *ast.Ident:
+ names = []*ast.Ident{ident}
+ case *ast.StarExpr:
+ // Must have the form *identifier.
+ if ident, ok := ident.X.(*ast.Ident); ok {
+ names = []*ast.Ident{ident}
+ }
+ }
+ if names == nil {
+ // Can only happen if AST is incorrect. Safe to continue with a nil list.
+ log.Print("invalid program: unexpected type for embedded field")
+ }
+ }
// Trims if any is unexported. Good enough in practice.
ok := true
- for _, name := range field.Names {
+ for _, name := range names {
if !isExported(name.Name) {
trimmed = true
ok = false
diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go
index 3e7acee50b..1a673f78d4 100644
--- a/src/cmd/doc/testdata/pkg.go
+++ b/src/cmd/doc/testdata/pkg.go
@@ -60,8 +60,12 @@ func internalFunc(a int) bool
// Comment about exported type.
type ExportedType struct {
// Comment before exported field.
- ExportedField int // Comment on line with exported field.
- unexportedField int // Comment on line with unexported field.
+ ExportedField int // Comment on line with exported field.
+ unexportedField int // Comment on line with unexported field.
+ ExportedEmbeddedType // Comment on line with exported embedded field.
+ *ExportedEmbeddedType // Comment on line with exported embedded *field.
+ unexportedType // Comment on line with unexported embedded field.
+ *unexportedType // Comment on line with unexported embedded *field.
}
// Comment about exported method.
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index c81bd40864..bbad8d40e9 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -1022,12 +1022,6 @@ Vendor directories do not affect the placement of new repositories
being checked out for the first time by 'go get': those are always
placed in the main GOPATH, never in a vendor subtree.
-In Go 1.5, as an experiment, setting the environment variable
-GO15VENDOREXPERIMENT=1 enabled these features.
-As of Go 1.6 they are on by default. To turn them off, set
-GO15VENDOREXPERIMENT=0. In Go 1.7, the environment
-variable will stop having any effect.
-
See https://golang.org/s/go15vendor for details.
@@ -1094,8 +1088,6 @@ Special-purpose environment variables:
installed in a location other than where it is built.
File names in stack traces are rewritten from GOROOT to
GOROOT_FINAL.
- GO15VENDOREXPERIMENT
- Set to 0 to disable vendoring semantics.
GO_EXTLINK_ENABLED
Whether the linker should use external linking mode
when using -linkmode=auto with code that uses cgo.
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index a1f925ed0b..e65aee4a27 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -667,6 +667,7 @@ var (
goarch string
goos string
exeSuffix string
+ gopath []string
)
func init() {
@@ -675,6 +676,7 @@ func init() {
if goos == "windows" {
exeSuffix = ".exe"
}
+ gopath = filepath.SplitList(buildContext.GOPATH)
}
// A builder holds global state about a build.
@@ -684,6 +686,7 @@ type builder struct {
work string // the temporary work directory (ends in filepath.Separator)
actionCache map[cacheKey]*action // a cache of already-constructed actions
mkdirCache map[string]bool // a cache of created directories
+ flagCache map[string]bool // a cache of supported compiler flags
print func(args ...interface{}) (int, error)
output sync.Mutex
@@ -1684,6 +1687,22 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
inc = append(inc, flag, b.work)
// Finally, look in the installed package directories for each action.
+ // First add the package dirs corresponding to GOPATH entries
+ // in the original GOPATH order.
+ need := map[string]*build.Package{}
+ for _, a1 := range all {
+ if a1.p != nil && a1.pkgdir == a1.p.build.PkgRoot {
+ need[a1.p.build.Root] = a1.p.build
+ }
+ }
+ for _, root := range gopath {
+ if p := need[root]; p != nil && !incMap[p.PkgRoot] {
+ incMap[p.PkgRoot] = true
+ inc = append(inc, flag, p.PkgTargetRoot)
+ }
+ }
+
+ // Then add anything that's left.
for _, a1 := range all {
if a1.p == nil {
continue
@@ -2909,6 +2928,17 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
// disable word wrapping in error messages
a = append(a, "-fmessage-length=0")
+ // Tell gcc not to include the work directory in object files.
+ if b.gccSupportsFlag("-fdebug-prefix-map=a=b") {
+ a = append(a, "-fdebug-prefix-map="+b.work+"=/tmp/go-build")
+ }
+
+ // Tell gcc not to include flags in object files, which defeats the
+ // point of -fdebug-prefix-map above.
+ if b.gccSupportsFlag("-gno-record-gcc-switches") {
+ a = append(a, "-gno-record-gcc-switches")
+ }
+
// On OS X, some of the compilers behave as if -fno-common
// is always set, and the Mach-O linker in 6l/8l assumes this.
// See https://golang.org/issue/3253.
@@ -2923,19 +2953,24 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
// -no-pie must be passed when doing a partial link with -Wl,-r. But -no-pie is
// not supported by all compilers.
func (b *builder) gccSupportsNoPie() bool {
- if goos != "linux" {
- // On some BSD platforms, error messages from the
- // compiler make it to the console despite cmd.Std*
- // all being nil. As -no-pie is only required on linux
- // systems so far, we only test there.
- return false
+ return b.gccSupportsFlag("-no-pie")
+}
+
+// gccSupportsFlag checks to see if the compiler supports a flag.
+func (b *builder) gccSupportsFlag(flag string) bool {
+ b.exec.Lock()
+ defer b.exec.Unlock()
+ if b, ok := b.flagCache[flag]; ok {
+ return b
}
- src := filepath.Join(b.work, "trivial.c")
- if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
- return false
+ if b.flagCache == nil {
+ src := filepath.Join(b.work, "trivial.c")
+ if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
+ return false
+ }
+ b.flagCache = make(map[string]bool)
}
- cmdArgs := b.gccCmd(b.work)
- cmdArgs = append(cmdArgs, "-no-pie", "-c", "trivial.c")
+ cmdArgs := append(envList("CC", defaultCC), flag, "-c", "trivial.c")
if buildN || buildX {
b.showcmd(b.work, "%s", joinUnambiguously(cmdArgs))
if buildN {
@@ -2946,7 +2981,9 @@ func (b *builder) gccSupportsNoPie() bool {
cmd.Dir = b.work
cmd.Env = envForDir(cmd.Dir, os.Environ())
out, err := cmd.CombinedOutput()
- return err == nil && !bytes.Contains(out, []byte("unrecognized"))
+ supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
+ b.flagCache[flag] = supported
+ return supported
}
// gccArchArgs returns arguments to pass to gcc based on the architecture.
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 24f612756b..8d427b37c2 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -33,11 +33,6 @@ func mkEnv() []envVar {
var b builder
b.init()
- vendorExpValue := "0"
- if go15VendorExperiment {
- vendorExpValue = "1"
- }
-
env := []envVar{
{"GOARCH", goarch},
{"GOBIN", gobin},
@@ -49,7 +44,6 @@ func mkEnv() []envVar {
{"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot},
{"GOTOOLDIR", toolDir},
- {"GO15VENDOREXPERIMENT", vendorExpValue},
// disable escape codes in clang errors
{"TERM", "dumb"},
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index 6d12f75073..51931769d5 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -10,6 +10,7 @@ import (
"fmt"
"go/build"
"go/format"
+ "internal/race"
"internal/testenv"
"io"
"io/ioutil"
@@ -69,7 +70,11 @@ func TestMain(m *testing.M) {
flag.Parse()
if canRun {
- out, err := exec.Command("go", "build", "-tags", "testgo", "-o", "testgo"+exeSuffix).CombinedOutput()
+ args := []string{"build", "-tags", "testgo", "-o", "testgo" + exeSuffix}
+ if race.Enabled {
+ args = append(args, "-race")
+ }
+ out, err := exec.Command("go", args...).CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out)
os.Exit(2)
@@ -1652,8 +1657,8 @@ func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
func main() {
println(extern)
}`)
- tg.run("run", "-ldflags", `-X main.extern "hello world"`, tg.path("main.go"))
- tg.grepStderr("^hello world", `ldflags -X main.extern 'hello world' failed`)
+ tg.run("run", "-ldflags", `-X "main.extern=hello world"`, tg.path("main.go"))
+ tg.grepStderr("^hello world", `ldflags -X "main.extern=hello world"' failed`)
}
func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) {
@@ -1721,7 +1726,6 @@ func TestSymlinksVendor(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.tempDir("gopath/src/dir1/vendor/v")
tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `v`\nfunc main(){}")
tg.tempFile("gopath/src/dir1/vendor/v/v.go", "package v")
@@ -2333,7 +2337,7 @@ func TestGoGetHTTPS404(t *testing.T) {
tg.run("get", "bazil.org/fuse/fs/fstestutil")
}
-// Test that you can not import a main package.
+// Test that you cannot import a main package.
func TestIssue4210(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -2565,6 +2569,59 @@ func TestGoInstallShadowedGOPATH(t *testing.T) {
tg.grepStderr("no install location for.*gopath2.src.test: hidden by .*gopath1.src.test", "missing error")
}
+func TestGoBuildGOPATHOrder(t *testing.T) {
+ // golang.org/issue/14176#issuecomment-179895769
+ // golang.org/issue/14192
+ // -I arguments to compiler could end up not in GOPATH order,
+ // leading to unexpected import resolution in the compiler.
+ // This is still not a complete fix (see golang.org/issue/14271 and next test)
+ // but it is clearly OK and enough to fix both of the two reported
+ // instances of the underlying problem. It will have to do for now.
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("p1")+string(filepath.ListSeparator)+tg.path("p2"))
+
+ tg.tempFile("p1/src/foo/foo.go", "package foo\n")
+ tg.tempFile("p2/src/baz/baz.go", "package baz\n")
+ tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n")
+ tg.tempFile("p1/src/bar/bar.go", `
+ package bar
+ import _ "baz"
+ import _ "foo"
+ `)
+
+ tg.run("install", "-x", "bar")
+}
+
+func TestGoBuildGOPATHOrderBroken(t *testing.T) {
+ // This test is known not to work.
+ // See golang.org/issue/14271.
+ t.Skip("golang.org/issue/14271")
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+
+ tg.tempFile("p1/src/foo/foo.go", "package foo\n")
+ tg.tempFile("p2/src/baz/baz.go", "package baz\n")
+ tg.tempFile("p1/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/baz.a", "bad\n")
+ tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n")
+ tg.tempFile("p1/src/bar/bar.go", `
+ package bar
+ import _ "baz"
+ import _ "foo"
+ `)
+
+ colon := string(filepath.ListSeparator)
+ tg.setenv("GOPATH", tg.path("p1")+colon+tg.path("p2"))
+ tg.run("install", "-x", "bar")
+
+ tg.setenv("GOPATH", tg.path("p2")+colon+tg.path("p1"))
+ tg.run("install", "-x", "bar")
+}
+
func TestIssue11709(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -2682,3 +2739,49 @@ func TestIssue13655(t *testing.T) {
tg.grepStdout("runtime/internal/sys", "did not find required dependency of "+pkg+" on runtime/internal/sys")
}
}
+
+// For issue 14337.
+func TestParallelTest(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ const testSrc = `package package_test
+ import (
+ "testing"
+ )
+ func TestTest(t *testing.T) {
+ }`
+ tg.tempFile("src/p1/p1_test.go", strings.Replace(testSrc, "package_test", "p1_test", 1))
+ tg.tempFile("src/p2/p2_test.go", strings.Replace(testSrc, "package_test", "p2_test", 1))
+ tg.tempFile("src/p3/p3_test.go", strings.Replace(testSrc, "package_test", "p3_test", 1))
+ tg.tempFile("src/p4/p4_test.go", strings.Replace(testSrc, "package_test", "p4_test", 1))
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("test", "-p=4", "p1", "p2", "p3", "p4")
+}
+
+func TestCgoConsistentResults(t *testing.T) {
+ if !canCgo {
+ t.Skip("skipping because cgo not enabled")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ exe1 := tg.path("cgotest1" + exeSuffix)
+ exe2 := tg.path("cgotest2" + exeSuffix)
+ tg.run("build", "-o", exe1, "cgotest")
+ tg.run("build", "-x", "-o", exe2, "cgotest")
+ b1, err := ioutil.ReadFile(exe1)
+ tg.must(err)
+ b2, err := ioutil.ReadFile(exe2)
+ tg.must(err)
+
+ if !tg.doGrepMatch(`-fdebug-prefix-map=\$WORK`, &tg.stderr) {
+ t.Skip("skipping because C compiler does not support -fdebug-prefix-map")
+ }
+ if !bytes.Equal(b1, b2) {
+ t.Error("building cgotest twice did not produce the same output")
+ }
+}
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index d8e7efedb3..de5e5ddeab 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -421,12 +421,6 @@ Vendor directories do not affect the placement of new repositories
being checked out for the first time by 'go get': those are always
placed in the main GOPATH, never in a vendor subtree.
-In Go 1.5, as an experiment, setting the environment variable
-GO15VENDOREXPERIMENT=1 enabled these features.
-As of Go 1.6 they are on by default. To turn them off, set
-GO15VENDOREXPERIMENT=0. In Go 1.7, the environment
-variable will stop having any effect.
-
See https://golang.org/s/go15vendor for details.
`,
}
@@ -497,8 +491,6 @@ Special-purpose environment variables:
installed in a location other than where it is built.
File names in stack traces are rewritten from GOROOT to
GOROOT_FINAL.
- GO15VENDOREXPERIMENT
- Set to 0 to disable vendoring semantics.
GO_EXTLINK_ENABLED
Whether the linker should use external linking mode
when using -linkmode=auto with code that uses cgo.
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index d384594722..f9b979da7f 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -454,7 +454,9 @@ func envForDir(dir string, base []string) []string {
// mergeEnvLists merges the two environment lists such that
// variables with the same name in "in" replace those in "out".
+// This always returns a newly allocated slice.
func mergeEnvLists(in, out []string) []string {
+ out = append([]string(nil), out...)
NextVar:
for _, inkv := range in {
k := strings.SplitAfterN(inkv, "=", 2)[0]
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index a804ccd277..6b5ead2b8c 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -263,15 +263,6 @@ func reloadPackage(arg string, stk *importStack) *Package {
return loadPackage(arg, stk)
}
-// The Go 1.5 vendoring experiment was enabled by setting GO15VENDOREXPERIMENT=1.
-// In Go 1.6 this is on by default and is disabled by setting GO15VENDOREXPERIMENT=0.
-// In Go 1.7 the variable will stop having any effect.
-// The variable is obnoxiously long so that years from now when people find it in
-// their profiles and wonder what it does, there is some chance that a web search
-// might answer the question.
-// There is a copy of this variable in src/go/build/build.go. Delete that one when this one goes away.
-var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") != "0"
-
// dirToImportPath returns the pseudo-import path we use for a package
// outside the Go path. It begins with _/ and then contains the full path
// to the directory. If the package lives in c:\home\gopher\my\pkg then
@@ -361,7 +352,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
// TODO: After Go 1, decide when to pass build.AllowBinary here.
// See issue 3268 for mistakes to avoid.
buildMode := build.ImportComment
- if !go15VendorExperiment || mode&useVendor == 0 || path != origPath {
+ if mode&useVendor == 0 || path != origPath {
// Not vendoring, or we already found the vendored path.
buildMode |= build.IgnoreVendor
}
@@ -371,7 +362,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
bp.BinDir = gobin
}
if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
- (!go15VendorExperiment || (!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/"))) {
+ !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
}
p.load(stk, bp, err)
@@ -412,7 +403,7 @@ func isDir(path string) bool {
// x/vendor/path, vendor/path, or else stay path if none of those exist.
// vendoredImportPath returns the expanded path or, if no expansion is found, the original.
func vendoredImportPath(parent *Package, path string) (found string) {
- if parent == nil || parent.Root == "" || !go15VendorExperiment {
+ if parent == nil || parent.Root == "" {
return path
}
@@ -580,10 +571,6 @@ func findInternal(path string) (index int, ok bool) {
// If the import is allowed, disallowVendor returns the original package p.
// If not, it returns a new package containing just an appropriate error.
func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package {
- if !go15VendorExperiment {
- return p
- }
-
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
@@ -967,7 +954,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
}
}
- if p.Standard && !p1.Standard && p.Error == nil {
+ if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath),
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 342edee50d..797d91fb96 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -383,7 +383,7 @@ func (v *vcsCmd) ping(scheme, repo string) error {
// The parent of dir must exist; dir must not.
func (v *vcsCmd) create(dir, repo string) error {
for _, cmd := range v.createCmd {
- if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
+ if strings.Contains(cmd, "submodule") {
continue
}
if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil {
@@ -396,7 +396,7 @@ func (v *vcsCmd) create(dir, repo string) error {
// download downloads any new changes for the repo in dir.
func (v *vcsCmd) download(dir string) error {
for _, cmd := range v.downloadCmd {
- if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
+ if strings.Contains(cmd, "submodule") {
continue
}
if err := v.run(dir, cmd); err != nil {
@@ -445,7 +445,7 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
if tag == "" && v.tagSyncDefault != nil {
for _, cmd := range v.tagSyncDefault {
- if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
+ if strings.Contains(cmd, "submodule") {
continue
}
if err := v.run(dir, cmd); err != nil {
@@ -456,7 +456,7 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
}
for _, cmd := range v.tagSyncCmd {
- if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
+ if strings.Contains(cmd, "submodule") {
continue
}
if err := v.run(dir, cmd, "tag", tag); err != nil {
diff --git a/src/cmd/go/vendor_test.go b/src/cmd/go/vendor_test.go
index 006a8c9d3f..40fe309b6d 100644
--- a/src/cmd/go/vendor_test.go
+++ b/src/cmd/go/vendor_test.go
@@ -20,7 +20,6 @@ func TestVendorImports(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...")
want := `
vend [vend/vendor/p r]
@@ -51,7 +50,6 @@ func TestVendorBuild(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("build", "vend/x")
}
@@ -59,7 +57,6 @@ func TestVendorRun(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello"))
tg.run("run", "hello.go")
tg.grepStdout("hello, world", "missing hello world output")
@@ -74,7 +71,6 @@ func TestVendorGOPATH(t *testing.T) {
}
gopath := changeVolume(filepath.Join(tg.pwd(), "testdata"), strings.ToLower)
tg.setenv("GOPATH", gopath)
- tg.setenv("GO15VENDOREXPERIMENT", "1")
cd := changeVolume(filepath.Join(tg.pwd(), "testdata/src/vend/hello"), strings.ToUpper)
tg.cd(cd)
tg.run("run", "hello.go")
@@ -85,7 +81,6 @@ func TestVendorTest(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello"))
tg.run("test", "-v")
tg.grepStdout("TestMsgInternal", "missing use in internal test")
@@ -96,7 +91,6 @@ func TestVendorInvalid(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.runFail("build", "vend/x/invalid")
tg.grepStderr("must be imported as foo", "missing vendor import error")
@@ -106,7 +100,6 @@ func TestVendorImportError(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.runFail("build", "vend/x/vendor/p/p")
@@ -173,7 +166,6 @@ func TestVendorGet(t *testing.T) {
package p
const C = 1`)
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.cd(tg.path("src/v"))
tg.run("run", "m.go")
tg.run("test")
@@ -192,7 +184,6 @@ func TestVendorGetUpdate(t *testing.T) {
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("get", "github.com/rsc/go-get-issue-11864")
tg.run("get", "-u", "github.com/rsc/go-get-issue-11864")
}
@@ -204,7 +195,6 @@ func TestGetSubmodules(t *testing.T) {
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("get", "-d", "github.com/rsc/go-get-issue-12612")
tg.run("get", "-u", "-d", "github.com/rsc/go-get-issue-12612")
}
@@ -213,7 +203,6 @@ func TestVendorCache(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.runFail("build", "p")
tg.grepStderr("must be imported as x", "did not fail to build p")
}
@@ -225,7 +214,6 @@ func TestVendorTest2(t *testing.T) {
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("get", "github.com/rsc/go-get-issue-11864")
// build -i should work
@@ -251,7 +239,6 @@ func TestVendorList(t *testing.T) {
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.run("get", "github.com/rsc/go-get-issue-11864")
tg.run("list", "-f", `{{join .TestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/t")
@@ -272,7 +259,6 @@ func TestVendor12156(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor2"))
- tg.setenv("GO15VENDOREXPERIMENT", "1")
tg.cd(filepath.Join(tg.pwd(), "testdata/testvendor2/src/p"))
tg.runFail("build", "p.go")
tg.grepStderrNot("panic", "panicked")
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index cfebeffe4a..b10b804fd2 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -143,7 +143,9 @@ func visitFile(path string, f os.FileInfo, err error) error {
if err == nil && isGoFile(f) {
err = processFile(path, nil, os.Stdout, false)
}
- if err != nil {
+ // Don't complain if a file was deleted in the meantime (i.e.
+ // the directory changed concurrently while running gofmt).
+ if err != nil && !os.IsNotExist(err) {
report(err)
}
return nil
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 19a70e177e..1a51dc3b88 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -60,7 +60,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
// Treat MRC 15, 0, , C13, C0, 3 specially.
case AMRC:
if p.To.Offset&0xffff0fff == 0xee1d0f70 {
- // Because the instruction might be rewriten to a BL which returns in R0
+ // Because the instruction might be rewritten to a BL which returns in R0
// the register must be zero.
if p.To.Offset&0xf000 != 0 {
ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go
index e928121938..f38078fca8 100644
--- a/src/cmd/internal/obj/obj.go
+++ b/src/cmd/internal/obj/obj.go
@@ -290,3 +290,21 @@ func linkgetline(ctxt *Link, lineno int32, f **LSym, l *int32) {
func Linkprfile(ctxt *Link, line int) {
fmt.Printf("%s ", ctxt.LineHist.LineString(line))
}
+
+func fieldtrack(ctxt *Link, cursym *LSym) {
+ p := cursym.Text
+ if p == nil || p.Link == nil { // handle external functions and ELF section symbols
+ return
+ }
+ ctxt.Cursym = cursym
+
+ for ; p != nil; p = p.Link {
+ if p.As == AUSEFIELD {
+ r := Addrel(ctxt.Cursym)
+ r.Off = 0
+ r.Siz = 0
+ r.Sym = p.From.Sym
+ r.Type = R_USEFIELD
+ }
+ }
+}
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 8d4a506843..bae64f4a29 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -298,6 +298,7 @@ func Flushplist(ctxt *Link) {
ctxt.Arch.Follow(ctxt, s)
ctxt.Arch.Preprocess(ctxt, s)
ctxt.Arch.Assemble(ctxt, s)
+ fieldtrack(ctxt, s)
linkpcln(ctxt, s)
}
diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go
index ca7b0cfdca..64bd865e42 100644
--- a/src/cmd/internal/obj/x86/a.out.go
+++ b/src/cmd/internal/obj/x86/a.out.go
@@ -295,8 +295,6 @@ const (
AFMOVX
AFMOVXP
- AFCOMB
- AFCOMBP
AFCOMD
AFCOMDP
AFCOMDPP
@@ -626,14 +624,7 @@ const (
APADDUSW
APADDW
APAND
- APANDB
- APANDL
APANDN
- APANDSB
- APANDSW
- APANDUSB
- APANDUSW
- APANDW
APAVGB
APAVGW
APCMPEQB
@@ -650,23 +641,6 @@ const (
APEXTRD
APEXTRQ
APEXTRW
- APFACC
- APFADD
- APFCMPEQ
- APFCMPGE
- APFCMPGT
- APFMAX
- APFMIN
- APFMUL
- APFNACC
- APFPNACC
- APFRCP
- APFRCPI2T
- APFRCPIT1
- APFRSQIT1
- APFRSQRT
- APFSUB
- APFSUBR
APHADDD
APHADDSW
APHADDW
@@ -697,7 +671,6 @@ const (
APMOVZXWD
APMOVZXWQ
APMULDQ
- APMULHRW
APMULHUW
APMULHW
APMULLD
@@ -728,7 +701,6 @@ const (
APSUBUSB
APSUBUSW
APSUBW
- APSWAPL
APUNPCKHBW
APUNPCKHLQ
APUNPCKHQDQ
@@ -767,11 +739,6 @@ const (
AUNPCKLPS
AXORPD
AXORPS
-
- APF2IW
- APF2IL
- API2FW
- API2FL
ARETFW
ARETFL
ARETFQ
diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go
index 1875eae418..3b59e2f36f 100644
--- a/src/cmd/internal/obj/x86/anames.go
+++ b/src/cmd/internal/obj/x86/anames.go
@@ -255,8 +255,6 @@ var Anames = []string{
"FMOVWP",
"FMOVX",
"FMOVXP",
- "FCOMB",
- "FCOMBP",
"FCOMD",
"FCOMDP",
"FCOMDPP",
@@ -569,14 +567,7 @@ var Anames = []string{
"PADDUSW",
"PADDW",
"PAND",
- "PANDB",
- "PANDL",
"PANDN",
- "PANDSB",
- "PANDSW",
- "PANDUSB",
- "PANDUSW",
- "PANDW",
"PAVGB",
"PAVGW",
"PCMPEQB",
@@ -593,23 +584,6 @@ var Anames = []string{
"PEXTRD",
"PEXTRQ",
"PEXTRW",
- "PFACC",
- "PFADD",
- "PFCMPEQ",
- "PFCMPGE",
- "PFCMPGT",
- "PFMAX",
- "PFMIN",
- "PFMUL",
- "PFNACC",
- "PFPNACC",
- "PFRCP",
- "PFRCPI2T",
- "PFRCPIT1",
- "PFRSQIT1",
- "PFRSQRT",
- "PFSUB",
- "PFSUBR",
"PHADDD",
"PHADDSW",
"PHADDW",
@@ -640,7 +614,6 @@ var Anames = []string{
"PMOVZXWD",
"PMOVZXWQ",
"PMULDQ",
- "PMULHRW",
"PMULHUW",
"PMULHW",
"PMULLD",
@@ -671,7 +644,6 @@ var Anames = []string{
"PSUBUSB",
"PSUBUSW",
"PSUBW",
- "PSWAPL",
"PUNPCKHBW",
"PUNPCKHLQ",
"PUNPCKHQDQ",
@@ -710,10 +682,6 @@ var Anames = []string{
"UNPCKLPS",
"XORPD",
"XORPS",
- "PF2IW",
- "PF2IL",
- "PI2FW",
- "PI2FL",
"RETFW",
"RETFL",
"RETFQ",
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 4577ed7925..9ab6615e43 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -184,7 +184,6 @@ const (
Zm2_r
Zm_r_xm
Zm_r_i_xm
- Zm_r_3d
Zm_r_xm_nr
Zr_m_xm_nr
Zibm_r /* mmx1,mmx2/mem64,imm8 */
@@ -753,10 +752,6 @@ var yxrrl = []ytab{
{Yxr, Ynone, Yrl, Zm_r, 1},
}
-var ymfp = []ytab{
- {Ymm, Ynone, Ymr, Zm_r_3d, 1},
-}
-
var ymrxr = []ytab{
{Ymr, Ynone, Yxr, Zm_r, 1},
{Yxm, Ynone, Yxr, Zm_r_xm, 1},
@@ -1085,7 +1080,6 @@ var optab =
{ACVTPD2PS, yxm, Pe, [23]uint8{0x5a}},
{ACVTPS2PL, yxcvm1, Px, [23]uint8{Pe, 0x5b, Pm, 0x2d}},
{ACVTPS2PD, yxm, Pm, [23]uint8{0x5a}},
- {API2FW, ymfp, Px, [23]uint8{0x0c}},
{ACVTSD2SL, yxcvfl, Pf2, [23]uint8{0x2d}},
{ACVTSD2SQ, yxcvfq, Pw, [23]uint8{Pf2, 0x2d}},
{ACVTSD2SS, yxm, Pf2, [23]uint8{0x5a}},
@@ -1303,26 +1297,6 @@ var optab =
{APEXTRB, yextr, Pq, [23]uint8{0x3a, 0x14, 00}},
{APEXTRD, yextr, Pq, [23]uint8{0x3a, 0x16, 00}},
{APEXTRQ, yextr, Pq3, [23]uint8{0x3a, 0x16, 00}},
- {APF2IL, ymfp, Px, [23]uint8{0x1d}},
- {APF2IW, ymfp, Px, [23]uint8{0x1c}},
- {API2FL, ymfp, Px, [23]uint8{0x0d}},
- {APFACC, ymfp, Px, [23]uint8{0xae}},
- {APFADD, ymfp, Px, [23]uint8{0x9e}},
- {APFCMPEQ, ymfp, Px, [23]uint8{0xb0}},
- {APFCMPGE, ymfp, Px, [23]uint8{0x90}},
- {APFCMPGT, ymfp, Px, [23]uint8{0xa0}},
- {APFMAX, ymfp, Px, [23]uint8{0xa4}},
- {APFMIN, ymfp, Px, [23]uint8{0x94}},
- {APFMUL, ymfp, Px, [23]uint8{0xb4}},
- {APFNACC, ymfp, Px, [23]uint8{0x8a}},
- {APFPNACC, ymfp, Px, [23]uint8{0x8e}},
- {APFRCP, ymfp, Px, [23]uint8{0x96}},
- {APFRCPIT1, ymfp, Px, [23]uint8{0xa6}},
- {APFRCPI2T, ymfp, Px, [23]uint8{0xb6}},
- {APFRSQIT1, ymfp, Px, [23]uint8{0xa7}},
- {APFRSQRT, ymfp, Px, [23]uint8{0x97}},
- {APFSUB, ymfp, Px, [23]uint8{0x9a}},
- {APFSUBR, ymfp, Px, [23]uint8{0xaa}},
{APHADDD, ymmxmm0f38, Px, [23]uint8{0x0F, 0x38, 0x02, 0, 0x66, 0x0F, 0x38, 0x02, 0}},
{APHADDSW, yxm_q4, Pq4, [23]uint8{0x03}},
{APHADDW, yxm_q4, Pq4, [23]uint8{0x01}},
@@ -1353,7 +1327,6 @@ var optab =
{APMOVZXWD, yxm_q4, Pq4, [23]uint8{0x33}},
{APMOVZXWQ, yxm_q4, Pq4, [23]uint8{0x34}},
{APMULDQ, yxm_q4, Pq4, [23]uint8{0x28}},
- {APMULHRW, ymfp, Px, [23]uint8{0xb7}},
{APMULHUW, ymm, Py1, [23]uint8{0xe4, Pe, 0xe4}},
{APMULHW, ymm, Py1, [23]uint8{0xe5, Pe, 0xe5}},
{APMULLD, yxm_q4, Pq4, [23]uint8{0x40}},
@@ -1395,7 +1368,6 @@ var optab =
{APSUBUSB, yxm, Pe, [23]uint8{0xd8}},
{APSUBUSW, yxm, Pe, [23]uint8{0xd9}},
{APSUBW, yxm, Pe, [23]uint8{0xf9}},
- {APSWAPL, ymfp, Px, [23]uint8{0xbb}},
{APUNPCKHBW, ymm, Py1, [23]uint8{0x68, Pe, 0x68}},
{APUNPCKHLQ, ymm, Py1, [23]uint8{0x6a, Pe, 0x6a}},
{APUNPCKHQDQ, yxm, Pe, [23]uint8{0x6d}},
@@ -1553,8 +1525,6 @@ var optab =
{AFCMOVNE, yfcmv, Px, [23]uint8{0xdb, 01}},
{AFCMOVNU, yfcmv, Px, [23]uint8{0xdb, 03}},
{AFCMOVUN, yfcmv, Px, [23]uint8{0xda, 03}},
- {AFCOMB, nil, 0, [23]uint8{}},
- {AFCOMBP, nil, 0, [23]uint8{}},
{AFCOMD, yfadd, Px, [23]uint8{0xdc, 02, 0xd8, 02, 0xdc, 02}}, /* botch */
{AFCOMDP, yfadd, Px, [23]uint8{0xdc, 03, 0xd8, 03, 0xdc, 03}}, /* botch */
{AFCOMDPP, ycompp, Px, [23]uint8{0xde, 03}},
@@ -3556,15 +3526,6 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
ctxt.Andptr[0] = byte(p.To.Offset)
ctxt.Andptr = ctxt.Andptr[1:]
- case Zm_r_3d:
- ctxt.Andptr[0] = 0x0f
- ctxt.Andptr = ctxt.Andptr[1:]
- ctxt.Andptr[0] = 0x0f
- ctxt.Andptr = ctxt.Andptr[1:]
- asmand(ctxt, p, &p.From, &p.To)
- ctxt.Andptr[0] = byte(op)
- ctxt.Andptr = ctxt.Andptr[1:]
-
case Zibm_r, Zibr_m:
for {
tmp1 := z
@@ -4618,15 +4579,6 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
ctxt.Andptr = ctxt.And[:]
ctxt.Asmode = int(p.Mode)
- if p.As == obj.AUSEFIELD {
- r := obj.Addrel(ctxt.Cursym)
- r.Off = 0
- r.Siz = 0
- r.Sym = p.From.Sym
- r.Type = obj.R_USEFIELD
- return
- }
-
if ctxt.Headtype == obj.Hnacl && p.Mode == 32 {
switch p.As {
case obj.ARET:
diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go
index 6495dfb356..f038883dc0 100644
--- a/src/cmd/internal/objfile/disasm.go
+++ b/src/cmd/internal/objfile/disasm.go
@@ -15,8 +15,8 @@ import (
"strings"
"text/tabwriter"
- "golang.org/x/arch/arm/armasm"
- "golang.org/x/arch/x86/x86asm"
+ "cmd/internal/unvendor/golang.org/x/arch/arm/armasm"
+ "cmd/internal/unvendor/golang.org/x/arch/x86/x86asm"
)
// Disasm is a disassembler for a given File.
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/Makefile b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/Makefile
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/Makefile
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/Makefile
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/decode_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/ext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/ext_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/ext_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/ext_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/gnu.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/gnu.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/gnu.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/gnu.go
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/inst.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/inst.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/inst.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/inst.go
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/objdump_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdump_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/objdump_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdump_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/objdumpext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdumpext_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/objdumpext_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdumpext_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/plan9x.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/plan9x.go
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/tables.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/tables.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/tables.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/tables.go
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/Makefile b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/Makefile
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/Makefile
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/Makefile
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/decode.txt b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/decode.txt
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/decode.txt
rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/decode.txt
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/Makefile b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/Makefile
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/Makefile
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/Makefile
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/ext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/ext_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/ext_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/ext_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/gnu.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/gnu.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/intel.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/intel.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdump_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdump_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdump_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdump_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/tables.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/tables.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/Makefile b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/Makefile
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/Makefile
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/Makefile
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/xed_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xed_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/xed_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xed_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/xedext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xedext_test.go
similarity index 100%
rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/xedext_test.go
rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xedext_test.go
diff --git a/src/cmd/vendor/vendor.json b/src/cmd/internal/unvendor/vendor.json
similarity index 100%
rename from src/cmd/vendor/vendor.json
rename to src/cmd/internal/unvendor/vendor.json
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 563600d9a2..fb3d8fb2cd 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -951,7 +951,7 @@ func defgotype(gotype *LSym) *DWDie {
}
if !strings.HasPrefix(gotype.Name, "type.") {
- Diag("dwarf: type name doesn't start with \".type\": %s", gotype.Name)
+ Diag("dwarf: type name doesn't start with \"type.\": %s", gotype.Name)
return mustFind(&dwtypes, "")
}
@@ -1946,7 +1946,9 @@ func writepub(ispub func(*DWDie) bool) int64 {
*/
func writearanges() int64 {
sectionstart := Cpos()
- headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize))) // don't count unit_length field itself
+ // The first tuple is aligned to a multiple of the size of a single tuple
+ // (twice the size of an address)
+ headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize*2))) // don't count unit_length field itself
for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
b := getattr(compunit, DW_AT_low_pc)
diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go
index 808d377f8a..9ec14c24ed 100644
--- a/src/cmd/link/internal/ld/pobj.go
+++ b/src/cmd/link/internal/ld/pobj.go
@@ -119,33 +119,6 @@ func Ldmain() {
obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
- // Clumsy hack to preserve old two-argument -X name val syntax for old scripts.
- // Rewrite that syntax into new syntax -X name=val.
- // TODO(rsc): Delete this hack in Go 1.6 or later.
- var args []string
- for i := 0; i < len(os.Args); i++ {
- arg := os.Args[i]
- if (arg == "-X" || arg == "--X") && i+2 < len(os.Args) && !strings.Contains(os.Args[i+1], "=") {
- fmt.Fprintf(os.Stderr, "link: warning: option %s %s %s may not work in future releases; use %s %s=%s\n",
- arg, os.Args[i+1], os.Args[i+2],
- arg, os.Args[i+1], os.Args[i+2])
- args = append(args, arg)
- args = append(args, os.Args[i+1]+"="+os.Args[i+2])
- i += 2
- continue
- }
- if (strings.HasPrefix(arg, "-X=") || strings.HasPrefix(arg, "--X=")) && i+1 < len(os.Args) && strings.Count(arg, "=") == 1 {
- fmt.Fprintf(os.Stderr, "link: warning: option %s %s may not work in future releases; use %s=%s\n",
- arg, os.Args[i+1],
- arg, os.Args[i+1])
- args = append(args, arg+"="+os.Args[i+1])
- i++
- continue
- }
- args = append(args, arg)
- }
- os.Args = args
-
obj.Flagparse(usage)
startProfile()
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index 731f3ede94..6122b85298 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -34,8 +34,6 @@ package ld
import (
"cmd/internal/obj"
"log"
- "os"
- "path/filepath"
"strconv"
)
@@ -70,13 +68,6 @@ func linknew(arch *LinkArch) *Link {
log.Fatalf("invalid goarch %s (want %s)", p, arch.Name)
}
- var buf string
- buf, _ = os.Getwd()
- if buf == "" {
- buf = "/???"
- }
- buf = filepath.ToSlash(buf)
-
ctxt.Headtype = headtype(obj.Getgoos())
if ctxt.Headtype < 0 {
log.Fatalf("unknown goos %s", obj.Getgoos())
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index 3e6169e453..b87ca81007 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -215,6 +215,11 @@ func Asmelfsym() {
dwarfaddelfsectionsyms()
+ // Some linkers will add a FILE sym if one is not present.
+ // Avoid having the working directory inserted into the symbol table.
+ putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0)
+ numelfsym++
+
elfbind = STB_LOCAL
genasmsym(putelfsym)
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
index ee022b803a..dc57a6335a 100644
--- a/src/crypto/rsa/rsa.go
+++ b/src/crypto/rsa/rsa.go
@@ -14,7 +14,7 @@
// possible.
//
// Two sets of interfaces are included in this package. When a more abstract
-// interface isn't neccessary, there are functions for encrypting/decrypting
+// interface isn't necessary, there are functions for encrypting/decrypting
// with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract
// over the public-key primitive, the PrivateKey struct implements the
// Decrypter and Signer interfaces from the crypto package.
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index 869ffa50bd..224ed1bc86 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -74,7 +74,7 @@ type cipherSuite struct {
var cipherSuites = []*cipherSuite{
// Ciphersuite order is chosen so that ECDHE comes before plain RSA
- // and RC4 comes before AES (because of the Lucky13 attack).
+ // and RC4 comes before AES-CBC (because of the Lucky13 attack).
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index d8e7cb77af..28c36160b5 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -199,7 +199,7 @@ type Scanner interface {
// time.Time
// nil - for NULL values
//
- // An error should be returned if the value can not be stored
+ // An error should be returned if the value cannot be stored
// without loss of information.
Scan(src interface{}) error
}
diff --git a/src/encoding/csv/writer.go b/src/encoding/csv/writer.go
index 353d91f238..a6056285b4 100644
--- a/src/encoding/csv/writer.go
+++ b/src/encoding/csv/writer.go
@@ -130,7 +130,7 @@ func (w *Writer) fieldNeedsQuotes(field string) bool {
if field == "" {
return false
}
- if field == `\.` || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
+ if field == `\.` || strings.ContainsRune(field, w.Comma) || strings.ContainsAny(field, "\"\r\n") {
return true
}
diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go
index 8efcdc78ff..b772171f93 100644
--- a/src/encoding/gob/codec_test.go
+++ b/src/encoding/gob/codec_test.go
@@ -970,7 +970,7 @@ func TestBadRecursiveType(t *testing.T) {
err := NewEncoder(b).Encode(&rec)
if err == nil {
t.Error("expected error; got none")
- } else if strings.Index(err.Error(), "recursive") < 0 {
+ } else if !strings.Contains(err.Error(), "recursive") {
t.Error("expected recursive type error; got", err)
}
// Can't test decode easily because we can't encode one, so we can't pass one to a Decoder.
diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go
index 570d79696b..811dd2b18c 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -280,7 +280,7 @@ func TestValueError(t *testing.T) {
}
t4p := &Type4{3}
var t4 Type4 // note: not a pointer.
- if err := encAndDec(t4p, t4); err == nil || strings.Index(err.Error(), "pointer") < 0 {
+ if err := encAndDec(t4p, t4); err == nil || !strings.Contains(err.Error(), "pointer") {
t.Error("expected error about pointer; got", err)
}
}
@@ -388,7 +388,7 @@ func TestSingletons(t *testing.T) {
t.Errorf("expected error decoding %v: %s", test.in, test.err)
continue
case err != nil && test.err != "":
- if strings.Index(err.Error(), test.err) < 0 {
+ if !strings.Contains(err.Error(), test.err) {
t.Errorf("wrong error decoding %v: wanted %s, got %v", test.in, test.err, err)
}
continue
@@ -414,7 +414,7 @@ func TestStructNonStruct(t *testing.T) {
var ns NonStruct
if err := encAndDec(s, &ns); err == nil {
t.Error("should get error for struct/non-struct")
- } else if strings.Index(err.Error(), "type") < 0 {
+ } else if !strings.Contains(err.Error(), "type") {
t.Error("for struct/non-struct expected type error; got", err)
}
// Now try the other way
@@ -424,7 +424,7 @@ func TestStructNonStruct(t *testing.T) {
}
if err := encAndDec(ns, &s); err == nil {
t.Error("should get error for non-struct/struct")
- } else if strings.Index(err.Error(), "type") < 0 {
+ } else if !strings.Contains(err.Error(), "type") {
t.Error("for non-struct/struct expected type error; got", err)
}
}
diff --git a/src/encoding/gob/gobencdec_test.go b/src/encoding/gob/gobencdec_test.go
index eb76b481d1..d674f0c784 100644
--- a/src/encoding/gob/gobencdec_test.go
+++ b/src/encoding/gob/gobencdec_test.go
@@ -548,7 +548,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
if err == nil {
t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)")
}
- if strings.Index(err.Error(), "type") < 0 {
+ if !strings.Contains(err.Error(), "type") {
t.Fatal("expected type error; got", err)
}
// Non-encoder to GobDecoder: error
@@ -562,7 +562,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
if err == nil {
t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)")
}
- if strings.Index(err.Error(), "type") < 0 {
+ if !strings.Contains(err.Error(), "type") {
t.Fatal("expected type error; got", err)
}
}
diff --git a/src/encoding/hex/hex.go b/src/encoding/hex/hex.go
index d1fc7024a9..a51b1db61c 100644
--- a/src/encoding/hex/hex.go
+++ b/src/encoding/hex/hex.go
@@ -105,7 +105,7 @@ func Dump(data []byte) string {
dumper := Dumper(&buf)
dumper.Write(data)
dumper.Close()
- return string(buf.Bytes())
+ return buf.String()
}
// Dumper returns a WriteCloser that writes a hex dump of all written data to
diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index 8ebd693030..9fcd5d7695 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -850,7 +850,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
switch k {
case reflect.String:
s := vf.String()
- dashDash = strings.Index(s, "--") >= 0
+ dashDash = strings.Contains(s, "--")
dashLast = s[len(s)-1] == '-'
if !dashDash {
p.WriteString(s)
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index 793f709a79..1d9d015f4a 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -259,6 +259,12 @@ var fmtTests = []struct {
{"%+.3F", float32(-1.0), "-1.000"},
{"%+07.2f", 1.0, "+001.00"},
{"%+07.2f", -1.0, "-001.00"},
+ {"%-07.2f", 1.0, "1.00 "},
+ {"%-07.2f", -1.0, "-1.00 "},
+ {"%+-07.2f", 1.0, "+1.00 "},
+ {"%+-07.2f", -1.0, "-1.00 "},
+ {"%-+07.2f", 1.0, "+1.00 "},
+ {"%-+07.2f", -1.0, "-1.00 "},
{"%+10.2f", +1.0, " +1.00"},
{"%+10.2f", -1.0, " -1.00"},
{"% .3E", -1.0, "-1.000E+00"},
@@ -380,6 +386,9 @@ var fmtTests = []struct {
{"%20e", math.Inf(1), " +Inf"},
{"%-20f", math.Inf(-1), "-Inf "},
{"%20g", math.NaN(), " NaN"},
+ {"%+20f", math.NaN(), " +NaN"},
+ {"% -20f", math.NaN(), " NaN "},
+ {"%+-20f", math.NaN(), "+NaN "},
// arrays
{"%v", array, "[1 2 3 4 5]"},
@@ -648,13 +657,19 @@ var fmtTests = []struct {
// Complex numbers: exhaustively tested in TestComplexFormatting.
{"%7.2f", 1 + 2i, "( 1.00 +2.00i)"},
{"%+07.2f", -1 - 2i, "(-001.00-002.00i)"},
- // Zero padding does not apply to infinities.
+ // Zero padding does not apply to infinities and NaN.
{"%020f", math.Inf(-1), " -Inf"},
{"%020f", math.Inf(+1), " +Inf"},
+ {"%020f", math.NaN(), " NaN"},
{"% 020f", math.Inf(-1), " -Inf"},
{"% 020f", math.Inf(+1), " Inf"},
+ {"% 020f", math.NaN(), " NaN"},
{"%+020f", math.Inf(-1), " -Inf"},
{"%+020f", math.Inf(+1), " +Inf"},
+ {"%+020f", math.NaN(), " +NaN"},
+ {"%-020f", math.Inf(-1), "-Inf "},
+ {"%-020f", math.Inf(+1), "+Inf "},
+ {"%-020f", math.NaN(), "NaN "},
{"%20f", -1.0, " -1.000000"},
// Make sure we can handle very large widths.
{"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 517b18f7d4..c811cc6a3d 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -5,7 +5,6 @@
package fmt
import (
- "math"
"strconv"
"unicode/utf8"
)
@@ -405,42 +404,38 @@ func doPrec(f *fmt, def int) int {
// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
// Format number, reserving space for leading + sign if needed.
- num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+ num := strconv.AppendFloat(f.intbuf[:1], v, verb, prec, n)
if num[1] == '-' || num[1] == '+' {
num = num[1:]
} else {
num[0] = '+'
}
- // Special handling for infinity, which doesn't look like a number so shouldn't be padded with zeros.
- if math.IsInf(v, 0) {
- if f.zero {
- defer func() { f.zero = true }()
- f.zero = false
- }
- }
- // num is now a signed version of the number.
- // If we're zero padding, want the sign before the leading zeros.
- // Achieve this by writing the sign out and then padding the unsigned number.
- if f.zero && f.widPresent && f.wid > len(num) {
- if f.space && v >= 0 {
- f.buf.WriteByte(' ') // This is what C does: even with zero, f.space means space.
- f.wid--
- } else if f.plus || v < 0 {
- f.buf.WriteByte(num[0])
- f.wid--
- }
- f.pad(num[1:])
- return
- }
// f.space says to replace a leading + with a space.
if f.space && num[0] == '+' {
num[0] = ' '
+ }
+ // Special handling for infinities and NaN,
+ // which don't look like a number so shouldn't be padded with zeros.
+ if num[1] == 'I' || num[1] == 'N' {
+ oldZero := f.zero
+ f.zero = false
+ // Remove sign before NaN if not asked for.
+ if num[1] == 'N' && !f.space && !f.plus {
+ num = num[1:]
+ }
f.pad(num)
+ f.zero = oldZero
return
}
- // Now we know the sign is attached directly to the number, if present at all.
- // We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf).
- if f.plus || num[0] == '-' || math.IsInf(v, 0) {
+ // We want a sign if asked for and if the sign is not positive.
+ if f.plus || num[0] != '+' {
+ // If we're zero padding we want the sign before the leading zeros.
+ // Achieve this by writing the sign out and then padding the unsigned number.
+ if f.zero && f.widPresent && f.wid > len(num) {
+ f.buf.WriteByte(num[0])
+ f.wid--
+ num = num[1:]
+ }
f.pad(num)
return
}
diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go
index 7ac74dcb4b..ce6f08659a 100644
--- a/src/fmt/scan_test.go
+++ b/src/fmt/scan_test.go
@@ -519,7 +519,7 @@ func testScanfMulti(name string, t *testing.T) {
if err != nil {
if test.err == "" {
t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
- } else if strings.Index(err.Error(), test.err) < 0 {
+ } else if !strings.Contains(err.Error(), test.err) {
t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
}
continue
@@ -613,7 +613,7 @@ func TestScanNotPointer(t *testing.T) {
_, err := Fscan(r, a)
if err == nil {
t.Error("expected error scanning non-pointer")
- } else if strings.Index(err.Error(), "pointer") < 0 {
+ } else if !strings.Contains(err.Error(), "pointer") {
t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
}
}
@@ -623,7 +623,7 @@ func TestScanlnNoNewline(t *testing.T) {
_, err := Sscanln("1 x\n", &a)
if err == nil {
t.Error("expected error scanning string missing newline")
- } else if strings.Index(err.Error(), "newline") < 0 {
+ } else if !strings.Contains(err.Error(), "newline") {
t.Errorf("expected newline error scanning string missing newline, got: %s", err)
}
}
@@ -634,7 +634,7 @@ func TestScanlnWithMiddleNewline(t *testing.T) {
_, err := Fscanln(r, &a, &b)
if err == nil {
t.Error("expected error scanning string with extra newline")
- } else if strings.Index(err.Error(), "newline") < 0 {
+ } else if !strings.Contains(err.Error(), "newline") {
t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
}
}
diff --git a/src/go/constant/value.go b/src/go/constant/value.go
index 310814df71..1b0938dda4 100644
--- a/src/go/constant/value.go
+++ b/src/go/constant/value.go
@@ -276,10 +276,10 @@ func smallRat(x *big.Float) bool {
// MakeUnknown returns the Unknown value.
func MakeUnknown() Value { return unknownVal{} }
-// MakeBool returns the Bool value for x.
+// MakeBool returns the Bool value for b.
func MakeBool(b bool) Value { return boolVal(b) }
-// MakeString returns the String value for x.
+// MakeString returns the String value for s.
func MakeString(s string) Value { return stringVal(s) }
// MakeInt64 returns the Int value for x.
diff --git a/src/go/doc/comment.go b/src/go/doc/comment.go
index f414ca4090..5631539abc 100644
--- a/src/go/doc/comment.go
+++ b/src/go/doc/comment.go
@@ -225,7 +225,7 @@ func heading(line string) string {
}
// exclude lines with illegal characters
- if strings.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 {
+ if strings.ContainsAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") {
return ""
}
diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go
index 68690424a1..ad1c4cd02a 100644
--- a/src/go/internal/gcimporter/bimport.go
+++ b/src/go/internal/gcimporter/bimport.go
@@ -678,4 +678,8 @@ var predeclared = []types.Type{
// package unsafe
types.Typ[types.UnsafePointer],
+
+ // any type, for builtin export data
+ // TODO(mdempsky): Provide an actual Type value to represent "any"?
+ types.Typ[types.Invalid],
}
diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go
index 0ef8eb4fc6..052277f4fe 100644
--- a/src/go/internal/gcimporter/gcimporter.go
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -31,7 +31,8 @@ var pkgExts = [...]string{".a", ".o"}
// FindPkg returns the filename and unique package id for an import
// path based on package information provided by build.Import (using
-// the build.Default build.Context).
+// the build.Default build.Context). A relative srcDir is interpreted
+// relative to the current working directory.
// If no file was found, an empty filename is returned.
//
func FindPkg(path, srcDir string) (filename, id string) {
@@ -44,6 +45,9 @@ func FindPkg(path, srcDir string) (filename, id string) {
default:
// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
// Don't require the source files to be present.
+ if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
+ srcDir = abs
+ }
bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
if bp.PkgObj == "" {
return
@@ -381,7 +385,7 @@ func (p *parser) getPkg(id, name string) *types.Package {
if pname := pkg.Name(); pname == "" {
pkg.SetName(name)
} else if pname != name {
- p.errorf("%s package name mismatch: %s (given) vs %s (expected)", pname, name)
+ p.errorf("%s package name mismatch: %s (given) vs %s (expected)", id, pname, name)
}
}
return pkg
diff --git a/src/go/types/eval.go b/src/go/types/eval.go
index 7b42ff1a9d..f928ee6923 100644
--- a/src/go/types/eval.go
+++ b/src/go/types/eval.go
@@ -44,7 +44,7 @@ func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (tv Typ
scope = pkg.scope
} else {
// The package scope extent (position information) may be
- // incorrect (files spread accross a wide range of fset
+ // incorrect (files spread across a wide range of fset
// positions) - ignore it and just consider its children
// (file scopes).
for _, fscope := range pkg.scope.children {
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index 14148a585b..1536df5bf1 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -483,11 +483,9 @@ func pkgName(path string) string {
// (Per the go/build package dependency tests, we cannot import
// path/filepath and simply use filepath.Dir.)
func dir(path string) string {
- if i := strings.LastIndexAny(path, "/\\"); i >= 0 {
- path = path[:i]
+ if i := strings.LastIndexAny(path, `/\`); i > 0 {
+ return path[:i]
}
- if path == "" {
- path = "."
- }
- return path
+ // i <= 0
+ return "."
}
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
index 09f2585bcf..97e6a69521 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -266,13 +266,16 @@ func walkDirs(t *testing.T, dir string) {
}
// typecheck package in directory
- files, err := pkgFilenames(dir)
- if err != nil {
- t.Error(err)
- return
- }
- if files != nil {
- typecheck(t, dir, files)
+ // but ignore files directly under $GOROOT/src (might be temporary test files).
+ if dir != filepath.Join(runtime.GOROOT(), "src") {
+ files, err := pkgFilenames(dir)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if files != nil {
+ typecheck(t, dir, files)
+ }
}
// traverse subdirectories, but don't walk into testdata
diff --git a/src/go/types/universe.go b/src/go/types/universe.go
index 40185c1ad4..cc3bd5a370 100644
--- a/src/go/types/universe.go
+++ b/src/go/types/universe.go
@@ -196,7 +196,7 @@ func init() {
//
func def(obj Object) {
name := obj.Name()
- if strings.Index(name, " ") >= 0 {
+ if strings.Contains(name, " ") {
return // nothing to do
}
// fix Obj link for named types
diff --git a/src/log/syslog/syslog.go b/src/log/syslog/syslog.go
index 4bf447626f..0e342242ec 100644
--- a/src/log/syslog/syslog.go
+++ b/src/log/syslog/syslog.go
@@ -85,7 +85,7 @@ type Writer struct {
}
// This interface and the separate syslog_unix.go file exist for
-// Solaris support as implemented by gccgo. On Solaris you can not
+// Solaris support as implemented by gccgo. On Solaris you cannot
// simply open a TCP connection to the syslog daemon. The gccgo
// sources have a syslog_solaris.go file that implements unixSyslog to
// return a type that satisfies this interface and simply calls the C
diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go
index 4566ff4e39..57df124e88 100644
--- a/src/math/big/ratconv.go
+++ b/src/math/big/ratconv.go
@@ -15,7 +15,7 @@ import (
)
func ratTok(ch rune) bool {
- return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+ return strings.ContainsRune("+-/0123456789.eE", ch)
}
// Scan is a support routine for fmt.Scanner. It accepts the formats
@@ -25,7 +25,7 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
if err != nil {
return err
}
- if strings.IndexRune("efgEFGv", ch) < 0 {
+ if !strings.ContainsRune("efgEFGv", ch) {
return errors.New("Rat.Scan: invalid verb")
}
if _, ok := z.SetString(string(tok)); !ok {
diff --git a/src/mime/encodedword.go b/src/mime/encodedword.go
index db4b5f4510..d219bbd393 100644
--- a/src/mime/encodedword.go
+++ b/src/mime/encodedword.go
@@ -89,7 +89,7 @@ func (e WordEncoder) bEncode(buf *bytes.Buffer, charset, s string) {
var currentLen, last, runeLen int
for i := 0; i < len(s); i += runeLen {
- // Multi-byte characters must not be split accross encoded-words.
+ // Multi-byte characters must not be split across encoded-words.
// See RFC 2047, section 5.3.
_, runeLen = utf8.DecodeRuneInString(s[i:])
@@ -119,7 +119,7 @@ func (e WordEncoder) qEncode(buf *bytes.Buffer, charset, s string) {
var currentLen, runeLen int
for i := 0; i < len(s); i += runeLen {
b := s[i]
- // Multi-byte characters must not be split accross encoded-words.
+ // Multi-byte characters must not be split across encoded-words.
// See RFC 2047, section 5.3.
var encLen int
if b >= ' ' && b <= '~' && b != '=' && b != '?' && b != '_' {
diff --git a/src/mime/grammar.go b/src/mime/grammar.go
index 31b66e8f03..6a6f71dbd4 100644
--- a/src/mime/grammar.go
+++ b/src/mime/grammar.go
@@ -11,7 +11,7 @@ import (
// isTSpecial reports whether rune is in 'tspecials' as defined by RFC
// 1521 and RFC 2045.
func isTSpecial(r rune) bool {
- return strings.IndexRune(`()<>@,;:\"/[]?=`, r) != -1
+ return strings.ContainsRune(`()<>@,;:\"/[]?=`, r)
}
// isTokenChar reports whether rune is in 'token' as defined by RFC
diff --git a/src/net/dial.go b/src/net/dial.go
index 193776fe41..0661c3ecdf 100644
--- a/src/net/dial.go
+++ b/src/net/dial.go
@@ -6,6 +6,7 @@ package net
import (
"errors"
+ "runtime"
"time"
)
@@ -225,8 +226,10 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
finalDeadline: finalDeadline,
}
+ // DualStack mode requires that dialTCP support cancelation. This is
+ // not available on plan9 (golang.org/issue/11225), so we ignore it.
var primaries, fallbacks addrList
- if d.DualStack && network == "tcp" {
+ if d.DualStack && network == "tcp" && runtime.GOOS != "plan9" {
primaries, fallbacks = addrs.partition(isIPv4)
} else {
primaries = addrs
@@ -236,9 +239,9 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
if len(fallbacks) == 0 {
// dialParallel can accept an empty fallbacks list,
// but this shortcut avoids the goroutine/channel overhead.
- c, err = dialSerial(ctx, primaries, nil)
+ c, err = dialSerial(ctx, primaries, ctx.Cancel)
} else {
- c, err = dialParallel(ctx, primaries, fallbacks)
+ c, err = dialParallel(ctx, primaries, fallbacks, ctx.Cancel)
}
if d.KeepAlive > 0 && err == nil {
@@ -255,10 +258,9 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
// head start. It returns the first established connection and
// closes the others. Otherwise it returns an error from the first
// primary address.
-func dialParallel(ctx *dialContext, primaries, fallbacks addrList) (Conn, error) {
- results := make(chan dialResult) // unbuffered, so dialSerialAsync can detect race loss & cleanup
+func dialParallel(ctx *dialContext, primaries, fallbacks addrList, userCancel <-chan struct{}) (Conn, error) {
+ results := make(chan dialResult, 2)
cancel := make(chan struct{})
- defer close(cancel)
// Spawn the primary racer.
go dialSerialAsync(ctx, primaries, nil, cancel, results)
@@ -267,28 +269,59 @@ func dialParallel(ctx *dialContext, primaries, fallbacks addrList) (Conn, error)
fallbackTimer := time.NewTimer(ctx.fallbackDelay())
go dialSerialAsync(ctx, fallbacks, fallbackTimer, cancel, results)
- var primaryErr error
- for nracers := 2; nracers > 0; nracers-- {
- res := <-results
- // If we're still waiting for a connection, then hasten the delay.
- // Otherwise, disable the Timer and let cancel take over.
- if fallbackTimer.Stop() && res.error != nil {
- fallbackTimer.Reset(0)
- }
- if res.error == nil {
- return res.Conn, nil
- }
- if res.primary {
- primaryErr = res.error
+ // Wait for both racers to succeed or fail.
+ var primaryResult, fallbackResult dialResult
+ for !primaryResult.done || !fallbackResult.done {
+ select {
+ case <-userCancel:
+ // Forward an external cancelation request.
+ if cancel != nil {
+ close(cancel)
+ cancel = nil
+ }
+ userCancel = nil
+ case res := <-results:
+ // Drop the result into its assigned bucket.
+ if res.primary {
+ primaryResult = res
+ } else {
+ fallbackResult = res
+ }
+ // On success, cancel the other racer (if one exists.)
+ if res.error == nil && cancel != nil {
+ close(cancel)
+ cancel = nil
+ }
+ // If the fallbackTimer was pending, then either we've canceled the
+ // fallback because we no longer want it, or we haven't canceled yet
+ // and therefore want it to wake up immediately.
+ if fallbackTimer.Stop() && cancel != nil {
+ fallbackTimer.Reset(0)
+ }
}
}
- return nil, primaryErr
+
+ // Return, in order of preference:
+ // 1. The primary connection (but close the other if we got both.)
+ // 2. The fallback connection.
+ // 3. The primary error.
+ if primaryResult.error == nil {
+ if fallbackResult.error == nil {
+ fallbackResult.Conn.Close()
+ }
+ return primaryResult.Conn, nil
+ } else if fallbackResult.error == nil {
+ return fallbackResult.Conn, nil
+ } else {
+ return nil, primaryResult.error
+ }
}
type dialResult struct {
Conn
error
primary bool
+ done bool
}
// dialSerialAsync runs dialSerial after some delay, and returns the
@@ -300,19 +333,11 @@ func dialSerialAsync(ctx *dialContext, ras addrList, timer *time.Timer, cancel <
select {
case <-timer.C:
case <-cancel:
- return
+ // dialSerial will immediately return errCanceled in this case.
}
}
c, err := dialSerial(ctx, ras, cancel)
- select {
- case results <- dialResult{c, err, timer == nil}:
- // We won the race.
- case <-cancel:
- // The other goroutine won the race.
- if c != nil {
- c.Close()
- }
- }
+ results <- dialResult{Conn: c, error: err, primary: timer == nil, done: true}
}
// dialSerial connects to a list of addresses in sequence, returning
@@ -336,11 +361,11 @@ func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, e
break
}
- // dialTCP does not support cancelation (see golang.org/issue/11225),
- // so if cancel fires, we'll continue trying to connect until the next
- // timeout, or return a spurious connection for the caller to close.
+ // If this dial is canceled, the implementation is expected to complete
+ // quickly, but it's still possible that we could return a spurious Conn,
+ // which the caller must Close.
dialer := func(d time.Time) (Conn, error) {
- return dialSingle(ctx, ra, d)
+ return dialSingle(ctx, ra, d, cancel)
}
c, err := dial(ctx.network, ra, dialer, partialDeadline)
if err == nil {
@@ -360,7 +385,7 @@ func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, e
// dialSingle attempts to establish and returns a single connection to
// the destination address. This must be called through the OS-specific
// dial function, because some OSes don't implement the deadline feature.
-func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err error) {
+func dialSingle(ctx *dialContext, ra Addr, deadline time.Time, cancel <-chan struct{}) (c Conn, err error) {
la := ctx.LocalAddr
if la != nil && la.Network() != ra.Network() {
return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
@@ -368,7 +393,7 @@ func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err erro
switch ra := ra.(type) {
case *TCPAddr:
la, _ := la.(*TCPAddr)
- c, err = testHookDialTCP(ctx.network, la, ra, deadline, ctx.Cancel)
+ c, err = testHookDialTCP(ctx.network, la, ra, deadline, cancel)
case *UDPAddr:
la, _ := la.(*UDPAddr)
c, err = dialUDP(ctx.network, la, ra, deadline)
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 2311b10824..1df923f14b 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -176,6 +176,7 @@ func TestDialerDualStackFDLeak(t *testing.T) {
t.Skip("both IPv4 and IPv6 are required")
}
+ before := sw.Sockets()
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
testHookLookupIP = lookupLocalhost
@@ -195,17 +196,15 @@ func TestDialerDualStackFDLeak(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- defer dss.teardown()
if err := dss.buildup(handler); err != nil {
+ dss.teardown()
t.Fatal(err)
}
- before := sw.Sockets()
- const T = 100 * time.Millisecond
const N = 10
var wg sync.WaitGroup
wg.Add(N)
- d := &Dialer{DualStack: true, Timeout: T}
+ d := &Dialer{DualStack: true, Timeout: 100 * time.Millisecond}
for i := 0; i < N; i++ {
go func() {
defer wg.Done()
@@ -218,7 +217,7 @@ func TestDialerDualStackFDLeak(t *testing.T) {
}()
}
wg.Wait()
- time.Sleep(2 * T) // wait for the dial racers to stop
+ dss.teardown()
after := sw.Sockets()
if len(after) != len(before) {
t.Errorf("got %d; want %d", len(after), len(before))
@@ -229,9 +228,8 @@ func TestDialerDualStackFDLeak(t *testing.T) {
// expected to hang until the timeout elapses. These addresses are reserved
// for benchmarking by RFC 6890.
const (
- slowDst4 = "192.18.0.254"
- slowDst6 = "2001:2::254"
- slowTimeout = 1 * time.Second
+ slowDst4 = "198.18.0.254"
+ slowDst6 = "2001:2::254"
)
// In some environments, the slow IPs may be explicitly unreachable, and fail
@@ -240,7 +238,10 @@ const (
func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
c, err := dialTCP(net, laddr, raddr, deadline, cancel)
if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
- time.Sleep(deadline.Sub(time.Now()))
+ select {
+ case <-cancel:
+ case <-time.After(deadline.Sub(time.Now())):
+ }
}
return c, err
}
@@ -284,6 +285,9 @@ func TestDialParallel(t *testing.T) {
if !supportsIPv4 || !supportsIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping on plan9; cannot cancel dialTCP, golang.org/issue/11225")
+ }
closedPortDelay, expectClosedPortDelay := dialClosedPort()
if closedPortDelay > expectClosedPortDelay {
@@ -389,7 +393,6 @@ func TestDialParallel(t *testing.T) {
fallbacks := makeAddrs(tt.fallbacks, dss.port)
d := Dialer{
FallbackDelay: fallbackDelay,
- Timeout: slowTimeout,
}
ctx := &dialContext{
Dialer: d,
@@ -398,7 +401,7 @@ func TestDialParallel(t *testing.T) {
finalDeadline: d.deadline(time.Now()),
}
startTime := time.Now()
- c, err := dialParallel(ctx, primaries, fallbacks)
+ c, err := dialParallel(ctx, primaries, fallbacks, nil)
elapsed := time.Now().Sub(startTime)
if c != nil {
@@ -418,9 +421,27 @@ func TestDialParallel(t *testing.T) {
} else if !(elapsed <= expectElapsedMax) {
t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
}
+
+ // Repeat each case, ensuring that it can be canceled quickly.
+ cancel := make(chan struct{})
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ time.Sleep(5 * time.Millisecond)
+ close(cancel)
+ wg.Done()
+ }()
+ startTime = time.Now()
+ c, err = dialParallel(ctx, primaries, fallbacks, cancel)
+ if c != nil {
+ c.Close()
+ }
+ elapsed = time.Now().Sub(startTime)
+ if elapsed > 100*time.Millisecond {
+ t.Errorf("#%d (cancel): got %v; want <= 100ms", i, elapsed)
+ }
+ wg.Wait()
}
- // Wait for any slowDst4/slowDst6 connections to timeout.
- time.Sleep(slowTimeout * 3 / 2)
}
func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
@@ -463,8 +484,6 @@ func TestDialerFallbackDelay(t *testing.T) {
{true, 200 * time.Millisecond, 200 * time.Millisecond},
// The default is 300ms.
{true, 0, 300 * time.Millisecond},
- // This case is last, in order to wait for hanging slowDst6 connections.
- {false, 0, slowTimeout},
}
handler := func(dss *dualStackServer, ln Listener) {
@@ -488,7 +507,7 @@ func TestDialerFallbackDelay(t *testing.T) {
}
for i, tt := range testCases {
- d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout}
+ d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay}
startTime := time.Now()
c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
@@ -509,17 +528,58 @@ func TestDialerFallbackDelay(t *testing.T) {
}
}
-func TestDialSerialAsyncSpuriousConnection(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping on plan9; no deadline support, golang.org/issue/11932")
+func TestDialParallelSpuriousConnection(t *testing.T) {
+ if !supportsIPv4 || !supportsIPv6 {
+ t.Skip("both IPv4 and IPv6 are required")
}
- ln, err := newLocalListener("tcp")
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping on plan9; cannot cancel dialTCP, golang.org/issue/11225")
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+ handler := func(dss *dualStackServer, ln Listener) {
+ // Accept one connection per address.
+ c, err := ln.Accept()
+ if err != nil {
+ t.Fatal(err)
+ }
+ // The client should close itself, without sending data.
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
+ var b [1]byte
+ if _, err := c.Read(b[:]); err != io.EOF {
+ t.Errorf("got %v; want %v", err, io.EOF)
+ }
+ c.Close()
+ wg.Done()
+ }
+ dss, err := newDualStackServer([]streamListener{
+ {network: "tcp4", address: "127.0.0.1"},
+ {network: "tcp6", address: "::1"},
+ })
if err != nil {
t.Fatal(err)
}
- defer ln.Close()
+ defer dss.teardown()
+ if err := dss.buildup(handler); err != nil {
+ t.Fatal(err)
+ }
- d := Dialer{}
+ const fallbackDelay = 100 * time.Millisecond
+
+ origTestHookDialTCP := testHookDialTCP
+ defer func() { testHookDialTCP = origTestHookDialTCP }()
+ testHookDialTCP = func(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
+ // Sleep long enough for Happy Eyeballs to kick in, and inhibit cancelation.
+ // This forces dialParallel to juggle two successful connections.
+ time.Sleep(fallbackDelay * 2)
+ cancel = nil
+ return dialTCP(net, laddr, raddr, deadline, cancel)
+ }
+
+ d := Dialer{
+ FallbackDelay: fallbackDelay,
+ }
ctx := &dialContext{
Dialer: d,
network: "tcp",
@@ -527,28 +587,23 @@ func TestDialSerialAsyncSpuriousConnection(t *testing.T) {
finalDeadline: d.deadline(time.Now()),
}
- results := make(chan dialResult)
- cancel := make(chan struct{})
+ makeAddr := func(ip string) addrList {
+ addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port))
+ if err != nil {
+ t.Fatal(err)
+ }
+ return addrList{addr}
+ }
- // Spawn a connection in the background.
- go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results)
-
- // Receive it at the server.
- c, err := ln.Accept()
+ // dialParallel returns one connection (and closes the other.)
+ c, err := dialParallel(ctx, makeAddr("127.0.0.1"), makeAddr("::1"), nil)
if err != nil {
t.Fatal(err)
}
- defer c.Close()
+ c.Close()
- // Tell dialSerialAsync that someone else won the race.
- close(cancel)
-
- // The connection should close itself, without sending data.
- c.SetReadDeadline(time.Now().Add(1 * time.Second))
- var b [1]byte
- if _, err := c.Read(b[:]); err != io.EOF {
- t.Errorf("got %v; want %v", err, io.EOF)
- }
+ // The server should've seen both connections.
+ wg.Wait()
}
func TestDialerPartialDeadline(t *testing.T) {
@@ -677,7 +732,6 @@ func TestDialerDualStack(t *testing.T) {
c.Close()
}
}
- time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop
}
func TestDialerKeepAlive(t *testing.T) {
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 17188f0024..736e57322c 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -229,7 +229,6 @@ type resolverConfig struct {
// time to recheck resolv.conf.
ch chan struct{} // guards lastChecked and modTime
lastChecked time.Time // last time resolv.conf was checked
- modTime time.Time // time of resolv.conf modification
mu sync.RWMutex // protects dnsConfig
dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups
@@ -239,16 +238,12 @@ var resolvConf resolverConfig
// init initializes conf and is only called via conf.initOnce.
func (conf *resolverConfig) init() {
- // Set dnsConfig, modTime, and lastChecked so we don't parse
+ // Set dnsConfig and lastChecked so we don't parse
// resolv.conf twice the first time.
conf.dnsConfig = systemConf().resolv
if conf.dnsConfig == nil {
conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
}
-
- if fi, err := os.Stat("/etc/resolv.conf"); err == nil {
- conf.modTime = fi.ModTime()
- }
conf.lastChecked = time.Now()
// Prepare ch so that only one update of resolverConfig may
@@ -274,17 +269,12 @@ func (conf *resolverConfig) tryUpdate(name string) {
}
conf.lastChecked = now
+ var mtime time.Time
if fi, err := os.Stat(name); err == nil {
- if fi.ModTime().Equal(conf.modTime) {
- return
- }
- conf.modTime = fi.ModTime()
- } else {
- // If modTime wasn't set prior, assume nothing has changed.
- if conf.modTime.IsZero() {
- return
- }
- conf.modTime = time.Time{}
+ mtime = fi.ModTime()
+ }
+ if mtime.Equal(conf.dnsConfig.mtime) {
+ return
}
dnsConf := dnsReadConfig(name)
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 934f25b2c9..d7f00c784d 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -124,20 +124,20 @@ func (conf *resolvConfTest) writeAndUpdate(lines []string) error {
return err
}
f.Close()
- if err := conf.forceUpdate(conf.path); err != nil {
+ if err := conf.forceUpdate(conf.path, time.Now().Add(time.Hour)); err != nil {
return err
}
return nil
}
-func (conf *resolvConfTest) forceUpdate(name string) error {
+func (conf *resolvConfTest) forceUpdate(name string, lastChecked time.Time) error {
dnsConf := dnsReadConfig(name)
conf.mu.Lock()
conf.dnsConfig = dnsConf
conf.mu.Unlock()
for i := 0; i < 5; i++ {
if conf.tryAcquireSema() {
- conf.lastChecked = time.Time{}
+ conf.lastChecked = lastChecked
conf.releaseSema()
return nil
}
@@ -153,7 +153,7 @@ func (conf *resolvConfTest) servers() []string {
}
func (conf *resolvConfTest) teardown() error {
- err := conf.forceUpdate("/etc/resolv.conf")
+ err := conf.forceUpdate("/etc/resolv.conf", time.Time{})
os.RemoveAll(conf.dir)
return err
}
@@ -353,7 +353,6 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) {
t.Error(err)
continue
}
- conf.tryUpdate(conf.path)
addrs, err := goLookupIP(tt.name)
if err != nil {
if err, ok := err.(*DNSError); !ok || (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) {
@@ -392,7 +391,6 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
if err := conf.writeAndUpdate([]string{}); err != nil {
t.Fatal(err)
}
- conf.tryUpdate(conf.path)
// Redirect host file lookups.
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
testHookHostsPath = "testdata/hosts"
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index 6073fdb6d8..0515ca90de 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -8,18 +8,21 @@
package net
+import "time"
+
var defaultNS = []string{"127.0.0.1", "::1"}
type dnsConfig struct {
- servers []string // servers to use
- search []string // suffixes to append to local name
- ndots int // number of dots in name to trigger absolute lookup
- timeout int // seconds before giving up on packet
- attempts int // lost packets before giving up on server
- rotate bool // round robin among servers
- unknownOpt bool // anything unknown was encountered
- lookup []string // OpenBSD top-level database "lookup" order
- err error // any error that occurs during open of resolv.conf
+ servers []string // servers to use
+ search []string // suffixes to append to local name
+ ndots int // number of dots in name to trigger absolute lookup
+ timeout int // seconds before giving up on packet
+ attempts int // lost packets before giving up on server
+ rotate bool // round robin among servers
+ unknownOpt bool // anything unknown was encountered
+ lookup []string // OpenBSD top-level database "lookup" order
+ err error // any error that occurs during open of resolv.conf
+ mtime time.Time // time of resolv.conf modification
}
// See resolv.conf(5) on a Linux machine.
@@ -38,6 +41,13 @@ func dnsReadConfig(filename string) *dnsConfig {
return conf
}
defer file.close()
+ if fi, err := file.file.Stat(); err == nil {
+ conf.mtime = fi.ModTime()
+ } else {
+ conf.servers = defaultNS
+ conf.err = err
+ return conf
+ }
for line, ok := file.readLine(); ok; line, ok = file.readLine() {
if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
// comment.
diff --git a/src/net/dnsconfig_unix_test.go b/src/net/dnsconfig_unix_test.go
index c8eed61890..849c0da93b 100644
--- a/src/net/dnsconfig_unix_test.go
+++ b/src/net/dnsconfig_unix_test.go
@@ -10,6 +10,7 @@ import (
"os"
"reflect"
"testing"
+ "time"
)
var dnsReadConfigTests = []struct {
@@ -76,6 +77,7 @@ func TestDNSReadConfig(t *testing.T) {
if conf.err != nil {
t.Fatal(conf.err)
}
+ conf.mtime = time.Time{}
if !reflect.DeepEqual(conf, tt.want) {
t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want)
}
diff --git a/src/net/dnsmsg.go b/src/net/dnsmsg.go
index 93078fe849..5747fd232b 100644
--- a/src/net/dnsmsg.go
+++ b/src/net/dnsmsg.go
@@ -315,7 +315,7 @@ func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
if !f(&txt, "Txt", "") {
return false
}
- // more bytes than rr.Hdr.Rdlength said there woudld be
+ // more bytes than rr.Hdr.Rdlength said there would be
if rr.Hdr.Rdlength-n < uint16(len(txt))+1 {
return false
}
@@ -406,6 +406,13 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
s += "."
}
+ // Allow root domain.
+ if s == "." {
+ msg[off] = 0
+ off++
+ return off, true
+ }
+
// Each dot ends a segment of the name.
// We trade each dot byte for a length byte.
// There is also a trailing zero.
@@ -422,8 +429,13 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
if i-begin >= 1<<6 { // top two bits of length must be clear
return len(msg), false
}
+ if i-begin == 0 {
+ return len(msg), false
+ }
+
msg[off] = byte(i - begin)
off++
+
for j := begin; j < i; j++ {
msg[off] = s[j]
off++
@@ -494,6 +506,9 @@ Loop:
return "", len(msg), false
}
}
+ if len(s) == 0 {
+ s = "."
+ }
if ptr == 0 {
off1 = off
}
@@ -803,20 +818,32 @@ func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
// Pack it in: header and then the pieces.
off := 0
off, ok = packStruct(&dh, msg, off)
+ if !ok {
+ return nil, false
+ }
for i := 0; i < len(question); i++ {
off, ok = packStruct(&question[i], msg, off)
+ if !ok {
+ return nil, false
+ }
}
for i := 0; i < len(answer); i++ {
off, ok = packRR(answer[i], msg, off)
+ if !ok {
+ return nil, false
+ }
}
for i := 0; i < len(ns); i++ {
off, ok = packRR(ns[i], msg, off)
+ if !ok {
+ return nil, false
+ }
}
for i := 0; i < len(extra); i++ {
off, ok = packRR(extra[i], msg, off)
- }
- if !ok {
- return nil, false
+ if !ok {
+ return nil, false
+ }
}
return msg[0:off], true
}
@@ -848,6 +875,9 @@ func (dns *dnsMsg) Unpack(msg []byte) bool {
for i := 0; i < len(dns.question); i++ {
off, ok = unpackStruct(&dns.question[i], msg, off)
+ if !ok {
+ return false
+ }
}
for i := 0; i < int(dh.Ancount); i++ {
rec, off, ok = unpackRR(msg, off)
diff --git a/src/net/dnsmsg_test.go b/src/net/dnsmsg_test.go
index 1078d77ceb..339fb83c62 100644
--- a/src/net/dnsmsg_test.go
+++ b/src/net/dnsmsg_test.go
@@ -10,6 +10,103 @@ import (
"testing"
)
+func TestStructPackUnpack(t *testing.T) {
+ want := dnsQuestion{
+ Name: ".",
+ Qtype: dnsTypeA,
+ Qclass: dnsClassINET,
+ }
+ buf := make([]byte, 50)
+ n, ok := packStruct(&want, buf, 0)
+ if !ok {
+ t.Fatal("packing failed")
+ }
+ buf = buf[:n]
+ got := dnsQuestion{}
+ n, ok = unpackStruct(&got, buf, 0)
+ if !ok {
+ t.Fatal("unpacking failed")
+ }
+ if n != len(buf) {
+ t.Error("unpacked different amount than packed: got n = %d, want = %d", n, len(buf))
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got = %+v, want = %+v", got, want)
+ }
+}
+
+func TestDomainNamePackUnpack(t *testing.T) {
+ tests := []struct {
+ in string
+ want string
+ ok bool
+ }{
+ {"", ".", true},
+ {".", ".", true},
+ {"google..com", "", false},
+ {"google.com", "google.com.", true},
+ {"google..com.", "", false},
+ {"google.com.", "google.com.", true},
+ {".google.com.", "", false},
+ {"www..google.com.", "", false},
+ {"www.google.com.", "www.google.com.", true},
+ }
+
+ for _, test := range tests {
+ buf := make([]byte, 30)
+ n, ok := packDomainName(test.in, buf, 0)
+ if ok != test.ok {
+ t.Errorf("packing of %s: got ok = %t, want = %t", test.in, ok, test.ok)
+ continue
+ }
+ if !test.ok {
+ continue
+ }
+ buf = buf[:n]
+ got, n, ok := unpackDomainName(buf, 0)
+ if !ok {
+ t.Errorf("unpacking for %s failed", test.in)
+ continue
+ }
+ if n != len(buf) {
+ t.Error(
+ "unpacked different amount than packed for %s: got n = %d, want = %d",
+ test.in,
+ n,
+ len(buf),
+ )
+ }
+ if got != test.want {
+ t.Errorf("unpacking packing of %s: got = %s, want = %s", test.in, got, test.want)
+ }
+ }
+}
+
+func TestDNSPackUnpack(t *testing.T) {
+ want := dnsMsg{
+ question: []dnsQuestion{{
+ Name: ".",
+ Qtype: dnsTypeAAAA,
+ Qclass: dnsClassINET,
+ }},
+ answer: []dnsRR{},
+ ns: []dnsRR{},
+ extra: []dnsRR{},
+ }
+ b, ok := want.Pack()
+ if !ok {
+ t.Fatal("packing failed")
+ }
+ var got dnsMsg
+ ok = got.Unpack(b)
+ if !ok {
+ t.Fatal("unpacking failed")
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got = %+v, want = %+v", got, want)
+ }
+}
+
func TestDNSParseSRVReply(t *testing.T) {
data, err := hex.DecodeString(dnsSRVReply)
if err != nil {
diff --git a/src/net/error_plan9_test.go b/src/net/error_plan9_test.go
index 495ea96534..d7c7f1487f 100644
--- a/src/net/error_plan9_test.go
+++ b/src/net/error_plan9_test.go
@@ -9,6 +9,8 @@ import "syscall"
var (
errTimedout = syscall.ETIMEDOUT
errOpNotSupported = syscall.EPLAN9
+
+ abortedConnRequestErrors []error
)
func isPlatformError(err error) bool {
diff --git a/src/net/error_posix_test.go b/src/net/error_posix_test.go
index 981cc837ba..b411a378df 100644
--- a/src/net/error_posix_test.go
+++ b/src/net/error_posix_test.go
@@ -12,16 +12,6 @@ import (
"testing"
)
-var (
- errTimedout = syscall.ETIMEDOUT
- errOpNotSupported = syscall.EOPNOTSUPP
-)
-
-func isPlatformError(err error) bool {
- _, ok := err.(syscall.Errno)
- return ok
-}
-
func TestSpuriousENOTAVAIL(t *testing.T) {
for _, tt := range []struct {
error
diff --git a/src/net/error_unix_test.go b/src/net/error_unix_test.go
new file mode 100644
index 0000000000..db66d0acf1
--- /dev/null
+++ b/src/net/error_unix_test.go
@@ -0,0 +1,21 @@
+// Copyright 2015 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.
+
+// +build !plan9,!windows
+
+package net
+
+import "syscall"
+
+var (
+ errTimedout = syscall.ETIMEDOUT
+ errOpNotSupported = syscall.EOPNOTSUPP
+
+ abortedConnRequestErrors = []error{syscall.ECONNABORTED} // see accept in fd_unix.go
+)
+
+func isPlatformError(err error) bool {
+ _, ok := err.(syscall.Errno)
+ return ok
+}
diff --git a/src/net/error_windows_test.go b/src/net/error_windows_test.go
new file mode 100644
index 0000000000..834a9de441
--- /dev/null
+++ b/src/net/error_windows_test.go
@@ -0,0 +1,19 @@
+// Copyright 2015 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 net
+
+import "syscall"
+
+var (
+ errTimedout = syscall.ETIMEDOUT
+ errOpNotSupported = syscall.EOPNOTSUPP
+
+ abortedConnRequestErrors = []error{syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET} // see accept in fd_windows.go
+)
+
+func isPlatformError(err error) bool {
+ _, ok := err.(syscall.Errno)
+ return ok
+}
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index fd50d772d6..abdee9d02c 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -579,7 +579,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
o.handle = s
o.rsan = int32(unsafe.Sizeof(rawsa[0]))
_, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error {
- return syscall.AcceptEx(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o)
+ return acceptFunc(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o)
})
if err != nil {
netfd.Close()
diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go
index 126b0ebdd1..63ea35ab8c 100644
--- a/src/net/hook_windows.go
+++ b/src/net/hook_windows.go
@@ -13,9 +13,10 @@ var (
testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349
// Placeholders for socket system calls.
- socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket
- closeFunc func(syscall.Handle) error = syscall.Closesocket
- connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect
- connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
- listenFunc func(syscall.Handle, int) error = syscall.Listen
+ socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket
+ closeFunc func(syscall.Handle) error = syscall.Closesocket
+ connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect
+ connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
+ listenFunc func(syscall.Handle, int) error = syscall.Listen
+ acceptFunc func(syscall.Handle, syscall.Handle, *byte, uint32, uint32, uint32, *uint32, *syscall.Overlapped) error = syscall.AcceptEx
)
diff --git a/src/net/hosts.go b/src/net/hosts.go
index c4de1b6a97..9c101c6ef5 100644
--- a/src/net/hosts.go
+++ b/src/net/hosts.go
@@ -110,7 +110,9 @@ func lookupStaticHost(host string) []string {
lowerHost := []byte(host)
lowerASCIIBytes(lowerHost)
if ips, ok := hosts.byName[absDomainName(lowerHost)]; ok {
- return ips
+ ipsCp := make([]string, len(ips))
+ copy(ipsCp, ips)
+ return ipsCp
}
}
return nil
@@ -127,7 +129,9 @@ func lookupStaticAddr(addr string) []string {
}
if len(hosts.byAddr) != 0 {
if hosts, ok := hosts.byAddr[addr]; ok {
- return hosts
+ hostsCp := make([]string, len(hosts))
+ copy(hostsCp, hosts)
+ return hostsCp
}
}
return nil
diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go
index 4c67bfa982..5d6c9cfe19 100644
--- a/src/net/hosts_test.go
+++ b/src/net/hosts_test.go
@@ -64,13 +64,17 @@ func TestLookupStaticHost(t *testing.T) {
for _, tt := range lookupStaticHostTests {
testHookHostsPath = tt.name
for _, ent := range tt.ents {
- ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
- for _, in := range ins {
- addrs := lookupStaticHost(in)
- if !reflect.DeepEqual(addrs, ent.out) {
- t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, in, addrs, ent.out)
- }
- }
+ testStaticHost(t, tt.name, ent)
+ }
+ }
+}
+
+func testStaticHost(t *testing.T, hostsPath string, ent staticHostEntry) {
+ ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
+ for _, in := range ins {
+ addrs := lookupStaticHost(in)
+ if !reflect.DeepEqual(addrs, ent.out) {
+ t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", hostsPath, in, addrs, ent.out)
}
}
}
@@ -129,13 +133,43 @@ func TestLookupStaticAddr(t *testing.T) {
for _, tt := range lookupStaticAddrTests {
testHookHostsPath = tt.name
for _, ent := range tt.ents {
- hosts := lookupStaticAddr(ent.in)
- for i := range ent.out {
- ent.out[i] = absDomainName([]byte(ent.out[i]))
- }
- if !reflect.DeepEqual(hosts, ent.out) {
- t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", tt.name, ent.in, hosts, ent.out)
- }
+ testStaticAddr(t, tt.name, ent)
}
}
}
+
+func testStaticAddr(t *testing.T, hostsPath string, ent staticHostEntry) {
+ hosts := lookupStaticAddr(ent.in)
+ for i := range ent.out {
+ ent.out[i] = absDomainName([]byte(ent.out[i]))
+ }
+ if !reflect.DeepEqual(hosts, ent.out) {
+ t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", hostsPath, ent.in, hosts, ent.out)
+ }
+}
+
+func TestHostCacheModification(t *testing.T) {
+ // Ensure that programs can't modify the internals of the host cache.
+ // See https://github.com/golang/go/issues/14212.
+ defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+
+ testHookHostsPath = "testdata/ipv4-hosts"
+ ent := staticHostEntry{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}
+ testStaticHost(t, testHookHostsPath, ent)
+ // Modify the addresses return by lookupStaticHost.
+ addrs := lookupStaticHost(ent.in)
+ for i := range addrs {
+ addrs[i] += "junk"
+ }
+ testStaticHost(t, testHookHostsPath, ent)
+
+ testHookHostsPath = "testdata/ipv6-hosts"
+ ent = staticHostEntry{"::1", []string{"localhost"}}
+ testStaticAddr(t, testHookHostsPath, ent)
+ // Modify the hosts return by lookupStaticAddr.
+ hosts := lookupStaticAddr(ent.in)
+ for i := range hosts {
+ hosts[i] += "junk"
+ }
+ testStaticAddr(t, testHookHostsPath, ent)
+}
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index f61c138c1d..520a5477a7 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -34,7 +34,7 @@ import (
type Dir string
func (d Dir) Open(name string) (File, error) {
- if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
+ if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) ||
strings.Contains(name, "\x00") {
return nil, errors.New("http: invalid character in file path")
}
@@ -451,7 +451,7 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) {
// ServeFile replies to the request with the contents of the named
// file or directory.
//
-// If the provided file or direcory name is a relative path, it is
+// If the provided file or directory name is a relative path, it is
// interpreted relative to the current directory and may ascend to parent
// directories. If the provided name is constructed from user input, it
// should be sanitized before calling ServeFile. As a precaution, ServeFile
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index c4faccc7a8..4e19b3e71f 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -1,5 +1,5 @@
-// Code generated by golang.org/x/tools/cmd/bundle command:
-// $ bundle golang.org/x/net/http2 net/http http2
+// Code generated by golang.org/x/tools/cmd/bundle.
+//go:generate bundle -o h2_bundle.go -prefix http2 -import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack golang.org/x/net/http2
// Package http2 implements the HTTP/2 protocol.
//
@@ -6141,13 +6141,18 @@ func (rt http2erringRoundTripper) RoundTrip(*Request) (*Response, error) { retur
// call gzip.NewReader on the first call to Read
type http2gzipReader struct {
body io.ReadCloser // underlying Response.Body
- zr io.Reader // lazily-initialized gzip reader
+ zr *gzip.Reader // lazily-initialized gzip reader
+ zerr error // sticky error
}
func (gz *http2gzipReader) Read(p []byte) (n int, err error) {
+ if gz.zerr != nil {
+ return 0, gz.zerr
+ }
if gz.zr == nil {
gz.zr, err = gzip.NewReader(gz.body)
if err != nil {
+ gz.zerr = err
return 0, err
}
}
diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go
index fabfeca943..7e52adb607 100644
--- a/src/net/http/httptest/server.go
+++ b/src/net/http/httptest/server.go
@@ -167,7 +167,7 @@ func (s *Server) Close() {
// few milliseconds wasn't liked (early versions of
// https://golang.org/cl/15151) so now we just
// forcefully close StateNew. The docs for Server.Close say
- // we wait for "oustanding requests", so we don't close things
+ // we wait for "outstanding requests", so we don't close things
// in StateActive.
if st == http.StateIdle || st == http.StateNew {
s.closeConn(c)
@@ -202,10 +202,31 @@ func (s *Server) logCloseHangDebugInfo() {
// CloseClientConnections closes any open HTTP connections to the test Server.
func (s *Server) CloseClientConnections() {
+ var conns int
+ ch := make(chan bool)
+
s.mu.Lock()
- defer s.mu.Unlock()
for c := range s.conns {
- s.closeConn(c)
+ conns++
+ s.closeConnChan(c, ch)
+ }
+ s.mu.Unlock()
+
+ // Wait for outstanding closes to finish.
+ //
+ // Out of paranoia for making a late change in Go 1.6, we
+ // bound how long this can wait, since golang.org/issue/14291
+ // isn't fully understood yet. At least this should only be used
+ // in tests.
+ timer := time.NewTimer(5 * time.Second)
+ defer timer.Stop()
+ for i := 0; i < conns; i++ {
+ select {
+ case <-ch:
+ case <-timer.C:
+ // Too slow. Give up.
+ return
+ }
}
}
@@ -267,9 +288,13 @@ func (s *Server) wrap() {
}
}
-// closeConn closes c. Except on plan9, which is special. See comment below.
+// closeConn closes c.
// s.mu must be held.
-func (s *Server) closeConn(c net.Conn) {
+func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) }
+
+// closeConnChan is like closeConn, but takes an optional channel to receive a value
+// when the goroutine closing c is done.
+func (s *Server) closeConnChan(c net.Conn, done chan<- bool) {
if runtime.GOOS == "plan9" {
// Go's Plan 9 net package isn't great at unblocking reads when
// their underlying TCP connections are closed. Don't trust
@@ -278,7 +303,21 @@ func (s *Server) closeConn(c net.Conn) {
// resources if the syscall doesn't end up returning. Oh well.
s.forgetConn(c)
}
- go c.Close()
+
+ // Somewhere in the chaos of https://golang.org/cl/15151 we found that
+ // some types of conns were blocking in Close too long (or deadlocking?)
+ // and we had to call Close in a goroutine. I (bradfitz) forget what
+ // that was at this point, but I suspect it was *tls.Conns, which
+ // were later fixed in https://golang.org/cl/18572, so this goroutine
+ // is _probably_ unnecessary now. But it's too late in Go 1.6 too remove
+ // it with confidence.
+ // TODO(bradfitz): try to remove it for Go 1.7. (golang.org/issue/14291)
+ go func() {
+ c.Close()
+ if done != nil {
+ done <- true
+ }
+ }()
}
// forgetConn removes c from the set of tracked conns and decrements it from the
diff --git a/src/net/http/httptest/server_test.go b/src/net/http/httptest/server_test.go
index 6ffc671e57..c9606f2419 100644
--- a/src/net/http/httptest/server_test.go
+++ b/src/net/http/httptest/server_test.go
@@ -84,3 +84,17 @@ func TestServerCloseBlocking(t *testing.T) {
ts.Close() // test we don't hang here forever.
}
+
+// Issue 14290
+func TestServerCloseClientConnections(t *testing.T) {
+ var s *Server
+ s = NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ s.CloseClientConnections()
+ }))
+ defer s.Close()
+ res, err := http.Get(s.URL)
+ if err == nil {
+ res.Body.Close()
+ t.Fatal("Unexpected response: %#v", res)
+ }
+}
diff --git a/src/net/http/httputil/dump.go b/src/net/http/httputil/dump.go
index e22cc66dbf..245eed0b21 100644
--- a/src/net/http/httputil/dump.go
+++ b/src/net/http/httputil/dump.go
@@ -264,19 +264,20 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
return
}
-// errNoBody is a sentinel error value used by failureToReadBody so we can detect
-// that the lack of body was intentional.
+// errNoBody is a sentinel error value used by failureToReadBody so we
+// can detect that the lack of body was intentional.
var errNoBody = errors.New("sentinel error value")
// failureToReadBody is a io.ReadCloser that just returns errNoBody on
-// Read. It's swapped in when we don't actually want to consume the
-// body, but need a non-nil one, and want to distinguish the error
-// from reading the dummy body.
+// Read. It's swapped in when we don't actually want to consume
+// the body, but need a non-nil one, and want to distinguish the
+// error from reading the dummy body.
type failureToReadBody struct{}
func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody }
func (failureToReadBody) Close() error { return nil }
+// emptyBody is an instance of empty reader.
var emptyBody = ioutil.NopCloser(strings.NewReader(""))
// DumpResponse is like DumpRequest but dumps a response.
@@ -286,7 +287,13 @@ func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
savecl := resp.ContentLength
if !body {
- resp.Body = failureToReadBody{}
+ // For content length of zero. Make sure the body is an empty
+ // reader, instead of returning error through failureToReadBody{}.
+ if resp.ContentLength == 0 {
+ resp.Body = emptyBody
+ } else {
+ resp.Body = failureToReadBody{}
+ }
} else if resp.Body == nil {
resp.Body = emptyBody
} else {
diff --git a/src/net/http/httputil/dump_test.go b/src/net/http/httputil/dump_test.go
index 46bf521723..fc884347a6 100644
--- a/src/net/http/httputil/dump_test.go
+++ b/src/net/http/httputil/dump_test.go
@@ -288,6 +288,27 @@ Transfer-Encoding: chunked
foo
0`,
},
+ {
+ res: &http.Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0,
+ Header: http.Header{
+ // To verify if headers are not filtered out.
+ "Foo1": []string{"Bar1"},
+ "Foo2": []string{"Bar2"},
+ },
+ Body: nil,
+ },
+ body: false, // to verify we see 0, not empty.
+ want: `HTTP/1.1 200 OK
+Foo1: Bar1
+Foo2: Bar2
+Content-Length: 0`,
+ },
}
func TestDumpResponse(t *testing.T) {
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 5e3b6084ae..e2d8d277e0 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -1009,7 +1009,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
w.closeAfterReply = true
}
default:
- // Some other kind of error occured, like a read timeout, or
+ // Some other kind of error occurred, like a read timeout, or
// corrupt chunked encoding. In any case, whatever remains
// on the wire must not be parsed as another HTTP request.
w.closeAfterReply = true
@@ -2032,7 +2032,7 @@ const (
// For HTTP/2, StateActive fires on the transition from zero
// to one active request, and only transitions away once all
// active requests are complete. That means that ConnState
- // can not be used to do per-request work; ConnState only notes
+ // cannot be used to do per-request work; ConnState only notes
// the overall state of the connection.
StateActive
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 41df906cf2..03e9162b14 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -163,6 +163,26 @@ func (t *Transport) onceSetNextProtoDefaults() {
return
}
if t.TLSNextProto != nil {
+ // This is the documented way to disable http2 on a
+ // Transport.
+ return
+ }
+ if t.TLSClientConfig != nil {
+ // Be conservative for now (for Go 1.6) at least and
+ // don't automatically enable http2 if they've
+ // specified a custom TLS config. Let them opt-in
+ // themselves via http2.ConfigureTransport so we don't
+ // surprise them by modifying their tls.Config.
+ // Issue 14275.
+ return
+ }
+ if t.ExpectContinueTimeout != 0 && t != DefaultTransport {
+ // ExpectContinueTimeout is unsupported in http2, so
+ // if they explicitly asked for it (as opposed to just
+ // using the DefaultTransport, which sets it), then
+ // disable http2 for now.
+ //
+ // Issue 13851. (and changed in Issue 14391)
return
}
t2, err := http2configureTransport(t)
@@ -398,7 +418,7 @@ func (t *Transport) CloseIdleConnections() {
// CancelRequest cancels an in-flight request by closing its connection.
// CancelRequest should only be called after RoundTrip has returned.
//
-// Deprecated: Use Request.Cancel instead. CancelRequest can not cancel
+// Deprecated: Use Request.Cancel instead. CancelRequest cannot cancel
// HTTP/2 requests.
func (t *Transport) CancelRequest(req *Request) {
t.reqMu.Lock()
@@ -1337,7 +1357,7 @@ type writeRequest struct {
req *transportRequest
ch chan<- error
- // Optional blocking chan for Expect: 100-continue (for recieve).
+ // Optional blocking chan for Expect: 100-continue (for receive).
// If not nil, writeLoop blocks sending request body until
// it receives from this chan.
continueCh <-chan struct{}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 8cb89a4220..d9da078fa0 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -2885,23 +2885,39 @@ func TestTransportPrefersResponseOverWriteError(t *testing.T) {
}
func TestTransportAutomaticHTTP2(t *testing.T) {
- tr := &Transport{}
+ testTransportAutoHTTP(t, &Transport{}, true)
+}
+
+// golang.org/issue/14391: also check DefaultTransport
+func TestTransportAutomaticHTTP2_DefaultTransport(t *testing.T) {
+ testTransportAutoHTTP(t, DefaultTransport.(*Transport), true)
+}
+
+func TestTransportAutomaticHTTP2_TLSNextProto(t *testing.T) {
+ testTransportAutoHTTP(t, &Transport{
+ TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper),
+ }, false)
+}
+
+func TestTransportAutomaticHTTP2_TLSConfig(t *testing.T) {
+ testTransportAutoHTTP(t, &Transport{
+ TLSClientConfig: new(tls.Config),
+ }, false)
+}
+
+func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) {
+ testTransportAutoHTTP(t, &Transport{
+ ExpectContinueTimeout: 1 * time.Second,
+ }, false)
+}
+
+func testTransportAutoHTTP(t *testing.T, tr *Transport, wantH2 bool) {
_, err := tr.RoundTrip(new(Request))
if err == nil {
t.Error("expected error from RoundTrip")
}
- if tr.TLSNextProto["h2"] == nil {
- t.Errorf("HTTP/2 not registered.")
- }
-
- // Now with TLSNextProto set:
- tr = &Transport{TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper)}
- _, err = tr.RoundTrip(new(Request))
- if err == nil {
- t.Error("expected error from RoundTrip")
- }
- if tr.TLSNextProto["h2"] != nil {
- t.Errorf("HTTP/2 registered, despite non-nil TLSNextProto field")
+ if reg := tr.TLSNextProto["h2"] != nil; reg != wantH2 {
+ t.Errorf("HTTP/2 registered = %v; want %v", reg, wantH2)
}
}
diff --git a/src/net/internal/socktest/switch.go b/src/net/internal/socktest/switch.go
index 8bef06b97c..3c37b6ff80 100644
--- a/src/net/internal/socktest/switch.go
+++ b/src/net/internal/socktest/switch.go
@@ -121,7 +121,7 @@ const (
FilterSocket FilterType = iota // for Socket
FilterConnect // for Connect or ConnectEx
FilterListen // for Listen
- FilterAccept // for Accept or Accept4
+ FilterAccept // for Accept, Accept4 or AcceptEx
FilterGetsockoptInt // for GetsockoptInt
FilterClose // for Close or Closesocket
)
diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go
index e61bf2be60..2e3d2bc7fc 100644
--- a/src/net/internal/socktest/sys_windows.go
+++ b/src/net/internal/socktest/sys_windows.go
@@ -154,3 +154,33 @@ func (sw *Switch) Listen(s syscall.Handle, backlog int) (err error) {
sw.stats.getLocked(so.Cookie).Listened++
return nil
}
+
+// AcceptEx wraps syscall.AcceptEx.
+func (sw *Switch) AcceptEx(ls syscall.Handle, as syscall.Handle, b *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, rcvd *uint32, overlapped *syscall.Overlapped) error {
+ so := sw.sockso(ls)
+ if so == nil {
+ return syscall.AcceptEx(ls, as, b, rxdatalen, laddrlen, raddrlen, rcvd, overlapped)
+ }
+ sw.fmu.RLock()
+ f, _ := sw.fltab[FilterAccept]
+ sw.fmu.RUnlock()
+
+ af, err := f.apply(so)
+ if err != nil {
+ return err
+ }
+ so.Err = syscall.AcceptEx(ls, as, b, rxdatalen, laddrlen, raddrlen, rcvd, overlapped)
+ if err = af.apply(so); err != nil {
+ return err
+ }
+
+ sw.smu.Lock()
+ defer sw.smu.Unlock()
+ if so.Err != nil {
+ sw.stats.getLocked(so.Cookie).AcceptFailed++
+ return so.Err
+ }
+ nso := sw.addLocked(as, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
+ sw.stats.getLocked(nso.Cookie).Accepted++
+ return nil
+}
diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go
index 2d829743ec..b879717425 100644
--- a/src/net/main_windows_test.go
+++ b/src/net/main_windows_test.go
@@ -11,6 +11,7 @@ var (
origConnect = connectFunc
origConnectEx = connectExFunc
origListen = listenFunc
+ origAccept = acceptFunc
)
func installTestHooks() {
@@ -19,6 +20,7 @@ func installTestHooks() {
connectFunc = sw.Connect
connectExFunc = sw.ConnectEx
listenFunc = sw.Listen
+ acceptFunc = sw.AcceptEx
}
func uninstallTestHooks() {
@@ -27,6 +29,7 @@ func uninstallTestHooks() {
connectFunc = origConnect
connectExFunc = origConnectEx
listenFunc = origListen
+ acceptFunc = origAccept
}
func forceCloseSockets() {
diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go
index dd6f4df3b9..38b317af7d 100644
--- a/src/net/mockserver_test.go
+++ b/src/net/mockserver_test.go
@@ -30,10 +30,20 @@ func testUnixAddr() string {
func newLocalListener(network string) (Listener, error) {
switch network {
- case "tcp", "tcp4", "tcp6":
+ case "tcp":
+ if supportsIPv4 {
+ if ln, err := Listen("tcp4", "127.0.0.1:0"); err == nil {
+ return ln, nil
+ }
+ }
+ if supportsIPv6 {
+ return Listen("tcp6", "[::1]:0")
+ }
+ case "tcp4":
if supportsIPv4 {
return Listen("tcp4", "127.0.0.1:0")
}
+ case "tcp6":
if supportsIPv6 {
return Listen("tcp6", "[::1]:0")
}
diff --git a/src/net/net_test.go b/src/net/net_test.go
index cd62b4373e..94392928c2 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -6,6 +6,7 @@ package net
import (
"io"
+ "net/internal/socktest"
"os"
"runtime"
"testing"
@@ -304,3 +305,58 @@ func TestListenCloseListen(t *testing.T) {
}
t.Fatalf("failed to listen/close/listen on same address after %d tries", maxTries)
}
+
+// See golang.org/issue/6163, golang.org/issue/6987.
+func TestAcceptIgnoreAbortedConnRequest(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+ }
+
+ syserr := make(chan error)
+ go func() {
+ defer close(syserr)
+ for _, err := range abortedConnRequestErrors {
+ syserr <- err
+ }
+ }()
+ sw.Set(socktest.FilterAccept, func(so *socktest.Status) (socktest.AfterFilter, error) {
+ if err, ok := <-syserr; ok {
+ return nil, err
+ }
+ return nil, nil
+ })
+ defer sw.Set(socktest.FilterAccept, nil)
+
+ operr := make(chan error, 1)
+ handler := func(ls *localServer, ln Listener) {
+ defer close(operr)
+ c, err := ln.Accept()
+ if err != nil {
+ if perr := parseAcceptError(err); perr != nil {
+ operr <- perr
+ }
+ operr <- err
+ return
+ }
+ c.Close()
+ }
+ ls, err := newLocalServer("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ls.teardown()
+ if err := ls.buildup(handler); err != nil {
+ t.Fatal(err)
+ }
+
+ c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+
+ for err := range operr {
+ t.Error(err)
+ }
+}
diff --git a/src/net/net_windows_test.go b/src/net/net_windows_test.go
index 095a339e02..df39032721 100644
--- a/src/net/net_windows_test.go
+++ b/src/net/net_windows_test.go
@@ -314,20 +314,43 @@ func TestInterfacesWithNetsh(t *testing.T) {
}
}
-func netshInterfaceIPv4ShowAddress(name string) ([]string, error) {
- out, err := runCmd("netsh", "interface", "ipv4", "show", "address", "name=\""+name+"\"")
- if err != nil {
- return nil, err
- }
+func netshInterfaceIPv4ShowAddress(name string, netshOutput []byte) []string {
// adress information is listed like:
+ //
+ //Configuration for interface "Local Area Connection"
+ // DHCP enabled: Yes
// IP Address: 10.0.0.2
// Subnet Prefix: 10.0.0.0/24 (mask 255.255.255.0)
// IP Address: 10.0.0.3
// Subnet Prefix: 10.0.0.0/24 (mask 255.255.255.0)
+ // Default Gateway: 10.0.0.254
+ // Gateway Metric: 0
+ // InterfaceMetric: 10
+ //
+ //Configuration for interface "Loopback Pseudo-Interface 1"
+ // DHCP enabled: No
+ // IP Address: 127.0.0.1
+ // Subnet Prefix: 127.0.0.0/8 (mask 255.0.0.0)
+ // InterfaceMetric: 50
+ //
addrs := make([]string, 0)
var addr, subnetprefix string
- lines := bytes.Split(out, []byte{'\r', '\n'})
+ var processingOurInterface bool
+ lines := bytes.Split(netshOutput, []byte{'\r', '\n'})
for _, line := range lines {
+ if !processingOurInterface {
+ if !bytes.HasPrefix(line, []byte("Configuration for interface")) {
+ continue
+ }
+ if !bytes.Contains(line, []byte(`"`+name+`"`)) {
+ continue
+ }
+ processingOurInterface = true
+ continue
+ }
+ if len(line) == 0 {
+ break
+ }
if bytes.Contains(line, []byte("Subnet Prefix:")) {
f := bytes.Split(line, []byte{':'})
if len(f) == 2 {
@@ -351,18 +374,50 @@ func netshInterfaceIPv4ShowAddress(name string) ([]string, error) {
}
}
}
- return addrs, nil
+ return addrs
}
-func netshInterfaceIPv6ShowAddress(name string) ([]string, error) {
+func netshInterfaceIPv6ShowAddress(name string, netshOutput []byte) []string {
+ // adress information is listed like:
+ //
+ //Address ::1 Parameters
+ //---------------------------------------------------------
+ //Interface Luid : Loopback Pseudo-Interface 1
+ //Scope Id : 0.0
+ //Valid Lifetime : infinite
+ //Preferred Lifetime : infinite
+ //DAD State : Preferred
+ //Address Type : Other
+ //Skip as Source : false
+ //
+ //Address XXXX::XXXX:XXXX:XXXX:XXXX%11 Parameters
+ //---------------------------------------------------------
+ //Interface Luid : Local Area Connection
+ //Scope Id : 0.11
+ //Valid Lifetime : infinite
+ //Preferred Lifetime : infinite
+ //DAD State : Preferred
+ //Address Type : Other
+ //Skip as Source : false
+ //
+
// TODO: need to test ipv6 netmask too, but netsh does not outputs it
- out, err := runCmd("netsh", "interface", "ipv6", "show", "address", "interface=\""+name+"\"")
- if err != nil {
- return nil, err
- }
+ var addr string
addrs := make([]string, 0)
- lines := bytes.Split(out, []byte{'\r', '\n'})
+ lines := bytes.Split(netshOutput, []byte{'\r', '\n'})
for _, line := range lines {
+ if addr != "" {
+ if len(line) == 0 {
+ addr = ""
+ continue
+ }
+ if string(line) != "Interface Luid : "+name {
+ continue
+ }
+ addrs = append(addrs, addr)
+ addr = ""
+ continue
+ }
if !bytes.HasPrefix(line, []byte("Address")) {
continue
}
@@ -383,9 +438,9 @@ func netshInterfaceIPv6ShowAddress(name string) ([]string, error) {
f[0] = []byte(ParseIP(string(f[0])).String())
}
- addrs = append(addrs, string(bytes.ToLower(bytes.TrimSpace(f[0]))))
+ addr = string(bytes.ToLower(bytes.TrimSpace(f[0])))
}
- return addrs, nil
+ return addrs
}
func TestInterfaceAddrsWithNetsh(t *testing.T) {
@@ -395,6 +450,16 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
if !isEnglishOS(t) {
t.Skip("English version of OS required for this test")
}
+
+ outIPV4, err := runCmd("netsh", "interface", "ipv4", "show", "address")
+ if err != nil {
+ t.Fatal(err)
+ }
+ outIPV6, err := runCmd("netsh", "interface", "ipv6", "show", "address", "level=verbose")
+ if err != nil {
+ t.Fatal(err)
+ }
+
ift, err := Interfaces()
if err != nil {
t.Fatal(err)
@@ -431,14 +496,8 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
}
sort.Strings(have)
- want, err := netshInterfaceIPv4ShowAddress(ifi.Name)
- if err != nil {
- t.Fatal(err)
- }
- wantIPv6, err := netshInterfaceIPv6ShowAddress(ifi.Name)
- if err != nil {
- t.Fatal(err)
- }
+ want := netshInterfaceIPv4ShowAddress(ifi.Name, outIPV4)
+ wantIPv6 := netshInterfaceIPv6ShowAddress(ifi.Name, outIPV6)
want = append(want, wantIPv6...)
sort.Strings(want)
@@ -487,8 +546,13 @@ func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
//
//Connection Name: Bluetooth Network Connection
//Network Adapter: Bluetooth Device (Personal Area Network)
- //Physical Address: XX-XX-XX-XX-XX-XX
- //Transport Name: Media disconnected
+ //Physical Address: N/A
+ //Transport Name: Hardware not present
+ //
+ //Connection Name: VMware Network Adapter VMnet8
+ //Network Adapter: VMware Virtual Ethernet Adapter for VMnet8
+ //Physical Address: Disabled
+ //Transport Name: Disconnected
//
want := make(map[string]string)
var name string
@@ -516,6 +580,9 @@ func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
if addr == "" {
t.Fatal("empty address on \"Physical Address\" line: %q", line)
}
+ if addr == "disabled" || addr == "n/a" {
+ continue
+ }
addr = strings.Replace(addr, "-", ":", -1)
want[name] = addr
name = ""
diff --git a/src/net/rpc/server_test.go b/src/net/rpc/server_test.go
index 8871c88133..cf171ac4fb 100644
--- a/src/net/rpc/server_test.go
+++ b/src/net/rpc/server_test.go
@@ -183,7 +183,7 @@ func testRPC(t *testing.T, addr string) {
err = client.Call("Arith.Unknown", args, reply)
if err == nil {
t.Error("expected error calling unknown service")
- } else if strings.Index(err.Error(), "method") < 0 {
+ } else if !strings.Contains(err.Error(), "method") {
t.Error("expected error about method; got", err)
}
@@ -226,7 +226,7 @@ func testRPC(t *testing.T, addr string) {
err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
if err == nil {
t.Error("expected error calling Arith.Add with wrong arg type")
- } else if strings.Index(err.Error(), "type") < 0 {
+ } else if !strings.Contains(err.Error(), "type") {
t.Error("expected error about type; got", err)
}
diff --git a/src/net/url/url.go b/src/net/url/url.go
index 1a93e3496e..b3513a85a3 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -511,7 +511,7 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
return nil, host, nil
}
userinfo := authority[:i]
- if strings.Index(userinfo, ":") < 0 {
+ if !strings.Contains(userinfo, ":") {
if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
return nil, "", err
}
@@ -709,8 +709,8 @@ func (v Values) Get(key string) string {
if v == nil {
return ""
}
- vs, ok := v[key]
- if !ok || len(vs) == 0 {
+ vs := v[key]
+ if len(vs) == 0 {
return ""
}
return vs[0]
diff --git a/src/os/exec/lp_windows.go b/src/os/exec/lp_windows.go
index c3efd67e9e..0b0712dcad 100644
--- a/src/os/exec/lp_windows.go
+++ b/src/os/exec/lp_windows.go
@@ -70,7 +70,7 @@ func LookPath(file string) (f string, err error) {
}
exts = append(exts, e)
}
- if strings.IndexAny(file, `:\/`) != -1 {
+ if strings.ContainsAny(file, `:\/`) {
if f, err = findExecutable(file, exts); err == nil {
return
}
diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go
index 5c073da991..2f7d48d5bd 100644
--- a/src/os/os_windows_test.go
+++ b/src/os/os_windows_test.go
@@ -177,7 +177,7 @@ func TestStatDir(t *testing.T) {
}
if !os.SameFile(fi, fi2) {
- t.Fatal("race condition occured")
+ t.Fatal("race condition occurred")
}
}
diff --git a/src/os/signal/doc.go b/src/os/signal/doc.go
index 80e66cffe5..9ee547b15d 100644
--- a/src/os/signal/doc.go
+++ b/src/os/signal/doc.go
@@ -11,7 +11,7 @@ package on Windows and Plan 9, see below.
Types of signals
The signals SIGKILL and SIGSTOP may not be caught by a program, and
-therefore can not be affected by this package.
+therefore cannot be affected by this package.
Synchronous signals are signals triggered by errors in program
execution: SIGBUS, SIGFPE, and SIGSEGV. These are only considered
diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go
index 89f16de355..d64bf84fc0 100644
--- a/src/path/filepath/match.go
+++ b/src/path/filepath/match.go
@@ -49,7 +49,7 @@ Pattern:
star, chunk, pattern = scanChunk(pattern)
if star && chunk == "" {
// Trailing * matches rest of string unless it has a /.
- return strings.Index(name, string(Separator)) < 0, nil
+ return !strings.Contains(name, string(Separator)), nil
}
// Look for match at current position.
t, ok, err := matchChunk(chunk, name)
@@ -305,5 +305,5 @@ func glob(dir, pattern string, matches []string) (m []string, e error) {
// recognized by Match.
func hasMeta(path string) bool {
// TODO(niemeyer): Should other magic characters be added here?
- return strings.IndexAny(path, "*?[") >= 0
+ return strings.ContainsAny(path, "*?[")
}
diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go
index 0edbfc70c4..d8bab7f4da 100644
--- a/src/path/filepath/match_test.go
+++ b/src/path/filepath/match_test.go
@@ -88,7 +88,7 @@ func TestMatch(t *testing.T) {
pattern := tt.pattern
s := tt.s
if runtime.GOOS == "windows" {
- if strings.Index(pattern, "\\") >= 0 {
+ if strings.Contains(pattern, "\\") {
// no escape allowed on windows.
continue
}
diff --git a/src/path/filepath/symlink.go b/src/path/filepath/symlink.go
index bc287c5ecb..f627a94ddb 100644
--- a/src/path/filepath/symlink.go
+++ b/src/path/filepath/symlink.go
@@ -100,7 +100,7 @@ func walkSymlinks(path string) (string, error) {
return "", err
}
if runtime.GOOS == "windows" {
- // walkLinks(".", ...) always retuns "." on unix.
+ // walkLinks(".", ...) always returns "." on unix.
// But on windows it returns symlink target, if current
// directory is a symlink. Stop the walk, if symlink
// target is not absolute path, and return "."
diff --git a/src/path/match.go b/src/path/match.go
index 75dd3b38e7..8d9aa513b1 100644
--- a/src/path/match.go
+++ b/src/path/match.go
@@ -43,7 +43,7 @@ Pattern:
star, chunk, pattern = scanChunk(pattern)
if star && chunk == "" {
// Trailing * matches rest of string unless it has a /.
- return strings.Index(name, "/") < 0, nil
+ return !strings.Contains(name, "/"), nil
}
// Look for match at current position.
t, ok, err := matchChunk(chunk, name)
diff --git a/src/regexp/backtrack.go b/src/regexp/backtrack.go
index fd95604fe4..3a1100dde8 100644
--- a/src/regexp/backtrack.go
+++ b/src/regexp/backtrack.go
@@ -254,7 +254,6 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
}
panic("bad arg in InstCapture")
- continue
case syntax.InstEmptyWidth:
if syntax.EmptyOp(inst.Arg)&^i.context(pos) != 0 {
@@ -299,7 +298,6 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
// Otherwise, continue on in hope of a longer match.
continue
}
- panic("unreachable")
}
return m.matched
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index d7d0edb993..42ae6e1d7a 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -454,7 +454,7 @@ func Match(pattern string, b []byte) (matched bool, err error) {
// in Expand, so for instance $1 represents the text of the first submatch.
func (re *Regexp) ReplaceAllString(src, repl string) string {
n := 2
- if strings.Index(repl, "$") >= 0 {
+ if strings.Contains(repl, "$") {
n = 2 * (re.numSubexp + 1)
}
b := re.replaceAll(nil, src, n, func(dst []byte, match []int) []byte {
diff --git a/src/regexp/syntax/regexp.go b/src/regexp/syntax/regexp.go
index 75822cf981..ca5724063b 100644
--- a/src/regexp/syntax/regexp.go
+++ b/src/regexp/syntax/regexp.go
@@ -252,7 +252,7 @@ const meta = `\.+*?()|[]{}^$`
func escape(b *bytes.Buffer, r rune, force bool) {
if unicode.IsPrint(r) {
- if strings.IndexRune(meta, r) >= 0 || force {
+ if strings.ContainsRune(meta, r) || force {
b.WriteRune('\\')
}
b.WriteRune(r)
diff --git a/src/runtime/alg.go b/src/runtime/alg.go
index 9ea0eb0187..9e19119f4a 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -16,24 +16,16 @@ const (
// type algorithms - known to compiler
const (
- alg_MEM = iota
+ alg_NOEQ = iota
alg_MEM0
alg_MEM8
alg_MEM16
alg_MEM32
alg_MEM64
alg_MEM128
- alg_NOEQ
- alg_NOEQ0
- alg_NOEQ8
- alg_NOEQ16
- alg_NOEQ32
- alg_NOEQ64
- alg_NOEQ128
alg_STRING
alg_INTER
alg_NILINTER
- alg_SLICE
alg_FLOAT32
alg_FLOAT64
alg_CPLX64
@@ -77,24 +69,16 @@ func memhash128(p unsafe.Pointer, h uintptr) uintptr {
func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr
var algarray = [alg_max]typeAlg{
- alg_MEM: {nil, nil}, // not used
+ alg_NOEQ: {nil, nil},
alg_MEM0: {memhash0, memequal0},
alg_MEM8: {memhash8, memequal8},
alg_MEM16: {memhash16, memequal16},
alg_MEM32: {memhash32, memequal32},
alg_MEM64: {memhash64, memequal64},
alg_MEM128: {memhash128, memequal128},
- alg_NOEQ: {nil, nil},
- alg_NOEQ0: {nil, nil},
- alg_NOEQ8: {nil, nil},
- alg_NOEQ16: {nil, nil},
- alg_NOEQ32: {nil, nil},
- alg_NOEQ64: {nil, nil},
- alg_NOEQ128: {nil, nil},
alg_STRING: {strhash, strequal},
alg_INTER: {interhash, interequal},
alg_NILINTER: {nilinterhash, nilinterequal},
- alg_SLICE: {nil, nil},
alg_FLOAT32: {f32hash, f32equal},
alg_FLOAT64: {f64hash, f64equal},
alg_CPLX64: {c64hash, c64equal},
@@ -188,13 +172,6 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
}
}
-func memequal(p, q unsafe.Pointer, size uintptr) bool {
- if p == q {
- return true
- }
- return memeq(p, q, size)
-}
-
func memequal0(p, q unsafe.Pointer) bool {
return true
}
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index 4181859724..9237d57f24 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -1239,12 +1239,18 @@ TEXT ·checkASM(SB),NOSPLIT,$0-1
SETEQ ret+0(FP)
RET
-TEXT runtime·memeq(SB),NOSPLIT,$0-13
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$0-13
MOVL a+0(FP), SI
MOVL b+4(FP), DI
+ CMPL SI, DI
+ JEQ eq
MOVL size+8(FP), BX
LEAL ret+12(FP), AX
JMP runtime·memeqbody(SB)
+eq:
+ MOVB $1, ret+12(FP)
+ RET
// memequal_varlen(a, b unsafe.Pointer) bool
TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 5094812a05..98a8e839ed 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -1269,12 +1269,18 @@ DATA shifts<>+0xf0(SB)/8, $0x0807060504030201
DATA shifts<>+0xf8(SB)/8, $0xff0f0e0d0c0b0a09
GLOBL shifts<>(SB),RODATA,$256
-TEXT runtime·memeq(SB),NOSPLIT,$0-25
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$0-25
MOVQ a+0(FP), SI
MOVQ b+8(FP), DI
+ CMPQ SI, DI
+ JEQ eq
MOVQ size+16(FP), BX
LEAQ ret+24(FP), AX
JMP runtime·memeqbody(SB)
+eq:
+ MOVB $1, ret+24(FP)
+ RET
// memequal_varlen(a, b unsafe.Pointer) bool
TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index ecbc5975bb..ae7a53821b 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -573,13 +573,19 @@ TEXT runtime·aeshash64(SB),NOSPLIT,$0-20
MOVL AX, ret+16(FP)
RET
-TEXT runtime·memeq(SB),NOSPLIT,$0-17
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$0-13
MOVL a+0(FP), SI
MOVL b+4(FP), DI
+ CMPL SI, DI
+ JEQ eq
MOVL size+8(FP), BX
CALL runtime·memeqbody(SB)
MOVB AX, ret+16(FP)
RET
+eq:
+ MOVB $1, ret+16(FP)
+ RET
// memequal_varlen(a, b unsafe.Pointer) bool
TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 07894a3a72..5d0206d1c9 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -750,13 +750,16 @@ TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
MOVW R0, ret+8(FP)
RET
-TEXT runtime·memeq(SB),NOSPLIT,$-4-13
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$-4-13
MOVW a+0(FP), R1
MOVW b+4(FP), R2
MOVW size+8(FP), R3
ADD R1, R3, R6
MOVW $1, R0
MOVB R0, ret+12(FP)
+ CMP R1, R2
+ RET.EQ
loop:
CMP R1, R6
RET.EQ
@@ -779,7 +782,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$16-9
MOVW R0, 4(R13)
MOVW R1, 8(R13)
MOVW R2, 12(R13)
- BL runtime·memeq(SB)
+ BL runtime·memequal(SB)
MOVB 16(R13), R0
MOVB R0, ret+8(FP)
RET
@@ -866,7 +869,7 @@ loop:
MOVB R8, v+16(FP)
RET
-// TODO: share code with memeq?
+// TODO: share code with memequal?
TEXT bytes·Equal(SB),NOSPLIT,$0-25
MOVW a_len+4(FP), R1
MOVW b_len+16(FP), R3
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
index ab5d5b5e5f..5a5c64c270 100644
--- a/src/runtime/asm_arm64.s
+++ b/src/runtime/asm_arm64.s
@@ -765,13 +765,16 @@ TEXT runtime·memhash_varlen(SB),NOSPLIT,$40-24
MOVD R3, ret+16(FP)
RET
-TEXT runtime·memeq(SB),NOSPLIT,$-8-25
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$-8-25
MOVD a+0(FP), R1
MOVD b+8(FP), R2
MOVD size+16(FP), R3
ADD R1, R3, R6
MOVD $1, R0
MOVB R0, ret+24(FP)
+ CMP R1, R2
+ BEQ done
loop:
CMP R1, R6
BEQ done
@@ -794,7 +797,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
MOVD R3, 8(RSP)
MOVD R4, 16(RSP)
MOVD R5, 24(RSP)
- BL runtime·memeq(SB)
+ BL runtime·memequal(SB)
MOVBU 32(RSP), R3
MOVB R3, ret+16(FP)
RET
@@ -929,7 +932,7 @@ notfound:
MOVD R0, ret+24(FP)
RET
-// TODO: share code with memeq?
+// TODO: share code with memequal?
TEXT bytes·Equal(SB),NOSPLIT,$0-49
MOVD a_len+8(FP), R1
MOVD b_len+32(FP), R3
diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s
index 08482fed23..80cea8587a 100644
--- a/src/runtime/asm_mips64x.s
+++ b/src/runtime/asm_mips64x.s
@@ -647,9 +647,11 @@ TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0
TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0
MOVW (R0), R1
-TEXT runtime·memeq(SB),NOSPLIT,$-8-25
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$-8-25
MOVV a+0(FP), R1
MOVV b+8(FP), R2
+ BEQ R1, R2, eq
MOVV size+16(FP), R3
ADDV R1, R3, R4
loop:
@@ -666,6 +668,10 @@ test:
MOVB R0, ret+24(FP)
RET
+eq:
+ MOVV $1, R1
+ MOVB R1, ret+24(FP)
+ RET
// memequal_varlen(a, b unsafe.Pointer) bool
TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
@@ -676,7 +682,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
MOVV R1, 8(R29)
MOVV R2, 16(R29)
MOVV R3, 24(R29)
- JAL runtime·memeq(SB)
+ JAL runtime·memequal(SB)
MOVBU 32(R29), R1
MOVB R1, ret+16(FP)
RET
@@ -710,7 +716,7 @@ loop:
MOVB R0, ret+32(FP)
RET
-// TODO: share code with memeq?
+// TODO: share code with memequal?
TEXT bytes·Equal(SB),NOSPLIT,$0-49
MOVV a_len+8(FP), R3
MOVV b_len+32(FP), R4
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index 50c4f2623c..f067b4a9b9 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -795,9 +795,12 @@ TEXT runtime·aeshash64(SB),NOSPLIT|NOFRAME,$0-0
TEXT runtime·aeshashstr(SB),NOSPLIT|NOFRAME,$0-0
MOVW (R0), R1
-TEXT runtime·memeq(SB),NOSPLIT|NOFRAME,$0-25
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25
MOVD a+0(FP), R3
MOVD b+8(FP), R4
+ CMP R3, R4
+ BEQ eq
MOVD size+16(FP), R5
SUB $1, R3
SUB $1, R4
@@ -816,6 +819,10 @@ test:
MOVB R0, ret+24(FP)
RET
+eq:
+ MOVD $1, R1
+ MOVB R1, ret+24(FP)
+ RET
// memequal_varlen(a, b unsafe.Pointer) bool
TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
@@ -827,7 +834,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
MOVD R3, FIXED_FRAME+0(R1)
MOVD R4, FIXED_FRAME+8(R1)
MOVD R5, FIXED_FRAME+16(R1)
- BL runtime·memeq(SB)
+ BL runtime·memequal(SB)
MOVBZ FIXED_FRAME+24(R1), R3
MOVB R3, ret+16(FP)
RET
@@ -864,7 +871,7 @@ loop:
MOVB R0, ret+32(FP)
RET
-// TODO: share code with memeq?
+// TODO: share code with memequal?
TEXT bytes·Equal(SB),NOSPLIT,$0-49
MOVD a_len+8(FP), R3
MOVD b_len+32(FP), R4
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index 66115fd8b4..f632f7ab5a 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -340,7 +340,7 @@ var racecgosync uint64 // represents possible synchronization in C code
// When and if we implement a moving garbage collector,
// cgoCheckPointer will pin the pointer for the duration of the cgo
// call. (This is necessary but not sufficient; the cgo program will
-// also have to change to pin Go pointers that can not point to Go
+// also have to change to pin Go pointers that cannot point to Go
// pointers.)
// cgoCheckPointer checks if the argument contains a Go pointer that
@@ -463,6 +463,9 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
if !top {
panic(errorString(msg))
}
+ if st.elem.kind&kindNoPointers != 0 {
+ return
+ }
for i := 0; i < s.cap; i++ {
cgoCheckArg(st.elem, p, true, false, msg)
p = add(p, st.elem.size)
diff --git a/src/runtime/cgocheck.go b/src/runtime/cgocheck.go
index 0077e22332..aebce1506d 100644
--- a/src/runtime/cgocheck.go
+++ b/src/runtime/cgocheck.go
@@ -135,9 +135,6 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
hbits := heapBitsForAddr(uintptr(src))
for i := uintptr(0); i < off+size; i += sys.PtrSize {
bits := hbits.bits()
- if bits != 0 {
- println(i, bits)
- }
if i >= off && bits&bitPointer != 0 {
v := *(*unsafe.Pointer)(add(src, i))
if cgoIsGoPointer(v) {
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 5be18beb23..063c5ce391 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -421,7 +421,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
if sg := c.sendq.dequeue(); sg != nil {
// Found a waiting sender. If buffer is size 0, receive value
- // directly from sender. Otherwise, recieve from head of queue
+ // directly from sender. Otherwise, receive from head of queue
// and add sender's value to the tail of the queue (both map to
// the same buffer slot because the queue is full).
recv(c, sg, ep, func() { unlock(&c.lock) })
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index d7b367f941..63769e801c 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -7,10 +7,12 @@
package runtime_test
import (
+ "internal/testenv"
"os/exec"
"runtime"
"strings"
"testing"
+ "time"
)
func TestCgoCrashHandler(t *testing.T) {
@@ -147,3 +149,41 @@ func TestEnsureDropM(t *testing.T) {
t.Errorf("expected %q, got %v", want, got)
}
}
+
+// Test for issue 14387.
+// Test that the program that doesn't need any cgo pointer checking
+// takes about the same amount of time with it as without it.
+func TestCgoCheckBytes(t *testing.T) {
+ // Make sure we don't count the build time as part of the run time.
+ testenv.MustHaveGoBuild(t)
+ exe, err := buildTestProg(t, "testprogcgo")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ cmd := testEnv(exec.Command(exe, "CgoCheckBytes"))
+
+ start := time.Now()
+ cmd.Run()
+ d1 := time.Since(start)
+
+ cmd = testEnv(exec.Command(exe, "CgoCheckBytes"))
+ cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0")
+
+ start = time.Now()
+ cmd.Run()
+ d2 := time.Since(start)
+
+ if d2*10 < d1 {
+ t.Errorf("cgo check too slow: got %v, expected at most %v", d1, d2*10)
+ }
+}
+
+func TestCgoPanicDeadlock(t *testing.T) {
+ // test issue 14432
+ got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock")
+ want := "panic: cgo error\n\n"
+ if !strings.HasPrefix(got, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, got)
+ }
+}
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index b622eb4526..de45e832f8 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -317,3 +317,38 @@ func TestNetpollDeadlock(t *testing.T) {
t.Fatalf("output does not start with %q:\n%s", want, output)
}
}
+
+func TestPanicTraceback(t *testing.T) {
+ output := runTestProg(t, "testprog", "PanicTraceback")
+ want := "panic: hello"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+
+ // Check functions in the traceback.
+ fns := []string{"panic", "main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
+ for _, fn := range fns {
+ re := regexp.MustCompile(`(?m)^` + regexp.QuoteMeta(fn) + `\(.*\n`)
+ idx := re.FindStringIndex(output)
+ if idx == nil {
+ t.Fatalf("expected %q function in traceback:\n%s", fn, output)
+ }
+ output = output[idx[1]:]
+ }
+}
+
+func testPanicDeadlock(t *testing.T, name string, want string) {
+ // test issue 14432
+ output := runTestProg(t, "testprog", name)
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+
+func TestPanicDeadlockGosched(t *testing.T) {
+ testPanicDeadlock(t, "GoschedInPanic", "panic: errorThatGosched\n\n")
+}
+
+func TestPanicDeadlockSyscall(t *testing.T) {
+ testPanicDeadlock(t, "SyscallInPanic", "1\n2\npanic: 3\n\n")
+}
diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go
index 1a012eb6ef..771b303f6e 100644
--- a/src/runtime/crash_unix_test.go
+++ b/src/runtime/crash_unix_test.go
@@ -14,6 +14,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
+ "strings"
"syscall"
"testing"
)
@@ -52,6 +53,18 @@ func TestCrashDumpsAllThreads(t *testing.T) {
cmd = exec.Command(filepath.Join(dir, "a.exe"))
cmd = testEnv(cmd)
cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
+
+ // Set GOGC=off. Because of golang.org/issue/10958, the tight
+ // loops in the test program are not preemptible. If GC kicks
+ // in, it may lock up and prevent main from saying it's ready.
+ newEnv := []string{}
+ for _, s := range cmd.Env {
+ if !strings.HasPrefix(s, "GOGC=") {
+ newEnv = append(newEnv, s)
+ }
+ }
+ cmd.Env = append(newEnv, "GOGC=off")
+
var outbuf bytes.Buffer
cmd.Stdout = &outbuf
cmd.Stderr = &outbuf
diff --git a/src/runtime/debug/stack_test.go b/src/runtime/debug/stack_test.go
index f54437231b..9376e82b84 100644
--- a/src/runtime/debug/stack_test.go
+++ b/src/runtime/debug/stack_test.go
@@ -59,7 +59,7 @@ func TestStack(t *testing.T) {
}
func check(t *testing.T, line, has string) {
- if strings.Index(line, has) < 0 {
+ if !strings.Contains(line, has) {
t.Errorf("expected %q in %q", has, line)
}
}
diff --git a/src/runtime/export_linux_test.go b/src/runtime/export_linux_test.go
index c8b9746676..61d6ae4bf2 100644
--- a/src/runtime/export_linux_test.go
+++ b/src/runtime/export_linux_test.go
@@ -7,3 +7,4 @@
package runtime
var NewOSProc0 = newosproc0
+var Mincore = mincore
diff --git a/src/runtime/export_mmap_test.go b/src/runtime/export_mmap_test.go
new file mode 100644
index 0000000000..11ea076f0b
--- /dev/null
+++ b/src/runtime/export_mmap_test.go
@@ -0,0 +1,15 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+// Export guts for testing.
+
+package runtime
+
+var Mmap = mmap
+
+const ENOMEM = _ENOMEM
+const MAP_ANON = _MAP_ANON
+const MAP_PRIVATE = _MAP_PRIVATE
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index 5400c1d14e..245cc88aae 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -45,42 +45,6 @@ func LFStackPop(head *uint64) *LFNode {
return (*LFNode)(unsafe.Pointer(lfstackpop(head)))
}
-type ParFor struct {
- body func(*ParFor, uint32)
- done uint32
- Nthr uint32
- thrseq uint32
- Cnt uint32
- wait bool
-}
-
-func NewParFor(nthrmax uint32) *ParFor {
- var desc *ParFor
- systemstack(func() {
- desc = (*ParFor)(unsafe.Pointer(parforalloc(nthrmax)))
- })
- return desc
-}
-
-func ParForSetup(desc *ParFor, nthr, n uint32, wait bool, body func(*ParFor, uint32)) {
- systemstack(func() {
- parforsetup((*parfor)(unsafe.Pointer(desc)), nthr, n, wait,
- *(*func(*parfor, uint32))(unsafe.Pointer(&body)))
- })
-}
-
-func ParForDo(desc *ParFor) {
- systemstack(func() {
- parfordo((*parfor)(unsafe.Pointer(desc)))
- })
-}
-
-func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
- desc1 := (*parfor)(unsafe.Pointer(desc))
- pos := desc1.thr[tid].pos
- return uint32(pos), uint32(pos >> 32)
-}
-
func GCMask(x interface{}) (ret []byte) {
systemstack(func() {
ret = getgcmask(x)
diff --git a/src/runtime/hashmap_fast.go b/src/runtime/hashmap_fast.go
index 519dc77f71..f95ea3e1b7 100644
--- a/src/runtime/hashmap_fast.go
+++ b/src/runtime/hashmap_fast.go
@@ -216,7 +216,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
if k.len != key.len {
continue
}
- if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) {
+ if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
}
}
@@ -254,7 +254,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
}
if keymaybe != bucketCnt {
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize))
- if memeq(k.str, key.str, uintptr(key.len)) {
+ if memequal(k.str, key.str, uintptr(key.len)) {
return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize))
}
}
@@ -284,7 +284,7 @@ dohash:
if k.len != key.len {
continue
}
- if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) {
+ if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
}
}
@@ -321,7 +321,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
if k.len != key.len {
continue
}
- if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) {
+ if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
}
}
@@ -357,7 +357,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
}
if keymaybe != bucketCnt {
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize))
- if memeq(k.str, key.str, uintptr(key.len)) {
+ if memequal(k.str, key.str, uintptr(key.len)) {
return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize)), true
}
}
@@ -387,7 +387,7 @@ dohash:
if k.len != key.len {
continue
}
- if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) {
+ if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
}
}
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 71dc865e07..50dff77e42 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -398,22 +398,6 @@ func assertE2E2(inter *interfacetype, e eface, r *eface) bool {
return true
}
-func ifacethash(i iface) uint32 {
- tab := i.tab
- if tab == nil {
- return 0
- }
- return tab._type.hash
-}
-
-func efacethash(e eface) uint32 {
- t := e._type
- if t == nil {
- return 0
- }
- return t.hash
-}
-
func iterate_itabs(fn func(*itab)) {
for _, h := range &hash {
for ; h != nil; h = h.link {
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
index 45086c43cd..1204e8143e 100644
--- a/src/runtime/mbarrier.go
+++ b/src/runtime/mbarrier.go
@@ -100,7 +100,7 @@ func gcmarkwb_m(slot *uintptr, ptr uintptr) {
// related operations. In particular there are times when the GC assumes
// that the world is stopped but scheduler related code is still being
// executed, dealing with syscalls, dealing with putting gs on runnable
-// queues and so forth. This code can not execute write barriers because
+// queues and so forth. This code cannot execute write barriers because
// the GC might drop them on the floor. Stopping the world involves removing
// the p associated with an m. We use the fact that m.p == nil to indicate
// that we are in one these critical section and throw if the write is of
diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go
index 1e388ec728..c3fe6106d7 100644
--- a/src/runtime/mem_bsd.go
+++ b/src/runtime/mem_bsd.go
@@ -59,9 +59,9 @@ func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
return p
}
-func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
- const _ENOMEM = 12
+const _ENOMEM = 12
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
mSysStatInc(sysStat, n)
// On 64-bit, we don't actually have v reserved, so tread carefully.
diff --git a/src/runtime/mfixalloc.go b/src/runtime/mfixalloc.go
index 8653a6a99f..569a304cf4 100644
--- a/src/runtime/mfixalloc.go
+++ b/src/runtime/mfixalloc.go
@@ -30,8 +30,8 @@ type fixalloc struct {
}
// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
-// Since assignments to mlink.next will result in a write barrier being preformed
-// this can not be used by some of the internal GC structures. For example when
+// Since assignments to mlink.next will result in a write barrier being performed
+// this cannot be used by some of the internal GC structures. For example when
// the sweeper is placing an unmarked object on the free list it does not want the
// write barrier to be called since that could result in the object being reachable.
type mlink struct {
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index fc73bbfbe1..3efa375d6a 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -506,9 +506,7 @@ func ThreadCreateProfile(p []StackRecord) (n int, ok bool) {
ok = true
i := 0
for mp := first; mp != nil; mp = mp.alllink {
- for s := range mp.createstack {
- p[i].Stack0[s] = uintptr(mp.createstack[s])
- }
+ p[i].Stack0 = mp.createstack
i++
}
}
diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go
index 368687d006..8ae636077b 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -165,7 +165,7 @@ type MemStats struct {
// Size of the trailing by_size array differs between Go and C,
// and all data after by_size is local to runtime, not exported.
-// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+// NumSizeClasses was changed, but we cannot change Go struct because of backward compatibility.
// sizeof_C_MStats is what C thinks about size of Go struct.
var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0])
@@ -192,7 +192,7 @@ func readmemstats_m(stats *MemStats) {
updatememstats(nil)
// Size of the trailing by_size array differs between Go and C,
- // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+ // NumSizeClasses was changed, but we cannot change Go struct because of backward compatibility.
memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats)
// Stack numbers are part of the heap numbers, separate those out for user consumption
diff --git a/src/runtime/norace_linux_test.go b/src/runtime/norace_linux_test.go
index bbf9d0b413..049801d3fc 100644
--- a/src/runtime/norace_linux_test.go
+++ b/src/runtime/norace_linux_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The file contains tests that can not run under race detector for some reason.
+// The file contains tests that cannot run under race detector for some reason.
// +build !race
package runtime_test
diff --git a/src/runtime/norace_test.go b/src/runtime/norace_test.go
index 3681bf190d..e9b39b2f45 100644
--- a/src/runtime/norace_test.go
+++ b/src/runtime/norace_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The file contains tests that can not run under race detector for some reason.
+// The file contains tests that cannot run under race detector for some reason.
// +build !race
package runtime_test
diff --git a/src/runtime/os1_darwin.go b/src/runtime/os1_darwin.go
index 5c00407b2f..19bb0f16e0 100644
--- a/src/runtime/os1_darwin.go
+++ b/src/runtime/os1_darwin.go
@@ -157,7 +157,7 @@ func sigblock() {
}
// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
func minit() {
// Initialize signal handling.
_g_ := getg()
diff --git a/src/runtime/os1_dragonfly.go b/src/runtime/os1_dragonfly.go
index bf3e1ccb83..7e4f84e6a3 100644
--- a/src/runtime/os1_dragonfly.go
+++ b/src/runtime/os1_dragonfly.go
@@ -133,7 +133,7 @@ func sigblock() {
}
// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
func minit() {
_g_ := getg()
diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os1_freebsd.go
index 79d995476e..f00fdf4389 100644
--- a/src/runtime/os1_freebsd.go
+++ b/src/runtime/os1_freebsd.go
@@ -136,7 +136,7 @@ func sigblock() {
}
// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
func minit() {
_g_ := getg()
diff --git a/src/runtime/os1_linux.go b/src/runtime/os1_linux.go
index b38cfc14f9..2d53b934f5 100644
--- a/src/runtime/os1_linux.go
+++ b/src/runtime/os1_linux.go
@@ -225,7 +225,7 @@ func sigblock() {
func gettid() uint32
// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
func minit() {
// Initialize signal handling.
_g_ := getg()
diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go
index dab205de6a..5526d906d8 100644
--- a/src/runtime/os1_nacl.go
+++ b/src/runtime/os1_nacl.go
@@ -30,7 +30,7 @@ func sigblock() {
}
// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
func minit() {
_g_ := getg()
diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go
index eab8eb8702..e32df9585c 100644
--- a/src/runtime/os1_netbsd.go
+++ b/src/runtime/os1_netbsd.go
@@ -167,7 +167,7 @@ func sigblock() {
}
// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
func minit() {
_g_ := getg()
_g_.m.procid = uint64(lwp_self())
diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go
index 7506d591df..9911077911 100644
--- a/src/runtime/os1_plan9.go
+++ b/src/runtime/os1_plan9.go
@@ -33,7 +33,7 @@ func sigblock() {
}
// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
func minit() {
// Mask all SSE floating-point exceptions
// when running on the 64-bit kernel.
diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go
index a28e11e088..8d46bca36d 100644
--- a/src/runtime/os1_windows.go
+++ b/src/runtime/os1_windows.go
@@ -399,7 +399,7 @@ func sigblock() {
}
// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
func minit() {
var thandle uintptr
stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
diff --git a/src/runtime/os2_nacl.go b/src/runtime/os2_nacl.go
index 0c91e0f737..d8c88db0ad 100644
--- a/src/runtime/os2_nacl.go
+++ b/src/runtime/os2_nacl.go
@@ -10,18 +10,19 @@ const (
// native_client/src/trusted/service_runtime/include/sys/errno.h
// The errors are mainly copied from Linux.
- _EPERM = 1 /* Operation not permitted */
- _ENOENT = 2 /* No such file or directory */
- _ESRCH = 3 /* No such process */
- _EINTR = 4 /* Interrupted system call */
- _EIO = 5 /* I/O error */
- _ENXIO = 6 /* No such device or address */
- _E2BIG = 7 /* Argument list too long */
- _ENOEXEC = 8 /* Exec format error */
- _EBADF = 9 /* Bad file number */
- _ECHILD = 10 /* No child processes */
- _EAGAIN = 11 /* Try again */
- _ENOMEM = 12 /* Out of memory */
+ _EPERM = 1 /* Operation not permitted */
+ _ENOENT = 2 /* No such file or directory */
+ _ESRCH = 3 /* No such process */
+ _EINTR = 4 /* Interrupted system call */
+ _EIO = 5 /* I/O error */
+ _ENXIO = 6 /* No such device or address */
+ _E2BIG = 7 /* Argument list too long */
+ _ENOEXEC = 8 /* Exec format error */
+ _EBADF = 9 /* Bad file number */
+ _ECHILD = 10 /* No child processes */
+ _EAGAIN = 11 /* Try again */
+ // _ENOMEM is defined in mem_bsd.go for nacl.
+ // _ENOMEM = 12 /* Out of memory */
_EACCES = 13 /* Permission denied */
_EFAULT = 14 /* Bad address */
_EBUSY = 16 /* Device or resource busy */
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index 7bda07bd4a..fdc817d3f7 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -208,7 +208,7 @@ func sigblock() {
}
// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
func minit() {
_g_ := getg()
asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno))
@@ -442,7 +442,21 @@ func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
//go:nosplit
func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer {
- return unsafe.Pointer(sysvicall6(&libc_mmap, uintptr(addr), uintptr(n), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off)))
+ p, err := doMmap(uintptr(addr), n, uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off))
+ if p == ^uintptr(0) {
+ return unsafe.Pointer(err)
+ }
+ return unsafe.Pointer(p)
+}
+
+//go:nosplit
+func doMmap(addr, n, prot, flags, fd, off uintptr) (uintptr, uintptr) {
+ var libcall libcall
+ libcall.fn = uintptr(unsafe.Pointer(&libc_mmap))
+ libcall.n = 6
+ libcall.args = uintptr(noescape(unsafe.Pointer(&addr)))
+ asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
+ return libcall.r1, libcall.err
}
//go:nosplit
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index b8257768ac..78557759cc 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -7,6 +7,7 @@ package runtime
import "unsafe"
type mOS struct {
+ machport uint32 // return address for mach ipc
waitsema uint32 // semaphore for parking on locks
}
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index ba07330e35..349e997395 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -333,6 +333,21 @@ func Goexit() {
goexit1()
}
+// Call all Error and String methods before freezing the world.
+// Used when crashing with panicking.
+// This must match types handled by printany.
+func preprintpanics(p *_panic) {
+ for p != nil {
+ switch v := p.arg.(type) {
+ case error:
+ p.arg = v.Error()
+ case stringer:
+ p.arg = v.String()
+ }
+ p = p.link
+ }
+}
+
// Print all currently active panics. Used when crashing.
func printpanics(p *_panic) {
if p.link != nil {
@@ -459,6 +474,10 @@ func gopanic(e interface{}) {
}
// ran out of deferred calls - old-school panic now
+ // Because it is unsafe to call arbitrary user code after freezing
+ // the world, we call preprintpanics to invoke all necessary Error
+ // and String methods to prepare the panic strings before startpanic.
+ preprintpanics(gp._panic)
startpanic()
printpanics(gp._panic)
dopanic(0) // should not return
diff --git a/src/runtime/parfor.go b/src/runtime/parfor.go
deleted file mode 100644
index 9e11cb3e12..0000000000
--- a/src/runtime/parfor.go
+++ /dev/null
@@ -1,217 +0,0 @@
-// 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.
-
-// Parallel for algorithm.
-
-package runtime
-
-import (
- "runtime/internal/atomic"
- "runtime/internal/sys"
-)
-
-// A parfor holds state for the parallel for operation.
-type parfor struct {
- body func(*parfor, uint32) // executed for each element
- done uint32 // number of idle threads
- nthr uint32 // total number of threads
- thrseq uint32 // thread id sequencer
- cnt uint32 // iteration space [0, cnt)
- wait bool // if true, wait while all threads finish processing,
- // otherwise parfor may return while other threads are still working
-
- thr []parforthread // thread descriptors
-
- // stats
- nsteal uint64
- nstealcnt uint64
- nprocyield uint64
- nosyield uint64
- nsleep uint64
-}
-
-// A parforthread holds state for a single thread in the parallel for.
-type parforthread struct {
- // the thread's iteration space [32lsb, 32msb)
- pos uint64
- // stats
- nsteal uint64
- nstealcnt uint64
- nprocyield uint64
- nosyield uint64
- nsleep uint64
- pad [sys.CacheLineSize]byte
-}
-
-func parforalloc(nthrmax uint32) *parfor {
- return &parfor{
- thr: make([]parforthread, nthrmax),
- }
-}
-
-// Parforsetup initializes desc for a parallel for operation with nthr
-// threads executing n jobs.
-//
-// On return the nthr threads are each expected to call parfordo(desc)
-// to run the operation. During those calls, for each i in [0, n), one
-// thread will be used invoke body(desc, i).
-// If wait is true, no parfordo will return until all work has been completed.
-// If wait is false, parfordo may return when there is a small amount
-// of work left, under the assumption that another thread has that
-// work well in hand.
-func parforsetup(desc *parfor, nthr, n uint32, wait bool, body func(*parfor, uint32)) {
- if desc == nil || nthr == 0 || nthr > uint32(len(desc.thr)) || body == nil {
- print("desc=", desc, " nthr=", nthr, " count=", n, " body=", body, "\n")
- throw("parfor: invalid args")
- }
-
- desc.body = body
- desc.done = 0
- desc.nthr = nthr
- desc.thrseq = 0
- desc.cnt = n
- desc.wait = wait
- desc.nsteal = 0
- desc.nstealcnt = 0
- desc.nprocyield = 0
- desc.nosyield = 0
- desc.nsleep = 0
-
- for i := range desc.thr {
- begin := uint32(uint64(n) * uint64(i) / uint64(nthr))
- end := uint32(uint64(n) * uint64(i+1) / uint64(nthr))
- desc.thr[i].pos = uint64(begin) | uint64(end)<<32
- }
-}
-
-func parfordo(desc *parfor) {
- // Obtain 0-based thread index.
- tid := atomic.Xadd(&desc.thrseq, 1) - 1
- if tid >= desc.nthr {
- print("tid=", tid, " nthr=", desc.nthr, "\n")
- throw("parfor: invalid tid")
- }
-
- // If single-threaded, just execute the for serially.
- body := desc.body
- if desc.nthr == 1 {
- for i := uint32(0); i < desc.cnt; i++ {
- body(desc, i)
- }
- return
- }
-
- me := &desc.thr[tid]
- mypos := &me.pos
- for {
- for {
- // While there is local work,
- // bump low index and execute the iteration.
- pos := atomic.Xadd64(mypos, 1)
- begin := uint32(pos) - 1
- end := uint32(pos >> 32)
- if begin < end {
- body(desc, begin)
- continue
- }
- break
- }
-
- // Out of work, need to steal something.
- idle := false
- for try := uint32(0); ; try++ {
- // If we don't see any work for long enough,
- // increment the done counter...
- if try > desc.nthr*4 && !idle {
- idle = true
- atomic.Xadd(&desc.done, 1)
- }
-
- // ...if all threads have incremented the counter,
- // we are done.
- extra := uint32(0)
- if !idle {
- extra = 1
- }
- if desc.done+extra == desc.nthr {
- if !idle {
- atomic.Xadd(&desc.done, 1)
- }
- goto exit
- }
-
- // Choose a random victim for stealing.
- var begin, end uint32
- victim := fastrand1() % (desc.nthr - 1)
- if victim >= tid {
- victim++
- }
- victimpos := &desc.thr[victim].pos
- for {
- // See if it has any work.
- pos := atomic.Load64(victimpos)
- begin = uint32(pos)
- end = uint32(pos >> 32)
- if begin+1 >= end {
- end = 0
- begin = end
- break
- }
- if idle {
- atomic.Xadd(&desc.done, -1)
- idle = false
- }
- begin2 := begin + (end-begin)/2
- newpos := uint64(begin) | uint64(begin2)<<32
- if atomic.Cas64(victimpos, pos, newpos) {
- begin = begin2
- break
- }
- }
- if begin < end {
- // Has successfully stolen some work.
- if idle {
- throw("parfor: should not be idle")
- }
- atomic.Store64(mypos, uint64(begin)|uint64(end)<<32)
- me.nsteal++
- me.nstealcnt += uint64(end) - uint64(begin)
- break
- }
-
- // Backoff.
- if try < desc.nthr {
- // nothing
- } else if try < 4*desc.nthr {
- me.nprocyield++
- procyield(20)
- } else if !desc.wait {
- // If a caller asked not to wait for the others, exit now
- // (assume that most work is already done at this point).
- if !idle {
- atomic.Xadd(&desc.done, 1)
- }
- goto exit
- } else if try < 6*desc.nthr {
- me.nosyield++
- osyield()
- } else {
- me.nsleep++
- usleep(1)
- }
- }
- }
-
-exit:
- atomic.Xadd64(&desc.nsteal, int64(me.nsteal))
- atomic.Xadd64(&desc.nstealcnt, int64(me.nstealcnt))
- atomic.Xadd64(&desc.nprocyield, int64(me.nprocyield))
- atomic.Xadd64(&desc.nosyield, int64(me.nosyield))
- atomic.Xadd64(&desc.nsleep, int64(me.nsleep))
- me.nsteal = 0
- me.nstealcnt = 0
- me.nprocyield = 0
- me.nosyield = 0
- me.nsleep = 0
-}
diff --git a/src/runtime/parfor_test.go b/src/runtime/parfor_test.go
deleted file mode 100644
index 5d22aecc9b..0000000000
--- a/src/runtime/parfor_test.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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.
-
-// The race detector does not understand ParFor synchronization.
-// +build !race
-
-package runtime_test
-
-import (
- . "runtime"
- "testing"
-)
-
-// Simple serial sanity test for parallelfor.
-func TestParFor(t *testing.T) {
- const P = 1
- const N = 20
- data := make([]uint64, N)
- for i := uint64(0); i < N; i++ {
- data[i] = i
- }
- desc := NewParFor(P)
- ParForSetup(desc, P, N, true, func(desc *ParFor, i uint32) {
- data[i] = data[i]*data[i] + 1
- })
- ParForDo(desc)
- for i := uint64(0); i < N; i++ {
- if data[i] != i*i+1 {
- t.Fatalf("Wrong element %d: %d", i, data[i])
- }
- }
-}
-
-// Test that nonblocking parallelfor does not block.
-func TestParFor2(t *testing.T) {
- const P = 7
- const N = 1003
- data := make([]uint64, N)
- for i := uint64(0); i < N; i++ {
- data[i] = i
- }
- desc := NewParFor(P)
- ParForSetup(desc, P, N, false, func(desc *ParFor, i uint32) {
- data[i] = data[i]*data[i] + 1
- })
- for p := 0; p < P; p++ {
- ParForDo(desc)
- }
- for i := uint64(0); i < N; i++ {
- if data[i] != i*i+1 {
- t.Fatalf("Wrong element %d: %d", i, data[i])
- }
- }
-}
-
-// Test that iterations are properly distributed.
-func TestParForSetup(t *testing.T) {
- const P = 11
- const N = 101
- desc := NewParFor(P)
- for n := uint32(0); n < N; n++ {
- for p := uint32(1); p <= P; p++ {
- ParForSetup(desc, p, n, true, func(desc *ParFor, i uint32) {})
- sum := uint32(0)
- size0 := uint32(0)
- end0 := uint32(0)
- for i := uint32(0); i < p; i++ {
- begin, end := ParForIters(desc, i)
- size := end - begin
- sum += size
- if i == 0 {
- size0 = size
- if begin != 0 {
- t.Fatalf("incorrect begin: %d (n=%d, p=%d)", begin, n, p)
- }
- } else {
- if size != size0 && size != size0+1 {
- t.Fatalf("incorrect size: %d/%d (n=%d, p=%d)", size, size0, n, p)
- }
- if begin != end0 {
- t.Fatalf("incorrect begin/end: %d/%d (n=%d, p=%d)", begin, end0, n, p)
- }
- }
- end0 = end
- }
- if sum != n {
- t.Fatalf("incorrect sum: %d/%d (p=%d)", sum, n, p)
- }
- }
- }
-}
-
-// Test parallel parallelfor.
-func TestParForParallel(t *testing.T) {
- N := uint64(1e7)
- if testing.Short() {
- N /= 10
- }
- data := make([]uint64, N)
- for i := uint64(0); i < N; i++ {
- data[i] = i
- }
- P := GOMAXPROCS(-1)
- c := make(chan bool, P)
- desc := NewParFor(uint32(P))
- ParForSetup(desc, uint32(P), uint32(N), false, func(desc *ParFor, i uint32) {
- data[i] = data[i]*data[i] + 1
- })
- for p := 1; p < P; p++ {
- go func() {
- ParForDo(desc)
- c <- true
- }()
- }
- ParForDo(desc)
- for p := 1; p < P; p++ {
- <-c
- }
- for i := uint64(0); i < N; i++ {
- if data[i] != i*i+1 {
- t.Fatalf("Wrong element %d: %d", i, data[i])
- }
- }
-
- data, desc = nil, nil
- GC()
-}
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index 7d677cb64e..e09a33d5d9 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -346,7 +346,7 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
name := f.Name()
// Hide runtime.goexit and any runtime functions at the beginning.
// This is useful mainly for allocation traces.
- wasPanic = name == "runtime.panic"
+ wasPanic = name == "runtime.gopanic"
if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") {
continue
}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index d1f5088b50..389917916f 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -2406,7 +2406,7 @@ func entersyscallblock_handoff() {
// The goroutine g exited its system call.
// Arrange for it to run on a cpu again.
// This is called only from the go syscall library, not
-// from the low-level system calls used by the
+// from the low-level system calls used by the runtime.
//go:nosplit
func exitsyscall(dummy int32) {
_g_ := getg()
diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go
new file mode 100644
index 0000000000..2bd91c1ec0
--- /dev/null
+++ b/src/runtime/runtime-lldb_test.go
@@ -0,0 +1,262 @@
+// 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.
+
+package runtime_test
+
+import (
+ "debug/elf"
+ "debug/macho"
+ "encoding/binary"
+ "internal/testenv"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+var lldbPath string
+
+func checkLldbPython(t *testing.T) {
+ cmd := exec.Command("lldb", "-P")
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Skipf("skipping due to issue running lldb: %v\n%s", err, out)
+ }
+ lldbPath = strings.TrimSpace(string(out))
+
+ cmd = exec.Command("/usr/bin/python2.7", "-c", "import sys;sys.path.append(sys.argv[1]);import lldb; print('go lldb python support')", lldbPath)
+ out, err = cmd.CombinedOutput()
+
+ if err != nil {
+ t.Skipf("skipping due to issue running python: %v\n%s", err, out)
+ }
+ if string(out) != "go lldb python support\n" {
+ t.Skipf("skipping due to lack of python lldb support: %s", out)
+ }
+
+ if runtime.GOOS == "darwin" {
+ // Try to see if we have debugging permissions.
+ cmd = exec.Command("/usr/sbin/DevToolsSecurity", "-status")
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Skipf("DevToolsSecurity failed: %v", err)
+ } else if !strings.Contains(string(out), "enabled") {
+ t.Skip(string(out))
+ }
+ cmd = exec.Command("/usr/bin/groups")
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Skipf("groups failed: %v", err)
+ } else if !strings.Contains(string(out), "_developer") {
+ t.Skip("Not in _developer group")
+ }
+ }
+}
+
+const lldbHelloSource = `
+package main
+import "fmt"
+func main() {
+ mapvar := make(map[string]string,5)
+ mapvar["abc"] = "def"
+ mapvar["ghi"] = "jkl"
+ intvar := 42
+ ptrvar := &intvar
+ fmt.Println("hi") // line 10
+ _ = ptrvar
+}
+`
+
+const lldbScriptSource = `
+import sys
+sys.path.append(sys.argv[1])
+import lldb
+import os
+
+TIMEOUT_SECS = 5
+
+debugger = lldb.SBDebugger.Create()
+debugger.SetAsync(True)
+target = debugger.CreateTargetWithFileAndArch("a.exe", None)
+if target:
+ print "Created target"
+ main_bp = target.BreakpointCreateByLocation("main.go", 10)
+ if main_bp:
+ print "Created breakpoint"
+ process = target.LaunchSimple(None, None, os.getcwd())
+ if process:
+ print "Process launched"
+ listener = debugger.GetListener()
+ process.broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
+ while True:
+ event = lldb.SBEvent()
+ if listener.WaitForEvent(TIMEOUT_SECS, event):
+ if lldb.SBProcess.GetRestartedFromEvent(event):
+ continue
+ state = process.GetState()
+ if state in [lldb.eStateUnloaded, lldb.eStateLaunching, lldb.eStateRunning]:
+ continue
+ else:
+ print "Timeout launching"
+ break
+ if state == lldb.eStateStopped:
+ for t in process.threads:
+ if t.GetStopReason() == lldb.eStopReasonBreakpoint:
+ print "Hit breakpoint"
+ frame = t.GetFrameAtIndex(0)
+ if frame:
+ if frame.line_entry:
+ print "Stopped at %s:%d" % (frame.line_entry.file.basename, frame.line_entry.line)
+ if frame.function:
+ print "Stopped in %s" % (frame.function.name,)
+ var = frame.FindVariable('intvar')
+ if var:
+ print "intvar = %s" % (var.GetValue(),)
+ else:
+ print "no intvar"
+ else:
+ print "Process state", state
+ process.Destroy()
+else:
+ print "Failed to create target a.exe"
+
+lldb.SBDebugger.Destroy(debugger)
+sys.exit()
+`
+
+const expectedLldbOutput = `Created target
+Created breakpoint
+Process launched
+Hit breakpoint
+Stopped at main.go:10
+Stopped in main.main
+intvar = 42
+`
+
+func TestLldbPython(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
+ t.Skip("gdb test can fail with GOROOT_FINAL pending")
+ }
+
+ checkLldbPython(t)
+
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatalf("failed to create temp directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ src := filepath.Join(dir, "main.go")
+ err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644)
+ if err != nil {
+ t.Fatalf("failed to create file: %v", err)
+ }
+
+ cmd := exec.Command("go", "build", "-gcflags", "-N -l", "-o", "a.exe")
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("building source %v\n%s", err, out)
+ }
+
+ src = filepath.Join(dir, "script.py")
+ err = ioutil.WriteFile(src, []byte(lldbScriptSource), 0755)
+ if err != nil {
+ t.Fatalf("failed to create script: %v", err)
+ }
+
+ cmd = exec.Command("/usr/bin/python2.7", "script.py", lldbPath)
+ cmd.Dir = dir
+ got, _ := cmd.CombinedOutput()
+
+ if string(got) != expectedLldbOutput {
+ if strings.Contains(string(got), "Timeout launching") {
+ t.Skip("Timeout launching")
+ }
+ t.Fatalf("Unexpected lldb output:\n%s", got)
+ }
+}
+
+// Check that aranges are valid even when lldb isn't installed.
+func TestDwarfAranges(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatalf("failed to create temp directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ src := filepath.Join(dir, "main.go")
+ err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644)
+ if err != nil {
+ t.Fatalf("failed to create file: %v", err)
+ }
+
+ cmd := exec.Command("go", "build", "-o", "a.exe")
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("building source %v\n%s", err, out)
+ }
+
+ filename := filepath.Join(dir, "a.exe")
+ if f, err := elf.Open(filename); err == nil {
+ sect := f.Section(".debug_aranges")
+ if sect == nil {
+ t.Fatal("Missing aranges section")
+ }
+ verifyAranges(t, f.ByteOrder, sect.Open())
+ } else if f, err := macho.Open(filename); err == nil {
+ sect := f.Section("__debug_aranges")
+ if sect == nil {
+ t.Fatal("Missing aranges section")
+ }
+ verifyAranges(t, f.ByteOrder, sect.Open())
+ } else {
+ t.Skip("Not an elf or macho binary.")
+ }
+}
+
+func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker) {
+ var header struct {
+ UnitLength uint32 // does not include the UnitLength field
+ Version uint16
+ Offset uint32
+ AddressSize uint8
+ SegmentSize uint8
+ }
+ for {
+ offset, err := data.Seek(0, 1)
+ if err != nil {
+ t.Fatalf("Seek error: %v", err)
+ }
+ if err = binary.Read(data, byteorder, &header); err == io.EOF {
+ return
+ } else if err != nil {
+ t.Fatalf("Error reading arange header: %v", err)
+ }
+ tupleSize := int64(header.SegmentSize) + 2*int64(header.AddressSize)
+ lastTupleOffset := offset + int64(header.UnitLength) + 4 - tupleSize
+ if lastTupleOffset%tupleSize != 0 {
+ t.Fatalf("Invalid arange length %d, (addr %d, seg %d)", header.UnitLength, header.AddressSize, header.SegmentSize)
+ }
+ if _, err = data.Seek(lastTupleOffset, 0); err != nil {
+ t.Fatalf("Seek error: %v", err)
+ }
+ buf := make([]byte, tupleSize)
+ if n, err := data.Read(buf); err != nil || int64(n) < tupleSize {
+ t.Fatalf("Read error: %v", err)
+ }
+ for _, val := range buf {
+ if val != 0 {
+ t.Fatalf("Invalid terminator")
+ }
+ }
+ }
+}
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 917fe89d38..6a4dfa17b8 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -311,7 +311,6 @@ type m struct {
park note
alllink *m // on allm
schedlink muintptr
- machport uint32 // return address for mach ipc (os x)
mcache *mcache
lockedg *g
createstack [32]uintptr // stack that created this thread.
diff --git a/src/runtime/runtime_linux_test.go b/src/runtime/runtime_linux_test.go
index 5344ed2051..58c797f1dd 100644
--- a/src/runtime/runtime_linux_test.go
+++ b/src/runtime/runtime_linux_test.go
@@ -8,6 +8,7 @@ import (
. "runtime"
"syscall"
"testing"
+ "unsafe"
)
var pid, tid int
@@ -27,3 +28,15 @@ func TestLockOSThread(t *testing.T) {
t.Fatalf("pid=%d but tid=%d", pid, tid)
}
}
+
+// Test that error values are negative. Use address 1 (a misaligned
+// pointer) to get -EINVAL.
+func TestMincoreErrorSign(t *testing.T) {
+ var dst byte
+ v := Mincore(unsafe.Pointer(uintptr(1)), 1, &dst)
+
+ const EINVAL = 0x16
+ if v != -EINVAL {
+ t.Errorf("mincore = %v, want %v", v, -EINVAL)
+ }
+}
diff --git a/src/runtime/runtime_mmap_test.go b/src/runtime/runtime_mmap_test.go
new file mode 100644
index 0000000000..ff5e733cb0
--- /dev/null
+++ b/src/runtime/runtime_mmap_test.go
@@ -0,0 +1,30 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package runtime_test
+
+import (
+ "runtime"
+ "runtime/internal/sys"
+ "testing"
+)
+
+// Test that the error value returned by mmap is positive, as that is
+// what the code in mem_bsd.go, mem_darwin.go, and mem_linux.go expects.
+// See the uses of ENOMEM in sysMap in those files.
+func TestMmapErrorSign(t *testing.T) {
+ p := runtime.Mmap(nil, ^uintptr(0)&^(sys.PhysPageSize-1), 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0)
+
+ // The runtime.mmap function is nosplit, but t.Errorf is not.
+ // Reset the pointer so that we don't get an "invalid stack
+ // pointer" error from t.Errorf if we call it.
+ v := uintptr(p)
+ p = nil
+
+ if v != runtime.ENOMEM {
+ t.Errorf("mmap = %v, want %v", v, runtime.ENOMEM)
+ }
+}
diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go
index 150a25520a..37b75c1a89 100644
--- a/src/runtime/string_test.go
+++ b/src/runtime/string_test.go
@@ -102,6 +102,17 @@ func BenchmarkRuneIterate2(b *testing.B) {
}
}
+func BenchmarkArrayEqual(b *testing.B) {
+ a1 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+ a2 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ if a1 != a2 {
+ b.Fatal("not equal")
+ }
+ }
+}
+
func TestStringW(t *testing.T) {
strings := []string{
"hello",
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index f060182c22..6c28fd2e78 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -85,7 +85,7 @@ func fastrand1() uint32
// in asm_*.s
//go:noescape
-func memeq(a, b unsafe.Pointer, size uintptr) bool
+func memequal(a, b unsafe.Pointer, size uintptr) bool
// noescape hides a pointer from escape analysis. noescape is
// the identity function but escape analysis doesn't think the
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 82a8db9914..6b6437dddd 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -261,7 +261,7 @@ cont:
MOVW R1, 24(R6)
// switch stack and g
- MOVW R6, R13 // sigtramp can not re-entrant, so no need to back up R13.
+ MOVW R6, R13 // sigtramp is not re-entrant, so no need to back up R13.
MOVW R5, g
BL (R0)
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index d0034d5a33..a3b851d2fc 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -245,7 +245,7 @@ cont:
MOVD R1, 48(R6)
// switch stack and g
- MOVD R6, RSP // sigtramp can not re-entrant, so no need to back up RSP.
+ MOVD R6, RSP // sigtramp is not re-entrant, so no need to back up RSP.
MOVD R5, g
BL (R0)
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index aed85cb0aa..f407078176 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -258,7 +258,7 @@ TEXT runtime·sysMmap(SB),NOSPLIT,$0
// Call the function stored in _cgo_mmap using the GCC calling convention.
// This must be called on the system stack.
-TEXT runtime·callCgoMmap(SB),NOSPLIT,$0
+TEXT runtime·callCgoMmap(SB),NOSPLIT,$16
MOVQ addr+0(FP), DI
MOVQ n+8(FP), SI
MOVL prot+16(FP), DX
@@ -266,7 +266,11 @@ TEXT runtime·callCgoMmap(SB),NOSPLIT,$0
MOVL fd+24(FP), R8
MOVL off+28(FP), R9
MOVQ _cgo_mmap(SB), AX
+ MOVQ SP, BX
+ ANDQ $~15, SP // alignment as per amd64 psABI
+ MOVQ BX, 0(SP)
CALL AX
+ MOVQ 0(SP), SP
MOVQ AX, ret+32(FP)
RET
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index ca0e07aaa4..94c101a3d4 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -269,6 +269,9 @@ TEXT runtime·mmap(SB),NOSPLIT,$-8
MOVD $SYS_mmap, R8
SVC
+ CMN $4095, R0
+ BCC 2(PC)
+ NEG R0,R0
MOVD R0, ret+32(FP)
RET
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index 6ccb38f90b..26437ddde4 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -168,6 +168,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$-8-28
MOVV dst+16(FP), R6
MOVV $SYS_mincore, R2
SYSCALL
+ SUBVU R2, R0, R2 // caller expects negative errno
MOVW R2, ret+24(FP)
RET
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index ba410c51b6..d063e025a6 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -153,6 +153,7 @@ TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
MOVD n+8(FP), R4
MOVD dst+16(FP), R5
SYSCALL $SYS_mincore
+ NEG R3 // caller expects negative errno
MOVW R3, ret+24(FP)
RET
diff --git a/src/runtime/sys_nacl_386.s b/src/runtime/sys_nacl_386.s
index bf2d36ec85..e69a0b7bfe 100644
--- a/src/runtime/sys_nacl_386.s
+++ b/src/runtime/sys_nacl_386.s
@@ -227,6 +227,9 @@ TEXT runtime·mmap(SB),NOSPLIT,$32
LEAL 24(SP), AX
MOVL AX, 20(SP)
NACL_SYSCALL(SYS_mmap)
+ CMPL AX, $-4095
+ JNA 2(PC)
+ NEGL AX
MOVL AX, ret+24(FP)
RET
diff --git a/src/runtime/testdata/testprog/deadlock.go b/src/runtime/testdata/testprog/deadlock.go
index 7f0a0cd1e0..ff9c82d61b 100644
--- a/src/runtime/testdata/testprog/deadlock.go
+++ b/src/runtime/testdata/testprog/deadlock.go
@@ -29,7 +29,9 @@ func init() {
register("GoexitInPanic", GoexitInPanic)
register("PanicAfterGoexit", PanicAfterGoexit)
register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit)
-
+ register("PanicTraceback", PanicTraceback)
+ register("GoschedInPanic", GoschedInPanic)
+ register("SyscallInPanic", SyscallInPanic)
}
func SimpleDeadlock() {
@@ -152,6 +154,29 @@ func GoexitInPanic() {
runtime.Goexit()
}
+type errorThatGosched struct{}
+
+func (errorThatGosched) Error() string {
+ runtime.Gosched()
+ return "errorThatGosched"
+}
+
+func GoschedInPanic() {
+ panic(errorThatGosched{})
+}
+
+type errorThatPrint struct{}
+
+func (errorThatPrint) Error() string {
+ fmt.Println("1")
+ fmt.Println("2")
+ return "3"
+}
+
+func SyscallInPanic() {
+ panic(errorThatPrint{})
+}
+
func PanicAfterGoexit() {
defer func() {
panic("hello")
@@ -171,3 +196,21 @@ func RecoveredPanicAfterGoexit() {
}()
runtime.Goexit()
}
+
+func PanicTraceback() {
+ pt1()
+}
+
+func pt1() {
+ defer func() {
+ panic("panic pt1")
+ }()
+ pt2()
+}
+
+func pt2() {
+ defer func() {
+ panic("panic pt2")
+ }()
+ panic("hello")
+}
diff --git a/src/runtime/testdata/testprogcgo/cgo.go b/src/runtime/testdata/testprogcgo/cgo.go
index cf1af8268c..5d2550dbb0 100644
--- a/src/runtime/testdata/testprogcgo/cgo.go
+++ b/src/runtime/testdata/testprogcgo/cgo.go
@@ -6,17 +6,20 @@ package main
/*
void foo1(void) {}
+void foo2(void* p) {}
*/
import "C"
import (
"fmt"
"runtime"
"time"
+ "unsafe"
)
func init() {
register("CgoSignalDeadlock", CgoSignalDeadlock)
register("CgoTraceback", CgoTraceback)
+ register("CgoCheckBytes", CgoCheckBytes)
}
func CgoSignalDeadlock() {
@@ -78,3 +81,10 @@ func CgoTraceback() {
runtime.Stack(buf, true)
fmt.Printf("OK\n")
}
+
+func CgoCheckBytes() {
+ b := make([]byte, 1e6)
+ for i := 0; i < 1e3; i++ {
+ C.foo2(unsafe.Pointer(&b[0]))
+ }
+}
diff --git a/src/runtime/testdata/testprogcgo/deadlock.go b/src/runtime/testdata/testprogcgo/deadlock.go
new file mode 100644
index 0000000000..ac8855af3b
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/deadlock.go
@@ -0,0 +1,30 @@
+// 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.
+
+package main
+
+/*
+char *geterror() {
+ return "cgo error";
+}
+*/
+import "C"
+import (
+ "fmt"
+)
+
+func init() {
+ register("CgoPanicDeadlock", CgoPanicDeadlock)
+}
+
+type cgoError struct{}
+
+func (cgoError) Error() string {
+ fmt.Print("") // necessary to trigger the deadlock
+ return C.GoString(C.geterror())
+}
+
+func CgoPanicDeadlock() {
+ panic(cgoError{})
+}
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 6559cd7ba3..b4bfe71627 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -380,7 +380,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
tracepc--
}
- print(funcname(f), "(")
+ name := funcname(f)
+ if name == "runtime.gopanic" {
+ name = "panic"
+ }
+ print(name, "(")
argp := (*[100]uintptr)(unsafe.Pointer(frame.argp))
for i := uintptr(0); i < frame.arglen/sys.PtrSize; i++ {
if i >= 10 {
@@ -617,10 +621,10 @@ func showframe(f *_func, gp *g) bool {
level, _, _ := gotraceback()
name := funcname(f)
- // Special case: always show runtime.panic frame, so that we can
+ // Special case: always show runtime.gopanic frame, so that we can
// see where a panic started in the middle of a stack trace.
// See golang.org/issue/5832.
- if name == "runtime.panic" {
+ if name == "runtime.gopanic" {
return true
}
diff --git a/src/runtime/vdso_linux_amd64.go b/src/runtime/vdso_linux_amd64.go
index 38914bb2b9..42571e063c 100644
--- a/src/runtime/vdso_linux_amd64.go
+++ b/src/runtime/vdso_linux_amd64.go
@@ -263,7 +263,7 @@ func vdso_find_version(info *vdso_info, ver *version_key) int32 {
def = (*elf64Verdef)(add(unsafe.Pointer(def), uintptr(def.vd_next)))
}
- return -1 // can not match any version
+ return -1 // cannot match any version
}
func vdso_parse_symbols(info *vdso_info, version int32) {
diff --git a/src/sort/sort.go b/src/sort/sort.go
index ac8f4a661f..5eb45c6d4a 100644
--- a/src/sort/sort.go
+++ b/src/sort/sort.go
@@ -335,7 +335,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
// unstable or rely on enough different elements in each step to encode the
// performed block rearrangements. See also "In-Place Merging Algorithms",
// Denham Coates-Evely, Department of Computer Science, Kings College,
-// January 2004 and the reverences in there.
+// January 2004 and the references in there.
// - Often "optimal" algorithms are optimal in the number of assignments
// but Interface has only Swap as operation.
diff --git a/src/sync/pool.go b/src/sync/pool.go
index 381af0bead..4fb1a1af9d 100644
--- a/src/sync/pool.go
+++ b/src/sync/pool.go
@@ -149,7 +149,7 @@ func (p *Pool) getSlow() (x interface{}) {
func (p *Pool) pin() *poolLocal {
pid := runtime_procPin()
// In pinSlow we store to localSize and then to local, here we load in opposite order.
- // Since we've disabled preemption, GC can not happen in between.
+ // Since we've disabled preemption, GC cannot happen in between.
// Thus here we must observe local at least as large localSize.
// We can observe a newer/larger local, it is fine (we must observe its zero-initialized-ness).
s := atomic.LoadUintptr(&p.localSize) // load-acquire
diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go
index 0155800f34..dd87850fcd 100644
--- a/src/text/scanner/scanner.go
+++ b/src/text/scanner/scanner.go
@@ -333,7 +333,7 @@ func (s *Scanner) error(msg string) {
if !pos.IsValid() {
pos = s.Pos()
}
- fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg)
+ fmt.Fprintf(os.Stderr, "text/scanner: %s: %s\n", pos, msg)
}
func (s *Scanner) isIdentRune(ch rune, i int) bool {
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index efe1817173..5ea45a4c53 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -446,7 +446,7 @@ func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
switch {
case constant.IsComplex:
return reflect.ValueOf(constant.Complex128) // incontrovertible.
- case constant.IsFloat && !isHexConstant(constant.Text) && strings.IndexAny(constant.Text, ".eE") >= 0:
+ case constant.IsFloat && !isHexConstant(constant.Text) && strings.ContainsAny(constant.Text, ".eE"):
return reflect.ValueOf(constant.Float64)
case constant.IsInt:
n := int(constant.Int64)
diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
index 49e9e7419a..58b8ea372d 100644
--- a/src/text/template/funcs.go
+++ b/src/text/template/funcs.go
@@ -515,7 +515,7 @@ func HTMLEscape(w io.Writer, b []byte) {
// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
func HTMLEscapeString(s string) string {
// Avoid allocation if we can.
- if strings.IndexAny(s, `'"&<>`) < 0 {
+ if !strings.ContainsAny(s, `'"&<>`) {
return s
}
var b bytes.Buffer
diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go
index ea93e05142..079c0ea6f7 100644
--- a/src/text/template/parse/lex.go
+++ b/src/text/template/parse/lex.go
@@ -155,7 +155,7 @@ func (l *lexer) ignore() {
// accept consumes the next rune if it's from the valid set.
func (l *lexer) accept(valid string) bool {
- if strings.IndexRune(valid, l.next()) >= 0 {
+ if strings.ContainsRune(valid, l.next()) {
return true
}
l.backup()
@@ -164,7 +164,7 @@ func (l *lexer) accept(valid string) bool {
// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
- for strings.IndexRune(valid, l.next()) >= 0 {
+ for strings.ContainsRune(valid, l.next()) {
}
l.backup()
}
diff --git a/src/time/format_test.go b/src/time/format_test.go
index af950a7c25..8c47dbcdd1 100644
--- a/src/time/format_test.go
+++ b/src/time/format_test.go
@@ -447,7 +447,7 @@ func TestParseErrors(t *testing.T) {
_, err := Parse(test.format, test.value)
if err == nil {
t.Errorf("expected error for %q %q", test.format, test.value)
- } else if strings.Index(err.Error(), test.expect) < 0 {
+ } else if !strings.Contains(err.Error(), test.expect) {
t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
}
}
diff --git a/src/unicode/utf16/utf16.go b/src/unicode/utf16/utf16.go
index b497500778..276fce9e56 100644
--- a/src/unicode/utf16/utf16.go
+++ b/src/unicode/utf16/utf16.go
@@ -36,7 +36,7 @@ func IsSurrogate(r rune) bool {
// the Unicode replacement code point U+FFFD.
func DecodeRune(r1, r2 rune) rune {
if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
- return (r1-surr1)<<10 | (r2 - surr2) + 0x10000
+ return (r1-surr1)<<10 | (r2 - surr2) + surrSelf
}
return replacementChar
}
@@ -88,21 +88,19 @@ func Decode(s []uint16) []rune {
n := 0
for i := 0; i < len(s); i++ {
switch r := s[i]; {
+ case r < surr1, surr3 <= r:
+ // normal rune
+ a[n] = rune(r)
case surr1 <= r && r < surr2 && i+1 < len(s) &&
surr2 <= s[i+1] && s[i+1] < surr3:
// valid surrogate sequence
a[n] = DecodeRune(rune(r), rune(s[i+1]))
i++
- n++
- case surr1 <= r && r < surr3:
+ default:
// invalid surrogate sequence
a[n] = replacementChar
- n++
- default:
- // normal rune
- a[n] = rune(r)
- n++
}
+ n++
}
- return a[0:n]
+ return a[:n]
}
diff --git a/src/unicode/utf16/utf16_test.go b/src/unicode/utf16/utf16_test.go
index 3dca472bbe..e5be504e08 100644
--- a/src/unicode/utf16/utf16_test.go
+++ b/src/unicode/utf16/utf16_test.go
@@ -147,3 +147,56 @@ func TestIsSurrogate(t *testing.T) {
}
}
}
+
+func BenchmarkDecodeValidASCII(b *testing.B) {
+ // "hello world"
+ data := []uint16{104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100}
+ for i := 0; i < b.N; i++ {
+ Decode(data)
+ }
+}
+
+func BenchmarkDecodeValidJapaneseChars(b *testing.B) {
+ // "日本語日本語日本語"
+ data := []uint16{26085, 26412, 35486, 26085, 26412, 35486, 26085, 26412, 35486}
+ for i := 0; i < b.N; i++ {
+ Decode(data)
+ }
+}
+
+func BenchmarkDecodeRune(b *testing.B) {
+ rs := make([]rune, 10)
+ // U+1D4D0 to U+1D4D4: MATHEMATICAL BOLD SCRIPT CAPITAL LETTERS
+ for i, u := range []rune{'𝓐', '𝓑', '𝓒', '𝓓', '𝓔'} {
+ rs[2*i], rs[2*i+1] = EncodeRune(u)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ for j := 0; j < 5; j++ {
+ DecodeRune(rs[2*j], rs[2*j+1])
+ }
+ }
+}
+
+func BenchmarkEncodeValidASCII(b *testing.B) {
+ data := []rune{'h', 'e', 'l', 'l', 'o'}
+ for i := 0; i < b.N; i++ {
+ Encode(data)
+ }
+}
+
+func BenchmarkEncodeValidJapaneseChars(b *testing.B) {
+ data := []rune{'日', '本', '語'}
+ for i := 0; i < b.N; i++ {
+ Encode(data)
+ }
+}
+
+func BenchmarkEncodeRune(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _, u := range []rune{'𝓐', '𝓑', '𝓒', '𝓓', '𝓔'} {
+ EncodeRune(u)
+ }
+ }
+}
diff --git a/test/escape_iface.go b/test/escape_iface.go
index 2b1144ad2c..9149fa1770 100644
--- a/test/escape_iface.go
+++ b/test/escape_iface.go
@@ -225,3 +225,23 @@ func dotTypeEscape() *T2 { // #11931
T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap"
}
}
+
+func dotTypeEscape2() { // #13805
+ {
+ i := 0
+ var v int
+ var x interface{} = i // ERROR "i does not escape"
+ *(&v) = x.(int) // ERROR "&v does not escape"
+ }
+ {
+ i := 0
+ var x interface{} = i // ERROR "i does not escape"
+ sink = x.(int) // ERROR "x.\(int\) escapes to heap"
+
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ var x interface{} = &i // ERROR "&i escapes to heap"
+ sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap"
+ }
+}
diff --git a/test/fixedbugs/issue11610.go b/test/fixedbugs/issue11610.go
index a326249ed4..56f245dee5 100644
--- a/test/fixedbugs/issue11610.go
+++ b/test/fixedbugs/issue11610.go
@@ -9,9 +9,9 @@
package a
import"" // ERROR "import path is empty"
-var? // ERROR "invalid declaration"
+var? // ERROR "unexpected \?"
-var x int // ERROR "unexpected var"
+var x int // ERROR "unexpected var" "cannot declare name"
func main() {
}
diff --git a/test/fixedbugs/issue14331.dir/a.go b/test/fixedbugs/issue14331.dir/a.go
new file mode 100644
index 0000000000..1b7f853bc9
--- /dev/null
+++ b/test/fixedbugs/issue14331.dir/a.go
@@ -0,0 +1,14 @@
+// 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.
+
+package a
+
+var S struct {
+ Str string `tag`
+}
+
+func F() string {
+ v := S
+ return v.Str
+}
diff --git a/test/fixedbugs/issue14331.dir/b.go b/test/fixedbugs/issue14331.dir/b.go
new file mode 100644
index 0000000000..7a0abb2506
--- /dev/null
+++ b/test/fixedbugs/issue14331.dir/b.go
@@ -0,0 +1,11 @@
+// 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.
+
+package b
+
+import "./a"
+
+func G() string {
+ return a.F()
+}
diff --git a/test/fixedbugs/issue14331.go b/test/fixedbugs/issue14331.go
new file mode 100644
index 0000000000..32f3e5156c
--- /dev/null
+++ b/test/fixedbugs/issue14331.go
@@ -0,0 +1,9 @@
+// compiledir
+
+// 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.
+
+// Inline function misses struct tags.
+
+package ignored
diff --git a/test/fixedbugs/issue14405.go b/test/fixedbugs/issue14405.go
new file mode 100644
index 0000000000..c2a89464ea
--- /dev/null
+++ b/test/fixedbugs/issue14405.go
@@ -0,0 +1,17 @@
+// compile
+
+// 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.
+
+// Mention of field with large offset in struct literal causes crash
+package p
+
+type T struct {
+ Slice [1 << 20][]int
+ Ptr *int
+}
+
+func New(p *int) *T {
+ return &T{Ptr: p}
+}
diff --git a/test/linkx_run.go b/test/linkx_run.go
index a6c7c67014..440271ac4a 100644
--- a/test/linkx_run.go
+++ b/test/linkx_run.go
@@ -18,7 +18,7 @@ import (
)
func main() {
- test(" ") // old deprecated syntax
+ // test(" ") // old deprecated & removed syntax
test("=") // new syntax
}
diff --git a/test/writebarrier.go b/test/writebarrier.go
index 9b741a60df..dcd20a0225 100644
--- a/test/writebarrier.go
+++ b/test/writebarrier.go
@@ -144,3 +144,17 @@ type T8 struct {
func f16(x []T8, y T8) []T8 {
return append(x, y) // ERROR "write barrier"
}
+
+func t1(i interface{}) **int {
+ // From issue 14306, make sure we have write barriers in a type switch
+ // where the assigned variable escapes.
+ switch x := i.(type) { // ERROR "write barrier"
+ case *int:
+ return &x
+ }
+ switch y := i.(type) { // no write barrier here
+ case **int:
+ return y
+ }
+ return nil
+}