diff --git a/README.md b/README.md index 8cf23cae1e..49231bf25d 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,14 @@ BSD-style license found in the LICENSE file. Official binary distributions are available at https://golang.org/dl/. After downloading a binary release, visit https://golang.org/doc/install -or load doc/install.html in your web browser for installation +or load [doc/install.html](./doc/install.html) in your web browser for installation instructions. #### Install From Source If a binary distribution is not available for your combination of operating system and architecture, visit -https://golang.org/doc/install/source or load doc/install-source.html +https://golang.org/doc/install/source or load [doc/install-source.html](./doc/install-source.html) in your web browser for source installation instructions. ### Contributing diff --git a/doc/devel/release.html b/doc/devel/release.html index 30d1611509..584340b005 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -48,6 +48,15 @@ See the Go 1.10.2 milestone on our issue tracker for details.

+

+go1.10.3 (released 2018/06/05) includes fixes to the go command, and the +crypto/tls, crypto/x509, and strings packages. +In particular, it adds +minimal support to the go command for the vgo transition. +See the Go +1.10.3 milestone on our issue tracker for details. +

+

go1.9 (released 2017/08/24)

@@ -101,6 +110,15 @@ See the Go 1.9.6 milestone on our issue tracker for details.

+

+go1.9.7 (released 2018/06/05) includes fixes to the go command, and the +crypto/x509, and strings packages. +In particular, it adds +minimal support to the go command for the vgo transition. +See the Go +1.9.7 milestone on our issue tracker for details. +

+

go1.8 (released 2017/02/16)

