diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-07-27 22:27:54 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-08-01 11:21:40 -0700 |
commit | f75af8c1464e948b5e166cf5ab09ebf0d82fc253 (patch) | |
tree | 3ba3299859b504bdeb477727471216bd094a0191 /libgo/go/golang.org/x | |
parent | 75a23e59031fe673fc3b2e60fd1fe5f4c70ecb85 (diff) | |
download | gcc-f75af8c1464e948b5e166cf5ab09ebf0d82fc253.tar.gz |
libgo: update to go1.15rc1
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/245157
Diffstat (limited to 'libgo/go/golang.org/x')
66 files changed, 1598 insertions, 605 deletions
diff --git a/libgo/go/golang.org/x/crypto/chacha20/chacha_arm64.go b/libgo/go/golang.org/x/crypto/chacha20/chacha_arm64.go index 87f1e369cc2..b799e440b4a 100644 --- a/libgo/go/golang.org/x/crypto/chacha20/chacha_arm64.go +++ b/libgo/go/golang.org/x/crypto/chacha20/chacha_arm64.go @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.11 -// +build !gccgo,!appengine +// +build go1.11,!gccgo,!purego package chacha20 diff --git a/libgo/go/golang.org/x/crypto/chacha20/chacha_generic.go b/libgo/go/golang.org/x/crypto/chacha20/chacha_generic.go index 098ec9f6be0..a2ecf5c325b 100644 --- a/libgo/go/golang.org/x/crypto/chacha20/chacha_generic.go +++ b/libgo/go/golang.org/x/crypto/chacha20/chacha_generic.go @@ -42,10 +42,14 @@ type Cipher struct { // The last len bytes of buf are leftover key stream bytes from the previous // XORKeyStream invocation. The size of buf depends on how many blocks are - // computed at a time. + // computed at a time by xorKeyStreamBlocks. buf [bufSize]byte len int + // overflow is set when the counter overflowed, no more blocks can be + // generated, and the next XORKeyStream call should panic. + overflow bool + // The counter-independent results of the first round are cached after they // are computed the first time. precompDone bool @@ -89,6 +93,7 @@ func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) { return nil, errors.New("chacha20: wrong nonce size") } + key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint c.key = [8]uint32{ binary.LittleEndian.Uint32(key[0:4]), binary.LittleEndian.Uint32(key[4:8]), @@ -136,6 +141,36 @@ func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) { return a, b, c, d } +// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will +// behave as if (64 * counter) bytes had been encrypted so far. +// +// To prevent accidental counter reuse, SetCounter panics if counter is less +// than the current value. +// +// Note that the execution time of XORKeyStream is not independent of the +// counter value. +func (s *Cipher) SetCounter(counter uint32) { + // Internally, s may buffer multiple blocks, which complicates this + // implementation slightly. When checking whether the counter has rolled + // back, we must use both s.counter and s.len to determine how many blocks + // we have already output. + outputCounter := s.counter - uint32(s.len)/blockSize + if s.overflow || counter < outputCounter { + panic("chacha20: SetCounter attempted to rollback counter") + } + + // In the general case, we set the new counter value and reset s.len to 0, + // causing the next call to XORKeyStream to refill the buffer. However, if + // we're advancing within the existing buffer, we can save work by simply + // setting s.len. + if counter < s.counter { + s.len = int(s.counter-counter) * blockSize + } else { + s.counter = counter + s.len = 0 + } +} + // XORKeyStream XORs each byte in the given slice with a byte from the // cipher's key stream. Dst and src must overlap entirely or not at all. // @@ -169,34 +204,52 @@ func (s *Cipher) XORKeyStream(dst, src []byte) { dst[i] = src[i] ^ b } s.len -= len(keyStream) - src = src[len(keyStream):] - dst = dst[len(keyStream):] + dst, src = dst[len(keyStream):], src[len(keyStream):] + } + if len(src) == 0 { + return } - const blocksPerBuf = bufSize / blockSize - numBufs := (uint64(len(src)) + bufSize - 1) / bufSize - if uint64(s.counter)+numBufs*blocksPerBuf >= 1<<32 { + // If we'd need to let the counter overflow and keep generating output, + // panic immediately. If instead we'd only reach the last block, remember + // not to generate any more output after the buffer is drained. + numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize + if s.overflow || uint64(s.counter)+numBlocks > 1<<32 { panic("chacha20: counter overflow") + } else if uint64(s.counter)+numBlocks == 1<<32 { + s.overflow = true } // xorKeyStreamBlocks implementations expect input lengths that are a // multiple of bufSize. Platform-specific ones process multiple blocks at a // time, so have bufSizes that are a multiple of blockSize. - rem := len(src) % bufSize - full := len(src) - rem - + full := len(src) - len(src)%bufSize if full > 0 { s.xorKeyStreamBlocks(dst[:full], src[:full]) } + dst, src = dst[full:], src[full:] + + // If using a multi-block xorKeyStreamBlocks would overflow, use the generic + // one that does one block at a time. + const blocksPerBuf = bufSize / blockSize + if uint64(s.counter)+blocksPerBuf > 1<<32 { + s.buf = [bufSize]byte{} + numBlocks := (len(src) + blockSize - 1) / blockSize + buf := s.buf[bufSize-numBlocks*blockSize:] + copy(buf, src) + s.xorKeyStreamBlocksGeneric(buf, buf) + s.len = len(buf) - copy(dst, buf) + return + } // If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and // keep the leftover keystream for the next XORKeyStream invocation. - if rem > 0 { + if len(src) > 0 { s.buf = [bufSize]byte{} - copy(s.buf[:], src[full:]) + copy(s.buf[:], src) s.xorKeyStreamBlocks(s.buf[:], s.buf[:]) - s.len = bufSize - copy(dst[full:], s.buf[:]) + s.len = bufSize - copy(dst, s.buf[:]) } } @@ -233,7 +286,9 @@ func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) { s.precompDone = true } - for i := 0; i < len(src); i += blockSize { + // A condition of len(src) > 0 would be sufficient, but this also + // acts as a bounds check elimination hint. + for len(src) >= 64 && len(dst) >= 64 { // The remainder of the first column round. fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter) @@ -258,49 +313,28 @@ func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) { x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) } - // Finally, add back the initial state to generate the key stream. - x0 += c0 - x1 += c1 - x2 += c2 - x3 += c3 - x4 += c4 - x5 += c5 - x6 += c6 - x7 += c7 - x8 += c8 - x9 += c9 - x10 += c10 - x11 += c11 - x12 += s.counter - x13 += c13 - x14 += c14 - x15 += c15 + // Add back the initial state to generate the key stream, then + // XOR the key stream with the source and write out the result. + addXor(dst[0:4], src[0:4], x0, c0) + addXor(dst[4:8], src[4:8], x1, c1) + addXor(dst[8:12], src[8:12], x2, c2) + addXor(dst[12:16], src[12:16], x3, c3) + addXor(dst[16:20], src[16:20], x4, c4) + addXor(dst[20:24], src[20:24], x5, c5) + addXor(dst[24:28], src[24:28], x6, c6) + addXor(dst[28:32], src[28:32], x7, c7) + addXor(dst[32:36], src[32:36], x8, c8) + addXor(dst[36:40], src[36:40], x9, c9) + addXor(dst[40:44], src[40:44], x10, c10) + addXor(dst[44:48], src[44:48], x11, c11) + addXor(dst[48:52], src[48:52], x12, s.counter) + addXor(dst[52:56], src[52:56], x13, c13) + addXor(dst[56:60], src[56:60], x14, c14) + addXor(dst[60:64], src[60:64], x15, c15) s.counter += 1 - if s.counter == 0 { - panic("chacha20: internal error: counter overflow") - } - in, out := src[i:], dst[i:] - in, out = in[:blockSize], out[:blockSize] // bounds check elimination hint - - // XOR the key stream with the source and write out the result. - xor(out[0:], in[0:], x0) - xor(out[4:], in[4:], x1) - xor(out[8:], in[8:], x2) - xor(out[12:], in[12:], x3) - xor(out[16:], in[16:], x4) - xor(out[20:], in[20:], x5) - xor(out[24:], in[24:], x6) - xor(out[28:], in[28:], x7) - xor(out[32:], in[32:], x8) - xor(out[36:], in[36:], x9) - xor(out[40:], in[40:], x10) - xor(out[44:], in[44:], x11) - xor(out[48:], in[48:], x12) - xor(out[52:], in[52:], x13) - xor(out[56:], in[56:], x14) - xor(out[60:], in[60:], x15) + src, dst = src[blockSize:], dst[blockSize:] } } diff --git a/libgo/go/golang.org/x/crypto/chacha20/chacha_noasm.go b/libgo/go/golang.org/x/crypto/chacha20/chacha_noasm.go index ec609ed868b..4635307b8f2 100644 --- a/libgo/go/golang.org/x/crypto/chacha20/chacha_noasm.go +++ b/libgo/go/golang.org/x/crypto/chacha20/chacha_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo appengine +// +build !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo purego package chacha20 diff --git a/libgo/go/golang.org/x/crypto/chacha20/chacha_ppc64le.go b/libgo/go/golang.org/x/crypto/chacha20/chacha_ppc64le.go index d0ec61f08d9..b7993303415 100644 --- a/libgo/go/golang.org/x/crypto/chacha20/chacha_ppc64le.go +++ b/libgo/go/golang.org/x/crypto/chacha20/chacha_ppc64le.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!appengine +// +build !gccgo,!purego package chacha20 diff --git a/libgo/go/golang.org/x/crypto/chacha20/chacha_s390x.go b/libgo/go/golang.org/x/crypto/chacha20/chacha_s390x.go index cd55f45a333..a9244bdf4db 100644 --- a/libgo/go/golang.org/x/crypto/chacha20/chacha_s390x.go +++ b/libgo/go/golang.org/x/crypto/chacha20/chacha_s390x.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!appengine +// +build !gccgo,!purego package chacha20 diff --git a/libgo/go/golang.org/x/crypto/chacha20/xor.go b/libgo/go/golang.org/x/crypto/chacha20/xor.go index 0110c9865af..c2d04851e0d 100644 --- a/libgo/go/golang.org/x/crypto/chacha20/xor.go +++ b/libgo/go/golang.org/x/crypto/chacha20/xor.go @@ -13,10 +13,10 @@ const unaligned = runtime.GOARCH == "386" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x" -// xor reads a little endian uint32 from src, XORs it with u and +// addXor reads a little endian uint32 from src, XORs it with (a + b) and // places the result in little endian byte order in dst. -func xor(dst, src []byte, u uint32) { - _, _ = src[3], dst[3] // eliminate bounds checks +func addXor(dst, src []byte, a, b uint32) { + _, _ = src[3], dst[3] // bounds check elimination hint if unaligned { // The compiler should optimize this code into // 32-bit unaligned little endian loads and stores. @@ -27,15 +27,16 @@ func xor(dst, src []byte, u uint32) { v |= uint32(src[1]) << 8 v |= uint32(src[2]) << 16 v |= uint32(src[3]) << 24 - v ^= u + v ^= a + b dst[0] = byte(v) dst[1] = byte(v >> 8) dst[2] = byte(v >> 16) dst[3] = byte(v >> 24) } else { - dst[0] = src[0] ^ byte(u) - dst[1] = src[1] ^ byte(u>>8) - dst[2] = src[2] ^ byte(u>>16) - dst[3] = src[3] ^ byte(u>>24) + a += b + dst[0] = src[0] ^ byte(a) + dst[1] = src[1] ^ byte(a>>8) + dst[2] = src[2] ^ byte(a>>16) + dst[3] = src[3] ^ byte(a>>24) } } diff --git a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go index 737e46aa5a4..cda77819b84 100644 --- a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go +++ b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.7,amd64,!gccgo,!appengine +// +build !gccgo,!purego package chacha20poly1305 diff --git a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go index 91b38568ce1..fe191d395d5 100644 --- a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go +++ b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go @@ -12,56 +12,64 @@ import ( "golang.org/x/crypto/poly1305" ) -func roundTo16(n int) int { - return 16 * ((n + 15) / 16) +func writeWithPadding(p *poly1305.MAC, b []byte) { + p.Write(b) + if rem := len(b) % 16; rem != 0 { + var buf [16]byte + padLen := 16 - rem + p.Write(buf[:padLen]) + } +} + +func writeUint64(p *poly1305.MAC, n int) { + var buf [8]byte + binary.LittleEndian.PutUint64(buf[:], uint64(n)) + p.Write(buf[:]) } func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte { ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize) + ciphertext, tag := out[:len(plaintext)], out[len(plaintext):] if subtle.InexactOverlap(out, plaintext) { panic("chacha20poly1305: invalid buffer overlap") } - var polyKey, discardBuf [32]byte + var polyKey [32]byte s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce) s.XORKeyStream(polyKey[:], polyKey[:]) - s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes - s.XORKeyStream(out, plaintext) - - polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8) - copy(polyInput, additionalData) - copy(polyInput[roundTo16(len(additionalData)):], out[:len(plaintext)]) - binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData))) - binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(plaintext))) + s.SetCounter(1) // set the counter to 1, skipping 32 bytes + s.XORKeyStream(ciphertext, plaintext) - var tag [poly1305.TagSize]byte - poly1305.Sum(&tag, polyInput, &polyKey) - copy(out[len(plaintext):], tag[:]) + p := poly1305.New(&polyKey) + writeWithPadding(p, additionalData) + writeWithPadding(p, ciphertext) + writeUint64(p, len(additionalData)) + writeUint64(p, len(plaintext)) + p.Sum(tag[:0]) return ret } func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { - var tag [poly1305.TagSize]byte - copy(tag[:], ciphertext[len(ciphertext)-16:]) + tag := ciphertext[len(ciphertext)-16:] ciphertext = ciphertext[:len(ciphertext)-16] - var polyKey, discardBuf [32]byte + var polyKey [32]byte s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce) s.XORKeyStream(polyKey[:], polyKey[:]) - s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes + s.SetCounter(1) // set the counter to 1, skipping 32 bytes - polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8) - copy(polyInput, additionalData) - copy(polyInput[roundTo16(len(additionalData)):], ciphertext) - binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData))) - binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext))) + p := poly1305.New(&polyKey) + writeWithPadding(p, additionalData) + writeWithPadding(p, ciphertext) + writeUint64(p, len(additionalData)) + writeUint64(p, len(ciphertext)) ret, out := sliceForAppend(dst, len(ciphertext)) if subtle.InexactOverlap(out, ciphertext) { panic("chacha20poly1305: invalid buffer overlap") } - if !poly1305.Verify(&tag, polyInput, &polyKey) { + if !p.Verify(tag) { for i := range out { out[i] = 0 } diff --git a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go index 4c2eb703c32..9ce4aa9fe65 100644 --- a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go +++ b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64 !go1.7 gccgo appengine +// +build !amd64 gccgo purego package chacha20poly1305 diff --git a/libgo/go/golang.org/x/crypto/cryptobyte/asn1.go b/libgo/go/golang.org/x/crypto/cryptobyte/asn1.go index f930f7e5266..d3596ee66fd 100644 --- a/libgo/go/golang.org/x/crypto/cryptobyte/asn1.go +++ b/libgo/go/golang.org/x/crypto/cryptobyte/asn1.go @@ -81,7 +81,7 @@ func (b *Builder) AddASN1BigInt(n *big.Int) { for i := range bytes { bytes[i] ^= 0xff } - if bytes[0]&0x80 == 0 { + if len(bytes) == 0 || bytes[0]&0x80 == 0 { c.add(0xff) } c.add(bytes...) @@ -230,12 +230,12 @@ func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) { // String -// ReadASN1Boolean decodes an ASN.1 INTEGER and converts it to a boolean +// ReadASN1Boolean decodes an ASN.1 BOOLEAN and converts it to a boolean // representation into out and advances. It reports whether the read // was successful. func (s *String) ReadASN1Boolean(out *bool) bool { var bytes String - if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 { + if !s.ReadASN1(&bytes, asn1.BOOLEAN) || len(bytes) != 1 { return false } diff --git a/libgo/go/golang.org/x/crypto/poly1305/mac_noasm.go b/libgo/go/golang.org/x/crypto/poly1305/mac_noasm.go index a8dd589ae39..d118f30ed56 100644 --- a/libgo/go/golang.org/x/crypto/poly1305/mac_noasm.go +++ b/libgo/go/golang.org/x/crypto/poly1305/mac_noasm.go @@ -2,10 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!ppc64le gccgo appengine +// +build !amd64,!ppc64le,!s390x gccgo purego package poly1305 type mac struct{ macGeneric } - -func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} } diff --git a/libgo/go/golang.org/x/crypto/poly1305/poly1305.go b/libgo/go/golang.org/x/crypto/poly1305/poly1305.go index 066159b797d..9d7a6af09fe 100644 --- a/libgo/go/golang.org/x/crypto/poly1305/poly1305.go +++ b/libgo/go/golang.org/x/crypto/poly1305/poly1305.go @@ -26,7 +26,9 @@ const TagSize = 16 // 16-byte result into out. Authenticating two different messages with the same // key allows an attacker to forge messages at will. func Sum(out *[16]byte, m []byte, key *[32]byte) { - sum(out, m, key) + h := New(key) + h.Write(m) + h.Sum(out[:0]) } // Verify returns true if mac is a valid authenticator for m with the given key. @@ -46,10 +48,9 @@ func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { // two different messages with the same key allows an attacker // to forge messages at will. func New(key *[32]byte) *MAC { - return &MAC{ - mac: newMAC(key), - finalized: false, - } + m := &MAC{} + initialize(key, &m.macState) + return m } // MAC is an io.Writer computing an authentication tag @@ -58,7 +59,7 @@ func New(key *[32]byte) *MAC { // MAC cannot be used like common hash.Hash implementations, // because using a poly1305 key twice breaks its security. // Therefore writing data to a running MAC after calling -// Sum causes it to panic. +// Sum or Verify causes it to panic. type MAC struct { mac // platform-dependent implementation @@ -71,10 +72,10 @@ func (h *MAC) Size() int { return TagSize } // Write adds more data to the running message authentication code. // It never returns an error. // -// It must not be called after the first call of Sum. +// It must not be called after the first call of Sum or Verify. func (h *MAC) Write(p []byte) (n int, err error) { if h.finalized { - panic("poly1305: write to MAC after Sum") + panic("poly1305: write to MAC after Sum or Verify") } return h.mac.Write(p) } @@ -87,3 +88,12 @@ func (h *MAC) Sum(b []byte) []byte { h.finalized = true return append(b, mac[:]...) } + +// Verify returns whether the authenticator of all data written to +// the message authentication code matches the expected value. +func (h *MAC) Verify(expected []byte) bool { + var mac [TagSize]byte + h.mac.Sum(&mac) + h.finalized = true + return subtle.ConstantTimeCompare(expected, mac[:]) == 1 +} diff --git a/libgo/go/golang.org/x/crypto/poly1305/sum_amd64.go b/libgo/go/golang.org/x/crypto/poly1305/sum_amd64.go index df56a652ff0..99e5a1d50ef 100644 --- a/libgo/go/golang.org/x/crypto/poly1305/sum_amd64.go +++ b/libgo/go/golang.org/x/crypto/poly1305/sum_amd64.go @@ -2,24 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64,!gccgo,!appengine +// +build !gccgo,!purego package poly1305 //go:noescape func update(state *macState, msg []byte) -func sum(out *[16]byte, m []byte, key *[32]byte) { - h := newMAC(key) - h.Write(m) - h.Sum(out) -} - -func newMAC(key *[32]byte) (h mac) { - initialize(key, &h.r, &h.s) - return -} - // mac is a wrapper for macGeneric that redirects calls that would have gone to // updateGeneric to update. // diff --git a/libgo/go/golang.org/x/crypto/poly1305/sum_arm.go b/libgo/go/golang.org/x/crypto/poly1305/sum_arm.go deleted file mode 100644 index 6e695e4272e..00000000000 --- a/libgo/go/golang.org/x/crypto/poly1305/sum_arm.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build arm,!gccgo,!appengine,!nacl - -package poly1305 - -// poly1305_auth_armv6 is implemented in sum_arm.s -//go:noescape -func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte) - -func sum(out *[16]byte, m []byte, key *[32]byte) { - var mPtr *byte - if len(m) > 0 { - mPtr = &m[0] - } - poly1305_auth_armv6(out, mPtr, uint32(len(m)), key) -} diff --git a/libgo/go/golang.org/x/crypto/poly1305/sum_generic.go b/libgo/go/golang.org/x/crypto/poly1305/sum_generic.go index 1187eab78fd..c942a65904f 100644 --- a/libgo/go/golang.org/x/crypto/poly1305/sum_generic.go +++ b/libgo/go/golang.org/x/crypto/poly1305/sum_generic.go @@ -31,16 +31,18 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { h.Sum(out) } -func newMACGeneric(key *[32]byte) (h macGeneric) { - initialize(key, &h.r, &h.s) - return +func newMACGeneric(key *[32]byte) macGeneric { + m := macGeneric{} + initialize(key, &m.macState) + return m } // macState holds numbers in saturated 64-bit little-endian limbs. That is, // the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸. type macState struct { // h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but - // can grow larger during and after rounds. + // can grow larger during and after rounds. It must, however, remain below + // 2 * (2¹³⁰ - 5). h [3]uint64 // r and s are the private key components. r [2]uint64 @@ -97,11 +99,12 @@ const ( rMask1 = 0x0FFFFFFC0FFFFFFC ) -func initialize(key *[32]byte, r, s *[2]uint64) { - r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0 - r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1 - s[0] = binary.LittleEndian.Uint64(key[16:24]) - s[1] = binary.LittleEndian.Uint64(key[24:32]) +// initialize loads the 256-bit key into the two 128-bit secret values r and s. +func initialize(key *[32]byte, m *macState) { + m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0 + m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1 + m.s[0] = binary.LittleEndian.Uint64(key[16:24]) + m.s[1] = binary.LittleEndian.Uint64(key[24:32]) } // uint128 holds a 128-bit number as two 64-bit limbs, for use with the diff --git a/libgo/go/golang.org/x/crypto/poly1305/sum_noasm.go b/libgo/go/golang.org/x/crypto/poly1305/sum_noasm.go deleted file mode 100644 index 32a9cef6bbf..00000000000 --- a/libgo/go/golang.org/x/crypto/poly1305/sum_noasm.go +++ /dev/null @@ -1,13 +0,0 @@ -// 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. - -// +build s390x,!go1.11 !amd64,!s390x,!ppc64le gccgo appengine nacl - -package poly1305 - -func sum(out *[TagSize]byte, msg []byte, key *[32]byte) { - h := newMAC(key) - h.Write(msg) - h.Sum(out) -} diff --git a/libgo/go/golang.org/x/crypto/poly1305/sum_ppc64le.go b/libgo/go/golang.org/x/crypto/poly1305/sum_ppc64le.go index 3233616935b..2e7a120b192 100644 --- a/libgo/go/golang.org/x/crypto/poly1305/sum_ppc64le.go +++ b/libgo/go/golang.org/x/crypto/poly1305/sum_ppc64le.go @@ -2,24 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build ppc64le,!gccgo,!appengine +// +build !gccgo,!purego package poly1305 //go:noescape func update(state *macState, msg []byte) -func sum(out *[16]byte, m []byte, key *[32]byte) { - h := newMAC(key) - h.Write(m) - h.Sum(out) -} - -func newMAC(key *[32]byte) (h mac) { - initialize(key, &h.r, &h.s) - return -} - // mac is a wrapper for macGeneric that redirects calls that would have gone to // updateGeneric to update. // diff --git a/libgo/go/golang.org/x/crypto/poly1305/sum_s390x.go b/libgo/go/golang.org/x/crypto/poly1305/sum_s390x.go index a8920ee9d21..958fedc0790 100644 --- a/libgo/go/golang.org/x/crypto/poly1305/sum_s390x.go +++ b/libgo/go/golang.org/x/crypto/poly1305/sum_s390x.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build s390x,go1.11,!gccgo,!appengine +// +build !gccgo,!purego package poly1305 @@ -10,30 +10,66 @@ import ( "golang.org/x/sys/cpu" ) -// poly1305vx is an assembly implementation of Poly1305 that uses vector +// updateVX is an assembly implementation of Poly1305 that uses vector // instructions. It must only be called if the vector facility (vx) is // available. //go:noescape -func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]byte) +func updateVX(state *macState, msg []byte) -// poly1305vmsl is an assembly implementation of Poly1305 that uses vector -// instructions, including VMSL. It must only be called if the vector facility (vx) is -// available and if VMSL is supported. -//go:noescape -func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte) +// mac is a replacement for macGeneric that uses a larger buffer and redirects +// calls that would have gone to updateGeneric to updateVX if the vector +// facility is installed. +// +// A larger buffer is required for good performance because the vector +// implementation has a higher fixed cost per call than the generic +// implementation. +type mac struct { + macState + + buffer [16 * TagSize]byte // size must be a multiple of block size (16) + offset int +} -func sum(out *[16]byte, m []byte, key *[32]byte) { - if cpu.S390X.HasVX { - var mPtr *byte - if len(m) > 0 { - mPtr = &m[0] +func (h *mac) Write(p []byte) (int, error) { + nn := len(p) + if h.offset > 0 { + n := copy(h.buffer[h.offset:], p) + if h.offset+n < len(h.buffer) { + h.offset += n + return nn, nil } - if cpu.S390X.HasVXE && len(m) > 256 { - poly1305vmsl(out, mPtr, uint64(len(m)), key) + p = p[n:] + h.offset = 0 + if cpu.S390X.HasVX { + updateVX(&h.macState, h.buffer[:]) } else { - poly1305vx(out, mPtr, uint64(len(m)), key) + updateGeneric(&h.macState, h.buffer[:]) } - } else { - sumGeneric(out, m, key) } + + tail := len(p) % len(h.buffer) // number of bytes to copy into buffer + body := len(p) - tail // number of bytes to process now + if body > 0 { + if cpu.S390X.HasVX { + updateVX(&h.macState, p[:body]) + } else { + updateGeneric(&h.macState, p[:body]) + } + } + h.offset = copy(h.buffer[:], p[body:]) // copy tail bytes - can be 0 + return nn, nil +} + +func (h *mac) Sum(out *[TagSize]byte) { + state := h.macState + remainder := h.buffer[:h.offset] + + // Use the generic implementation if we have 2 or fewer blocks left + // to sum. The vector implementation has a higher startup time. + if cpu.S390X.HasVX && len(remainder) > 2*TagSize { + updateVX(&state, remainder) + } else if len(remainder) > 0 { + updateGeneric(&state, remainder) + } + finalize(out, &state.h, &state.s) } diff --git a/libgo/go/golang.org/x/mod/modfile/print.go b/libgo/go/golang.org/x/mod/modfile/print.go index 3bbea38529f..524f93022ac 100644 --- a/libgo/go/golang.org/x/mod/modfile/print.go +++ b/libgo/go/golang.org/x/mod/modfile/print.go @@ -138,16 +138,11 @@ func (p *printer) expr(x Expr) { p.printf(")") case *Line: - sep := "" - for _, tok := range x.Token { - p.printf("%s%s", sep, tok) - sep = " " - } + p.tokens(x.Token) case *LineBlock: - for _, tok := range x.Token { - p.printf("%s ", tok) - } + p.tokens(x.Token) + p.printf(" ") p.expr(&x.LParen) p.margin++ for _, l := range x.Line { @@ -163,3 +158,17 @@ func (p *printer) expr(x Expr) { // reach the end of the line. p.comment = append(p.comment, x.Comment().Suffix...) } + +func (p *printer) tokens(tokens []string) { + sep := "" + for _, t := range tokens { + if t == "," || t == ")" || t == "]" || t == "}" { + sep = "" + } + p.printf("%s%s", sep, t) + sep = " " + if t == "(" || t == "[" || t == "{" { + sep = "" + } + } +} diff --git a/libgo/go/golang.org/x/mod/modfile/read.go b/libgo/go/golang.org/x/mod/modfile/read.go index 616d00efdb1..c1f2008ee4c 100644 --- a/libgo/go/golang.org/x/mod/modfile/read.go +++ b/libgo/go/golang.org/x/mod/modfile/read.go @@ -2,13 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Module file parser. -// This is a simplified copy of Google's buildifier parser. - package modfile import ( "bytes" + "errors" "fmt" "os" "strconv" @@ -323,18 +321,17 @@ func (x *RParen) Span() (start, end Position) { // An input represents a single input file being parsed. type input struct { // Lexing state. - filename string // name of input file, for errors - complete []byte // entire input - remaining []byte // remaining input - token []byte // token being scanned - lastToken string // most recently returned token, for error messages - pos Position // current input position - comments []Comment // accumulated comments - endRule int // position of end of current rule + filename string // name of input file, for errors + complete []byte // entire input + remaining []byte // remaining input + tokenStart []byte // token being scanned to end of input + token token // next token to be returned by lex, peek + pos Position // current input position + comments []Comment // accumulated comments // Parser state. - file *FileSyntax // returned top-level syntax tree - parseError error // error encountered during parsing + file *FileSyntax // returned top-level syntax tree + parseErrors ErrorList // errors encountered during parsing // Comment assignment state. pre []Expr // all expressions, in preorder traversal @@ -352,25 +349,32 @@ func newInput(filename string, data []byte) *input { // parse parses the input file. func parse(file string, data []byte) (f *FileSyntax, err error) { - in := newInput(file, data) // The parser panics for both routine errors like syntax errors // and for programmer bugs like array index errors. // Turn both into error returns. Catching bug panics is // especially important when processing many files. + in := newInput(file, data) defer func() { - if e := recover(); e != nil { - if e == in.parseError { - err = in.parseError - } else { - err = fmt.Errorf("%s:%d:%d: internal error: %v", in.filename, in.pos.Line, in.pos.LineRune, e) - } + if e := recover(); e != nil && e != &in.parseErrors { + in.parseErrors = append(in.parseErrors, Error{ + Filename: in.filename, + Pos: in.pos, + Err: fmt.Errorf("internal error: %v", e), + }) + } + if err == nil && len(in.parseErrors) > 0 { + err = in.parseErrors } }() + // Prime the lexer by reading in the first token. It will be available + // in the next peek() or lex() call. + in.readToken() + // Invoke the parser. in.parseFile() - if in.parseError != nil { - return nil, in.parseError + if len(in.parseErrors) > 0 { + return nil, in.parseErrors } in.file.Name = in.filename @@ -381,14 +385,14 @@ func parse(file string, data []byte) (f *FileSyntax, err error) { } // Error is called to report an error. -// The reason s is often "syntax error". // Error does not return: it panics. func (in *input) Error(s string) { - if s == "syntax error" && in.lastToken != "" { - s += " near " + in.lastToken - } - in.parseError = fmt.Errorf("%s:%d:%d: %v", in.filename, in.pos.Line, in.pos.LineRune, s) - panic(in.parseError) + in.parseErrors = append(in.parseErrors, Error{ + Filename: in.filename, + Pos: in.pos, + Err: errors.New(s), + }) + panic(&in.parseErrors) } // eof reports whether the input has reached end of file. @@ -434,46 +438,68 @@ func (in *input) readRune() int { return int(r) } -type symType struct { +type token struct { + kind tokenKind pos Position endPos Position text string } +type tokenKind int + +const ( + _EOF tokenKind = -(iota + 1) + _EOLCOMMENT + _IDENT + _STRING + _COMMENT + + // newlines and punctuation tokens are allowed as ASCII codes. +) + +func (k tokenKind) isComment() bool { + return k == _COMMENT || k == _EOLCOMMENT +} + +// isEOL returns whether a token terminates a line. +func (k tokenKind) isEOL() bool { + return k == _EOF || k == _EOLCOMMENT || k == '\n' +} + // startToken marks the beginning of the next input token. -// It must be followed by a call to endToken, once the token has +// It must be followed by a call to endToken, once the token's text has // been consumed using readRune. -func (in *input) startToken(sym *symType) { - in.token = in.remaining - sym.text = "" - sym.pos = in.pos +func (in *input) startToken() { + in.tokenStart = in.remaining + in.token.text = "" + in.token.pos = in.pos } // endToken marks the end of an input token. -// It records the actual token string in sym.text if the caller -// has not done that already. -func (in *input) endToken(sym *symType) { - if sym.text == "" { - tok := string(in.token[:len(in.token)-len(in.remaining)]) - sym.text = tok - in.lastToken = sym.text - } - sym.endPos = in.pos +// It records the actual token string in tok.text. +func (in *input) endToken(kind tokenKind) { + in.token.kind = kind + text := string(in.tokenStart[:len(in.tokenStart)-len(in.remaining)]) + in.token.text = text + in.token.endPos = in.pos +} + +// peek returns the kind of the the next token returned by lex. +func (in *input) peek() tokenKind { + return in.token.kind } // lex is called from the parser to obtain the next input token. -// It returns the token value (either a rune like '+' or a symbolic token _FOR) -// and sets val to the data associated with the token. -// For all our input tokens, the associated data is -// val.Pos (the position where the token begins) -// and val.Token (the input string corresponding to the token). -func (in *input) lex(sym *symType) int { +func (in *input) lex() token { + tok := in.token + in.readToken() + return tok +} + +// readToken lexes the next token from the text and stores it in in.token. +func (in *input) readToken() { // Skip past spaces, stopping at non-space or EOF. - countNL := 0 // number of newlines we've skipped past for !in.eof() { - // Skip over spaces. Count newlines so we can give the parser - // information about where top-level blank lines are, - // for top-level comment assignment. c := in.peekRune() if c == ' ' || c == '\t' || c == '\r' { in.readRune() @@ -482,7 +508,7 @@ func (in *input) lex(sym *symType) int { // Comment runs to end of line. if in.peekPrefix("//") { - in.startToken(sym) + in.startToken() // Is this comment the only thing on its line? // Find the last \n before this // and see if it's all @@ -495,30 +521,23 @@ func (in *input) lex(sym *symType) int { // Consume comment. for len(in.remaining) > 0 && in.readRune() != '\n' { } - in.endToken(sym) - - sym.text = strings.TrimRight(sym.text, "\n") - in.lastToken = "comment" // If we are at top level (not in a statement), hand the comment to // the parser as a _COMMENT token. The grammar is written // to handle top-level comments itself. if !suffix { - // Not in a statement. Tell parser about top-level comment. - return _COMMENT + in.endToken(_COMMENT) + return } // Otherwise, save comment for later attachment to syntax tree. - if countNL > 1 { - in.comments = append(in.comments, Comment{sym.pos, "", false}) - } - in.comments = append(in.comments, Comment{sym.pos, sym.text, suffix}) - countNL = 1 - return _EOL + in.endToken(_EOLCOMMENT) + in.comments = append(in.comments, Comment{in.token.pos, in.token.text, suffix}) + return } if in.peekPrefix("/*") { - in.Error(fmt.Sprintf("mod files must use // comments (not /* */ comments)")) + in.Error("mod files must use // comments (not /* */ comments)") } // Found non-space non-comment. @@ -526,35 +545,27 @@ func (in *input) lex(sym *symType) int { } // Found the beginning of the next token. - in.startToken(sym) - defer in.endToken(sym) + in.startToken() // End of file. if in.eof() { - in.lastToken = "EOF" - return _EOF + in.endToken(_EOF) + return } // Punctuation tokens. switch c := in.peekRune(); c { - case '\n': + case '\n', '(', ')', '[', ']', '{', '}', ',': in.readRune() - return c - - case '(': - in.readRune() - return c - - case ')': - in.readRune() - return c + in.endToken(tokenKind(c)) + return case '"', '`': // quoted string quote := c in.readRune() for { if in.eof() { - in.pos = sym.pos + in.pos = in.token.pos in.Error("unexpected EOF in string") } if in.peekRune() == '\n' { @@ -566,14 +577,14 @@ func (in *input) lex(sym *symType) int { } if c == '\\' && quote != '`' { if in.eof() { - in.pos = sym.pos + in.pos = in.token.pos in.Error("unexpected EOF in string") } in.readRune() } } - in.endToken(sym) - return _STRING + in.endToken(_STRING) + return } // Checked all punctuation. Must be identifier token. @@ -587,17 +598,23 @@ func (in *input) lex(sym *symType) int { break } if in.peekPrefix("/*") { - in.Error(fmt.Sprintf("mod files must use // comments (not /* */ comments)")) + in.Error("mod files must use // comments (not /* */ comments)") } in.readRune() } - return _IDENT + in.endToken(_IDENT) } // isIdent reports whether c is an identifier rune. -// We treat nearly all runes as identifier runes. +// We treat most printable runes as identifier runes, except for a handful of +// ASCII punctuation characters. func isIdent(c int) bool { - return c != 0 && !unicode.IsSpace(rune(c)) + switch r := rune(c); r { + case ' ', '(', ')', '[', ']', '{', '}', ',': + return false + default: + return !unicode.IsSpace(r) && unicode.IsPrint(r) + } } // Comment assignment. @@ -668,7 +685,7 @@ func (in *input) assignComments() { for _, x := range in.pre { start, _ := x.Span() if debug { - fmt.Printf("pre %T :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte) + fmt.Fprintf(os.Stderr, "pre %T :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte) } xcom := x.Comment() for len(line) > 0 && start.Byte >= line[0].Start.Byte { @@ -695,7 +712,7 @@ func (in *input) assignComments() { start, end := x.Span() if debug { - fmt.Printf("post %T :%d:%d #%d :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte, end.Line, end.LineRune, end.Byte) + fmt.Fprintf(os.Stderr, "post %T :%d:%d #%d :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte, end.Line, end.LineRune, end.Byte) } // Do not assign suffix comments to end of line block or whole file. @@ -745,29 +762,29 @@ func reverseComments(list []Comment) { func (in *input) parseFile() { in.file = new(FileSyntax) - var sym symType var cb *CommentBlock for { - tok := in.lex(&sym) - switch tok { + switch in.peek() { case '\n': + in.lex() if cb != nil { in.file.Stmt = append(in.file.Stmt, cb) cb = nil } case _COMMENT: + tok := in.lex() if cb == nil { - cb = &CommentBlock{Start: sym.pos} + cb = &CommentBlock{Start: tok.pos} } com := cb.Comment() - com.Before = append(com.Before, Comment{Start: sym.pos, Token: sym.text}) + com.Before = append(com.Before, Comment{Start: tok.pos, Token: tok.text}) case _EOF: if cb != nil { in.file.Stmt = append(in.file.Stmt, cb) } return default: - in.parseStmt(&sym) + in.parseStmt() if cb != nil { in.file.Stmt[len(in.file.Stmt)-1].Comment().Before = cb.Before cb = nil @@ -776,60 +793,88 @@ func (in *input) parseFile() { } } -func (in *input) parseStmt(sym *symType) { - start := sym.pos - end := sym.endPos - token := []string{sym.text} +func (in *input) parseStmt() { + tok := in.lex() + start := tok.pos + end := tok.endPos + tokens := []string{tok.text} for { - tok := in.lex(sym) - switch tok { - case '\n', _EOF, _EOL: + tok := in.lex() + switch { + case tok.kind.isEOL(): in.file.Stmt = append(in.file.Stmt, &Line{ Start: start, - Token: token, + Token: tokens, End: end, }) return - case '(': - in.file.Stmt = append(in.file.Stmt, in.parseLineBlock(start, token, sym)) - return + + case tok.kind == '(': + if next := in.peek(); next.isEOL() { + // Start of block: no more tokens on this line. + in.file.Stmt = append(in.file.Stmt, in.parseLineBlock(start, tokens, tok)) + return + } else if next == ')' { + rparen := in.lex() + if in.peek().isEOL() { + // Empty block. + in.lex() + in.file.Stmt = append(in.file.Stmt, &LineBlock{ + Start: start, + Token: tokens, + LParen: LParen{Pos: tok.pos}, + RParen: RParen{Pos: rparen.pos}, + }) + return + } + // '( )' in the middle of the line, not a block. + tokens = append(tokens, tok.text, rparen.text) + } else { + // '(' in the middle of the line, not a block. + tokens = append(tokens, tok.text) + } + default: - token = append(token, sym.text) - end = sym.endPos + tokens = append(tokens, tok.text) + end = tok.endPos } } } -func (in *input) parseLineBlock(start Position, token []string, sym *symType) *LineBlock { +func (in *input) parseLineBlock(start Position, token []string, lparen token) *LineBlock { x := &LineBlock{ Start: start, Token: token, - LParen: LParen{Pos: sym.pos}, + LParen: LParen{Pos: lparen.pos}, } var comments []Comment for { - tok := in.lex(sym) - switch tok { - case _EOL: - // ignore + switch in.peek() { + case _EOLCOMMENT: + // Suffix comment, will be attached later by assignComments. + in.lex() case '\n': + // Blank line. Add an empty comment to preserve it. + in.lex() if len(comments) == 0 && len(x.Line) > 0 || len(comments) > 0 && comments[len(comments)-1].Token != "" { comments = append(comments, Comment{}) } case _COMMENT: - comments = append(comments, Comment{Start: sym.pos, Token: sym.text}) + tok := in.lex() + comments = append(comments, Comment{Start: tok.pos, Token: tok.text}) case _EOF: in.Error(fmt.Sprintf("syntax error (unterminated block started at %s:%d:%d)", in.filename, x.Start.Line, x.Start.LineRune)) case ')': + rparen := in.lex() x.RParen.Before = comments - x.RParen.Pos = sym.pos - tok = in.lex(sym) - if tok != '\n' && tok != _EOF && tok != _EOL { + x.RParen.Pos = rparen.pos + if !in.peek().isEOL() { in.Error("syntax error (expected newline after closing paren)") } + in.lex() return x default: - l := in.parseLine(sym) + l := in.parseLine() x.Line = append(x.Line, l) l.Comment().Before = comments comments = nil @@ -837,35 +882,29 @@ func (in *input) parseLineBlock(start Position, token []string, sym *symType) *L } } -func (in *input) parseLine(sym *symType) *Line { - start := sym.pos - end := sym.endPos - token := []string{sym.text} +func (in *input) parseLine() *Line { + tok := in.lex() + if tok.kind.isEOL() { + in.Error("internal parse error: parseLine at end of line") + } + start := tok.pos + end := tok.endPos + tokens := []string{tok.text} for { - tok := in.lex(sym) - switch tok { - case '\n', _EOF, _EOL: + tok := in.lex() + if tok.kind.isEOL() { return &Line{ Start: start, - Token: token, + Token: tokens, End: end, InBlock: true, } - default: - token = append(token, sym.text) - end = sym.endPos } + tokens = append(tokens, tok.text) + end = tok.endPos } } -const ( - _EOF = -(1 + iota) - _EOL - _IDENT - _STRING - _COMMENT -) - var ( slashSlash = []byte("//") moduleStr = []byte("module") diff --git a/libgo/go/golang.org/x/mod/modfile/rule.go b/libgo/go/golang.org/x/mod/modfile/rule.go index 62af06889f6..91ca6828df0 100644 --- a/libgo/go/golang.org/x/mod/modfile/rule.go +++ b/libgo/go/golang.org/x/mod/modfile/rule.go @@ -2,10 +2,24 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Package modfile implements a parser and formatter for go.mod files. +// +// The go.mod syntax is described in +// https://golang.org/cmd/go/#hdr-The_go_mod_file. +// +// The Parse and ParseLax functions both parse a go.mod file and return an +// abstract syntax tree. ParseLax ignores unknown statements and may be used to +// parse go.mod files that may have been developed with newer versions of Go. +// +// The File struct returned by Parse and ParseLax represent an abstract +// go.mod file. File has several methods like AddNewRequire and DropReplace +// that can be used to programmatically edit a file. +// +// The Format function formats a File back to a byte slice which can be +// written to a file. package modfile import ( - "bytes" "errors" "fmt" "path/filepath" @@ -120,7 +134,7 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File Syntax: fs, } - var errs bytes.Buffer + var errs ErrorList for _, x := range fs.Stmt { switch x := x.(type) { case *Line: @@ -129,14 +143,22 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File case *LineBlock: if len(x.Token) > 1 { if strict { - fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " ")) + errs = append(errs, Error{ + Filename: file, + Pos: x.Start, + Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")), + }) } continue } switch x.Token[0] { default: if strict { - fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " ")) + errs = append(errs, Error{ + Filename: file, + Pos: x.Start, + Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")), + }) } continue case "module", "require", "exclude", "replace": @@ -147,15 +169,15 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File } } - if errs.Len() > 0 { - return nil, errors.New(strings.TrimRight(errs.String(), "\n")) + if len(errs) > 0 { + return nil, errs } return f, nil } var GoVersionRE = lazyregexp.New(`^([1-9][0-9]*)\.(0|[1-9][0-9]*)$`) -func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, fix VersionFixer, strict bool) { +func (f *File) add(errs *ErrorList, line *Line, verb string, args []string, fix VersionFixer, strict bool) { // If strict is false, this module is a dependency. // We ignore all unknown directives as well as main-module-only // directives like replace and exclude. It will work better for @@ -171,60 +193,83 @@ func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, f } } + wrapModPathError := func(modPath string, err error) { + *errs = append(*errs, Error{ + Filename: f.Syntax.Name, + Pos: line.Start, + ModPath: modPath, + Verb: verb, + Err: err, + }) + } + wrapError := func(err error) { + *errs = append(*errs, Error{ + Filename: f.Syntax.Name, + Pos: line.Start, + Err: err, + }) + } + errorf := func(format string, args ...interface{}) { + wrapError(fmt.Errorf(format, args...)) + } + switch verb { default: - fmt.Fprintf(errs, "%s:%d: unknown directive: %s\n", f.Syntax.Name, line.Start.Line, verb) + errorf("unknown directive: %s", verb) case "go": if f.Go != nil { - fmt.Fprintf(errs, "%s:%d: repeated go statement\n", f.Syntax.Name, line.Start.Line) + errorf("repeated go statement") return } - if len(args) != 1 || !GoVersionRE.MatchString(args[0]) { - fmt.Fprintf(errs, "%s:%d: usage: go 1.23\n", f.Syntax.Name, line.Start.Line) + if len(args) != 1 { + errorf("go directive expects exactly one argument") + return + } else if !GoVersionRE.MatchString(args[0]) { + errorf("invalid go version '%s': must match format 1.23", args[0]) return } + f.Go = &Go{Syntax: line} f.Go.Version = args[0] case "module": if f.Module != nil { - fmt.Fprintf(errs, "%s:%d: repeated module statement\n", f.Syntax.Name, line.Start.Line) + errorf("repeated module statement") return } f.Module = &Module{Syntax: line} if len(args) != 1 { - - fmt.Fprintf(errs, "%s:%d: usage: module module/path\n", f.Syntax.Name, line.Start.Line) + errorf("usage: module module/path") return } s, err := parseString(&args[0]) if err != nil { - fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err) + errorf("invalid quoted string: %v", err) return } f.Module.Mod = module.Version{Path: s} case "require", "exclude": if len(args) != 2 { - fmt.Fprintf(errs, "%s:%d: usage: %s module/path v1.2.3\n", f.Syntax.Name, line.Start.Line, verb) + errorf("usage: %s module/path v1.2.3", verb) return } s, err := parseString(&args[0]) if err != nil { - fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err) + errorf("invalid quoted string: %v", err) return } v, err := parseVersion(verb, s, &args[1], fix) if err != nil { - fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err) + wrapError(err) return } pathMajor, err := modulePathMajor(s) if err != nil { - fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err) + wrapError(err) return } if err := module.CheckPathMajor(v, pathMajor); err != nil { - fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, &Error{Verb: verb, ModPath: s, Err: err}) + wrapModPathError(s, err) return } if verb == "require" { @@ -245,55 +290,55 @@ func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, f arrow = 1 } if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" { - fmt.Fprintf(errs, "%s:%d: usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory\n", f.Syntax.Name, line.Start.Line, verb, verb) + errorf("usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory", verb, verb) return } s, err := parseString(&args[0]) if err != nil { - fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err) + errorf("invalid quoted string: %v", err) return } pathMajor, err := modulePathMajor(s) if err != nil { - fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err) + wrapModPathError(s, err) return } var v string if arrow == 2 { v, err = parseVersion(verb, s, &args[1], fix) if err != nil { - fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err) + wrapError(err) return } if err := module.CheckPathMajor(v, pathMajor); err != nil { - fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, &Error{Verb: verb, ModPath: s, Err: err}) + wrapModPathError(s, err) return } } ns, err := parseString(&args[arrow+1]) if err != nil { - fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err) + errorf("invalid quoted string: %v", err) return } nv := "" if len(args) == arrow+2 { if !IsDirectoryPath(ns) { - fmt.Fprintf(errs, "%s:%d: replacement module without version must be directory path (rooted or starting with ./ or ../)\n", f.Syntax.Name, line.Start.Line) + errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)") return } if filepath.Separator == '/' && strings.Contains(ns, `\`) { - fmt.Fprintf(errs, "%s:%d: replacement directory appears to be Windows path (on a non-windows system)\n", f.Syntax.Name, line.Start.Line) + errorf("replacement directory appears to be Windows path (on a non-windows system)") return } } if len(args) == arrow+3 { nv, err = parseVersion(verb, ns, &args[arrow+2], fix) if err != nil { - fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err) + wrapError(err) return } if IsDirectoryPath(ns) { - fmt.Fprintf(errs, "%s:%d: replacement module directory path %q cannot have version\n", f.Syntax.Name, line.Start.Line, ns) + errorf("replacement module directory path %q cannot have version", ns) return } } @@ -372,8 +417,19 @@ func IsDirectoryPath(ns string) bool { // a single token in a go.mod line. func MustQuote(s string) bool { for _, r := range s { - if !unicode.IsPrint(r) || r == ' ' || r == '"' || r == '\'' || r == '`' { + switch r { + case ' ', '"', '\'', '`': return true + + case '(', ')', '[', ']', '{', '}', ',': + if len(s) > 1 { + return true + } + + default: + if !unicode.IsPrint(r) { + return true + } } } return s == "" || strings.Contains(s, "//") || strings.Contains(s, "/*") @@ -405,14 +461,42 @@ func parseString(s *string) (string, error) { return t, nil } +type ErrorList []Error + +func (e ErrorList) Error() string { + errStrs := make([]string, len(e)) + for i, err := range e { + errStrs[i] = err.Error() + } + return strings.Join(errStrs, "\n") +} + type Error struct { - Verb string - ModPath string - Err error + Filename string + Pos Position + Verb string + ModPath string + Err error } func (e *Error) Error() string { - return fmt.Sprintf("%s %s: %v", e.Verb, e.ModPath, e.Err) + var pos string + if e.Pos.LineRune > 1 { + // Don't print LineRune if it's 1 (beginning of line). + // It's always 1 except in scanner errors, which are rare. + pos = fmt.Sprintf("%s:%d:%d: ", e.Filename, e.Pos.Line, e.Pos.LineRune) + } else if e.Pos.Line > 0 { + pos = fmt.Sprintf("%s:%d: ", e.Filename, e.Pos.Line) + } else if e.Filename != "" { + pos = fmt.Sprintf("%s: ", e.Filename) + } + + var directive string + if e.ModPath != "" { + directive = fmt.Sprintf("%s %s: ", e.Verb, e.ModPath) + } + + return pos + directive + e.Err.Error() } func (e *Error) Unwrap() error { return e.Err } diff --git a/libgo/go/golang.org/x/mod/zip/zip.go b/libgo/go/golang.org/x/mod/zip/zip.go index 37c764257e4..6865895b3d0 100644 --- a/libgo/go/golang.org/x/mod/zip/zip.go +++ b/libgo/go/golang.org/x/mod/zip/zip.go @@ -247,6 +247,9 @@ func CreateFromDir(w io.Writer, m module.Version, dir string) (err error) { var files []File err = filepath.Walk(dir, func(filePath string, info os.FileInfo, err error) error { + if err != nil { + return err + } relPath, err := filepath.Rel(dir, filePath) if err != nil { return err @@ -313,6 +316,12 @@ func (f dirFile) Path() string { return f.slashPath } func (f dirFile) Lstat() (os.FileInfo, error) { return f.info, nil } func (f dirFile) Open() (io.ReadCloser, error) { return os.Open(f.filePath) } +// isVendoredPackage attempts to report whether the given filename is contained +// in a package whose import path contains (but does not end with) the component +// "vendor". +// +// Unfortunately, isVendoredPackage reports false positives for files in any +// non-top-level package whose import path ends in "vendor". func isVendoredPackage(name string) bool { var i int if strings.HasPrefix(name, "vendor/") { @@ -322,15 +331,8 @@ func isVendoredPackage(name string) bool { // // i = j + len("/vendor/") // - // (See https://golang.org/issue/31562.) - // - // Unfortunately, we can't fix it without invalidating checksums. - // Fortunately, the error appears to be strictly conservative: we'll retain - // vendored packages that we should have pruned, but we won't prune - // non-vendored packages that we should have retained. - // - // Since this defect doesn't seem to break anything, it's not worth fixing - // for now. + // (See https://golang.org/issue/31562 and https://golang.org/issue/37397.) + // Unfortunately, we can't fix it without invalidating module checksums. i += len("/vendor/") } else { return false diff --git a/libgo/go/golang.org/x/net/dns/dnsmessage/message.go b/libgo/go/golang.org/x/net/dns/dnsmessage/message.go index 82bcdcc838c..654f191f8a9 100644 --- a/libgo/go/golang.org/x/net/dns/dnsmessage/message.go +++ b/libgo/go/golang.org/x/net/dns/dnsmessage/message.go @@ -1819,17 +1819,6 @@ func unpackText(msg []byte, off int) (string, int, error) { return string(msg[beginOff:endOff]), endOff, nil } -func skipText(msg []byte, off int) (int, error) { - if off >= len(msg) { - return off, errBaseLen - } - endOff := off + 1 + int(msg[off]) - if endOff > len(msg) { - return off, errCalcLen - } - return endOff, nil -} - // packBytes appends the wire format of field to msg. func packBytes(msg []byte, field []byte) []byte { return append(msg, field...) @@ -1844,14 +1833,6 @@ func unpackBytes(msg []byte, off int, field []byte) (int, error) { return newOff, nil } -func skipBytes(msg []byte, off int, field []byte) (int, error) { - newOff := off + len(field) - if newOff > len(msg) { - return off, errBaseLen - } - return newOff, nil -} - const nameLen = 255 // A Name is a non-encoded domain name. It is used instead of strings to avoid @@ -2159,7 +2140,7 @@ func unpackResourceBody(msg []byte, off int, hdr ResourceHeader) (ResourceBody, return nil, off, &nestedError{name + " record", err} } if r == nil { - return nil, off, errors.New("invalid resource type: " + string(hdr.Type+'0')) + return nil, off, errors.New("invalid resource type: " + hdr.Type.String()) } return r, off + int(hdr.Length), nil } diff --git a/libgo/go/golang.org/x/net/http2/hpack/huffman.go b/libgo/go/golang.org/x/net/http2/hpack/huffman.go index b412a96c504..a1ab2f05679 100644 --- a/libgo/go/golang.org/x/net/http2/hpack/huffman.go +++ b/libgo/go/golang.org/x/net/http2/hpack/huffman.go @@ -105,7 +105,14 @@ func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error { return nil } +// incomparable is a zero-width, non-comparable type. Adding it to a struct +// makes that struct also non-comparable, and generally doesn't add +// any size (as long as it's first). +type incomparable [0]func() + type node struct { + _ incomparable + // children is non-nil for internal nodes children *[256]*node diff --git a/libgo/go/golang.org/x/net/route/address.go b/libgo/go/golang.org/x/net/route/address.go index b71528191f6..e3125a473bc 100644 --- a/libgo/go/golang.org/x/net/route/address.go +++ b/libgo/go/golang.org/x/net/route/address.go @@ -46,12 +46,12 @@ func (a *LinkAddr) marshal(b []byte) (int, error) { data := b[8:] if nlen > 0 { b[5] = byte(nlen) - copy(data[:nlen], a.Addr) + copy(data[:nlen], a.Name) data = data[nlen:] } if alen > 0 { b[6] = byte(alen) - copy(data[:alen], a.Name) + copy(data[:alen], a.Addr) data = data[alen:] } return ll, nil diff --git a/libgo/go/golang.org/x/net/route/route.go b/libgo/go/golang.org/x/net/route/route.go index bba7ed7ef4e..4462cf1b6f6 100644 --- a/libgo/go/golang.org/x/net/route/route.go +++ b/libgo/go/golang.org/x/net/route/route.go @@ -88,7 +88,7 @@ func (m *RouteMessage) Marshal() ([]byte, error) { return m.marshal() } -// A RIBType reprensents a type of routing information base. +// A RIBType represents a type of routing information base. type RIBType int const ( diff --git a/libgo/go/golang.org/x/sys/cpu/byteorder.go b/libgo/go/golang.org/x/sys/cpu/byteorder.go index 74116e97abb..ff3eb5b4481 100644 --- a/libgo/go/golang.org/x/sys/cpu/byteorder.go +++ b/libgo/go/golang.org/x/sys/cpu/byteorder.go @@ -5,13 +5,43 @@ package cpu import ( - "encoding/binary" "runtime" ) +// byteOrder is a subset of encoding/binary.ByteOrder. +type byteOrder interface { + Uint32([]byte) uint32 + Uint64([]byte) uint64 +} + +type littleEndian struct{} +type bigEndian struct{} + +func (littleEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func (littleEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func (bigEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func (bigEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} + // hostByteOrder returns binary.LittleEndian on little-endian machines and // binary.BigEndian on big-endian machines. -func hostByteOrder() binary.ByteOrder { +func hostByteOrder() byteOrder { switch runtime.GOARCH { case "386", "amd64", "amd64p32", "alpha", @@ -21,7 +51,7 @@ func hostByteOrder() binary.ByteOrder { "ppc64le", "riscv", "riscv64", "sh": - return binary.LittleEndian + return littleEndian{} case "armbe", "arm64be", "m68k", "mips", "mips64", "mips64p32", @@ -29,7 +59,7 @@ func hostByteOrder() binary.ByteOrder { "s390", "s390x", "shbe", "sparc", "sparc64": - return binary.BigEndian + return bigEndian{} } panic("unknown architecture") } diff --git a/libgo/go/golang.org/x/sys/cpu/cpu.go b/libgo/go/golang.org/x/sys/cpu/cpu.go index 679e78c2cef..e44deb75746 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu.go @@ -78,6 +78,51 @@ var ARM64 struct { _ CacheLinePad } +// ARM contains the supported CPU features of the current ARM (32-bit) platform. +// All feature flags are false if: +// 1. the current platform is not arm, or +// 2. the current operating system is not Linux. +var ARM struct { + _ CacheLinePad + HasSWP bool // SWP instruction support + HasHALF bool // Half-word load and store support + HasTHUMB bool // ARM Thumb instruction set + Has26BIT bool // Address space limited to 26-bits + HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support + HasFPA bool // Floating point arithmetic support + HasVFP bool // Vector floating point support + HasEDSP bool // DSP Extensions support + HasJAVA bool // Java instruction set + HasIWMMXT bool // Intel Wireless MMX technology support + HasCRUNCH bool // MaverickCrunch context switching and handling + HasTHUMBEE bool // Thumb EE instruction set + HasNEON bool // NEON instruction set + HasVFPv3 bool // Vector floating point version 3 support + HasVFPv3D16 bool // Vector floating point version 3 D8-D15 + HasTLS bool // Thread local storage support + HasVFPv4 bool // Vector floating point version 4 support + HasIDIVA bool // Integer divide instruction support in ARM mode + HasIDIVT bool // Integer divide instruction support in Thumb mode + HasVFPD32 bool // Vector floating point version 3 D15-D31 + HasLPAE bool // Large Physical Address Extensions + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + _ CacheLinePad +} + +// MIPS64X contains the supported CPU features of the current mips64/mips64le +// platforms. If the current platform is not mips64/mips64le or the current +// operating system is not Linux then all feature flags are false. +var MIPS64X struct { + _ CacheLinePad + HasMSA bool // MIPS SIMD architecture + _ CacheLinePad +} + // PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. // If the current platform is not ppc64/ppc64le then all feature flags are false. // diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_arm.go b/libgo/go/golang.org/x/sys/cpu/cpu_arm.go new file mode 100644 index 00000000000..bb0b91577cf --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_arm.go @@ -0,0 +1,40 @@ +// 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 cpu + +// const cacheLineSize = 32 + +// HWCAP/HWCAP2 bits. +// These are specific to Linux. +const ( + hwcap_SWP = 1 << 0 + hwcap_HALF = 1 << 1 + hwcap_THUMB = 1 << 2 + hwcap_26BIT = 1 << 3 + hwcap_FAST_MULT = 1 << 4 + hwcap_FPA = 1 << 5 + hwcap_VFP = 1 << 6 + hwcap_EDSP = 1 << 7 + hwcap_JAVA = 1 << 8 + hwcap_IWMMXT = 1 << 9 + hwcap_CRUNCH = 1 << 10 + hwcap_THUMBEE = 1 << 11 + hwcap_NEON = 1 << 12 + hwcap_VFPv3 = 1 << 13 + hwcap_VFPv3D16 = 1 << 14 + hwcap_TLS = 1 << 15 + hwcap_VFPv4 = 1 << 16 + hwcap_IDIVA = 1 << 17 + hwcap_IDIVT = 1 << 18 + hwcap_VFPD32 = 1 << 19 + hwcap_LPAE = 1 << 20 + hwcap_EVTSTRM = 1 << 21 + + hwcap2_AES = 1 << 0 + hwcap2_PMULL = 1 << 1 + hwcap2_SHA1 = 1 << 2 + hwcap2_SHA2 = 1 << 3 + hwcap2_CRC32 = 1 << 4 +) diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_arm64.go b/libgo/go/golang.org/x/sys/cpu/cpu_arm64.go new file mode 100644 index 00000000000..74df5c6ff83 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_arm64.go @@ -0,0 +1,138 @@ +// Copyright 2019 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 cpu + +import "runtime" + +// const cacheLineSize = 64 + +func init() { + switch runtime.GOOS { + case "android", "darwin": + // Android and iOS don't seem to allow reading these registers. + // Fake the minimal features expected by + // TestARM64minimalFeatures. + ARM64.HasASIMD = true + ARM64.HasFP = true + case "linux": + doinit() + default: + readARM64Registers() + } +} + +func readARM64Registers() { + Initialized = true + + // ID_AA64ISAR0_EL1 + isar0 := getisar0() + + switch extractBits(isar0, 4, 7) { + case 1: + ARM64.HasAES = true + case 2: + ARM64.HasAES = true + ARM64.HasPMULL = true + } + + switch extractBits(isar0, 8, 11) { + case 1: + ARM64.HasSHA1 = true + } + + switch extractBits(isar0, 12, 15) { + case 1: + ARM64.HasSHA2 = true + case 2: + ARM64.HasSHA2 = true + ARM64.HasSHA512 = true + } + + switch extractBits(isar0, 16, 19) { + case 1: + ARM64.HasCRC32 = true + } + + switch extractBits(isar0, 20, 23) { + case 2: + ARM64.HasATOMICS = true + } + + switch extractBits(isar0, 28, 31) { + case 1: + ARM64.HasASIMDRDM = true + } + + switch extractBits(isar0, 32, 35) { + case 1: + ARM64.HasSHA3 = true + } + + switch extractBits(isar0, 36, 39) { + case 1: + ARM64.HasSM3 = true + } + + switch extractBits(isar0, 40, 43) { + case 1: + ARM64.HasSM4 = true + } + + switch extractBits(isar0, 44, 47) { + case 1: + ARM64.HasASIMDDP = true + } + + // ID_AA64ISAR1_EL1 + isar1 := getisar1() + + switch extractBits(isar1, 0, 3) { + case 1: + ARM64.HasDCPOP = true + } + + switch extractBits(isar1, 12, 15) { + case 1: + ARM64.HasJSCVT = true + } + + switch extractBits(isar1, 16, 19) { + case 1: + ARM64.HasFCMA = true + } + + switch extractBits(isar1, 20, 23) { + case 1: + ARM64.HasLRCPC = true + } + + // ID_AA64PFR0_EL1 + pfr0 := getpfr0() + + switch extractBits(pfr0, 16, 19) { + case 0: + ARM64.HasFP = true + case 1: + ARM64.HasFP = true + ARM64.HasFPHP = true + } + + switch extractBits(pfr0, 20, 23) { + case 0: + ARM64.HasASIMD = true + case 1: + ARM64.HasASIMD = true + ARM64.HasASIMDHP = true + } + + switch extractBits(pfr0, 32, 35) { + case 1: + ARM64.HasSVE = true + } +} + +func extractBits(data uint64, start, end uint) uint { + return (uint)(data>>start) & ((1 << (end - start + 1)) - 1) +} diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_gc_arm64.go b/libgo/go/golang.org/x/sys/cpu/cpu_gc_arm64.go new file mode 100644 index 00000000000..7b88e865a42 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_gc_arm64.go @@ -0,0 +1,11 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !gccgo + +package cpu + +func getisar0() uint64 +func getisar1() uint64 +func getpfr0() uint64 diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_gccgo_arm64.go b/libgo/go/golang.org/x/sys/cpu/cpu_gccgo_arm64.go new file mode 100644 index 00000000000..53ca8d65c37 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_gccgo_arm64.go @@ -0,0 +1,11 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build gccgo + +package cpu + +func getisar0() uint64 { return 0 } +func getisar1() uint64 { return 0 } +func getpfr0() uint64 { return 0 } diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_gccgo.c b/libgo/go/golang.org/x/sys/cpu/cpu_gccgo_x86.c index e363c7d1319..e363c7d1319 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_gccgo.c +++ b/libgo/go/golang.org/x/sys/cpu/cpu_gccgo_x86.c diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_gccgo.go b/libgo/go/golang.org/x/sys/cpu/cpu_gccgo_x86.go index ba49b91bd39..ba49b91bd39 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_gccgo.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_gccgo_x86.go diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_linux.go b/libgo/go/golang.org/x/sys/cpu/cpu_linux.go index 76b5f507faf..fe139182c8d 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_linux.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_linux.go @@ -2,58 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//+build !amd64,!amd64p32,!386 +// +build !386,!amd64,!amd64p32,!arm64 package cpu -import ( - "io/ioutil" -) - -const ( - _AT_HWCAP = 16 - _AT_HWCAP2 = 26 - - procAuxv = "/proc/self/auxv" - - uintSize = int(32 << (^uint(0) >> 63)) -) - -// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 -// These are initialized in cpu_$GOARCH.go -// and should not be changed after they are initialized. -var hwCap uint -var hwCap2 uint - func init() { - buf, err := ioutil.ReadFile(procAuxv) - if err != nil { - // e.g. on android /proc/self/auxv is not accessible, so silently - // ignore the error and leave Initialized = false + if err := readHWCAP(); err != nil { return } - - bo := hostByteOrder() - for len(buf) >= 2*(uintSize/8) { - var tag, val uint - switch uintSize { - case 32: - tag = uint(bo.Uint32(buf[0:])) - val = uint(bo.Uint32(buf[4:])) - buf = buf[8:] - case 64: - tag = uint(bo.Uint64(buf[0:])) - val = uint(bo.Uint64(buf[8:])) - buf = buf[16:] - } - switch tag { - case _AT_HWCAP: - hwCap = val - case _AT_HWCAP2: - hwCap2 = val - } - } doinit() - Initialized = true } diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_linux_arm.go b/libgo/go/golang.org/x/sys/cpu/cpu_linux_arm.go new file mode 100644 index 00000000000..2057006dce4 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_linux_arm.go @@ -0,0 +1,39 @@ +// Copyright 2019 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 cpu + +func doinit() { + ARM.HasSWP = isSet(hwCap, hwcap_SWP) + ARM.HasHALF = isSet(hwCap, hwcap_HALF) + ARM.HasTHUMB = isSet(hwCap, hwcap_THUMB) + ARM.Has26BIT = isSet(hwCap, hwcap_26BIT) + ARM.HasFASTMUL = isSet(hwCap, hwcap_FAST_MULT) + ARM.HasFPA = isSet(hwCap, hwcap_FPA) + ARM.HasVFP = isSet(hwCap, hwcap_VFP) + ARM.HasEDSP = isSet(hwCap, hwcap_EDSP) + ARM.HasJAVA = isSet(hwCap, hwcap_JAVA) + ARM.HasIWMMXT = isSet(hwCap, hwcap_IWMMXT) + ARM.HasCRUNCH = isSet(hwCap, hwcap_CRUNCH) + ARM.HasTHUMBEE = isSet(hwCap, hwcap_THUMBEE) + ARM.HasNEON = isSet(hwCap, hwcap_NEON) + ARM.HasVFPv3 = isSet(hwCap, hwcap_VFPv3) + ARM.HasVFPv3D16 = isSet(hwCap, hwcap_VFPv3D16) + ARM.HasTLS = isSet(hwCap, hwcap_TLS) + ARM.HasVFPv4 = isSet(hwCap, hwcap_VFPv4) + ARM.HasIDIVA = isSet(hwCap, hwcap_IDIVA) + ARM.HasIDIVT = isSet(hwCap, hwcap_IDIVT) + ARM.HasVFPD32 = isSet(hwCap, hwcap_VFPD32) + ARM.HasLPAE = isSet(hwCap, hwcap_LPAE) + ARM.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) + ARM.HasAES = isSet(hwCap2, hwcap2_AES) + ARM.HasPMULL = isSet(hwCap2, hwcap2_PMULL) + ARM.HasSHA1 = isSet(hwCap2, hwcap2_SHA1) + ARM.HasSHA2 = isSet(hwCap2, hwcap2_SHA2) + ARM.HasCRC32 = isSet(hwCap2, hwcap2_CRC32) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_linux_arm64.go b/libgo/go/golang.org/x/sys/cpu/cpu_linux_arm64.go index 15a9b4a7cc7..79a38a0b9bc 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_linux_arm64.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_linux_arm64.go @@ -33,6 +33,12 @@ const ( ) func doinit() { + if err := readHWCAP(); err != nil { + // failed to read /proc/self/auxv, try reading registers directly + readARM64Registers() + return + } + // HWCAP feature bits ARM64.HasFP = isSet(hwCap, hwcap_FP) ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD) diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_linux_mips64x.go b/libgo/go/golang.org/x/sys/cpu/cpu_linux_mips64x.go new file mode 100644 index 00000000000..eb24e5073e7 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_linux_mips64x.go @@ -0,0 +1,22 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build mips64 mips64le + +package cpu + +// HWCAP bits. These are exposed by the Linux kernel 5.4. +const ( + // CPU features + hwcap_MIPS_MSA = 1 << 1 +) + +func doinit() { + // HWCAP feature bits + MIPS64X.HasMSA = isSet(hwCap, hwcap_MIPS_MSA) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_linux_noinit.go b/libgo/go/golang.org/x/sys/cpu/cpu_linux_noinit.go new file mode 100644 index 00000000000..42b5d33cb69 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_linux_noinit.go @@ -0,0 +1,9 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le,!s390x + +package cpu + +func doinit() {} diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_linux_ppc64x.go b/libgo/go/golang.org/x/sys/cpu/cpu_linux_ppc64x.go index 99f8a6399ef..6b1b8932f16 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_linux_ppc64x.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_linux_ppc64x.go @@ -7,6 +7,8 @@ package cpu +// const cacheLineSize = 128 + // HWCAP/HWCAP2 bits. These are exposed by the kernel. const ( // ISA Level diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_linux_s390x.go b/libgo/go/golang.org/x/sys/cpu/cpu_linux_s390x.go index b88d6b8f662..92f2896ffa0 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_linux_s390x.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_linux_s390x.go @@ -4,6 +4,8 @@ package cpu +// const cacheLineSize = 256 + const ( // bit mask values from /usr/include/bits/hwcap.h hwcap_ZARCH = 2 diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_mips64x.go b/libgo/go/golang.org/x/sys/cpu/cpu_mips64x.go new file mode 100644 index 00000000000..35675579033 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_mips64x.go @@ -0,0 +1,9 @@ +// 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. + +// +build mips64 mips64le + +package cpu + +// const cacheLineSize = 32 diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_mipsx.go b/libgo/go/golang.org/x/sys/cpu/cpu_mipsx.go new file mode 100644 index 00000000000..2af7fa5b0a4 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_mipsx.go @@ -0,0 +1,9 @@ +// 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. + +// +build mips mipsle + +package cpu + +// const cacheLineSize = 32 diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_linux_other.go b/libgo/go/golang.org/x/sys/cpu/cpu_other_arm64.go index 6e8f9fe1920..3ffc4afa03c 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_linux_other.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_other_arm64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!amd64p32,!386,!arm64,!ppc64,!ppc64le,!s390x +// +build !linux,arm64 package cpu diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_riscv64.go b/libgo/go/golang.org/x/sys/cpu/cpu_riscv64.go index 18c8a48b9c3..bc41bbb3b3b 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_riscv64.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_riscv64.go @@ -5,3 +5,5 @@ // +build riscv64 package cpu + +// const cacheLineSize = 32 diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_wasm.go b/libgo/go/golang.org/x/sys/cpu/cpu_wasm.go new file mode 100644 index 00000000000..c890010e308 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_wasm.go @@ -0,0 +1,13 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build wasm + +package cpu + +// We're compiling the cpu package for an unknown (software-abstracted) CPU. +// Make CacheLinePad an empty struct and hope that the usual struct alignment +// rules are good enough. + +// const cacheLineSize = 0 diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_x86.go b/libgo/go/golang.org/x/sys/cpu/cpu_x86.go index 6009379c7fa..d6afec9f97a 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_x86.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_x86.go @@ -6,6 +6,8 @@ package cpu +// const cacheLineSize = 64 + func init() { Initialized = true diff --git a/libgo/go/golang.org/x/sys/cpu/hwcap_linux.go b/libgo/go/golang.org/x/sys/cpu/hwcap_linux.go new file mode 100644 index 00000000000..f3baa379328 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/hwcap_linux.go @@ -0,0 +1,56 @@ +// Copyright 2019 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 cpu + +import ( + "io/ioutil" +) + +const ( + _AT_HWCAP = 16 + _AT_HWCAP2 = 26 + + procAuxv = "/proc/self/auxv" + + uintSize = int(32 << (^uint(0) >> 63)) +) + +// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 +// These are initialized in cpu_$GOARCH.go +// and should not be changed after they are initialized. +var hwCap uint +var hwCap2 uint + +func readHWCAP() error { + buf, err := ioutil.ReadFile(procAuxv) + if err != nil { + // e.g. on android /proc/self/auxv is not accessible, so silently + // ignore the error and leave Initialized = false. On some + // architectures (e.g. arm64) doinit() implements a fallback + // readout and will set Initialized = true again. + return err + } + bo := hostByteOrder() + for len(buf) >= 2*(uintSize/8) { + var tag, val uint + switch uintSize { + case 32: + tag = uint(bo.Uint32(buf[0:])) + val = uint(bo.Uint32(buf[4:])) + buf = buf[8:] + case 64: + tag = uint(bo.Uint64(buf[0:])) + val = uint(bo.Uint64(buf[8:])) + buf = buf[16:] + } + switch tag { + case _AT_HWCAP: + hwCap = val + case _AT_HWCAP2: + hwCap2 = val + } + } + return nil +} diff --git a/libgo/go/golang.org/x/text/unicode/bidi/core.go b/libgo/go/golang.org/x/text/unicode/bidi/core.go index 48d144008aa..50deb6600a3 100644 --- a/libgo/go/golang.org/x/text/unicode/bidi/core.go +++ b/libgo/go/golang.org/x/text/unicode/bidi/core.go @@ -480,15 +480,15 @@ func (s *isolatingRunSequence) resolveWeakTypes() { // Rule W1. // Changes all NSMs. - preceedingCharacterType := s.sos + precedingCharacterType := s.sos for i, t := range s.types { if t == NSM { - s.types[i] = preceedingCharacterType + s.types[i] = precedingCharacterType } else { if t.in(LRI, RLI, FSI, PDI) { - preceedingCharacterType = ON + precedingCharacterType = ON } - preceedingCharacterType = t + precedingCharacterType = t } } diff --git a/libgo/go/golang.org/x/tools/go/analysis/analysis.go b/libgo/go/golang.org/x/tools/go/analysis/analysis.go index ea605f4fd46..8c9977355c9 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/analysis.go +++ b/libgo/go/golang.org/x/tools/go/analysis/analysis.go @@ -7,6 +7,8 @@ import ( "go/token" "go/types" "reflect" + + "golang.org/x/tools/internal/analysisinternal" ) // An Analyzer describes an analysis function and its options. @@ -69,6 +71,17 @@ type Analyzer struct { func (a *Analyzer) String() string { return a.Name } +func init() { + // Set the analysisinternal functions to be able to pass type errors + // to the Pass type without modifying the go/analysis API. + analysisinternal.SetTypeErrors = func(p interface{}, errors []types.Error) { + p.(*Pass).typeErrors = errors + } + analysisinternal.GetTypeErrors = func(p interface{}) []types.Error { + return p.(*Pass).typeErrors + } +} + // A Pass provides information to the Run function that // applies a specific analyzer to a single Go package. // @@ -138,6 +151,9 @@ type Pass struct { // WARNING: This is an experimental API and may change in the future. AllObjectFacts func() []ObjectFact + // typeErrors contains types.Errors that are associated with the pkg. + typeErrors []types.Error + /* Further fields may be added in future. */ // For example, suggested or applied refactorings. } diff --git a/libgo/go/golang.org/x/tools/go/analysis/doc.go b/libgo/go/golang.org/x/tools/go/analysis/doc.go index a2353fc88b9..fb17a0e4154 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/doc.go +++ b/libgo/go/golang.org/x/tools/go/analysis/doc.go @@ -1,8 +1,9 @@ /* -The analysis package defines the interface between a modular static +Package analysis defines the interface between a modular static analysis and an analysis driver program. + Background A static analysis is a function that inspects a package of Go code and @@ -41,9 +42,9 @@ the go/analysis/passes/ subdirectory: package unusedresult var Analyzer = &analysis.Analyzer{ - Name: "unusedresult", - Doc: "check for unused results of calls to some functions", - Run: run, + Name: "unusedresult", + Doc: "check for unused results of calls to some functions", + Run: run, ... } @@ -51,7 +52,6 @@ the go/analysis/passes/ subdirectory: ... } - An analysis driver is a program such as vet that runs a set of analyses and prints the diagnostics that they report. The driver program must import the list of Analyzers it needs. @@ -70,51 +70,18 @@ A driver may use the name, flags, and documentation to provide on-line help that describes the analyses it performs. The doc comment contains a brief one-line summary, optionally followed by paragraphs of explanation. -The vet command, shown below, is an example of a driver that runs -multiple analyzers. It is based on the multichecker package -(see the "Standalone commands" section for details). - - $ go build golang.org/x/tools/go/analysis/cmd/vet - $ ./vet help - vet is a tool for static analysis of Go programs. - - Usage: vet [-flag] [package] - - Registered analyzers: - - asmdecl report mismatches between assembly files and Go declarations - assign check for useless assignments - atomic check for common mistakes using the sync/atomic package - ... - unusedresult check for unused results of calls to some functions - - $ ./vet help unusedresult - unusedresult: check for unused results of calls to some functions - - Analyzer flags: - - -unusedresult.funcs value - comma-separated list of functions whose results must be used (default Error,String) - -unusedresult.stringmethods value - comma-separated list of names of methods of type func() string whose results must be used - - Some functions like fmt.Errorf return a result and have no side effects, - so it is always a mistake to discard the result. This analyzer reports - calls to certain functions in which the result of the call is ignored. - - The set of functions may be controlled using flags. The Analyzer type has more fields besides those shown above: type Analyzer struct { - Name string - Doc string - Flags flag.FlagSet - Run func(*Pass) (interface{}, error) - RunDespiteErrors bool - ResultType reflect.Type - Requires []*Analyzer - FactTypes []Fact + Name string + Doc string + Flags flag.FlagSet + Run func(*Pass) (interface{}, error) + RunDespiteErrors bool + ResultType reflect.Type + Requires []*Analyzer + FactTypes []Fact } The Flags field declares a set of named (global) flag variables that @@ -154,13 +121,13 @@ package being analyzed, and provides operations to the Run function for reporting diagnostics and other information back to the driver. type Pass struct { - Fset *token.FileSet - Files []*ast.File - OtherFiles []string - Pkg *types.Package - TypesInfo *types.Info - ResultOf map[*Analyzer]interface{} - Report func(Diagnostic) + Fset *token.FileSet + Files []*ast.File + OtherFiles []string + Pkg *types.Package + TypesInfo *types.Info + ResultOf map[*Analyzer]interface{} + Report func(Diagnostic) ... } @@ -203,6 +170,15 @@ Diagnostic is defined as: The optional Category field is a short identifier that classifies the kind of message when an analysis produces several kinds of diagnostic. +Many analyses want to associate diagnostics with a severity level. +Because Diagnostic does not have a severity level field, an Analyzer's +diagnostics effectively all have the same severity level. To separate which +diagnostics are high severity and which are low severity, expose multiple +Analyzers instead. Analyzers should also be separated when their +diagnostics belong in different groups, or could be tagged differently +before being shown to the end user. Analyzers should document their severity +level to help downstream tools surface diagnostics properly. + Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl and buildtag, inspect the raw text of Go source files or even non-Go files such as assembly. To report a diagnostic against a line of a @@ -245,7 +221,7 @@ package. An Analyzer that uses facts must declare their types: var Analyzer = &analysis.Analyzer{ - Name: "printf", + Name: "printf", FactTypes: []analysis.Fact{new(isWrapper)}, ... } @@ -330,7 +306,5 @@ entirety as: A tool that provides multiple analyzers can use multichecker in a similar way, giving it the list of Analyzers. - - */ package analysis diff --git a/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go b/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go index 0778f422074..4b7be2d1f5f 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go +++ b/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go @@ -382,7 +382,7 @@ func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis. func (tree JSONTree) Print() { data, err := json.MarshalIndent(tree, "", "\t") if err != nil { - log.Panicf("internal error: JSON marshalling failed: %v", err) + log.Panicf("internal error: JSON marshaling failed: %v", err) } fmt.Printf("%s\n", data) } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/libgo/go/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go index 7f7ca088b25..132bdf70fa2 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go @@ -41,7 +41,7 @@ var Analyzer = &analysis.Analyzer{ } func run(pass *analysis.Pass) (interface{}, error) { - if runtime.Compiler != "gccgo" && imports(pass.Pkg, "runtime/cgo") == nil { + if runtime.Compiler != "gccgo" && !analysisutil.Imports(pass.Pkg, "runtime/cgo") { return nil, nil // doesn't use cgo } @@ -375,15 +375,3 @@ func imported(info *types.Info, spec *ast.ImportSpec) *types.Package { } return obj.(*types.PkgName).Imported() } - -// imports reports whether pkg has path among its direct imports. -// It returns the imported package if so, or nil if not. -// TODO(adonovan): move to analysisutil. -func imports(pkg *types.Package, path string) *types.Package { - for _, imp := range pkg.Imports() { - if imp.Path() == path { - return imp - } - } - return nil -} diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/libgo/go/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go index b80271afb95..384f0255704 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go @@ -51,7 +51,7 @@ func run(pass *analysis.Pass) (interface{}, error) { return // not enough arguments, e.g. called with return values of another function } if fn.FullName() == "errors.As" && !pointerToInterfaceOrError(pass, call.Args[1]) { - pass.ReportRangef(call, "second argument to errors.As must be a pointer to an interface or a type implementing error") + pass.ReportRangef(call, "second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type") } }) return nil, nil diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go b/libgo/go/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go index ec335d35061..fd9e2af2b18 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go @@ -12,6 +12,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" ) @@ -43,7 +44,7 @@ func run(pass *analysis.Pass) (interface{}, error) { // Fast path: if the package doesn't import net/http, // skip the traversal. - if !imports(pass.Pkg, "net/http") { + if !analysisutil.Imports(pass.Pkg, "net/http") { return nil, nil } @@ -166,12 +167,3 @@ func isNamedType(t types.Type, path, name string) bool { obj := n.Obj() return obj.Name() == name && obj.Pkg() != nil && obj.Pkg().Path() == path } - -func imports(pkg *types.Package, path string) bool { - for _, imp := range pkg.Imports() { - if imp.Path() == path { - return true - } - } - return false -} diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go b/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go new file mode 100644 index 00000000000..c5a71a7c570 --- /dev/null +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go @@ -0,0 +1,101 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package ifaceassert defines an Analyzer that flags +// impossible interface-interface type assertions. +package ifaceassert + +import ( + "go/ast" + "go/types" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +const Doc = `detect impossible interface-to-interface type assertions + +This checker flags type assertions v.(T) and corresponding type-switch cases +in which the static type V of v is an interface that cannot possibly implement +the target interface T. This occurs when V and T contain methods with the same +name but different signatures. Example: + + var v interface { + Read() + } + _ = v.(io.Reader) + +The Read method in v has a different signature than the Read method in +io.Reader, so this assertion cannot succeed. +` + +var Analyzer = &analysis.Analyzer{ + Name: "ifaceassert", + Doc: Doc, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: run, +} + +// assertableTo checks whether interface v can be asserted into t. It returns +// nil on success, or the first conflicting method on failure. +func assertableTo(v, t types.Type) *types.Func { + // ensure that v and t are interfaces + V, _ := v.Underlying().(*types.Interface) + T, _ := t.Underlying().(*types.Interface) + if V == nil || T == nil { + return nil + } + if f, wrongType := types.MissingMethod(V, T, false); wrongType { + return f + } + return nil +} + +func run(pass *analysis.Pass) (interface{}, error) { + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + nodeFilter := []ast.Node{ + (*ast.TypeAssertExpr)(nil), + (*ast.TypeSwitchStmt)(nil), + } + inspect.Preorder(nodeFilter, func(n ast.Node) { + var ( + assert *ast.TypeAssertExpr // v.(T) expression + targets []ast.Expr // interfaces T in v.(T) + ) + switch n := n.(type) { + case *ast.TypeAssertExpr: + // take care of v.(type) in *ast.TypeSwitchStmt + if n.Type == nil { + return + } + assert = n + targets = append(targets, n.Type) + case *ast.TypeSwitchStmt: + // retrieve type assertion from type switch's 'assign' field + switch t := n.Assign.(type) { + case *ast.ExprStmt: + assert = t.X.(*ast.TypeAssertExpr) + case *ast.AssignStmt: + assert = t.Rhs[0].(*ast.TypeAssertExpr) + } + // gather target types from case clauses + for _, c := range n.Body.List { + targets = append(targets, c.(*ast.CaseClause).List...) + } + } + V := pass.TypesInfo.TypeOf(assert.X) + for _, target := range targets { + T := pass.TypesInfo.TypeOf(target) + if f := assertableTo(V, T); f != nil { + pass.Reportf( + target.Pos(), + "impossible type assertion: no type can implement both %v and %v (conflicting types for %v method)", + V, T, f.Name(), + ) + } + } + }) + return nil, nil +} diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go b/libgo/go/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go index 13a458d9d6b..80c9476fcdd 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go @@ -104,3 +104,13 @@ func LineStart(f *token.File, line int) token.Pos { } } } + +// Imports returns true if path is imported by pkg. +func Imports(pkg *types.Package, path string) bool { + for _, imp := range pkg.Imports() { + if imp.Path() == path { + return true + } + } + return false +} diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go index e6177f2ea9b..ddad4c796cb 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file contains the printf-checker. - +// Package printf defines an Analyzer that checks consistency +// of Printf format strings and arguments. package printf import ( @@ -508,9 +508,13 @@ func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, return fn, KindNone } -// isFormatter reports whether t satisfies fmt.Formatter. +// isFormatter reports whether t could satisfy fmt.Formatter. // The only interface method to look for is "Format(State, rune)". func isFormatter(typ types.Type) bool { + // If the type is an interface, the value it holds might satisfy fmt.Formatter. + if _, ok := typ.Underlying().(*types.Interface); ok { + return true + } obj, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Format") fn, ok := obj.(*types.Func) if !ok { @@ -828,7 +832,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o } } - // Does current arg implement fmt.Formatter? + // Could current arg implement fmt.Formatter? formatter := false if state.argNum < len(call.Args) { if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok { @@ -892,43 +896,51 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString) return false } - if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && recursiveStringer(pass, arg) { - pass.ReportRangef(call, "%s format %s with arg %s causes recursive String method call", state.name, state.format, analysisutil.Format(pass.Fset, arg)) - return false + if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) { + if methodName, ok := recursiveStringer(pass, arg); ok { + pass.ReportRangef(call, "%s format %s with arg %s causes recursive %s method call", state.name, state.format, analysisutil.Format(pass.Fset, arg), methodName) + return false + } } return true } // recursiveStringer reports whether the argument e is a potential -// recursive call to stringer, such as t and &t in these examples: +// recursive call to stringer or is an error, such as t and &t in these examples: // // func (t *T) String() string { printf("%s", t) } -// func (t T) String() string { printf("%s", t) } +// func (t T) Error() string { printf("%s", t) } // func (t T) String() string { printf("%s", &t) } -// -func recursiveStringer(pass *analysis.Pass, e ast.Expr) bool { +func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool) { typ := pass.TypesInfo.Types[e].Type // It's unlikely to be a recursive stringer if it has a Format method. if isFormatter(typ) { - return false + return "", false } - // Does e allow e.String()? - obj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "String") - stringMethod, ok := obj.(*types.Func) - if !ok { - return false + // Does e allow e.String() or e.Error()? + strObj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "String") + strMethod, strOk := strObj.(*types.Func) + errObj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "Error") + errMethod, errOk := errObj.(*types.Func) + if !strOk && !errOk { + return "", false } - // Is the expression e within the body of that String method? - if stringMethod.Pkg() != pass.Pkg || !stringMethod.Scope().Contains(e.Pos()) { - return false + // Is the expression e within the body of that String or Error method? + var method *types.Func + if strOk && strMethod.Pkg() == pass.Pkg && strMethod.Scope().Contains(e.Pos()) { + method = strMethod + } else if errOk && errMethod.Pkg() == pass.Pkg && errMethod.Scope().Contains(e.Pos()) { + method = errMethod + } else { + return "", false } - sig := stringMethod.Type().(*types.Signature) + sig := method.Type().(*types.Signature) if !isStringer(sig) { - return false + return "", false } // Is it the receiver r, or &r? @@ -936,9 +948,11 @@ func recursiveStringer(pass *analysis.Pass, e ast.Expr) bool { e = u.X // strip off & from &r } if id, ok := e.(*ast.Ident); ok { - return pass.TypesInfo.Uses[id] == sig.Recv() + if pass.TypesInfo.Uses[id] == sig.Recv() { + return method.Name(), true + } } - return false + return "", false } // isStringer reports whether the method signature matches the String() definition in fmt.Stringer. @@ -1062,8 +1076,8 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { if isFunctionValue(pass, arg) { pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.Name(), analysisutil.Format(pass.Fset, arg)) } - if recursiveStringer(pass, arg) { - pass.ReportRangef(call, "%s arg %s causes recursive call to String method", fn.Name(), analysisutil.Format(pass.Fset, arg)) + if methodName, ok := recursiveStringer(pass, arg); ok { + pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.Name(), analysisutil.Format(pass.Fset, arg), methodName) } } } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/stringintconv/string.go b/libgo/go/golang.org/x/tools/go/analysis/passes/stringintconv/string.go new file mode 100644 index 00000000000..7a005901e84 --- /dev/null +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/stringintconv/string.go @@ -0,0 +1,126 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package stringintconv defines an Analyzer that flags type conversions +// from integers to strings. +package stringintconv + +import ( + "fmt" + "go/ast" + "go/types" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +const Doc = `check for string(int) conversions + +This checker flags conversions of the form string(x) where x is an integer +(but not byte or rune) type. Such conversions are discouraged because they +return the UTF-8 representation of the Unicode code point x, and not a decimal +string representation of x as one might expect. Furthermore, if x denotes an +invalid code point, the conversion cannot be statically rejected. + +For conversions that intend on using the code point, consider replacing them +with string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the +string representation of the value in the desired base. +` + +var Analyzer = &analysis.Analyzer{ + Name: "stringintconv", + Doc: Doc, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: run, +} + +func typeName(typ types.Type) string { + if v, _ := typ.(interface{ Name() string }); v != nil { + return v.Name() + } + if v, _ := typ.(interface{ Obj() *types.TypeName }); v != nil { + return v.Obj().Name() + } + return "" +} + +func run(pass *analysis.Pass) (interface{}, error) { + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + nodeFilter := []ast.Node{ + (*ast.CallExpr)(nil), + } + inspect.Preorder(nodeFilter, func(n ast.Node) { + call := n.(*ast.CallExpr) + + // Retrieve target type name. + var tname *types.TypeName + switch fun := call.Fun.(type) { + case *ast.Ident: + tname, _ = pass.TypesInfo.Uses[fun].(*types.TypeName) + case *ast.SelectorExpr: + tname, _ = pass.TypesInfo.Uses[fun.Sel].(*types.TypeName) + } + if tname == nil { + return + } + target := tname.Name() + + // Check that target type T in T(v) has an underlying type of string. + T, _ := tname.Type().Underlying().(*types.Basic) + if T == nil || T.Kind() != types.String { + return + } + if s := T.Name(); target != s { + target += " (" + s + ")" + } + + // Check that type V of v has an underlying integral type that is not byte or rune. + if len(call.Args) != 1 { + return + } + v := call.Args[0] + vtyp := pass.TypesInfo.TypeOf(v) + V, _ := vtyp.Underlying().(*types.Basic) + if V == nil || V.Info()&types.IsInteger == 0 { + return + } + switch V.Kind() { + case types.Byte, types.Rune, types.UntypedRune: + return + } + + // Retrieve source type name. + source := typeName(vtyp) + if source == "" { + return + } + if s := V.Name(); source != s { + source += " (" + s + ")" + } + diag := analysis.Diagnostic{ + Pos: n.Pos(), + Message: fmt.Sprintf("conversion from %s to %s yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)", source, target), + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Did you mean to convert a rune to a string?", + TextEdits: []analysis.TextEdit{ + { + Pos: v.Pos(), + End: v.Pos(), + NewText: []byte("rune("), + }, + { + Pos: v.End(), + End: v.End(), + NewText: []byte(")"), + }, + }, + }, + }, + } + pass.Report(diag) + }) + return nil, nil +} diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go b/libgo/go/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go index 089c064838d..90896dd1bb9 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go @@ -189,7 +189,18 @@ func (d *deadState) findDead(stmt ast.Stmt) { case *ast.EmptyStmt: // do not warn about unreachable empty statements default: - d.pass.ReportRangef(stmt, "unreachable code") + d.pass.Report(analysis.Diagnostic{ + Pos: stmt.Pos(), + End: stmt.End(), + Message: "unreachable code", + SuggestedFixes: []analysis.SuggestedFix{{ + Message: "Remove", + TextEdits: []analysis.TextEdit{{ + Pos: stmt.Pos(), + End: stmt.End(), + }}, + }}, + }) d.reachable = true // silence error about next statement } } diff --git a/libgo/go/golang.org/x/tools/go/ast/astutil/imports.go b/libgo/go/golang.org/x/tools/go/ast/astutil/imports.go index 3e4b195368b..2087ceec9cf 100644 --- a/libgo/go/golang.org/x/tools/go/ast/astutil/imports.go +++ b/libgo/go/golang.org/x/tools/go/ast/astutil/imports.go @@ -275,9 +275,10 @@ func DeleteNamedImport(fset *token.FileSet, f *ast.File, name, path string) (del // We deleted an entry but now there may be // a blank line-sized hole where the import was. - if line-lastLine > 1 { + if line-lastLine > 1 || !gen.Rparen.IsValid() { // There was a blank line immediately preceding the deleted import, - // so there's no need to close the hole. + // so there's no need to close the hole. The right parenthesis is + // invalid after AddImport to an import statement without parenthesis. // Do nothing. } else if line != fset.File(gen.Rparen).LineCount() { // There was no blank line. Close the hole. diff --git a/libgo/go/golang.org/x/tools/go/ast/inspector/inspector.go b/libgo/go/golang.org/x/tools/go/ast/inspector/inspector.go index ddbdd3f08fc..af5e17feeea 100644 --- a/libgo/go/golang.org/x/tools/go/ast/inspector/inspector.go +++ b/libgo/go/golang.org/x/tools/go/ast/inspector/inspector.go @@ -90,7 +90,7 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { // The types argument, if non-empty, enables type-based filtering of // events. The function f if is called only for nodes whose type // matches an element of the types slice. -func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (prune bool)) { +func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (proceed bool)) { mask := maskOf(types) for i := 0; i < len(in.events); { ev := in.events[i] @@ -114,7 +114,7 @@ func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (prun // supplies each call to f an additional argument, the current // traversal stack. The stack's first element is the outermost node, // an *ast.File; its last is the innermost, n. -func (in *Inspector) WithStack(types []ast.Node, f func(n ast.Node, push bool, stack []ast.Node) (prune bool)) { +func (in *Inspector) WithStack(types []ast.Node, f func(n ast.Node, push bool, stack []ast.Node) (proceed bool)) { mask := maskOf(types) var stack []ast.Node for i := 0; i < len(in.events); { @@ -150,7 +150,11 @@ func traverse(files []*ast.File) []event { extent += int(f.End() - f.Pos()) } // This estimate is based on the net/http package. - events := make([]event, 0, extent*33/100) + capacity := extent * 33 / 100 + if capacity > 1e6 { + capacity = 1e6 // impose some reasonable maximum + } + events := make([]event, 0, capacity) var stack []event for _, f := range files { diff --git a/libgo/go/golang.org/x/tools/go/cfg/cfg.go b/libgo/go/golang.org/x/tools/go/cfg/cfg.go index b075034bb45..3ebc65f60e5 100644 --- a/libgo/go/golang.org/x/tools/go/cfg/cfg.go +++ b/libgo/go/golang.org/x/tools/go/cfg/cfg.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This package constructs a simple control-flow graph (CFG) of the +// Package cfg constructs a simple control-flow graph (CFG) of the // statements and expressions within a single function. // // Use cfg.New to construct the CFG for a function body. diff --git a/libgo/go/golang.org/x/tools/go/types/objectpath/objectpath.go b/libgo/go/golang.org/x/tools/go/types/objectpath/objectpath.go index 882e3b3d8a9..cffd7acbee7 100644 --- a/libgo/go/golang.org/x/tools/go/types/objectpath/objectpath.go +++ b/libgo/go/golang.org/x/tools/go/types/objectpath/objectpath.go @@ -226,7 +226,8 @@ func For(obj types.Object) (Path, error) { // the best paths because non-types may // refer to types, but not the reverse. empty := make([]byte, 0, 48) // initial space - for _, name := range scope.Names() { + names := scope.Names() + for _, name := range names { o := scope.Lookup(name) tname, ok := o.(*types.TypeName) if !ok { @@ -253,7 +254,7 @@ func For(obj types.Object) (Path, error) { // Then inspect everything else: // non-types, and declared methods of defined types. - for _, name := range scope.Names() { + for _, name := range names { o := scope.Lookup(name) path := append(empty, name...) if _, ok := o.(*types.TypeName); !ok { diff --git a/libgo/go/golang.org/x/tools/internal/analysisinternal/analysis.go b/libgo/go/golang.org/x/tools/internal/analysisinternal/analysis.go new file mode 100644 index 00000000000..26586810c7f --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/analysisinternal/analysis.go @@ -0,0 +1,118 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package analysisinternal exposes internal-only fields from go/analysis. +package analysisinternal + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "go/types" + "strings" + + "golang.org/x/tools/go/ast/astutil" +) + +func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos { + // Get the end position for the type error. + offset, end := fset.PositionFor(start, false).Offset, start + if offset >= len(src) { + return end + } + if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 { + end = start + token.Pos(width) + } + return end +} + +func ZeroValue(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { + under := typ + if n, ok := typ.(*types.Named); ok { + under = n.Underlying() + } + switch u := under.(type) { + case *types.Basic: + switch { + case u.Info()&types.IsNumeric != 0: + return &ast.BasicLit{Kind: token.INT, Value: "0"} + case u.Info()&types.IsBoolean != 0: + return &ast.Ident{Name: "false"} + case u.Info()&types.IsString != 0: + return &ast.BasicLit{Kind: token.STRING, Value: `""`} + default: + panic("unknown basic type") + } + case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice: + return ast.NewIdent("nil") + case *types.Struct: + texpr := typeExpr(fset, f, pkg, typ) // typ because we want the name here. + if texpr == nil { + return nil + } + return &ast.CompositeLit{ + Type: texpr, + } + case *types.Array: + texpr := typeExpr(fset, f, pkg, u.Elem()) + if texpr == nil { + return nil + } + return &ast.CompositeLit{ + Type: &ast.ArrayType{ + Elt: texpr, + Len: &ast.BasicLit{Kind: token.INT, Value: fmt.Sprintf("%v", u.Len())}, + }, + } + } + return nil +} + +func typeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { + switch t := typ.(type) { + case *types.Basic: + switch t.Kind() { + case types.UnsafePointer: + return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")} + default: + return ast.NewIdent(t.Name()) + } + case *types.Named: + if t.Obj().Pkg() == pkg { + return ast.NewIdent(t.Obj().Name()) + } + pkgName := t.Obj().Pkg().Name() + // If the file already imports the package under another name, use that. + for _, group := range astutil.Imports(fset, f) { + for _, cand := range group { + if strings.Trim(cand.Path.Value, `"`) == t.Obj().Pkg().Path() { + if cand.Name != nil && cand.Name.Name != "" { + pkgName = cand.Name.Name + } + } + } + } + if pkgName == "." { + return ast.NewIdent(t.Obj().Name()) + } + return &ast.SelectorExpr{ + X: ast.NewIdent(pkgName), + Sel: ast.NewIdent(t.Obj().Name()), + } + default: + return nil // TODO: anonymous structs, but who does that + } +} + +var GetTypeErrors = func(p interface{}) []types.Error { return nil } +var SetTypeErrors = func(p interface{}, errors []types.Error) {} + +type TypeErrorPass string + +const ( + NoNewVars TypeErrorPass = "nonewvars" + NoResultValues TypeErrorPass = "noresultvalues" + UndeclaredName TypeErrorPass = "undeclaredname" +) diff --git a/libgo/go/golang.org/x/xerrors/fmt.go b/libgo/go/golang.org/x/xerrors/fmt.go index 74c1c93ec9c..829862ddf6a 100644 --- a/libgo/go/golang.org/x/xerrors/fmt.go +++ b/libgo/go/golang.org/x/xerrors/fmt.go @@ -7,10 +7,14 @@ package xerrors import ( "fmt" "strings" + "unicode" + "unicode/utf8" "golang.org/x/xerrors/internal" ) +const percentBangString = "%!" + // Errorf formats according to a format specifier and returns the string as a // value that satisfies error. // @@ -18,29 +22,71 @@ import ( // formatted with additional detail enabled. If the last argument is an error // the returned error's Format method will return it if the format string ends // with ": %s", ": %v", or ": %w". If the last argument is an error and the -// format string ends with ": %w", the returned error implements Wrapper -// with an Unwrap method returning it. +// format string ends with ": %w", the returned error implements an Unwrap +// method returning it. +// +// If the format specifier includes a %w verb with an error operand in a +// position other than at the end, the returned error will still implement an +// Unwrap method returning the operand, but the error's Format method will not +// return the wrapped error. +// +// It is invalid to include more than one %w verb or to supply it with an +// operand that does not implement the error interface. The %w verb is otherwise +// a synonym for %v. func Errorf(format string, a ...interface{}) error { - err, wrap := lastError(format, a) format = formatPlusW(format) - if err == nil { - return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)} + // Support a ": %[wsv]" suffix, which works well with xerrors.Formatter. + wrap := strings.HasSuffix(format, ": %w") + idx, format2, ok := parsePercentW(format) + percentWElsewhere := !wrap && idx >= 0 + if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) { + err := errorAt(a, len(a)-1) + if err == nil { + return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)} + } + // TODO: this is not entirely correct. The error value could be + // printed elsewhere in format if it mixes numbered with unnumbered + // substitutions. With relatively small changes to doPrintf we can + // have it optionally ignore extra arguments and pass the argument + // list in its entirety. + msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...) + frame := Frame{} + if internal.EnableTrace { + frame = Caller(1) + } + if wrap { + return &wrapError{msg, err, frame} + } + return &noWrapError{msg, err, frame} + } + // Support %w anywhere. + // TODO: don't repeat the wrapped error's message when %w occurs in the middle. + msg := fmt.Sprintf(format2, a...) + if idx < 0 { + return &noWrapError{msg, nil, Caller(1)} + } + err := errorAt(a, idx) + if !ok || err == nil { + // Too many %ws or argument of %w is not an error. Approximate the Go + // 1.13 fmt.Errorf message. + return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)} } - - // TODO: this is not entirely correct. The error value could be - // printed elsewhere in format if it mixes numbered with unnumbered - // substitutions. With relatively small changes to doPrintf we can - // have it optionally ignore extra arguments and pass the argument - // list in its entirety. - msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...) frame := Frame{} if internal.EnableTrace { frame = Caller(1) } - if wrap { - return &wrapError{msg, err, frame} + return &wrapError{msg, err, frame} +} + +func errorAt(args []interface{}, i int) error { + if i < 0 || i >= len(args) { + return nil } - return &noWrapError{msg, err, frame} + err, ok := args[i].(error) + if !ok { + return nil + } + return err } // formatPlusW is used to avoid the vet check that will barf at %w. @@ -48,24 +94,56 @@ func formatPlusW(s string) string { return s } -func lastError(format string, a []interface{}) (err error, wrap bool) { - wrap = strings.HasSuffix(format, ": %w") - if !wrap && - !strings.HasSuffix(format, ": %s") && - !strings.HasSuffix(format, ": %v") { - return nil, false - } - - if len(a) == 0 { - return nil, false +// Return the index of the only %w in format, or -1 if none. +// Also return a rewritten format string with %w replaced by %v, and +// false if there is more than one %w. +// TODO: handle "%[N]w". +func parsePercentW(format string) (idx int, newFormat string, ok bool) { + // Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go. + idx = -1 + ok = true + n := 0 + sz := 0 + var isW bool + for i := 0; i < len(format); i += sz { + if format[i] != '%' { + sz = 1 + continue + } + // "%%" is not a format directive. + if i+1 < len(format) && format[i+1] == '%' { + sz = 2 + continue + } + sz, isW = parsePrintfVerb(format[i:]) + if isW { + if idx >= 0 { + ok = false + } else { + idx = n + } + // "Replace" the last character, the 'w', with a 'v'. + p := i + sz - 1 + format = format[:p] + "v" + format[p+1:] + } + n++ } + return idx, format, ok +} - err, ok := a[len(a)-1].(error) - if !ok { - return nil, false +// Parse the printf verb starting with a % at s[0]. +// Return how many bytes it occupies and whether the verb is 'w'. +func parsePrintfVerb(s string) (int, bool) { + // Assume only that the directive is a sequence of non-letters followed by a single letter. + sz := 0 + var r rune + for i := 1; i < len(s); i += sz { + r, sz = utf8.DecodeRuneInString(s[i:]) + if unicode.IsLetter(r) { + return i + sz, r == 'w' + } } - - return err, wrap + return len(s), false } type noWrapError struct { |