diff --git a/misc/cgo/life/main.go b/misc/cgo/life/main.go index 45376fd05a..145a273bdd 100644 --- a/misc/cgo/life/main.go +++ b/misc/cgo/life/main.go @@ -1,4 +1,4 @@ -// cmpout -tags=use_go_run +// run -tags=use_go_run // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/misc/cgo/stdio/chain.go b/misc/cgo/stdio/chain.go index 0fa813cab7..cdc385208c 100644 --- a/misc/cgo/stdio/chain.go +++ b/misc/cgo/stdio/chain.go @@ -1,4 +1,4 @@ -// cmpout -tags=use_go_run +// run -tags=use_go_run // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/misc/cgo/stdio/fib.go b/misc/cgo/stdio/fib.go index 56e32552ee..58f185c90f 100644 --- a/misc/cgo/stdio/fib.go +++ b/misc/cgo/stdio/fib.go @@ -1,4 +1,4 @@ -// cmpout -tags=use_go_run +// run -tags=use_go_run // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/misc/cgo/stdio/hello.go b/misc/cgo/stdio/hello.go index 63bff4c617..56220d34be 100644 --- a/misc/cgo/stdio/hello.go +++ b/misc/cgo/stdio/hello.go @@ -1,4 +1,4 @@ -// cmpout -tags=use_go_run +// run -tags=use_go_run // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js index 142080bf55..151de2e2d1 100755 --- a/misc/wasm/wasm_exec.js +++ b/misc/wasm/wasm_exec.js @@ -51,7 +51,7 @@ global.Go = class { constructor() { - this.argv = []; + this.argv = ["js"]; this.env = {}; this.exit = (code) => { if (code !== 0) { @@ -143,6 +143,11 @@ mem().setInt32(sp + 16, (msec % 1000) * 1000000, true); }, + // func getRandomData(r []byte) + "runtime.getRandomData": (sp) => { + crypto.getRandomValues(loadSlice(sp + 8)); + }, + // func boolVal(value bool) Value "syscall/js.boolVal": (sp) => { storeValue(sp + 16, mem().getUint8(sp + 8) !== 0); diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go index 6e29698a14..1f89d0c59a 100644 --- a/src/archive/tar/format.go +++ b/src/archive/tar/format.go @@ -94,7 +94,7 @@ const ( // application can only parse GNU formatted archives. // // Reference: - // http://www.gnu.org/software/tar/manual/html_node/Standard.html + // https://www.gnu.org/software/tar/manual/html_node/Standard.html FormatGNU // Schily's tar format, which is incompatible with USTAR. diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go index 36b551ec2c..c545c5b830 100644 --- a/src/archive/zip/struct.go +++ b/src/archive/zip/struct.go @@ -202,7 +202,7 @@ func timeZone(offset time.Duration) *time.Location { // msDosTimeToTime converts an MS-DOS date and time into a time.Time. // The resolution is 2s. -// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx +// See: https://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx func msDosTimeToTime(dosDate, dosTime uint16) time.Time { return time.Date( // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980 @@ -222,7 +222,7 @@ func msDosTimeToTime(dosDate, dosTime uint16) time.Time { // timeToMsDosTime converts a time.Time to an MS-DOS date and time. // The resolution is 2s. -// See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx +// See: https://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) { fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9) fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11) diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go index 0f1a193345..506148ee30 100644 --- a/src/archive/zip/writer.go +++ b/src/archive/zip/writer.go @@ -72,7 +72,7 @@ func (w *Writer) SetComment(comment string) error { } // Close finishes writing the zip file by writing the central directory. -// It does not (and cannot) close the underlying writer. +// It does not 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 dc9d5e95d3..a2eca2ed12 100644 --- a/src/bytes/buffer.go +++ b/src/bytes/buffer.go @@ -202,6 +202,7 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { b.lastRead = opInvalid for { i := b.grow(MinRead) + b.buf = b.buf[:i] m, e := r.Read(b.buf[i:cap(b.buf)]) if m < 0 { panic(errNegativeRead) diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go index e4bbc12f6a..acbe5ca0c4 100644 --- a/src/bytes/buffer_test.go +++ b/src/bytes/buffer_test.go @@ -269,6 +269,39 @@ func TestReadFrom(t *testing.T) { } } +type panicReader struct{ panic bool } + +func (r panicReader) Read(p []byte) (int, error) { + if r.panic { + panic(nil) + } + return 0, io.EOF +} + +// Make sure that an empty Buffer remains empty when +// it is "grown" before a Read that panics +func TestReadFromPanicReader(t *testing.T) { + + // First verify non-panic behaviour + var buf Buffer + i, err := buf.ReadFrom(panicReader{}) + if err != nil { + t.Fatal(err) + } + if i != 0 { + t.Fatalf("unexpected return from bytes.ReadFrom (1): got: %d, want %d", i, 0) + } + check(t, "TestReadFromPanicReader (1)", &buf, "") + + // Confirm that when Reader panics, the emtpy buffer remains empty + var buf2 Buffer + defer func() { + recover() + check(t, "TestReadFromPanicReader (2)", &buf2, "") + }() + buf2.ReadFrom(panicReader{panic: true}) +} + func TestReadFromNegativeReader(t *testing.T) { var b Buffer defer func() { diff --git a/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s b/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s index 647628176a..afd1dfd313 100644 --- a/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s +++ b/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s @@ -371,5 +371,683 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 VPEXTRB $-1, X1, AX // c4e37914c8ff VPEXTRD $-1, X1, AX // c4e37916c8ff VPEXTRQ $-1, X1, AX // c4e3f916c8ff + // EVEX: High-16 X registers. + VADDPD X30, X1, X0 // 6291f50858c6 + VADDPD X2, X29, X0 // 62f1950058c2 + VADDPD X30, X29, X0 // 6291950058c6 + VADDPD X2, X1, X28 // 6261f50858e2 + VADDPD X30, X1, X28 // 6201f50858e6 + VADDPD X2, X29, X28 // 6261950058e2 + VADDPD X30, X29, X28 // 6201950058e6 + VADDPD X30, X11, X10 // 6211a50858d6 + VADDPD X12, X29, X10 // 6251950058d4 + VADDPD X30, X29, X10 // 6211950058d6 + VADDPD X12, X11, X28 // 6241a50858e4 + VADDPD X30, X11, X28 // 6201a50858e6 + VADDPD X12, X29, X28 // 6241950058e4 + VADDPD X30, X29, X28 // 6201950058e6 + VADDPD (AX), X29, X0 // 62f195005800 + VADDPD (AX), X1, X28 // 6261f5085820 + VADDPD (AX), X29, X28 // 626195005820 + VADDPD (AX), X29, X10 // 627195005810 + VADDPD (AX), X10, X28 // 6261ad085820 + VADDPD (CX)(AX*1), X29, X0 // 62f19500580401 + VADDPD (CX)(AX*1), X1, X28 // 6261f508582401 + VADDPD (CX)(AX*1), X29, X28 // 62619500582401 + VADDPD (CX)(AX*1), X29, X10 // 62719500581401 + VADDPD (CX)(AX*1), X10, X28 // 6261ad08582401 + VADDPD (CX)(AX*2), X29, X0 // 62f19500580441 + VADDPD (CX)(AX*2), X1, X28 // 6261f508582441 + VADDPD (CX)(AX*2), X29, X28 // 62619500582441 + VADDPD (CX)(AX*2), X29, X10 // 62719500581441 + VADDPD (CX)(AX*2), X10, X28 // 6261ad08582441 + // EVEX: displacement without Disp8. + VADDPD 15(AX), X29, X0 // 62f1950058800f000000 + VADDPD 15(AX), X1, X28 // 6261f50858a00f000000 + VADDPD 15(AX), X29, X28 // 6261950058a00f000000 + VADDPD 15(AX), X29, X10 // 6271950058900f000000 + VADDPD 15(AX), X10, X28 // 6261ad0858a00f000000 + VADDPD 15(CX)(AX*1), X29, X0 // 62f195005884010f000000 + VADDPD 15(CX)(AX*1), X1, X28 // 6261f50858a4010f000000 + VADDPD 15(CX)(AX*1), X29, X28 // 6261950058a4010f000000 + VADDPD 15(CX)(AX*1), X29, X10 // 627195005894010f000000 + VADDPD 15(CX)(AX*1), X10, X28 // 6261ad0858a4010f000000 + VADDPD 15(CX)(AX*2), X29, X0 // 62f195005884410f000000 + VADDPD 15(CX)(AX*2), X1, X28 // 6261f50858a4410f000000 + VADDPD 15(CX)(AX*2), X29, X28 // 6261950058a4410f000000 + VADDPD 15(CX)(AX*2), X29, X10 // 627195005894410f000000 + VADDPD 15(CX)(AX*2), X10, X28 // 6261ad0858a4410f000000 + // EVEX: compressed displacement (Disp8). + VADDPD 2032(DX), X29, X0 // 62f1950058427f + VADDPD 2032(DX), X1, X29 // 6261f508586a7f + VADDPD 2032(DX), X29, X28 // 6261950058627f + VADDPD 2032(DX)(AX*2), X29, X0 // 62f195005844427f + VADDPD 2032(DX)(AX*2), X1, X29 // 6261f508586c427f + VADDPD 2032(DX)(AX*2), X29, X28 // 626195005864427f + VADDPD 4064(DX), Y0, Y29 // 6261fd28586a7f + VADDPD 4064(DX), Y29, Y1 // 62f19520584a7f + VADDPD 4064(DX), Y28, Y29 // 62619d20586a7f + VADDPD 4064(DX)(AX*2), Y0, Y29 // 6261fd28586c427f + VADDPD 4064(DX)(AX*2), Y29, Y1 // 62f19520584c427f + VADDPD 8128(DX), Z0, Z29 // 6261fd48586a7f + VADDPD 8128(DX), Z29, Z1 // 62f19540584a7f + VADDPD 8128(DX), Z28, Z29 // 62619d40586a7f + VADDPD 8128(DX)(AX*2), Z0, Z29 // 6261fd48586c427f + VADDPD 8128(DX)(AX*2), Z29, Z1 // 62f19540584c427f + // EVEX: compressed displacement that does not fit into 8bits. + VADDPD 2048(DX), X29, X0 // 62f19500588200080000 + VADDPD 2048(DX), X1, X29 // 6261f50858aa00080000 + VADDPD 2048(DX), X29, X28 // 6261950058a200080000 + VADDPD 2048(DX)(AX*2), X29, X0 // 62f1950058844200080000 + VADDPD 2048(DX)(AX*2), X1, X29 // 6261f50858ac4200080000 + VADDPD 2048(DX)(AX*2), X29, X28 // 6261950058a44200080000 + VADDPD 4096(DX), Y0, Y29 // 6261fd2858aa00100000 + VADDPD 4096(DX), Y29, Y1 // 62f19520588a00100000 + VADDPD 4096(DX), Y28, Y29 // 62619d2058aa00100000 + VADDPD 4096(DX)(AX*2), Y0, Y29 // 6261fd2858ac4200100000 + VADDPD 4096(DX)(AX*2), Y29, Y1 // 62f19520588c4200100000 + VADDPD 8192(DX), Z0, Z29 // 6261fd4858aa00200000 + VADDPD 8192(DX), Z29, Z1 // 62f19540588a00200000 + VADDPD 8192(DX), Z28, Z29 // 62619d4058aa00200000 + VADDPD 8192(DX)(AX*2), Z0, Z29 // 6261fd4858ac4200200000 + VADDPD 8192(DX)(AX*2), Z29, Z1 // 62f19540588c4200200000 + // EVEX: Y registers; VL=256. + VADDPD Y30, Y1, Y0 // 6291f52858c6 + VADDPD Y0, Y29, Y2 // 62f1952058d0 + VADDPD Y0, Y29, Y30 // 6261952058f0 + VADDPD Y28, Y1, Y2 // 6291f52858d4 + VADDPD Y28, Y1, Y30 // 6201f52858f4 + VADDPD Y28, Y29, Y2 // 6291952058d4 + VADDPD Y28, Y29, Y30 // 6201952058f4 + VADDPD Y10, Y11, Y30 // 6241a52858f2 + VADDPD Y10, Y29, Y12 // 6251952058e2 + VADDPD Y10, Y29, Y30 // 6241952058f2 + VADDPD Y28, Y11, Y12 // 6211a52858e4 + VADDPD Y28, Y11, Y30 // 6201a52858f4 + VADDPD Y28, Y29, Y12 // 6211952058e4 + VADDPD Y28, Y29, Y30 // 6201952058f4 + VADDPD (AX), Y29, Y0 // 62f195205800 + VADDPD (AX), Y1, Y28 // 6261f5285820 + VADDPD (AX), Y29, Y28 // 626195205820 + VADDPD (AX), Y29, Y10 // 627195205810 + VADDPD (AX), Y10, Y28 // 6261ad285820 + VADDPD (CX)(AX*1), Y29, Y0 // 62f19520580401 + VADDPD (CX)(AX*1), Y1, Y28 // 6261f528582401 + VADDPD (CX)(AX*1), Y29, Y28 // 62619520582401 + VADDPD (CX)(AX*1), Y29, Y10 // 62719520581401 + VADDPD (CX)(AX*1), Y10, Y28 // 6261ad28582401 + VADDPD (CX)(AX*2), Y29, Y0 // 62f19520580441 + VADDPD (CX)(AX*2), Y1, Y28 // 6261f528582441 + VADDPD (CX)(AX*2), Y29, Y28 // 62619520582441 + VADDPD (CX)(AX*2), Y29, Y10 // 62719520581441 + VADDPD (CX)(AX*2), Y10, Y28 // 6261ad28582441 + VADDPD 15(AX), Y0, Y29 // 6261fd2858a80f000000 + VADDPD 15(AX), Y28, Y1 // 62f19d2058880f000000 + VADDPD 15(AX), Y28, Y29 // 62619d2058a80f000000 + VADDPD 15(AX), Y10, Y29 // 6261ad2858a80f000000 + VADDPD 15(AX), Y28, Y10 // 62719d2058900f000000 + VADDPD 15(CX)(AX*1), Y0, Y29 // 6261fd2858ac010f000000 + VADDPD 15(CX)(AX*1), Y28, Y1 // 62f19d20588c010f000000 + VADDPD 15(CX)(AX*1), Y28, Y29 // 62619d2058ac010f000000 + VADDPD 15(CX)(AX*1), Y10, Y29 // 6261ad2858ac010f000000 + VADDPD 15(CX)(AX*1), Y28, Y10 // 62719d205894010f000000 + VADDPD 15(CX)(AX*2), Y0, Y29 // 6261fd2858ac410f000000 + VADDPD 15(CX)(AX*2), Y28, Y1 // 62f19d20588c410f000000 + VADDPD 15(CX)(AX*2), Y28, Y29 // 62619d2058ac410f000000 + VADDPD 15(CX)(AX*2), Y10, Y29 // 6261ad2858ac410f000000 + VADDPD 15(CX)(AX*2), Y28, Y10 // 62719d205894410f000000 + VADDPD 2048(DX), Y0, Y29 // 6261fd28586a40 + VADDPD 2048(DX), Y29, Y1 // 62f19520584a40 + VADDPD 2048(DX), Y28, Y29 // 62619d20586a40 + VADDPD 2048(DX)(AX*2), Y0, Y29 // 6261fd28586c4240 + VADDPD 2048(DX)(AX*2), Y29, Y1 // 62f19520584c4240 + VADDPD 2048(DX)(AX*2), Y28, Y29 // 62619d20586c4240 + // EVEX: Z registers; VL=512. + VADDPD Z30, Z0, Z1 // 6291fd4858ce + VADDPD Z0, Z2, Z29 // 6261ed4858e8 + VADDPD Z0, Z30, Z29 // 62618d4058e8 + VADDPD Z28, Z2, Z1 // 6291ed4858cc + VADDPD Z28, Z30, Z1 // 62918d4058cc + VADDPD Z28, Z2, Z29 // 6201ed4858ec + VADDPD Z28, Z30, Z29 // 62018d4058ec + VADDPD Z10, Z30, Z11 // 62518d4058da + VADDPD Z10, Z12, Z29 // 62419d4858ea + VADDPD Z10, Z30, Z29 // 62418d4058ea + VADDPD Z28, Z12, Z11 // 62119d4858dc + VADDPD Z28, Z30, Z11 // 62118d4058dc + VADDPD Z28, Z12, Z29 // 62019d4858ec + VADDPD Z28, Z30, Z29 // 62018d4058ec + VADDPD (AX), Z0, Z29 // 6261fd485828 + VADDPD (AX), Z28, Z1 // 62f19d405808 + VADDPD (AX), Z28, Z29 // 62619d405828 + VADDPD (AX), Z10, Z29 // 6261ad485828 + VADDPD (AX), Z28, Z10 // 62719d405810 + VADDPD (CX)(AX*1), Z0, Z29 // 6261fd48582c01 + VADDPD (CX)(AX*1), Z28, Z1 // 62f19d40580c01 + VADDPD (CX)(AX*1), Z28, Z29 // 62619d40582c01 + VADDPD (CX)(AX*1), Z10, Z29 // 6261ad48582c01 + VADDPD (CX)(AX*1), Z28, Z10 // 62719d40581401 + VADDPD (CX)(AX*2), Z0, Z29 // 6261fd48582c41 + VADDPD (CX)(AX*2), Z28, Z1 // 62f19d40580c41 + VADDPD (CX)(AX*2), Z28, Z29 // 62619d40582c41 + VADDPD (CX)(AX*2), Z10, Z29 // 6261ad48582c41 + VADDPD (CX)(AX*2), Z28, Z10 // 62719d40581441 + VADDPD 15(AX), Z29, Z0 // 62f1954058800f000000 + VADDPD 15(AX), Z1, Z28 // 6261f54858a00f000000 + VADDPD 15(AX), Z29, Z28 // 6261954058a00f000000 + VADDPD 15(AX), Z29, Z10 // 6271954058900f000000 + VADDPD 15(AX), Z10, Z28 // 6261ad4858a00f000000 + VADDPD 15(CX)(AX*1), Z29, Z0 // 62f195405884010f000000 + VADDPD 15(CX)(AX*1), Z1, Z28 // 6261f54858a4010f000000 + VADDPD 15(CX)(AX*1), Z29, Z28 // 6261954058a4010f000000 + VADDPD 15(CX)(AX*1), Z29, Z10 // 627195405894010f000000 + VADDPD 15(CX)(AX*1), Z10, Z28 // 6261ad4858a4010f000000 + VADDPD 15(CX)(AX*2), Z29, Z0 // 62f195405884410f000000 + VADDPD 15(CX)(AX*2), Z1, Z28 // 6261f54858a4410f000000 + VADDPD 15(CX)(AX*2), Z29, Z28 // 6261954058a4410f000000 + VADDPD 15(CX)(AX*2), Z29, Z10 // 627195405894410f000000 + VADDPD 15(CX)(AX*2), Z10, Z28 // 6261ad4858a4410f000000 + VADDPD 2048(DX), Z29, Z0 // 62f19540584220 + VADDPD 2048(DX), Z1, Z29 // 6261f548586a20 + VADDPD 2048(DX), Z29, Z28 // 62619540586220 + VADDPD 2048(DX)(AX*2), Z29, Z0 // 62f1954058444220 + VADDPD 2048(DX)(AX*2), Z1, Z29 // 6261f548586c4220 + VADDPD 2048(DX)(AX*2), Z29, Z28 // 6261954058644220 + // EVEX: KOP (opmask) instructions. + KMOVB K0, K0 // c5f990c0 + KMOVB K7, K7 // c5f990ff + KMOVB K5, K1 // c5f990cd + KMOVB K1, K5 // c5f990e9 + KMOVB (AX), K1 // c5f99008 + KMOVB K0, (AX) // c5f99100 + KMOVB K7, (R10) // c4c179913a + KMOVB K5, AX // c5f993c5 + KMOVB K7, R10 // c57993d7 + KMOVB AX, K5 // c5f992e8 + KMOVB R10, K7 // c4c17992fa + KMOVW K0, K0 // c5f890c0 + KMOVW K7, K7 // c5f890ff + KMOVW K5, K1 // c5f890cd + KMOVW K1, K5 // c5f890e9 + KMOVW (AX), K1 // c5f89008 + KMOVW K0, (AX) // c5f89100 + KMOVW K7, (R10) // c4c178913a + KMOVW K5, AX // c5f893c5 + KMOVW K7, R10 // c57893d7 + KMOVW AX, K5 // c5f892e8 + KMOVW R10, K7 // c4c17892fa + KMOVD K0, K0 // c4e1f990c0 + KMOVD K7, K7 // c4e1f990ff + KMOVD K5, K1 // c4e1f990cd + KMOVD K1, K5 // c4e1f990e9 + KMOVD (AX), K1 // c4e1f99008 + KMOVD AX, K5 // c5fb92e8 + KMOVD R10, K7 // c4c17b92fa + KMOVD K0, (AX) // c4e1f99100 + KMOVD K7, (R10) // c4c1f9913a + KMOVD K5, AX // c5fb93c5 + KMOVD K7, R10 // c57b93d7 + KMOVQ K0, K0 // c4e1f890c0 + KMOVQ K7, K7 // c4e1f890ff + KMOVQ K5, K1 // c4e1f890cd + KMOVQ K1, K5 // c4e1f890e9 + KMOVQ (AX), K1 // c4e1f89008 + KMOVQ AX, K5 // c4e1fb92e8 + KMOVQ R10, K7 // c4c1fb92fa + KMOVQ K0, (AX) // c4e1f89100 + KMOVQ K7, (R10) // c4c1f8913a + KMOVQ K5, AX // c4e1fb93c5 + KMOVQ K7, R10 // c461fb93d7 + KNOTB K7, K0 // c5f944c7 + KNOTB K1, K5 // c5f944e9 + KNOTW K7, K0 // c5f844c7 + KNOTW K1, K5 // c5f844e9 + KNOTD K7, K0 // c4e1f944c7 + KNOTD K1, K5 // c4e1f944e9 + KNOTQ K7, K0 // c4e1f844c7 + KNOTQ K1, K5 // c4e1f844e9 + KORB K7, K5, K0 // c5d545c7 + KORB K0, K7, K5 // c5c545e8 + KORW K7, K5, K0 // c5d445c7 + KORW K0, K7, K5 // c5c445e8 + KORD K7, K5, K0 // c4e1d545c7 + KORD K0, K7, K5 // c4e1c545e8 + KORQ K7, K5, K0 // c4e1d445c7 + KORQ K0, K7, K5 // c4e1c445e8 + KSHIFTLB $0, K7, K0 // c4e37932c700 + KSHIFTLB $196, K1, K5 // c4e37932e9c4 + KSHIFTLW $0, K7, K0 // c4e3f932c700 + KSHIFTLW $196, K1, K5 // c4e3f932e9c4 + KSHIFTLD $0, K7, K0 // c4e37933c700 + KSHIFTLD $196, K1, K5 // c4e37933e9c4 + KSHIFTLQ $0, K7, K0 // c4e3f933c700 + KSHIFTLQ $196, K1, K5 // c4e3f933e9c4 + // EVEX: masking with K1-K7. + VADDPD X2, X1, K1, X0 // 62f1f50958c2 + VADDPD X12, X1, K4, X10 // 6251f50c58d4 + VADDPD X22, X1, K7, X20 // 62a1f50f58e6 + VADDPD (AX), X1, K1, X1 // 62f1f5095808 + VADDPD 8(R10), X10, K4, X10 // 6251ad0c589208000000 + VADDPD (R10)(AX*4), X20, K7, X20 // 62c1dd07582482 + VADDPD Y2, Y1, K1, Y0 // 62f1f52958c2 + VADDPD Y12, Y1, K4, Y10 // 6251f52c58d4 + VADDPD Y22, Y1, K7, Y20 // 62a1f52f58e6 + VADDPD (AX), Y1, K1, Y1 // 62f1f5295808 + VADDPD 8(R10), Y10, K4, Y10 // 6251ad2c589208000000 + VADDPD (R10)(AX*4), Y20, K7, Y20 // 62c1dd27582482 + VADDPD Z2, Z1, K1, Z0 // 62f1f54958c2 + VADDPD Z12, Z1, K4, Z10 // 6251f54c58d4 + VADDPD Z22, Z1, K7, Z20 // 62a1f54f58e6 + VADDPD (AX), Z1, K1, Z1 // 62f1f5495808 + VADDPD 8(R10), Z10, K4, Z10 // 6251ad4c589208000000 + VADDPD (R10)(AX*4), Z20, K7, Z20 // 62c1dd47582482 + // EVEX gather (also tests Z as VSIB index). + VPGATHERDD 360(AX)(X2*4), K1, X1 // 62f27d09904c905a + VPGATHERDD 640(BP)(X15*8), K3, X14 // 62327d0b90b4fd80020000 + VPGATHERDD 960(R10)(X25*2), K7, X24 // 62027d0790844ac0030000 + VPGATHERDD 1280(R10)(X1*4), K4, X0 // 62d27d0c90848a00050000 + VPGATHERDD 360(AX)(Y2*4), K1, Y1 // 62f27d29904c905a + VPGATHERDD 640(BP)(Y15*8), K3, Y14 // 62327d2b90b4fd80020000 + VPGATHERDD 960(R10)(Y25*2), K7, Y24 // 62027d2790844ac0030000 + VPGATHERDD 1280(R10)(Y1*4), K4, Y0 // 62d27d2c90848a00050000 + VPGATHERDD 360(AX)(Z2*4), K1, Z1 // 62f27d49904c905a + VPGATHERDD 640(BP)(Z15*8), K3, Z14 // 62327d4b90b4fd80020000 + VPGATHERDD 960(R10)(Z25*2), K7, Z24 // 62027d4790844ac0030000 + VPGATHERDD 1280(R10)(Z1*4), K4, Z0 // 62d27d4c90848a00050000 + VPGATHERDQ 360(AX)(X2*4), K1, X1 // 62f2fd09904c902d + VPGATHERDQ 640(BP)(X15*8), K3, X14 // 6232fd0b9074fd50 + VPGATHERDQ 960(R10)(X25*2), K7, X24 // 6202fd0790444a78 + VPGATHERDQ 1280(R10)(X1*4), K4, X0 // 62d2fd0c90848a00050000 + VPGATHERDQ 360(AX)(X2*4), K1, Y1 // 62f2fd29904c902d + VPGATHERDQ 640(BP)(X15*8), K3, Y14 // 6232fd2b9074fd50 + VPGATHERDQ 960(R10)(X25*2), K7, Y24 // 6202fd2790444a78 + VPGATHERDQ 1280(R10)(X1*4), K4, Y0 // 62d2fd2c90848a00050000 + VPGATHERDQ 360(AX)(Y2*4), K1, Z1 // 62f2fd49904c902d + VPGATHERDQ 640(BP)(Y15*8), K3, Z14 // 6232fd4b9074fd50 + VPGATHERDQ 960(R10)(Y25*2), K7, Z24 // 6202fd4790444a78 + VPGATHERDQ 1280(R10)(Y1*4), K4, Z0 // 62d2fd4c90848a00050000 + VGATHERDPD 360(R15)(X30*2), K6, X20 // 6282fd069264772d + VGATHERDPD 640(R15)(X20*2), K6, X10 // 6252fd0692546750 + VGATHERDPD 960(R15)(X10*2), K6, X20 // 6282fd0e92645778 + VGATHERDPD 1280(R15)(X0*2), K6, X10 // 6252fd0e92944700050000 + VGATHERDPD 360(R15)(X30*2), K6, Y20 // 6282fd269264772d + VGATHERDPD 640(R15)(X20*2), K6, Y10 // 6252fd2692546750 + VGATHERDPD 960(R15)(X10*2), K6, Y20 // 6282fd2e92645778 + VGATHERDPD 1280(R15)(X0*2), K6, Y10 // 6252fd2e92944700050000 + VGATHERDPD 360(R15)(Y30*2), K6, Z20 // 6282fd469264772d + VGATHERDPD 640(R15)(Y20*2), K6, Z10 // 6252fd4692546750 + VGATHERDPD 960(R15)(Y10*2), K6, Z20 // 6282fd4e92645778 + VGATHERDPD 1280(R15)(Y0*2), K6, Z10 // 6252fd4e92944700050000 + VGATHERDPS 360(R15)(X30*2), K6, X20 // 62827d069264775a + VGATHERDPS 640(R15)(X20*2), K6, X10 // 62527d0692946780020000 + VGATHERDPS 960(R15)(X10*2), K6, X20 // 62827d0e92a457c0030000 + VGATHERDPS 1280(R15)(X0*2), K6, X10 // 62527d0e92944700050000 + VGATHERDPS 360(R15)(Y30*2), K6, Y20 // 62827d269264775a + VGATHERDPS 640(R15)(Y20*2), K6, Y10 // 62527d2692946780020000 + VGATHERDPS 960(R15)(Y10*2), K6, Y20 // 62827d2e92a457c0030000 + VGATHERDPS 1280(R15)(Y0*2), K6, Y10 // 62527d2e92944700050000 + VGATHERDPS 360(R15)(Z30*2), K6, Z20 // 62827d469264775a + VGATHERDPS 640(R15)(Z20*2), K6, Z10 // 62527d4692946780020000 + VGATHERDPS 960(R15)(Z10*2), K6, Z20 // 62827d4e92a457c0030000 + VGATHERDPS 1280(R15)(Z0*2), K6, Z10 // 62527d4e92944700050000 + VGATHERQPS 360(R15)(X30*2), K6, X20 // 62827d069364775a + VGATHERQPS 640(R15)(X20*2), K6, X10 // 62527d0693946780020000 + VGATHERQPS 960(R15)(X10*2), K6, X20 // 62827d0e93a457c0030000 + VGATHERQPS 1280(R15)(X0*2), K6, X10 // 62527d0e93944700050000 + VGATHERQPS 360(R15)(Y30*2), K6, X20 // 62827d269364775a + VGATHERQPS 640(R15)(Y20*2), K6, X10 // 62527d2693946780020000 + VGATHERQPS 960(R15)(Y10*2), K6, X20 // 62827d2e93a457c0030000 + VGATHERQPS 1280(R15)(Y0*2), K6, X10 // 62527d2e93944700050000 + VGATHERQPS 360(R15)(Z30*2), K6, Y20 // 62827d469364775a + VGATHERQPS 640(R15)(Z20*2), K6, Y10 // 62527d4693946780020000 + VGATHERQPS 960(R15)(Z10*2), K6, Y20 // 62827d4e93a457c0030000 + VGATHERQPS 1280(R15)(Z0*2), K6, Y10 // 62527d4e93944700050000 + VPGATHERQD 360(R15)(X30*2), K6, X20 // 62827d069164775a + VPGATHERQD 640(R15)(X20*2), K6, X10 // 62527d0691946780020000 + VPGATHERQD 960(R15)(X10*2), K6, X20 // 62827d0e91a457c0030000 + VPGATHERQD 1280(R15)(X0*2), K6, X10 // 62527d0e91944700050000 + VPGATHERQD 360(R15)(Y30*2), K6, X20 // 62827d269164775a + VPGATHERQD 640(R15)(Y20*2), K6, X10 // 62527d2691946780020000 + VPGATHERQD 960(R15)(Y10*2), K6, X20 // 62827d2e91a457c0030000 + VPGATHERQD 1280(R15)(Y0*2), K6, X10 // 62527d2e91944700050000 + VPGATHERQD 360(R15)(Z30*2), K6, Y20 // 62827d469164775a + VPGATHERQD 640(R15)(Z20*2), K6, Y10 // 62527d4691946780020000 + VPGATHERQD 960(R15)(Z10*2), K6, Y20 // 62827d4e91a457c0030000 + VPGATHERQD 1280(R15)(Z0*2), K6, Y10 // 62527d4e91944700050000 + VPGATHERQQ 360(R15)(X30*2), K6, X20 // 6282fd069164772d + VPGATHERQQ 640(R15)(X20*2), K6, X10 // 6252fd0691546750 + VPGATHERQQ 960(R15)(X10*2), K6, X20 // 6282fd0e91645778 + VPGATHERQQ 1280(R15)(X0*2), K6, X10 // 6252fd0e91944700050000 + VPGATHERQQ 360(R15)(Y30*2), K6, Y20 // 6282fd269164772d + VPGATHERQQ 640(R15)(Y20*2), K6, Y10 // 6252fd2691546750 + VPGATHERQQ 960(R15)(Y10*2), K6, Y20 // 6282fd2e91645778 + VPGATHERQQ 1280(R15)(Y0*2), K6, Y10 // 6252fd2e91944700050000 + VPGATHERQQ 360(R15)(Z30*2), K6, Z20 // 6282fd469164772d + VPGATHERQQ 640(R15)(Z20*2), K6, Z10 // 6252fd4691546750 + VPGATHERQQ 960(R15)(Z10*2), K6, Z20 // 6282fd4e91645778 + VPGATHERQQ 1280(R15)(Z0*2), K6, Z10 // 6252fd4e91944700050000 + VGATHERQPD 360(R15)(X30*2), K6, X20 // 6282fd069364772d + VGATHERQPD 640(R15)(X20*2), K6, X10 // 6252fd0693546750 + VGATHERQPD 960(R15)(X10*2), K6, X20 // 6282fd0e93645778 + VGATHERQPD 1280(R15)(X0*2), K6, X10 // 6252fd0e93944700050000 + VGATHERQPD 360(R15)(Y30*2), K6, Y20 // 6282fd269364772d + VGATHERQPD 640(R15)(Y20*2), K6, Y10 // 6252fd2693546750 + VGATHERQPD 960(R15)(Y10*2), K6, Y20 // 6282fd2e93645778 + VGATHERQPD 1280(R15)(Y0*2), K6, Y10 // 6252fd2e93944700050000 + VGATHERQPD 360(R15)(Z30*2), K6, Z20 // 6282fd469364772d + VGATHERQPD 640(R15)(Z20*2), K6, Z10 // 6252fd4693546750 + VGATHERQPD 960(R15)(Z10*2), K6, Z20 // 6282fd4e93645778 + VGATHERQPD 1280(R15)(Z0*2), K6, Z10 // 6252fd4e93944700050000 + // EVEX: corner cases for High-16 registers. + VADDPD X31, X16, X15 // 6211fd0058ff + VADDPD X23, X15, X16 // 62a1850858c7 + VADDPD Y31, Y16, Y15 // 6211fd2058ff + VADDPD Y23, Y15, Y16 // 62a1852858c7 + VADDPD Z31, Z16, Z15 // 6211fd4058ff + VADDPD Z23, Z15, Z16 // 62a1854858c7 + VGATHERQPD (DX)(X16*1),K1,X31 // 6262fd01933c02 + VGATHERQPD (DX)(X31*1),K1,X16 // 62a2fd0193043a + VGATHERQPD (DX)(X15*1),K1,X23 // 62a2fd09933c3a + VGATHERQPD (DX)(X23*1),K1,X15 // 6272fd01933c3a + VGATHERQPD (DX)(Y16*1),K1,Y31 // 6262fd21933c02 + VGATHERQPD (DX)(Y31*1),K1,Y16 // 62a2fd2193043a + VGATHERQPD (DX)(Y15*1),K1,Y23 // 62a2fd29933c3a + VGATHERQPD (DX)(Y23*1),K1,Y15 // 6272fd21933c3a + VGATHERQPD (DX)(Z16*1),K1,Z31 // 6262fd41933c02 + VGATHERQPD (DX)(Z31*1),K1,Z16 // 62a2fd4193043a + VGATHERQPD (DX)(Z15*1),K1,Z23 // 62a2fd49933c3a + VGATHERQPD (DX)(Z23*1),K1,Z15 // 6272fd41933c3a + // EVEX: VCVTPD2DQ with Y suffix (VL=2). + VCVTPD2DQY (BX), X20 // 62e1ff28e623 + VCVTPD2DQY (R11), X30 // 6241ff28e633 + // XED encoder uses EVEX.X=0 for these; most x86 tools use EVEX.X=1. + // Either way is OK. + VMOVQ SP, X20 // 62e1fd086ee4 or 62a1fd086ee4 + VMOVQ BP, X20 // 62e1fd086ee5 or 62a1fd086ee5 + VMOVQ R14, X20 // 62c1fd086ee6 or 6281fd086ee6 + // "VMOVQ r/m64, xmm1"/6E vs "VMOVQ xmm2/m64, xmm1"/7E with mem operand. + VMOVQ (AX), X20 // 62e1fd086e20 or 62e1fe087e20 + VMOVQ 7(DX), X20 // 62e1fd086ea207000000 or 62e1fe087ea207000000 + VMOVQ -15(R11)(CX*1), X20 // 62c1fd086ea40bf1ffffff or 62c1fe087ea40bf1ffffff + VMOVQ (SP)(AX*2), X20 // 62e1fd086e2444 or 62e1fe087e2444 + // "VMOVQ xmm1, r/m64"/7E vs "VMOVQ xmm1, xmm2/m64"/D6 with mem operand. + VMOVQ X20, (AX) // 62e1fd087e20 or 62e1fd08d620 + VMOVQ X20, 7(DX) // 62e1fd087ea207000000 or 62e1fd08d6a207000000 + VMOVQ X20, -15(R11)(CX*1) // 62c1fd087ea40bf1ffffff or 62c1fd08d6a40bf1ffffff + VMOVQ X20, (SP)(AX*2) // 62e1fd087e2444 or 62e1fd08d62444 + // VMOVHPD: overlapping VEX and EVEX variants. + VMOVHPD (AX), X5, X5 // c5d11628 or c4e1d11628 or 62f1d5281628 or 62f1d5481628 + VMOVHPD 7(DX), X5, X5 // c5d1166a07 or 62f1d52816aa07000000 or 62f1d54816aa07000000 + VMOVHPD -15(R11)(CX*1), X5, X5 // c4c151166c0bf1 or 62d1d52816ac0bf1ffffff or 62d1d54816ac0bf1ffffff + VMOVHPD (SP)(AX*2), X5, X5 // c5d1162c44 or c4e1d1162c44 or 62f1d528162c44 or 62f1d548162c44 + VMOVHPD (AX), X8, X5 // c5b91628 or c4e1b91628 or 62f1bd281628 or 62f1bd481628 + VMOVHPD 7(DX), X8, X5 // c5b9166a07 or 62f1bd2816aa07000000 or 62f1bd4816aa07000000 + VMOVHPD -15(R11)(CX*1), X8, X5 // c4c139166c0bf1 or 62d1bd4816ac0bf1ffffff + VMOVHPD (SP)(AX*2), X8, X5 // c5b9162c44 or c4e1b9162c44 or 62f1bd28162c44 or 62f1bd48162c44 + VMOVHPD (AX), X20, X5 // 62f1dd001628 or 62f1dd201628 or 62f1dd401628 + VMOVHPD 7(DX), X20, X5 // 62f1dd0016aa07000000 or 62f1dd2016aa07000000 or 62f1dd4016aa07000000 + VMOVHPD -15(R11)(CX*1), X20, X5 // 62d1dd0016ac0bf1ffffff or 62d1dd2016ac0bf1ffffff or 62d1dd4016ac0bf1ffffff + VMOVHPD (SP)(AX*2), X20, X5 // 62f1dd00162c44 or 62f1dd20162c44 or 62f1dd40162c44 + VMOVHPD (AX), X5, X8 // c5511600 or c461d11600 or 6271d5281600 or 6271d5481600 + VMOVHPD 7(DX), X5, X8 // c551164207 or 6271d528168207000000 or 6271d548168207000000 + VMOVHPD -15(R11)(CX*1), X5, X8 // c4415116440bf1 or 6251d52816840bf1ffffff or 6251d54816840bf1ffffff + VMOVHPD (SP)(AX*2), X5, X8 // c551160444 or 6271d528160444 or 6271d548160444 + VMOVHPD (AX), X8, X8 // c5391600 or 6271bd281600 or 6271bd481600 + VMOVHPD 7(DX), X8, X8 // c539164207 or 6271bd28168207000000 or 6271bd48168207000000 + VMOVHPD -15(R11)(CX*1), X8, X8 // c4413916440bf1 or 6251bd2816840bf1ffffff or 6251bd4816840bf1ffffff + VMOVHPD (SP)(AX*2), X8, X8 // c539160444 or 6271bd28160444 or 6271bd48160444 + VMOVHPD (AX), X20, X8 // 6271dd001600 or 6271dd201600 or 6271dd401600 + VMOVHPD 7(DX), X20, X8 // 6271dd00168207000000 or 6271dd20168207000000 or 6271dd40168207000000 + VMOVHPD -15(R11)(CX*1), X20, X8 // 6251dd0016840bf1ffffff or 6251dd2016840bf1ffffff or 6251dd4016840bf1ffffff + VMOVHPD (SP)(AX*2), X20, X8 // 6271dd00160444 or 6271dd20160444 or 6271dd40160444 + VMOVHPD (AX), X5, X20 // 62e1d5081620 or 62e1d5281620 or 62e1d5481620 + VMOVHPD 7(DX), X5, X20 // 62e1d50816a207000000 or 62e1d52816a207000000 or 62e1d54816a207000000 + VMOVHPD -15(R11)(CX*1), X5, X20 // 62c1d50816a40bf1ffffff or 62c1d52816a40bf1ffffff or 62c1d54816a40bf1ffffff + VMOVHPD (SP)(AX*2), X5, X20 // 62e1d508162444 or 62e1d528162444 or 62e1d548162444 + VMOVHPD (AX), X8, X20 // 62e1bd081620 or 62e1bd281620 or 62e1bd481620 + VMOVHPD 7(DX), X8, X20 // 62e1bd0816a207000000 or 62e1bd2816a207000000 or 62e1bd4816a207000000 + VMOVHPD -15(R11)(CX*1), X8, X20 // 62c1bd0816a40bf1ffffff or 62c1bd2816a40bf1ffffff or 62c1bd4816a40bf1ffffff + VMOVHPD (SP)(AX*2), X8, X20 // 62e1bd08162444 or 62e1bd28162444 or 62e1bd48162444 + VMOVHPD (AX), X20, X20 // 62e1dd001620 or 62e1dd201620 or 62e1dd401620 + VMOVHPD 7(DX), X20, X20 // 62e1dd0016a207000000 or 62e1dd2016a207000000 or 62e1dd4016a207000000 + VMOVHPD -15(R11)(CX*1), X20, X20 // 62c1dd0016a40bf1ffffff or 62c1dd2016a40bf1ffffff or 62c1dd4016a40bf1ffffff + VMOVHPD (SP)(AX*2), X20, X20 // 62e1dd00162444 or 62e1dd20162444 or 62e1dd40162444 + VMOVHPD X5, (AX) // c5f91728 or 62f1fd281728 or 62f1fd481728 + VMOVHPD X8, (AX) // c5791700 or 6271fd281700 or 6271fd481700 + VMOVHPD X20, (AX) // 62e1fd081720 or 62e1fd281720 or 62e1fd481720 + VMOVHPD X5, 7(DX) // c5f9176a07 or 62f1fd2817aa07000000 or 62f1fd4817aa07000000 + VMOVHPD X8, 7(DX) // c579174207 or 6271fd28178207000000 or 6271fd48178207000000 + VMOVHPD X20, 7(DX) // 62e1fd0817a207000000 or 62e1fd2817a207000000 or 62e1fd4817a207000000 + VMOVHPD X5, -15(R11)(CX*1) // c4c179176c0bf1 or 62d1fd2817ac0bf1ffffff or 62d1fd4817ac0bf1ffffff + VMOVHPD X8, -15(R11)(CX*1) // c4417917440bf1 or 6251fd2817840bf1ffffff or 6251fd4817840bf1ffffff + VMOVHPD X20, -15(R11)(CX*1) // 62c1fd0817a40bf1ffffff or 62c1fd2817a40bf1ffffff or 62c1fd4817a40bf1ffffff + VMOVHPD X5, (SP)(AX*2) // c5f9172c44 or 62f1fd28172c44 or 62f1fd48172c44 + VMOVHPD X8, (SP)(AX*2) // c579170444 or 6271fd28170444 or 6271fd48170444 + VMOVHPD X20, (SP)(AX*2) // 62e1fd08172444 or 62e1fd28172444 or 62e1fd48172444 + // VMOVLPD: overlapping VEX and EVEX variants. + VMOVLPD (AX), X5, X5 // c5d11228 or 62f1d5281228 or 62f1d5481228 + VMOVLPD 7(DX), X5, X5 // c5d1126a07 or 62f1d52812aa07000000 or 62f1d54812aa07000000 + VMOVLPD -15(R11)(CX*1), X5, X5 // c4c151126c0bf1 or 62d1d52812ac0bf1ffffff or 62d1d54812ac0bf1ffffff + VMOVLPD (SP)(AX*2), X5, X5 // c5d1122c44 or 62f1d528122c44 or 62f1d548122c44 + VMOVLPD (AX), X8, X5 // c5b91228 or 62f1bd281228 or 62f1bd481228 + VMOVLPD 7(DX), X8, X5 // c5b9126a07 or 62f1bd2812aa07000000 or 62f1bd4812aa07000000 + VMOVLPD -15(R11)(CX*1), X8, X5 // c4c139126c0bf1 or 62d1bd2812ac0bf1ffffff or 62d1bd4812ac0bf1ffffff + VMOVLPD (SP)(AX*2), X8, X5 // c5b9122c44 or 62f1bd28122c44 or 62f1bd48122c44 + VMOVLPD (AX), X20, X5 // 62f1dd001228 or 62f1dd201228 or 62f1dd401228 + VMOVLPD 7(DX), X20, X5 // 62f1dd0012aa07000000 or 62f1dd2012aa07000000 or 62f1dd4012aa07000000 + VMOVLPD -15(R11)(CX*1), X20, X5 // 62d1dd0012ac0bf1ffffff or 62d1dd2012ac0bf1ffffff or 62d1dd4012ac0bf1ffffff + VMOVLPD (SP)(AX*2), X20, X5 // 62f1dd00122c44 or 62f1dd20122c44 or 62f1dd40122c44 + VMOVLPD (AX), X5, X8 // c5511200 or 6271d5281200 or 6271d5481200 + VMOVLPD 7(DX), X5, X8 // c551124207 or 6271d528128207000000 or 6271d548128207000000 + VMOVLPD -15(R11)(CX*1), X5, X8 // c4415112440bf1 or 6251d52812840bf1ffffff or 6251d54812840bf1ffffff + VMOVLPD (SP)(AX*2), X5, X8 // c551120444 or 6271d528120444 or 6271d548120444 + VMOVLPD (AX), X8, X8 // c5391200 or 6271bd281200 or 6271bd481200 + VMOVLPD 7(DX), X8, X8 // c539124207 or 6271bd28128207000000 or 6271bd48128207000000 + VMOVLPD -15(R11)(CX*1), X8, X8 // c4413912440bf1 or 6251bd2812840bf1ffffff or 6251bd4812840bf1ffffff + VMOVLPD (SP)(AX*2), X8, X8 // c539120444 or 6271bd28120444 or 6271bd48120444 + VMOVLPD (AX), X20, X8 // 6271dd001200 or 6271dd201200 or 6271dd401200 + VMOVLPD 7(DX), X20, X8 // 6271dd00128207000000 or 6271dd20128207000000 or 6271dd40128207000000 + VMOVLPD -15(R11)(CX*1), X20, X8 // 6251dd0012840bf1ffffff or 6251dd2012840bf1ffffff or 6251dd4012840bf1ffffff + VMOVLPD (SP)(AX*2), X20, X8 // 6271dd00120444 or 6271dd20120444 or 6271dd40120444 + VMOVLPD (AX), X5, X20 // 62e1d5081220 or 62e1d5281220 or 62e1d5481220 + VMOVLPD 7(DX), X5, X20 // 62e1d50812a207000000 or 62e1d52812a207000000 or 62e1d54812a207000000 + VMOVLPD -15(R11)(CX*1), X5, X20 // 62c1d50812a40bf1ffffff or 62c1d52812a40bf1ffffff or 62c1d54812a40bf1ffffff + VMOVLPD (SP)(AX*2), X5, X20 // 62e1d508122444 or 62e1d528122444 or 62e1d548122444 + VMOVLPD (AX), X8, X20 // 62e1bd081220 or 62e1bd281220 or 62e1bd481220 + VMOVLPD 7(DX), X8, X20 // 62e1bd0812a207000000 or 62e1bd2812a207000000 or 62e1bd4812a207000000 + VMOVLPD -15(R11)(CX*1), X8, X20 // 62c1bd0812a40bf1ffffff or 62c1bd2812a40bf1ffffff or 62c1bd4812a40bf1ffffff + VMOVLPD (SP)(AX*2), X8, X20 // 62e1bd08122444 or 62e1bd28122444 or 62e1bd48122444 + VMOVLPD (AX), X20, X20 // 62e1dd001220 or 62e1dd201220 or 62e1dd401220 + VMOVLPD 7(DX), X20, X20 // 62e1dd0012a207000000 or 62e1dd2012a207000000 or 62e1dd4012a207000000 + VMOVLPD -15(R11)(CX*1), X20, X20 // 62c1dd0012a40bf1ffffff or 62c1dd2012a40bf1ffffff or 62c1dd4012a40bf1ffffff + VMOVLPD (SP)(AX*2), X20, X20 // 62e1dd00122444 or 62e1dd20122444 or 62e1dd40122444 + VMOVLPD X5, (AX) // c5f91328 or 62f1fd281328 or 62f1fd481328 + VMOVLPD X8, (AX) // c5791300 or 6271fd281300 or 6271fd481300 + VMOVLPD X20, (AX) // 62e1fd081320 or 62e1fd281320 or 62e1fd481320 + VMOVLPD X5, 7(DX) // c5f9136a07 or 62f1fd2813aa07000000 or 62f1fd4813aa07000000 + VMOVLPD X8, 7(DX) // c579134207 or 6271fd28138207000000 or 6271fd48138207000000 + VMOVLPD X20, 7(DX) // 62e1fd0813a207000000 or 62e1fd2813a207000000 or 62e1fd4813a207000000 + VMOVLPD X5, -15(R11)(CX*1) // c4c179136c0bf1 or 62d1fd2813ac0bf1ffffff or 62d1fd4813ac0bf1ffffff + VMOVLPD X8, -15(R11)(CX*1) // c4417913440bf1 or 6251fd2813840bf1ffffff or 6251fd4813840bf1ffffff + VMOVLPD X20, -15(R11)(CX*1) // 62c1fd0813a40bf1ffffff or 62c1fd2813a40bf1ffffff or 62c1fd4813a40bf1ffffff + VMOVLPD X5, (SP)(AX*2) // c5f9132c44 or 62f1fd28132c44 or 62f1fd48132c44 + VMOVLPD X8, (SP)(AX*2) // c579130444 or 6271fd28130444 or 6271fd48130444 + VMOVLPD X20, (SP)(AX*2) // 62e1fd08132444 or 62e1fd28132444 or 62e1fd48132444 + // "VPEXTRW imm8u, xmm1, r32/m16"/15 vs "VPEXTRW imm8u, xmm2, r32"/C5. + VPEXTRW $17, X20, AX // 62b17d08c5c411 or 62e37d0815e011 or 62e3fd0815e011 + VPEXTRW $127, X20, AX // 62b17d08c5c47f or 62e37d0815e07f or 62e3fd0815e07f + VPEXTRW $17, X20, SP // 62b17d08c5e411 or 62e37d0815e411 or 62e3fd0815e411 + VPEXTRW $127, X20, SP // 62b17d08c5e47f or 62e37d0815e47f or 62e3fd0815e47f + VPEXTRW $17, X20, BP // 62b17d08c5ec11 or 62e37d0815e511 or 62e3fd0815e511 + VPEXTRW $127, X20, BP // 62b17d08c5ec7f or 62e37d0815e57f or 62e3fd0815e57f + VPEXTRW $17, X20, R14 // 62317d08c5f411 or 62c37d0815e611 or 62c3fd0815e611 + VPEXTRW $127, X20, R14 // 62317d08c5f47f or 62c37d0815e67f or 62c3fd0815e67f + VPEXTRW $17, X20, (AX) // 62e37d08152011 or 62e3fd08152011 + VPEXTRW $127, X20, (AX) // 62e37d0815207f or 62e3fd0815207f + VPEXTRW $17, X20, 7(DX) // 62e37d0815a20700000011 or 62e3fd0815a20700000011 + VPEXTRW $127, X20, 7(DX) // 62e37d0815a2070000007f or 62e3fd0815a2070000007f + VPEXTRW $17, X20, -15(R11)(CX*1) // 62c37d0815a40bf1ffffff11 or 62c3fd0815a40bf1ffffff11 + VPEXTRW $127, X20, -15(R11)(CX*1) // 62c37d0815a40bf1ffffff7f or 62c3fd0815a40bf1ffffff7f + VPEXTRW $17, X20, (SP)(AX*2) // 62e37d0815244411 or 62e3fd0815244411 + VPEXTRW $127, X20, (SP)(AX*2) // 62e37d081524447f or 62e3fd081524447f + // EVEX: embedded zeroing. + VADDPD.Z X30, X1, X0 // 6291f58858c6 + VMAXPD.Z (AX), Z2, K1, Z1 // 62f1edc95f08 + // EVEX: embedded rounding. + VADDPD.RU_SAE Z3, Z2, K1, Z1 // 62f1ed5958cb + VADDPD.RD_SAE Z3, Z2, K1, Z1 // 62f1ed3958cb + VADDPD.RZ_SAE Z3, Z2, K1, Z1 // 62f1ed7958cb + VADDPD.RN_SAE Z3, Z2, K1, Z1 // 62f1ed1958cb + VADDPD.RU_SAE.Z Z3, Z2, K1, Z1 // 62f1edd958cb + VADDPD.RD_SAE.Z Z3, Z2, K1, Z1 // 62f1edb958cb + VADDPD.RZ_SAE.Z Z3, Z2, K1, Z1 // 62f1edf958cb + VADDPD.RN_SAE.Z Z3, Z2, K1, Z1 // 62f1ed9958cb + // EVEX: embedded broadcasting. + VADDPD.BCST (AX), X2, K1, X1 // 62f1ed195808 + VADDPD.BCST.Z (AX), X2, K1, X1 // 62f1ed995808 + VADDPD.BCST (AX), Y2, K1, Y1 // 62f1ed395808 + VADDPD.BCST.Z (AX), Y2, K1, Y1 // 62f1edb95808 + VADDPD.BCST (AX), Z2, K1, Z1 // 62f1ed595808 + VADDPD.BCST.Z (AX), Z2, K1, Z1 // 62f1edd95808 + VMAXPD.BCST (AX), Z2, K1, Z1 // 62f1ed595f08 + VMAXPD.BCST.Z (AX), Z2, K1, Z1 // 62f1edd95f08 + // EVEX: surpress all exceptions (SAE). + VMAXPD.SAE Z3, Z2, K1, Z1 // 62f1ed595fcb or 62f1ed195fcb + VMAXPD.SAE.Z Z3, Z2, K1, Z1 // 62f1edd95fcb or 62f1ed995fcb + VMAXPD (AX), Z2, K1, Z1 // 62f1ed495f08 + VCMPSD.SAE $0, X0, X2, K0 // 62f1ef18c2c000 + VCMPSD.SAE $0, X0, X2, K1, K0 // 62f1ef19c2c000 + // EVEX: broadcast-affected compressed displacement (Disp8). + VADDPD.BCST 1016(DX), X0, X29 // 6261fd18586a7f + VADDPD.BCST 1016(DX), X29, X1 // 62f19510584a7f + VADDPD.BCST 1016(DX), X28, X29 // 62619d10586a7f + VADDPD.BCST 1016(DX)(AX*2), X0, X29 // 6261fd18586c427f + VADDPD.BCST 1016(DX)(AX*2), X29, X1 // 62f19510584c427f + VADDPD.BCST 1016(DX), Y0, Y29 // 6261fd38586a7f + VADDPD.BCST 1016(DX), Y29, Y1 // 62f19530584a7f + VADDPD.BCST 1016(DX), Y28, Y29 // 62619d30586a7f + VADDPD.BCST 1016(DX)(AX*2), Y0, Y29 // 6261fd38586c427f + VADDPD.BCST 1016(DX)(AX*2), Y29, Y1 // 62f19530584c427f + VADDPD.BCST 1016(DX), Z0, Z29 // 6261fd58586a7f + VADDPD.BCST 1016(DX), Z29, Z1 // 62f19550584a7f + VADDPD.BCST 1016(DX), Z28, Z29 // 62619d50586a7f + VADDPD.BCST 1016(DX)(AX*2), Z0, Z29 // 6261fd58586c427f + VADDPD.BCST 1016(DX)(AX*2), Z29, Z1 // 62f19550584c427f + VADDPS.BCST 508(DX), Z0, Z29 // 62617c58586a7f + VADDPS.BCST 508(DX), Z1, Z29 // 62617458586a7f + VADDPS.BCST 508(DX), Z28, Z29 // 62611c50586a7f + VADDPS.BCST 508(DX)(AX*2), Z0, Z29 // 62617c58586c427f + VADDPS.BCST 508(DX)(AX*2), Z1, Z29 // 62617458586c427f + // EVEX: broadcast-affected compressed displacement that does not fit into 8bits. + VADDPD.BCST 2032(DX), X0, X29 // 6261fd1858aaf0070000 + VADDPD.BCST 2032(DX), X29, X1 // 62f19510588af0070000 + VADDPD.BCST 2032(DX), X28, X29 // 62619d1058aaf0070000 + VADDPD.BCST 2032(DX)(AX*2), X0, X29 // 6261fd1858ac42f0070000 + VADDPD.BCST 2032(DX)(AX*2), X29, X1 // 62f19510588c42f0070000 + VADDPD.BCST 2032(DX), Y0, Y29 // 6261fd3858aaf0070000 + VADDPD.BCST 2032(DX), Y29, Y1 // 62f19530588af0070000 + VADDPD.BCST 2032(DX), Y28, Y29 // 62619d3058aaf0070000 + VADDPD.BCST 2032(DX)(AX*2), Y0, Y29 // 6261fd3858ac42f0070000 + VADDPD.BCST 2032(DX)(AX*2), Y29, Y1 // 62f19530588c42f0070000 + VADDPD.BCST 2032(DX), Z0, Z29 // 6261fd5858aaf0070000 + VADDPD.BCST 2032(DX), Z29, Z1 // 62f19550588af0070000 + VADDPD.BCST 2032(DX), Z28, Z29 // 62619d5058aaf0070000 + VADDPD.BCST 2032(DX)(AX*2), Z0, Z29 // 6261fd5858ac42f0070000 + VADDPD.BCST 2032(DX)(AX*2), Z29, Z1 // 62f19550588c42f0070000 + VADDPS.BCST 2032(DX), Z0, Z29 // 62617c5858aaf0070000 + VADDPS.BCST 2032(DX), Z1, Z29 // 6261745858aaf0070000 + VADDPS.BCST 2032(DX), Z28, Z29 // 62611c5058aaf0070000 + VADDPS.BCST 2032(DX)(AX*2), Z0, Z29 // 62617c5858ac42f0070000 + VADDPS.BCST 2032(DX)(AX*2), Z1, Z29 // 6261745858ac42f0070000 + // Forced EVEX encoding due to suffixes. + VADDPD.BCST 2032(DX), X0, X0 // 62f1fd185882f0070000 + VADDPD.BCST 2032(DX), Y0, Y0 // 62f1fd385882f0070000 + // Test new Z-cases one-by-one. + // + // Zevex_i_r_k_rm. + VCVTPS2PH $1, Z2, K5, Y21 // 62b37d4d1dd501 + VCVTPS2PH $2, Z21, K4, Y2 // 62e37d4c1dea02 + // Zevex_i_r_rm. + VCVTPS2PH $1, Z2, Y21 // 62b37d481dd501 + VCVTPS2PH $2, Z21, Y2 // 62e37d481dea02 + // Zevex_i_rm_k_r. + VFPCLASSPDX $1, X2, K5, K3 // 62f3fd0d66da01 + VFPCLASSPDX $2, X21, K4, K1 // 62b3fd0c66cd02 + VFPCLASSPDX $1, (AX), K5, K3 // 62f3fd0d661801 + VFPCLASSPDX $2, (CX), K4, K1 // 62f3fd0c660902 + // Zevex_i_rm_k_vo. + VPROLD $1, X2, K5, X21 // 62f1550572ca01 + VPROLD $2, Y21, K5, Y2 // 62b16d2d72cd02 + VPROLD $1, (AX), K5, X21 // 62f15505720801 + VPROLD $2, (CX), K5, Y2 // 62f16d2d720902 + // Zevex_i_rm_r. + VFPCLASSPDX $1, X2, K3 // 62f3fd0866da01 + VFPCLASSPDX $2, X21, K1 // 62b3fd0866cd02 + VFPCLASSPDX $1, (AX), K3 // 62f3fd08661801 + VFPCLASSPDX $2, (CX), K1 // 62f3fd08660902 + // Zevex_i_rm_v_k_r. + VALIGND $1, X2, X9, K5, X21 // 62e3350d03ea01 + VALIGND $2, Y21, Y2, K5, Y9 // 62336d2d03cd02 + VALIGND $3, Z9, Z21, K5, Z2 // 62d3554503d103 + VALIGND $1, (AX), X9, K5, X21 // 62e3350d032801 + VALIGND $2, (CX), Y2, K5, Y9 // 62736d2d030902 + VALIGND $3, (AX), Z21, K5, Z2 // 62f35545031003 + // Zevex_i_rm_v_r. + VALIGND $1, X2, X9, X21 // 62e3350803ea01 + VALIGND $2, Y21, Y2, Y9 // 62336d2803cd02 + VALIGND $3, Z9, Z21, Z2 // 62d3554003d103 + VALIGND $1, (AX), X9, X21 // 62e33508032801 + VALIGND $2, (CX), Y2, Y9 // 62736d28030902 + VALIGND $3, (AX), Z21, Z2 // 62f35540031003 + // Zevex_i_rm_vo. + VPROLD $1, X2, X21 // 62f1550072ca01 + VPROLD $2, Y21, Y2 // 62b16d2872cd02 + VPROLD $1, (AX), X21 // 62f15500720801 + VPROLD $2, (CX), Y2 // 62f16d28720902 + // Zevex_k_rmo. + VGATHERPF0DPD K5, (AX)(Y2*2) // 62f2fd4dc60c50 + VGATHERPF0DPD K3, (CX)(Y21*2) // 62f2fd43c60c69 + VSCATTERPF1DPD K5, (AX)(Y2*2) // 62f2fd4dc63450 + VSCATTERPF1DPD K3, (CX)(Y21*2) // 62f2fd43c63469 + // Zevex_r_k_rm. + VPSCATTERDD X2, K5, (AX)(X21*2) // 62f27d05a01468 + VPSCATTERDD X21, K5, (AX)(X2*2) // 62e27d0da02c50 + VPSCATTERDD Y2, K5, (AX)(Y21*2) // 62f27d25a01468 + VPSCATTERDD Y21, K5, (AX)(Y2*2) // 62e27d2da02c50 + VPSCATTERDD Z2, K5, (AX)(Z21*2) // 62f27d45a01468 + VPSCATTERDD Z21, K5, (AX)(Z2*2) // 62e27d4da02c50 + // Zevex_r_v_k_rm. + VMOVSD X2, X9, K5, X21 // 62b1b70d11d5 or 62e1b70d10ea + VMOVSD X21, X2, K5, X9 // 62c1ef0d11e9 or 6231ef0d10cd + VMOVSD X9, X21, K5, X2 // 6271d70511ca or 62d1d70510d1 + // Zevex_r_v_rm. + VMOVSD X2, X9, X21 // 62b1b70811d5 or 62e1b70810ea + VMOVSD X21, X2, X9 // 62c1ef0811e9 or 6231ef0810cd + VMOVSD X9, X21, X2 // 6271d70011ca or 62d1d70010d1 + VPMOVDB X2, X21 // 62b27e0831d5 + VPMOVDB X21, X2 // 62e27e0831ea + VPMOVDB X2, (AX) // 62f27e083110 + VPMOVDB X21, (AX) // 62e27e083128 + // Zevex_rm_k_r. + VMOVDDUP X2, K5, X21 // 62e1ff0d12ea + VMOVDDUP X21, K5, X2 // 62b1ff0d12d5 + VMOVDDUP (AX), K5, X21 // 62e1ff0d1228 + VMOVDDUP (CX), K5, X2 // 62f1ff0d1211 + VMOVDDUP Y2, K5, Y21 // 62e1ff2d12ea + VMOVDDUP Y21, K5, Y2 // 62b1ff2d12d5 + VMOVDDUP (AX), K5, Y21 // 62e1ff2d1228 + VMOVDDUP (CX), K5, Y2 // 62f1ff2d1211 + VMOVDDUP Z2, K5, Z21 // 62e1ff4d12ea + VMOVDDUP Z21, K5, Z2 // 62b1ff4d12d5 + VMOVDDUP (AX), K5, Z21 // 62e1ff4d1228 + VMOVDDUP (CX), K5, Z2 // 62f1ff4d1211 + // Zevex_rm_v_k_r. + VADDPD Z2, Z9, K5, Z21 // 62e1b54d58ea + VADDPD Z21, Z2, K5, Z9 // 6231ed4d58cd + VADDPD Z9, Z21, K5, Z2 // 62d1d54558d1 + // Zevex_rm_v_r. + VADDPD Z2, Z9, Z21 // 62e1b54858ea + VADDPD Z21, Z2, Z9 // 6231ed4858cd + VADDPD Z9, Z21, Z2 // 62d1d54058d1 // End of tests. RET diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index ce6282f0dd..54be761c54 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -190,6 +190,15 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2 EOR $(1<<63-1), R1 // EOR $9223372036854775807, R1 // 21f840d2 + AND $0x22220000, R3, R4 // AND $572653568, R3, R4 // 5b44a4d264001b8a + ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa + EOR $0x22220000, R3, R4 // EOR $572653568, R3, R4 // 5b44a4d264001bca + BIC $0x22220000, R3, R4 // BIC $572653568, R3, R4 // 5b44a4d264003b8a + ORN $0x22220000, R3, R4 // ORN $572653568, R3, R4 // 5b44a4d264003baa + EON $0x22220000, R3, R4 // EON $572653568, R3, R4 // 5b44a4d264003bca + ANDS $0x22220000, R3, R4 // ANDS $572653568, R3, R4 // 5b44a4d264001bea + BICS $0x22220000, R3, R4 // BICS $572653568, R3, R4 // 5b44a4d264003bea + AND $8, R0, RSP // 1f007d92 ORR $8, R0, RSP // 1f007db2 EOR $8, R0, RSP // 1f007dd2 @@ -390,6 +399,18 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 CMP R1>>22, R2 CMP R1<<33, R2 CMP R22.SXTX, RSP // ffe336eb + + CMP $0x22220000, RSP // CMP $572653568, RSP // 5b44a4d2ff633beb + CMPW $0x22220000, RSP // CMPW $572653568, RSP // 5b44a4d2ff633b6b + +// TST + TST $15, R2 // 5f0c40f2 + TST R1, R2 // 5f0001ea + TST R1->11, R2 // 5f2c81ea + TST R1>>22, R2 // 5f5841ea + TST R1<<33, R2 // 5f8401ea + TST $0x22220000, R3 // TST $572653568, R3 // 5b44a4d27f001bea + // // CBZ // diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index 36829686f6..be2251e442 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -87,4 +87,6 @@ TEXT errors(SB),$0 MADD R1, R2, R3 // ERROR "illegal combination" CINC CS, R2, R3, R4 // ERROR "illegal combination" CSEL LT, R1, R2 // ERROR "illegal combination" + AND $0x22220000, R2, RSP // ERROR "illegal combination" + ANDS $0x22220000, R2, RSP // ERROR "illegal combination" RET diff --git a/src/cmd/cgo/godefs.go b/src/cmd/cgo/godefs.go index 6d638f0644..6720945cdd 100644 --- a/src/cmd/cgo/godefs.go +++ b/src/cmd/cgo/godefs.go @@ -19,7 +19,7 @@ import ( func (p *Package) godefs(f *File, srcfile string) string { var buf bytes.Buffer - fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n") + fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n") fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " ")) fmt.Fprintf(&buf, "\n") diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 399e96d01e..e9b7986565 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -73,7 +73,7 @@ func (p *Package) writeDefs() { // Write second Go output: definitions of _C_xxx. // In a separate file so that the import of "unsafe" does not // pollute the original file. - fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n") + fmt.Fprintf(fgo2, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n") fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName) fmt.Fprintf(fgo2, "import \"unsafe\"\n\n") if !*gccgo && *importRuntimeCgo { @@ -536,7 +536,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { p.GccFiles = append(p.GccFiles, base+".cgo2.c") // Write Go output: Go input with rewrites of C.xxx to _C_xxx. - fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n") + fmt.Fprintf(fgo1, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n") fmt.Fprintf(fgo1, "//line %s:1\n", srcfile) fgo1.Write(f.Edit.Bytes()) @@ -725,7 +725,7 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { // packedAttribute returns host compiler struct attribute that will be // used to match gc's struct layout. For example, on 386 Windows, // gcc wants to 8-align int64s, but gc does not. -// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, +// Use __gcc_struct__ to work around https://gcc.gnu.org/PR52991 on x86, // and https://golang.org/issue/5603. func (p *Package) packedAttribute() string { s := "__attribute__((__packed__" @@ -740,7 +740,7 @@ func (p *Package) packedAttribute() string { func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { p.writeExportHeader(fgcch) - fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") + fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n") fmt.Fprintf(fgcc, "#include \n") fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n") @@ -981,7 +981,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { p.writeExportHeader(fgcch) - fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") + fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n") fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n") fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog) @@ -1147,7 +1147,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { // writeExportHeader writes out the start of the _cgo_export.h file. func (p *Package) writeExportHeader(fgcch io.Writer) { - fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n") + fmt.Fprintf(fgcch, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n") pkg := *importPath if pkg == "" { pkg = p.PackagePath diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go index 9d47b04b1c..531298a216 100644 --- a/src/cmd/compile/fmt_test.go +++ b/src/cmd/compile/fmt_test.go @@ -702,32 +702,32 @@ var knownFormats = map[string]string{ "interface{} %v": "", "map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "", "map[cmd/compile/internal/ssa.ID]uint32 %v": "", - "reflect.Type %s": "", - "rune %#U": "", - "rune %c": "", - "string %-*s": "", - "string %-16s": "", - "string %-6s": "", - "string %.*s": "", - "string %q": "", - "string %s": "", - "string %v": "", - "time.Duration %d": "", - "time.Duration %v": "", - "uint %04x": "", - "uint %5d": "", - "uint %d": "", - "uint %x": "", - "uint16 %d": "", - "uint16 %v": "", - "uint16 %x": "", - "uint32 %d": "", - "uint32 %v": "", - "uint32 %x": "", - "uint64 %08x": "", - "uint64 %d": "", - "uint64 %x": "", - "uint8 %d": "", - "uint8 %x": "", - "uintptr %d": "", + "reflect.Type %s": "", + "rune %#U": "", + "rune %c": "", + "string %-*s": "", + "string %-16s": "", + "string %-6s": "", + "string %.*s": "", + "string %q": "", + "string %s": "", + "string %v": "", + "time.Duration %d": "", + "time.Duration %v": "", + "uint %04x": "", + "uint %5d": "", + "uint %d": "", + "uint %x": "", + "uint16 %d": "", + "uint16 %v": "", + "uint16 %x": "", + "uint32 %d": "", + "uint32 %v": "", + "uint32 %x": "", + "uint64 %08x": "", + "uint64 %d": "", + "uint64 %x": "", + "uint8 %d": "", + "uint8 %x": "", + "uintptr %d": "", } diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index d88c5e5c5e..736ea0a018 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -778,15 +778,26 @@ func functypefield0(t *types.Type, this *types.Field, in, out []*types.Field) { // origSym returns the original symbol written by the user. func origSym(s *types.Sym) *types.Sym { - if s != nil && s.Name[0] == '~' { + if s == nil { + return nil + } + + if len(s.Name) > 1 && s.Name[0] == '~' { switch s.Name[1] { case 'r': // originally an unnamed result - s = nil + return nil case 'b': // originally the blank identifier _ // TODO(mdempsky): Does s.Pkg matter here? - s = nblank.Sym + return nblank.Sym } + return s } + + if strings.HasPrefix(s.Name, ".anon") { + // originally an unnamed or _ name (see subr.go: structargs) + return nil + } + return s } diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 4e92f5421b..75194ca6f0 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -1268,7 +1268,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) { case OTARRAY: if n.Left != nil { - mode.Fprintf(s, "[]%v", n.Left) + mode.Fprintf(s, "[%v]%v", n.Left, n.Right) return } mode.Fprintf(s, "[]%v", n.Right) // happens before typecheck @@ -1599,7 +1599,7 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) { case OTYPE: mode.Fprintf(s, "%v %v%j type=%v", n.Op, n.Sym, n, n.Type) - 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(s) mode.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype) } diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 46fe87e8c3..25452911eb 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -352,7 +352,7 @@ func (v *hairyVisitor) visit(n *Node) bool { v.budget -= v.extraCallCost case OPANIC: - v.budget -= v.extraCallCost + v.budget -= inlineExtraPanicCost case ORECOVER: // recover matches the argument frame pointer to find diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 74590ccc39..e8b33008b4 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -532,6 +532,10 @@ func Main(archInit func(*Arch)) { checkMapKeys() timings.AddEvent(fcount, "funcs") + if nsavederrors+nerrors != 0 { + errorexit() + } + // Phase 4: Decide how to capture closed variables. // This needs to run before escape analysis, // because variables captured by value do not escape. @@ -659,14 +663,6 @@ func Main(archInit func(*Arch)) { Ctxt.DwFixups = nil genDwarfInline = 0 } - - // Check whether any of the functions we have compiled have gigantic stack frames. - obj.SortSlice(largeStackFrames, func(i, j int) bool { - return largeStackFrames[i].Before(largeStackFrames[j]) - }) - for _, largePos := range largeStackFrames { - yyerrorl(largePos, "stack frame too large (>1GB)") - } } // Phase 9: Check external declarations. @@ -688,6 +684,14 @@ func Main(archInit func(*Arch)) { dumpasmhdr() } + // Check whether any of the functions we have compiled have gigantic stack frames. + obj.SortSlice(largeStackFrames, func(i, j int) bool { + return largeStackFrames[i].Before(largeStackFrames[j]) + }) + for _, largePos := range largeStackFrames { + yyerrorl(largePos, "stack frame too large (>1GB)") + } + if len(compilequeue) != 0 { Fatalf("%d uncompiled functions", len(compilequeue)) } diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index 9747a0299e..cf1164772b 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -257,18 +257,32 @@ const maxStackSize = 1 << 30 // worker indicates which of the backend workers is doing the processing. func compileSSA(fn *Node, worker int) { f := buildssa(fn, worker) - if f.Frontend().(*ssafn).stksize >= maxStackSize { + // Note: check arg size to fix issue 25507. + if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize { largeStackFramesMu.Lock() largeStackFrames = append(largeStackFrames, fn.Pos) largeStackFramesMu.Unlock() return } pp := newProgs(fn, worker) + defer pp.Free() genssa(f, pp) + // Check frame size again. + // The check above included only the space needed for local variables. + // After genssa, the space needed includes local variables and the callee arg region. + // We must do this check prior to calling pp.Flush. + // If there are any oversized stack frames, + // the assembler may emit inscrutable complaints about invalid instructions. + if pp.Text.To.Offset >= maxStackSize { + largeStackFramesMu.Lock() + largeStackFrames = append(largeStackFrames, fn.Pos) + largeStackFramesMu.Unlock() + return + } + pp.Flush() // assemble, fill in boilerplate, etc. // fieldtrack must be called after pp.Flush. See issue 20014. fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack) - pp.Free() } func init() { diff --git a/src/cmd/compile/internal/gc/phi.go b/src/cmd/compile/internal/gc/phi.go index bd66568eed..5218cd0ef3 100644 --- a/src/cmd/compile/internal/gc/phi.go +++ b/src/cmd/compile/internal/gc/phi.go @@ -14,7 +14,7 @@ import ( // This file contains the algorithm to place phi nodes in a function. // For small functions, we use Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau. -// http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf +// https://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf // For large functions, we use Sreedhar & Gao: A Linear Time Algorithm for Placing Φ-Nodes. // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.8.1979&rep=rep1&type=pdf diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index f3f1ca3d39..88b4380637 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -461,17 +461,6 @@ func (lv *Liveness) regEffects(v *ssa.Value) (uevar, kill liveRegMask) { for _, reg := range regs[:nreg] { if reg.GCNum() == -1 { if ptrOnly { - if reg.String() == "g" { - // Issue #25504: Sometimes we - // spill and reload the g - // register, which this sees - // as a pointer load into the - // g register. The g register - // isn't a GP register and - // can't appear in register - // maps. Ignore it. - continue - } v.Fatalf("pointer in non-pointer register %v", reg) } else { continue diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index f42d1e43db..591c8f3bfe 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -4078,7 +4078,7 @@ func canMergeLoads() bool { } // isRuneCount reports whether n is of the form len([]rune(string)). -// These are optimized into a call to runtime.runecount. +// These are optimized into a call to runtime.countrunes. func isRuneCount(n *Node) bool { return Debug['N'] == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTRARRAYRUNE } diff --git a/src/cmd/compile/internal/ssa/branchelim.go b/src/cmd/compile/internal/ssa/branchelim.go index 1967fb93fe..d9dcaf8444 100644 --- a/src/cmd/compile/internal/ssa/branchelim.go +++ b/src/cmd/compile/internal/ssa/branchelim.go @@ -4,7 +4,7 @@ package ssa -// branchelim tries to elminiate branches by +// branchelim tries to eliminate branches by // generating CondSelect instructions. // // Search for basic blocks that look like diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 322ea82c8d..13b7d7e1e8 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -252,6 +252,19 @@ func deadcode(f *Func) { b.Values = b.Values[:i] } + // Remove dead blocks from WBLoads list. + i = 0 + for _, b := range f.WBLoads { + if reachable[b.ID] { + f.WBLoads[i] = b + i++ + } + } + for j := i; j < len(f.WBLoads); j++ { + f.WBLoads[j] = nil + } + f.WBLoads = f.WBLoads[:i] + // Remove unreachable blocks. Return dead blocks to allocator. i = 0 for _, b := range f.Blocks { diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index be9f19b51c..5832050a8a 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -28,6 +28,7 @@ var testCtxts = map[string]*obj.Link{ func testConfig(tb testing.TB) *Conf { return testConfigArch(tb, "amd64") } func testConfigS390X(tb testing.TB) *Conf { return testConfigArch(tb, "s390x") } +func testConfigARM64(tb testing.TB) *Conf { return testConfigArch(tb, "arm64") } func testConfigArch(tb testing.TB, arch string) *Conf { ctxt, ok := testCtxts[arch] diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 2f0364fb00..28694e435e 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -349,10 +349,10 @@ func init() { // result is undefined if the input is zero. // flags are set to "equal" if the input is zero, "not equal" otherwise. // BS{F,R}L returns only the result. - {name: "BSFQ", argLength: 1, reg: gp11flags, asm: "BSFQ", typ: "(UInt64,Flags)"}, // # of low-order zeroes in 64-bit arg - {name: "BSFL", argLength: 1, reg: gp11, asm: "BSFL", typ: "UInt32"}, // # of low-order zeroes in 32-bit arg - {name: "BSRQ", argLength: 1, reg: gp11flags, asm: "BSRQ", typ: "(UInt64,Flags)"}, // # of high-order zeroes in 64-bit arg - {name: "BSRL", argLength: 1, reg: gp11, asm: "BSRL", typ: "UInt32"}, // # of high-order zeroes in 32-bit arg + {name: "BSFQ", argLength: 1, reg: gp11flags, asm: "BSFQ", typ: "(UInt64,Flags)"}, // # of low-order zeroes in 64-bit arg + {name: "BSFL", argLength: 1, reg: gp11, asm: "BSFL", typ: "UInt32", clobberFlags: true}, // # of low-order zeroes in 32-bit arg + {name: "BSRQ", argLength: 1, reg: gp11flags, asm: "BSRQ", typ: "(UInt64,Flags)"}, // # of high-order zeroes in 64-bit arg + {name: "BSRL", argLength: 1, reg: gp11, asm: "BSRL", typ: "UInt32", clobberFlags: true}, // # of high-order zeroes in 32-bit arg // CMOV instructions: 64, 32 and 16-bit sizes. // if arg2 encodes a true result, return arg1, else arg0 diff --git a/src/cmd/compile/internal/ssa/gen/Wasm.rules b/src/cmd/compile/internal/ssa/gen/Wasm.rules index 01f3f5a670..18c208cccb 100644 --- a/src/cmd/compile/internal/ssa/gen/Wasm.rules +++ b/src/cmd/compile/internal/ssa/gen/Wasm.rules @@ -46,8 +46,7 @@ (Not x) -> (I64Eqz x) // Lowering pointer arithmetic -(OffPtr [0] ptr) -> ptr -(OffPtr [off] ptr) && off > 0 -> (I64AddConst [off] ptr) +(OffPtr [off] ptr) -> (I64AddConst [off] ptr) // Lowering extension // It is unnecessary to extend loads @@ -388,6 +387,7 @@ (I64Ne x (I64Const [0])) -> (I64Eqz (I64Eqz x)) (I64Add x (I64Const [y])) -> (I64AddConst [y] x) +(I64AddConst [0] x) -> x (I64Eqz (I64Eqz (I64Eqz x))) -> (I64Eqz x) ((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off] (I64AddConst [off2] ptr) mem) diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 76212c0866..7931aa7f06 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -212,7 +212,7 @@ // (Mod64u x y) is always between 0 (inclusive) and y (exclusive). (IsInBounds (Mod32u _ y) y) -> (ConstBool [1]) (IsInBounds (Mod64u _ y) y) -> (ConstBool [1]) -// Right shifting a unsigned number limits its value. +// Right shifting an unsigned number limits its value. (IsInBounds (ZeroExt8to64 (Rsh8Ux64 _ (Const64 [c]))) (Const64 [d])) && 0 < c && c < 8 && 1< (ConstBool [1]) (IsInBounds (ZeroExt8to32 (Rsh8Ux64 _ (Const64 [c]))) (Const32 [d])) && 0 < c && c < 8 && 1< (ConstBool [1]) (IsInBounds (ZeroExt8to16 (Rsh8Ux64 _ (Const64 [c]))) (Const16 [d])) && 0 < c && c < 8 && 1< (ConstBool [1]) diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index e85a988d14..4e12132aa5 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -7393,9 +7393,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BSFL", - argLen: 1, - asm: x86.ABSFL, + name: "BSFL", + argLen: 1, + clobberFlags: true, + asm: x86.ABSFL, reg: regInfo{ inputs: []inputInfo{ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 @@ -7420,9 +7421,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BSRL", - argLen: 1, - asm: x86.ABSRL, + name: "BSRL", + argLen: 1, + clobberFlags: true, + asm: x86.ABSRL, reg: regInfo{ inputs: []inputInfo{ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 080ad0fda1..bbf1932981 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -532,6 +532,9 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos } s.assignReg(r, v, c) + if c.Op == OpLoadReg && s.isGReg(r) { + s.f.Fatalf("allocValToReg.OpLoadReg targeting g: " + c.LongString()) + } if nospill { s.nospill |= regMask(1) << r } @@ -809,6 +812,10 @@ func (s *regAllocState) regspec(op Op) regInfo { return opcodeTable[op].reg } +func (s *regAllocState) isGReg(r register) bool { + return s.f.Config.hasGReg && s.GReg == r +} + func (s *regAllocState) regalloc(f *Func) { regValLiveSet := f.newSparseSet(f.NumValues()) // set of values that may be live in register defer f.retSparseSet(regValLiveSet) @@ -951,6 +958,7 @@ func (s *regAllocState) regalloc(f *Func) { // Majority vote? Deepest nesting level? phiRegs = phiRegs[:0] var phiUsed regMask + for _, v := range phis { if !s.values[v.ID].needReg { phiRegs = append(phiRegs, noRegister) @@ -1516,6 +1524,9 @@ func (s *regAllocState) regalloc(f *Func) { // predecessor of it, find live values that we use soon after // the merge point and promote them to registers now. if len(b.Succs) == 1 { + if s.f.Config.hasGReg && s.regs[s.GReg].v != nil { + s.freeReg(s.GReg) // Spill value in G register before any merge. + } // For this to be worthwhile, the loop must have no calls in it. top := b.Succs[0].b loop := s.loopnest.b2l[top.ID] @@ -1996,6 +2007,9 @@ func (e *edgeState) process() { c = e.p.NewValue1(pos, OpLoadReg, c.Type, c) } e.set(r, vid, c, false, pos) + if c.Op == OpLoadReg && e.s.isGReg(register(r.(*Register).num)) { + e.s.f.Fatalf("process.OpLoadReg targeting g: " + c.LongString()) + } } } @@ -2110,6 +2124,9 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP } } e.set(loc, vid, x, true, pos) + if x.Op == OpLoadReg && e.s.isGReg(register(loc.(*Register).num)) { + e.s.f.Fatalf("processDest.OpLoadReg targeting g: " + x.LongString()) + } if splice != nil { (*splice).Uses-- *splice = x diff --git a/src/cmd/compile/internal/ssa/regalloc_test.go b/src/cmd/compile/internal/ssa/regalloc_test.go index 02751a9349..bb8be5e7ac 100644 --- a/src/cmd/compile/internal/ssa/regalloc_test.go +++ b/src/cmd/compile/internal/ssa/regalloc_test.go @@ -36,6 +36,55 @@ func TestLiveControlOps(t *testing.T) { checkFunc(f.f) } +// Test to make sure G register is never reloaded from spill (spill of G is okay) +// See #25504 +func TestNoGetgLoadReg(t *testing.T) { + /* + Original: + func fff3(i int) *g { + gee := getg() + if i == 0 { + fff() + } + return gee // here + } + */ + c := testConfigARM64(t) + f := c.Fun("b1", + Bloc("b1", + Valu("v1", OpInitMem, types.TypeMem, 0, nil), + Valu("v6", OpArg, c.config.Types.Int64, 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64)), + Valu("v8", OpGetG, c.config.Types.Int64.PtrTo(), 0, nil, "v1"), + Valu("v11", OpARM64CMPconst, types.TypeFlags, 0, nil, "v6"), + Eq("v11", "b2", "b4"), + ), + Bloc("b4", + Goto("b3"), + ), + Bloc("b3", + Valu("v14", OpPhi, types.TypeMem, 0, nil, "v1", "v12"), + Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil), + Valu("v16", OpARM64MOVDstore, types.TypeMem, 0, nil, "v8", "sb", "v14"), + Exit("v16"), + ), + Bloc("b2", + Valu("v12", OpARM64CALLstatic, types.TypeMem, 0, nil, "v1"), + Goto("b3"), + ), + ) + regalloc(f.f) + checkFunc(f.f) + // Double-check that we never restore to the G register. Regalloc should catch it, but check again anyway. + r := f.f.RegAlloc + for _, b := range f.blocks { + for _, v := range b.Values { + if v.Op == OpLoadReg && r[v.ID].String() == "g" { + t.Errorf("Saw OpLoadReg targeting g register: %s", v.LongString()) + } + } + } +} + // Test to make sure we don't push spills into loops. // See issue #19595. func TestSpillWithLoop(t *testing.T) { diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go index 38822a7466..f3648ebca1 100644 --- a/src/cmd/compile/internal/ssa/rewriteWasm.go +++ b/src/cmd/compile/internal/ssa/rewriteWasm.go @@ -463,6 +463,8 @@ func rewriteValueWasm(v *Value) bool { return rewriteValueWasm_OpWasmF64Mul_0(v) case OpWasmI64Add: return rewriteValueWasm_OpWasmI64Add_0(v) + case OpWasmI64AddConst: + return rewriteValueWasm_OpWasmI64AddConst_0(v) case OpWasmI64And: return rewriteValueWasm_OpWasmI64And_0(v) case OpWasmI64Eq: @@ -3688,34 +3690,17 @@ func rewriteValueWasm_OpNot_0(v *Value) bool { } } func rewriteValueWasm_OpOffPtr_0(v *Value) bool { - // match: (OffPtr [0] ptr) - // cond: - // result: ptr - for { - if v.AuxInt != 0 { - break - } - ptr := v.Args[0] - v.reset(OpCopy) - v.Type = ptr.Type - v.AddArg(ptr) - return true - } // match: (OffPtr [off] ptr) - // cond: off > 0 + // cond: // result: (I64AddConst [off] ptr) for { off := v.AuxInt ptr := v.Args[0] - if !(off > 0) { - break - } v.reset(OpWasmI64AddConst) v.AuxInt = off v.AddArg(ptr) return true } - return false } func rewriteValueWasm_OpOr16_0(v *Value) bool { // match: (Or16 x y) @@ -5211,6 +5196,22 @@ func rewriteValueWasm_OpWasmI64Add_0(v *Value) bool { } return false } +func rewriteValueWasm_OpWasmI64AddConst_0(v *Value) bool { + // match: (I64AddConst [0] x) + // cond: + // result: x + for { + if v.AuxInt != 0 { + break + } + x := v.Args[0] + v.reset(OpCopy) + v.Type = x.Type + v.AddArg(x) + return true + } + return false +} func rewriteValueWasm_OpWasmI64And_0(v *Value) bool { b := v.Block _ = b diff --git a/src/cmd/compile/internal/ssa/sparsemap.go b/src/cmd/compile/internal/ssa/sparsemap.go index c42fb99c7a..f55db54b1c 100644 --- a/src/cmd/compile/internal/ssa/sparsemap.go +++ b/src/cmd/compile/internal/ssa/sparsemap.go @@ -6,7 +6,7 @@ package ssa import "cmd/internal/src" -// from http://research.swtch.com/sparse +// from https://research.swtch.com/sparse // in turn, from Briggs and Torczon type sparseEntry struct { diff --git a/src/cmd/compile/internal/ssa/sparseset.go b/src/cmd/compile/internal/ssa/sparseset.go index b5cabfb0cd..395931d1ff 100644 --- a/src/cmd/compile/internal/ssa/sparseset.go +++ b/src/cmd/compile/internal/ssa/sparseset.go @@ -4,7 +4,7 @@ package ssa -// from http://research.swtch.com/sparse +// from https://research.swtch.com/sparse // in turn, from Briggs and Torczon type sparseSet struct { diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go index f20fbb4b71..ec80f94e59 100644 --- a/src/cmd/cover/cover_test.go +++ b/src/cmd/cover/cover_test.go @@ -5,6 +5,7 @@ package main_test import ( + "bufio" "bytes" "flag" "fmt" @@ -17,6 +18,7 @@ import ( "os/exec" "path/filepath" "regexp" + "runtime" "strings" "testing" ) @@ -36,6 +38,12 @@ var ( coverInput = filepath.Join(testdata, "test_line.go") coverOutput = filepath.Join(testdata, "test_cover.go") coverProfile = filepath.Join(testdata, "profile.cov") + + // The HTML test files are in a separate directory + // so they are a complete package. + htmlProfile = filepath.Join(testdata, "html", "html.cov") + htmlHTML = filepath.Join(testdata, "html", "html.html") + htmlGolden = filepath.Join(testdata, "html", "html.golden") ) var debug = flag.Bool("debug", false, "keep rewritten files for debugging") @@ -256,6 +264,61 @@ func TestCoverFunc(t *testing.T) { } } +// Check that cover produces correct HTML. +// Issue #25767. +func TestCoverHTML(t *testing.T) { + if _, err := exec.LookPath("diff"); err != nil { + t.Skipf("skip test on %s: diff command is required", runtime.GOOS) + } + testenv.MustHaveGoBuild(t) + if !*debug { + defer os.Remove(testcover) + defer os.Remove(htmlProfile) + defer os.Remove(htmlHTML) + } + // go build -o testcover + cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", testcover) + run(cmd, t) + // go test -coverprofile testdata/html/html.cov cmd/cover/testdata/html + cmd = exec.Command(testenv.GoToolPath(t), "test", "-coverprofile", htmlProfile, "cmd/cover/testdata/html") + run(cmd, t) + // ./testcover -html testdata/html/html.cov -o testdata/html/html.html + cmd = exec.Command(testcover, "-html", htmlProfile, "-o", htmlHTML) + run(cmd, t) + + // Extract the parts of the HTML with comment markers, + // and compare against a golden file. + entireHTML, err := ioutil.ReadFile(htmlHTML) + if err != nil { + t.Fatal(err) + } + var out bytes.Buffer + scan := bufio.NewScanner(bytes.NewReader(entireHTML)) + in := false + for scan.Scan() { + line := scan.Text() + if strings.Contains(line, "// START") { + in = true + } + if in { + fmt.Fprintln(&out, line) + } + if strings.Contains(line, "// END") { + in = false + } + } + if err := ioutil.WriteFile(htmlHTML, out.Bytes(), 0644); err != nil { + t.Fatal(err) + } + diff := "diff" + if runtime.GOOS == "plan9" { + diff = "/bin/ape/diff" + } + // diff -uw testdata/html/html.html testdata/html/html.golden + cmd = exec.Command(diff, "-u", "-w", htmlHTML, htmlGolden) + run(cmd, t) +} + func run(c *exec.Cmd, t *testing.T) { t.Helper() c.Stdout = os.Stdout diff --git a/src/cmd/cover/profile.go b/src/cmd/cover/profile.go index 5628b91f51..656c862740 100644 --- a/src/cmd/cover/profile.go +++ b/src/cmd/cover/profile.go @@ -153,6 +153,7 @@ type Boundary struct { Start bool // Is this the start of a block? Count int // Event count from the cover profile. Norm float64 // Count normalized to [0..1]. + Index int // Order in input file. } // Boundaries returns a Profile as a set of Boundary objects within the provided src. @@ -168,13 +169,15 @@ func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) { divisor := math.Log(float64(max)) // boundary returns a Boundary, populating the Norm field with a normalized Count. + index := 0 boundary := func(offset int, start bool, count int) Boundary { - b := Boundary{Offset: offset, Start: start, Count: count} + b := Boundary{Offset: offset, Start: start, Count: count, Index: index} + index++ if !start || count == 0 { return b } if max <= 1 { - b.Norm = 0.8 // Profile is in"set" mode; we want a heat map. Use cov8 in the CSS. + b.Norm = 0.8 // Profile is in "set" mode; we want a heat map. Use cov8 in the CSS. } else if count > 0 { b.Norm = math.Log(float64(count)) / divisor } @@ -209,7 +212,9 @@ func (b boundariesByPos) Len() int { return len(b) } func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b boundariesByPos) Less(i, j int) bool { if b[i].Offset == b[j].Offset { - return !b[i].Start && b[j].Start + // Boundaries at the same offset should be ordered according to + // their original position. + return b[i].Index < b[j].Index } return b[i].Offset < b[j].Offset } diff --git a/src/cmd/cover/testdata/html/html.go b/src/cmd/cover/testdata/html/html.go new file mode 100644 index 0000000000..20578259a5 --- /dev/null +++ b/src/cmd/cover/testdata/html/html.go @@ -0,0 +1,30 @@ +package html + +import "fmt" + +// This file is tested by html_test.go. +// The comments below are markers for extracting the annotated source +// from the HTML output. + +// This is a regression test for incorrect sorting of boundaries +// that coincide, specifically for empty select clauses. +// START f +func f() { + ch := make(chan int) + select { + case <-ch: + default: + } +} + +// END f + +// https://golang.org/issue/25767 +// START g +func g() { + if false { + fmt.Printf("Hello") + } +} + +// END g diff --git a/src/cmd/cover/testdata/html/html.golden b/src/cmd/cover/testdata/html/html.golden new file mode 100644 index 0000000000..84377d1e20 --- /dev/null +++ b/src/cmd/cover/testdata/html/html.golden @@ -0,0 +1,18 @@ +// START f +func f() { + ch := make(chan int) + select { + case <-ch: + default: + } +} + +// END f +// START g +func g() { + if false { + fmt.Printf("Hello") + } +} + +// END g diff --git a/src/cmd/cover/testdata/html/html_test.go b/src/cmd/cover/testdata/html/html_test.go new file mode 100644 index 0000000000..c15561fe4a --- /dev/null +++ b/src/cmd/cover/testdata/html/html_test.go @@ -0,0 +1,8 @@ +package html + +import "testing" + +func TestAll(t *testing.T) { + f() + g() +} diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 99d1db5909..effea903e9 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -1438,7 +1438,7 @@ func checkCC() { fatalf("cannot invoke C compiler %q: %v\n\n"+ "Go needs a system C compiler for use with cgo.\n"+ "To set a C compiler, set CC=the-compiler.\n"+ - "To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output) + "To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc[""], err, outputHdr, output) } } diff --git a/src/cmd/dist/main.go b/src/cmd/dist/main.go index a72a2607f9..37e37e2733 100644 --- a/src/cmd/dist/main.go +++ b/src/cmd/dist/main.go @@ -9,7 +9,6 @@ import ( "fmt" "os" "runtime" - "strconv" "strings" ) @@ -61,6 +60,8 @@ func main() { // Even on 64-bit platform, darwin uname -m prints i386. // We don't support any of the OS X versions that run on 32-bit-only hardware anymore. gohostarch = "amd64" + // macOS 10.9 and later require clang + defaultclang = true case "freebsd": // Since FreeBSD 10 gcc is no longer part of the base system. defaultclang = true @@ -126,29 +127,6 @@ func main() { } bginit() - // The OS X 10.6 linker does not support external linking mode. - // See golang.org/issue/5130. - // - // OS X 10.6 does not work with clang either, but OS X 10.9 requires it. - // It seems to work with OS X 10.8, so we default to clang for 10.8 and later. - // See golang.org/issue/5822. - // - // Roughly, OS X 10.N shows up as uname release (N+4), - // so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12. - if gohostos == "darwin" { - rel := run("", CheckExit, "uname", "-r") - if i := strings.Index(rel, "."); i >= 0 { - rel = rel[:i] - } - osx, _ := strconv.Atoi(rel) - if osx <= 6+4 { - goextlinkenabled = "0" - } - if osx >= 8+4 { - defaultclang = true - } - } - if len(os.Args) > 1 && os.Args[1] == "-check-goarm" { useVFPv1() // might fail with SIGILL println("VFPv1 OK.") diff --git a/src/cmd/dist/sys_windows.go b/src/cmd/dist/sys_windows.go index 6d1f82e093..216dc01798 100644 --- a/src/cmd/dist/sys_windows.go +++ b/src/cmd/dist/sys_windows.go @@ -14,7 +14,7 @@ var ( procGetSystemInfo = modkernel32.NewProc("GetSystemInfo") ) -// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx +// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx type systeminfo struct { wProcessorArchitecture uint16 wReserved uint16 diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 5bd5b424af..a1c470cc97 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -889,7 +889,7 @@ func (t *tester) extLink() bool { pair := gohostos + "-" + goarch switch pair { case "android-arm", - "darwin-arm", "darwin-arm64", + "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64", "dragonfly-amd64", "freebsd-386", "freebsd-amd64", "freebsd-arm", "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x", @@ -897,15 +897,6 @@ func (t *tester) extLink() bool { "openbsd-386", "openbsd-amd64", "windows-386", "windows-amd64": return true - case "darwin-386", "darwin-amd64": - // linkmode=external fails on OS X 10.6 and earlier == Darwin - // 10.8 and earlier. - unameR, err := exec.Command("uname", "-r").Output() - if err != nil { - log.Fatalf("uname -r: %v", err) - } - major, _ := strconv.Atoi(string(unameR[:bytes.IndexByte(unameR, '.')])) - return major > 10 } return false } diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 8cccbf4de0..3494601e69 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -579,7 +579,7 @@ // // Usage: // -// go list [-deps] [-e] [-f format] [-json] [-test] [build flags] [packages] +// go list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-list] [-test] [build flags] [packages] // // List lists the packages named by the import paths, one per line. // @@ -609,6 +609,9 @@ // Root string // Go root or Go path dir containing this package // ConflictDir string // this directory shadows Dir in $GOPATH // BinaryOnly bool // binary-only package: cannot be recompiled from sources +// ForTest string // package is only for use in named test +// DepOnly bool // package is only a dependency, not explicitly listed +// Export string // file containing export data (when using -export) // // // Source files // GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) @@ -683,9 +686,15 @@ // The -json flag causes the package data to be printed in JSON format // instead of using the template format. // +// The -cgo flag causes list to set CgoFiles not to the original *.go files +// importing "C" but instead to the translated files generated by the cgo +// command. +// // The -deps flag causes list to iterate over not just the named packages // but also all their dependencies. It visits them in a depth-first post-order // traversal, so that a package is listed only after all its dependencies. +// Packages not explicitly listed on the command line will have the DepOnly +// field set to true. // // The -e flag changes the handling of erroneous packages, those that // cannot be found or are malformed. By default, the list command @@ -697,6 +706,9 @@ // a non-nil Error field; other information may or may not be missing // (zeroed). // +// The -export flag causes list to set the Export field to the name of a +// file containing up-to-date export information for the given package. +// // The -test flag causes list to report not only the named packages // but also their test binaries (for packages with tests), to convey to // source code analysis tools exactly how test binaries are constructed. @@ -707,7 +719,18 @@ // package itself). The reported import path of a package recompiled // for a particular test binary is followed by a space and the name of // the test binary in brackets, as in "math/rand [math/rand.test]" -// or "regexp [sort.test]". +// or "regexp [sort.test]". The ForTest field is also set to the name +// of the package being tested ("math/rand" or "sort" in the previous +// examples). +// +// The Dir, Target, Shlib, Root, ConflictDir, and Export file paths +// are all absolute paths. +// +// By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir +// (that is, paths relative to Dir, not absolute paths). +// The extra entries added by the -cgo and -test flags are absolute paths +// referring to cached copies of generated Go source files. +// Although they are Go source files, the paths may not end in ".go". // // For more about build flags, see 'go help build'. // diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index b3129dc7f6..f7ac776eb6 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -1977,6 +1977,55 @@ func TestGoListTest(t *testing.T) { tg.grepStdout(`^runtime/cgo$`, "missing runtime/cgo") } +func TestGoListCgo(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOCACHE", tg.tempdir) + + tg.run("list", "-f", `{{join .CgoFiles "\n"}}`, "net") + if tg.stdout.String() == "" { + t.Skip("net does not use cgo") + } + if strings.Contains(tg.stdout.String(), tg.tempdir) { + t.Fatalf(".CgoFiles without -cgo unexpectedly mentioned cache %s", tg.tempdir) + } + tg.run("list", "-cgo", "-f", `{{join .CgoFiles "\n"}}`, "net") + if !strings.Contains(tg.stdout.String(), tg.tempdir) { + t.Fatalf(".CgoFiles with -cgo did not mention cache %s", tg.tempdir) + } + for _, file := range strings.Split(tg.stdout.String(), "\n") { + if file == "" { + continue + } + if _, err := os.Stat(file); err != nil { + t.Fatalf("cannot find .CgoFiles result %s: %v", file, err) + } + } +} + +func TestGoListExport(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOCACHE", tg.tempdir) + + tg.run("list", "-f", "{{.Export}}", "strings") + if tg.stdout.String() != "" { + t.Fatalf(".Export without -export unexpectedly set") + } + tg.run("list", "-export", "-f", "{{.Export}}", "strings") + file := strings.TrimSpace(tg.stdout.String()) + if file == "" { + t.Fatalf(".Export with -export was empty") + } + if _, err := os.Stat(file); err != nil { + t.Fatalf("cannot find .Export result %s: %v", file, err) + } +} + // Issue 4096. Validate the output of unsuccessful go install foo/quxx. func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) { tg := testgo(t) @@ -2925,7 +2974,7 @@ func TestCgoPkgConfig(t *testing.T) { // OpenBSD's pkg-config is strict about whitespace and only // supports backslash-escaped whitespace. It does not support // quotes, which the normal freedesktop.org pkg-config does - // support. See http://man.openbsd.org/pkg-config.1 + // support. See https://man.openbsd.org/pkg-config.1 tg.tempFile("foo.pc", ` Name: foo Description: The foo library @@ -3203,6 +3252,43 @@ func TestGoTestBuildsAnXtestContainingOnlyNonRunnableExamples(t *testing.T) { tg.grepStdout("File with non-runnable example was built.", "file with non-runnable example was not built") } +// issue 24570 +func TestGoTestCoverMultiPackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "-cover", "./testdata/testcover/...") + tg.grepStdout(`\?.*testdata/testcover/pkg1.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1") + tg.grepStdout(`ok.*testdata/testcover/pkg2.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2") + tg.grepStdout(`ok.*testdata/testcover/pkg3.*\d\.\d\d\ds.*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3") +} + +// issue 24570 +func TestGoTestCoverprofileMultiPackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.creatingTemp("testdata/cover.out") + tg.run("test", "-coverprofile=testdata/cover.out", "./testdata/testcover/...") + tg.grepStdout(`\?.*testdata/testcover/pkg1.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1") + tg.grepStdout(`ok.*testdata/testcover/pkg2.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2") + tg.grepStdout(`ok.*testdata/testcover/pkg3.*\d\.\d\d\ds.*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3") + if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil { + t.Error(err) + } else { + if !bytes.Contains(out, []byte("mode: set")) { + t.Errorf(`missing "mode: set" in %s`, out) + } + if !bytes.Contains(out, []byte(`pkg1/a.go:5.10,7.2 1 0`)) && !bytes.Contains(out, []byte(`pkg1\a.go:5.10,7.2 1 0`)) { + t.Errorf(`missing "pkg1/a.go:5.10,7.2 1 0" in %s`, out) + } + if !bytes.Contains(out, []byte(`pkg2/a.go:5.10,7.2 1 0`)) && !bytes.Contains(out, []byte(`pkg2\a.go:5.10,7.2 1 0`)) { + t.Errorf(`missing "pkg2/a.go:5.10,7.2 1 0" in %s`, out) + } + if !bytes.Contains(out, []byte(`pkg3/a.go:5.10,7.2 1 1`)) && !bytes.Contains(out, []byte(`pkg3\a.go:5.10,7.2 1 1`)) { + t.Errorf(`missing "pkg3/a.go:5.10,7.2 1 1" in %s`, out) + } + } +} + func TestGoGenerateHandlesSimpleCommand(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping because windows has no echo command") @@ -3690,6 +3776,40 @@ func TestGoGetUpdateInsecure(t *testing.T) { tg.run("get", "-d", "-u", "-f", "-insecure", pkg) } +func TestGoGetUpdateUnknownProtocol(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + + const repo = "github.com/golang/example" + + // Clone the repo via HTTPS manually. + repoDir := tg.path("src/" + repo) + cmd := exec.Command("git", "clone", "-q", "https://"+repo, repoDir) + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("cloning %v repo: %v\n%s", repo, err, out) + } + + // Configure the repo to use a protocol unknown to cmd/go + // that still actually works. + cmd = exec.Command("git", "remote", "set-url", "origin", "xyz://"+repo) + cmd.Dir = repoDir + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("git remote set-url: %v\n%s", err, out) + } + cmd = exec.Command("git", "config", "--local", "url.https://github.com/.insteadOf", "xyz://github.com/") + cmd.Dir = repoDir + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("git config: %v\n%s", err, out) + } + + // We need -f to ignore import comments. + tg.run("get", "-d", "-u", "-f", repo+"/hello") +} + func TestGoGetInsecureCustomDomain(t *testing.T) { testenv.MustHaveExternalNetwork(t) @@ -4900,30 +5020,34 @@ func TestTestRegexps(t *testing.T) { // BenchmarkX/Y is run in full, twice want := `=== RUN TestX === RUN TestX/Y - x_test.go:6: LOG: X running - x_test.go:8: LOG: Y running + x_test.go:6: LOG: X running + x_test.go:8: LOG: Y running === RUN TestXX - z_test.go:10: LOG: XX running + z_test.go:10: LOG: XX running === RUN TestX === RUN TestX/Y - x_test.go:6: LOG: X running - x_test.go:8: LOG: Y running + x_test.go:6: LOG: X running + x_test.go:8: LOG: Y running === RUN TestXX - z_test.go:10: LOG: XX running + z_test.go:10: LOG: XX running --- BENCH: BenchmarkX/Y - x_test.go:15: LOG: Y running N=1 - x_test.go:15: LOG: Y running N=100 - x_test.go:15: LOG: Y running N=10000 - x_test.go:15: LOG: Y running N=1000000 - x_test.go:15: LOG: Y running N=100000000 - x_test.go:15: LOG: Y running N=2000000000 + x_test.go:15: LOG: Y running N=1 + x_test.go:15: LOG: Y running N=100 + x_test.go:15: LOG: Y running N=10000 + x_test.go:15: LOG: Y running N=1000000 + x_test.go:15: LOG: Y running N=100000000 + x_test.go:15: LOG: Y running N=2000000000 --- BENCH: BenchmarkX/Y - x_test.go:15: LOG: Y running N=1 - x_test.go:15: LOG: Y running N=2000000000 + x_test.go:15: LOG: Y running N=1 + x_test.go:15: LOG: Y running N=100 + x_test.go:15: LOG: Y running N=10000 + x_test.go:15: LOG: Y running N=1000000 + x_test.go:15: LOG: Y running N=100000000 + x_test.go:15: LOG: Y running N=2000000000 --- BENCH: BenchmarkX - x_test.go:13: LOG: X running N=1 + x_test.go:13: LOG: X running N=1 --- BENCH: BenchmarkXX - z_test.go:18: LOG: XX running N=1 + z_test.go:18: LOG: XX running N=1 ` have := strings.Join(lines, "") @@ -6300,3 +6424,47 @@ func TestLinkerTmpDirIsDeleted(t *testing.T) { t.Fatalf("Stat(%q) returns unexpected error: %v", tmpdir, err) } } + +func testCDAndGOPATHAreDifferent(tg *testgoData, cd, gopath string) { + tg.setenv("GOPATH", gopath) + + tg.tempDir("dir") + exe := tg.path("dir/a.exe") + + tg.cd(cd) + + tg.run("build", "-o", exe, "-ldflags", "-X=my.pkg.Text=linkXworked") + out, err := exec.Command(exe).CombinedOutput() + if err != nil { + tg.t.Fatal(err) + } + if string(out) != "linkXworked\n" { + tg.t.Errorf(`incorrect output with GOPATH=%q and CD=%q: expected "linkXworked\n", but have %q`, gopath, cd, string(out)) + } +} + +func TestCDAndGOPATHAreDifferent(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + + gopath := filepath.Join(tg.pwd(), "testdata") + cd := filepath.Join(gopath, "src/my.pkg/main") + + testCDAndGOPATHAreDifferent(tg, cd, gopath) + if runtime.GOOS == "windows" { + testCDAndGOPATHAreDifferent(tg, cd, strings.Replace(gopath, `\`, `/`, -1)) + testCDAndGOPATHAreDifferent(tg, cd, strings.ToUpper(gopath)) + testCDAndGOPATHAreDifferent(tg, cd, strings.ToLower(gopath)) + } +} + +// Issue 25579. +func TestGoBuildDashODevNull(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.run("build", "-o", os.DevNull, filepath.Join(tg.pwd(), "testdata", "src", "hello", "hello.go")) + tg.mustNotExist("hello") + tg.mustNotExist("hello.exe") +} diff --git a/src/cmd/go/internal/get/discovery.go b/src/cmd/go/internal/get/discovery.go index b2918dbb4f..97aa1d7e8d 100644 --- a/src/cmd/go/internal/get/discovery.go +++ b/src/cmd/go/internal/get/discovery.go @@ -55,6 +55,13 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { continue } if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { + // Ignore VCS type "mod", which is new Go modules. + // This code is for old go get and must ignore the new mod lines. + // Otherwise matchGoImport will complain about two + // different metaImport lines for the same Prefix. + if f[1] == "mod" { + continue + } imports = append(imports, metaImport{ Prefix: f[0], VCS: f[1], diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go index 733116eca0..ffa15c5ba4 100644 --- a/src/cmd/go/internal/get/get.go +++ b/src/cmd/go/internal/get/get.go @@ -209,7 +209,7 @@ var downloadRootCache = map[string]bool{} // download runs the download half of the get command // for the package named by the argument. func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) { - if mode&load.UseVendor != 0 { + if mode&load.ResolveImport != 0 { // Caller is responsible for expanding vendor paths. panic("internal error: download mode has useVendor set") } @@ -217,7 +217,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) if parent == nil { return load.LoadPackage(path, stk) } - return load.LoadImport(path, parent.Dir, parent, stk, nil, mode) + return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule) } p := load1(arg, mode) @@ -346,12 +346,12 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) base.Errorf("%s", err) continue } - // If this is a test import, apply vendor lookup now. - // We cannot pass useVendor to download, because + // If this is a test import, apply module and vendor lookup now. + // We cannot pass ResolveImport to download, because // download does caching based on the value of path, // so it must be the fully qualified path already. if i >= len(p.Imports) { - path = load.VendoredImportPath(p, path) + path = load.ResolveImportPath(p, path) } download(path, p, stk, 0) } @@ -369,6 +369,7 @@ func downloadPackage(p *load.Package) error { vcs *vcsCmd repo, rootPath string err error + blindRepo bool // set if the repo has unusual configuration ) security := web.Secure @@ -389,10 +390,12 @@ func downloadPackage(p *load.Package) error { dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) remote, err := vcs.remoteRepo(vcs, dir) if err != nil { - return err + // Proceed anyway. The package is present; we likely just don't understand + // the repo configuration (e.g. unusual remote protocol). + blindRepo = true } repo = remote - if !*getF { + if !*getF && err == nil { if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil { repo := rr.repo if rr.vcs.resolveRepo != nil { @@ -416,7 +419,7 @@ func downloadPackage(p *load.Package) error { } vcs, repo, rootPath = rr.vcs, rr.repo, rr.root } - if !vcs.isSecure(repo) && !*getInsecure { + if !blindRepo && !vcs.isSecure(repo) && !*getInsecure { return fmt.Errorf("cannot download, %v uses insecure protocol", repo) } diff --git a/src/cmd/go/internal/get/pkg_test.go b/src/cmd/go/internal/get/pkg_test.go index b8937a57ec..1179d86693 100644 --- a/src/cmd/go/internal/get/pkg_test.go +++ b/src/cmd/go/internal/get/pkg_test.go @@ -47,6 +47,20 @@ var parseMetaGoImportsTests = []struct { {"baz/quux", "git", "http://github.com/rsc/baz/quux"}, }, }, + { + ` + `, + []metaImport{ + {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, + }, + }, + { + ` + `, + []metaImport{ + {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, + }, + }, { ` diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 5b242a887a..7261d24839 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -23,7 +23,7 @@ import ( ) var CmdList = &base.Command{ - UsageLine: "list [-deps] [-e] [-f format] [-json] [-test] [build flags] [packages]", + UsageLine: "list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-list] [-test] [build flags] [packages]", Short: "list packages", Long: ` List lists the packages named by the import paths, one per line. @@ -54,6 +54,9 @@ syntax of package template. The default output is equivalent to -f Root string // Go root or Go path dir containing this package ConflictDir string // this directory shadows Dir in $GOPATH BinaryOnly bool // binary-only package: cannot be recompiled from sources + ForTest string // package is only for use in named test + DepOnly bool // package is only a dependency, not explicitly listed + Export string // file containing export data (when using -export) // Source files GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) @@ -128,9 +131,15 @@ for the go/build package's Context type. The -json flag causes the package data to be printed in JSON format instead of using the template format. +The -cgo flag causes list to set CgoFiles not to the original *.go files +importing "C" but instead to the translated files generated by the cgo +command. + The -deps flag causes list to iterate over not just the named packages but also all their dependencies. It visits them in a depth-first post-order traversal, so that a package is listed only after all its dependencies. +Packages not explicitly listed on the command line will have the DepOnly +field set to true. The -e flag changes the handling of erroneous packages, those that cannot be found or are malformed. By default, the list command @@ -142,6 +151,9 @@ printing. Erroneous packages will have a non-empty ImportPath and a non-nil Error field; other information may or may not be missing (zeroed). +The -export flag causes list to set the Export field to the name of a +file containing up-to-date export information for the given package. + The -test flag causes list to report not only the named packages but also their test binaries (for packages with tests), to convey to source code analysis tools exactly how test binaries are constructed. @@ -152,7 +164,18 @@ dependencies specially for that test (most commonly the tested package itself). The reported import path of a package recompiled for a particular test binary is followed by a space and the name of the test binary in brackets, as in "math/rand [math/rand.test]" -or "regexp [sort.test]". +or "regexp [sort.test]". The ForTest field is also set to the name +of the package being tested ("math/rand" or "sort" in the previous +examples). + +The Dir, Target, Shlib, Root, ConflictDir, and Export file paths +are all absolute paths. + +By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir +(that is, paths relative to Dir, not absolute paths). +The extra entries added by the -cgo and -test flags are absolute paths +referring to cached copies of generated Go source files. +Although they are Go source files, the paths may not end in ".go". For more about build flags, see 'go help build'. @@ -165,8 +188,10 @@ func init() { work.AddBuildFlags(CmdList) } +var listCgo = CmdList.Flag.Bool("cgo", false, "") var listDeps = CmdList.Flag.Bool("deps", false, "") var listE = CmdList.Flag.Bool("e", false, "") +var listExport = CmdList.Flag.Bool("export", false, "") var listFmt = CmdList.Flag.String("f", "{{.ImportPath}}", "") var listJson = CmdList.Flag.Bool("json", false, "") var listTest = CmdList.Flag.Bool("test", false, "") @@ -222,11 +247,22 @@ func runList(cmd *base.Command, args []string) { pkgs = load.Packages(args) } - if *listTest { - c := cache.Default() - if c == nil { + if cache.Default() == nil { + // These flags return file names pointing into the build cache, + // so the build cache must exist. + if *listCgo { + base.Fatalf("go list -cgo requires build cache") + } + if *listExport { + base.Fatalf("go list -export requires build cache") + } + if *listTest { base.Fatalf("go list -test requires build cache") } + } + + if *listTest { + c := cache.Default() // Add test binaries to packages to be listed. for _, p := range pkgs { if p.Error != nil { @@ -279,13 +315,14 @@ func runList(cmd *base.Command, args []string) { pkgs = load.PackageList(pkgs) } - // Estimate whether staleness information is needed, - // since it's a little bit of work to compute. + // Do we need to run a build to gather information? needStale := *listJson || strings.Contains(*listFmt, ".Stale") - if needStale { + if needStale || *listExport || *listCgo { var b work.Builder b.Init() - b.ComputeStaleOnly = true + b.IsCmdList = true + b.NeedExport = *listExport + b.NeedCgoFiles = *listCgo a := &work.Action{} // TODO: Use pkgsFilter? for _, p := range pkgs { @@ -296,8 +333,8 @@ func runList(cmd *base.Command, args []string) { for _, p := range pkgs { // Show vendor-expanded paths in listing - p.TestImports = p.Vendored(p.TestImports) - p.XTestImports = p.Vendored(p.XTestImports) + p.TestImports = p.Resolve(p.TestImports) + p.XTestImports = p.Resolve(p.XTestImports) } if *listTest { diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index e89eadc962..b5a27c6306 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -6,6 +6,7 @@ package load import ( + "bytes" "fmt" "go/build" "go/token" @@ -14,6 +15,7 @@ import ( pathpkg "path" "path/filepath" "sort" + "strconv" "strings" "unicode" "unicode/utf8" @@ -49,6 +51,7 @@ type PackagePublic struct { BinaryOnly bool `json:",omitempty"` // package cannot be recompiled ForTest string `json:",omitempty"` // package is only for use in named test DepOnly bool `json:",omitempty"` // package is only as a dependency, not explicitly listed + Export string `json:",omitempty"` // file containing export data (set by go list -export) // Stale and StaleReason remain here *only* for the list command. // They are only initialized in preparation for list execution. @@ -179,7 +182,7 @@ func (e *NoGoError) Error() string { return "no Go files in " + e.Package.Dir } -// Vendored returns the vendor-resolved version of imports, +// Resolve returns the resolved version of imports, // which should be p.TestImports or p.XTestImports, NOT p.Imports. // The imports in p.TestImports and p.XTestImports are not recursively // loaded during the initial load of p, so they list the imports found in @@ -189,14 +192,14 @@ func (e *NoGoError) Error() string { // can produce better error messages if it starts with the original paths. // The initial load of p loads all the non-test imports and rewrites // the vendored paths, so nothing should ever call p.vendored(p.Imports). -func (p *Package) Vendored(imports []string) []string { +func (p *Package) Resolve(imports []string) []string { if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] { - panic("internal error: p.vendored(p.Imports) called") + panic("internal error: p.Resolve(p.Imports) called") } seen := make(map[string]bool) var all []string for _, path := range imports { - path = VendoredImportPath(p, path) + path = ResolveImportPath(p, path) if !seen[path] { seen[path] = true all = append(all, path) @@ -397,16 +400,20 @@ func makeImportValid(r rune) rune { // Mode flags for loadImport and download (in get.go). const ( - // UseVendor means that loadImport should do vendor expansion - // (provided the vendoring experiment is enabled). - // That is, useVendor means that the import path came from - // a source file and has not been vendor-expanded yet. - // Every import path should be loaded initially with useVendor, - // and then the expanded version (with the /vendor/ in it) gets - // recorded as the canonical import path. At that point, future loads - // of that package must not pass useVendor, because + // ResolveImport means that loadImport should do import path expansion. + // That is, ResolveImport means that the import path came from + // a source file and has not been expanded yet to account for + // vendoring or possible module adjustment. + // Every import path should be loaded initially with ResolveImport, + // and then the expanded version (for example with the /vendor/ in it) + // gets recorded as the canonical import path. At that point, future loads + // of that package must not pass ResolveImport, because // disallowVendor will reject direct use of paths containing /vendor/. - UseVendor = 1 << iota + ResolveImport = 1 << iota + + // ResolveModule is for download (part of "go get") and indicates + // that the module adjustment should be done, but not vendor adjustment. + ResolveModule // GetTestDeps is for download (part of "go get") and indicates // that test dependencies should be fetched too. @@ -431,12 +438,15 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo isLocal := build.IsLocalImport(path) if isLocal { importPath = dirToImportPath(filepath.Join(srcDir, path)) - } else if mode&UseVendor != 0 { - // We do our own vendor resolution, because we want to + } else if mode&ResolveImport != 0 { + // We do our own path resolution, because we want to // find out the key to use in packageCache without the // overhead of repeated calls to buildContext.Import. // The code is also needed in a few other places anyway. - path = VendoredImportPath(parent, path) + path = ResolveImportPath(parent, path) + importPath = path + } else if mode&ResolveModule != 0 { + path = ModuleImportPath(parent, path) importPath = path } @@ -453,7 +463,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo // Import always returns bp != nil, even if an error occurs, // in order to return partial information. buildMode := build.ImportComment - if mode&UseVendor == 0 || path != origPath { + if mode&ResolveImport == 0 || path != origPath { // Not vendoring, or we already found the vendored path. buildMode |= build.IgnoreVendor } @@ -484,7 +494,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo if perr := disallowInternal(srcDir, p, stk); perr != p { return setErrorPos(perr, importPos) } - if mode&UseVendor != 0 { + if mode&ResolveImport != 0 { if perr := disallowVendor(srcDir, origPath, p, stk); perr != p { return setErrorPos(perr, importPos) } @@ -543,7 +553,50 @@ func isDir(path string) bool { return result } -// VendoredImportPath returns the expansion of path when it appears in parent. +// ResolveImportPath returns the true meaning of path when it appears in parent. +// There are two different resolutions applied. +// First, there is Go 1.5 vendoring (golang.org/s/go15vendor). +// If vendor expansion doesn't trigger, then the path is also subject to +// Go 1.11 vgo legacy conversion (golang.org/issue/25069). +func ResolveImportPath(parent *Package, path string) (found string) { + found = VendoredImportPath(parent, path) + if found != path { + return found + } + return ModuleImportPath(parent, path) +} + +// dirAndRoot returns the source directory and workspace root +// for the package p, guaranteeing that root is a path prefix of dir. +func dirAndRoot(p *Package) (dir, root string) { + dir = filepath.Clean(p.Dir) + root = filepath.Join(p.Root, "src") + if !str.HasFilePathPrefix(dir, root) || p.ImportPath != "command-line-arguments" && filepath.Join(root, p.ImportPath) != dir { + // Look for symlinks before reporting error. + dir = expandPath(dir) + root = expandPath(root) + } + + if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || p.ImportPath != "command-line-arguments" && !p.Internal.Local && filepath.Join(root, p.ImportPath) != dir { + base.Fatalf("unexpected directory layout:\n"+ + " import path: %s\n"+ + " root: %s\n"+ + " dir: %s\n"+ + " expand root: %s\n"+ + " expand dir: %s\n"+ + " separator: %s", + p.ImportPath, + filepath.Join(p.Root, "src"), + filepath.Clean(p.Dir), + root, + dir, + string(filepath.Separator)) + } + + return dir, root +} + +// VendoredImportPath returns the vendor-expansion of path when it appears in parent. // If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path, // 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. @@ -552,29 +605,7 @@ func VendoredImportPath(parent *Package, path string) (found string) { return path } - dir := filepath.Clean(parent.Dir) - root := filepath.Join(parent.Root, "src") - if !str.HasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir { - // Look for symlinks before reporting error. - dir = expandPath(dir) - root = expandPath(root) - } - - if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir { - base.Fatalf("unexpected directory layout:\n"+ - " import path: %s\n"+ - " root: %s\n"+ - " dir: %s\n"+ - " expand root: %s\n"+ - " expand dir: %s\n"+ - " separator: %s", - parent.ImportPath, - filepath.Join(parent.Root, "src"), - filepath.Clean(parent.Dir), - root, - dir, - string(filepath.Separator)) - } + dir, root := dirAndRoot(parent) vpath := "vendor/" + path for i := len(dir); i >= len(root); i-- { @@ -618,6 +649,164 @@ func VendoredImportPath(parent *Package, path string) (found string) { return path } +var ( + modulePrefix = []byte("\nmodule ") + goModPathCache = make(map[string]string) +) + +// goModPath returns the module path in the go.mod in dir, if any. +func goModPath(dir string) (path string) { + path, ok := goModPathCache[dir] + if ok { + return path + } + defer func() { + goModPathCache[dir] = path + }() + + data, err := ioutil.ReadFile(filepath.Join(dir, "go.mod")) + if err != nil { + return "" + } + var i int + if bytes.HasPrefix(data, modulePrefix[1:]) { + i = 0 + } else { + i = bytes.Index(data, modulePrefix) + if i < 0 { + return "" + } + i++ + } + line := data[i:] + + // Cut line at \n, drop trailing \r if present. + if j := bytes.IndexByte(line, '\n'); j >= 0 { + line = line[:j] + } + if line[len(line)-1] == '\r' { + line = line[:len(line)-1] + } + line = line[len("module "):] + + // If quoted, unquote. + path = strings.TrimSpace(string(line)) + if path != "" && path[0] == '"' { + s, err := strconv.Unquote(path) + if err != nil { + return "" + } + path = s + } + return path +} + +// findVersionElement returns the slice indices of the final version element /vN in path. +// If there is no such element, it returns -1, -1. +func findVersionElement(path string) (i, j int) { + j = len(path) + for i = len(path) - 1; i >= 0; i-- { + if path[i] == '/' { + if isVersionElement(path[i:j]) { + return i, j + } + j = i + } + } + return -1, -1 +} + +// isVersionElement reports whether s is a well-formed path version element: +// v2, v3, v10, etc, but not v0, v05, v1. +func isVersionElement(s string) bool { + if len(s) < 3 || s[0] != '/' || s[1] != 'v' || s[2] == '0' || s[2] == '1' && len(s) == 3 { + return false + } + for i := 2; i < len(s); i++ { + if s[i] < '0' || '9' < s[i] { + return false + } + } + return true +} + +// ModuleImportPath translates import paths found in go modules +// back down to paths that can be resolved in ordinary builds. +// +// Define “new” code as code with a go.mod file in the same directory +// or a parent directory. If an import in new code says x/y/v2/z but +// x/y/v2/z does not exist and x/y/go.mod says “module x/y/v2”, +// then go build will read the import as x/y/z instead. +// See golang.org/issue/25069. +func ModuleImportPath(parent *Package, path string) (found string) { + if parent == nil || parent.Root == "" { + return path + } + + // If there are no vN elements in path, leave it alone. + // (The code below would do the same, but only after + // some other file system accesses that we can avoid + // here by returning early.) + if i, _ := findVersionElement(path); i < 0 { + return path + } + + dir, root := dirAndRoot(parent) + + // Consider dir and parents, up to and including root. + for i := len(dir); i >= len(root); i-- { + if i < len(dir) && dir[i] != filepath.Separator { + continue + } + if goModPath(dir[:i]) != "" { + goto HaveGoMod + } + } + // This code is not in a tree with a go.mod, + // so apply no changes to the path. + return path + +HaveGoMod: + // This import is in a tree with a go.mod. + // Allow it to refer to code in GOPATH/src/x/y/z as x/y/v2/z + // if GOPATH/src/x/y/go.mod says module "x/y/v2", + + // If x/y/v2/z exists, use it unmodified. + if bp, _ := cfg.BuildContext.Import(path, "", build.IgnoreVendor); bp.Dir != "" { + return path + } + + // Otherwise look for a go.mod supplying a version element. + // Some version-like elements may appear in paths but not + // be module versions; we skip over those to look for module + // versions. For example the module m/v2 might have a + // package m/v2/api/v1/foo. + limit := len(path) + for limit > 0 { + i, j := findVersionElement(path[:limit]) + if i < 0 { + return path + } + if bp, _ := cfg.BuildContext.Import(path[:i], "", build.IgnoreVendor); bp.Dir != "" { + if mpath := goModPath(bp.Dir); mpath != "" { + // Found a valid go.mod file, so we're stopping the search. + // If the path is m/v2/p and we found m/go.mod that says + // "module m/v2", then we return "m/p". + if mpath == path[:j] { + return path[:i] + path[j:] + } + // Otherwise just return the original path. + // We didn't find anything worth rewriting, + // and the go.mod indicates that we should + // not consider parent directories. + return path + } + } + limit = i + } + return path +} + // hasGoFiles reports whether dir contains any files with names ending in .go. // For a vendor check we must exclude directories that contain no .go files. // Otherwise it is not possible to vendor just a/b/c and still import the @@ -1082,7 +1271,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { if path == "C" { continue } - p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], UseVendor) + p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport) if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil { p.Error = &PackageError{ ImportStack: stk.Copy(), diff --git a/src/cmd/go/internal/load/search.go b/src/cmd/go/internal/load/search.go index 595de07904..6494f8e569 100644 --- a/src/cmd/go/internal/load/search.go +++ b/src/cmd/go/internal/load/search.go @@ -13,6 +13,7 @@ import ( "path" "path/filepath" "regexp" + "runtime" "strings" ) @@ -282,7 +283,12 @@ func MatchPackage(pattern, cwd string) func(*Package) bool { } dir = filepath.Join(cwd, dir) if pattern == "" { - return func(p *Package) bool { return p.Dir == dir } + return func(p *Package) bool { + if runtime.GOOS != "windows" { + return p.Dir == dir + } + return strings.EqualFold(p.Dir, dir) + } } matchPath := matchPattern(pattern) return func(p *Package) bool { diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index a9b47ce72d..0a13dfc1b7 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -49,16 +49,13 @@ type TestCover struct { // (for example, if there are no "package p" test files and // package p need not be instrumented for coverage or any other reason), // then the returned ptest == p. -// -// The caller is expected to have checked that len(p.TestGoFiles)+len(p.XTestGoFiles) > 0, -// or else there's no point in any of this. func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) { var imports, ximports []*Package var stk ImportStack stk.Push(p.ImportPath + " (test)") rawTestImports := str.StringList(p.TestImports) for i, path := range p.TestImports { - p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], UseVendor) + p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport) if p1.Error != nil { return nil, nil, nil, p1.Error } @@ -86,7 +83,7 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag pxtestNeedsPtest := false rawXTestImports := str.StringList(p.XTestImports) for i, path := range p.XTestImports { - p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], UseVendor) + p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport) if p1.Error != nil { return nil, nil, nil, p1.Error } diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index bcff5ff3b1..aff5ff2c9d 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -600,10 +600,10 @@ func runTest(cmd *base.Command, args []string) { for _, path := range p.Imports { deps[path] = true } - for _, path := range p.Vendored(p.TestImports) { + for _, path := range p.Resolve(p.TestImports) { deps[path] = true } - for _, path := range p.Vendored(p.XTestImports) { + for _, path := range p.Resolve(p.XTestImports) { deps[path] = true } } @@ -781,14 +781,6 @@ var windowsBadWords = []string{ } func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, printAction *work.Action, err error) { - if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { - build := b.CompileAction(work.ModeBuild, work.ModeBuild, p) - run := &work.Action{Mode: "test run", Package: p, Deps: []*work.Action{build}} - addTestVet(b, p, run, nil) - print := &work.Action{Mode: "test print", Func: builderNoTest, Package: p, Deps: []*work.Action{run}} - return build, run, print, nil - } - // Build Package structs describing: // pmain - pkg.test binary // ptest - package + test files @@ -1176,13 +1168,17 @@ func (c *runCache) builderRunTest(b *work.Builder, a *work.Action) error { if err == nil { norun := "" + res := "ok" if !testShowPass && !testJSON { buf.Reset() } - if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { + if len(a.Package.TestGoFiles)+len(a.Package.XTestGoFiles) == 0 { + res = "? " + norun = " [no test files]" + } else if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { norun = " [no tests to run]" } - fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun) + fmt.Fprintf(cmd.Stdout, "%s \t%s\t%s%s%s\n", res, a.Package.ImportPath, t, coveragePercentage(out), norun) c.saveOutput(a) } else { base.SetExitStatus(1) @@ -1596,15 +1592,3 @@ func builderPrintTest(b *work.Builder, a *work.Action) error { } return nil } - -// builderNoTest is the action for testing a package with no test files. -func builderNoTest(b *work.Builder, a *work.Action) error { - var stdout io.Writer = os.Stdout - if testJSON { - json := test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp) - defer json.Close() - stdout = json - } - fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", a.Package.ImportPath) - return nil -} diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go index c83fe4e58d..3b5c4d65fd 100644 --- a/src/cmd/go/internal/work/action.go +++ b/src/cmd/go/internal/work/action.go @@ -36,7 +36,10 @@ type Builder struct { flagCache map[[2]string]bool // a cache of supported compiler flags Print func(args ...interface{}) (int, error) - ComputeStaleOnly bool // compute staleness for go list; no actual build + IsCmdList bool // running as part of go list; set p.Stale and additional fields below + NeedError bool // list needs p.Error + NeedExport bool // list needs p.Export + NeedCgoFiles bool // list needs p.CgoFiles to cgo-generated files, not originals objdirSeq int // counter for NewObjdir pkgSeq int diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index e5f0e624c3..5cb0c2431f 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -284,11 +284,6 @@ func runBuild(cmd *base.Command, args []string) { cfg.BuildO += cfg.ExeSuffix } - // Special case -o /dev/null by not writing at all. - if cfg.BuildO == os.DevNull { - cfg.BuildO = "" - } - // sanity check some often mis-used options switch cfg.BuildContext.Compiler { case "gccgo": @@ -311,6 +306,11 @@ func runBuild(cmd *base.Command, args []string) { pkgs = pkgsFilter(load.Packages(args)) + // Special case -o /dev/null by not writing at all. + if cfg.BuildO == os.DevNull { + cfg.BuildO = "" + } + if cfg.BuildO != "" { if len(pkgs) > 1 { base.Fatalf("go build: cannot use -o with multiple packages") diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index 94a06ff68f..f1c538c309 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -414,7 +414,7 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID // already up-to-date, then to avoid a rebuild, report the package // as up-to-date as well. See "Build IDs" comment above. // TODO(rsc): Rewrite this code to use a TryCache func on the link action. - if target != "" && !cfg.BuildA && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" { + if target != "" && !cfg.BuildA && !b.NeedExport && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" { buildID, err := buildid.ReadFile(target) if err == nil { id := strings.Split(buildID, buildIDSeparator) @@ -455,8 +455,8 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID return true } - if b.ComputeStaleOnly { - // Invoked during go list only to compute and record staleness. + if b.IsCmdList { + // Invoked during go list to compute and record staleness. if p := a.Package; p != nil && !p.Stale { p.Stale = true if cfg.BuildA { @@ -521,10 +521,6 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID a.output = []byte{} } - if b.ComputeStaleOnly { - return true - } - return false } @@ -609,11 +605,17 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error { panic("internal error: a.output not set") } outputID, _, err := c.Put(a.actionID, r) + r.Close() if err == nil && cfg.BuildX { b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cp", target, c.OutputFile(outputID)))) } + if b.NeedExport { + if err != nil { + return err + } + a.Package.Export = c.OutputFile(outputID) + } c.PutBytes(cache.Subkey(a.actionID, "stdout"), a.output) - r.Close() } } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 072e2904c1..5fd2f66b86 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -54,7 +54,7 @@ func actionList(root *Action) []*Action { // do runs the action graph rooted at root. func (b *Builder) Do(root *Action) { - if c := cache.Default(); c != nil && !b.ComputeStaleOnly { + if c := cache.Default(); c != nil && !b.IsCmdList { // If we're doing real work, take time at the end to trim the cache. defer c.Trim() } @@ -296,11 +296,11 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { return h.Sum() } -// needCgoHeader reports whether the actions triggered by this one +// needCgoHdr reports whether the actions triggered by this one // expect to be able to access the cgo-generated header file. -func needCgoHeader(a *Action) bool { +func (b *Builder) needCgoHdr(a *Action) bool { // If this build triggers a header install, run cgo to get the header. - if (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { + if !b.IsCmdList && (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { for _, t1 := range a.triggers { if t1.Mode == "install header" { return true @@ -317,19 +317,54 @@ func needCgoHeader(a *Action) bool { return false } +const ( + needBuild uint32 = 1 << iota + needCgoHdr + needVet + needCgoFiles + needStale +) + // build is the action for building a single package. // Note that any new influence on this logic must be reported in b.buildActionID above as well. func (b *Builder) build(a *Action) (err error) { p := a.Package + + bit := func(x uint32, b bool) uint32 { + if b { + return x + } + return 0 + } + cached := false - needCgo := needCgoHeader(a) + need := bit(needBuild, !b.IsCmdList || b.NeedExport) | + bit(needCgoHdr, b.needCgoHdr(a)) | + bit(needVet, a.needVet) | + bit(needCgoFiles, b.NeedCgoFiles && (p.UsesCgo() || p.UsesSwig())) + + // Save p.CgoFiles now, because we may modify it for go list. + cgofiles := append([]string{}, p.CgoFiles...) if !p.BinaryOnly { if b.useCache(a, p, b.buildActionID(a), p.Target) { - if b.ComputeStaleOnly || !needCgo && !a.needVet { - return nil + // We found the main output in the cache. + // If we don't need any other outputs, we can stop. + need &^= needBuild + if b.NeedExport { + p.Export = a.built } + if need&needCgoFiles != 0 && b.loadCachedCgoFiles(a) { + need &^= needCgoFiles + } + // Otherwise, we need to write files to a.Objdir (needVet, needCgoHdr). + // Remember that we might have them in cache + // and check again after we create a.Objdir. cached = true + a.output = []byte{} // start saving output in case we miss any cache results + } + if need == 0 { + return nil } defer b.flushOutput(a) } @@ -338,6 +373,9 @@ func (b *Builder) build(a *Action) (err error) { if err != nil && err != errPrintedOutput { err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err) } + if err != nil && b.IsCmdList && b.NeedError && p.Error == nil { + p.Error = &load.PackageError{Err: err.Error()} + } }() if cfg.BuildN { // In -n mode, print a banner between packages. @@ -357,14 +395,17 @@ func (b *Builder) build(a *Action) (err error) { if err == nil { a.built = a.Package.Target a.Target = a.Package.Target + if b.NeedExport { + a.Package.Export = a.Package.Target + } a.buildID = b.fileHash(a.Package.Target) a.Package.Stale = false a.Package.StaleReason = "binary-only package" return nil } - if b.ComputeStaleOnly { - a.Package.Stale = true - a.Package.StaleReason = "missing or invalid binary-only package" + a.Package.Stale = true + a.Package.StaleReason = "missing or invalid binary-only package" + if b.IsCmdList { return nil } return fmt.Errorf("missing or invalid binary-only package") @@ -375,8 +416,21 @@ func (b *Builder) build(a *Action) (err error) { } objdir := a.Objdir - if cached && (!needCgo || b.loadCachedCgo(a)) && (!a.needVet || b.loadCachedVet(a)) { - return nil + if cached { + if need&needCgoHdr != 0 && b.loadCachedCgoHdr(a) { + need &^= needCgoHdr + } + + // Load cached vet config, but only if that's all we have left + // (need == needVet, not testing just the one bit). + // If we are going to do a full build anyway, + // we're going to regenerate the files below anyway. + if need == needVet && b.loadCachedVet(a) { + need &^= needVet + } + if need == 0 { + return nil + } } // make target directory @@ -387,9 +441,8 @@ func (b *Builder) build(a *Action) (err error) { } } - var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string + var gofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string gofiles = append(gofiles, a.Package.GoFiles...) - cgofiles = append(cgofiles, a.Package.CgoFiles...) cfiles = append(cfiles, a.Package.CFiles...) sfiles = append(sfiles, a.Package.SFiles...) cxxfiles = append(cxxfiles, a.Package.CXXFiles...) @@ -500,19 +553,27 @@ func (b *Builder) build(a *Action) (err error) { } b.cacheGofiles(a, gofiles) + // Running cgo generated the cgo header. + need &^= needCgoHdr + // Sanity check only, since Package.load already checked as well. if len(gofiles) == 0 { return &load.NoGoError{Package: a.Package} } // Prepare Go vet config if needed. - if a.needVet { + if need&needVet != 0 { buildVetConfig(a, gofiles) + need &^= needVet } - if cached { - // The cached package file is OK, so we don't need to run the compile. - // We've only gone this far in order to prepare the vet configuration - // or cgo header, and now we have. + if need&needCgoFiles != 0 { + if !b.loadCachedCgoFiles(a) { + return fmt.Errorf("failed to cache translated CgoFiles") + } + need &^= needCgoFiles + } + if need == 0 { + // Nothing left to do. return nil } @@ -656,17 +717,25 @@ func (b *Builder) cacheObjdirFile(a *Action, c *cache.Cache, name string) error return err } -func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error { +func (b *Builder) findCachedObjdirFile(a *Action, c *cache.Cache, name string) (string, error) { entry, err := c.Get(cache.Subkey(a.actionID, name)) if err != nil { - return err + return "", err } out := c.OutputFile(entry.OutputID) info, err := os.Stat(out) if err != nil || info.Size() != entry.Size { - return fmt.Errorf("not in cache") + return "", fmt.Errorf("not in cache") } - return b.copyFile(a.Objdir+name, out, 0666, true) + return out, nil +} + +func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error { + cached, err := b.findCachedObjdirFile(a, c, name) + if err != nil { + return err + } + return b.copyFile(a.Objdir+name, cached, 0666, true) } func (b *Builder) cacheCgoHdr(a *Action) { @@ -677,7 +746,7 @@ func (b *Builder) cacheCgoHdr(a *Action) { b.cacheObjdirFile(a, c, "_cgo_install.h") } -func (b *Builder) loadCachedCgo(a *Action) bool { +func (b *Builder) loadCachedCgoHdr(a *Action) bool { c := cache.Default() if c == nil { return false @@ -737,6 +806,33 @@ func (b *Builder) loadCachedVet(a *Action) bool { return true } +func (b *Builder) loadCachedCgoFiles(a *Action) bool { + c := cache.Default() + if c == nil { + return false + } + list, _, err := c.GetBytes(cache.Subkey(a.actionID, "gofiles")) + if err != nil { + return false + } + var files []string + for _, name := range strings.Split(string(list), "\n") { + if name == "" { // end of list + continue + } + if strings.HasPrefix(name, "./") { + continue + } + file, err := b.findCachedObjdirFile(a, c, name) + if err != nil { + return false + } + files = append(files, file) + } + a.Package.CgoFiles = files + return true +} + type vetConfig struct { Compiler string Dir string @@ -939,7 +1035,7 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) { // link is the action for linking a single command. // Note that any new influence on this logic must be reported in b.linkActionID above as well. func (b *Builder) link(a *Action) (err error) { - if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) { + if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) || b.IsCmdList { return nil } defer b.flushOutput(a) @@ -1172,7 +1268,7 @@ func (b *Builder) linkSharedActionID(a *Action) cache.ActionID { } func (b *Builder) linkShared(a *Action) (err error) { - if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) { + if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) || b.IsCmdList { return nil } defer b.flushOutput(a) @@ -1236,13 +1332,17 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) { // We want to hide that awful detail as much as possible, so don't // advertise it by touching the mtimes (usually the libraries are up // to date). - if !a.buggyInstall && !b.ComputeStaleOnly { + if !a.buggyInstall && !b.IsCmdList { now := time.Now() os.Chtimes(a.Target, now, now) } return nil } - if b.ComputeStaleOnly { + + // If we're building for go list -export, + // never install anything; just keep the cache reference. + if b.IsCmdList { + a.built = a1.built return nil } @@ -1468,6 +1568,7 @@ var objectMagic = [][]byte{ {0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386 {0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64 {0x00, 0x00, 0x06, 0x47}, // Plan 9 arm + {0x00, 0x61, 0x73, 0x6D}, // WASM } func isObject(s string) bool { diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index 5c67aa945e..cd39a8f791 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -41,43 +41,57 @@ var re = regexp.MustCompile var validCompilerFlags = []*regexp.Regexp{ re(`-D([A-Za-z_].*)`), + re(`-F([^@\-].*)`), re(`-I([^@\-].*)`), re(`-O`), re(`-O([^@\-].*)`), re(`-W`), re(`-W([^@,]+)`), // -Wall but not -Wa,-foo. re(`-Wa,-mbig-obj`), + re(`-Wp,-D([A-Za-z_].*)`), re(`-ansi`), + re(`-f(no-)?asynchronous-unwind-tables`), re(`-f(no-)?blocks`), + re(`-f(no-)builtin-[a-zA-Z0-9_]*`), re(`-f(no-)?common`), re(`-f(no-)?constant-cfstrings`), re(`-fdiagnostics-show-note-include-stack`), + re(`-f(no-)?eliminate-unused-debug-types`), re(`-f(no-)?exceptions`), + re(`-f(no-)?fast-math`), re(`-f(no-)?inline-functions`), re(`-finput-charset=([^@\-].*)`), re(`-f(no-)?fat-lto-objects`), + re(`-f(no-)?keep-inline-dllexport`), re(`-f(no-)?lto`), re(`-fmacro-backtrace-limit=(.+)`), re(`-fmessage-length=(.+)`), re(`-f(no-)?modules`), re(`-f(no-)?objc-arc`), + re(`-f(no-)?objc-nonfragile-abi`), + re(`-f(no-)?objc-legacy-dispatch`), re(`-f(no-)?omit-frame-pointer`), re(`-f(no-)?openmp(-simd)?`), re(`-f(no-)?permissive`), re(`-f(no-)?(pic|PIC|pie|PIE)`), + re(`-f(no-)?plt`), re(`-f(no-)?rtti`), re(`-f(no-)?split-stack`), re(`-f(no-)?stack-(.+)`), re(`-f(no-)?strict-aliasing`), re(`-f(un)signed-char`), re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B + re(`-f(no-)?visibility-inlines-hidden`), re(`-fsanitize=(.+)`), re(`-ftemplate-depth-(.+)`), re(`-fvisibility=(.+)`), re(`-g([^@\-].*)?`), re(`-m32`), re(`-m64`), - re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-marm`), + re(`-mfloat-abi=([^@\-].*)`), + re(`-mfpmath=[0-9a-z,+]*`), re(`-m(no-)?avx[0-9a-z.]*`), re(`-m(no-)?ms-bitfields`), re(`-m(no-)?stack-(.+)`), @@ -86,14 +100,19 @@ var validCompilerFlags = []*regexp.Regexp{ re(`-miphoneos-version-min=(.+)`), re(`-mnop-fun-dllimport`), re(`-m(no-)?sse[0-9.]*`), + re(`-mthumb(-interwork)?`), + re(`-mthreads`), re(`-mwindows`), + re(`--param=ssp-buffer-size=[0-9]*`), re(`-pedantic(-errors)?`), re(`-pipe`), re(`-pthread`), re(`-?-std=([^@\-].*)`), re(`-?-stdlib=([^@\-].*)`), + re(`--sysroot=([^@\-].*)`), re(`-w`), re(`-x([^@\-].*)`), + re(`-v`), } var validCompilerFlagsWithNextArg = []string{ @@ -115,18 +134,24 @@ var validLinkerFlags = []*regexp.Regexp{ re(`-O`), re(`-O([^@\-].*)`), re(`-f(no-)?(pic|PIC|pie|PIE)`), + re(`-f(no-)?openmp(-simd)?`), re(`-fsanitize=([^@\-].*)`), re(`-g([^@\-].*)?`), - re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-headerpad_max_install_names`), + re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-mfloat-abi=([^@\-].*)`), re(`-mmacosx-(.+)`), re(`-mios-simulator-version-min=(.+)`), re(`-miphoneos-version-min=(.+)`), + re(`-mthreads`), re(`-mwindows`), re(`-(pic|PIC|pie|PIE)`), re(`-pthread`), + re(`-rdynamic`), re(`-shared`), re(`-?-static([-a-z0-9+]*)`), re(`-?-stdlib=([^@\-].*)`), + re(`-v`), // Note that any wildcards in -Wl need to exclude comma, // since -Wl splits its argument at commas and passes @@ -134,22 +159,27 @@ var validLinkerFlags = []*regexp.Regexp{ // in a wildcard would allow tunnelling arbitrary additional // linker arguments through one of these. re(`-Wl,--(no-)?allow-multiple-definition`), + re(`-Wl,--(no-)?allow-shlib-undefined`), re(`-Wl,--(no-)?as-needed`), re(`-Wl,-Bdynamic`), re(`-Wl,-Bstatic`), + re(`-WL,-O([^@,\-][^,]*)?`), re(`-Wl,-d[ny]`), re(`-Wl,--disable-new-dtags`), + re(`-Wl,-e[=,][a-zA-Z0-9]*`), re(`-Wl,--enable-new-dtags`), re(`-Wl,--end-group`), re(`-Wl,-framework,[^,@\-][^,]+`), re(`-Wl,-headerpad_max_install_names`), re(`-Wl,--no-undefined`), - re(`-Wl,-rpath[=,]([^,@\-][^,]+)`), + re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`), + re(`-Wl,-s`), re(`-Wl,-search_paths_first`), re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`), re(`-Wl,--start-group`), re(`-Wl,-?-static`), - re(`-Wl,--subsystem,(native|windows|console|posix|xbox)`), + re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`), + re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`), re(`-Wl,-undefined[=,]([^,@\-][^,]+)`), re(`-Wl,-?-unresolved-symbols=[^,]+`), re(`-Wl,--(no-)?warn-([^,]+)`), @@ -157,6 +187,7 @@ var validLinkerFlags = []*regexp.Regexp{ re(`-Wl,-z,relro`), re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o) + re(`\./.*\.(a|o|obj|dll|dylib|so)`), } var validLinkerFlagsWithNextArg = []string{ diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index bd898c9de6..d23b6eadff 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -12,6 +12,7 @@ import ( var goodCompilerFlags = [][]string{ {"-DFOO"}, {"-Dfoo=bar"}, + {"-F/Qt"}, {"-I/"}, {"-I/etc/passwd"}, {"-I."}, @@ -57,11 +58,14 @@ var goodCompilerFlags = [][]string{ {"-I", "世界"}, {"-framework", "Chocolate"}, {"-x", "c"}, + {"-v"}, } var badCompilerFlags = [][]string{ {"-D@X"}, {"-D-X"}, + {"-F@dir"}, + {"-F-dir"}, {"-I@dir"}, {"-I-dir"}, {"-O@1"}, @@ -125,6 +129,7 @@ var goodLinkerFlags = [][]string{ {"-Wl,--no-warn-error"}, {"foo.so"}, {"_世界.dll"}, + {"./x.o"}, {"libcgosotest.dylib"}, {"-F", "framework"}, {"-l", "."}, @@ -132,6 +137,7 @@ var goodLinkerFlags = [][]string{ {"-l", "世界"}, {"-L", "framework"}, {"-framework", "Chocolate"}, + {"-v"}, {"-Wl,-framework", "-Wl,Chocolate"}, {"-Wl,-framework,Chocolate"}, {"-Wl,-unresolved-symbols=ignore-all"}, @@ -191,6 +197,7 @@ var badLinkerFlags = [][]string{ {"-x", "--c"}, {"-x", "@obj"}, {"-Wl,-rpath,@foo"}, + {"../x.o"}, } func TestCheckLinkerFlags(t *testing.T) { diff --git a/src/cmd/go/testdata/modlegacy/src/new/go.mod b/src/cmd/go/testdata/modlegacy/src/new/go.mod new file mode 100644 index 0000000000..d0dd46d314 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/go.mod @@ -0,0 +1 @@ +module "new/v2" diff --git a/src/cmd/go/testdata/modlegacy/src/new/new.go b/src/cmd/go/testdata/modlegacy/src/new/new.go new file mode 100644 index 0000000000..e99c47a6a8 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/new.go @@ -0,0 +1,3 @@ +package new + +import _ "new/v2/p2" diff --git a/src/cmd/go/testdata/modlegacy/src/new/p1/p1.go b/src/cmd/go/testdata/modlegacy/src/new/p1/p1.go new file mode 100644 index 0000000000..4539f40919 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/p1/p1.go @@ -0,0 +1,7 @@ +package p1 + +import _ "old/p2" +import _ "new/v2" +import _ "new/v2/p2" +import _ "new/sub/v2/x/v1/y" // v2 is module, v1 is directory in module +import _ "new/sub/inner/x" // new/sub/inner/go.mod overrides new/sub/go.mod diff --git a/src/cmd/go/testdata/modlegacy/src/new/p2/p2.go b/src/cmd/go/testdata/modlegacy/src/new/p2/p2.go new file mode 100644 index 0000000000..9b9052f541 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/p2/p2.go @@ -0,0 +1 @@ +package p2 diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/go.mod b/src/cmd/go/testdata/modlegacy/src/new/sub/go.mod new file mode 100644 index 0000000000..484d20c6b2 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/go.mod @@ -0,0 +1 @@ +module new/sub/v2 diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod new file mode 100644 index 0000000000..ba3934541f --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod @@ -0,0 +1 @@ +module new/sub/inner diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go new file mode 100644 index 0000000000..823aafd071 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go @@ -0,0 +1 @@ +package x diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go b/src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go new file mode 100644 index 0000000000..789ca715ec --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go @@ -0,0 +1 @@ +package y diff --git a/src/cmd/go/testdata/modlegacy/src/old/p1/p1.go b/src/cmd/go/testdata/modlegacy/src/old/p1/p1.go new file mode 100644 index 0000000000..90527483ab --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/old/p1/p1.go @@ -0,0 +1,5 @@ +package p1 + +import _ "old/p2" +import _ "new/p1" +import _ "new" diff --git a/src/cmd/go/testdata/modlegacy/src/old/p2/p2.go b/src/cmd/go/testdata/modlegacy/src/old/p2/p2.go new file mode 100644 index 0000000000..9b9052f541 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/old/p2/p2.go @@ -0,0 +1 @@ +package p2 diff --git a/src/cmd/go/testdata/testcover/pkg1/a.go b/src/cmd/go/testdata/testcover/pkg1/a.go new file mode 100644 index 0000000000..e2916119d4 --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg1/a.go @@ -0,0 +1,7 @@ +package pkg1 + +import "fmt" + +func F() { + fmt.Println("pkg1") +} diff --git a/src/cmd/go/testdata/testcover/pkg2/a.go b/src/cmd/go/testdata/testcover/pkg2/a.go new file mode 100644 index 0000000000..7bd9bd44ee --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg2/a.go @@ -0,0 +1,7 @@ +package pkg2 + +import "fmt" + +func F() { + fmt.Println("pkg2") +} diff --git a/src/cmd/go/testdata/testcover/pkg2/a_test.go b/src/cmd/go/testdata/testcover/pkg2/a_test.go new file mode 100644 index 0000000000..4f791ad6ab --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg2/a_test.go @@ -0,0 +1 @@ +package pkg2 diff --git a/src/cmd/go/testdata/testcover/pkg3/a.go b/src/cmd/go/testdata/testcover/pkg3/a.go new file mode 100644 index 0000000000..bf86ed8dc0 --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg3/a.go @@ -0,0 +1,7 @@ +package pkg3 + +import "fmt" + +func F() { + fmt.Println("pkg3") +} diff --git a/src/cmd/go/testdata/testcover/pkg3/a_test.go b/src/cmd/go/testdata/testcover/pkg3/a_test.go new file mode 100644 index 0000000000..39c2c5a6fc --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg3/a_test.go @@ -0,0 +1,7 @@ +package pkg3 + +import "testing" + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/vendor_test.go b/src/cmd/go/vendor_test.go index 4f21a510a3..0e7a633240 100644 --- a/src/cmd/go/vendor_test.go +++ b/src/cmd/go/vendor_test.go @@ -10,6 +10,7 @@ import ( "bytes" "fmt" "internal/testenv" + "os" "path/filepath" "regexp" "strings" @@ -328,3 +329,75 @@ func TestVendor12156(t *testing.T) { tg.grepStderrNot("panic", "panicked") tg.grepStderr(`cannot find package "x"`, "wrong error") } + +// Module legacy support does path rewriting very similar to vendoring. + +func TestModLegacy(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/modlegacy")) + tg.run("list", "-f", "{{.Imports}}", "old/p1") + tg.grepStdout("new/p1", "old/p1 should import new/p1") + tg.run("list", "-f", "{{.Imports}}", "new/p1") + tg.grepStdout("new/p2", "new/p1 should import new/p2 (not new/v2/p2)") + tg.grepStdoutNot("new/v2", "new/p1 should NOT import new/v2*") + tg.grepStdout("new/sub/x/v1/y", "new/p1 should import new/sub/x/v1/y (not new/sub/v2/x/v1/y)") + tg.grepStdoutNot("new/sub/v2", "new/p1 should NOT import new/sub/v2*") + tg.grepStdout("new/sub/inner/x", "new/p1 should import new/sub/inner/x (no rewrites)") + tg.run("build", "old/p1", "new/p1") +} + +func TestModLegacyGet(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path("d1")) + tg.run("get", "vcs-test.golang.org/git/modlegacy1-old.git/p1") + tg.run("list", "-f", "{{.Deps}}", "vcs-test.golang.org/git/modlegacy1-old.git/p1") + tg.grepStdout("new.git/p2", "old/p1 should depend on new/p2") + tg.grepStdoutNot("new.git/v2/p2", "old/p1 should NOT depend on new/v2/p2") + tg.run("build", "vcs-test.golang.org/git/modlegacy1-old.git/p1", "vcs-test.golang.org/git/modlegacy1-new.git/p1") + + tg.setenv("GOPATH", tg.path("d2")) + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/rsc/vgotest5") + tg.run("get", "github.com/rsc/vgotest4") + tg.run("get", "github.com/myitcv/vgo_example_compat") + + if testing.Short() { + return + } + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/rsc/vgotest4") + tg.run("get", "github.com/rsc/vgotest5") + tg.run("get", "github.com/myitcv/vgo_example_compat") + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5") + tg.run("get", "github.com/myitcv/vgo_example_compat") + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/rsc/vgotest5", "github.com/rsc/vgotest4") + tg.run("get", "github.com/myitcv/vgo_example_compat") + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/myitcv/vgo_example_compat") + tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5") + + pkgs := []string{"github.com/myitcv/vgo_example_compat", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5"} + for i := 0; i < 3; i++ { + for j := 0; j < 3; j++ { + for k := 0; k < 3; k++ { + if i == j || i == k || k == j { + continue + } + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", pkgs[i], pkgs[j], pkgs[k]) + } + } + } +} diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index bf96bb58a6..e727143757 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -245,12 +245,12 @@ var optab = []Optab{ {AANDS, C_BITCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0}, {AANDS, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0}, {ATST, C_BITCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0}, - {AAND, C_MOVCON, C_REG, C_NONE, C_RSP, 62, 8, 0, 0, 0}, + {AAND, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0}, {AAND, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0}, {AANDS, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0}, {AANDS, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0}, {ATST, C_MOVCON, C_REG, C_NONE, C_NONE, 62, 8, 0, 0, 0}, - {AAND, C_VCON, C_REG, C_NONE, C_RSP, 28, 8, 0, LFROM, 0}, + {AAND, C_VCON, C_REG, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, {AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, {AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, {AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, @@ -3548,7 +3548,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { if r == 0 { r = rt } - if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) { + if p.To.Reg == REGSP || r == REGSP { o2 = c.opxrrr(p, p.As, false) o2 |= REGTMP & 31 << 16 o2 |= LSL0_64 diff --git a/src/cmd/internal/obj/s390x/a.out.go b/src/cmd/internal/obj/s390x/a.out.go index ec959c4090..babcd2af01 100644 --- a/src/cmd/internal/obj/s390x/a.out.go +++ b/src/cmd/internal/obj/s390x/a.out.go @@ -150,7 +150,7 @@ const ( ) // LINUX for zSeries ELF Application Binary Interface Supplement -// http://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_zSeries/x1472.html +// https://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_zSeries/x1472.html var S390XDWARFRegisters = map[int16]int16{} func init() { diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go index b3dbaa39eb..2cd3a94045 100644 --- a/src/cmd/internal/objabi/reloctype_string.go +++ b/src/cmd/internal/objabi/reloctype_string.go @@ -4,9 +4,9 @@ package objabi import "strconv" -const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFF" +const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORT" -var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 323, 337, 348, 362, 377, 394, 412, 433, 443, 454, 467, 478} +var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 323, 337, 348, 362, 377, 394, 412, 433, 443, 454, 467, 478, 490} func (i RelocType) String() string { i -= 1 diff --git a/src/cmd/internal/test2json/test2json.go b/src/cmd/internal/test2json/test2json.go index f8052136be..1a54a1c3bb 100644 --- a/src/cmd/internal/test2json/test2json.go +++ b/src/cmd/internal/test2json/test2json.go @@ -147,7 +147,7 @@ var ( fourSpace = []byte(" ") skipLinePrefix = []byte("? \t") - skipLineSuffix = []byte("\t[no test files]\n") + skipLineSuffix = []byte(" [no test files]\n") ) // handleInputLine handles a single whole test output line. @@ -166,7 +166,7 @@ func (c *converter) handleInputLine(line []byte) { return } - // Special case for entirely skipped test binary: "? \tpkgname\t[no test files]\n" is only line. + // Special case for entirely skipped test binary: "? \tpkgname\t0.001s [no test files]\n" is only line. // Report it as plain output but remember to say skip in the final summary. if bytes.HasPrefix(line, skipLinePrefix) && bytes.HasSuffix(line, skipLineSuffix) && len(c.report) == 0 { c.result = "skip" diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index 6897ae21fe..af274444f3 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -617,7 +617,7 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { // so for now we'll just use non-lazy pointers, // which don't need to be told which library to use. // - // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html + // https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html // has details about what we're avoiding. addgotsym(ctxt, s) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 6cc5c544f5..be65b7be06 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -95,7 +95,7 @@ func trampoline(ctxt *Link, s *sym.Symbol) { if Symaddr(r.Sym) == 0 && r.Sym.Type != sym.SDYNIMPORT { if r.Sym.File != s.File { if !isRuntimeDepPkg(s.File) || !isRuntimeDepPkg(r.Sym.File) { - Errorf(s, "unresolved inter-package jump to %s(%s)", r.Sym, r.Sym.File) + ctxt.ErrorUnresolved(s, r) } // runtime and its dependent packages may call to each other. // they are fine, as they will be laid down together. @@ -128,7 +128,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) { continue } - if r.Sym != nil && ((r.Sym.Type == 0 && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) { + if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) { // When putting the runtime but not main into a shared library // these symbols are undefined and that's OK. if ctxt.BuildMode == BuildModeShared { @@ -140,7 +140,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) { continue } } else { - Errorf(s, "relocation target %s not defined", r.Sym.Name) + ctxt.ErrorUnresolved(s, r) continue } } diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go new file mode 100644 index 0000000000..4884a07d05 --- /dev/null +++ b/src/cmd/link/internal/ld/ld_test.go @@ -0,0 +1,70 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ld + +import ( + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "strings" + "testing" +) + +func TestUndefinedRelocErrors(t *testing.T) { + testenv.MustHaveGoBuild(t) + dir, err := ioutil.TempDir("", "go-build") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + out, err := exec.Command(testenv.GoToolPath(t), "build", "./testdata/issue10978").CombinedOutput() + if err == nil { + t.Fatal("expected build to fail") + } + + wantErrors := map[string]int{ + // Main function has dedicated error message. + "function main is undeclared in the main package": 1, + + // Single error reporting per each symbol. + // This way, duplicated messages are not reported for + // multiple relocations with a same name. + "main.defined1: relocation target main.undefined not defined": 1, + "main.defined2: relocation target main.undefined not defined": 1, + } + unexpectedErrors := map[string]int{} + + for _, l := range strings.Split(string(out), "\n") { + if strings.HasPrefix(l, "#") || l == "" { + continue + } + matched := "" + for want := range wantErrors { + if strings.Contains(l, want) { + matched = want + break + } + } + if matched != "" { + wantErrors[matched]-- + } else { + unexpectedErrors[l]++ + } + } + + for want, n := range wantErrors { + switch { + case n > 0: + t.Errorf("unmatched error: %s (x%d)", want, n) + case n < 0: + t.Errorf("extra errors: %s (x%d)", want, -n) + } + } + for unexpected, n := range unexpectedErrors { + t.Errorf("unexpected error: %s (x%d)", unexpected, n) + } +} diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 3278ea4e98..0d18a9fe1e 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1963,7 +1963,7 @@ func usage() { type SymbolType int8 const ( - // see also http://9p.io/magic/man2html/1/nm + // see also https://9p.io/magic/man2html/1/nm TextSym SymbolType = 'T' DataSym SymbolType = 'D' BSSSym SymbolType = 'B' @@ -2200,6 +2200,18 @@ func undefsym(ctxt *Link, s *sym.Symbol) { } func (ctxt *Link) undef() { + // undefsym performs checks (almost) identical to checks + // that report undefined relocations in relocsym. + // Both undefsym and relocsym can report same symbol as undefined, + // which results in error message duplication (see #10978). + // + // The undef is run after Arch.Asmb and could detect some + // programming errors there, but if object being linked is already + // failed with errors, it is better to avoid duplicated errors. + if nerrors > 0 { + return + } + for _, s := range ctxt.Textp { undefsym(ctxt, s) } diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index a413353b9f..a790fd084b 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -81,6 +81,33 @@ type Link struct { PackageShlib map[string]string tramps []*sym.Symbol // trampolines + + // unresolvedSymSet is a set of erroneous unresolved references. + // Used to avoid duplicated error messages. + unresolvedSymSet map[unresolvedSymKey]bool +} + +type unresolvedSymKey struct { + from *sym.Symbol // Symbol that referenced unresolved "to" + to *sym.Symbol // Unresolved symbol referenced by "from" +} + +// ErrorUnresolved prints unresolved symbol error for r.Sym that is referenced from s. +func (ctxt *Link) ErrorUnresolved(s *sym.Symbol, r *sym.Reloc) { + if ctxt.unresolvedSymSet == nil { + ctxt.unresolvedSymSet = make(map[unresolvedSymKey]bool) + } + + k := unresolvedSymKey{from: s, to: r.Sym} + if !ctxt.unresolvedSymSet[k] { + ctxt.unresolvedSymSet[k] = true + // Give a special error message for main symbol (see #24809). + if r.Sym.Name == "main.main" { + Errorf(s, "function main is undeclared in the main package") + } else { + Errorf(s, "relocation target %s not defined", r.Sym.Name) + } + } } // The smallest possible offset from the hardware stack pointer to a local diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 8643fef043..d804dc83b3 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -142,12 +142,8 @@ const ( S_ATTR_SOME_INSTRUCTIONS = 0x00000400 ) -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - // Mach-O file writing -// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html +// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html var machohdr MachoHdr diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 66b1463086..8005dc5228 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -116,7 +116,7 @@ const ( // license that can be found in the LICENSE file. // PE (Portable Executable) file writing -// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx +// https://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx // DOS stub that prints out // "This program cannot be run in DOS mode." diff --git a/src/cmd/link/internal/ld/testdata/issue10978/main.go b/src/cmd/link/internal/ld/testdata/issue10978/main.go new file mode 100644 index 0000000000..5e8c09749f --- /dev/null +++ b/src/cmd/link/internal/ld/testdata/issue10978/main.go @@ -0,0 +1,27 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func undefined() + +func defined1() int { + // To check multiple errors for a single symbol, + // reference undefined more than once. + undefined() + undefined() + return 0 +} + +func defined2() { + undefined() + undefined() +} + +func init() { + _ = defined1() + defined2() +} + +// The "main" function remains undeclared. diff --git a/src/cmd/link/internal/ld/testdata/issue10978/main.s b/src/cmd/link/internal/ld/testdata/issue10978/main.s new file mode 100644 index 0000000000..1d00e76c1d --- /dev/null +++ b/src/cmd/link/internal/ld/testdata/issue10978/main.s @@ -0,0 +1 @@ +// This file is needed to make "go build" work for package with external functions. diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go index 7fb9a38a9f..301c2ce116 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -1048,7 +1048,7 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym // __i686.get_pc_thunk.bx is allowed to be duplicated, to // workaround that we set dupok. // TODO(minux): correctly handle __i686.get_pc_thunk.bx without - // set dupok generally. See http://codereview.appspot.com/5823055/ + // set dupok generally. See https://golang.org/cl/5823055 // comment #5 for details. if s != nil && elfsym.other == 2 { s.Attr |= sym.AttrDuplicateOK | sym.AttrVisibilityHidden diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go index 235a5a25d1..aadb0c3b6e 100644 --- a/src/cmd/link/internal/wasm/asm.go +++ b/src/cmd/link/internal/wasm/asm.go @@ -88,7 +88,7 @@ func assignAddress(ctxt *ld.Link, sect *sym.Section, n int, s *sym.Symbol, va ui } // asmb writes the final WebAssembly module binary. -// Spec: http://webassembly.github.io/spec/core/binary/modules.html +// Spec: https://webassembly.github.io/spec/core/binary/modules.html func asmb(ctxt *ld.Link) { if ctxt.Debugvlog != 0 { ctxt.Logf("%5.2f asmb\n", ld.Cputime()) diff --git a/src/cmd/pprof/readlineui.go b/src/cmd/pprof/readlineui.go index 67fb7aa49c..6e91816f9b 100644 --- a/src/cmd/pprof/readlineui.go +++ b/src/cmd/pprof/readlineui.go @@ -86,7 +86,7 @@ func (r *readlineUI) print(withColor bool, args ...interface{}) { if withColor { text = colorize(text) } - fmt.Fprintf(r.term, text) + fmt.Fprint(r.term, text) } // colorize prints the msg in red using ANSI color escapes. diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go index c3c22e7c96..a5153e1511 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go @@ -15,6 +15,7 @@ package driver import ( + "errors" "fmt" "os" "strings" @@ -28,6 +29,7 @@ type source struct { ExecName string BuildID string Base []string + DiffBase bool Normalize bool Seconds int @@ -43,7 +45,8 @@ type source struct { func parseFlags(o *plugin.Options) (*source, []string, error) { flag := o.Flagset // Comparisons. - flagBase := flag.StringList("base", "", "Source for base profile for comparison") + flagBase := flag.StringList("base", "", "Source for base profile for profile subtraction") + flagDiffBase := flag.StringList("diff_base", "", "Source for diff base profile for comparison") // Source options. flagSymbolize := flag.String("symbolize", "", "Options for profile symbolization") flagBuildID := flag.String("buildid", "", "Override build id for first mapping") @@ -85,7 +88,7 @@ func parseFlags(o *plugin.Options) (*source, []string, error) { usageMsgVars) }) if len(args) == 0 { - return nil, nil, fmt.Errorf("no profile source specified") + return nil, nil, errors.New("no profile source specified") } var execName string @@ -112,7 +115,7 @@ func parseFlags(o *plugin.Options) (*source, []string, error) { return nil, nil, err } if cmd != nil && *flagHTTP != "" { - return nil, nil, fmt.Errorf("-http is not compatible with an output format on the command line") + return nil, nil, errors.New("-http is not compatible with an output format on the command line") } si := pprofVariables["sample_index"].value @@ -140,15 +143,13 @@ func parseFlags(o *plugin.Options) (*source, []string, error) { Comment: *flagAddComment, } - for _, s := range *flagBase { - if *s != "" { - source.Base = append(source.Base, *s) - } + if err := source.addBaseProfiles(*flagBase, *flagDiffBase); err != nil { + return nil, nil, err } normalize := pprofVariables["normalize"].boolValue() if normalize && len(source.Base) == 0 { - return nil, nil, fmt.Errorf("Must have base profile to normalize by") + return nil, nil, errors.New("must have base profile to normalize by") } source.Normalize = normalize @@ -158,6 +159,34 @@ func parseFlags(o *plugin.Options) (*source, []string, error) { return source, cmd, nil } +// addBaseProfiles adds the list of base profiles or diff base profiles to +// the source. This function will return an error if both base and diff base +// profiles are specified. +func (source *source) addBaseProfiles(flagBase, flagDiffBase []*string) error { + base, diffBase := dropEmpty(flagBase), dropEmpty(flagDiffBase) + if len(base) > 0 && len(diffBase) > 0 { + return errors.New("-base and -diff_base flags cannot both be specified") + } + + source.Base = base + if len(diffBase) > 0 { + source.Base, source.DiffBase = diffBase, true + } + return nil +} + +// dropEmpty list takes a slice of string pointers, and outputs a slice of +// non-empty strings associated with the flag. +func dropEmpty(list []*string) []string { + var l []string + for _, s := range list { + if *s != "" { + l = append(l, *s) + } + } + return l +} + // installFlags creates command line flags for pprof variables. func installFlags(flag plugin.FlagSet) flagsInstalled { f := flagsInstalled{ @@ -240,7 +269,7 @@ func outputFormat(bcmd map[string]*bool, acmd map[string]*string) (cmd []string, for n, b := range bcmd { if *b { if cmd != nil { - return nil, fmt.Errorf("must set at most one output format") + return nil, errors.New("must set at most one output format") } cmd = []string{n} } @@ -248,7 +277,7 @@ func outputFormat(bcmd map[string]*bool, acmd map[string]*string) (cmd []string, for n, s := range acmd { if *s != "" { if cmd != nil { - return nil, fmt.Errorf("must set at most one output format") + return nil, errors.New("must set at most one output format") } cmd = []string{n, *s} } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go index acc0b4ad8a..2dabc3017b 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go @@ -65,7 +65,13 @@ func generateRawReport(p *profile.Profile, cmd []string, vars variables, o *plug // Identify units of numeric tags in profile. numLabelUnits := identifyNumLabelUnits(p, o.UI) - vars = applyCommandOverrides(cmd, vars) + // Get report output format + c := pprofCommands[cmd[0]] + if c == nil { + panic("unexpected nil command") + } + + vars = applyCommandOverrides(cmd[0], c.format, vars) // Delay focus after configuring report to get percentages on all samples. relative := vars["relative_percentages"].boolValue() @@ -78,10 +84,6 @@ func generateRawReport(p *profile.Profile, cmd []string, vars variables, o *plug if err != nil { return nil, nil, err } - c := pprofCommands[cmd[0]] - if c == nil { - panic("unexpected nil command") - } ropt.OutputFormat = c.format if len(cmd) == 2 { s, err := regexp.Compile(cmd[1]) @@ -149,13 +151,10 @@ func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin. return out.Close() } -func applyCommandOverrides(cmd []string, v variables) variables { +func applyCommandOverrides(cmd string, outputFormat int, v variables) variables { trim, tagfilter, filter := v["trim"].boolValue(), true, true - switch cmd[0] { - case "proto", "raw": - trim, tagfilter, filter = false, false, false - v.set("addresses", "t") + switch cmd { case "callgrind", "kcachegrind": trim = false v.set("addresses", "t") @@ -163,7 +162,7 @@ func applyCommandOverrides(cmd []string, v variables) variables { trim = false v.set("addressnoinlines", "t") case "peek": - trim, filter = false, false + trim, tagfilter, filter = false, false, false case "list": v.set("nodecount", "0") v.set("lines", "t") @@ -176,6 +175,12 @@ func applyCommandOverrides(cmd []string, v variables) variables { v.set("nodecount", "80") } } + + if outputFormat == report.Proto || outputFormat == report.Raw { + trim, tagfilter, filter = false, false, false + v.set("addresses", "t") + } + if !trim { v.set("nodecount", "0") v.set("nodefraction", "0") diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go index 309e9950b6..ff6afe9cff 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go @@ -288,7 +288,7 @@ type testFlags struct { floats map[string]float64 strings map[string]string args []string - stringLists map[string][]*string + stringLists map[string][]string } func (testFlags) ExtraUsage() string { return "" } @@ -355,7 +355,12 @@ func (f testFlags) StringVar(p *string, s, d, c string) { func (f testFlags) StringList(s, d, c string) *[]*string { if t, ok := f.stringLists[s]; ok { - return &t + // convert slice of strings to slice of string pointers before returning. + tp := make([]*string, len(t)) + for i, v := range t { + tp[i] = &v + } + return &tp } return &[]*string{} } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go index 7c576de614..7a7a1a20f2 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go @@ -63,6 +63,9 @@ func fetchProfiles(s *source, o *plugin.Options) (*profile.Profile, error) { } if pbase != nil { + if s.DiffBase { + pbase.SetLabel("pprof::base", []string{"true"}) + } if s.Normalize { err := p.Normalize(pbase) if err != nil { diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go index afb135b7cd..e67b2e9f87 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go @@ -210,13 +210,20 @@ func TestFetchWithBase(t *testing.T) { baseVars := pprofVariables defer func() { pprofVariables = baseVars }() + type WantSample struct { + values []int64 + labels map[string][]string + } + const path = "testdata/" type testcase struct { - desc string - sources []string - bases []string - normalize bool - expectedSamples [][]int64 + desc string + sources []string + bases []string + diffBases []string + normalize bool + wantSamples []WantSample + wantErrorMsg string } testcases := []testcase{ @@ -224,58 +231,216 @@ func TestFetchWithBase(t *testing.T) { "not normalized base is same as source", []string{path + "cppbench.contention"}, []string{path + "cppbench.contention"}, + nil, false, - [][]int64{}, + nil, + "", + }, + { + "not normalized base is same as source", + []string{path + "cppbench.contention"}, + []string{path + "cppbench.contention"}, + nil, + false, + nil, + "", }, { "not normalized single source, multiple base (all profiles same)", []string{path + "cppbench.contention"}, []string{path + "cppbench.contention", path + "cppbench.contention"}, + nil, false, - [][]int64{{-2700, -608881724}, {-100, -23992}, {-200, -179943}, {-100, -17778444}, {-100, -75976}, {-300, -63568134}}, + []WantSample{ + { + values: []int64{-2700, -608881724}, + labels: map[string][]string{}, + }, + { + values: []int64{-100, -23992}, + labels: map[string][]string{}, + }, + { + values: []int64{-200, -179943}, + labels: map[string][]string{}, + }, + { + values: []int64{-100, -17778444}, + labels: map[string][]string{}, + }, + { + values: []int64{-100, -75976}, + labels: map[string][]string{}, + }, + { + values: []int64{-300, -63568134}, + labels: map[string][]string{}, + }, + }, + "", }, { "not normalized, different base and source", []string{path + "cppbench.contention"}, []string{path + "cppbench.small.contention"}, + nil, false, - [][]int64{{1700, 608878600}, {100, 23992}, {200, 179943}, {100, 17778444}, {100, 75976}, {300, 63568134}}, + []WantSample{ + { + values: []int64{1700, 608878600}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 23992}, + labels: map[string][]string{}, + }, + { + values: []int64{200, 179943}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 17778444}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 75976}, + labels: map[string][]string{}, + }, + { + values: []int64{300, 63568134}, + labels: map[string][]string{}, + }, + }, + "", }, { "normalized base is same as source", []string{path + "cppbench.contention"}, []string{path + "cppbench.contention"}, + nil, true, - [][]int64{}, + nil, + "", }, { "normalized single source, multiple base (all profiles same)", []string{path + "cppbench.contention"}, []string{path + "cppbench.contention", path + "cppbench.contention"}, + nil, true, - [][]int64{}, + nil, + "", }, { "normalized different base and source", []string{path + "cppbench.contention"}, []string{path + "cppbench.small.contention"}, + nil, true, - [][]int64{{-229, -370}, {28, 0}, {57, 0}, {28, 80}, {28, 0}, {85, 287}}, + []WantSample{ + { + values: []int64{-229, -370}, + labels: map[string][]string{}, + }, + { + values: []int64{28, 0}, + labels: map[string][]string{}, + }, + { + values: []int64{57, 0}, + labels: map[string][]string{}, + }, + { + values: []int64{28, 80}, + labels: map[string][]string{}, + }, + { + values: []int64{28, 0}, + labels: map[string][]string{}, + }, + { + values: []int64{85, 287}, + labels: map[string][]string{}, + }, + }, + "", + }, + { + "not normalized diff base is same as source", + []string{path + "cppbench.contention"}, + nil, + []string{path + "cppbench.contention"}, + false, + []WantSample{ + { + values: []int64{2700, 608881724}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 23992}, + labels: map[string][]string{}, + }, + { + values: []int64{200, 179943}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 17778444}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 75976}, + labels: map[string][]string{}, + }, + { + values: []int64{300, 63568134}, + labels: map[string][]string{}, + }, + { + values: []int64{-2700, -608881724}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-100, -23992}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-200, -179943}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-100, -17778444}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-100, -75976}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-300, -63568134}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + }, + "", + }, + { + "diff_base and base both specified", + []string{path + "cppbench.contention"}, + []string{path + "cppbench.contention"}, + []string{path + "cppbench.contention"}, + false, + nil, + "-base and -diff_base flags cannot both be specified", }, } for _, tc := range testcases { t.Run(tc.desc, func(t *testing.T) { pprofVariables = baseVars.makeCopy() - - base := make([]*string, len(tc.bases)) - for i, s := range tc.bases { - base[i] = &s - } - f := testFlags{ - stringLists: map[string][]*string{ - "base": base, + stringLists: map[string][]string{ + "base": tc.bases, + "diff_base": tc.diffBases, }, bools: map[string]bool{ "normalize": tc.normalize, @@ -289,30 +454,37 @@ func TestFetchWithBase(t *testing.T) { }) src, _, err := parseFlags(o) + if tc.wantErrorMsg != "" { + if err == nil { + t.Fatalf("got nil, want error %q", tc.wantErrorMsg) + } + + if gotErrMsg := err.Error(); gotErrMsg != tc.wantErrorMsg { + t.Fatalf("got error %q, want error %q", gotErrMsg, tc.wantErrorMsg) + } + return + } + if err != nil { - t.Fatalf("%s: %v", tc.desc, err) + t.Fatalf("got error %q, want no error", err) } p, err := fetchProfiles(src, o) - pprofVariables = baseVars + if err != nil { - t.Fatal(err) + t.Fatalf("got error %q, want no error", err) } - if want, got := len(tc.expectedSamples), len(p.Sample); want != got { - t.Fatalf("want %d samples got %d", want, got) + if got, want := len(p.Sample), len(tc.wantSamples); got != want { + t.Fatalf("got %d samples want %d", got, want) } - if len(p.Sample) > 0 { - for i, sample := range p.Sample { - if want, got := len(tc.expectedSamples[i]), len(sample.Value); want != got { - t.Errorf("want %d values for sample %d, got %d", want, i, got) - } - for j, value := range sample.Value { - if want, got := tc.expectedSamples[i][j], value; want != got { - t.Errorf("want value of %d for value %d of sample %d, got %d", want, j, i, got) - } - } + for i, sample := range p.Sample { + if !reflect.DeepEqual(tc.wantSamples[i].values, sample.Value) { + t.Errorf("for sample %d got values %v, want %v", i, sample.Value, tc.wantSamples[i]) + } + if !reflect.DeepEqual(tc.wantSamples[i].labels, sample.Label) { + t.Errorf("for sample %d got labels %v, want %v", i, sample.Label, tc.wantSamples[i].labels) } } }) diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go index db26862c7d..8d775e16bd 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go @@ -294,7 +294,13 @@ func TestInteractiveCommands(t *testing.T) { t.Errorf("failed on %q: %v", tc.input, err) continue } - vars = applyCommandOverrides(cmd, vars) + + // Get report output format + c := pprofCommands[cmd[0]] + if c == nil { + t.Errorf("unexpected nil command") + } + vars = applyCommandOverrides(cmd[0], c.format, vars) for n, want := range tc.want { if got := vars[n].stringValue(); got != want { diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go index 15cadfb548..76db9cbf99 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go @@ -264,6 +264,10 @@ func (rpt *Report) newGraph(nodes graph.NodeSet) *graph.Graph { s.NumUnit = numUnits } + // Remove label marking samples from the base profiles, so it does not appear + // as a nodelet in the graph view. + prof.RemoveLabel("pprof::base") + formatTag := func(v int64, key string) string { return measurement.ScaledLabel(v, key, o.OutputUnit) } @@ -1212,10 +1216,11 @@ func NewDefault(prof *profile.Profile, options Options) *Report { return New(prof, o) } -// computeTotal computes the sum of all sample values. This will be -// used to compute percentages. +// computeTotal computes the sum of the absolute value of all sample values. +// If any samples have the label "pprof::base" with value "true", then the total +// will only include samples with that label. func computeTotal(prof *profile.Profile, value, meanDiv func(v []int64) int64) int64 { - var div, ret int64 + var div, total, diffDiv, diffTotal int64 for _, sample := range prof.Sample { var d, v int64 v = value(sample.Value) @@ -1225,13 +1230,21 @@ func computeTotal(prof *profile.Profile, value, meanDiv func(v []int64) int64) i if v < 0 { v = -v } - ret += v + total += v div += d + if sample.HasLabel("pprof::base", "true") { + diffTotal += v + diffDiv += d + } + } + if diffTotal > 0 { + total = diffTotal + div = diffDiv } if div != 0 { - return ret / div + return total / div } - return ret + return total } // Report contains the data and associated routines to extract a diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go index 49c6e4934f..9eb435bbb8 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go @@ -287,3 +287,121 @@ func TestLegendActiveFilters(t *testing.T) { } } } + +func TestComputeTotal(t *testing.T) { + p1 := testProfile.Copy() + p1.Sample = []*profile.Sample{ + { + Location: []*profile.Location{testL[0]}, + Value: []int64{1, 1}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{1, 10}, + }, + { + Location: []*profile.Location{testL[4], testL[2], testL[0]}, + Value: []int64{1, 100}, + }, + } + + p2 := testProfile.Copy() + p2.Sample = []*profile.Sample{ + { + Location: []*profile.Location{testL[0]}, + Value: []int64{1, 1}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{1, -10}, + }, + { + Location: []*profile.Location{testL[4], testL[2], testL[0]}, + Value: []int64{1, 100}, + }, + } + + p3 := testProfile.Copy() + p3.Sample = []*profile.Sample{ + { + Location: []*profile.Location{testL[0]}, + Value: []int64{10000, 1}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{-10, 3}, + Label: map[string][]string{"pprof::base": {"true"}}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{1000, -10}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{-9000, 3}, + Label: map[string][]string{"pprof::base": {"true"}}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{-1, 3}, + Label: map[string][]string{"pprof::base": {"true"}}, + }, + { + Location: []*profile.Location{testL[4], testL[2], testL[0]}, + Value: []int64{100, 100}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{100, 3}, + Label: map[string][]string{"pprof::base": {"true"}}, + }, + } + + testcases := []struct { + desc string + prof *profile.Profile + value, meanDiv func(v []int64) int64 + wantTotal int64 + }{ + { + desc: "no diff base, all positive values, index 1", + prof: p1, + value: func(v []int64) int64 { + return v[0] + }, + wantTotal: 3, + }, + { + desc: "no diff base, all positive values, index 2", + prof: p1, + value: func(v []int64) int64 { + return v[1] + }, + wantTotal: 111, + }, + { + desc: "no diff base, some negative values", + prof: p2, + value: func(v []int64) int64 { + return v[1] + }, + wantTotal: 111, + }, + { + desc: "diff base, some negative values", + prof: p3, + value: func(v []int64) int64 { + return v[0] + }, + wantTotal: 9111, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + if gotTotal := computeTotal(tc.prof, tc.value, tc.meanDiv); gotTotal != tc.wantTotal { + t.Errorf("got total %d, want %v", gotTotal, tc.wantTotal) + } + }) + } +} diff --git a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go index 096890d9b4..0c8f3bb5b7 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go @@ -1103,6 +1103,7 @@ var heapzSampleTypes = [][]string{ {"objects", "space"}, {"inuse_objects", "inuse_space"}, {"alloc_objects", "alloc_space"}, + {"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"}, // Go pprof legacy profiles } var contentionzSampleTypes = [][]string{ {"contentions", "delay"}, diff --git a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go index 5f63453e09..6ba0e338c9 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go @@ -39,10 +39,12 @@ func TestLegacyProfileType(t *testing.T) { {[]string{"objects", "space"}, heap, true, "heapzSampleTypes"}, {[]string{"inuse_objects", "inuse_space"}, heap, true, "heapzSampleTypes"}, {[]string{"alloc_objects", "alloc_space"}, heap, true, "heapzSampleTypes"}, + {[]string{"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"}, heap, true, "heapzSampleTypes"}, {[]string{"contentions", "delay"}, cont, true, "contentionzSampleTypes"}, // False cases {[]string{"objects"}, heap, false, "heapzSampleTypes"}, {[]string{"objects", "unknown"}, heap, false, "heapzSampleTypes"}, + {[]string{"inuse_objects", "inuse_space", "alloc_objects", "alloc_space"}, heap, false, "heapzSampleTypes"}, {[]string{"contentions", "delay"}, heap, false, "heapzSampleTypes"}, {[]string{"samples", "cpu"}, heap, false, "heapzSampleTypes"}, {[]string{"samples", "cpu"}, cont, false, "contentionzSampleTypes"}, diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile.go b/src/cmd/vendor/github.com/google/pprof/profile/profile.go index 350538bf43..452194b127 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/profile.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/profile.go @@ -674,6 +674,36 @@ func numLabelsToString(numLabels map[string][]int64, numUnits map[string][]strin return strings.Join(ls, " ") } +// SetLabel sets the specified key to the specified value for all samples in the +// profile. +func (p *Profile) SetLabel(key string, value []string) { + for _, sample := range p.Sample { + if sample.Label == nil { + sample.Label = map[string][]string{key: value} + } else { + sample.Label[key] = value + } + } +} + +// RemoveLabel removes all labels associated with the specified key for all +// samples in the profile. +func (p *Profile) RemoveLabel(key string) { + for _, sample := range p.Sample { + delete(sample.Label, key) + } +} + +// HasLabel returns true if a sample has a label with indicated key and value. +func (s *Sample) HasLabel(key, value string) bool { + for _, v := range s.Label[key] { + if v == value { + return true + } + } + return false +} + // Scale multiplies all sample values in a profile by a constant. func (p *Profile) Scale(ratio float64) { if ratio == 1 { diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go b/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go index 8ed67b1dd6..5b299b1d55 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go @@ -741,7 +741,7 @@ func TestNumLabelMerge(t *testing.T) { wantNumUnits []map[string][]string }{ { - name: "different tag units not merged", + name: "different label units not merged", profs: []*Profile{testProfile4.Copy(), testProfile5.Copy()}, wantNumLabels: []map[string][]int64{ { @@ -912,6 +912,271 @@ func locationHash(s *Sample) string { return tb } +func TestHasLabel(t *testing.T) { + var testcases = []struct { + desc string + labels map[string][]string + key string + value string + wantHasLabel bool + }{ + { + desc: "empty label does not have label", + labels: map[string][]string{}, + key: "key", + value: "value", + wantHasLabel: false, + }, + { + desc: "label with one key and value has label", + labels: map[string][]string{"key": {"value"}}, + key: "key", + value: "value", + wantHasLabel: true, + }, + { + desc: "label with one key and value does not have label", + labels: map[string][]string{"key": {"value"}}, + key: "key1", + value: "value1", + wantHasLabel: false, + }, + { + desc: "label with many keys and values has label", + labels: map[string][]string{ + "key1": {"value2", "value1"}, + "key2": {"value1", "value2", "value2"}, + "key3": {"value1", "value2", "value2"}, + }, + key: "key1", + value: "value1", + wantHasLabel: true, + }, + { + desc: "label with many keys and values does not have label", + labels: map[string][]string{ + "key1": {"value2", "value1"}, + "key2": {"value1", "value2", "value2"}, + "key3": {"value1", "value2", "value2"}, + }, + key: "key5", + value: "value5", + wantHasLabel: false, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + sample := &Sample{ + Label: tc.labels, + } + if gotHasLabel := sample.HasLabel(tc.key, tc.value); gotHasLabel != tc.wantHasLabel { + t.Errorf("sample.HasLabel(%q, %q) got %v, want %v", tc.key, tc.value, gotHasLabel, tc.wantHasLabel) + } + }) + } +} + +func TestRemove(t *testing.T) { + var testcases = []struct { + desc string + samples []*Sample + removeKey string + wantLabels []map[string][]string + }{ + { + desc: "some samples have label already", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value1", "value2", "value3"}, + "key2": {"value1"}, + }, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value2"}, + }, + }, + }, + removeKey: "key1", + wantLabels: []map[string][]string{ + {}, + {"key2": {"value1"}}, + {}, + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + profile := testProfile1.Copy() + profile.Sample = tc.samples + profile.RemoveLabel(tc.removeKey) + if got, want := len(profile.Sample), len(tc.wantLabels); got != want { + t.Fatalf("got %v samples, want %v samples", got, want) + } + for i, sample := range profile.Sample { + wantLabels := tc.wantLabels[i] + if got, want := len(sample.Label), len(wantLabels); got != want { + t.Errorf("got %v label keys for sample %v, want %v", got, i, want) + continue + } + for wantKey, wantValues := range wantLabels { + if gotValues, ok := sample.Label[wantKey]; ok { + if !reflect.DeepEqual(gotValues, wantValues) { + t.Errorf("for key %s, got values %v, want values %v", wantKey, gotValues, wantValues) + } + } else { + t.Errorf("for key %s got no values, want %v", wantKey, wantValues) + } + } + } + }) + } +} + +func TestSetLabel(t *testing.T) { + var testcases = []struct { + desc string + samples []*Sample + setKey string + setVal []string + wantLabels []map[string][]string + }{ + { + desc: "some samples have label already", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value1", "value2", "value3"}, + "key2": {"value1"}, + }, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value2"}, + }, + }, + }, + setKey: "key1", + setVal: []string{"value1"}, + wantLabels: []map[string][]string{ + {"key1": {"value1"}}, + {"key1": {"value1"}, "key2": {"value1"}}, + {"key1": {"value1"}}, + }, + }, + { + desc: "no samples have labels", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + }, + }, + setKey: "key1", + setVal: []string{"value1"}, + wantLabels: []map[string][]string{ + {"key1": {"value1"}}, + }, + }, + { + desc: "all samples have some labels, but not key being added", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key2": {"value2"}, + }, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key3": {"value3"}, + }, + }, + }, + setKey: "key1", + setVal: []string{"value1"}, + wantLabels: []map[string][]string{ + {"key1": {"value1"}, "key2": {"value2"}}, + {"key1": {"value1"}, "key3": {"value3"}}, + }, + }, + { + desc: "all samples have key being added", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value1"}, + }, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value1"}, + }, + }, + }, + setKey: "key1", + setVal: []string{"value1"}, + wantLabels: []map[string][]string{ + {"key1": {"value1"}}, + {"key1": {"value1"}}, + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + profile := testProfile1.Copy() + profile.Sample = tc.samples + profile.SetLabel(tc.setKey, tc.setVal) + if got, want := len(profile.Sample), len(tc.wantLabels); got != want { + t.Fatalf("got %v samples, want %v samples", got, want) + } + for i, sample := range profile.Sample { + wantLabels := tc.wantLabels[i] + if got, want := len(sample.Label), len(wantLabels); got != want { + t.Errorf("got %v label keys for sample %v, want %v", got, i, want) + continue + } + for wantKey, wantValues := range wantLabels { + if gotValues, ok := sample.Label[wantKey]; ok { + if !reflect.DeepEqual(gotValues, wantValues) { + t.Errorf("for key %s, got values %v, want values %v", wantKey, gotValues, wantValues) + } + } else { + t.Errorf("for key %s got no values, want %v", wantKey, wantValues) + } + } + } + }) + } +} + func TestNumLabelUnits(t *testing.T) { var tagFilterTests = []struct { desc string diff --git a/src/cmd/vendor/vendor.json b/src/cmd/vendor/vendor.json index 89506e7fe1..26b32692b2 100644 --- a/src/cmd/vendor/vendor.json +++ b/src/cmd/vendor/vendor.json @@ -5,98 +5,98 @@ { "checksumSHA1": "G9UsR+iruMWxwUefhy+ID+VIFNs=", "path": "github.com/google/pprof/driver", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "LzGfApA19baVJIbQEqziWpRS3zE=", "path": "github.com/google/pprof/internal/binutils", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { - "checksumSHA1": "f7aprpcWR7iZX1PJgKBZrpt++XY=", + "checksumSHA1": "uoKLYk9VTOx2kYV3hU3vOGm4BX8=", "path": "github.com/google/pprof/internal/driver", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "IhuyU2pFSHhQxzadDBw1nHbcsrY=", "path": "github.com/google/pprof/internal/elfexec", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "8vah+aXLGpbtn55JR8MkCAEOMrk=", "path": "github.com/google/pprof/internal/graph", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "QPWfnT5pEU2jOOb8l8hpiFzQJ7Q=", "path": "github.com/google/pprof/internal/measurement", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "PWZdFtGfGz/zbQTfvel9737NZdY=", "path": "github.com/google/pprof/internal/plugin", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "LmDglu/S6vFmgqkxubKDZemFHaY=", "path": "github.com/google/pprof/internal/proftest", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { - "checksumSHA1": "gdyWnzbjgwmqJ2EN/WAp+QPu7d0=", + "checksumSHA1": "qgsLCrPLve6es8A3bA3qv2LPoYk=", "path": "github.com/google/pprof/internal/report", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "rWdirHgJi1+TdRwv5v3zjgFKcJA=", "path": "github.com/google/pprof/internal/symbolizer", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "5lS2AF207MVYyjF+82qHkWK2V64=", "path": "github.com/google/pprof/internal/symbolz", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { - "checksumSHA1": "RvwtpZ+NVtPRCo4EiFvLFFHpoBo=", + "checksumSHA1": "JMf63Fn5hz7JFgz6A2aT9DP/bL0=", "path": "github.com/google/pprof/profile", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "xmqfYca88U2c/I4642r3ps9uIRg=", "path": "github.com/google/pprof/third_party/d3", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "LzWzD56Trzpq+0hLR00Yw5Gpepw=", "path": "github.com/google/pprof/third_party/d3flamegraph", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "738v1E0v0qRW6oAKdCpBEtyVNnY=", "path": "github.com/google/pprof/third_party/svgpan", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { - "checksumSHA1": "UDJQBwUTuQYEHHJ/D7nPBv1qNqI=", + "checksumSHA1": "J5yI4NzHbondzccJmummyJR/kQQ=", "path": "github.com/ianlancetaylor/demangle", - "revision": "4883227f66371e02c4948937d3e2be1664d9be38", - "revisionTime": "2016-09-27T19:13:59Z" + "revision": "fc6590592b44fedfff586c5d94647c090fbd6bac", + "revisionTime": "2018-05-24T22:59:00Z" }, { "path": "golang.org/x/arch/arm/armasm", diff --git a/src/cmd/vet/all/whitelist/darwin_386.txt b/src/cmd/vet/all/whitelist/darwin_386.txt index f7645eff1a..934b773f50 100644 --- a/src/cmd/vet/all/whitelist/darwin_386.txt +++ b/src/cmd/vet/all/whitelist/darwin_386.txt @@ -2,7 +2,5 @@ // Ok -runtime/sys_darwin_386.s: [386] now: function now missing Go declaration runtime/sys_darwin_386.s: [386] sysenter: function sysenter missing Go declaration runtime/sys_darwin_386.s: [386] setldt: function setldt missing Go declaration -runtime/sys_darwin_386.s: [386] cannot check cross-package assembly function: now is in package time diff --git a/src/cmd/vet/all/whitelist/darwin_amd64.txt b/src/cmd/vet/all/whitelist/darwin_amd64.txt index 8423415aea..fcdacb2dc1 100644 --- a/src/cmd/vet/all/whitelist/darwin_amd64.txt +++ b/src/cmd/vet/all/whitelist/darwin_amd64.txt @@ -1,4 +1,3 @@ // darwin/amd64-specific vet whitelist. See readme.txt for details. runtime/sys_darwin_amd64.s: [amd64] settls: function settls missing Go declaration -runtime/sys_darwin_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time diff --git a/src/cmd/vet/buildtag.go b/src/cmd/vet/buildtag.go index 80d8f81924..d1fedec554 100644 --- a/src/cmd/vet/buildtag.go +++ b/src/cmd/vet/buildtag.go @@ -19,11 +19,39 @@ var ( ) // checkBuildTag checks that build tags are in the correct location and well-formed. -func checkBuildTag(name string, data []byte) { +func checkBuildTag(f *File) { if !vet("buildtags") { return } - lines := bytes.SplitAfter(data, nl) + // badf is like File.Badf, but it uses a line number instead of + // token.Pos. + badf := func(line int, format string, args ...interface{}) { + msg := fmt.Sprintf(format, args) + fmt.Fprintf(os.Stderr, "%s:%d: %s\n", f.name, line, msg) + setExit(1) + } + + // we must look at the raw lines, as build tags may appear in non-Go + // files such as assembly files. + lines := bytes.SplitAfter(f.content, nl) + + // lineWithComment reports whether a line corresponds to a comment in + // the source file. If the source file wasn't Go, the function always + // returns true. + lineWithComment := func(line int) bool { + if f.file == nil { + // Current source file is not Go, so be conservative. + return true + } + for _, group := range f.file.Comments { + startLine := f.fset.Position(group.Pos()).Line + endLine := f.fset.Position(group.End()).Line + if startLine <= line && line <= endLine { + return true + } + } + return false + } // Determine cutpoint where +build comments are no longer valid. // They are valid in leading // comments in the file followed by @@ -46,18 +74,29 @@ func checkBuildTag(name string, data []byte) { if !bytes.HasPrefix(line, slashSlash) { continue } + if !bytes.Contains(line, plusBuild) { + // Check that the comment contains "+build" early, to + // avoid unnecessary lineWithComment calls that may + // incur linear searches. + continue + } + if !lineWithComment(i + 1) { + // This is a line in a Go source file that looks like a + // comment, but actually isn't - such as part of a raw + // string. + continue + } + text := bytes.TrimSpace(line[2:]) if bytes.HasPrefix(text, plusBuild) { fields := bytes.Fields(text) if !bytes.Equal(fields[0], plusBuild) { // Comment is something like +buildasdf not +build. - fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1) - setExit(1) + badf(i+1, "possible malformed +build comment") continue } if i >= cutoff { - fmt.Fprintf(os.Stderr, "%s:%d: +build comment must appear before package clause and be followed by a blank line\n", name, i+1) - setExit(1) + badf(i+1, "+build comment must appear before package clause and be followed by a blank line") continue } // Check arguments. @@ -65,15 +104,13 @@ func checkBuildTag(name string, data []byte) { for _, arg := range fields[1:] { for _, elem := range strings.Split(string(arg), ",") { if strings.HasPrefix(elem, "!!") { - fmt.Fprintf(os.Stderr, "%s:%d: invalid double negative in build constraint: %s\n", name, i+1, arg) - setExit(1) + badf(i+1, "invalid double negative in build constraint: %s", arg) break Args } elem = strings.TrimPrefix(elem, "!") for _, c := range elem { if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { - fmt.Fprintf(os.Stderr, "%s:%d: invalid non-alphanumeric build constraint: %s\n", name, i+1, arg) - setExit(1) + badf(i+1, "invalid non-alphanumeric build constraint: %s", arg) break Args } } @@ -82,9 +119,8 @@ func checkBuildTag(name string, data []byte) { continue } // Comment with +build but not at beginning. - if bytes.Contains(line, plusBuild) && i < cutoff { - fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1) - setExit(1) + if i < cutoff { + badf(i+1, "possible malformed +build comment") continue } } diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go index 4422add72f..50af846c59 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -415,23 +415,24 @@ func doPackage(names []string, basePkg *Package) *Package { warnf("%s: %s", name, err) return nil } - checkBuildTag(name, data) var parsedFile *ast.File if strings.HasSuffix(name, ".go") { - parsedFile, err = parser.ParseFile(fs, name, data, 0) + parsedFile, err = parser.ParseFile(fs, name, data, parser.ParseComments) if err != nil { warnf("%s: %s", name, err) return nil } astFiles = append(astFiles, parsedFile) } - files = append(files, &File{ + file := &File{ fset: fs, content: data, name: name, file: parsedFile, dead: make(map[ast.Node]bool), - }) + } + checkBuildTag(file) + files = append(files, file) } if len(astFiles) == 0 { return nil diff --git a/src/cmd/vet/testdata/atomic.go b/src/cmd/vet/testdata/atomic.go index 8b587567c7..69730b4e6f 100644 --- a/src/cmd/vet/testdata/atomic.go +++ b/src/cmd/vet/testdata/atomic.go @@ -43,7 +43,7 @@ func AtomicTests() { { // A variable declaration creates a new variable in the current scope. - x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at testdata/atomic.go:16" + x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at atomic.go:16" // Re-declaration assigns a new value. x, w := atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value" diff --git a/src/cmd/vet/testdata/buildtag/buildtag.go b/src/cmd/vet/testdata/buildtag/buildtag.go index f12f895dfb..6ee08da638 100644 --- a/src/cmd/vet/testdata/buildtag/buildtag.go +++ b/src/cmd/vet/testdata/buildtag/buildtag.go @@ -12,3 +12,7 @@ package testdata // +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line" var _ = 3 + +var _ = ` +// +build notacomment +` diff --git a/src/cmd/vet/testdata/shadow.go b/src/cmd/vet/testdata/shadow.go index 3b61137b87..c55cb2772a 100644 --- a/src/cmd/vet/testdata/shadow.go +++ b/src/cmd/vet/testdata/shadow.go @@ -17,7 +17,7 @@ func ShadowRead(f *os.File, buf []byte) (err error) { _ = err } if f != nil { - _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13" + _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13" if err != nil { return err } @@ -25,8 +25,8 @@ func ShadowRead(f *os.File, buf []byte) (err error) { _ = i } if f != nil { - x := one() // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14" - var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13" + x := one() // ERROR "declaration of .x. shadows declaration at shadow.go:14" + var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13" if x == 1 && err != nil { return err } @@ -46,7 +46,7 @@ func ShadowRead(f *os.File, buf []byte) (err error) { if shadowTemp := shadowTemp; true { // OK: obviously intentional idiomatic redeclaration var f *os.File // OK because f is not mentioned later in the function. // The declaration of x is a shadow because x is mentioned below. - var x int // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14" + var x int // ERROR "declaration of .x. shadows declaration at shadow.go:14" _, _, _ = x, f, shadowTemp } // Use a couple of variables to trigger shadowing errors. diff --git a/src/cmd/vet/testdata/structtag.go b/src/cmd/vet/testdata/structtag.go index c87e42f5d0..ce21e803c8 100644 --- a/src/cmd/vet/testdata/structtag.go +++ b/src/cmd/vet/testdata/structtag.go @@ -44,40 +44,40 @@ type AnonymousXML struct{} type DuplicateJSONFields struct { JSON int `json:"a"` - DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:46" + DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at structtag.go:46" IgnoredJSON int `json:"-"` OtherIgnoredJSON int `json:"-"` OmitJSON int `json:",omitempty"` OtherOmitJSON int `json:",omitempty"` - DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:46" + DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at structtag.go:46" NonJSON int `foo:"a"` DuplicateNonJSON int `foo:"a"` Embedded struct { DuplicateJSON int `json:"a"` // OK because its not in the same struct type } - AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at testdata/structtag.go:46" + AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at structtag.go:46" XML int `xml:"a"` - DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:60" + DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at structtag.go:60" IgnoredXML int `xml:"-"` OtherIgnoredXML int `xml:"-"` OmitXML int `xml:",omitempty"` OtherOmitXML int `xml:",omitempty"` - DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:60" + DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at structtag.go:60" NonXML int `foo:"a"` DuplicateNonXML int `foo:"a"` Embedded struct { DuplicateXML int `xml:"a"` // OK because its not in the same struct type } - AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at testdata/structtag.go:60" + AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at structtag.go:60" Attribute struct { XMLName xml.Name `xml:"b"` NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct. Attr int `xml:"b,attr"` // OK because 0 is valid. - DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at testdata/structtag.go:76" - DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at testdata/structtag.go:76" + DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at structtag.go:76" + DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at structtag.go:76" - AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at testdata/structtag.go:76" + AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at structtag.go:76" } } diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go index f654d4679e..ecb4ce1295 100644 --- a/src/cmd/vet/vet_test.go +++ b/src/cmd/vet/vet_test.go @@ -6,12 +6,17 @@ package main_test import ( "bytes" + "errors" "fmt" "internal/testenv" + "io/ioutil" + "log" "os" "os/exec" "path/filepath" + "regexp" "runtime" + "strconv" "strings" "sync" "testing" @@ -19,7 +24,7 @@ import ( const ( dataDir = "testdata" - binary = "testvet.exe" + binary = "./testvet.exe" ) // We implement TestMain so remove the test binary when all is done. @@ -29,16 +34,6 @@ func TestMain(m *testing.M) { os.Exit(result) } -func MustHavePerl(t *testing.T) { - switch runtime.GOOS { - case "plan9", "windows": - t.Skipf("skipping test: perl not available on %s", runtime.GOOS) - } - if _, err := exec.LookPath("perl"); err != nil { - t.Skipf("skipping test: perl not found in path") - } -} - var ( buildMu sync.Mutex // guards following built = false // We have built the binary. @@ -55,7 +50,6 @@ func Build(t *testing.T) { t.Skip("cannot run on this environment") } testenv.MustHaveGoBuild(t) - MustHavePerl(t) cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", binary) output, err := cmd.CombinedOutput() if err != nil { @@ -67,23 +61,19 @@ func Build(t *testing.T) { } func Vet(t *testing.T, files []string) { - errchk := filepath.Join(runtime.GOROOT(), "test", "errchk") flags := []string{ - "./" + binary, "-printfuncs=Warn:1,Warnf:1", "-all", "-shadow", } - cmd := exec.Command(errchk, append(flags, files...)...) - if !run(cmd, t) { - t.Fatal("vet command failed") - } + cmd := exec.Command(binary, append(flags, files...)...) + errchk(cmd, files, t) } -// Run this shell script, but do it in Go so it can be run by "go test". -// go build -o testvet -// $(GOROOT)/test/errchk ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s -// rm testvet +// TestVet is equivalent to running this: +// go build -o ./testvet +// errorCheck the output of ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s +// rm ./testvet // // TestVet tests self-contained files in testdata/*.go. @@ -95,7 +85,6 @@ func TestVet(t *testing.T) { Build(t) t.Parallel() - // errchk ./testvet gos, err := filepath.Glob(filepath.Join(dataDir, "*.go")) if err != nil { t.Fatal(err) @@ -128,17 +117,14 @@ func TestVet(t *testing.T) { func TestVetPrint(t *testing.T) { Build(t) - errchk := filepath.Join(runtime.GOROOT(), "test", "errchk") + file := filepath.Join("testdata", "print.go") cmd := exec.Command( - errchk, - "go", "vet", "-vettool=./"+binary, + "go", "vet", "-vettool="+binary, "-printf", "-printfuncs=Warn:1,Warnf:1", - "testdata/print.go", + file, ) - if !run(cmd, t) { - t.Fatal("vet command failed") - } + errchk(cmd, []string{file}, t) } func TestVetAsm(t *testing.T) { @@ -155,7 +141,6 @@ func TestVetAsm(t *testing.T) { } t.Parallel() - // errchk ./testvet Vet(t, append(gos, asms...)) } @@ -181,23 +166,20 @@ func TestVetDirs(t *testing.T) { } } -func run(c *exec.Cmd, t *testing.T) bool { +func errchk(c *exec.Cmd, files []string, t *testing.T) { output, err := c.CombinedOutput() - if err != nil { + if _, ok := err.(*exec.ExitError); !ok { t.Logf("vet output:\n%s", output) t.Fatal(err) } - // Errchk delights by not returning non-zero status if it finds errors, so we look at the output. - // It prints "BUG" if there is a failure. - if !c.ProcessState.Success() { - t.Logf("vet output:\n%s", output) - return false + fullshort := make([]string, 0, len(files)*2) + for _, f := range files { + fullshort = append(fullshort, f, filepath.Base(f)) } - ok := !bytes.Contains(output, []byte("BUG")) - if !ok { - t.Logf("vet output:\n%s", output) + err = errorCheck(string(output), false, fullshort...) + if err != nil { + t.Errorf("error check failed: %s", err) } - return ok } // TestTags verifies that the -tags argument controls which files to check. @@ -214,7 +196,7 @@ func TestTags(t *testing.T) { "-v", // We're going to look at the files it examines. "testdata/tagtest", } - cmd := exec.Command("./"+binary, args...) + cmd := exec.Command(binary, args...) output, err := cmd.CombinedOutput() if err != nil { t.Fatal(err) @@ -234,10 +216,225 @@ func TestTags(t *testing.T) { func TestVetVerbose(t *testing.T) { t.Parallel() Build(t) - cmd := exec.Command("./"+binary, "-v", "-all", "testdata/cgo/cgo3.go") + cmd := exec.Command(binary, "-v", "-all", "testdata/cgo/cgo3.go") out, err := cmd.CombinedOutput() if err != nil { t.Logf("%s", out) t.Error(err) } } + +// All declarations below were adapted from test/run.go. + +// errorCheck matches errors in outStr against comments in source files. +// For each line of the source files which should generate an error, +// there should be a comment of the form // ERROR "regexp". +// If outStr has an error for a line which has no such comment, +// this function will report an error. +// Likewise if outStr does not have an error for a line which has a comment, +// or if the error message does not match the . +// The syntax is Perl but its best to stick to egrep. +// +// Sources files are supplied as fullshort slice. +// It consists of pairs: full path to source file and it's base name. +func errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) { + var errs []error + out := splitOutput(outStr, wantAuto) + // Cut directory name. + for i := range out { + for j := 0; j < len(fullshort); j += 2 { + full, short := fullshort[j], fullshort[j+1] + out[i] = strings.Replace(out[i], full, short, -1) + } + } + + var want []wantedError + for j := 0; j < len(fullshort); j += 2 { + full, short := fullshort[j], fullshort[j+1] + want = append(want, wantedErrors(full, short)...) + } + for _, we := range want { + var errmsgs []string + if we.auto { + errmsgs, out = partitionStrings("", out) + } else { + errmsgs, out = partitionStrings(we.prefix, out) + } + if len(errmsgs) == 0 { + errs = append(errs, fmt.Errorf("%s:%d: missing error %q", we.file, we.lineNum, we.reStr)) + continue + } + matched := false + n := len(out) + for _, errmsg := range errmsgs { + // Assume errmsg says "file:line: foo". + // Cut leading "file:line: " to avoid accidental matching of file name instead of message. + text := errmsg + if i := strings.Index(text, " "); i >= 0 { + text = text[i+1:] + } + if we.re.MatchString(text) { + matched = true + } else { + out = append(out, errmsg) + } + } + if !matched { + errs = append(errs, fmt.Errorf("%s:%d: no match for %#q in:\n\t%s", we.file, we.lineNum, we.reStr, strings.Join(out[n:], "\n\t"))) + continue + } + } + + if len(out) > 0 { + errs = append(errs, fmt.Errorf("Unmatched Errors:")) + for _, errLine := range out { + errs = append(errs, fmt.Errorf("%s", errLine)) + } + } + + if len(errs) == 0 { + return nil + } + if len(errs) == 1 { + return errs[0] + } + var buf bytes.Buffer + fmt.Fprintf(&buf, "\n") + for _, err := range errs { + fmt.Fprintf(&buf, "%s\n", err.Error()) + } + return errors.New(buf.String()) +} + +func splitOutput(out string, wantAuto bool) []string { + // gc error messages continue onto additional lines with leading tabs. + // Split the output at the beginning of each line that doesn't begin with a tab. + // lines are impossible to match so those are filtered out. + var res []string + for _, line := range strings.Split(out, "\n") { + line = strings.TrimSuffix(line, "\r") // normalize Windows output + if strings.HasPrefix(line, "\t") { + res[len(res)-1] += "\n" + line + } else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "#") || !wantAuto && strings.HasPrefix(line, "") { + continue + } else if strings.TrimSpace(line) != "" { + res = append(res, line) + } + } + return res +} + +// matchPrefix reports whether s starts with file name prefix followed by a :, +// and possibly preceded by a directory name. +func matchPrefix(s, prefix string) bool { + i := strings.Index(s, ":") + if i < 0 { + return false + } + j := strings.LastIndex(s[:i], "/") + s = s[j+1:] + if len(s) <= len(prefix) || s[:len(prefix)] != prefix { + return false + } + if s[len(prefix)] == ':' { + return true + } + return false +} + +func partitionStrings(prefix string, strs []string) (matched, unmatched []string) { + for _, s := range strs { + if matchPrefix(s, prefix) { + matched = append(matched, s) + } else { + unmatched = append(unmatched, s) + } + } + return +} + +type wantedError struct { + reStr string + re *regexp.Regexp + lineNum int + auto bool // match line + file string + prefix string +} + +var ( + errRx = regexp.MustCompile(`// (?:GC_)?ERROR (.*)`) + errAutoRx = regexp.MustCompile(`// (?:GC_)?ERRORAUTO (.*)`) + errQuotesRx = regexp.MustCompile(`"([^"]*)"`) + lineRx = regexp.MustCompile(`LINE(([+-])([0-9]+))?`) +) + +// wantedErrors parses expected errors from comments in a file. +func wantedErrors(file, short string) (errs []wantedError) { + cache := make(map[string]*regexp.Regexp) + + src, err := ioutil.ReadFile(file) + if err != nil { + log.Fatal(err) + } + for i, line := range strings.Split(string(src), "\n") { + lineNum := i + 1 + if strings.Contains(line, "////") { + // double comment disables ERROR + continue + } + var auto bool + m := errAutoRx.FindStringSubmatch(line) + if m != nil { + auto = true + } else { + m = errRx.FindStringSubmatch(line) + } + if m == nil { + continue + } + all := m[1] + mm := errQuotesRx.FindAllStringSubmatch(all, -1) + if mm == nil { + log.Fatalf("%s:%d: invalid errchk line: %s", file, lineNum, line) + } + for _, m := range mm { + replacedOnce := false + rx := lineRx.ReplaceAllStringFunc(m[1], func(m string) string { + if replacedOnce { + return m + } + replacedOnce = true + n := lineNum + if strings.HasPrefix(m, "LINE+") { + delta, _ := strconv.Atoi(m[5:]) + n += delta + } else if strings.HasPrefix(m, "LINE-") { + delta, _ := strconv.Atoi(m[5:]) + n -= delta + } + return fmt.Sprintf("%s:%d", short, n) + }) + re := cache[rx] + if re == nil { + var err error + re, err = regexp.Compile(rx) + if err != nil { + log.Fatalf("%s:%d: invalid regexp \"%#q\" in ERROR line: %v", file, lineNum, rx, err) + } + cache[rx] = re + } + prefix := fmt.Sprintf("%s:%d", short, lineNum) + errs = append(errs, wantedError{ + reStr: rx, + re: re, + prefix: prefix, + auto: auto, + lineNum: lineNum, + file: short, + }) + } + } + + return +} diff --git a/src/compress/bzip2/bzip2.go b/src/compress/bzip2/bzip2.go index f07c7e81e8..c40129b982 100644 --- a/src/compress/bzip2/bzip2.go +++ b/src/compress/bzip2/bzip2.go @@ -8,7 +8,7 @@ package bzip2 import "io" // There's no RFC for bzip2. I used the Wikipedia page for reference and a lot -// of guessing: http://en.wikipedia.org/wiki/Bzip2 +// of guessing: https://en.wikipedia.org/wiki/Bzip2 // The source code to pyflate was useful for debugging: // http://www.paul.sladen.org/projects/pyflate diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go index 4d6a5357d8..8b92f1586d 100644 --- a/src/compress/flate/deflate.go +++ b/src/compress/flate/deflate.go @@ -720,7 +720,7 @@ func (w *Writer) Write(data []byte) (n int, err error) { // In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH. func (w *Writer) Flush() error { // For more about flushing: - // http://www.bolet.org/~pornin/deflate-flush.html + // https://www.bolet.org/~pornin/deflate-flush.html return w.d.syncFlush() } diff --git a/src/compress/lzw/reader_test.go b/src/compress/lzw/reader_test.go index f8974de28f..98bbfbb763 100644 --- a/src/compress/lzw/reader_test.go +++ b/src/compress/lzw/reader_test.go @@ -66,7 +66,7 @@ var lzwTests = []lzwTest{ "\x54\x9e\x08\x29\xf2\x44\x8a\x93\x27\x54\x04", io.ErrUnexpectedEOF, }, - // This example comes from http://en.wikipedia.org/wiki/Graphics_Interchange_Format. + // This example comes from https://en.wikipedia.org/wiki/Graphics_Interchange_Format. { "gif;LSB;8", "\x28\xff\xff\xff\x28\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", diff --git a/src/compress/zlib/reader_test.go b/src/compress/zlib/reader_test.go index 7e27aecb47..70e33babd1 100644 --- a/src/compress/zlib/reader_test.go +++ b/src/compress/zlib/reader_test.go @@ -19,7 +19,7 @@ type zlibTest struct { } // Compare-to-golden test data was generated by the ZLIB example program at -// http://www.zlib.net/zpipe.c +// https://www.zlib.net/zpipe.c var zlibTests = []zlibTest{ { diff --git a/src/context/benchmark_test.go b/src/context/benchmark_test.go index 6dd8510ff4..5d56863050 100644 --- a/src/context/benchmark_test.go +++ b/src/context/benchmark_test.go @@ -13,6 +13,30 @@ import ( "time" ) +func BenchmarkCommonParentCancel(b *testing.B) { + root := WithValue(Background(), "key", "value") + shared, sharedcancel := WithCancel(root) + defer sharedcancel() + + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + x := 0 + for pb.Next() { + ctx, cancel := WithCancel(shared) + if ctx.Value("key").(string) != "value" { + b.Fatal("should not be reached") + } + for i := 0; i < 100; i++ { + x /= x + 1 + } + cancel() + for i := 0; i < 100; i++ { + x /= x + 1 + } + } + }) +} + func BenchmarkWithTimeout(b *testing.B) { for concurrency := 40; concurrency <= 4e5; concurrency *= 100 { name := fmt.Sprintf("concurrency=%d", concurrency) diff --git a/src/crypto/aes/aes_test.go b/src/crypto/aes/aes_test.go index 28144968fc..bedc2da946 100644 --- a/src/crypto/aes/aes_test.go +++ b/src/crypto/aes/aes_test.go @@ -122,7 +122,7 @@ func TestTd(t *testing.T) { } // Test vectors are from FIPS 197: -// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf +// https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf // Appendix A of FIPS 197: Key expansion examples type KeyTest struct { diff --git a/src/crypto/aes/block.go b/src/crypto/aes/block.go index 41ea9cf95e..8647019d58 100644 --- a/src/crypto/aes/block.go +++ b/src/crypto/aes/block.go @@ -31,8 +31,8 @@ // // See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission // for implementation details. -// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf -// http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf +// https://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf +// https://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf package aes diff --git a/src/crypto/aes/const.go b/src/crypto/aes/const.go index cbac5ff0ea..4eca4b9aff 100644 --- a/src/crypto/aes/const.go +++ b/src/crypto/aes/const.go @@ -15,7 +15,7 @@ package aes // This file contains AES constants - 8720 bytes of initialized data. -// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf +// https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf // AES is based on the mathematical behavior of binary polynomials // (polynomials over GF(2)) modulo the irreducible polynomial x⁸ + x⁴ + x³ + x + 1. diff --git a/src/crypto/cipher/cfb_test.go b/src/crypto/cipher/cfb_test.go index 9b544bb211..ecb716df01 100644 --- a/src/crypto/cipher/cfb_test.go +++ b/src/crypto/cipher/cfb_test.go @@ -14,7 +14,7 @@ import ( ) // cfbTests contains the test vectors from -// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section +// https://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section // F.3.13. var cfbTests = []struct { key, iv, plaintext, ciphertext string diff --git a/src/crypto/cipher/cipher.go b/src/crypto/cipher/cipher.go index 31c14d7f91..7e1a4de9a3 100644 --- a/src/crypto/cipher/cipher.go +++ b/src/crypto/cipher/cipher.go @@ -4,7 +4,7 @@ // Package cipher implements standard block cipher modes that can be wrapped // around low-level block cipher implementations. -// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html +// See https://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html // and NIST Special Publication 800-38A. package cipher diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go index 0ea053428c..28f8b2093e 100644 --- a/src/crypto/cipher/gcm.go +++ b/src/crypto/cipher/gcm.go @@ -63,7 +63,7 @@ type gcmFieldElement struct { } // gcm represents a Galois Counter Mode with a specific key. See -// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf +// https://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf type gcm struct { cipher Block nonceSize int @@ -80,7 +80,7 @@ type gcm struct { // An exception is when the underlying Block was created by aes.NewCipher // on systems with hardware support for AES. See the crypto/aes package documentation for details. func NewGCM(cipher Block) (AEAD, error) { - return NewGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, gcmTagSize) + return newGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, gcmTagSize) } // NewGCMWithNonceSize returns the given 128-bit, block cipher wrapped in Galois @@ -90,18 +90,22 @@ func NewGCM(cipher Block) (AEAD, error) { // cryptosystem that uses non-standard nonce lengths. All other users should use // NewGCM, which is faster and more resistant to misuse. func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) { - return NewGCMWithNonceAndTagSize(cipher, size, gcmTagSize) + return newGCMWithNonceAndTagSize(cipher, size, gcmTagSize) } -// NewGCMWithNonceAndTagSize returns the given 128-bit, block cipher wrapped in Galois -// Counter Mode, which accepts nonces of the given length and generates tags with the given length. +// NewGCMWithTagSize returns the given 128-bit, block cipher wrapped in Galois +// Counter Mode, which generates tags with the given length. // // Tag sizes between 12 and 16 bytes are allowed. // // Only use this function if you require compatibility with an existing // cryptosystem that uses non-standard tag lengths. All other users should use // NewGCM, which is more resistant to misuse. -func NewGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, error) { +func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) { + return newGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, tagSize) +} + +func newGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, error) { if tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize { return nil, errors.New("cipher: incorrect tag size given to GCM") } diff --git a/src/crypto/cipher/gcm_test.go b/src/crypto/cipher/gcm_test.go index 31f4d95364..c48001db28 100644 --- a/src/crypto/cipher/gcm_test.go +++ b/src/crypto/cipher/gcm_test.go @@ -231,9 +231,28 @@ func TestAESGCM(t *testing.T) { plaintext, _ := hex.DecodeString(test.plaintext) ad, _ := hex.DecodeString(test.ad) tagSize := (len(test.result) - len(test.plaintext)) / 2 - aesgcm, err := cipher.NewGCMWithNonceAndTagSize(aes, len(nonce), tagSize) - if err != nil { - t.Fatal(err) + + var aesgcm cipher.AEAD + switch { + // Handle non-standard nonce sizes + case tagSize != 16: + aesgcm, err = cipher.NewGCMWithTagSize(aes, tagSize) + if err != nil { + t.Fatal(err) + } + + // Handle non-standard tag sizes + case len(nonce) != 12: + aesgcm, err = cipher.NewGCMWithNonceSize(aes, len(nonce)) + if err != nil { + t.Fatal(err) + } + + default: + aesgcm, err = cipher.NewGCM(aes) + if err != nil { + t.Fatal(err) + } } ct := aesgcm.Seal(nil, nonce, plaintext, ad) @@ -277,12 +296,11 @@ func TestAESGCM(t *testing.T) { func TestGCMInvalidTagSize(t *testing.T) { key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed") - nonce, _ := hex.DecodeString("54cc7dc2c37ec006bcc6d1db") aes, _ := aes.NewCipher(key) for _, tagSize := range []int{0, 1, aes.BlockSize() + 1} { - aesgcm, err := cipher.NewGCMWithNonceAndTagSize(aes, len(nonce), tagSize) + aesgcm, err := cipher.NewGCMWithTagSize(aes, tagSize) if aesgcm != nil || err == nil { t.Fatalf("NewGCMWithNonceAndTagSize was successful with an invalid %d-byte tag size", tagSize) } diff --git a/src/crypto/dsa/dsa.go b/src/crypto/dsa/dsa.go index e94585579e..575314b1b4 100644 --- a/src/crypto/dsa/dsa.go +++ b/src/crypto/dsa/dsa.go @@ -11,6 +11,8 @@ import ( "errors" "io" "math/big" + + "crypto/internal/randutil" ) // Parameters represents the domain parameters for a key. These parameters can @@ -195,6 +197,8 @@ func fermatInverse(k, P *big.Int) *big.Int { // Be aware that calling Sign with an attacker-controlled PrivateKey may // require an arbitrary amount of CPU. func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { + randutil.MaybeReadByte(rand) + // FIPS 186-3, section 4.6 n := priv.Q.BitLen() diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index 6a47cc7d98..bae3f03e5d 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -28,6 +28,8 @@ import ( "io" "math/big" "unsafe" + + "crypto/internal/randutil" ) // A invertible implements fast inverse mod Curve.Params().N @@ -176,6 +178,8 @@ var errZeroParam = errors.New("zero parameter") // returns the signature as a pair of integers. The security of the private key // depends on the entropy of rand. func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { + randutil.MaybeReadByte(rand) + if boring.Enabled && rand == boring.RandReader { b, err := boringPrivateKey(priv) if err != nil { diff --git a/src/crypto/ecdsa/ecdsa_test.go b/src/crypto/ecdsa/ecdsa_test.go index 9224a039f3..6284e06bd4 100644 --- a/src/crypto/ecdsa/ecdsa_test.go +++ b/src/crypto/ecdsa/ecdsa_test.go @@ -213,7 +213,7 @@ func fromHex(s string) *big.Int { func TestVectors(t *testing.T) { // This test runs the full set of NIST test vectors from - // http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip + // https://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip // // The SigVer.rsp file has been edited to remove test vectors for // unsupported algorithms and has been compressed. diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go index 35aacf24e5..4fc2b5e521 100644 --- a/src/crypto/elliptic/elliptic.go +++ b/src/crypto/elliptic/elliptic.go @@ -20,7 +20,7 @@ import ( ) // A Curve represents a short-form Weierstrass curve with a=-3. -// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html +// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw.html type Curve interface { // Params returns the parameters for the curve. Params() *CurveParams @@ -108,7 +108,7 @@ func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and // (x2, y2, z2) and returns their sum, also in Jacobian form. func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { - // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl + // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int) if z1.Sign() == 0 { x3.Set(x2) @@ -191,7 +191,7 @@ func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and // returns its double, also in Jacobian form. func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { - // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b delta := new(big.Int).Mul(z, z) delta.Mod(delta, curve.P) gamma := new(big.Int).Mul(y, y) diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go index 22d0e2429c..2ea63f3f0c 100644 --- a/src/crypto/elliptic/p224.go +++ b/src/crypto/elliptic/p224.go @@ -7,7 +7,7 @@ package elliptic // This is a constant-time, 32-bit implementation of P224. See FIPS 186-3, // section D.2.2. // -// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. +// See https://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. import ( "math/big" @@ -503,7 +503,7 @@ func p224Contract(out, in *p224FieldElement) { // p224AddJacobian computes *out = a+b where a != b. func p224AddJacobian(x3, y3, z3, x1, y1, z1, x2, y2, z2 *p224FieldElement) { - // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-p224Add-2007-bl + // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-p224Add-2007-bl var z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v p224FieldElement var c p224LargeFieldElement diff --git a/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go index bbf0087e66..bb9757355a 100644 --- a/src/crypto/elliptic/p256.go +++ b/src/crypto/elliptic/p256.go @@ -817,7 +817,7 @@ func p256Scalar8(out *[p256Limbs]uint32) { // p256PointDouble sets {xOut,yOut,zOut} = 2*{x,y,z}. // -// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l +// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l func p256PointDouble(xOut, yOut, zOut, x, y, z *[p256Limbs]uint32) { var delta, gamma, alpha, beta, tmp, tmp2 [p256Limbs]uint32 @@ -850,7 +850,7 @@ func p256PointDouble(xOut, yOut, zOut, x, y, z *[p256Limbs]uint32) { // p256PointAddMixed sets {xOut,yOut,zOut} = {x1,y1,z1} + {x2,y2,1}. // (i.e. the second point is affine.) // -// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl +// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl // // Note that this function does not handle P+P, infinity+P nor P+infinity // correctly. @@ -886,7 +886,7 @@ func p256PointAddMixed(xOut, yOut, zOut, x1, y1, z1, x2, y2 *[p256Limbs]uint32) // p256PointAdd sets {xOut,yOut,zOut} = {x1,y1,z1} + {x2,y2,z2}. // -// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl +// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl // // Note that this function does not handle P+P, infinity+P nor P+infinity // correctly. diff --git a/src/crypto/elliptic/p256_amd64.go b/src/crypto/elliptic/p256_amd64.go index b4346d7484..30eb33a0d4 100644 --- a/src/crypto/elliptic/p256_amd64.go +++ b/src/crypto/elliptic/p256_amd64.go @@ -7,7 +7,7 @@ // detail in: // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with // 256-bit primes" -// http://link.springer.com/article/10.1007%2Fs13389-014-0090-x +// https://link.springer.com/article/10.1007%2Fs13389-014-0090-x // https://eprint.iacr.org/2013/816.pdf // +build amd64 diff --git a/src/crypto/elliptic/p256_asm_amd64.s b/src/crypto/elliptic/p256_asm_amd64.s index 4aebe37c8d..a4e3757977 100644 --- a/src/crypto/elliptic/p256_asm_amd64.s +++ b/src/crypto/elliptic/p256_asm_amd64.s @@ -6,7 +6,7 @@ // P256. The optimizations performed here are described in detail in: // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with // 256-bit primes" -// http://link.springer.com/article/10.1007%2Fs13389-014-0090-x +// https://link.springer.com/article/10.1007%2Fs13389-014-0090-x // https://eprint.iacr.org/2013/816.pdf #include "textflag.h" diff --git a/src/crypto/elliptic/p256_asm_s390x.s b/src/crypto/elliptic/p256_asm_s390x.s index d0e6d09e2e..2219b858b3 100644 --- a/src/crypto/elliptic/p256_asm_s390x.s +++ b/src/crypto/elliptic/p256_asm_s390x.s @@ -991,7 +991,7 @@ TEXT ·p256OrdMul(SB), NOSPLIT, $0 * *Mi obra de arte de siglo XXI @vpaprots * * - * First group is special, doesnt get the two inputs: + * First group is special, doesn't get the two inputs: * +--------+--------+<-+ * +-------| ADD2 | ADD1 |--|-----+ * | +--------+--------+ | | @@ -1733,9 +1733,9 @@ TEXT ·p256PointAddAffineAsm(SB), NOSPLIT, $0 #undef CAR2 // p256PointDoubleAsm(P3, P1 *p256Point) -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw.html +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html #define P3ptr R1 #define P1ptr R2 #define CPOOL R4 @@ -1783,7 +1783,7 @@ TEXT ·p256PointAddAffineAsm(SB), NOSPLIT, $0 #define CAR1 V28 #define CAR2 V29 /* - * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2004-hmv + * https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2004-hmv * Cost: 4M + 4S + 1*half + 5add + 2*2 + 1*3. * Source: 2004 Hankerson–Menezes–Vanstone, page 91. * A = 3(X₁-Z₁²)×(X₁+Z₁²) @@ -1995,7 +1995,7 @@ TEXT ·p256PointDoubleAsm(SB), NOSPLIT, $0 * Y₃ = D×(A×C² - X₃) - B×C³ * Z₃ = Z₁×Z₂×C * - * Three-operand formula (adopted): http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 + * Three-operand formula (adopted): https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 * Temp storage: T1,T2,U1,H,Z3=X3=Y3,S1,R * * T1 = Z1*Z1 diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go index 4576b9843b..1f70abbb68 100644 --- a/src/crypto/hmac/hmac.go +++ b/src/crypto/hmac/hmac.go @@ -28,7 +28,7 @@ import ( ) // FIPS 198-1: -// http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf +// https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf // key is zero padded to the block size of the hash function // ipad = 0x36 byte repeated for key length diff --git a/src/crypto/hmac/hmac_test.go b/src/crypto/hmac/hmac_test.go index cb5ea98d72..96e84f74a1 100644 --- a/src/crypto/hmac/hmac_test.go +++ b/src/crypto/hmac/hmac_test.go @@ -26,7 +26,7 @@ type hmacTest struct { var hmacTests = []hmacTest{ // Tests from US FIPS 198 - // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf + // https://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf { sha1.New, []byte{ @@ -206,7 +206,7 @@ var hmacTests = []hmacTest{ sha256.BlockSize, }, - // Tests from http://csrc.nist.gov/groups/ST/toolkit/examples.html + // Tests from https://csrc.nist.gov/groups/ST/toolkit/examples.html // (truncated tag tests are left out) { sha1.New, diff --git a/src/crypto/internal/randutil/randutil.go b/src/crypto/internal/randutil/randutil.go new file mode 100644 index 0000000000..84b1295a87 --- /dev/null +++ b/src/crypto/internal/randutil/randutil.go @@ -0,0 +1,38 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package randutil contains internal randomness utilities for various +// crypto packages. +package randutil + +import ( + "io" + "sync" +) + +var ( + closedChanOnce sync.Once + closedChan chan struct{} +) + +// MaybeReadByte reads a single byte from r with ~50% probability. This is used +// to ensure that callers do not depend on non-guaranteed behaviour, e.g. +// assuming that rsa.GenerateKey is deterministic w.r.t. a given random stream. +// +// This does not affect tests that pass a stream of fixed bytes as the random +// source (e.g. a zeroReader). +func MaybeReadByte(r io.Reader) { + closedChanOnce.Do(func() { + closedChan = make(chan struct{}) + close(closedChan) + }) + + select { + case <-closedChan: + return + case <-closedChan: + var buf [1]byte + r.Read(buf[:]) + } +} diff --git a/src/crypto/rc4/rc4_test.go b/src/crypto/rc4/rc4_test.go index af79882463..1fc08b8593 100644 --- a/src/crypto/rc4/rc4_test.go +++ b/src/crypto/rc4/rc4_test.go @@ -16,7 +16,7 @@ type rc4Test struct { var golden = []rc4Test{ // Test vectors from the original cypherpunk posting of ARC4: - // http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0?pli=1 + // https://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0?pli=1 { []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, []byte{0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79}, @@ -30,7 +30,7 @@ var golden = []rc4Test{ []byte{0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, 0xbd, 0x61}, }, - // Test vectors from the Wikipedia page: http://en.wikipedia.org/wiki/RC4 + // Test vectors from the Wikipedia page: https://en.wikipedia.org/wiki/RC4 { []byte{0x4b, 0x65, 0x79}, []byte{0xeb, 0x9f, 0x77, 0x81, 0xb7, 0x34, 0xca, 0x72, 0xa7, 0x19}, diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go index f77fc00761..b617840c79 100644 --- a/src/crypto/rsa/pkcs1v15.go +++ b/src/crypto/rsa/pkcs1v15.go @@ -11,6 +11,8 @@ import ( "errors" "io" "math/big" + + "crypto/internal/randutil" ) // This file implements encryption and decryption using PKCS#1 v1.5 padding. @@ -36,6 +38,8 @@ type PKCS1v15DecryptOptions struct { // WARNING: use of this function to encrypt plaintexts other than // session keys is dangerous. Use RSA OAEP in new protocols. func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, error) { + randutil.MaybeReadByte(random) + if err := checkPub(pub); err != nil { return nil, err } diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go index 9302ea8535..6cbcfe5449 100644 --- a/src/crypto/rsa/rsa.go +++ b/src/crypto/rsa/rsa.go @@ -33,6 +33,8 @@ import ( "math" "math/big" "unsafe" + + "crypto/internal/randutil" ) var bigZero = big.NewInt(0) @@ -72,7 +74,7 @@ var ( // We require pub.E to fit into a 32-bit integer so that we // do not have different behavior depending on whether // int is 32 or 64 bits. See also -// http://www.imperialviolet.org/2012/03/16/rsae.html. +// https://www.imperialviolet.org/2012/03/16/rsae.html. func checkPub(pub *PublicKey) error { if pub.N == nil { return errPublicModulus @@ -224,6 +226,8 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) { // [1] US patent 4405829 (1972, expired) // [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) { + randutil.MaybeReadByte(random) + if boring.Enabled && random == boring.RandReader && nprimes == 2 && (bits == 2048 || bits == 3072) { N, E, D, P, Q, Dp, Dq, Qinv, err := boring.GenerateKeyRSA(bits) if err != nil { @@ -526,6 +530,8 @@ func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err er var ir *big.Int if random != nil { + randutil.MaybeReadByte(random) + // Blinding enabled. Blinding involves multiplying c by r^e. // Then the decryption operation performs (m^e * r^e)^d mod n // which equals mr mod n. The factor of r can then be removed diff --git a/src/crypto/sha1/sha1block_amd64.s b/src/crypto/sha1/sha1block_amd64.s index a0032c4544..135f113898 100644 --- a/src/crypto/sha1/sha1block_amd64.s +++ b/src/crypto/sha1/sha1block_amd64.s @@ -395,7 +395,7 @@ end: PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x60,0x240) \ PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x60,0x260) -// Macros calculating individual rounds have general forn +// Macros calculating individual rounds have general form // CALC_ROUND_PRE + PRECALC_ROUND + CALC_ROUND_POST // CALC_ROUND_{PRE,POST} macros follow @@ -413,7 +413,7 @@ end: LEAL (REG_E)(R12*1), REG_E // E += A >>> 5 -// Registers are cycleickly rotated DX -> AX -> DI -> SI -> BX -> CX +// Registers are cyclically rotated DX -> AX -> DI -> SI -> BX -> CX #define CALC_0 \ MOVL SI, BX \ // Precalculating first round RORXL $2, SI, SI \ diff --git a/src/crypto/sha256/sha256block_386.s b/src/crypto/sha256/sha256block_386.s index 33ed027e1f..086a0ab25c 100644 --- a/src/crypto/sha256/sha256block_386.s +++ b/src/crypto/sha256/sha256block_386.s @@ -6,7 +6,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 diff --git a/src/crypto/sha256/sha256block_amd64.s b/src/crypto/sha256/sha256block_amd64.s index f30f4829a6..f6af47c50e 100644 --- a/src/crypto/sha256/sha256block_amd64.s +++ b/src/crypto/sha256/sha256block_amd64.s @@ -8,7 +8,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // The avx2-version is described in an Intel White-Paper: // "Fast SHA-256 Implementations on Intel Architecture Processors" @@ -755,7 +755,7 @@ avx2_loop1: // for w0 - w47 JB avx2_loop1 avx2_loop2: - // w48 - w63 processed with no scheduliung (last 16 rounds) + // w48 - w63 processed with no scheduling (last 16 rounds) VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1) DO_ROUND_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, h) diff --git a/src/crypto/sha256/sha256block_ppc64le.s b/src/crypto/sha256/sha256block_ppc64le.s index f5435602fe..77e63c073f 100644 --- a/src/crypto/sha256/sha256block_ppc64le.s +++ b/src/crypto/sha256/sha256block_ppc64le.s @@ -16,7 +16,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 diff --git a/src/crypto/sha512/sha512block_amd64.s b/src/crypto/sha512/sha512block_amd64.s index a02356607e..0fa0df2f60 100644 --- a/src/crypto/sha512/sha512block_amd64.s +++ b/src/crypto/sha512/sha512block_amd64.s @@ -8,7 +8,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 @@ -274,7 +274,7 @@ end: // Version below is based on "Fast SHA512 Implementations on Intel // Architecture Processors" White-paper -// http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-sha512-implementations-ia-processors-paper.pdf +// https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-sha512-implementations-ia-processors-paper.pdf // AVX2 version by Intel, same algorithm in Linux kernel: // https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha512-avx2-asm.S diff --git a/src/crypto/sha512/sha512block_ppc64le.s b/src/crypto/sha512/sha512block_ppc64le.s index 170e3a6456..55f0c06c7a 100644 --- a/src/crypto/sha512/sha512block_ppc64le.s +++ b/src/crypto/sha512/sha512block_ppc64le.s @@ -16,7 +16,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index 897a8e09bc..a76e4efac0 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -247,19 +247,19 @@ type ClientHelloInfo struct { // ServerName indicates the name of the server requested by the client // in order to support virtual hosting. ServerName is only set if the // client is using SNI (see - // http://tools.ietf.org/html/rfc4366#section-3.1). + // https://tools.ietf.org/html/rfc4366#section-3.1). ServerName string // SupportedCurves lists the elliptic curves supported by the client. // SupportedCurves is set only if the Supported Elliptic Curves // Extension is being used (see - // http://tools.ietf.org/html/rfc4492#section-5.1.1). + // https://tools.ietf.org/html/rfc4492#section-5.1.1). SupportedCurves []CurveID // SupportedPoints lists the point formats supported by the client. // SupportedPoints is set only if the Supported Point Formats Extension // is being used (see - // http://tools.ietf.org/html/rfc4492#section-5.1.2). + // https://tools.ietf.org/html/rfc4492#section-5.1.2). SupportedPoints []uint8 // SignatureSchemes lists the signature and hash schemes that the client @@ -460,7 +460,8 @@ type Config struct { PreferServerCipherSuites bool // SessionTicketsDisabled may be set to true to disable session ticket - // (resumption) support. + // (resumption) support. Note that on clients, session ticket support is + // also disabled if ClientSessionCache is nil. SessionTicketsDisabled bool // SessionTicketKey is used by TLS servers to provide session @@ -474,7 +475,7 @@ type Config struct { SessionTicketKey [32]byte // ClientSessionCache is a cache of ClientSessionState entries for TLS - // session resumption. + // session resumption. It is only used by clients. ClientSessionCache ClientSessionCache // MinVersion contains the minimum SSL/TLS version that is acceptable. diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go index dc3b8911c7..cdaa7aba97 100644 --- a/src/crypto/tls/conn.go +++ b/src/crypto/tls/conn.go @@ -1061,9 +1061,9 @@ func (c *Conn) Write(b []byte) (int, error) { // This can be prevented by splitting each Application Data // record into two records, effectively randomizing the IV. // - // http://www.openssl.org/~bodo/tls-cbc.txt + // https://www.openssl.org/~bodo/tls-cbc.txt // https://bugzilla.mozilla.org/show_bug.cgi?id=665814 - // http://www.imperialviolet.org/2012/01/15/beastfollowup.html + // https://www.imperialviolet.org/2012/01/15/beastfollowup.html var m int if len(b) > 1 && c.vers <= VersionTLS10 { diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go index f8c8d571cc..a5bf10efb8 100644 --- a/src/crypto/tls/handshake_messages.go +++ b/src/crypto/tls/handshake_messages.go @@ -192,7 +192,7 @@ func (m *clientHelloMsg) marshal() []byte { z = z[9:] } if len(m.supportedCurves) > 0 { - // http://tools.ietf.org/html/rfc4492#section-5.5.1 + // https://tools.ietf.org/html/rfc4492#section-5.5.1 z[0] = byte(extensionSupportedCurves >> 8) z[1] = byte(extensionSupportedCurves) l := 2 + 2*len(m.supportedCurves) @@ -209,7 +209,7 @@ func (m *clientHelloMsg) marshal() []byte { } } if len(m.supportedPoints) > 0 { - // http://tools.ietf.org/html/rfc4492#section-5.5.2 + // https://tools.ietf.org/html/rfc4492#section-5.5.2 z[0] = byte(extensionSupportedPoints >> 8) z[1] = byte(extensionSupportedPoints) l := 1 + len(m.supportedPoints) @@ -224,7 +224,7 @@ func (m *clientHelloMsg) marshal() []byte { } } if m.ticketSupported { - // http://tools.ietf.org/html/rfc5077#section-3.2 + // https://tools.ietf.org/html/rfc5077#section-3.2 z[0] = byte(extensionSessionTicket >> 8) z[1] = byte(extensionSessionTicket) l := len(m.sessionTicket) @@ -414,7 +414,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { case extensionStatusRequest: m.ocspStapling = length > 0 && data[0] == statusTypeOCSP case extensionSupportedCurves: - // http://tools.ietf.org/html/rfc4492#section-5.5.1 + // https://tools.ietf.org/html/rfc4492#section-5.5.1 if length < 2 { return false } @@ -430,7 +430,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { d = d[2:] } case extensionSupportedPoints: - // http://tools.ietf.org/html/rfc4492#section-5.5.2 + // https://tools.ietf.org/html/rfc4492#section-5.5.2 if length < 1 { return false } @@ -441,7 +441,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.supportedPoints = make([]uint8, l) copy(m.supportedPoints, data[1:]) case extensionSessionTicket: - // http://tools.ietf.org/html/rfc5077#section-3.2 + // https://tools.ietf.org/html/rfc5077#section-3.2 m.ticketSupported = true m.sessionTicket = data[:length] case extensionSignatureAlgorithms: @@ -1224,7 +1224,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) { return m.raw } - // See http://tools.ietf.org/html/rfc4346#section-7.4.4 + // See https://tools.ietf.org/html/rfc4346#section-7.4.4 length := 1 + len(m.certificateTypes) + 2 casLength := 0 for _, ca := range m.certificateAuthorities { @@ -1374,7 +1374,7 @@ func (m *certificateVerifyMsg) marshal() (x []byte) { return m.raw } - // See http://tools.ietf.org/html/rfc4346#section-7.4.8 + // See https://tools.ietf.org/html/rfc4346#section-7.4.8 siglength := len(m.signature) length := 2 + siglength if m.hasSignatureAndHash { @@ -1452,7 +1452,7 @@ func (m *newSessionTicketMsg) marshal() (x []byte) { return m.raw } - // See http://tools.ietf.org/html/rfc5077#section-3.3 + // See https://tools.ietf.org/html/rfc5077#section-3.3 ticketLen := len(m.ticket) length := 2 + 4 + ticketLen x = make([]byte, 4+length) diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go index a168c5b260..5d6dc21c6d 100644 --- a/src/crypto/tls/key_agreement.go +++ b/src/crypto/tls/key_agreement.go @@ -141,7 +141,7 @@ func pickTLS12HashForSignature(sigType uint8, clientList []SignatureScheme) (Sig if len(clientList) == 0 { // If the client didn't specify any signature_algorithms // extension then we can assume that it supports SHA1. See - // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 + // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 switch sigType { case signatureRSA: return PKCS1WithSHA1, nil @@ -239,7 +239,7 @@ NextCandidate: ecdhePublic = elliptic.Marshal(curve, x, y) } - // http://tools.ietf.org/html/rfc4492#section-5.4 + // https://tools.ietf.org/html/rfc4492#section-5.4 serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic)) serverECDHParams[0] = 3 // named curve serverECDHParams[1] = byte(ka.curveid >> 8) diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go index c8bc0cbba8..8246cd3484 100644 --- a/src/crypto/tls/prf.go +++ b/src/crypto/tls/prf.go @@ -140,7 +140,7 @@ func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, labe } // masterFromPreMasterSecret generates the master secret from the pre-master -// secret. See http://tools.ietf.org/html/rfc5246#section-8.1 +// secret. See https://tools.ietf.org/html/rfc5246#section-8.1 func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte { seed := make([]byte, 0, len(clientRandom)+len(serverRandom)) seed = append(seed, clientRandom...) diff --git a/src/crypto/x509/pkix/pkix.go b/src/crypto/x509/pkix/pkix.go index 7b32220b74..3cc4d587e3 100644 --- a/src/crypto/x509/pkix/pkix.go +++ b/src/crypto/x509/pkix/pkix.go @@ -95,7 +95,7 @@ func (r RDNSequence) String() string { type RelativeDistinguishedNameSET []AttributeTypeAndValue // AttributeTypeAndValue mirrors the ASN.1 structure of the same name in -// http://tools.ietf.org/html/rfc5280#section-4.1.2.4 +// https://tools.ietf.org/html/rfc5280#section-4.1.2.4 type AttributeTypeAndValue struct { Type asn1.ObjectIdentifier Value interface{} diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go index 5c310bff09..a02ac3cfe8 100644 --- a/src/crypto/x509/root_cgo_darwin.go +++ b/src/crypto/x509/root_cgo_darwin.go @@ -7,7 +7,7 @@ package x509 /* -#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080 +#cgo CFLAGS: -mmacosx-version-min=10.10 -D__MAC_OS_X_VERSION_MAX_ALLOWED=101300 #cgo LDFLAGS: -framework CoreFoundation -framework Security #include @@ -16,59 +16,6 @@ package x509 #include #include -// FetchPEMRoots_MountainLion is the version of FetchPEMRoots from Go 1.6 -// which still works on OS X 10.8 (Mountain Lion). -// It lacks support for admin & user cert domains. -// See golang.org/issue/16473 -int FetchPEMRoots_MountainLion(CFDataRef *pemRoots) { - if (pemRoots == NULL) { - return -1; - } - CFArrayRef certs = NULL; - OSStatus err = SecTrustCopyAnchorCertificates(&certs); - if (err != noErr) { - return -1; - } - CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0); - int i, ncerts = CFArrayGetCount(certs); - for (i = 0; i < ncerts; i++) { - CFDataRef data = NULL; - SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i); - if (cert == NULL) { - continue; - } - // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport. - // Once we support weak imports via cgo we should prefer that, and fall back to this - // for older systems. - err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); - if (err != noErr) { - continue; - } - if (data != NULL) { - CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data)); - CFRelease(data); - } - } - CFRelease(certs); - *pemRoots = combinedData; - return 0; -} - -// useOldCode reports whether the running machine is OS X 10.8 Mountain Lion -// or older. We only support Mountain Lion and higher, but we'll at least try our -// best on older machines and continue to use the old code path. -// -// See golang.org/issue/16473 -int useOldCode() { - char str[256]; - size_t size = sizeof(str); - memset(str, 0, size); - sysctlbyname("kern.osrelease", str, &size, NULL, 0); - // OS X 10.8 is osrelease "12.*", 10.7 is 11.*, 10.6 is 10.*. - // We never supported things before that. - return memcmp(str, "12.", 3) == 0 || memcmp(str, "11.", 3) == 0 || memcmp(str, "10.", 3) == 0; -} - // FetchPEMRoots fetches the system's list of trusted X.509 root certificates. // // On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root @@ -80,10 +27,6 @@ int useOldCode() { int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) { int i; - if (useOldCode()) { - return FetchPEMRoots_MountainLion(pemRoots); - } - // Get certificates from all domains, not just System, this lets // the user add CAs to their "login" keychain, and Admins to add // to the "System" keychain @@ -193,10 +136,7 @@ int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) { } } - // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport. - // Once we support weak imports via cgo we should prefer that, and fall back to this - // for older systems. - err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); + err = SecItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); if (err != noErr) { continue; } diff --git a/src/crypto/x509/sha2_windows_test.go b/src/crypto/x509/sha2_windows_test.go index 79dc685c5b..620b7b9e77 100644 --- a/src/crypto/x509/sha2_windows_test.go +++ b/src/crypto/x509/sha2_windows_test.go @@ -13,7 +13,7 @@ func init() { } if major := byte(v); major < 6 { // Windows XP SP2 and Windows 2003 do not support SHA2. - // http://blogs.technet.com/b/pki/archive/2010/09/30/sha2-and-windows.aspx + // https://blogs.technet.com/b/pki/archive/2010/09/30/sha2-and-windows.aspx supportSHA2 = false } } diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 96d7742a3c..1e7a989089 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -340,8 +340,8 @@ var ErrNoRows = errors.New("sql: no rows in result set") // // The sql package creates and frees connections automatically; it // also maintains a free pool of idle connections. If the database has -// a concept of per-connection state, such state can only be reliably -// observed within a transaction. Once DB.Begin is called, the +// a concept of per-connection state, such state can be reliably observed +// within a transaction (Tx) or connection (Conn). Once DB.Begin is called, the // returned Tx is bound to a single connection. Once Commit or // Rollback is called on the transaction, that transaction's // connection is returned to DB's idle connection pool. The pool size diff --git a/src/debug/macho/reloctype_string.go b/src/debug/macho/reloctype_string.go index 6d5c5d87e8..9c2b13186e 100644 --- a/src/debug/macho/reloctype_string.go +++ b/src/debug/macho/reloctype_string.go @@ -2,7 +2,7 @@ package macho -import "fmt" +import "strconv" const _RelocTypeGeneric_name = "GENERIC_RELOC_VANILLAGENERIC_RELOC_PAIRGENERIC_RELOC_SECTDIFFGENERIC_RELOC_PB_LA_PTRGENERIC_RELOC_LOCAL_SECTDIFFGENERIC_RELOC_TLV" @@ -10,7 +10,7 @@ var _RelocTypeGeneric_index = [...]uint8{0, 21, 39, 61, 84, 112, 129} func (i RelocTypeGeneric) String() string { if i < 0 || i >= RelocTypeGeneric(len(_RelocTypeGeneric_index)-1) { - return fmt.Sprintf("RelocTypeGeneric(%d)", i) + return "RelocTypeGeneric(" + strconv.FormatInt(int64(i), 10) + ")" } return _RelocTypeGeneric_name[_RelocTypeGeneric_index[i]:_RelocTypeGeneric_index[i+1]] } @@ -21,7 +21,7 @@ var _RelocTypeX86_64_index = [...]uint8{0, 21, 40, 59, 80, 96, 119, 140, 161, 18 func (i RelocTypeX86_64) String() string { if i < 0 || i >= RelocTypeX86_64(len(_RelocTypeX86_64_index)-1) { - return fmt.Sprintf("RelocTypeX86_64(%d)", i) + return "RelocTypeX86_64(" + strconv.FormatInt(int64(i), 10) + ")" } return _RelocTypeX86_64_name[_RelocTypeX86_64_index[i]:_RelocTypeX86_64_index[i+1]] } @@ -32,7 +32,7 @@ var _RelocTypeARM_index = [...]uint8{0, 17, 31, 49, 73, 92, 106, 126, 148, 162, func (i RelocTypeARM) String() string { if i < 0 || i >= RelocTypeARM(len(_RelocTypeARM_index)-1) { - return fmt.Sprintf("RelocTypeARM(%d)", i) + return "RelocTypeARM(" + strconv.FormatInt(int64(i), 10) + ")" } return _RelocTypeARM_name[_RelocTypeARM_index[i]:_RelocTypeARM_index[i+1]] } @@ -43,7 +43,7 @@ var _RelocTypeARM64_index = [...]uint16{0, 20, 42, 62, 80, 101, 128, 158, 184, 2 func (i RelocTypeARM64) String() string { if i < 0 || i >= RelocTypeARM64(len(_RelocTypeARM64_index)-1) { - return fmt.Sprintf("RelocTypeARM64(%d)", i) + return "RelocTypeARM64(" + strconv.FormatInt(int64(i), 10) + ")" } return _RelocTypeARM64_name[_RelocTypeARM64_index[i]:_RelocTypeARM64_index[i+1]] } diff --git a/src/debug/pe/pe.go b/src/debug/pe/pe.go index 872c977fe3..e933ae1c2a 100644 --- a/src/debug/pe/pe.go +++ b/src/debug/pe/pe.go @@ -91,6 +91,7 @@ const ( IMAGE_FILE_MACHINE_AM33 = 0x1d3 IMAGE_FILE_MACHINE_AMD64 = 0x8664 IMAGE_FILE_MACHINE_ARM = 0x1c0 + IMAGE_FILE_MACHINE_ARM64 = 0xaa64 IMAGE_FILE_MACHINE_EBC = 0xebc IMAGE_FILE_MACHINE_I386 = 0x14c IMAGE_FILE_MACHINE_IA64 = 0x200 diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index ae382ee6bf..1ed357adff 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -250,7 +250,7 @@ func (oi ObjectIdentifier) String() string { // parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and // returns it. An object identifier is a sequence of variable length integers // that are assigned in a hierarchy. -func parseObjectIdentifier(bytes []byte) (s []int, err error) { +func parseObjectIdentifier(bytes []byte) (s ObjectIdentifier, err error) { if len(bytes) == 0 { err = SyntaxError{"zero length OBJECT IDENTIFIER"} return diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go index 185349773f..f0a54e0cb2 100644 --- a/src/encoding/asn1/asn1_test.go +++ b/src/encoding/asn1/asn1_test.go @@ -227,7 +227,7 @@ func TestBitStringRightAlign(t *testing.T) { type objectIdentifierTest struct { in []byte ok bool - out []int + out ObjectIdentifier // has base type[]int } var objectIdentifierTestData = []objectIdentifierTest{ diff --git a/src/encoding/asn1/marshal_test.go b/src/encoding/asn1/marshal_test.go index f20ccdc8e9..a77826a7b0 100644 --- a/src/encoding/asn1/marshal_test.go +++ b/src/encoding/asn1/marshal_test.go @@ -8,6 +8,7 @@ import ( "bytes" "encoding/hex" "math/big" + "reflect" "strings" "testing" "time" @@ -253,6 +254,62 @@ func TestInvalidUTF8(t *testing.T) { } } +func TestMarshalOID(t *testing.T) { + var marshalTestsOID = []marshalTest{ + {[]byte("\x06\x01\x30"), "0403060130"}, // bytes format returns a byte sequence \x04 + // {ObjectIdentifier([]int{0}), "060100"}, // returns an error as OID 0.0 has the same encoding + {[]byte("\x06\x010"), "0403060130"}, // same as above "\x06\x010" = "\x06\x01" + "0" + {ObjectIdentifier([]int{2, 999, 3}), "0603883703"}, // Example of ITU-T X.690 + {ObjectIdentifier([]int{0, 0}), "060100"}, // zero OID + } + for i, test := range marshalTestsOID { + data, err := Marshal(test.in) + if err != nil { + t.Errorf("#%d failed: %s", i, err) + } + out, _ := hex.DecodeString(test.out) + if !bytes.Equal(out, data) { + t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out) + } + } +} + +func TestIssue11130(t *testing.T) { + data := []byte("\x06\x010") // == \x06\x01\x30 == OID = 0 (the figure) + var v interface{} + // v has Zero value here and Elem() would panic + _, err := Unmarshal(data, &v) + if err != nil { + t.Errorf("%v", err) + return + } + if reflect.TypeOf(v).String() != reflect.TypeOf(ObjectIdentifier{}).String() { + t.Errorf("marshal OID returned an invalid type") + return + } + + data1, err := Marshal(v) + if err != nil { + t.Errorf("%v", err) + return + } + + if !bytes.Equal(data, data1) { + t.Errorf("got: %q, want: %q \n", data1, data) + return + } + + var v1 interface{} + _, err = Unmarshal(data1, &v1) + if err != nil { + t.Errorf("%v", err) + return + } + if !reflect.DeepEqual(v, v1) { + t.Errorf("got: %#v data=%q , want : %#v data=%q\n ", v1, data1, v, data) + } +} + func BenchmarkMarshal(b *testing.B) { b.ReportAllocs() diff --git a/src/encoding/hex/hex.go b/src/encoding/hex/hex.go index 4cb26b6673..aee5aecb1a 100644 --- a/src/encoding/hex/hex.go +++ b/src/encoding/hex/hex.go @@ -50,8 +50,8 @@ func DecodedLen(x int) int { return x / 2 } // Decode decodes src into DecodedLen(len(src)) bytes, // returning the actual number of bytes written to dst. // -// Decode expects that src contain only hexadecimal -// characters and that src should have an even length. +// Decode expects that src contains only hexadecimal +// characters and that src has even length. // If the input is malformed, Decode returns the number // of bytes decoded before the error. func Decode(dst, src []byte) (int, error) { @@ -101,10 +101,10 @@ func EncodeToString(src []byte) string { // DecodeString returns the bytes represented by the hexadecimal string s. // -// DecodeString expects that src contain only hexadecimal -// characters and that src should have an even length. -// If the input is malformed, DecodeString returns a string -// containing the bytes decoded before the error. +// DecodeString expects that src contains only hexadecimal +// characters and that src has even length. +// If the input is malformed, DecodeString returns +// the bytes decoded before the error. func DecodeString(s string) ([]byte, error) { src := []byte(s) // We can use the source slice itself as the destination diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 6a66940034..0b29249218 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -204,7 +204,7 @@ func (n Number) Int64() (int64, error) { func isValidNumber(s string) bool { // This function implements the JSON numbers grammar. // See https://tools.ietf.org/html/rfc7159#section-6 - // and http://json.org/number.gif + // and https://json.org/number.gif if s == "" { return false diff --git a/src/encoding/json/number_test.go b/src/encoding/json/number_test.go index 4b86999638..cc6701814f 100644 --- a/src/encoding/json/number_test.go +++ b/src/encoding/json/number_test.go @@ -10,7 +10,7 @@ import ( ) func TestNumberIsValid(t *testing.T) { - // From: http://stackoverflow.com/a/13340826 + // From: https://stackoverflow.com/a/13340826 var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`) validTests := []string{ diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go index 7d2ff01ee9..452caefab4 100644 --- a/src/encoding/xml/xml.go +++ b/src/encoding/xml/xml.go @@ -7,8 +7,8 @@ package xml // References: -// Annotated XML spec: http://www.xml.com/axml/testaxml.htm -// XML name spaces: http://www.w3.org/TR/REC-xml-names/ +// Annotated XML spec: https://www.xml.com/axml/testaxml.htm +// XML name spaces: https://www.w3.org/TR/REC-xml-names/ // TODO(rsc): // Test error handling. @@ -271,7 +271,7 @@ func NewTokenDecoder(t TokenReader) *Decoder { // it will return an error. // // Token implements XML name spaces as described by -// http://www.w3.org/TR/REC-xml-names/. Each of the +// https://www.w3.org/TR/REC-xml-names/. Each of the // Name structures contained in the Token has the Space // set to the URL identifying its name space when known. // If Token encounters an unrecognized name space prefix, @@ -863,7 +863,7 @@ func (d *Decoder) attrval() []byte { if !ok { return nil } - // http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2 + // https://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2 if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' || '0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' { d.buf.WriteByte(b) @@ -1134,7 +1134,7 @@ Input: } // Decide whether the given rune is in the XML Character Range, per -// the Char production of http://www.xml.com/axml/testaxml.htm, +// the Char production of https://www.xml.com/axml/testaxml.htm, // Section 2.2 Characters. func isInCharacterRange(r rune) (inrange bool) { return r == 0x09 || @@ -1263,7 +1263,7 @@ func isNameString(s string) bool { } // These tables were generated by cut and paste from Appendix B of -// the XML spec at http://www.xml.com/axml/testaxml.htm +// the XML spec at https://www.xml.com/axml/testaxml.htm // and then reformatting. First corresponds to (Letter | '_' | ':') // and second corresponds to NameChar. diff --git a/src/flag/flag.go b/src/flag/flag.go index f613144a7e..188adb285f 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -5,7 +5,7 @@ /* Package flag implements command-line flag parsing. - Usage: + Usage Define flags using flag.String(), Bool(), Int(), etc. @@ -35,7 +35,7 @@ slice flag.Args() or individually as flag.Arg(i). The arguments are indexed from 0 through flag.NArg()-1. - Command line flag syntax: + Command line flag syntax -flag -flag=x -flag x // non-boolean flags only diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index 3d4c92dcec..091443f646 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -177,7 +177,7 @@ func TestShouldBuild(t *testing.T) { } func TestGoodOSArchFile(t *testing.T) { - ctx := &Context{BuildTags: []string{"linux"}, GOOS:"darwin"} + ctx := &Context{BuildTags: []string{"linux"}, GOOS: "darwin"} m := map[string]bool{} want := map[string]bool{"linux": true} if !ctx.goodOSArchFile("hello_linux.go", m) { diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 33a269a62e..ff04b9e982 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -337,19 +337,21 @@ var pkgDeps = map[string][]string{ "net/textproto": {"L4", "OS", "net"}, // Core crypto. - "crypto/aes": {"L3"}, - "crypto/des": {"L3"}, - "crypto/hmac": {"L3"}, - "crypto/md5": {"L3"}, - "crypto/rc4": {"L3"}, - "crypto/sha1": {"L3"}, - "crypto/sha256": {"L3"}, - "crypto/sha512": {"L3"}, + "crypto/aes": {"L3"}, + "crypto/des": {"L3"}, + "crypto/hmac": {"L3"}, + "crypto/internal/randutil": {"io", "sync"}, + "crypto/md5": {"L3"}, + "crypto/rc4": {"L3"}, + "crypto/sha1": {"L3"}, + "crypto/sha256": {"L3"}, + "crypto/sha512": {"L3"}, "CRYPTO": { "crypto/aes", "crypto/des", "crypto/hmac", + "crypto/internal/randutil", "crypto/md5", "crypto/rc4", "crypto/sha1", @@ -408,6 +410,7 @@ var pkgDeps = map[string][]string{ "crypto/rand", "crypto/tls", "golang_org/x/net/http/httpguts", + "golang_org/x/net/http/httpproxy", "golang_org/x/net/http2/hpack", "golang_org/x/net/idna", "golang_org/x/text/unicode/norm", @@ -417,6 +420,7 @@ var pkgDeps = map[string][]string{ "net/http/httptrace", "net/http/internal", "runtime/debug", + "syscall/js", }, "net/http/internal": {"L4"}, "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "reflect", "time"}, diff --git a/src/go/constant/value_test.go b/src/go/constant/value_test.go index 5ec4f4c418..e6fca76e18 100644 --- a/src/go/constant/value_test.go +++ b/src/go/constant/value_test.go @@ -431,6 +431,7 @@ func TestUnknown(t *testing.T) { MakeBool(false), // token.ADD ok below, operation is never considered MakeString(""), MakeInt64(1), + MakeFromLiteral("''", token.CHAR, 0), MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0), MakeFloat64(1.2), MakeImag(MakeFloat64(1.2)), diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index a8745eea3e..308f93e8bd 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -530,6 +530,27 @@ func TestIssue25301(t *testing.T) { importPkg(t, "./testdata/issue25301") } +func TestIssue25596(t *testing.T) { + skipSpecialPlatforms(t) + + // This package only handles gc export data. + if runtime.Compiler != "gc" { + t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) + } + + // On windows, we have to set the -D option for the compiler to avoid having a drive + // letter and an illegal ':' in the import path - just skip it (see also issue #3483). + if runtime.GOOS == "windows" { + t.Skip("avoid dealing with relative paths/drive letters on windows") + } + + if f := compile(t, "testdata", "issue25596.go"); f != "" { + defer os.Remove(f) + } + + importPkg(t, "./testdata/issue25596") +} + func importPkg(t *testing.T, path string) *types.Package { pkg, err := Import(make(map[string]*types.Package), path, ".", nil) if err != nil { diff --git a/src/go/internal/gcimporter/testdata/issue25596.go b/src/go/internal/gcimporter/testdata/issue25596.go new file mode 100644 index 0000000000..8923373e5f --- /dev/null +++ b/src/go/internal/gcimporter/testdata/issue25596.go @@ -0,0 +1,13 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue25596 + +type E interface { + M() T +} + +type T interface { + E +} diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index afe5f5d0fc..05e032423c 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -174,7 +174,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b } } - if mode == invalid { + if mode == invalid && typ != Typ[Invalid] { check.invalidArg(x.pos(), "%s for %s", x, bin.name) return } diff --git a/src/go/types/check.go b/src/go/types/check.go index 177065fded..286b1f36a9 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -90,6 +90,7 @@ type Checker struct { interfaces map[*TypeName]*ifaceInfo // maps interface type names to corresponding interface infos untyped map[ast.Expr]exprInfo // map of expressions without final type delayed []func() // stack of delayed actions + objPath []Object // path of object dependencies during type inference (for cycle reporting) // context within which the current object is type-checked // (valid only for the duration of type-checking a specific object) @@ -144,6 +145,33 @@ func (check *Checker) later(f func()) { check.delayed = append(check.delayed, f) } +// push pushes obj onto the object path and returns its index in the path. +func (check *Checker) push(obj Object) int { + check.objPath = append(check.objPath, obj) + return len(check.objPath) - 1 +} + +// pop pops and returns the topmost object from the object path. +func (check *Checker) pop() Object { + i := len(check.objPath) - 1 + obj := check.objPath[i] + check.objPath[i] = nil + check.objPath = check.objPath[:i] + return obj +} + +// pathString returns a string of the form a->b-> ... ->g for an object path [a, b, ... g]. +func (check *Checker) pathString() string { + var s string + for i, p := range check.objPath { + if i > 0 { + s += "->" + } + s += p.Name() + } + return s +} + // NewChecker returns a new Checker instance for a given package. // Package files may be added incrementally via checker.Files. func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker { diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 288ba8e447..e8e01541a3 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -49,15 +49,18 @@ func pathString(path []*TypeName) string { return s } +// useCycleMarking enables the new coloring-based cycle marking scheme +// for package-level objects. Set this flag to false to disable this +// code quickly and revert to the existing mechanism (and comment out +// some of the new tests in cycles5.src that will fail again). +// TODO(gri) remove this for Go 1.12 +const useCycleMarking = true + // objDecl type-checks the declaration of obj in its respective (file) context. // See check.typ for the details on def and path. func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) { - if obj.Type() != nil { - return // already checked - nothing to do - } - if trace { - check.trace(obj.Pos(), "-- checking %s (path = %s)", obj, pathString(path)) + check.trace(obj.Pos(), "-- checking %s %s (path = %s, objPath = %s)", obj.color(), obj, pathString(path), check.pathString()) check.indent++ defer func() { check.indent-- @@ -65,6 +68,114 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) { }() } + // Checking the declaration of obj means inferring its type + // (and possibly its value, for constants). + // An object's type (and thus the object) may be in one of + // three states which are expressed by colors: + // + // - an object whose type is not yet known is painted white (initial color) + // - an object whose type is in the process of being inferred is painted grey + // - an object whose type is fully inferred is painted black + // + // During type inference, an object's color changes from white to grey + // to black (pre-declared objects are painted black from the start). + // A black object (i.e., its type) can only depend on (refer to) other black + // ones. White and grey objects may depend on white and black objects. + // A dependency on a grey object indicates a cycle which may or may not be + // valid. + // + // When objects turn grey, they are pushed on the object path (a stack); + // they are popped again when they turn black. Thus, if a grey object (a + // cycle) is encountered, it is on the object path, and all the objects + // it depends on are the remaining objects on that path. Color encoding + // is such that the color value of a grey object indicates the index of + // that object in the object path. + + // During type-checking, white objects may be assigned a type without + // traversing through objDecl; e.g., when initializing constants and + // variables. Update the colors of those objects here (rather than + // everywhere where we set the type) to satisfy the color invariants. + if obj.color() == white && obj.Type() != nil { + obj.setColor(black) + return + } + + switch obj.color() { + case white: + assert(obj.Type() == nil) + // All color values other than white and black are considered grey. + // Because black and white are < grey, all values >= grey are grey. + // Use those values to encode the object's index into the object path. + obj.setColor(grey + color(check.push(obj))) + defer func() { + check.pop().setColor(black) + }() + + case black: + assert(obj.Type() != nil) + return + + default: + // Color values other than white or black are considered grey. + fallthrough + + case grey: + // We have a cycle. + // In the existing code, this is marked by a non-nil type + // for the object except for constants and variables whose + // type may be non-nil (known), or nil if it depends on the + // not-yet known initialization value. + // In the former case, set the type to Typ[Invalid] because + // we have an initialization cycle. The cycle error will be + // reported later, when determining initialization order. + // TODO(gri) Report cycle here and simplify initialization + // order code. + switch obj := obj.(type) { + case *Const: + if useCycleMarking && check.typeCycle(obj) { + obj.typ = Typ[Invalid] + break + } + if obj.typ == nil { + obj.typ = Typ[Invalid] + } + + case *Var: + if useCycleMarking && check.typeCycle(obj) { + obj.typ = Typ[Invalid] + break + } + if obj.typ == nil { + obj.typ = Typ[Invalid] + } + + case *TypeName: + if useCycleMarking && check.typeCycle(obj) { + // break cycle + // (without this, calling underlying() + // below may lead to an endless loop + // if we have a cycle for a defined + // (*Named) type) + obj.typ = Typ[Invalid] + } + + case *Func: + if useCycleMarking && check.typeCycle(obj) { + // Don't set obj.typ to Typ[Invalid] here + // because plenty of code type-asserts that + // functions have a *Signature type. Grey + // functions have their type set to an empty + // signature which makes it impossible to + // initialize a variable with the function. + } + + default: + unreachable() + } + assert(obj.Type() != nil) + return + } + d := check.objMap[obj] if d == nil { check.dump("%v: %s should have been declared", obj.Pos(), obj) @@ -102,15 +213,89 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) { } } +// indir is a sentinel type name that is pushed onto the object path +// to indicate an "indirection" in the dependency from one type name +// to the next. For instance, for "type p *p" the object path contains +// p followed by indir, indicating that there's an indirection *p. +// Indirections are used to break type cycles. +var indir = NewTypeName(token.NoPos, nil, "*", nil) + +// typeCycle checks if the cycle starting with obj is valid and +// reports an error if it is not. +// TODO(gri) rename s/typeCycle/cycle/ once we don't need the other +// cycle method anymore. +func (check *Checker) typeCycle(obj Object) bool { + d := check.objMap[obj] + if d == nil { + check.dump("%v: %s should have been declared", obj.Pos(), obj) + unreachable() + } + + // We distinguish between cycles involving only constants and variables + // (nval = len(cycle)), cycles involving types (and functions) only + // (nval == 0), and mixed cycles (nval != 0 && nval != len(cycle)). + // We ignore functions at the moment (taking them into account correctly + // is complicated and it doesn't improve error reporting significantly). + // + // A cycle must have at least one indirection and one type definition + // to be permitted: If there is no indirection, the size of the type + // cannot be computed (it's either infinite or 0); if there is no type + // definition, we have a sequence of alias type names which will expand + // ad infinitum. + var nval int + var hasIndir, hasTDef bool + assert(obj.color() >= grey) + start := obj.color() - grey // index of obj in objPath + cycle := check.objPath[start:] + for _, obj := range cycle { + switch obj := obj.(type) { + case *Const, *Var: + nval++ + case *TypeName: + if obj == indir { + hasIndir = true + } else if !check.objMap[obj].alias { + hasTDef = true + } + case *Func: + // ignored for now + default: + unreachable() + } + } + + // A cycle involving only constants and variables is invalid but we + // ignore them here because they are reported via the initialization + // cycle check. + if nval == len(cycle) { + return false + } + + // A cycle involving only types (and possibly functions) must have at + // least one indirection and one type definition to be permitted: If + // there is no indirection, the size of the type cannot be computed + // (it's either infinite or 0); if there is no type definition, we + // have a sequence of alias type names which will expand ad infinitum. + if nval == 0 && hasIndir && hasTDef { + return false // cycle is permitted + } + + // report cycle + check.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name()) + for _, obj := range cycle { + if obj == indir { + continue // don't print indir sentinels + } + check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented + } + check.errorf(obj.Pos(), "\t%s", obj.Name()) + + return true +} + func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) { assert(obj.typ == nil) - if obj.visited { - obj.typ = Typ[Invalid] - return - } - obj.visited = true - // use the correct value of iota check.iota = obj.val defer func() { check.iota = nil }() @@ -144,12 +329,6 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) { func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { assert(obj.typ == nil) - if obj.visited { - obj.typ = Typ[Invalid] - return - } - obj.visited = true - // determine type, if any if typ != nil { obj.typ = check.typ(typ) @@ -279,7 +458,7 @@ func (check *Checker) addMethodDecls(obj *TypeName) { return } delete(check.methods, obj) - assert(!obj.IsAlias()) + assert(!check.objMap[obj].alias) // don't use TypeName.IsAlias (requires fully set up object) // use an objset to check for name conflicts var mset objset diff --git a/src/go/types/errors.go b/src/go/types/errors.go index 0c0049b1f3..4c8d8537ee 100644 --- a/src/go/types/errors.go +++ b/src/go/types/errors.go @@ -67,10 +67,20 @@ func (check *Checker) dump(format string, args ...interface{}) { } func (check *Checker) err(pos token.Pos, msg string, soft bool) { + // Cheap trick: Don't report errors with messages containing + // "invalid operand" or "invalid type" as those tend to be + // follow-on errors which don't add useful information. Only + // exclude them if these strings are not at the beginning, + // and only if we have at least one error already reported. + if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) { + return + } + err := Error{check.fset, pos, msg, soft} if check.firstErr == nil { check.firstErr = err } + f := check.conf.Error if f == nil { panic(bailout{}) // report only first error diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 0a2a811bd8..3f3c4f83c6 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1064,7 +1064,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { break } } - typ = check.typ(e.Type) + typ = check.typExpr(e.Type, nil, nil) base = typ case hint != nil: diff --git a/src/go/types/interfaces.go b/src/go/types/interfaces.go index b4efebae5d..e4b42dc5a3 100644 --- a/src/go/types/interfaces.go +++ b/src/go/types/interfaces.go @@ -144,7 +144,7 @@ func (check *Checker) infoFromTypeLit(scope *Scope, iface *ast.InterfaceType, tn } if trace { - check.trace(iface.Pos(), "-- collect methods for %v (path = %s)", iface, pathString(path)) + check.trace(iface.Pos(), "-- collect methods for %v (path = %s, objPath = %s)", iface, pathString(path), check.pathString()) check.indent++ defer func() { check.indent-- diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go index 02af0cf51b..8560bb9b7d 100644 --- a/src/go/types/issues_test.go +++ b/src/go/types/issues_test.go @@ -314,3 +314,44 @@ func TestIssue22525(t *testing.T) { t.Errorf("got: %swant: %s", got, want) } } + +func TestIssue25627(t *testing.T) { + const prefix = `package p; import "unsafe"; type P *struct{}; type I interface{}; type T ` + // The src strings (without prefix) are constructed such that the number of semicolons + // plus one corresponds to the number of fields expected in the respective struct. + for _, src := range []string{ + `struct { x Missing }`, + `struct { Missing }`, + `struct { *Missing }`, + `struct { unsafe.Pointer }`, + `struct { P }`, + `struct { *I }`, + `struct { a int; b Missing; *Missing }`, + } { + f, err := parser.ParseFile(fset, "", prefix+src, 0) + if err != nil { + t.Fatal(err) + } + + cfg := Config{Importer: importer.Default(), Error: func(err error) {}} + info := &Info{Types: make(map[ast.Expr]TypeAndValue)} + _, err = cfg.Check(f.Name.Name, fset, []*ast.File{f}, info) + if err != nil { + if _, ok := err.(Error); !ok { + t.Fatal(err) + } + } + + ast.Inspect(f, func(n ast.Node) bool { + if spec, _ := n.(*ast.TypeSpec); spec != nil { + if tv, ok := info.Types[spec.Type]; ok && spec.Name.Name == "T" { + want := strings.Count(src, ";") + 1 + if got := tv.Type.(*Struct).NumFields(); got != want { + t.Errorf("%s: got %d fields; want %d", src, got, want) + } + } + } + return true + }) + } +} diff --git a/src/go/types/object.go b/src/go/types/object.go index f158e2733f..07adfbc34c 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -34,9 +34,15 @@ type Object interface { // 0 for all other objects (including objects in file scopes). order() uint32 + // color returns the object's color. + color() color + // setOrder sets the order number of the object. It must be > 0. setOrder(uint32) + // setColor sets the object's color. It must not be white. + setColor(color color) + // setParent sets the parent scope of the object. setParent(*Scope) @@ -78,9 +84,41 @@ type object struct { name string typ Type order_ uint32 + color_ color scopePos_ token.Pos } +// color encodes the color of an object (see Checker.objDecl for details). +type color uint32 + +// An object may be painted in one of three colors. +// Color values other than white or black are considered grey. +const ( + white color = iota + black + grey // must be > white and black +) + +func (c color) String() string { + switch c { + case white: + return "white" + case black: + return "black" + default: + return "grey" + } +} + +// colorFor returns the (initial) color for an object depending on +// whether its type t is known or not. +func colorFor(t Type) color { + if t != nil { + return black + } + return white +} + // Parent returns the scope in which the object is declared. // The result is nil for methods and struct fields. func (obj *object) Parent() *Scope { return obj.parent } @@ -108,10 +146,12 @@ func (obj *object) Id() string { return Id(obj.pkg, obj.name) } func (obj *object) String() string { panic("abstract") } func (obj *object) order() uint32 { return obj.order_ } +func (obj *object) color() color { return obj.color_ } func (obj *object) scopePos() token.Pos { return obj.scopePos_ } func (obj *object) setParent(parent *Scope) { obj.parent = parent } func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = order } +func (obj *object) setColor(color color) { assert(color != white); obj.color_ = color } func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos } func (obj *object) sameId(pkg *Package, name string) bool { @@ -147,7 +187,7 @@ type PkgName struct { // NewPkgName returns a new PkgName object representing an imported package. // The remaining arguments set the attributes found with all Objects. func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName { - return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, token.NoPos}, imported, false} + return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, token.NoPos}, imported, false} } // Imported returns the package that was imported. @@ -157,14 +197,13 @@ func (obj *PkgName) Imported() *Package { return obj.imported } // A Const represents a declared constant. type Const struct { object - val constant.Value - visited bool // for initialization cycle detection + val constant.Value } // NewConst returns a new constant with value val. // The remaining arguments set the attributes found with all Objects. func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val constant.Value) *Const { - return &Const{object{nil, pos, pkg, name, typ, 0, token.NoPos}, val, false} + return &Const{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, val} } // Val returns the constant's value. @@ -185,7 +224,7 @@ type TypeName struct { // argument for NewNamed, which will set the TypeName's type as a side- // effect. func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName { - return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}} + return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}} } // IsAlias reports whether obj is an alias name for a type. @@ -216,7 +255,6 @@ func (obj *TypeName) IsAlias() bool { type Var struct { object embedded bool // if set, the variable is an embedded struct field, and name is the type name - visited bool // for initialization cycle detection isField bool // var is struct field used bool // set if the variable was used } @@ -224,19 +262,19 @@ type Var struct { // NewVar returns a new variable. // The arguments set the attributes found with all Objects. func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var { - return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}} + return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}} } // NewParam returns a new variable representing a function parameter. func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var { - return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, used: true} // parameters are always 'used' + return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, used: true} // parameters are always 'used' } // NewField returns a new variable representing a struct field. // For embedded fields, the name is the unqualified type name /// under which the field is accessible. func NewField(pos token.Pos, pkg *Package, name string, typ Type, embedded bool) *Var { - return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, embedded: embedded, isField: true} + return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, embedded: embedded, isField: true} } // Anonymous reports whether the variable is an embedded field. @@ -266,7 +304,7 @@ func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func { if sig != nil { typ = sig } - return &Func{object{nil, pos, pkg, name, typ, 0, token.NoPos}} + return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}} } // FullName returns the package- or receiver-type-qualified name of @@ -291,7 +329,7 @@ type Label struct { // NewLabel returns a new label. func NewLabel(pos token.Pos, pkg *Package, name string) *Label { - return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid]}, false} + return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid], color_: black}, false} } // A Builtin represents a built-in function. @@ -302,7 +340,7 @@ type Builtin struct { } func newBuiltin(id builtinId) *Builtin { - return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid]}, id} + return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid], color_: black}, id} } // Nil represents the predeclared value nil. diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index ad4c51f74d..229d203099 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -174,6 +174,8 @@ func TestStdFixed(t *testing.T) { "issue20529.go", // go/types does not have constraints on stack size "issue22200.go", // go/types does not have constraints on stack size "issue22200b.go", // go/types does not have constraints on stack size + "issue25507.go", // go/types does not have constraints on stack size + "issue20780.go", // go/types does not have constraints on stack size ) } diff --git a/src/go/types/testdata/cycles.src b/src/go/types/testdata/cycles.src index 79e75e9316..59f112dba1 100644 --- a/src/go/types/testdata/cycles.src +++ b/src/go/types/testdata/cycles.src @@ -147,7 +147,7 @@ type ( // test cases for issue 18643 // (type cycle detection when non-type expressions are involved) type ( - T14 [len(T14 /* ERROR cycle */ {})]int + T14 /* ERROR cycle */ [len(T14{})]int T15 [][len(T15 /* ERROR cycle */ {})]int T16 map[[len(T16 /* ERROR cycle */ {1:2})]int]int T17 map[int][len(T17 /* ERROR cycle */ {1:2})]int diff --git a/src/go/types/testdata/cycles2.src b/src/go/types/testdata/cycles2.src index 345ab56ea6..a7f4bc60f5 100644 --- a/src/go/types/testdata/cycles2.src +++ b/src/go/types/testdata/cycles2.src @@ -69,47 +69,38 @@ type T interface { // Variations of this test case. -type T1 interface { - m() [x1 /* ERROR no value */ .m()[0]]int +type T1 /* ERROR cycle */ interface { + m() [x1.m()[0]]int } var x1 T1 -type T2 interface { - m() [len(x2 /* ERROR no value */ .m())]int +type T2 /* ERROR cycle */ interface { + m() [len(x2.m())]int } var x2 T2 -type T3 interface { +type T3 /* ERROR cycle */ interface { m() [unsafe.Sizeof(x3.m)]int } var x3 T3 -// The test case below should also report an error for -// the cast inside the T4 interface (like it does for the -// variable initialization). The reason why it does not is -// that inside T4, the method x4.m depends on T4 which is not -// fully set up yet. The x4.m method happens to have an empty -// signature which is why the cast is permitted. -// TODO(gri) Consider marking methods as incomplete and provide -// a better error message in that case. - -type T4 interface { +type T4 /* ERROR cycle */ interface { m() [unsafe.Sizeof(cast4(x4.m))]int } var x4 T4 -var _ = cast4(x4 /* ERROR cannot convert */.m) +var _ = cast4(x4.m) type cast4 func() // This test is symmetric to the T4 case: Here the cast is // "correct", but it doesn't work inside the T5 interface. -type T5 interface { - m() [unsafe.Sizeof(cast5(x5 /* ERROR cannot convert */ .m))]int +type T5 /* ERROR cycle */ interface { + m() [unsafe.Sizeof(cast5(x5.m))]int } var x5 T5 diff --git a/src/go/types/testdata/cycles3.src b/src/go/types/testdata/cycles3.src index 3da4fb5761..5e89b627f0 100644 --- a/src/go/types/testdata/cycles3.src +++ b/src/go/types/testdata/cycles3.src @@ -48,7 +48,7 @@ type ( ) type ( - U interface { + U /* ERROR cycle */ interface { V } diff --git a/src/go/types/testdata/cycles5.src b/src/go/types/testdata/cycles5.src index aab9ee235e..9c2822e738 100644 --- a/src/go/types/testdata/cycles5.src +++ b/src/go/types/testdata/cycles5.src @@ -97,12 +97,12 @@ var _ = err.Error() // more esoteric cases type ( - T1 interface { T2 /* ERROR not an interface */ } + T1 interface { T2 } T2 /* ERROR cycle */ T2 ) type ( - T3 interface { T4 /* ERROR not an interface */ } + T3 interface { T4 } T4 /* ERROR cycle */ T5 T5 = T6 T6 = T7 @@ -117,3 +117,65 @@ const n = unsafe.Sizeof(func(){}) type I interface { m([unsafe.Sizeof(func() { I.m(nil, [n]byte{}) })]byte) } + + +// test cases for varias alias cycles + +type T10 /* ERROR cycle */ = *T10 // issue #25141 +type T11 /* ERROR cycle */ = interface{ f(T11) } // issue #23139 + +// issue #18640 +type ( + aa = bb + bb struct { + *aa + } +) + +type ( + a struct{ *b } + b = c + c struct{ *b } +) + +// issue #24939 +type ( + _ interface { + M(P) + } + + M interface { + F() P + } + + P = interface { + I() M + } +) + +// issue #8699 +type T12 /* ERROR cycle */ [len(a12)]int +var a12 = makeArray() +func makeArray() (res T12) { return } + +// issue #20770 +var r /* ERROR cycle */ = newReader() +func newReader() r + +// variations of the theme of #8699 amd #20770 +var arr /* ERROR cycle */ = f() +func f() [len(arr)]int + +// TODO(gri) here we should only get one error +func ff /* ERROR cycle */ (ff /* ERROR not a type */ ) + +type T13 /* ERROR cycle */ [len(b13)]int +var b13 T13 + +func g /* ERROR cycle */ () [unsafe.Sizeof(x)]int +var x = g + +func h /* ERROR cycle */ () [h /* ERROR no value */ ()[0]]int { panic(0) } + +var c14 /* ERROR cycle */ T14 +type T14 [uintptr(unsafe.Sizeof(&c14))]byte diff --git a/src/go/types/testdata/decls0.src b/src/go/types/testdata/decls0.src index 75d442bc13..162dfeda04 100644 --- a/src/go/types/testdata/decls0.src +++ b/src/go/types/testdata/decls0.src @@ -184,10 +184,10 @@ type ( // cycles in function/method declarations // (test cases for issue 5217 and variants) -func f1(x f1 /* ERROR "not a type" */ ) {} -func f2(x *f2 /* ERROR "not a type" */ ) {} -func f3() (x f3 /* ERROR "not a type" */ ) { return } -func f4() (x *f4 /* ERROR "not a type" */ ) { return } +func f1 /* ERROR cycle */ (x f1 /* ERROR "not a type" */ ) {} +func f2 /* ERROR cycle */ (x *f2 /* ERROR "not a type" */ ) {} +func f3 /* ERROR cycle */ () (x f3 /* ERROR "not a type" */ ) { return } +func f4 /* ERROR cycle */ () (x *f4 /* ERROR "not a type" */ ) { return } func (S0) m1(x S0.m1 /* ERROR "field or method" */ ) {} func (S0) m2(x *S0.m2 /* ERROR "field or method" */ ) {} diff --git a/src/go/types/testdata/decls3.src b/src/go/types/testdata/decls3.src index 3071fdae5e..18ddf5859c 100644 --- a/src/go/types/testdata/decls3.src +++ b/src/go/types/testdata/decls3.src @@ -99,9 +99,9 @@ func _() { // unsafe.Pointers are treated like regular pointers when embedded type T2 struct { unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer - */* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer + */* ERROR "cannot be unsafe.Pointer" */ /* ERROR "Pointer redeclared" */ unsafe.Pointer UP /* ERROR "cannot be unsafe.Pointer" */ - * /* ERROR "cannot be unsafe.Pointer" */ UP + * /* ERROR "cannot be unsafe.Pointer" */ /* ERROR "UP redeclared" */ UP } } diff --git a/src/go/types/testdata/errors.src b/src/go/types/testdata/errors.src index 29fcd8fe1d..ff929217c4 100644 --- a/src/go/types/testdata/errors.src +++ b/src/go/types/testdata/errors.src @@ -53,3 +53,8 @@ func _() { // Use unqualified names for package-local objects. type T struct{} var _ int = T /* ERROR value of type T */ {} // use T in error message rather then errors.T + +// Don't report errors containing "invalid type" (issue #24182). +func _(x *missing /* ERROR undeclared name: missing */ ) { + x.m() // there shouldn't be an error here referring to *invalid type +} diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src index 9750bdc2e2..d727c3b3e2 100644 --- a/src/go/types/testdata/issues.src +++ b/src/go/types/testdata/issues.src @@ -97,7 +97,7 @@ func issue10979() { // issue11347 // These should not crash. -var a1, b1 /* ERROR cycle */ , c1 /* ERROR cycle */ b1 = 0 > 0<<""[""[c1]]>c1 +var a1, b1 /* ERROR cycle */ /* ERROR cycle */ , c1 /* ERROR cycle */ b1 = 0 > 0<<""[""[c1]]>c1 var a2, b2 /* ERROR cycle */ = 0 /* ERROR cannot initialize */ /* ERROR cannot initialize */ > 0<<""[b2] var a3, b3 /* ERROR cycle */ = int /* ERROR cannot initialize */ /* ERROR cannot initialize */ (1<<""[b3]) diff --git a/src/go/types/type.go b/src/go/types/type.go index f274e30ab6..60e3efaec3 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -264,18 +264,17 @@ var markComplete = make([]*Func, 0) // to be embedded. This is necessary for interfaces that embed alias type names referring to // non-defined (literal) interface types. func NewInterface(methods []*Func, embeddeds []*Named) *Interface { - var tnames []Type - if len(embeddeds) > 0 { - tnames := make([]Type, len(embeddeds)) - for i, t := range embeddeds { - tnames[i] = t - } + tnames := make([]Type, len(embeddeds)) + for i, t := range embeddeds { + tnames[i] = t } return NewInterface2(methods, tnames) } // NewInterface2 returns a new (incomplete) interface for the given methods and embedded types. -// Each embedded type must have an underlying type of interface type. +// Each embedded type must have an underlying type of interface type (this property is not +// verified for defined types, which may be in the process of being set up and which don't +// have a valid underlying type yet). // NewInterface2 takes ownership of the provided methods and may modify their types by setting // missing receivers. To compute the method set of the interface, Complete must be called. func NewInterface2(methods []*Func, embeddeds []Type) *Interface { @@ -298,8 +297,12 @@ func NewInterface2(methods []*Func, embeddeds []Type) *Interface { sort.Sort(byUniqueMethodName(methods)) if len(embeddeds) > 0 { + // All embedded types should be interfaces; however, defined types + // may not yet be fully resolved. Only verify that non-defined types + // are interfaces. This matches the behavior of the code before the + // fix for #25301 (issue #25596). for _, t := range embeddeds { - if !IsInterface(t) { + if _, ok := t.(*Named); !ok && !IsInterface(t) { panic("embedded type is not an interface") } } @@ -350,27 +353,24 @@ func (t *Interface) Complete() *Interface { } var allMethods []*Func - if t.embeddeds == nil { - if t.methods == nil { - allMethods = make([]*Func, 0, 1) - } else { - allMethods = t.methods + allMethods = append(allMethods, t.methods...) + for _, et := range t.embeddeds { + it := et.Underlying().(*Interface) + it.Complete() + for _, tm := range it.allMethods { + // Make a copy of the method and adjust its receiver type. + newm := *tm + newmtyp := *tm.typ.(*Signature) + newm.typ = &newmtyp + newmtyp.recv = NewVar(newm.pos, newm.pkg, "", t) + allMethods = append(allMethods, &newm) } - } else { - allMethods = append(allMethods, t.methods...) - for _, et := range t.embeddeds { - it := et.Underlying().(*Interface) - it.Complete() - for _, tm := range it.allMethods { - // Make a copy of the method and adjust its receiver type. - newm := *tm - newmtyp := *tm.typ.(*Signature) - newm.typ = &newmtyp - newmtyp.recv = NewVar(newm.pos, newm.pkg, "", t) - allMethods = append(allMethods, &newm) - } - } - sort.Sort(byUniqueMethodName(allMethods)) + } + sort.Sort(byUniqueMethodName(allMethods)) + + // t.methods and/or t.embeddeds may have been empty + if allMethods == nil { + allMethods = markComplete } t.allMethods = allMethods diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go index 78f67d1f05..6ed2d75dfe 100644 --- a/src/go/types/typestring_test.go +++ b/src/go/types/typestring_test.go @@ -140,16 +140,41 @@ func TestTypeString(t *testing.T) { func TestIncompleteInterfaces(t *testing.T) { sig := NewSignature(nil, nil, nil, false) + m := NewFunc(token.NoPos, nil, "m", sig) for _, test := range []struct { typ *Interface want string }{ {new(Interface), "interface{/* incomplete */}"}, {new(Interface).Complete(), "interface{}"}, + + {NewInterface(nil, nil), "interface{/* incomplete */}"}, + {NewInterface(nil, nil).Complete(), "interface{}"}, + {NewInterface([]*Func{}, nil), "interface{/* incomplete */}"}, + {NewInterface([]*Func{}, nil).Complete(), "interface{}"}, + {NewInterface(nil, []*Named{}), "interface{/* incomplete */}"}, + {NewInterface(nil, []*Named{}).Complete(), "interface{}"}, + {NewInterface([]*Func{m}, nil), "interface{m() /* incomplete */}"}, + {NewInterface([]*Func{m}, nil).Complete(), "interface{m()}"}, + {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}), "interface{T /* incomplete */}"}, + {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}).Complete(), "interface{T}"}, + {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil))}), "interface{T /* incomplete */}"}, + {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}), "interface{T /* incomplete */}"}, + {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}).Complete(), "interface{T}"}, + {NewInterface2(nil, nil), "interface{/* incomplete */}"}, {NewInterface2(nil, nil).Complete(), "interface{}"}, - {NewInterface2([]*Func{NewFunc(token.NoPos, nil, "m", sig)}, nil), "interface{m() /* incomplete */}"}, - {NewInterface2([]*Func{NewFunc(token.NoPos, nil, "m", sig)}, nil).Complete(), "interface{m()}"}, + {NewInterface2([]*Func{}, nil), "interface{/* incomplete */}"}, + {NewInterface2([]*Func{}, nil).Complete(), "interface{}"}, + {NewInterface2(nil, []Type{}), "interface{/* incomplete */}"}, + {NewInterface2(nil, []Type{}).Complete(), "interface{}"}, + {NewInterface2([]*Func{m}, nil), "interface{m() /* incomplete */}"}, + {NewInterface2([]*Func{m}, nil).Complete(), "interface{m()}"}, + {NewInterface2(nil, []Type{new(Interface).Complete()}), "interface{interface{} /* incomplete */}"}, + {NewInterface2(nil, []Type{new(Interface).Complete()}).Complete(), "interface{interface{}}"}, + {NewInterface2(nil, []Type{NewInterface2([]*Func{m}, nil)}), "interface{interface{m() /* incomplete */} /* incomplete */}"}, + {NewInterface2(nil, []Type{NewInterface2([]*Func{m}, nil).Complete()}), "interface{interface{m()} /* incomplete */}"}, + {NewInterface2(nil, []Type{NewInterface2([]*Func{m}, nil).Complete()}).Complete(), "interface{interface{m()}}"}, } { got := test.typ.String() if got != test.want { @@ -158,6 +183,13 @@ func TestIncompleteInterfaces(t *testing.T) { } } +// newDefined creates a new defined type named T with the given underlying type. +// Helper function for use with TestIncompleteInterfaces only. +func newDefined(underlying Type) *Named { + tname := NewTypeName(token.NoPos, nil, "T", nil) + return NewNamed(tname, underlying, nil) +} + func TestQualifiedTypeString(t *testing.T) { p, _ := pkgFor("p.go", "package p; type T int", nil) q, _ := pkgFor("q.go", "package q", nil) diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 999383ed27..45ada5874b 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -71,6 +71,12 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa case *TypeName: x.mode = typexpr + // package-level alias cycles are now checked by Checker.objDecl + if useCycleMarking { + if check.objMap[obj] != nil { + break + } + } if check.cycle(obj, path, true) { // maintain x.mode == typexpr despite error typ = Typ[Invalid] @@ -132,7 +138,11 @@ func (check *Checker) cycle(obj *TypeName, path []*TypeName, report bool) bool { // If def != nil, e is the type specification for the named type def, declared // in a type declaration, and def.underlying will be set to the type of e before // any components of e are type-checked. Path contains the path of named types -// referring to this type. +// referring to this type; i.e. it is the path of named types directly containing +// each other and leading to the current type e. Indirect containment (e.g. via +// pointer indirection, function parameter, etc.) breaks the path (leads to a new +// path, and usually via calling Checker.typ below) and those types are not found +// in the path. // func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) { if trace { @@ -151,7 +161,18 @@ func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) return } +// typ is like typExpr (with a nil argument for the def parameter), +// but typ breaks type cycles. It should be called for components of +// types that break cycles, such as pointer base types, slice or map +// element types, etc. See the comment in typExpr for details. +// func (check *Checker) typ(e ast.Expr) Type { + // typExpr is called with a nil path indicating an indirection: + // push indir sentinel on object path + if useCycleMarking { + check.push(indir) + defer check.pop() + } return check.typExpr(e, nil, nil) } @@ -677,6 +698,16 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa } } + // addInvalid adds an embedded field of invalid type to the struct for + // fields with errors; this keeps the number of struct fields in sync + // with the source as long as the fields are _ or have different names + // (issue #25627). + addInvalid := func(ident *ast.Ident, pos token.Pos) { + typ = Typ[Invalid] + tag = "" + add(ident, true, pos) + } + for _, f := range list.List { typ = check.typExpr(f.Type, nil, path) tag = check.tag(f.Tag) @@ -693,6 +724,9 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa name := embeddedFieldIdent(f.Type) if name == nil { check.invalidAST(pos, "embedded field type %s has no name", f.Type) + name = ast.NewIdent("_") + name.NamePos = pos + addInvalid(name, pos) continue } t, isPtr := deref(typ) @@ -702,22 +736,26 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa case *Basic: if t == Typ[Invalid] { // error was reported before + addInvalid(name, pos) continue } // unsafe.Pointer is treated like a regular pointer if t.kind == UnsafePointer { check.errorf(pos, "embedded field type cannot be unsafe.Pointer") + addInvalid(name, pos) continue } case *Pointer: check.errorf(pos, "embedded field type cannot be a pointer") + addInvalid(name, pos) continue case *Interface: if isPtr { check.errorf(pos, "embedded field type cannot be a pointer to an interface") + addInvalid(name, pos) continue } } diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 286ef7ba46..2ae8a31970 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -102,7 +102,7 @@ func defPredeclaredConsts() { } func defPredeclaredNil() { - def(&Nil{object{name: "nil", typ: Typ[UntypedNil]}}) + def(&Nil{object{name: "nil", typ: Typ[UntypedNil], color_: black}}) } // A builtinId is the id of a builtin function. @@ -207,6 +207,7 @@ func init() { // scope; other objects are inserted in the universe scope. // func def(obj Object) { + assert(obj.color() == black) name := obj.Name() if strings.Contains(name, " ") { return // nothing to do diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go index 1912caa212..908b84adcb 100644 --- a/src/hash/crc32/crc32.go +++ b/src/hash/crc32/crc32.go @@ -3,12 +3,12 @@ // license that can be found in the LICENSE file. // Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32, -// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for +// checksum. See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for // information. // // Polynomials are represented in LSB-first form also known as reversed representation. // -// See http://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials +// See https://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials // for information. package crc32 @@ -29,12 +29,12 @@ const ( // Castagnoli's polynomial, used in iSCSI. // Has better error detection characteristics than IEEE. - // http://dx.doi.org/10.1109/26.231911 + // https://dx.doi.org/10.1109/26.231911 Castagnoli = 0x82f63b78 // Koopman's polynomial. // Also has better error detection characteristics than IEEE. - // http://dx.doi.org/10.1109/DSN.2002.1028931 + // https://dx.doi.org/10.1109/DSN.2002.1028931 Koopman = 0xeb31d82e ) diff --git a/src/hash/crc32/crc32_amd64.s b/src/hash/crc32/crc32_amd64.s index a944ead9b2..6af6c253a7 100644 --- a/src/hash/crc32/crc32_amd64.s +++ b/src/hash/crc32/crc32_amd64.s @@ -149,7 +149,7 @@ GLOBL r4r3<>(SB),RODATA,$16 GLOBL rupoly<>(SB),RODATA,$16 GLOBL r5<>(SB),RODATA,$8 -// Based on http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf +// Based on https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf // len(p) must be at least 64, and must be a multiple of 16. // func ieeeCLMUL(crc uint32, p []byte) uint32 diff --git a/src/hash/crc64/crc64.go b/src/hash/crc64/crc64.go index 3b24c24406..a799a017c9 100644 --- a/src/hash/crc64/crc64.go +++ b/src/hash/crc64/crc64.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package crc64 implements the 64-bit cyclic redundancy check, or CRC-64, -// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for +// checksum. See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for // information. package crc64 diff --git a/src/html/template/attr.go b/src/html/template/attr.go index 92d2789e80..22922e6038 100644 --- a/src/html/template/attr.go +++ b/src/html/template/attr.go @@ -13,9 +13,9 @@ import ( // other content, or affects the contents, idempotency, or credentials of a // network message, then the value in this map is contentTypeUnsafe. // This map is derived from HTML5, specifically -// http://www.w3.org/TR/html5/Overview.html#attributes-1 +// https://www.w3.org/TR/html5/Overview.html#attributes-1 // as well as "%URI"-typed attributes from -// http://www.w3.org/TR/html4/index/attributes.html +// https://www.w3.org/TR/html4/index/attributes.html var attrTypeMap = map[string]contentType{ "accept": contentTypePlain, "accept-charset": contentTypeUnsafe, @@ -90,7 +90,7 @@ var attrTypeMap = map[string]contentType{ "name": contentTypePlain, "novalidate": contentTypeUnsafe, // Skip handler names from - // http://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects + // https://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects // since we have special handling in attrType. "open": contentTypePlain, "optimum": contentTypePlain, @@ -160,7 +160,7 @@ func attrType(name string) contentType { // Heuristics to prevent "javascript:..." injection in custom // data attributes and custom attributes like g:tweetUrl. - // http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes + // https://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes // "Custom data attributes are intended to store custom data // private to the page or application, for which there are no // more appropriate attributes or elements." diff --git a/src/html/template/content.go b/src/html/template/content.go index e7cdedc3b6..4aadf64df2 100644 --- a/src/html/template/content.go +++ b/src/html/template/content.go @@ -16,7 +16,7 @@ type ( // 2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`. // 3. CSS3 declaration productions, such as `color: red; margin: 2px`. // 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`. - // See http://www.w3.org/TR/css3-syntax/#parsing and + // See https://www.w3.org/TR/css3-syntax/#parsing and // https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style // // Use of this type presents a security risk: @@ -85,7 +85,7 @@ type ( URL string // Srcset encapsulates a known safe srcset attribute - // (see http://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset). + // (see https://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset). // // Use of this type presents a security risk: // the encapsulated content should come from a trusted source, diff --git a/src/html/template/context.go b/src/html/template/context.go index fdbf7e25ee..45be3a6a9f 100644 --- a/src/html/template/context.go +++ b/src/html/template/context.go @@ -13,7 +13,7 @@ import ( // // The zero value of type context is the start context for a template that // produces an HTML fragment as defined at -// http://www.w3.org/TR/html5/syntax.html#the-end +// https://www.w3.org/TR/html5/syntax.html#the-end // where the context element is null. type context struct { state state @@ -98,7 +98,7 @@ const ( // stateHTMLCmt occurs inside an . stateHTMLCmt // stateRCDATA occurs inside an RCDATA element (