mirror of https://github.com/golang/go.git
Merge branch 'master' into neilalexander/doc330852
This commit is contained in:
commit
99306054bc
1
AUTHORS
1
AUTHORS
|
|
@ -817,6 +817,7 @@ Lehner Florian <dev@der-flo.net>
|
|||
Leigh McCulloch <leighmcc@gmail.com>
|
||||
Leo Antunes <leo@costela.net>
|
||||
Leon Klingele <git@leonklingele.de>
|
||||
Leonard Wang <wangdeyu0907@gmail.com> <wangdeyu@golangcn.org>
|
||||
Leonel Quinteros <leonel.quinteros@gmail.com>
|
||||
Lev Shamardin <shamardin@gmail.com>
|
||||
Lewin Bormann <lewin.bormann@gmail.com>
|
||||
|
|
|
|||
|
|
@ -1569,7 +1569,7 @@ Leigh McCulloch <leighmcc@gmail.com>
|
|||
Leo Antunes <leo@costela.net>
|
||||
Leo Rudberg <ljr@google.com>
|
||||
Leon Klingele <git@leonklingele.de>
|
||||
Leonard Wang <wangdeyu0907@gmail.com>
|
||||
Leonard Wang <wangdeyu0907@gmail.com> <wangdeyu@golangcn.org>
|
||||
Leonardo Comelli <leonardo.comelli@gmail.com>
|
||||
Leonel Quinteros <leonel.quinteros@gmail.com>
|
||||
Lev Shamardin <shamardin@gmail.com>
|
||||
|
|
|
|||
108
api/next.txt
108
api/next.txt
|
|
@ -8,114 +8,6 @@ pkg runtime/debug, type BuildInfo struct, Settings []BuildSetting
|
|||
pkg runtime/debug, type BuildSetting struct
|
||||
pkg runtime/debug, type BuildSetting struct, Key string
|
||||
pkg runtime/debug, type BuildSetting struct, Value string
|
||||
pkg syscall (darwin-amd64), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (darwin-amd64), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (darwin-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (darwin-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (darwin-amd64-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (darwin-amd64-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (darwin-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (darwin-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (freebsd-386), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (freebsd-386), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (freebsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (freebsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (freebsd-386-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (freebsd-386-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (freebsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (freebsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (freebsd-amd64), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (freebsd-amd64), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (freebsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (freebsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (freebsd-amd64-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (freebsd-amd64-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (freebsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (freebsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (freebsd-arm), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (freebsd-arm), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (freebsd-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (freebsd-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (freebsd-arm-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (freebsd-arm-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (freebsd-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (freebsd-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (linux-386), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (linux-386), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (linux-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (linux-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (linux-386-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (linux-386-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (linux-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (linux-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (linux-amd64), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (linux-amd64), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (linux-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (linux-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (linux-amd64-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (linux-amd64-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (linux-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (linux-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (linux-arm), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (linux-arm), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (linux-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (linux-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (linux-arm-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (linux-arm-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (linux-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (linux-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (netbsd-386), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (netbsd-386), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (netbsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (netbsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (netbsd-386-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (netbsd-386-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (netbsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (netbsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (netbsd-amd64), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (netbsd-amd64), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (netbsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (netbsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (netbsd-amd64-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (netbsd-amd64-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (netbsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (netbsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (netbsd-arm), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (netbsd-arm), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (netbsd-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (netbsd-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (netbsd-arm-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (netbsd-arm-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (netbsd-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (netbsd-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (netbsd-arm64), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (netbsd-arm64), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (netbsd-arm64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (netbsd-arm64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (netbsd-arm64-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (netbsd-arm64-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (netbsd-arm64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (netbsd-arm64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (openbsd-386), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (openbsd-386), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (openbsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (openbsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (openbsd-386-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (openbsd-386-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (openbsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (openbsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (openbsd-amd64), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (openbsd-amd64), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (openbsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (openbsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (openbsd-amd64-cgo), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
|
||||
pkg syscall (openbsd-amd64-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
|
||||
pkg syscall (openbsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
|
||||
pkg syscall (openbsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
|
||||
pkg syscall (windows-386), func WSASendtoInet4(Handle, *WSABuf, uint32, *uint32, uint32, SockaddrInet4, *Overlapped, *uint8) error
|
||||
pkg syscall (windows-386), func WSASendtoInet6(Handle, *WSABuf, uint32, *uint32, uint32, SockaddrInet6, *Overlapped, *uint8) error
|
||||
pkg syscall (windows-amd64), func WSASendtoInet4(Handle, *WSABuf, uint32, *uint32, uint32, SockaddrInet4, *Overlapped, *uint8) error
|
||||
pkg syscall (windows-amd64), func WSASendtoInet6(Handle, *WSABuf, uint32, *uint32, uint32, SockaddrInet6, *Overlapped, *uint8) error
|
||||
pkg testing, func Fuzz(func(*F)) FuzzResult
|
||||
pkg testing, func MainStart(testDeps, []InternalTest, []InternalBenchmark, []InternalFuzzTarget, []InternalExample) *M
|
||||
pkg testing, func RunFuzzTargets(func(string, string) (bool, error), []InternalFuzzTarget) bool
|
||||
|
|
|
|||
225
doc/go1.18.html
225
doc/go1.18.html
|
|
@ -31,19 +31,30 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
|
||||
<h2 id="ports">Ports</h2>
|
||||
|
||||
<p id="freebsd">
|
||||
<h3 id="freebsd">FreeBSD</h3>
|
||||
|
||||
<p>
|
||||
Go 1.18 is the last release that is supported on FreeBSD 11.x, which has
|
||||
already reached end-of-life. Go 1.19 will require FreeBSD 12.2+ or FreeBSD
|
||||
13.0+.
|
||||
FreeBSD 13.0+ will require a kernel with the COMPAT_FREEBSD12 option set (this is the default).
|
||||
</p>
|
||||
|
||||
<h2 id="tools">Tools</h2>
|
||||
<h3 id="ppc64">PPC64</h3>
|
||||
|
||||
<p>
|
||||
TODO: complete this section, or delete if not needed
|
||||
<p><!-- CL 353969 -->
|
||||
TODO: <a href="https://golang.org/cl/353969">https://golang.org/cl/353969</a>: internal/buildcfg: enable register ABI for PPC64
|
||||
</p>
|
||||
|
||||
<h3 id="riscv">RISC-V</h3>
|
||||
|
||||
<p><!-- golang.org/issue/47100, CL 334872 -->
|
||||
The 64-bit RISC-V architecture on Linux (the <code>linux/riscv64</code> port)
|
||||
now supports the <code>c-archive</code> and <code>c-shared</code> build modes.
|
||||
</p>
|
||||
|
||||
<h2 id="tools">Tools</h2>
|
||||
|
||||
<h3 id="go-command">Go command</h3>
|
||||
|
||||
<p><!-- golang.org/issue/43684 -->
|
||||
|
|
@ -90,8 +101,21 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
package.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
TODO: complete this section, or delete if not needed
|
||||
<p><!-- https://golang.org/issue/44435 -->
|
||||
If the main module's <code>go.mod</code> file
|
||||
specifies <a href="/ref/mod#go-mod-file-go"><code>go</code> <code>1.17</code></a>
|
||||
or higher, <code>go</code> <code>mod</code> <code>download</code> without
|
||||
arguments now downloads source code for only the modules
|
||||
explicitly <a href="/ref/mod#go-mod-file-require">required</a> in the main
|
||||
module's <code>go.mod</code> file. (In a <code>go</code> <code>1.17</code> or
|
||||
higher module, that set already includes all dependencies needed to build the
|
||||
packages and tests in the main module.)
|
||||
To also download source code for transitive dependencies, use
|
||||
<code>go</code> <code>mod</code> <code>download</code> <code>all</code>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 349595 -->
|
||||
TODO: <a href="https://golang.org/cl/349595">https://golang.org/cl/349595</a>: https://golang.org/cl/349595: cmd/go: add GOAMD64 environment variable
|
||||
</p>
|
||||
|
||||
<h3 id="gofmt"><code>gofmt</code></h3>
|
||||
|
|
@ -102,7 +126,6 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
multiple CPUs, <code>gofmt</code> should now be significantly faster.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="runtime">Runtime</h2>
|
||||
|
||||
<p>
|
||||
|
|
@ -111,18 +134,53 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
|
||||
<h2 id="compiler">Compiler</h2>
|
||||
|
||||
<p>
|
||||
TODO: complete this section, or delete if not needed
|
||||
<p><!-- CL 298611 -->
|
||||
TODO: <a href="https://golang.org/cl/298611">https://golang.org/cl/298611</a>: https://golang.org/cl/298611: cmd/compile: add -asan option
|
||||
</p>
|
||||
|
||||
<p><!-- CL 352057 -->
|
||||
TODO: <a href="https://golang.org/cl/352057">https://golang.org/cl/352057</a>: https://golang.org/cl/352057: cmd/compile, runtime: track argument stack slot liveness
|
||||
</p>
|
||||
|
||||
<h2 id="linker">Linker</h2>
|
||||
|
||||
<p>
|
||||
TODO: complete this section, or delete if not needed
|
||||
<p><!-- CL 298610 -->
|
||||
TODO: <a href="https://golang.org/cl/298610">https://golang.org/cl/298610</a>: https://golang.org/cl/298610: cmd/link: add -asan option
|
||||
</p>
|
||||
|
||||
<h2 id="library">Core library</h2>
|
||||
|
||||
<h3 id="constraints">New <code>constraints</code> package</h3>
|
||||
|
||||
<p><!-- CL 349709 -->
|
||||
TODO: <a href="https://golang.org/cl/349709">https://golang.org/cl/349709</a>: constraints: new package
|
||||
</p>
|
||||
|
||||
<h3 id="netip">New <code>net/netip</code> package</h3>
|
||||
|
||||
<p>
|
||||
The new <a href="/pkg/net/netip/"><code>net/netip</code></a>
|
||||
package defines a new IP address type, <a href="/pkg/net/netip/#Addr"><code>Addr</code></a>.
|
||||
Compared to the existing
|
||||
<a href="/pkg/net/#IP"><code>net.IP</code></a> type, the <code>netip.Addr</code> type takes less
|
||||
memory, is immutable, and is comparable so it supports <code>==</code>
|
||||
and can be used as a map key.
|
||||
</p>
|
||||
<p>
|
||||
In addition to <code>Addr</code>, the package defines
|
||||
<a href="/pkg/net/netip/#AddrPort"><code>AddrPort</code></a>, representing
|
||||
an IP and port, and
|
||||
<a href="/pkg/net/netip/#Prefix"><code>Prefix</code></a>, representing
|
||||
a network CIDR prefix.
|
||||
</p>
|
||||
<p>
|
||||
The <code>net</code> package now has methods to send and receive UDP packets
|
||||
using <code>netip.Addr</code> values instead of the relatively heavy
|
||||
<code>*net.UDPAddr</code> values.
|
||||
</p>
|
||||
|
||||
<h3>TODO</h3>
|
||||
|
||||
<p>
|
||||
TODO: complete this section
|
||||
</p>
|
||||
|
|
@ -139,6 +197,26 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
TODO: complete this section
|
||||
</p>
|
||||
|
||||
<dl id="bufio"><dt><a href="/pkg/bufio/">bufio</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 345569 -->
|
||||
TODO: <a href="https://golang.org/cl/345569">https://golang.org/cl/345569</a>: add Writer.AvailableBuffer
|
||||
</p>
|
||||
|
||||
<p><!-- CL 345570 -->
|
||||
TODO: <a href="https://golang.org/cl/345570">https://golang.org/cl/345570</a>: make Reader.Reset and Writer.Reset work on the zero value
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- bufio -->
|
||||
|
||||
<dl id="crypto/tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 325250 -->
|
||||
TODO: <a href="https://golang.org/cl/325250">https://golang.org/cl/325250</a>: add Conn.NetConn method
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/tls -->
|
||||
|
||||
<dl id="debug/buildinfo"><dt><a href="/pkg/debug/buildinfo">debug/buildinfo</a></dt>
|
||||
<dd>
|
||||
<p><!-- golang.org/issue/39301 -->
|
||||
|
|
@ -165,6 +243,14 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
</dd>
|
||||
</dl><!-- image/draw -->
|
||||
|
||||
<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 340261 -->
|
||||
TODO: <a href="https://golang.org/cl/340261">https://golang.org/cl/340261</a>: deprecate (net.Error).Temporary
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- net -->
|
||||
|
||||
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 330852 -->
|
||||
|
|
@ -174,12 +260,24 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
will now be correctly used, if specified, for making HTTP requests when running
|
||||
on WebAssembly targets.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 338590 -->
|
||||
TODO: <a href="https://golang.org/cl/338590">https://golang.org/cl/338590</a>: add Cookie.Valid method
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- net/http -->
|
||||
|
||||
<dl id="os/user"><dt><a href="/pkg/os/user/">os/user</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 330753 -->
|
||||
TODO: <a href="https://golang.org/cl/330753">https://golang.org/cl/330753</a>: implement go native GroupIds
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- os/user -->
|
||||
|
||||
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 356049, 320929 -->
|
||||
<p><!-- CL 356049, CL 320929 -->
|
||||
The new
|
||||
<a href="/pkg/reflect/#Value.SetIterKey"><code>Value.SetIterKey</code></a>
|
||||
and <a href="/pkg/reflect/#Value.SetIterValue"><code>Value.SetIterValue</code></a>
|
||||
|
|
@ -187,8 +285,7 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<code>Value.Set(iter.Key())</code> and <code>Value.Set(iter.Value())</code> but
|
||||
do fewer allocations.
|
||||
</p>
|
||||
</dd>
|
||||
<dd>
|
||||
|
||||
<p><!-- CL 350691 -->
|
||||
The new
|
||||
<a href="/pkg/reflect/#Value.UnsafePointer"><code>Value.UnsafePointer</code></a>
|
||||
|
|
@ -197,9 +294,69 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
and <a href="/pkg/reflect/#Value.Pointer"><code>Value.Pointer</code></a>
|
||||
to eliminate the need to perform uintptr to unsafe.Pointer conversions at the callsite (as unsafe.Pointer rules require).
|
||||
</p>
|
||||
|
||||
<p><!-- CL 321889 -->
|
||||
TODO: <a href="https://golang.org/cl/321889">https://golang.org/cl/321889</a>: allocate hiter as part of MapIter
|
||||
</p>
|
||||
|
||||
<p><!-- CL 321891 -->
|
||||
TODO: <a href="https://golang.org/cl/321891">https://golang.org/cl/321891</a>: add MapIter.Reset
|
||||
</p>
|
||||
|
||||
<p><!-- CL 345486 -->
|
||||
TODO: <a href="https://golang.org/cl/345486">https://golang.org/cl/345486</a>: optimize for maps with string keys
|
||||
</p>
|
||||
|
||||
<p><!-- CL 352131 -->
|
||||
TODO: <a href="https://golang.org/cl/352131">https://golang.org/cl/352131</a>: add Value.{CanInt, CanUint, CanFloat, CanComplex}
|
||||
</p>
|
||||
|
||||
<p><!-- CL 357962 -->
|
||||
TODO: <a href="https://golang.org/cl/357962">https://golang.org/cl/357962</a>: add FieldByIndexErr
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- reflect -->
|
||||
|
||||
<dl id="regexp"><dt><a href="/pkg/regexp/">regexp</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 354569 -->
|
||||
TODO: <a href="https://golang.org/cl/354569">https://golang.org/cl/354569</a>: document and implement that invalid UTF-8 bytes are the same as U+FFFD
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- regexp -->
|
||||
|
||||
<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 343877 -->
|
||||
TODO: <a href="https://golang.org/cl/343877">https://golang.org/cl/343877</a>: reject surrogate halves in Unquote
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- strconv -->
|
||||
|
||||
<dl id="strings"><dt><a href="/pkg/strings/">strings</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 345849 -->
|
||||
TODO: <a href="https://golang.org/cl/345849">https://golang.org/cl/345849</a>: add Clone function
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- strings -->
|
||||
|
||||
<dl id="strings,bytes"><dt><a href="/pkg/strings,bytes/">strings,bytes</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 332771 -->
|
||||
TODO: <a href="https://golang.org/cl/332771">https://golang.org/cl/332771</a>: avoid allocations in Trim/TrimLeft/TrimRight
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- strings,bytes -->
|
||||
|
||||
<dl id="sync"><dt><a href="/pkg/sync/">sync</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 319769 -->
|
||||
TODO: <a href="https://golang.org/cl/319769">https://golang.org/cl/319769</a>: add Mutex.TryLock, RWMutex.TryLock, RWMutex.TryRLock
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- sync -->
|
||||
|
||||
<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 336550 -->
|
||||
|
|
@ -214,5 +371,45 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<a href="/pkg/syscall/?GOOS=windows#Syscall18"><code>Syscall18</code></a> are
|
||||
deprecated in favor of <a href="/pkg/syscall/?GOOS=windows#SyscallN"><code>SyscallN</code></a>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 355570 -->
|
||||
TODO: <a href="https://golang.org/cl/355570">https://golang.org/cl/355570</a>: add support for SysProcAttr.Pdeathsig on FreeBSD
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- syscall -->
|
||||
|
||||
<dl id="syscall/js"><dt><a href="/pkg/syscall/js/">syscall/js</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 356430 -->
|
||||
TODO: <a href="https://golang.org/cl/356430">https://golang.org/cl/356430</a>: remove Wrapper interface
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- syscall/js -->
|
||||
|
||||
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 343883 -->
|
||||
TODO: <a href="https://golang.org/cl/343883">https://golang.org/cl/343883</a>: increase alternation precedence
|
||||
</p>
|
||||
|
||||
<p><!-- CL 356669 -->
|
||||
TODO: <a href="https://golang.org/cl/356669">https://golang.org/cl/356669</a>: skip extra -count iterations if there are no tests
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- testing -->
|
||||
|
||||
<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 321490 -->
|
||||
TODO: <a href="https://golang.org/cl/321490">https://golang.org/cl/321490</a>: implement short-circuit and, or
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- text/template -->
|
||||
|
||||
<dl id="unicode/utf8"><dt><a href="/pkg/unicode/utf8/">unicode/utf8</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 345571 -->
|
||||
TODO: <a href="https://golang.org/cl/345571">https://golang.org/cl/345571</a>: add AppendRune
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- unicode/utf8 -->
|
||||
|
|
|
|||
|
|
@ -931,3 +931,55 @@ func TestManyCalls(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 49288.
|
||||
func TestPreemption(t *testing.T) {
|
||||
if runtime.Compiler == "gccgo" {
|
||||
t.Skip("skipping asynchronous preemption test with gccgo")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
|
||||
if !testWork {
|
||||
defer func() {
|
||||
os.Remove("testp8" + exeSuffix)
|
||||
os.Remove("libgo8.a")
|
||||
os.Remove("libgo8.h")
|
||||
}()
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo8.a", "./libgo8")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkLineComments(t, "libgo8.h")
|
||||
|
||||
ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
|
||||
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
argv := cmdToRun("./testp8")
|
||||
cmd = exec.Command(argv[0], argv[1:]...)
|
||||
var sb strings.Builder
|
||||
cmd.Stdout = &sb
|
||||
cmd.Stderr = &sb
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
timer := time.AfterFunc(time.Minute,
|
||||
func() {
|
||||
t.Error("test program timed out")
|
||||
cmd.Process.Kill()
|
||||
},
|
||||
)
|
||||
defer timer.Stop()
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
t.Log(sb.String())
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var started int32
|
||||
|
||||
// Start a goroutine that loops forever.
|
||||
func init() {
|
||||
runtime.GOMAXPROCS(1)
|
||||
go func() {
|
||||
for {
|
||||
atomic.StoreInt32(&started, 1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
//export GoFunction8
|
||||
func GoFunction8() {
|
||||
for atomic.LoadInt32(&started) == 0 {
|
||||
runtime.Gosched()
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Test preemption.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libgo8.h"
|
||||
|
||||
int main() {
|
||||
GoFunction8();
|
||||
|
||||
// That should have exited the program.
|
||||
abort();
|
||||
}
|
||||
|
|
@ -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 darwin dragonfly freebsd linux,!arm64 netbsd openbsd
|
||||
// +build darwin dragonfly freebsd linux,!arm64,!riscv64 netbsd openbsd
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
|||
|
|
@ -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 linux,arm64
|
||||
// +build linux,arm64 linux,riscv64
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sanitizers_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestASAN(t *testing.T) {
|
||||
goos, err := goEnv("GOOS")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
goarch, err := goEnv("GOARCH")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The asan tests require support for the -asan option.
|
||||
if !aSanSupported(goos, goarch) {
|
||||
t.Skipf("skipping on %s/%s; -asan option is not supported.", goos, goarch)
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
requireOvercommit(t)
|
||||
config := configure("address")
|
||||
config.skipIfCSanitizerBroken(t)
|
||||
|
||||
mustRun(t, config.goCmd("build", "std"))
|
||||
|
||||
cases := []struct {
|
||||
src string
|
||||
memoryAccessError string
|
||||
}{
|
||||
{src: "asan1_fail.go", memoryAccessError: "heap-use-after-free"},
|
||||
{src: "asan2_fail.go", memoryAccessError: "heap-buffer-overflow"},
|
||||
{src: "asan3_fail.go", memoryAccessError: "use-after-poison"},
|
||||
{src: "asan4_fail.go", memoryAccessError: "use-after-poison"},
|
||||
{src: "asan_useAfterReturn.go"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
name := strings.TrimSuffix(tc.src, ".go")
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := newTempDir(t)
|
||||
defer dir.RemoveAll(t)
|
||||
|
||||
outPath := dir.Join(name)
|
||||
mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src)))
|
||||
|
||||
cmd := hangProneCmd(outPath)
|
||||
if tc.memoryAccessError != "" {
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil && strings.Contains(string(out), tc.memoryAccessError) {
|
||||
return
|
||||
}
|
||||
t.Fatalf("%#q exited without expected memory access error\n%s; got failure\n%s", strings.Join(cmd.Args, " "), tc.memoryAccessError, out)
|
||||
}
|
||||
mustRun(t, cmd)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -267,6 +267,9 @@ func configure(sanitizer string) *config {
|
|||
c.ldFlags = append(c.ldFlags, "-fPIC", "-static-libtsan")
|
||||
}
|
||||
|
||||
case "address":
|
||||
c.goFlags = append(c.goFlags, "-asan")
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized sanitizer: %q", sanitizer))
|
||||
}
|
||||
|
|
@ -450,3 +453,14 @@ func mSanSupported(goos, goarch string) bool {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// aSanSupported is a copy of the function cmd/internal/sys.ASanSupported,
|
||||
// because the internal pacakage can't be used here.
|
||||
func aSanSupported(goos, goarch string) bool {
|
||||
switch goos {
|
||||
case "linux":
|
||||
return goarch == "amd64" || goarch == "arm64"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int *p;
|
||||
int* test() {
|
||||
p = (int *)malloc(2 * sizeof(int));
|
||||
free(p);
|
||||
return p;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
// C passes Go an invalid pointer.
|
||||
a := C.test()
|
||||
// Use after free
|
||||
*a = 2
|
||||
// We shouldn't get here; asan should stop us first.
|
||||
fmt.Println(*a)
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int *p;
|
||||
int* f() {
|
||||
int i;
|
||||
p = (int *)malloc(5*sizeof(int));
|
||||
for (i = 0; i < 5; i++) {
|
||||
p[i] = i+10;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := C.f()
|
||||
q5 := (*C.int)(unsafe.Add(unsafe.Pointer(a), 4*5))
|
||||
// Access to C pointer out of bounds.
|
||||
*q5 = 100
|
||||
// We shouldn't get here; asan should stop us first.
|
||||
fmt.Printf("q5: %d, %x\n", *q5, q5)
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void test(int *a) {
|
||||
// Access Go pointer out of bounds.
|
||||
int c = a[5]; // BOOM
|
||||
// We shouldn't get here; asan should stop us first.
|
||||
printf("a[5]=%d\n", c);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
cIntSlice := []C.int{200, 201, 203, 203, 204}
|
||||
C.test(&cIntSlice[0])
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void test(int* a) {
|
||||
// Access Go pointer out of bounds.
|
||||
a[3] = 300; // BOOM
|
||||
// We shouldn't get here; asan should stop us first.
|
||||
printf("a[3]=%d\n", a[3]);
|
||||
}*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
var cIntArray [2]C.int
|
||||
C.test(&cIntArray[0]) // cIntArray is moved to heap.
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// The -fsanitize=address option of C compier can detect stack-use-after-return bugs.
|
||||
// In the following program, the local variable 'local' was moved to heap by the Go
|
||||
// compiler because foo() is returning the reference to 'local', and return stack of
|
||||
// foo() will be invalid. Thus for main() to use the reference to 'local', the 'local'
|
||||
// must be available even after foo() has finished. Therefore, Go has no such issue.
|
||||
|
||||
import "fmt"
|
||||
|
||||
var ptr *int
|
||||
|
||||
func main() {
|
||||
foo()
|
||||
fmt.Printf("ptr=%x, %v", *ptr, ptr)
|
||||
}
|
||||
|
||||
func foo() {
|
||||
var local int
|
||||
local = 1
|
||||
ptr = &local // local is moved to heap.
|
||||
}
|
||||
|
|
@ -741,6 +741,9 @@ func (r *Reader) initFileList() {
|
|||
for _, file := range r.File {
|
||||
isDir := len(file.Name) > 0 && file.Name[len(file.Name)-1] == '/'
|
||||
name := toValidName(file.Name)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
|
||||
dirs[dir] = true
|
||||
}
|
||||
|
|
@ -782,8 +785,11 @@ func fileEntryLess(x, y string) bool {
|
|||
func (r *Reader) Open(name string) (fs.File, error) {
|
||||
r.initFileList()
|
||||
|
||||
if !fs.ValidPath(name) {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
|
||||
}
|
||||
e := r.openLookup(name)
|
||||
if e == nil || !fs.ValidPath(name) {
|
||||
if e == nil {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
||||
}
|
||||
if e.isDir {
|
||||
|
|
@ -797,7 +803,7 @@ func (r *Reader) Open(name string) (fs.File, error) {
|
|||
}
|
||||
|
||||
func split(name string) (dir, elem string, isDir bool) {
|
||||
if name[len(name)-1] == '/' {
|
||||
if len(name) > 0 && name[len(name)-1] == '/' {
|
||||
isDir = true
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -1202,6 +1203,15 @@ func TestCVE202127919(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("Error reading file: %v", err)
|
||||
}
|
||||
if len(r.File) != 1 {
|
||||
t.Fatalf("No entries in the file list")
|
||||
}
|
||||
if r.File[0].Name != "../test.txt" {
|
||||
t.Errorf("Unexpected entry name: %s", r.File[0].Name)
|
||||
}
|
||||
if _, err := r.File[0].Open(); err != nil {
|
||||
t.Errorf("Error opening file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadDataDescriptor(t *testing.T) {
|
||||
|
|
@ -1402,3 +1412,121 @@ func TestCVE202139293(t *testing.T) {
|
|||
t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCVE202141772(t *testing.T) {
|
||||
// Archive contains a file whose name is exclusively made up of '/', '\'
|
||||
// characters, or "../", "..\" paths, which would previously cause a panic.
|
||||
//
|
||||
// Length Method Size Cmpr Date Time CRC-32 Name
|
||||
// -------- ------ ------- ---- ---------- ----- -------- ----
|
||||
// 0 Stored 0 0% 08-05-2021 18:32 00000000 /
|
||||
// 0 Stored 0 0% 09-14-2021 12:59 00000000 //
|
||||
// 0 Stored 0 0% 09-14-2021 12:59 00000000 \
|
||||
// 11 Stored 11 0% 09-14-2021 13:04 0d4a1185 /test.txt
|
||||
// -------- ------- --- -------
|
||||
// 11 11 0% 4 files
|
||||
data := []byte{
|
||||
0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x08,
|
||||
0x00, 0x00, 0x06, 0x94, 0x05, 0x53, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x50,
|
||||
0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x50,
|
||||
0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x50, 0x4b,
|
||||
0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x91, 0x68, 0x2e, 0x53, 0x85, 0x11, 0x4a, 0x0d,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
|
||||
0x74, 0x2e, 0x74, 0x78, 0x74, 0x68, 0x65, 0x6c,
|
||||
0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
|
||||
0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x0a, 0x00,
|
||||
0x00, 0x08, 0x00, 0x00, 0x06, 0x94, 0x05, 0x53,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
|
||||
0xed, 0x41, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x50,
|
||||
0x4b, 0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x78, 0x67, 0x2e, 0x53, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
|
||||
0x00, 0x1f, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x0a,
|
||||
0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x18, 0x00, 0x93, 0x98, 0x25, 0x57, 0x25,
|
||||
0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
|
||||
0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
|
||||
0xa9, 0xd7, 0x01, 0x50, 0x4b, 0x01, 0x02, 0x3f,
|
||||
0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
|
||||
0x67, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00,
|
||||
0x00, 0x5c, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x93, 0x98,
|
||||
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
|
||||
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
|
||||
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x50, 0x4b,
|
||||
0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x91, 0x68, 0x2e, 0x53, 0x85, 0x11,
|
||||
0x4a, 0x0d, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00,
|
||||
0x00, 0x00, 0x09, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x5e, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
|
||||
0x74, 0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18,
|
||||
0x00, 0xa9, 0x80, 0x51, 0x01, 0x26, 0xa9, 0xd7,
|
||||
0x01, 0x31, 0xd1, 0x57, 0x01, 0x26, 0xa9, 0xd7,
|
||||
0x01, 0xdf, 0x48, 0x85, 0xf9, 0x25, 0xa9, 0xd7,
|
||||
0x01, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x04, 0x00, 0x31, 0x01, 0x00,
|
||||
0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}
|
||||
r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data)))
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading the archive: %v", err)
|
||||
}
|
||||
entryNames := []string{`/`, `//`, `\`, `/test.txt`}
|
||||
var names []string
|
||||
for _, f := range r.File {
|
||||
names = append(names, f.Name)
|
||||
if _, err := f.Open(); err != nil {
|
||||
t.Errorf("Error opening %q: %v", f.Name, err)
|
||||
}
|
||||
if _, err := r.Open(f.Name); err == nil {
|
||||
t.Errorf("Opening %q with fs.FS API succeeded", f.Name)
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(names, entryNames) {
|
||||
t.Errorf("Unexpected file entries: %q", names)
|
||||
}
|
||||
if _, err := r.Open(""); err == nil {
|
||||
t.Errorf("Opening %q with fs.FS API succeeded", "")
|
||||
}
|
||||
if _, err := r.Open("test.txt"); err != nil {
|
||||
t.Errorf("Error opening %q with fs.FS API: %v", "test.txt", err)
|
||||
}
|
||||
dirEntries, err := fs.ReadDir(r, ".")
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading the root directory: %v", err)
|
||||
}
|
||||
if len(dirEntries) != 1 || dirEntries[0].Name() != "test.txt" {
|
||||
t.Errorf("Unexpected directory entries")
|
||||
for _, dirEntry := range dirEntries {
|
||||
_, err := r.Open(dirEntry.Name())
|
||||
t.Logf("%q (Open error: %v)", dirEntry.Name(), err)
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
info, err := dirEntries[0].Info()
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading info entry: %v", err)
|
||||
}
|
||||
if name := info.Name(); name != "test.txt" {
|
||||
t.Errorf("Inconsistent name in info entry: %v", name)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1520,7 +1520,7 @@ func TestReaderDiscard(t *testing.T) {
|
|||
wantBuffered: 0,
|
||||
},
|
||||
// Any error from filling shouldn't show up until we
|
||||
// get past the valid bytes. Here we return we return 5 valid bytes at the same time
|
||||
// get past the valid bytes. Here we return 5 valid bytes at the same time
|
||||
// as an error, but test that we don't see the error from Discard.
|
||||
{
|
||||
name: "fill error, discard less",
|
||||
|
|
|
|||
|
|
@ -65,7 +65,11 @@ func TestIndexByteNearPageBoundary(t *testing.T) {
|
|||
|
||||
func TestIndexNearPageBoundary(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q [64]byte
|
||||
q := dangerousSlice(t)
|
||||
if len(q) > 64 {
|
||||
// Only worry about when we're near the end of a page.
|
||||
q = q[len(q)-64:]
|
||||
}
|
||||
b := dangerousSlice(t)
|
||||
if len(b) > 256 {
|
||||
// Only worry about when we're near the end of a page.
|
||||
|
|
@ -81,4 +85,16 @@ func TestIndexNearPageBoundary(t *testing.T) {
|
|||
}
|
||||
q[j-1] = 0
|
||||
}
|
||||
|
||||
// Test differing alignments and sizes of q which always end on a page boundary.
|
||||
q[len(q)-1] = 1 // difference is only found on the last byte
|
||||
for j := 0; j < len(q); j++ {
|
||||
for i := range b {
|
||||
idx := Index(b[i:], q[j:])
|
||||
if idx != -1 {
|
||||
t.Fatalf("Index(b[%d:], q[%d:])=%d, want -1\n", i, j, idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
q[len(q)-1] = 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ func Equal(a, b []byte) bool {
|
|||
}
|
||||
|
||||
// Compare returns an integer comparing two byte slices lexicographically.
|
||||
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
|
||||
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
|
||||
// A nil argument is equivalent to an empty slice.
|
||||
func Compare(a, b []byte) int {
|
||||
return bytealg.Compare(a, b)
|
||||
|
|
@ -746,7 +746,8 @@ func isSeparator(r rune) bool {
|
|||
// Title treats s as UTF-8-encoded bytes and returns a copy with all Unicode letters that begin
|
||||
// words mapped to their title case.
|
||||
//
|
||||
// BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
|
||||
// Deprecated: The rule Title uses for word boundaries does not handle Unicode
|
||||
// punctuation properly. Use golang.org/x/text/cases instead.
|
||||
func Title(s []byte) []byte {
|
||||
// Use a closure here to remember state.
|
||||
// Hackish but effective. Depends on Map scanning in order and calling
|
||||
|
|
|
|||
|
|
@ -37,6 +37,16 @@ func ExampleBuffer_Bytes() {
|
|||
// Output: hello world
|
||||
}
|
||||
|
||||
func ExampleBuffer_Cap() {
|
||||
buf1 := bytes.NewBuffer(make([]byte, 10))
|
||||
buf2 := bytes.NewBuffer(make([]byte, 0, 10))
|
||||
fmt.Println(buf1.Cap())
|
||||
fmt.Println(buf2.Cap())
|
||||
// Output:
|
||||
// 10
|
||||
// 10
|
||||
}
|
||||
|
||||
func ExampleBuffer_Grow() {
|
||||
var b bytes.Buffer
|
||||
b.Grow(64)
|
||||
|
|
@ -67,6 +77,39 @@ func ExampleBuffer_Next() {
|
|||
// e
|
||||
}
|
||||
|
||||
func ExampleBuffer_Read() {
|
||||
var b bytes.Buffer
|
||||
b.Grow(64)
|
||||
b.Write([]byte("abcde"))
|
||||
rdbuf := make([]byte, 1)
|
||||
n, err := b.Read(rdbuf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(n)
|
||||
fmt.Println(b.String())
|
||||
fmt.Println(string(rdbuf))
|
||||
// Output
|
||||
// 1
|
||||
// bcde
|
||||
// a
|
||||
}
|
||||
|
||||
func ExampleBuffer_ReadByte() {
|
||||
var b bytes.Buffer
|
||||
b.Grow(64)
|
||||
b.Write([]byte("abcde"))
|
||||
c, err := b.ReadByte()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(c)
|
||||
fmt.Println(b.String())
|
||||
// Output
|
||||
// 97
|
||||
// bcde
|
||||
}
|
||||
|
||||
func ExampleCompare() {
|
||||
// Interpret Compare's result by comparing it to zero.
|
||||
var a, b []byte
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func nilRegisterNumber(name string, n int16) (int16, bool) {
|
|||
|
||||
// Set configures the architecture specified by GOARCH and returns its representation.
|
||||
// It returns nil if GOARCH is not recognized.
|
||||
func Set(GOARCH string) *Arch {
|
||||
func Set(GOARCH string, shared bool) *Arch {
|
||||
switch GOARCH {
|
||||
case "386":
|
||||
return archX86(&x86.Link386)
|
||||
|
|
@ -73,7 +73,7 @@ func Set(GOARCH string) *Arch {
|
|||
case "ppc64le":
|
||||
return archPPC64(&ppc64.Linkppc64le)
|
||||
case "riscv64":
|
||||
return archRISCV64()
|
||||
return archRISCV64(shared)
|
||||
case "s390x":
|
||||
return archS390x()
|
||||
case "wasm":
|
||||
|
|
@ -541,12 +541,18 @@ func archMips64(linkArch *obj.LinkArch) *Arch {
|
|||
}
|
||||
}
|
||||
|
||||
func archRISCV64() *Arch {
|
||||
func archRISCV64(shared bool) *Arch {
|
||||
register := make(map[string]int16)
|
||||
|
||||
// Standard register names.
|
||||
for i := riscv.REG_X0; i <= riscv.REG_X31; i++ {
|
||||
if i == riscv.REG_G {
|
||||
// Disallow X3 in shared mode, as this will likely be used as the
|
||||
// GP register, which could result in problems in non-Go code,
|
||||
// including signal handlers.
|
||||
if shared && i == riscv.REG_GP {
|
||||
continue
|
||||
}
|
||||
if i == riscv.REG_TP || i == riscv.REG_G {
|
||||
continue
|
||||
}
|
||||
name := fmt.Sprintf("X%d", i-riscv.REG_X0)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import (
|
|||
func setArch(goarch string) (*arch.Arch, *obj.Link) {
|
||||
buildcfg.GOOS = "linux" // obj can handle this OS for all architectures.
|
||||
buildcfg.GOARCH = goarch
|
||||
architecture := arch.Set(goarch)
|
||||
architecture := arch.Set(goarch, false)
|
||||
if architecture == nil {
|
||||
panic("asm: unrecognized architecture " + goarch)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ var (
|
|||
CompilingRuntime = flag.Bool("compiling-runtime", false, "source to be compiled is part of the Go runtime")
|
||||
)
|
||||
|
||||
var DebugFlags struct {
|
||||
MayMoreStack string `help:"call named function before all stack growth checks"`
|
||||
}
|
||||
|
||||
var (
|
||||
D MultiFlag
|
||||
I MultiFlag
|
||||
|
|
@ -39,6 +43,7 @@ func init() {
|
|||
flag.Var(&D, "D", "predefined symbol with optional simple value -D=identifier=value; can be set multiple times")
|
||||
flag.Var(&I, "I", "include directory; can be set multiple times")
|
||||
flag.BoolVar(&DebugV, "v", false, "print debug output")
|
||||
flag.Var(objabi.NewDebugFlag(&DebugFlags, nil), "d", "enable debugging settings; try -d help")
|
||||
objabi.AddVersionFlag() // -V
|
||||
objabi.Flagcount("S", "print assembly and machine code", &PrintOut)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,19 +29,20 @@ func main() {
|
|||
buildcfg.Check()
|
||||
GOARCH := buildcfg.GOARCH
|
||||
|
||||
architecture := arch.Set(GOARCH)
|
||||
flags.Parse()
|
||||
|
||||
architecture := arch.Set(GOARCH, *flags.Shared || *flags.Dynlink)
|
||||
if architecture == nil {
|
||||
log.Fatalf("unrecognized architecture %s", GOARCH)
|
||||
}
|
||||
|
||||
flags.Parse()
|
||||
|
||||
ctxt := obj.Linknew(architecture.LinkArch)
|
||||
ctxt.Debugasm = flags.PrintOut
|
||||
ctxt.Debugvlog = flags.DebugV
|
||||
ctxt.Flag_dynlink = *flags.Dynlink
|
||||
ctxt.Flag_linkshared = *flags.Linkshared
|
||||
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
|
||||
ctxt.Flag_maymorestack = flags.DebugFlags.MayMoreStack
|
||||
ctxt.IsAsm = true
|
||||
ctxt.Pkgpath = *flags.Importpath
|
||||
switch *flags.Spectre {
|
||||
|
|
|
|||
|
|
@ -780,11 +780,11 @@ func (state *assignState) assignParamOrReturn(pt *types.Type, n types.Object, is
|
|||
}
|
||||
|
||||
// ComputePadding returns a list of "post element" padding values in
|
||||
// the case where we have a structure being passed in registers. Give
|
||||
// a param assignment corresponding to a struct, it returns a list of
|
||||
// contaning padding values for each field, e.g. the Kth element in
|
||||
// the case where we have a structure being passed in registers. Given
|
||||
// a param assignment corresponding to a struct, it returns a list
|
||||
// containing padding values for each field, e.g. the Kth element in
|
||||
// the list is the amount of padding between field K and the following
|
||||
// field. For things that are not struct (or structs without padding)
|
||||
// field. For things that are not structs (or structs without padding)
|
||||
// it returns a list of zeros. Example:
|
||||
//
|
||||
// type small struct {
|
||||
|
|
@ -796,8 +796,8 @@ func (state *assignState) assignParamOrReturn(pt *types.Type, n types.Object, is
|
|||
//
|
||||
// For this struct we would return a list [0, 1, 0, 0], meaning that
|
||||
// we have one byte of padding after the second field, and no bytes of
|
||||
// padding after any of the other fields. Input parameter "storage"
|
||||
// is with enough capacity to accommodate padding elements for
|
||||
// padding after any of the other fields. Input parameter "storage" is
|
||||
// a slice with enough capacity to accommodate padding elements for
|
||||
// the architected register set in question.
|
||||
func (pa *ABIParamAssignment) ComputePadding(storage []uint64) []uint64 {
|
||||
nr := len(pa.Registers)
|
||||
|
|
|
|||
|
|
@ -6,15 +6,6 @@
|
|||
|
||||
package base
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Debug holds the parsed debugging configuration values.
|
||||
var Debug DebugFlags
|
||||
|
||||
|
|
@ -26,7 +17,7 @@ var Debug DebugFlags
|
|||
// Each setting is name=value; for ints, name is short for name=1.
|
||||
type DebugFlags struct {
|
||||
Append int `help:"print information about append compilation"`
|
||||
Checkptr int `help:"instrument unsafe pointer conversions"`
|
||||
Checkptr int `help:"instrument unsafe pointer conversions\n0: instrumentation disabled\n1: conversions involving unsafe.Pointer are instrumented\n2: conversions to unsafe.Pointer force heap allocation"`
|
||||
Closure int `help:"print information about closure compilation"`
|
||||
DclStack int `help:"run internal dclstack check"`
|
||||
Defer int `help:"print information about defer compilation"`
|
||||
|
|
@ -40,7 +31,7 @@ type DebugFlags struct {
|
|||
LocationLists int `help:"print information about DWARF location list creation"`
|
||||
Nil int `help:"print information about nil checks"`
|
||||
NoOpenDefer int `help:"disable open-coded defers"`
|
||||
PCTab string `help:"print named pc-value table"`
|
||||
PCTab string `help:"print named pc-value table\nOne of: pctospadj, pctofile, pctoline, pctoinline, pctopcdata"`
|
||||
Panic int `help:"show all compiler panics"`
|
||||
Slice int `help:"print information about slice compilation"`
|
||||
SoftFloat int `help:"force compiler to emit soft-float code"`
|
||||
|
|
@ -51,142 +42,12 @@ type DebugFlags struct {
|
|||
UnifiedQuirks int `help:"enable unified IR construction's quirks mode"`
|
||||
WB int `help:"print information about write barriers"`
|
||||
ABIWrap int `help:"print information about ABI wrapper generation"`
|
||||
MayMoreStack string `help:"call named function before all stack growth checks"`
|
||||
|
||||
any bool // set when any of the values have been set
|
||||
}
|
||||
|
||||
// Any reports whether any of the debug flags have been set.
|
||||
func (d *DebugFlags) Any() bool { return d.any }
|
||||
|
||||
type debugField struct {
|
||||
name string
|
||||
help string
|
||||
val interface{} // *int or *string
|
||||
}
|
||||
|
||||
var debugTab []debugField
|
||||
|
||||
func init() {
|
||||
v := reflect.ValueOf(&Debug).Elem()
|
||||
t := v.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
f := t.Field(i)
|
||||
if f.Name == "any" {
|
||||
continue
|
||||
}
|
||||
name := strings.ToLower(f.Name)
|
||||
help := f.Tag.Get("help")
|
||||
if help == "" {
|
||||
panic(fmt.Sprintf("base.Debug.%s is missing help text", f.Name))
|
||||
}
|
||||
ptr := v.Field(i).Addr().Interface()
|
||||
switch ptr.(type) {
|
||||
default:
|
||||
panic(fmt.Sprintf("base.Debug.%s has invalid type %v (must be int or string)", f.Name, f.Type))
|
||||
case *int, *string:
|
||||
// ok
|
||||
}
|
||||
debugTab = append(debugTab, debugField{name, help, ptr})
|
||||
}
|
||||
Any bool // set when any of the debug flags have been set
|
||||
}
|
||||
|
||||
// DebugSSA is called to set a -d ssa/... option.
|
||||
// If nil, those options are reported as invalid options.
|
||||
// If DebugSSA returns a non-empty string, that text is reported as a compiler error.
|
||||
var DebugSSA func(phase, flag string, val int, valString string) string
|
||||
|
||||
// parseDebug parses the -d debug string argument.
|
||||
func parseDebug(debugstr string) {
|
||||
// parse -d argument
|
||||
if debugstr == "" {
|
||||
return
|
||||
}
|
||||
Debug.any = true
|
||||
Split:
|
||||
for _, name := range strings.Split(debugstr, ",") {
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
// display help about the -d option itself and quit
|
||||
if name == "help" {
|
||||
fmt.Print(debugHelpHeader)
|
||||
maxLen := len("ssa/help")
|
||||
for _, t := range debugTab {
|
||||
if len(t.name) > maxLen {
|
||||
maxLen = len(t.name)
|
||||
}
|
||||
}
|
||||
for _, t := range debugTab {
|
||||
fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
|
||||
}
|
||||
// ssa options have their own help
|
||||
fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
|
||||
fmt.Print(debugHelpFooter)
|
||||
os.Exit(0)
|
||||
}
|
||||
val, valstring, haveInt := 1, "", true
|
||||
if i := strings.IndexAny(name, "=:"); i >= 0 {
|
||||
var err error
|
||||
name, valstring = name[:i], name[i+1:]
|
||||
val, err = strconv.Atoi(valstring)
|
||||
if err != nil {
|
||||
val, haveInt = 1, false
|
||||
}
|
||||
}
|
||||
for _, t := range debugTab {
|
||||
if t.name != name {
|
||||
continue
|
||||
}
|
||||
switch vp := t.val.(type) {
|
||||
case nil:
|
||||
// Ignore
|
||||
case *string:
|
||||
*vp = valstring
|
||||
case *int:
|
||||
if !haveInt {
|
||||
log.Fatalf("invalid debug value %v", name)
|
||||
}
|
||||
*vp = val
|
||||
default:
|
||||
panic("bad debugtab type")
|
||||
}
|
||||
continue Split
|
||||
}
|
||||
// special case for ssa for now
|
||||
if DebugSSA != nil && strings.HasPrefix(name, "ssa/") {
|
||||
// expect form ssa/phase/flag
|
||||
// e.g. -d=ssa/generic_cse/time
|
||||
// _ in phase name also matches space
|
||||
phase := name[4:]
|
||||
flag := "debug" // default flag is debug
|
||||
if i := strings.Index(phase, "/"); i >= 0 {
|
||||
flag = phase[i+1:]
|
||||
phase = phase[:i]
|
||||
}
|
||||
err := DebugSSA(phase, flag, val, valstring)
|
||||
if err != "" {
|
||||
log.Fatalf(err)
|
||||
}
|
||||
continue Split
|
||||
}
|
||||
log.Fatalf("unknown debug key -d %s\n", name)
|
||||
}
|
||||
}
|
||||
|
||||
const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
|
||||
|
||||
<key> is one of:
|
||||
|
||||
`
|
||||
|
||||
const debugHelpFooter = `
|
||||
<value> is key-specific.
|
||||
|
||||
Key "checkptr" supports values:
|
||||
"0": instrumentation disabled
|
||||
"1": conversions involving unsafe.Pointer are instrumented
|
||||
"2": conversions to unsafe.Pointer force heap allocation
|
||||
|
||||
Key "pctab" supports values:
|
||||
"pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata"
|
||||
`
|
||||
|
|
|
|||
|
|
@ -64,19 +64,19 @@ type CmdFlags struct {
|
|||
// V is added by objabi.AddVersionFlag
|
||||
W CountFlag "help:\"debug parse tree after type checking\""
|
||||
|
||||
LowerC int "help:\"concurrency during compilation (1 means no concurrency)\""
|
||||
LowerD func(string) "help:\"enable debugging settings; try -d help\""
|
||||
LowerE CountFlag "help:\"no limit on number of errors reported\""
|
||||
LowerH CountFlag "help:\"halt on error\""
|
||||
LowerJ CountFlag "help:\"debug runtime-initialized variables\""
|
||||
LowerL CountFlag "help:\"disable inlining\""
|
||||
LowerM CountFlag "help:\"print optimization decisions\""
|
||||
LowerO string "help:\"write output to `file`\""
|
||||
LowerP *string "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below
|
||||
LowerR CountFlag "help:\"debug generated wrappers\""
|
||||
LowerT bool "help:\"enable tracing for debugging the compiler\""
|
||||
LowerW CountFlag "help:\"debug type checking\""
|
||||
LowerV *bool "help:\"increase debug verbosity\""
|
||||
LowerC int "help:\"concurrency during compilation (1 means no concurrency)\""
|
||||
LowerD flag.Value "help:\"enable debugging settings; try -d help\""
|
||||
LowerE CountFlag "help:\"no limit on number of errors reported\""
|
||||
LowerH CountFlag "help:\"halt on error\""
|
||||
LowerJ CountFlag "help:\"debug runtime-initialized variables\""
|
||||
LowerL CountFlag "help:\"disable inlining\""
|
||||
LowerM CountFlag "help:\"print optimization decisions\""
|
||||
LowerO string "help:\"write output to `file`\""
|
||||
LowerP *string "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below
|
||||
LowerR CountFlag "help:\"debug generated wrappers\""
|
||||
LowerT bool "help:\"enable tracing for debugging the compiler\""
|
||||
LowerW CountFlag "help:\"debug type checking\""
|
||||
LowerV *bool "help:\"increase debug verbosity\""
|
||||
|
||||
// Special characters
|
||||
Percent int "flag:\"%\" help:\"debug non-static initializers\""
|
||||
|
|
@ -145,7 +145,7 @@ func ParseFlags() {
|
|||
Flag.I = addImportDir
|
||||
|
||||
Flag.LowerC = 1
|
||||
Flag.LowerD = parseDebug
|
||||
Flag.LowerD = objabi.NewDebugFlag(&Debug, DebugSSA)
|
||||
Flag.LowerP = &Ctxt.Pkgpath
|
||||
Flag.LowerV = &Ctxt.Debugvlog
|
||||
|
||||
|
|
@ -192,6 +192,7 @@ func ParseFlags() {
|
|||
Ctxt.Flag_shared = Ctxt.Flag_dynlink || Ctxt.Flag_shared
|
||||
Ctxt.Flag_optimize = Flag.N == 0
|
||||
Ctxt.Debugasm = int(Flag.S)
|
||||
Ctxt.Flag_maymorestack = Debug.MayMoreStack
|
||||
|
||||
if flag.NArg() < 1 {
|
||||
usage()
|
||||
|
|
@ -331,7 +332,11 @@ func registerFlags() {
|
|||
f := v.Field(i).Interface().(func(string))
|
||||
objabi.Flagfn1(name, help, f)
|
||||
default:
|
||||
panic(fmt.Sprintf("base.Flag.%s has unexpected type %s", f.Name, f.Type))
|
||||
if val, ok := v.Field(i).Interface().(flag.Value); ok {
|
||||
flag.Var(val, name, help)
|
||||
} else {
|
||||
panic(fmt.Sprintf("base.Flag.%s has unexpected type %s", f.Name, f.Type))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -359,7 +364,7 @@ func concurrentBackendAllowed() bool {
|
|||
// while writing the object file, and that is non-concurrent.
|
||||
// Adding Debug_vlog, however, causes Debug.S to also print
|
||||
// while flushing the plist, which happens concurrently.
|
||||
if Ctxt.Debugvlog || Debug.Any() || Flag.Live > 0 {
|
||||
if Ctxt.Debugvlog || Debug.Any || Flag.Live > 0 {
|
||||
return false
|
||||
}
|
||||
// TODO: Test and delete this condition.
|
||||
|
|
|
|||
|
|
@ -333,11 +333,32 @@ func (e *escape) rewriteArgument(argp *ir.Node, init *ir.Nodes, call ir.Node, fn
|
|||
}
|
||||
}
|
||||
|
||||
// Peel away any slice lits.
|
||||
// Peel away any slice literals for better escape analyze
|
||||
// them. For example:
|
||||
//
|
||||
// go F([]int{a, b})
|
||||
//
|
||||
// If F doesn't escape its arguments, then the slice can
|
||||
// be allocated on the new goroutine's stack.
|
||||
//
|
||||
// For variadic functions, the compiler has already rewritten:
|
||||
//
|
||||
// f(a, b, c)
|
||||
//
|
||||
// to:
|
||||
//
|
||||
// f([]T{a, b, c}...)
|
||||
//
|
||||
// So we need to look into slice elements to handle uintptr(ptr)
|
||||
// arguments to syscall-like functions correctly.
|
||||
if arg := *argp; arg.Op() == ir.OSLICELIT {
|
||||
list := arg.(*ir.CompLitExpr).List
|
||||
for i := range list {
|
||||
visit(arg.Pos(), &list[i])
|
||||
el := &list[i]
|
||||
if list[i].Op() == ir.OKEY {
|
||||
el = &list[i].(*ir.KeyExpr).Value
|
||||
}
|
||||
visit(arg.Pos(), el)
|
||||
}
|
||||
} else {
|
||||
visit(call.Pos(), argp)
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
|
|||
break
|
||||
}
|
||||
|
||||
if fn := inlCallee(n.X); fn != nil && fn.Inl != nil {
|
||||
if fn := inlCallee(n.X); fn != nil && typecheck.HaveInlineBody(fn) {
|
||||
v.budget -= fn.Inl.Cost
|
||||
break
|
||||
}
|
||||
|
|
@ -585,7 +585,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
|
|||
if ir.IsIntrinsicCall(call) {
|
||||
break
|
||||
}
|
||||
if fn := inlCallee(call.X); fn != nil && fn.Inl != nil {
|
||||
if fn := inlCallee(call.X); fn != nil && typecheck.HaveInlineBody(fn) {
|
||||
n = mkinlcall(call, fn, maxCost, inlMap, edit)
|
||||
}
|
||||
}
|
||||
|
|
@ -685,6 +685,27 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
|
|||
return n
|
||||
}
|
||||
|
||||
// Don't inline a function fn that has no shape parameters, but is passed at
|
||||
// least one shape arg. This means we must be inlining a non-generic function
|
||||
// fn that was passed into a generic function, and can be called with a shape
|
||||
// arg because it matches an appropriate type parameters. But fn may include
|
||||
// an interface conversion (that may be applied to a shape arg) that was not
|
||||
// apparent when we first created the instantiation of the generic function.
|
||||
// We can't handle this if we actually do the inlining, since we want to know
|
||||
// all interface conversions immediately after stenciling. So, we avoid
|
||||
// inlining in this case. See #49309.
|
||||
if !fn.Type().HasShape() {
|
||||
for _, arg := range n.Args {
|
||||
if arg.Type().HasShape() {
|
||||
if logopt.Enabled() {
|
||||
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
|
||||
fmt.Sprintf("inlining non-shape function %v with shape args", ir.FuncName(fn)))
|
||||
}
|
||||
return n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if base.Flag.Cfg.Instrumenting && types.IsRuntimePkg(fn.Sym().Pkg) {
|
||||
// Runtime package must not be instrumented.
|
||||
// Instrument skips runtime package. However, some runtime code can be
|
||||
|
|
|
|||
|
|
@ -146,7 +146,10 @@ func (n *Name) editChildren(edit func(Node) Node) {}
|
|||
// That is, given "type T Defn", it returns Defn.
|
||||
// It is used by package types.
|
||||
func (n *Name) TypeDefn() *types.Type {
|
||||
return n.Ntype.Type()
|
||||
if n.Ntype != nil {
|
||||
return n.Ntype.Type()
|
||||
}
|
||||
return n.Type()
|
||||
}
|
||||
|
||||
// RecordFrameOffset records the frame offset for the name.
|
||||
|
|
|
|||
|
|
@ -235,12 +235,6 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
|
|||
return DotField(pos, x, last)
|
||||
}
|
||||
|
||||
// TODO(danscales,mdempsky): Interface method sets are not sorted the
|
||||
// same between types and types2. In particular, using "last" here
|
||||
// without conversion will likely fail if an interface contains
|
||||
// unexported methods from two different packages (due to cross-package
|
||||
// interface embedding).
|
||||
|
||||
var n ir.Node
|
||||
method2 := selinfo.Obj().(*types2.Func)
|
||||
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ func (g *genInst) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.N
|
|||
// yet. If so, it imports the body.
|
||||
func checkFetchBody(nameNode *ir.Name) {
|
||||
if nameNode.Func.Body == nil && nameNode.Func.Inl != nil {
|
||||
// If there is no body yet but Func.Inl exists, then we can can
|
||||
// If there is no body yet but Func.Inl exists, then we can
|
||||
// import the whole generic body.
|
||||
assert(nameNode.Func.Inl.Cost == 1 && nameNode.Sym().Pkg != types.LocalPkg)
|
||||
typecheck.ImportBody(nameNode.Func)
|
||||
|
|
@ -638,7 +638,18 @@ func checkFetchBody(nameNode *ir.Name) {
|
|||
// with the type arguments shapes. If the instantiated function is not already
|
||||
// cached, then it calls genericSubst to create the new instantiation.
|
||||
func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth bool) *instInfo {
|
||||
checkFetchBody(nameNode)
|
||||
if nameNode.Func == nil {
|
||||
// If nameNode.Func is nil, this must be a reference to a method of
|
||||
// an imported instantiated type. We will have already called
|
||||
// g.instantiateMethods() on the fully-instantiated type, so
|
||||
// g.instInfoMap[sym] will be non-nil below.
|
||||
rcvr := nameNode.Type().Recv()
|
||||
if rcvr == nil || !deref(rcvr.Type).IsFullyInstantiated() {
|
||||
base.FatalfAt(nameNode.Pos(), "Unexpected function instantiation %v with no body", nameNode)
|
||||
}
|
||||
} else {
|
||||
checkFetchBody(nameNode)
|
||||
}
|
||||
|
||||
// Convert any non-shape type arguments to their shape, so we can reduce the
|
||||
// number of instantiations we have to generate. You can actually have a mix
|
||||
|
|
|
|||
|
|
@ -959,11 +959,6 @@ func writeType(t *types.Type) *obj.LSym {
|
|||
base.Fatalf("unresolved defined type: %v", tbase)
|
||||
}
|
||||
|
||||
dupok := 0
|
||||
if tbase.Sym() == nil || tbase.HasShape() { // TODO(mdempsky): Probably need DUPOK for instantiated types too.
|
||||
dupok = obj.DUPOK
|
||||
}
|
||||
|
||||
if !NeedEmit(tbase) {
|
||||
if i := typecheck.BaseTypeIndex(t); i >= 0 {
|
||||
lsym.Pkg = tbase.Sym().Pkg.Prefix
|
||||
|
|
@ -1196,7 +1191,9 @@ func writeType(t *types.Type) *obj.LSym {
|
|||
}
|
||||
|
||||
ot = dextratypeData(lsym, ot, t)
|
||||
objw.Global(lsym, int32(ot), int16(dupok|obj.RODATA))
|
||||
objw.Global(lsym, int32(ot), int16(obj.DUPOK|obj.RODATA))
|
||||
// Note: DUPOK is required to ensure that we don't end up with more
|
||||
// than one type descriptor for a given type.
|
||||
|
||||
// The linker will leave a table of all the typelinks for
|
||||
// types in the binary, so the runtime can find them.
|
||||
|
|
|
|||
|
|
@ -958,6 +958,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
|
|||
return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
|
||||
}
|
||||
eltRO := x.regWidth(elt)
|
||||
source.Type = t
|
||||
for i := int64(0); i < t.NumElem(); i++ {
|
||||
sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source)
|
||||
mem = x.storeArgOrLoad(pos, b, sel, mem, elt, storeOffset+i*elt.Size(), loadRegOffset, storeRc.at(t, 0))
|
||||
|
|
@ -991,6 +992,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
|
|||
return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
|
||||
}
|
||||
|
||||
source.Type = t
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
fld := t.Field(i)
|
||||
sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ const (
|
|||
riscv64REG_CTXT = 20
|
||||
riscv64REG_LR = 1
|
||||
riscv64REG_SP = 2
|
||||
riscv64REG_GP = 3
|
||||
riscv64REG_TP = 4
|
||||
riscv64REG_TMP = 31
|
||||
riscv64REG_ZERO = 0
|
||||
|
|
@ -80,8 +81,8 @@ func init() {
|
|||
|
||||
// Add general purpose registers to gpMask.
|
||||
switch r {
|
||||
// ZERO, TP and TMP are not in any gp mask.
|
||||
case riscv64REG_ZERO, riscv64REG_TP, riscv64REG_TMP:
|
||||
// ZERO, GP, TP and TMP are not in any gp mask.
|
||||
case riscv64REG_ZERO, riscv64REG_GP, riscv64REG_TP, riscv64REG_TMP:
|
||||
case riscv64REG_G:
|
||||
gpgMask |= mask
|
||||
gpspsbgMask |= mask
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -635,6 +635,8 @@ func (s *regAllocState) init(f *Func) {
|
|||
// nothing to do
|
||||
case "ppc64le": // R2 already reserved.
|
||||
// nothing to do
|
||||
case "riscv64": // X3 (aka GP) and X4 (aka TP) already reserved.
|
||||
// nothing to do
|
||||
case "s390x":
|
||||
s.allocatable &^= 1 << 11 // R11
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ func TestStmtLines(t *testing.T) {
|
|||
if pkgname == "runtime" {
|
||||
continue
|
||||
}
|
||||
if pkgname == "crypto/elliptic/internal/fiat" {
|
||||
continue // golang.org/issue/49372
|
||||
}
|
||||
if e.Val(dwarf.AttrStmtList) == nil {
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -708,15 +708,7 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
|
|||
}
|
||||
|
||||
f.Name = p.name()
|
||||
if p.allowGenerics() && p.got(_Lbrack) {
|
||||
if p.tok == _Rbrack {
|
||||
p.syntaxError("empty type parameter list")
|
||||
p.next()
|
||||
} else {
|
||||
f.TParamList = p.paramList(nil, _Rbrack, true)
|
||||
}
|
||||
}
|
||||
f.Type = p.funcType()
|
||||
f.TParamList, f.Type = p.funcType("")
|
||||
if p.tok == _Lbrace {
|
||||
f.Body = p.funcBody()
|
||||
}
|
||||
|
|
@ -944,7 +936,7 @@ func (p *parser) operand(keep_parens bool) Expr {
|
|||
case _Func:
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
ftyp := p.funcType()
|
||||
_, ftyp := p.funcType("function literal")
|
||||
if p.tok == _Lbrace {
|
||||
p.xnest++
|
||||
|
||||
|
|
@ -1284,7 +1276,8 @@ func (p *parser) typeOrNil() Expr {
|
|||
case _Func:
|
||||
// fntype
|
||||
p.next()
|
||||
return p.funcType()
|
||||
_, t := p.funcType("function type")
|
||||
return t
|
||||
|
||||
case _Lbrack:
|
||||
// '[' oexpr ']' ntype
|
||||
|
|
@ -1357,18 +1350,34 @@ func (p *parser) typeInstance(typ Expr) Expr {
|
|||
return x
|
||||
}
|
||||
|
||||
func (p *parser) funcType() *FuncType {
|
||||
// If context != "", type parameters are not permitted.
|
||||
func (p *parser) funcType(context string) ([]*Field, *FuncType) {
|
||||
if trace {
|
||||
defer p.trace("funcType")()
|
||||
}
|
||||
|
||||
typ := new(FuncType)
|
||||
typ.pos = p.pos()
|
||||
|
||||
var tparamList []*Field
|
||||
if p.allowGenerics() && p.got(_Lbrack) {
|
||||
if context != "" {
|
||||
// accept but complain
|
||||
p.syntaxErrorAt(typ.pos, context+" cannot have type parameters")
|
||||
}
|
||||
if p.tok == _Rbrack {
|
||||
p.syntaxError("empty type parameter list")
|
||||
p.next()
|
||||
} else {
|
||||
tparamList = p.paramList(nil, _Rbrack, true)
|
||||
}
|
||||
}
|
||||
|
||||
p.want(_Lparen)
|
||||
typ.ParamList = p.paramList(nil, _Rparen, false)
|
||||
typ.ResultList = p.funcResult()
|
||||
|
||||
return typ
|
||||
return tparamList, typ
|
||||
}
|
||||
|
||||
// "[" has already been consumed, and pos is its position.
|
||||
|
|
@ -1697,11 +1706,13 @@ func (p *parser) methodDecl() *Field {
|
|||
// already progressed, no need to advance
|
||||
}
|
||||
|
||||
const context = "interface method"
|
||||
|
||||
switch p.tok {
|
||||
case _Lparen:
|
||||
// method
|
||||
f.Name = name
|
||||
f.Type = p.funcType()
|
||||
_, f.Type = p.funcType(context)
|
||||
|
||||
case _Lbrack:
|
||||
if p.allowGenerics() {
|
||||
|
|
@ -1721,7 +1732,7 @@ func (p *parser) methodDecl() *Field {
|
|||
// name[](
|
||||
p.errorAt(pos, "empty type parameter list")
|
||||
f.Name = name
|
||||
f.Type = p.funcType()
|
||||
_, f.Type = p.funcType(context)
|
||||
} else {
|
||||
p.errorAt(pos, "empty type argument list")
|
||||
f.Type = name
|
||||
|
|
@ -1738,7 +1749,7 @@ func (p *parser) methodDecl() *Field {
|
|||
// as if [] were absent.
|
||||
if p.tok == _Lparen {
|
||||
f.Name = name
|
||||
f.Type = p.funcType()
|
||||
_, f.Type = p.funcType(context)
|
||||
} else {
|
||||
f.Type = name
|
||||
}
|
||||
|
|
@ -1749,7 +1760,7 @@ func (p *parser) methodDecl() *Field {
|
|||
if list[0].Name != nil {
|
||||
// generic method
|
||||
f.Name = name
|
||||
f.Type = p.funcType()
|
||||
_, f.Type = p.funcType(context)
|
||||
// TODO(gri) Record list as type parameter list with f.Type
|
||||
// if we want to type-check the generic method.
|
||||
// For now, report an error so this is not a silent event.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type _ func /* ERROR function type cannot have type parameters */ [ /* ERROR empty type parameter list */ ]()
|
||||
type _ func /* ERROR function type cannot have type parameters */ [ x /* ERROR missing type constraint */ ]()
|
||||
type _ func /* ERROR function type cannot have type parameters */ [P any]()
|
||||
|
||||
var _ = func /* ERROR function literal cannot have type parameters */ [P any]() {}
|
||||
|
||||
type _ interface{
|
||||
m /* ERROR interface method cannot have type parameters */ [P any]()
|
||||
}
|
||||
|
|
@ -207,7 +207,7 @@ func (p *crawler) markInlBody(n *ir.Name) {
|
|||
if fn == nil {
|
||||
base.Fatalf("markInlBody: missing Func on %v", n)
|
||||
}
|
||||
if fn.Inl == nil {
|
||||
if !HaveInlineBody(fn) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,27 @@ func ImportBody(fn *ir.Func) {
|
|||
inimport = false
|
||||
}
|
||||
|
||||
// HaveInlineBody reports whether we have fn's inline body available
|
||||
// for inlining.
|
||||
func HaveInlineBody(fn *ir.Func) bool {
|
||||
if fn.Inl == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Unified IR is much more conservative about pruning unreachable
|
||||
// methods (at the cost of increased build artifact size).
|
||||
if base.Debug.Unified != 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if fn.Inl.Body != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
_, ok := inlineImporter[fn.Nname.Sym()]
|
||||
return ok
|
||||
}
|
||||
|
||||
func importReaderFor(sym *types.Sym, importers map[*types.Sym]iimporterAndOffset) *importReader {
|
||||
x, ok := importers[sym]
|
||||
if !ok {
|
||||
|
|
|
|||
|
|
@ -1421,7 +1421,9 @@ func Shapify(t *types.Type, index int) *types.Type {
|
|||
|
||||
// All pointers have the same shape.
|
||||
// TODO: Make unsafe.Pointer the same shape as normal pointers.
|
||||
if u.Kind() == types.TPTR {
|
||||
// Note: pointers to arrays are special because of slice-to-array-pointer
|
||||
// conversions. See issue 49295.
|
||||
if u.Kind() == types.TPTR && u.Elem().Kind() != types.TARRAY {
|
||||
u = types.Types[types.TUINT8].PtrTo()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"cmd/internal/objabi"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
|
|
@ -48,7 +49,13 @@ func NewPkg(path, name string) *Pkg {
|
|||
p := new(Pkg)
|
||||
p.Path = path
|
||||
p.Name = name
|
||||
p.Prefix = objabi.PathToPrefix(path)
|
||||
if strings.HasPrefix(path, "go.") {
|
||||
// Special compiler-internal packages don't need to be escaped.
|
||||
// This particularly helps with the go.shape package.
|
||||
p.Prefix = path
|
||||
} else {
|
||||
p.Prefix = objabi.PathToPrefix(path)
|
||||
}
|
||||
p.Syms = make(map[string]*Sym)
|
||||
pkgMap[path] = p
|
||||
|
||||
|
|
|
|||
|
|
@ -2202,4 +2202,4 @@ var (
|
|||
|
||||
var SimType [NTYPE]Kind
|
||||
|
||||
var ShapePkg = NewPkg(".shape", ".shape")
|
||||
var ShapePkg = NewPkg("go.shape", "go.shape")
|
||||
|
|
|
|||
|
|
@ -326,25 +326,25 @@ func TestTypesInfo(t *testing.T) {
|
|||
{brokenPkg + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string]invalid type`},
|
||||
|
||||
// parameterized functions
|
||||
{genericPkg + `p0; func f[T any](T) {}; var _ = f[int]`, `f`, `func[generic_p0.T₁ interface{}](generic_p0.T₁)`},
|
||||
{genericPkg + `p0; func f[T any](T) {}; var _ = f[int]`, `f`, `func[T interface{}](T)`},
|
||||
{genericPkg + `p1; func f[T any](T) {}; var _ = f[int]`, `f[int]`, `func(int)`},
|
||||
{genericPkg + `p2; func f[T any](T) {}; func _() { f(42) }`, `f`, `func(int)`},
|
||||
{genericPkg + `p3; func f[T any](T) {}; func _() { f[int](42) }`, `f[int]`, `func(int)`},
|
||||
{genericPkg + `p4; func f[T any](T) {}; func _() { f[int](42) }`, `f`, `func[generic_p4.T₁ interface{}](generic_p4.T₁)`},
|
||||
{genericPkg + `p4; func f[T any](T) {}; func _() { f[int](42) }`, `f`, `func[T interface{}](T)`},
|
||||
{genericPkg + `p5; func f[T any](T) {}; func _() { f(42) }`, `f(42)`, `()`},
|
||||
|
||||
// type parameters
|
||||
{genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
|
||||
{genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[generic_t1.P₁ interface{}]`},
|
||||
{genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[generic_t2.P₁ interface{}]`},
|
||||
{genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[generic_t3.P₁, generic_t3.Q₂ interface{}]`},
|
||||
{brokenPkg + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[broken_t4.P₁, broken_t4.Q₂ interface{m()}]`},
|
||||
{genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[P interface{}]`},
|
||||
{genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[P interface{}]`},
|
||||
{genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[P, Q interface{}]`},
|
||||
{brokenPkg + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[P, Q interface{m()}]`},
|
||||
|
||||
// instantiated types must be sanitized
|
||||
{genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`},
|
||||
|
||||
// issue 45096
|
||||
{genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `generic_issue45096.T₁`},
|
||||
{genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `T`},
|
||||
|
||||
// issue 47895
|
||||
{`package p; import "unsafe"; type S struct { f int }; var s S; var _ = unsafe.Offsetof(s.f)`, `s.f`, `int`},
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
if isString(x.typ) {
|
||||
if allString(x.typ) {
|
||||
if check.Types != nil {
|
||||
sig := makeSig(S, S, x.typ)
|
||||
sig.variadic = true
|
||||
|
|
|
|||
|
|
@ -112,15 +112,15 @@ var builtinCalls = []struct {
|
|||
|
||||
{"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`}, // constant
|
||||
{"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
|
||||
{"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(p.P₁) uintptr`},
|
||||
{"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(P) uintptr`},
|
||||
|
||||
{"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`}, // constant
|
||||
{"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
|
||||
{"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(p.P₁) uintptr`},
|
||||
{"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(P) uintptr`},
|
||||
|
||||
{"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`}, // constant
|
||||
{"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
|
||||
{"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(p.P₁) uintptr`},
|
||||
{"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(P) uintptr`},
|
||||
|
||||
{"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
|
||||
{"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ func (check *Checker) instantiateSignature(pos syntax.Pos, typ *Signature, targs
|
|||
pos = posList[i]
|
||||
}
|
||||
check.softErrorf(pos, err.Error())
|
||||
} else {
|
||||
check.mono.recordInstance(check.pkg, pos, tparams, targs, posList)
|
||||
}
|
||||
|
||||
return inst
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ type Checker struct {
|
|||
imports []*PkgName // list of imported packages
|
||||
dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through
|
||||
recvTParamMap map[*syntax.Name]*TypeParam // maps blank receiver type parameters to their type
|
||||
mono monoGraph // graph for detecting non-monomorphizable instantiation loops
|
||||
|
||||
firstErr error // first error encountered
|
||||
methods map[*TypeName][]*Func // maps package scope type names to associated non-blank (non-interface) methods
|
||||
|
|
@ -317,6 +318,11 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
|
|||
print("== recordUntyped ==")
|
||||
check.recordUntyped()
|
||||
|
||||
if check.firstErr == nil {
|
||||
// TODO(mdempsky): Ensure monomorph is safe when errors exist.
|
||||
check.monomorph()
|
||||
}
|
||||
|
||||
check.pkg.complete = true
|
||||
|
||||
// no longer needed - release memory
|
||||
|
|
@ -424,9 +430,9 @@ func (check *Checker) recordTypeAndValue(x syntax.Expr, mode operandMode, typ Ty
|
|||
}
|
||||
if mode == constant_ {
|
||||
assert(val != nil)
|
||||
// We check is(typ, IsConstType) here as constant expressions may be
|
||||
// We check allBasic(typ, IsConstType) here as constant expressions may be
|
||||
// recorded as type parameters.
|
||||
assert(typ == Typ[Invalid] || is(typ, IsConstType))
|
||||
assert(typ == Typ[Invalid] || allBasic(typ, IsConstType))
|
||||
}
|
||||
if m := check.Types; m != nil {
|
||||
m[x] = TypeAndValue{mode, typ, val}
|
||||
|
|
|
|||
|
|
@ -16,26 +16,54 @@ import (
|
|||
func (check *Checker) conversion(x *operand, T Type) {
|
||||
constArg := x.mode == constant_
|
||||
|
||||
var ok bool
|
||||
var cause string
|
||||
switch {
|
||||
case constArg && isConstType(T):
|
||||
// constant conversion (T cannot be a type parameter)
|
||||
constConvertibleTo := func(T Type, val *constant.Value) bool {
|
||||
switch t := asBasic(T); {
|
||||
case representableConst(x.val, check, t, &x.val):
|
||||
ok = true
|
||||
case t == nil:
|
||||
// nothing to do
|
||||
case representableConst(x.val, check, t, val):
|
||||
return true
|
||||
case isInteger(x.typ) && isString(t):
|
||||
codepoint := unicode.ReplacementChar
|
||||
if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
|
||||
codepoint = rune(i)
|
||||
}
|
||||
x.val = constant.MakeString(string(codepoint))
|
||||
ok = true
|
||||
if val != nil {
|
||||
*val = constant.MakeString(string(codepoint))
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var ok bool
|
||||
var cause string
|
||||
switch {
|
||||
case constArg && isConstType(T):
|
||||
// constant conversion
|
||||
ok = constConvertibleTo(T, &x.val)
|
||||
case constArg && isTypeParam(T):
|
||||
// x is convertible to T if it is convertible
|
||||
// to each specific type in the type set of T.
|
||||
// If T's type set is empty, or if it doesn't
|
||||
// have specific types, constant x cannot be
|
||||
// converted.
|
||||
ok = under(T).(*TypeParam).underIs(func(u Type) bool {
|
||||
// t is nil if there are no specific type terms
|
||||
if u == nil {
|
||||
cause = check.sprintf("%s does not contain specific types", T)
|
||||
return false
|
||||
}
|
||||
if !constConvertibleTo(u, nil) {
|
||||
cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
x.mode = value // type parameters are not constants
|
||||
case x.convertibleTo(check, T, &cause):
|
||||
// non-constant conversion
|
||||
x.mode = value
|
||||
ok = true
|
||||
x.mode = value
|
||||
}
|
||||
|
||||
if !ok {
|
||||
|
|
@ -65,7 +93,7 @@ func (check *Checker) conversion(x *operand, T Type) {
|
|||
// ok
|
||||
} else if IsInterface(T) || constArg && !isConstType(T) {
|
||||
final = Default(x.typ)
|
||||
} else if isInteger(x.typ) && isString(T) {
|
||||
} else if isInteger(x.typ) && allString(T) {
|
||||
final = x.typ
|
||||
}
|
||||
check.updateExprType(x.expr, final, true)
|
||||
|
|
@ -94,64 +122,8 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// determine type parameter operands with specific type terms
|
||||
Vp, _ := under(x.typ).(*TypeParam)
|
||||
Tp, _ := under(T).(*TypeParam)
|
||||
if Vp != nil && !Vp.hasTerms() {
|
||||
Vp = nil
|
||||
}
|
||||
if Tp != nil && !Tp.hasTerms() {
|
||||
Tp = nil
|
||||
}
|
||||
|
||||
errorf := func(format string, args ...interface{}) {
|
||||
if check != nil && cause != nil {
|
||||
msg := check.sprintf(format, args...)
|
||||
if *cause != "" {
|
||||
msg += "\n\t" + *cause
|
||||
}
|
||||
*cause = msg
|
||||
}
|
||||
}
|
||||
|
||||
// generic cases with specific type terms
|
||||
// (generic operands cannot be constants, so we can ignore x.val)
|
||||
switch {
|
||||
case Vp != nil && Tp != nil:
|
||||
return Vp.is(func(V *term) bool {
|
||||
return Tp.is(func(T *term) bool {
|
||||
if !convertibleToImpl(check, V.typ, T.typ, cause) {
|
||||
errorf("cannot convert %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
})
|
||||
case Vp != nil:
|
||||
return Vp.is(func(V *term) bool {
|
||||
if !convertibleToImpl(check, V.typ, T, cause) {
|
||||
errorf("cannot convert %s (in %s) to %s", V.typ, Vp, T)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
case Tp != nil:
|
||||
return Tp.is(func(T *term) bool {
|
||||
if !convertibleToImpl(check, x.typ, T.typ, cause) {
|
||||
errorf("cannot convert %s to %s (in %s)", x.typ, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// non-generic case
|
||||
return convertibleToImpl(check, x.typ, T, cause)
|
||||
}
|
||||
|
||||
// convertibleToImpl should only be called by convertibleTo
|
||||
func convertibleToImpl(check *Checker, V, T Type, cause *string) bool {
|
||||
// "V and T have identical underlying types if tags are ignored"
|
||||
V := x.typ
|
||||
Vu := under(V)
|
||||
Tu := under(T)
|
||||
if IdenticalIgnoreTags(Vu, Tu) {
|
||||
|
|
@ -222,6 +194,67 @@ func convertibleToImpl(check *Checker, V, T Type, cause *string) bool {
|
|||
}
|
||||
}
|
||||
|
||||
// optimization: if we don't have type parameters, we're done
|
||||
Vp, _ := Vu.(*TypeParam)
|
||||
Tp, _ := Tu.(*TypeParam)
|
||||
if Vp == nil && Tp == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
errorf := func(format string, args ...interface{}) {
|
||||
if check != nil && cause != nil {
|
||||
msg := check.sprintf(format, args...)
|
||||
if *cause != "" {
|
||||
msg += "\n\t" + *cause
|
||||
}
|
||||
*cause = msg
|
||||
}
|
||||
}
|
||||
|
||||
// generic cases with specific type terms
|
||||
// (generic operands cannot be constants, so we can ignore x.val)
|
||||
switch {
|
||||
case Vp != nil && Tp != nil:
|
||||
x := *x // don't clobber outer x
|
||||
return Vp.is(func(V *term) bool {
|
||||
if V == nil {
|
||||
return false // no specific types
|
||||
}
|
||||
x.typ = V.typ
|
||||
return Tp.is(func(T *term) bool {
|
||||
if !x.convertibleTo(check, T.typ, cause) {
|
||||
errorf("cannot convert %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
})
|
||||
case Vp != nil:
|
||||
x := *x // don't clobber outer x
|
||||
return Vp.is(func(V *term) bool {
|
||||
if V == nil {
|
||||
return false // no specific types
|
||||
}
|
||||
x.typ = V.typ
|
||||
if !x.convertibleTo(check, T, cause) {
|
||||
errorf("cannot convert %s (in %s) to %s", V.typ, Vp, T)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
case Tp != nil:
|
||||
return Tp.is(func(T *term) bool {
|
||||
if T == nil {
|
||||
return false // no specific types
|
||||
}
|
||||
if !x.convertibleTo(check, T.typ, cause) {
|
||||
errorf("cannot convert %s to %s (in %s)", x.typ, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ func (err *error_) msg(qf Qualifier) string {
|
|||
fmt.Fprintf(&buf, "%s: ", p.pos)
|
||||
}
|
||||
}
|
||||
buf.WriteString(sprintf(qf, p.format, p.args...))
|
||||
buf.WriteString(sprintf(qf, false, p.format, p.args...))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ func (err *error_) errorf(at poser, format string, args ...interface{}) {
|
|||
err.desc = append(err.desc, errorDesc{posFor(at), format, args})
|
||||
}
|
||||
|
||||
func sprintf(qf Qualifier, format string, args ...interface{}) string {
|
||||
func sprintf(qf Qualifier, debug bool, format string, args ...interface{}) string {
|
||||
for i, arg := range args {
|
||||
switch a := arg.(type) {
|
||||
case nil:
|
||||
|
|
@ -101,7 +101,7 @@ func sprintf(qf Qualifier, format string, args ...interface{}) string {
|
|||
case Object:
|
||||
arg = ObjectString(a, qf)
|
||||
case Type:
|
||||
arg = TypeString(a, qf)
|
||||
arg = typeString(a, qf, debug)
|
||||
}
|
||||
args[i] = arg
|
||||
}
|
||||
|
|
@ -146,7 +146,7 @@ func (check *Checker) markImports(pkg *Package) {
|
|||
}
|
||||
|
||||
func (check *Checker) sprintf(format string, args ...interface{}) string {
|
||||
return sprintf(check.qualifier, format, args...)
|
||||
return sprintf(check.qualifier, false, format, args...)
|
||||
}
|
||||
|
||||
func (check *Checker) report(err *error_) {
|
||||
|
|
@ -160,13 +160,13 @@ func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{})
|
|||
fmt.Printf("%s:\t%s%s\n",
|
||||
pos,
|
||||
strings.Repeat(". ", check.indent),
|
||||
check.sprintf(format, args...),
|
||||
sprintf(check.qualifier, true, format, args...),
|
||||
)
|
||||
}
|
||||
|
||||
// dump is only needed for debugging
|
||||
func (check *Checker) dump(format string, args ...interface{}) {
|
||||
fmt.Println(check.sprintf(format, args...))
|
||||
fmt.Println(sprintf(check.qualifier, true, format, args...))
|
||||
}
|
||||
|
||||
func (check *Checker) err(at poser, msg string, soft bool) {
|
||||
|
|
|
|||
|
|
@ -63,10 +63,10 @@ var unaryOpPredicates opPredicates
|
|||
func init() {
|
||||
// Setting unaryOpPredicates in init avoids declaration cycles.
|
||||
unaryOpPredicates = opPredicates{
|
||||
syntax.Add: isNumeric,
|
||||
syntax.Sub: isNumeric,
|
||||
syntax.Xor: isInteger,
|
||||
syntax.Not: isBoolean,
|
||||
syntax.Add: allNumeric,
|
||||
syntax.Sub: allNumeric,
|
||||
syntax.Xor: allInteger,
|
||||
syntax.Not: allBoolean,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -710,10 +710,10 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
|
|||
return nil, nil, _InvalidUntypedConversion
|
||||
}
|
||||
|
||||
switch t := under(target).(type) {
|
||||
switch u := under(target).(type) {
|
||||
case *Basic:
|
||||
if x.mode == constant_ {
|
||||
v, code := check.representation(x, t)
|
||||
v, code := check.representation(x, u)
|
||||
if code != 0 {
|
||||
return nil, nil, code
|
||||
}
|
||||
|
|
@ -743,7 +743,8 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
|
|||
return nil, nil, _InvalidUntypedConversion
|
||||
}
|
||||
case *TypeParam:
|
||||
ok := t.underIs(func(t Type) bool {
|
||||
// TODO(gri) review this code - doesn't look quite right
|
||||
ok := u.underIs(func(t Type) bool {
|
||||
target, _, _ := check.implicitTypeAndValue(x, t)
|
||||
return target != nil
|
||||
})
|
||||
|
|
@ -754,7 +755,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
|
|||
// Update operand types to the default type rather than the target
|
||||
// (interface) type: values must have concrete dynamic types.
|
||||
// Untyped nil was handled upfront.
|
||||
if !t.Empty() {
|
||||
if !u.Empty() {
|
||||
return nil, nil, _InvalidUntypedConversion // cannot assign untyped values to non-empty interfaces
|
||||
}
|
||||
return Default(x.typ), nil, 0 // default type for nil is nil
|
||||
|
|
@ -778,7 +779,7 @@ func (check *Checker) comparison(x, y *operand, op syntax.Operator) {
|
|||
defined = Comparable(x.typ) && Comparable(y.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
|
||||
case syntax.Lss, syntax.Leq, syntax.Gtr, syntax.Geq:
|
||||
// spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
|
||||
defined = isOrdered(x.typ) && isOrdered(y.typ)
|
||||
defined = allOrdered(x.typ) && allOrdered(y.typ)
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
|
|
@ -832,7 +833,7 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) {
|
|||
xval = constant.ToInt(x.val)
|
||||
}
|
||||
|
||||
if isInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
|
||||
if allInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
|
||||
// The lhs is of integer type or an untyped constant representable
|
||||
// as an integer. Nothing to do.
|
||||
} else {
|
||||
|
|
@ -863,11 +864,11 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) {
|
|||
x.mode = invalid
|
||||
return
|
||||
}
|
||||
} else if !isInteger(y.typ) {
|
||||
} else if !allInteger(y.typ) {
|
||||
check.errorf(y, invalidOp+"shift count %s must be integer", y)
|
||||
x.mode = invalid
|
||||
return
|
||||
} else if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
|
||||
} else if !allUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
|
||||
check.errorf(y, invalidOp+"signed shift count %s requires go1.13 or later", y)
|
||||
x.mode = invalid
|
||||
return
|
||||
|
|
@ -938,7 +939,7 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) {
|
|||
}
|
||||
|
||||
// non-constant shift - lhs must be an integer
|
||||
if !isInteger(x.typ) {
|
||||
if !allInteger(x.typ) {
|
||||
check.errorf(x, invalidOp+"shifted operand %s must be integer", x)
|
||||
x.mode = invalid
|
||||
return
|
||||
|
|
@ -952,19 +953,19 @@ var binaryOpPredicates opPredicates
|
|||
func init() {
|
||||
// Setting binaryOpPredicates in init avoids declaration cycles.
|
||||
binaryOpPredicates = opPredicates{
|
||||
syntax.Add: isNumericOrString,
|
||||
syntax.Sub: isNumeric,
|
||||
syntax.Mul: isNumeric,
|
||||
syntax.Div: isNumeric,
|
||||
syntax.Rem: isInteger,
|
||||
syntax.Add: allNumericOrString,
|
||||
syntax.Sub: allNumeric,
|
||||
syntax.Mul: allNumeric,
|
||||
syntax.Div: allNumeric,
|
||||
syntax.Rem: allInteger,
|
||||
|
||||
syntax.And: isInteger,
|
||||
syntax.Or: isInteger,
|
||||
syntax.Xor: isInteger,
|
||||
syntax.AndNot: isInteger,
|
||||
syntax.And: allInteger,
|
||||
syntax.Or: allInteger,
|
||||
syntax.Xor: allInteger,
|
||||
syntax.AndNot: allInteger,
|
||||
|
||||
syntax.AndAnd: isBoolean,
|
||||
syntax.OrOr: isBoolean,
|
||||
syntax.AndAnd: allBoolean,
|
||||
syntax.OrOr: allBoolean,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -994,10 +995,10 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op
|
|||
if IsInterface(x.typ) || IsInterface(y.typ) {
|
||||
return true
|
||||
}
|
||||
if isBoolean(x.typ) != isBoolean(y.typ) {
|
||||
if allBoolean(x.typ) != allBoolean(y.typ) {
|
||||
return false
|
||||
}
|
||||
if isString(x.typ) != isString(y.typ) {
|
||||
if allString(x.typ) != allString(y.typ) {
|
||||
return false
|
||||
}
|
||||
if x.isNil() && !hasNil(y.typ) {
|
||||
|
|
@ -1046,7 +1047,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op
|
|||
|
||||
if op == syntax.Div || op == syntax.Rem {
|
||||
// check for zero divisor
|
||||
if (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
|
||||
if (x.mode == constant_ || allInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
|
||||
check.error(&y, invalidOp+"division by zero")
|
||||
x.mode = invalid
|
||||
return
|
||||
|
|
|
|||
|
|
@ -101,77 +101,80 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
|
|||
|
||||
case *TypeParam:
|
||||
// TODO(gri) report detailed failure cause for better error messages
|
||||
var tkey, telem Type // tkey != nil if we have maps
|
||||
var key, elem Type // key != nil: we must have all maps
|
||||
mode := variable // non-maps result mode
|
||||
// TODO(gri) factor out closure and use it for non-typeparam cases as well
|
||||
if typ.underIs(func(u Type) bool {
|
||||
var key, elem Type
|
||||
alen := int64(-1) // valid if >= 0
|
||||
l := int64(-1) // valid if >= 0
|
||||
var k, e Type // k is only set for maps
|
||||
switch t := u.(type) {
|
||||
case *Basic:
|
||||
if !isString(t) {
|
||||
return false
|
||||
if isString(t) {
|
||||
e = universeByte
|
||||
mode = value
|
||||
}
|
||||
elem = universeByte
|
||||
case *Array:
|
||||
elem = t.elem
|
||||
alen = t.len
|
||||
case *Pointer:
|
||||
a, _ := under(t.base).(*Array)
|
||||
if a == nil {
|
||||
return false
|
||||
l = t.len
|
||||
e = t.elem
|
||||
if x.mode != variable {
|
||||
mode = value
|
||||
}
|
||||
case *Pointer:
|
||||
if t := asArray(t.base); t != nil {
|
||||
l = t.len
|
||||
e = t.elem
|
||||
}
|
||||
elem = a.elem
|
||||
alen = a.len
|
||||
case *Slice:
|
||||
elem = t.elem
|
||||
e = t.elem
|
||||
case *Map:
|
||||
key = t.key
|
||||
elem = t.elem
|
||||
default:
|
||||
k = t.key
|
||||
e = t.elem
|
||||
}
|
||||
if e == nil {
|
||||
return false
|
||||
}
|
||||
assert(elem != nil)
|
||||
if telem == nil {
|
||||
if elem == nil {
|
||||
// first type
|
||||
tkey, telem = key, elem
|
||||
length = alen
|
||||
} else {
|
||||
// all map keys must be identical (incl. all nil)
|
||||
if !Identical(key, tkey) {
|
||||
return false
|
||||
}
|
||||
// all element types must be identical
|
||||
if !Identical(elem, telem) {
|
||||
return false
|
||||
}
|
||||
tkey, telem = key, elem
|
||||
// track the minimal length for arrays
|
||||
if alen >= 0 && alen < length {
|
||||
length = alen
|
||||
}
|
||||
length = l
|
||||
key, elem = k, e
|
||||
return true
|
||||
}
|
||||
// all map keys must be identical (incl. all nil)
|
||||
// (that is, we cannot mix maps with other types)
|
||||
if !Identical(key, k) {
|
||||
return false
|
||||
}
|
||||
// all element types must be identical
|
||||
if !Identical(elem, e) {
|
||||
return false
|
||||
}
|
||||
// track the minimal length for arrays, if any
|
||||
if l >= 0 && l < length {
|
||||
length = l
|
||||
}
|
||||
return true
|
||||
}) {
|
||||
// For maps, the index expression must be assignable to the map key type.
|
||||
if tkey != nil {
|
||||
if key != nil {
|
||||
index := check.singleIndex(e)
|
||||
if index == nil {
|
||||
x.mode = invalid
|
||||
return false
|
||||
}
|
||||
var key operand
|
||||
check.expr(&key, index)
|
||||
check.assignment(&key, tkey, "map index")
|
||||
var k operand
|
||||
check.expr(&k, index)
|
||||
check.assignment(&k, key, "map index")
|
||||
// ok to continue even if indexing failed - map element type is known
|
||||
x.mode = mapindex
|
||||
x.typ = telem
|
||||
x.typ = elem
|
||||
x.expr = e
|
||||
return false
|
||||
}
|
||||
|
||||
// no maps
|
||||
valid = true
|
||||
x.mode = variable
|
||||
x.typ = telem
|
||||
x.mode = mode
|
||||
x.typ = elem
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +386,7 @@ func (check *Checker) isValidIndex(x *operand, what string, allowNegative bool)
|
|||
}
|
||||
|
||||
// spec: "the index x must be of integer type or an untyped constant"
|
||||
if !isInteger(x.typ) {
|
||||
if !allInteger(x.typ) {
|
||||
check.errorf(x, invalidArg+"%s %s must be integer", what, x)
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
|
|||
// At least one type argument couldn't be inferred.
|
||||
assert(targs != nil && index >= 0 && targs[index] == nil)
|
||||
tpar := tparams[index]
|
||||
check.errorf(pos, "cannot infer %s (%s) (%s)", tpar.obj.name, tpar.obj.pos, targs)
|
||||
check.errorf(pos, "cannot infer %s (%s)", tpar.obj.name, tpar.obj.pos)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -378,7 +378,6 @@ func (check *Checker) inferB(tparams []*TypeParam, targs []Type) (types []Type,
|
|||
|
||||
// If a constraint has a structural type, unify the corresponding type parameter with it.
|
||||
for _, tpar := range tparams {
|
||||
typ := tpar
|
||||
sbound := structure(tpar)
|
||||
if sbound != nil {
|
||||
// If the structural type is the underlying type of a single
|
||||
|
|
@ -386,8 +385,10 @@ func (check *Checker) inferB(tparams []*TypeParam, targs []Type) (types []Type,
|
|||
if named, _ := tpar.singleType().(*Named); named != nil {
|
||||
sbound = named
|
||||
}
|
||||
if !u.unify(typ, sbound) {
|
||||
check.errorf(tpar.obj, "%s does not match %s", tpar.obj, sbound)
|
||||
if !u.unify(tpar, sbound) {
|
||||
// TODO(gri) improve error message by providing the type arguments
|
||||
// which we know already
|
||||
check.errorf(tpar.obj, "%s does not match %s", tpar, sbound)
|
||||
return nil, 0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap
|
|||
qf = check.qualifier
|
||||
}
|
||||
errorf := func(format string, args ...interface{}) error {
|
||||
return errors.New(sprintf(qf, format, args...))
|
||||
return errors.New(sprintf(qf, false, format, args...))
|
||||
}
|
||||
|
||||
// No type argument with non-empty type set satisfies the empty type set.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,337 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package types2
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/syntax"
|
||||
)
|
||||
|
||||
// This file implements a check to validate that a Go package doesn't
|
||||
// have unbounded recursive instantiation, which is not compatible
|
||||
// with compilers using static instantiation (such as
|
||||
// monomorphization).
|
||||
//
|
||||
// It implements a sort of "type flow" analysis by detecting which
|
||||
// type parameters are instantiated with other type parameters (or
|
||||
// types derived thereof). A package cannot be statically instantiated
|
||||
// if the graph has any cycles involving at least one derived type.
|
||||
//
|
||||
// Concretely, we construct a directed, weighted graph. Vertices are
|
||||
// used to represent type parameters as well as some defined
|
||||
// types. Edges are used to represent how types depend on each other:
|
||||
//
|
||||
// * Everywhere a type-parameterized function or type is instantiated,
|
||||
// we add edges to each type parameter from the vertices (if any)
|
||||
// representing each type parameter or defined type referenced by
|
||||
// the type argument. If the type argument is just the referenced
|
||||
// type itself, then the edge has weight 0, otherwise 1.
|
||||
//
|
||||
// * For every defined type declared within a type-parameterized
|
||||
// function or method, we add an edge of weight 1 to the defined
|
||||
// type from each ambient type parameter.
|
||||
//
|
||||
// For example, given:
|
||||
//
|
||||
// func f[A, B any]() {
|
||||
// type T int
|
||||
// f[T, map[A]B]()
|
||||
// }
|
||||
//
|
||||
// we construct vertices representing types A, B, and T. Because of
|
||||
// declaration "type T int", we construct edges T<-A and T<-B with
|
||||
// weight 1; and because of instantiation "f[T, map[A]B]" we construct
|
||||
// edges A<-T with weight 0, and B<-A and B<-B with weight 1.
|
||||
//
|
||||
// Finally, we look for any positive-weight cycles. Zero-weight cycles
|
||||
// are allowed because static instantiation will reach a fixed point.
|
||||
|
||||
type monoGraph struct {
|
||||
vertices []monoVertex
|
||||
edges []monoEdge
|
||||
|
||||
// canon maps method receiver type parameters to their respective
|
||||
// receiver type's type parameters.
|
||||
canon map[*TypeParam]*TypeParam
|
||||
|
||||
// nameIdx maps a defined type or (canonical) type parameter to its
|
||||
// vertex index.
|
||||
nameIdx map[*TypeName]int
|
||||
}
|
||||
|
||||
type monoVertex struct {
|
||||
weight int // weight of heaviest known path to this vertex
|
||||
pre int // previous edge (if any) in the above path
|
||||
len int // length of the above path
|
||||
|
||||
// obj is the defined type or type parameter represented by this
|
||||
// vertex.
|
||||
obj *TypeName
|
||||
}
|
||||
|
||||
type monoEdge struct {
|
||||
dst, src int
|
||||
weight int
|
||||
|
||||
pos syntax.Pos
|
||||
typ Type
|
||||
}
|
||||
|
||||
func (check *Checker) monomorph() {
|
||||
// We detect unbounded instantiation cycles using a variant of
|
||||
// Bellman-Ford's algorithm. Namely, instead of always running |V|
|
||||
// iterations, we run until we either reach a fixed point or we've
|
||||
// found a path of length |V|. This allows us to terminate earlier
|
||||
// when there are no cycles, which should be the common case.
|
||||
|
||||
again := true
|
||||
for again {
|
||||
again = false
|
||||
|
||||
for i, edge := range check.mono.edges {
|
||||
src := &check.mono.vertices[edge.src]
|
||||
dst := &check.mono.vertices[edge.dst]
|
||||
|
||||
// N.B., we're looking for the greatest weight paths, unlike
|
||||
// typical Bellman-Ford.
|
||||
w := src.weight + edge.weight
|
||||
if w <= dst.weight {
|
||||
continue
|
||||
}
|
||||
|
||||
dst.pre = i
|
||||
dst.len = src.len + 1
|
||||
if dst.len == len(check.mono.vertices) {
|
||||
check.reportInstanceLoop(edge.dst)
|
||||
return
|
||||
}
|
||||
|
||||
dst.weight = w
|
||||
again = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (check *Checker) reportInstanceLoop(v int) {
|
||||
var stack []int
|
||||
seen := make([]bool, len(check.mono.vertices))
|
||||
|
||||
// We have a path that contains a cycle and ends at v, but v may
|
||||
// only be reachable from the cycle, not on the cycle itself. We
|
||||
// start by walking backwards along the path until we find a vertex
|
||||
// that appears twice.
|
||||
for !seen[v] {
|
||||
stack = append(stack, v)
|
||||
seen[v] = true
|
||||
v = check.mono.edges[check.mono.vertices[v].pre].src
|
||||
}
|
||||
|
||||
// Trim any vertices we visited before visiting v the first
|
||||
// time. Since v is the first vertex we found within the cycle, any
|
||||
// vertices we visited earlier cannot be part of the cycle.
|
||||
for stack[0] != v {
|
||||
stack = stack[1:]
|
||||
}
|
||||
|
||||
// TODO(mdempsky): Pivot stack so we report the cycle from the top?
|
||||
|
||||
var err error_
|
||||
obj0 := check.mono.vertices[v].obj
|
||||
err.errorf(obj0, "instantiation cycle:")
|
||||
|
||||
qf := RelativeTo(check.pkg)
|
||||
for _, v := range stack {
|
||||
edge := check.mono.edges[check.mono.vertices[v].pre]
|
||||
obj := check.mono.vertices[edge.dst].obj
|
||||
|
||||
switch obj.Type().(type) {
|
||||
default:
|
||||
panic("unexpected type")
|
||||
case *Named:
|
||||
err.errorf(edge.pos, "%s implicitly parameterized by %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
|
||||
case *TypeParam:
|
||||
err.errorf(edge.pos, "%s instantiated as %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
|
||||
}
|
||||
}
|
||||
check.report(&err)
|
||||
}
|
||||
|
||||
// recordCanon records that tpar is the canonical type parameter
|
||||
// corresponding to method type parameter mpar.
|
||||
func (w *monoGraph) recordCanon(mpar, tpar *TypeParam) {
|
||||
if w.canon == nil {
|
||||
w.canon = make(map[*TypeParam]*TypeParam)
|
||||
}
|
||||
w.canon[mpar] = tpar
|
||||
}
|
||||
|
||||
// recordInstance records that the given type parameters were
|
||||
// instantiated with the corresponding type arguments.
|
||||
func (w *monoGraph) recordInstance(pkg *Package, pos syntax.Pos, tparams []*TypeParam, targs []Type, posList []syntax.Pos) {
|
||||
for i, tpar := range tparams {
|
||||
pos := pos
|
||||
if i < len(posList) {
|
||||
pos = posList[i]
|
||||
}
|
||||
w.assign(pkg, pos, tpar, targs[i])
|
||||
}
|
||||
}
|
||||
|
||||
// assign records that tpar was instantiated as targ at pos.
|
||||
func (w *monoGraph) assign(pkg *Package, pos syntax.Pos, tpar *TypeParam, targ Type) {
|
||||
// Go generics do not have an analog to C++`s template-templates,
|
||||
// where a template parameter can itself be an instantiable
|
||||
// template. So any instantiation cycles must occur within a single
|
||||
// package. Accordingly, we can ignore instantiations of imported
|
||||
// type parameters.
|
||||
//
|
||||
// TODO(mdempsky): Push this check up into recordInstance? All type
|
||||
// parameters in a list will appear in the same package.
|
||||
if tpar.Obj().Pkg() != pkg {
|
||||
return
|
||||
}
|
||||
|
||||
// flow adds an edge from vertex src representing that typ flows to tpar.
|
||||
flow := func(src int, typ Type) {
|
||||
weight := 1
|
||||
if typ == targ {
|
||||
weight = 0
|
||||
}
|
||||
|
||||
w.addEdge(w.typeParamVertex(tpar), src, weight, pos, targ)
|
||||
}
|
||||
|
||||
// Recursively walk the type argument to find any defined types or
|
||||
// type parameters.
|
||||
var do func(typ Type)
|
||||
do = func(typ Type) {
|
||||
switch typ := typ.(type) {
|
||||
default:
|
||||
panic("unexpected type")
|
||||
|
||||
case *TypeParam:
|
||||
assert(typ.Obj().Pkg() == pkg)
|
||||
flow(w.typeParamVertex(typ), typ)
|
||||
|
||||
case *Named:
|
||||
if src := w.localNamedVertex(pkg, typ.Origin()); src >= 0 {
|
||||
flow(src, typ)
|
||||
}
|
||||
|
||||
targs := typ.TypeArgs()
|
||||
for i := 0; i < targs.Len(); i++ {
|
||||
do(targs.At(i))
|
||||
}
|
||||
|
||||
case *Array:
|
||||
do(typ.Elem())
|
||||
case *Basic:
|
||||
// ok
|
||||
case *Chan:
|
||||
do(typ.Elem())
|
||||
case *Map:
|
||||
do(typ.Key())
|
||||
do(typ.Elem())
|
||||
case *Pointer:
|
||||
do(typ.Elem())
|
||||
case *Slice:
|
||||
do(typ.Elem())
|
||||
|
||||
case *Interface:
|
||||
for i := 0; i < typ.NumMethods(); i++ {
|
||||
do(typ.Method(i).Type())
|
||||
}
|
||||
case *Signature:
|
||||
tuple := func(tup *Tuple) {
|
||||
for i := 0; i < tup.Len(); i++ {
|
||||
do(tup.At(i).Type())
|
||||
}
|
||||
}
|
||||
tuple(typ.Params())
|
||||
tuple(typ.Results())
|
||||
case *Struct:
|
||||
for i := 0; i < typ.NumFields(); i++ {
|
||||
do(typ.Field(i).Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
do(targ)
|
||||
}
|
||||
|
||||
// localNamedVertex returns the index of the vertex representing
|
||||
// named, or -1 if named doesn't need representation.
|
||||
func (w *monoGraph) localNamedVertex(pkg *Package, named *Named) int {
|
||||
obj := named.Obj()
|
||||
if obj.Pkg() != pkg {
|
||||
return -1 // imported type
|
||||
}
|
||||
|
||||
root := pkg.Scope()
|
||||
if obj.Parent() == root {
|
||||
return -1 // package scope, no ambient type parameters
|
||||
}
|
||||
|
||||
if idx, ok := w.nameIdx[obj]; ok {
|
||||
return idx
|
||||
}
|
||||
|
||||
idx := -1
|
||||
|
||||
// Walk the type definition's scope to find any ambient type
|
||||
// parameters that it's implicitly parameterized by.
|
||||
for scope := obj.Parent(); scope != root; scope = scope.Parent() {
|
||||
for _, elem := range scope.elems {
|
||||
if elem, ok := elem.(*TypeName); ok && !elem.IsAlias() && elem.Pos().Cmp(obj.Pos()) < 0 {
|
||||
if tpar, ok := elem.Type().(*TypeParam); ok {
|
||||
if idx < 0 {
|
||||
idx = len(w.vertices)
|
||||
w.vertices = append(w.vertices, monoVertex{obj: obj})
|
||||
}
|
||||
|
||||
w.addEdge(idx, w.typeParamVertex(tpar), 1, obj.Pos(), tpar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if w.nameIdx == nil {
|
||||
w.nameIdx = make(map[*TypeName]int)
|
||||
}
|
||||
w.nameIdx[obj] = idx
|
||||
return idx
|
||||
}
|
||||
|
||||
// typeParamVertex returns the index of the vertex representing tpar.
|
||||
func (w *monoGraph) typeParamVertex(tpar *TypeParam) int {
|
||||
if x, ok := w.canon[tpar]; ok {
|
||||
tpar = x
|
||||
}
|
||||
|
||||
obj := tpar.Obj()
|
||||
|
||||
if idx, ok := w.nameIdx[obj]; ok {
|
||||
return idx
|
||||
}
|
||||
|
||||
if w.nameIdx == nil {
|
||||
w.nameIdx = make(map[*TypeName]int)
|
||||
}
|
||||
|
||||
idx := len(w.vertices)
|
||||
w.vertices = append(w.vertices, monoVertex{obj: obj})
|
||||
w.nameIdx[obj] = idx
|
||||
return idx
|
||||
}
|
||||
|
||||
func (w *monoGraph) addEdge(dst, src, weight int, pos syntax.Pos, typ Type) {
|
||||
// TODO(mdempsky): Deduplicate redundant edges?
|
||||
w.edges = append(w.edges, monoEdge{
|
||||
dst: dst,
|
||||
src: src,
|
||||
weight: weight,
|
||||
|
||||
pos: pos,
|
||||
typ: typ,
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package types2_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/compile/internal/syntax"
|
||||
"cmd/compile/internal/types2"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func checkMono(t *testing.T, body string) error {
|
||||
src := "package x; import `unsafe`; var _ unsafe.Pointer;\n" + body
|
||||
file, err := syntax.Parse(syntax.NewFileBase("x.go"), strings.NewReader(src), nil, nil, syntax.AllowGenerics)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
files := []*syntax.File{file}
|
||||
|
||||
var buf bytes.Buffer
|
||||
conf := types2.Config{
|
||||
Error: func(err error) { fmt.Fprintln(&buf, err) },
|
||||
Importer: defaultImporter(),
|
||||
}
|
||||
conf.Check("x", files, nil)
|
||||
if buf.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return errors.New(strings.TrimRight(buf.String(), "\n"))
|
||||
}
|
||||
|
||||
func TestMonoGood(t *testing.T) {
|
||||
for i, good := range goods {
|
||||
if err := checkMono(t, good); err != nil {
|
||||
t.Errorf("%d: unexpected failure: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonoBad(t *testing.T) {
|
||||
for i, bad := range bads {
|
||||
if err := checkMono(t, bad); err == nil {
|
||||
t.Errorf("%d: unexpected success", i)
|
||||
} else {
|
||||
t.Log(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var goods = []string{
|
||||
"func F[T any](x T) { F(x) }",
|
||||
"func F[T, U, V any]() { F[U, V, T](); F[V, T, U]() }",
|
||||
"type Ring[A, B, C any] struct { L *Ring[B, C, A]; R *Ring[C, A, B] }",
|
||||
"func F[T any]() { type U[T any] [unsafe.Sizeof(F[*T])]byte }",
|
||||
"func F[T any]() { type U[T any] [unsafe.Sizeof(F[*T])]byte; var _ U[int] }",
|
||||
"type U[T any] [unsafe.Sizeof(F[*T])]byte; func F[T any]() { var _ U[U[int]] }",
|
||||
"func F[T any]() { type A = int; F[A]() }",
|
||||
}
|
||||
|
||||
// TODO(mdempsky): Validate specific error messages and positioning.
|
||||
|
||||
var bads = []string{
|
||||
"func F[T any](x T) { F(&x) }",
|
||||
"func F[T any]() { F[*T]() }",
|
||||
"func F[T any]() { F[[]T]() }",
|
||||
"func F[T any]() { F[[1]T]() }",
|
||||
"func F[T any]() { F[chan T]() }",
|
||||
"func F[T any]() { F[map[*T]int]() }",
|
||||
"func F[T any]() { F[map[error]T]() }",
|
||||
"func F[T any]() { F[func(T)]() }",
|
||||
"func F[T any]() { F[func() T]() }",
|
||||
"func F[T any]() { F[struct{ t T }]() }",
|
||||
"func F[T any]() { F[interface{ t() T }]() }",
|
||||
"type U[_ any] int; func F[T any]() { F[U[T]]() }",
|
||||
"func F[T any]() { type U int; F[U]() }",
|
||||
"func F[T any]() { type U int; F[*U]() }",
|
||||
"type U[T any] int; func (U[T]) m() { var _ U[*T] }",
|
||||
"type U[T any] int; func (*U[T]) m() { var _ U[*T] }",
|
||||
"type U[T1 any] [unsafe.Sizeof(F[*T1])]byte; func F[T2 any]() { var _ U[T2] }",
|
||||
"func F[A, B, C, D, E any]() { F[B, C, D, E, *A]() }",
|
||||
"type U[_ any] int; const X = unsafe.Sizeof(func() { type A[T any] U[A[*T]] })",
|
||||
"func F[T any]() { type A = *T; F[A]() }",
|
||||
"type A[T any] struct { _ A[*T] }",
|
||||
}
|
||||
|
|
@ -315,6 +315,8 @@ func (obj *TypeName) IsAlias() bool {
|
|||
return obj.pkg != nil || t.name != obj.name || t == universeByte || t == universeRune
|
||||
case *Named:
|
||||
return obj != t.obj
|
||||
case *TypeParam:
|
||||
return obj != t.obj
|
||||
default:
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ func TestIsAlias(t *testing.T) {
|
|||
pkg := NewPackage("p", "p")
|
||||
t1 := NewTypeName(nopos, pkg, "t1", nil)
|
||||
n1 := NewNamed(t1, new(Struct), nil)
|
||||
t5 := NewTypeName(nopos, pkg, "t5", nil)
|
||||
NewTypeParam(t5, nil)
|
||||
for _, test := range []struct {
|
||||
name *TypeName
|
||||
alias bool
|
||||
|
|
@ -46,6 +48,7 @@ func TestIsAlias(t *testing.T) {
|
|||
{NewTypeName(nopos, nil, "int32", Typ[Int32]), false}, // type name refers to basic type with same name
|
||||
{NewTypeName(nopos, pkg, "int32", Typ[Int32]), true}, // type name is declared in user-defined package (outside Universe)
|
||||
{NewTypeName(nopos, nil, "rune", Typ[Rune]), true}, // type name refers to basic type rune which is an alias already
|
||||
{t5, false}, // type name refers to type parameter and vice versa
|
||||
} {
|
||||
check(test.name, test.alias)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,19 +317,11 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
|||
}
|
||||
}
|
||||
|
||||
// common case: if we don't have type parameters, we're done
|
||||
// optimization: if we don't have type parameters, we're done
|
||||
if Vp == nil && Tp == nil {
|
||||
return false, _IncompatibleAssign
|
||||
}
|
||||
|
||||
// determine type parameter operands with specific type terms
|
||||
if Vp != nil && !Vp.hasTerms() {
|
||||
Vp = nil
|
||||
}
|
||||
if Tp != nil && !Tp.hasTerms() {
|
||||
Tp = nil
|
||||
}
|
||||
|
||||
errorf := func(format string, args ...interface{}) {
|
||||
if check != nil && reason != nil {
|
||||
msg := check.sprintf(format, args...)
|
||||
|
|
@ -340,25 +332,36 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
|||
}
|
||||
}
|
||||
|
||||
ok := false
|
||||
code := _IncompatibleAssign
|
||||
switch {
|
||||
case Vp != nil && Tp != nil:
|
||||
x := *x // don't clobber outer x
|
||||
ok = Vp.is(func(V *term) bool {
|
||||
x.typ = V.typ
|
||||
return Tp.is(func(T *term) bool {
|
||||
ok, code = x.assignableTo(check, T.typ, reason)
|
||||
if !ok {
|
||||
errorf("cannot assign %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
// x's type V is not a named type and T is a type parameter, and
|
||||
// x is assignable to each specific type in T's type set.
|
||||
if !hasName(V) && Tp != nil {
|
||||
ok := false
|
||||
code := _IncompatibleAssign
|
||||
Tp.is(func(T *term) bool {
|
||||
if T == nil {
|
||||
return false // no specific types
|
||||
}
|
||||
ok, code = x.assignableTo(check, T.typ, reason)
|
||||
if !ok {
|
||||
errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
case Vp != nil:
|
||||
return ok, code
|
||||
}
|
||||
|
||||
// x's type V is a type parameter and T is not a named type,
|
||||
// and values x' of each specific type in V's type set are
|
||||
// assignable to T.
|
||||
if Vp != nil && !hasName(T) {
|
||||
x := *x // don't clobber outer x
|
||||
ok = Vp.is(func(V *term) bool {
|
||||
ok := false
|
||||
code := _IncompatibleAssign
|
||||
Vp.is(func(V *term) bool {
|
||||
if V == nil {
|
||||
return false // no specific types
|
||||
}
|
||||
x.typ = V.typ
|
||||
ok, code = x.assignableTo(check, T, reason)
|
||||
if !ok {
|
||||
|
|
@ -367,19 +370,10 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
|||
}
|
||||
return true
|
||||
})
|
||||
case Tp != nil:
|
||||
x := *x // don't clobber outer x
|
||||
ok = Tp.is(func(T *term) bool {
|
||||
ok, code = x.assignableTo(check, T.typ, reason)
|
||||
if !ok {
|
||||
errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return ok, code
|
||||
}
|
||||
|
||||
return ok, code
|
||||
return false, _IncompatibleAssign
|
||||
}
|
||||
|
||||
// kind2tok translates syntax.LitKinds into token.Tokens.
|
||||
|
|
|
|||
|
|
@ -6,78 +6,100 @@
|
|||
|
||||
package types2
|
||||
|
||||
// hasName reports whether typ has a name. This includes
|
||||
// The isX predicates below report whether t is an X.
|
||||
// If t is a type parameter the result is false; i.e.,
|
||||
// these predicates don't look inside a type parameter.
|
||||
|
||||
func isBoolean(t Type) bool { return isBasic(t, IsBoolean) }
|
||||
func isInteger(t Type) bool { return isBasic(t, IsInteger) }
|
||||
func isUnsigned(t Type) bool { return isBasic(t, IsUnsigned) }
|
||||
func isFloat(t Type) bool { return isBasic(t, IsFloat) }
|
||||
func isComplex(t Type) bool { return isBasic(t, IsComplex) }
|
||||
func isNumeric(t Type) bool { return isBasic(t, IsNumeric) }
|
||||
func isString(t Type) bool { return isBasic(t, IsString) }
|
||||
func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) }
|
||||
func isConstType(t Type) bool { return isBasic(t, IsConstType) }
|
||||
|
||||
// isBasic reports whether under(t) is a basic type with the specified info.
|
||||
// If t is a type parameter the result is false; i.e.,
|
||||
// isBasic does not look inside a type parameter.
|
||||
func isBasic(t Type, info BasicInfo) bool {
|
||||
u, _ := under(t).(*Basic)
|
||||
return u != nil && u.info&info != 0
|
||||
}
|
||||
|
||||
// The allX predicates below report whether t is an X.
|
||||
// If t is a type parameter the result is true if isX is true
|
||||
// for all specified types of the type parameter's type set.
|
||||
// allX is an optimized version of isX(structure(t)) (which
|
||||
// is the same as underIs(t, isX)).
|
||||
|
||||
func allBoolean(t Type) bool { return allBasic(t, IsBoolean) }
|
||||
func allInteger(t Type) bool { return allBasic(t, IsInteger) }
|
||||
func allUnsigned(t Type) bool { return allBasic(t, IsUnsigned) }
|
||||
func allNumeric(t Type) bool { return allBasic(t, IsNumeric) }
|
||||
func allString(t Type) bool { return allBasic(t, IsString) }
|
||||
func allOrdered(t Type) bool { return allBasic(t, IsOrdered) }
|
||||
func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) }
|
||||
|
||||
// allBasic reports whether under(t) is a basic type with the specified info.
|
||||
// If t is a type parameter, the result is true if isBasic(t, info) is true
|
||||
// for all specific types of the type parameter's type set.
|
||||
// allBasic(t, info) is an optimized version of isBasic(structure(t), info).
|
||||
func allBasic(t Type, info BasicInfo) bool {
|
||||
switch u := under(t).(type) {
|
||||
case *Basic:
|
||||
return u.info&info != 0
|
||||
case *TypeParam:
|
||||
return u.is(func(t *term) bool { return t != nil && isBasic(t.typ, info) })
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasName reports whether t has a name. This includes
|
||||
// predeclared types, defined types, and type parameters.
|
||||
// hasName may be called with types that are not fully set up.
|
||||
func hasName(typ Type) bool {
|
||||
switch typ.(type) {
|
||||
func hasName(t Type) bool {
|
||||
switch t.(type) {
|
||||
case *Basic, *Named, *TypeParam:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isGeneric reports whether a type is a generic, uninstantiated type (generic
|
||||
// signatures are not included).
|
||||
func isGeneric(typ Type) bool {
|
||||
// A parameterized type is only instantiated if it doesn't have an instantiation already.
|
||||
named, _ := typ.(*Named)
|
||||
return named != nil && named.obj != nil && named.targs == nil && named.TypeParams() != nil
|
||||
}
|
||||
|
||||
func is(typ Type, what BasicInfo) bool {
|
||||
switch t := under(typ).(type) {
|
||||
case *Basic:
|
||||
return t.info&what != 0
|
||||
case *TypeParam:
|
||||
return t.underIs(func(t Type) bool { return is(t, what) })
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isBoolean(typ Type) bool { return is(typ, IsBoolean) }
|
||||
func isInteger(typ Type) bool { return is(typ, IsInteger) }
|
||||
func isUnsigned(typ Type) bool { return is(typ, IsUnsigned) }
|
||||
func isFloat(typ Type) bool { return is(typ, IsFloat) }
|
||||
func isComplex(typ Type) bool { return is(typ, IsComplex) }
|
||||
func isNumeric(typ Type) bool { return is(typ, IsNumeric) }
|
||||
func isString(typ Type) bool { return is(typ, IsString) }
|
||||
|
||||
// Note that if typ is a type parameter, isInteger(typ) || isFloat(typ) does not
|
||||
// produce the expected result because a type set that contains both an integer
|
||||
// and a floating-point type is neither (all) integers, nor (all) floats.
|
||||
// Use isIntegerOrFloat instead.
|
||||
func isIntegerOrFloat(typ Type) bool { return is(typ, IsInteger|IsFloat) }
|
||||
|
||||
// isNumericOrString is the equivalent of isIntegerOrFloat for isNumeric(typ) || isString(typ).
|
||||
func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) }
|
||||
|
||||
// isTyped reports whether typ is typed; i.e., not an untyped
|
||||
// isTyped reports whether t is typed; i.e., not an untyped
|
||||
// constant or boolean. isTyped may be called with types that
|
||||
// are not fully set up.
|
||||
func isTyped(typ Type) bool {
|
||||
func isTyped(t Type) bool {
|
||||
// isTyped is called with types that are not fully
|
||||
// set up. Must not call asBasic()!
|
||||
t, _ := typ.(*Basic)
|
||||
return t == nil || t.info&IsUntyped == 0
|
||||
b, _ := t.(*Basic)
|
||||
return b == nil || b.info&IsUntyped == 0
|
||||
}
|
||||
|
||||
// isUntyped(typ) is the same as !isTyped(typ).
|
||||
func isUntyped(typ Type) bool {
|
||||
return !isTyped(typ)
|
||||
// isUntyped(t) is the same as !isTyped(t).
|
||||
func isUntyped(t Type) bool {
|
||||
return !isTyped(t)
|
||||
}
|
||||
|
||||
func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
|
||||
|
||||
func isConstType(typ Type) bool {
|
||||
// Type parameters are never const types.
|
||||
t := asBasic(typ)
|
||||
return t != nil && t.info&IsConstType != 0
|
||||
// IsInterface reports whether t is an interface type.
|
||||
func IsInterface(t Type) bool {
|
||||
return asInterface(t) != nil
|
||||
}
|
||||
|
||||
// IsInterface reports whether typ is an interface type.
|
||||
func IsInterface(typ Type) bool {
|
||||
return asInterface(typ) != nil
|
||||
// isTypeParam reports whether t is a type parameter.
|
||||
func isTypeParam(t Type) bool {
|
||||
_, ok := under(t).(*TypeParam)
|
||||
return ok
|
||||
}
|
||||
|
||||
// isGeneric reports whether a type is a generic, uninstantiated type
|
||||
// (generic signatures are not included).
|
||||
// TODO(gri) should we include signatures or assert that they are not present?
|
||||
func isGeneric(t Type) bool {
|
||||
// A parameterized type is only generic if it doesn't have an instantiation already.
|
||||
named, _ := t.(*Named)
|
||||
return named != nil && named.obj != nil && named.targs == nil && named.TypeParams() != nil
|
||||
}
|
||||
|
||||
// Comparable reports whether values of type T are comparable.
|
||||
|
|
@ -116,15 +138,15 @@ func comparable(T Type, seen map[Type]bool) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// hasNil reports whether a type includes the nil value.
|
||||
func hasNil(typ Type) bool {
|
||||
switch t := under(typ).(type) {
|
||||
// hasNil reports whether type t includes the nil value.
|
||||
func hasNil(t Type) bool {
|
||||
switch u := under(t).(type) {
|
||||
case *Basic:
|
||||
return t.kind == UnsafePointer
|
||||
return u.kind == UnsafePointer
|
||||
case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
|
||||
return true
|
||||
case *TypeParam:
|
||||
return t.underIs(hasNil)
|
||||
return u.underIs(hasNil)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -366,9 +388,8 @@ func identicalTParams(x, y []*TypeParam, cmpTags bool, p *ifacePair) bool {
|
|||
// Default returns the default "typed" type for an "untyped" type;
|
||||
// it returns the incoming type for all other types. The default type
|
||||
// for untyped nil is untyped nil.
|
||||
//
|
||||
func Default(typ Type) Type {
|
||||
if t, ok := typ.(*Basic); ok {
|
||||
func Default(t Type) Type {
|
||||
if t, ok := t.(*Basic); ok {
|
||||
switch t.kind {
|
||||
case UntypedBool:
|
||||
return Typ[Bool]
|
||||
|
|
@ -384,5 +405,5 @@ func Default(typ Type) Type {
|
|||
return Typ[String]
|
||||
}
|
||||
}
|
||||
return typ
|
||||
return t
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
|||
list := make([]Type, sig.RecvTypeParams().Len())
|
||||
for i, t := range sig.RecvTypeParams().list() {
|
||||
list[i] = t
|
||||
check.mono.recordCanon(t, recvTParams[i])
|
||||
}
|
||||
smap := makeSubstMap(recvTParams, list)
|
||||
for i, tpar := range sig.RecvTypeParams().list() {
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
|
|||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
if !isNumeric(x.typ) {
|
||||
if !allNumeric(x.typ) {
|
||||
check.errorf(lhs[0], invalidOp+"%s%s%s (non-numeric type %s)", lhs[0], s.Op, s.Op, x.typ)
|
||||
return
|
||||
}
|
||||
|
|
@ -556,7 +556,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
|
|||
check.simpleStmt(s.Init)
|
||||
var x operand
|
||||
check.expr(&x, s.Cond)
|
||||
if x.mode != invalid && !isBoolean(x.typ) {
|
||||
if x.mode != invalid && !allBoolean(x.typ) {
|
||||
check.error(s.Cond, "non-boolean condition in if statement")
|
||||
}
|
||||
check.stmt(inner, s.Then)
|
||||
|
|
@ -645,7 +645,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
|
|||
if s.Cond != nil {
|
||||
var x operand
|
||||
check.expr(&x, s.Cond)
|
||||
if x.mode != invalid && !isBoolean(x.typ) {
|
||||
if x.mode != invalid && !allBoolean(x.typ) {
|
||||
check.error(s.Cond, "non-boolean condition in for statement")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,14 @@ func _[T interface{ [10]int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERR
|
|||
func _[T interface{ [10]byte | string }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] }
|
||||
func _[T interface{ [10]int | *[20]int | []int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] }
|
||||
|
||||
// indexing with strings and non-variable arrays (assignment not permitted)
|
||||
func _[T string](x T) { _ = x[0]; x /* ERROR cannot assign */ [0] = 0 }
|
||||
func _[T []byte | string](x T) { x /* ERROR cannot assign */ [0] = 0 }
|
||||
func _[T [10]byte]() { f := func() (x T) { return }; f /* ERROR cannot assign */ ()[0] = 0 }
|
||||
func _[T [10]byte]() { f := func() (x *T) { return }; f /* ERROR cannot index */ ()[0] = 0 }
|
||||
func _[T [10]byte]() { f := func() (x *T) { return }; (*f())[0] = 0 }
|
||||
func _[T *[10]byte]() { f := func() (x T) { return }; f()[0] = 0 }
|
||||
|
||||
// slicing
|
||||
|
||||
func _[T interface{ ~[10]E }, E any] (x T, i, j, k int) { var _ []E = x[i:j] }
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
package issue45985
|
||||
|
||||
// TODO(gri): this error should be on app[int] below.
|
||||
func app[S /* ERROR "type S = S does not match" */ interface{ ~[]T }, T any](s S, e T) S {
|
||||
func app[S /* ERROR "S does not match" */ interface{ ~[]T }, T any](s S, e T) S {
|
||||
return append(s, e)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
type Box[A any] struct {
|
||||
value A
|
||||
}
|
||||
|
||||
func Nest[A /* ERROR instantiation cycle */ any](b Box[A], n int) interface{} {
|
||||
if n == 0 {
|
||||
return b
|
||||
}
|
||||
return Nest(Box[Box[A]]{b}, n-1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
Nest(Box[int]{0}, 10)
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ type Fooer interface {
|
|||
Foo()
|
||||
}
|
||||
|
||||
type Fooable[F Fooer] struct {
|
||||
type Fooable[F /* ERROR instantiation cycle */ Fooer] struct {
|
||||
ptr F
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
func _[P int](x P) int {
|
||||
return x // ERROR cannot use x .* as int value in return statement
|
||||
}
|
||||
|
||||
func _[P int]() int {
|
||||
return P /* ERROR cannot use P\(1\) .* as int value in return statement */ (1)
|
||||
}
|
||||
|
||||
func _[P int](x int) P {
|
||||
return x // ERROR cannot use x .* as P value in return statement
|
||||
}
|
||||
|
||||
func _[P, Q any](x P) Q {
|
||||
return x // ERROR cannot use x .* as Q value in return statement
|
||||
}
|
||||
|
||||
// test case from issue
|
||||
func F[G interface{ uint }]() int {
|
||||
f := func(uint) int { return 0 }
|
||||
return f(G /* ERROR cannot use G\(1\) .* as uint value in argument to f */ (1))
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type integer interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 |
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
func Add1024[T integer](s []T) {
|
||||
for i, v := range s {
|
||||
s[i] = v + 1024 // ERROR cannot convert 1024 \(untyped int constant\) to T
|
||||
}
|
||||
}
|
||||
|
||||
func f[T interface{ int8 }]() {
|
||||
println(T(1024 /* ERROR cannot convert 1024 \(untyped int value\) to T */))
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
func _[
|
||||
T0 any,
|
||||
T1 []int,
|
||||
T2 ~float64 | ~complex128 | chan int,
|
||||
]() {
|
||||
_ = T0(nil /* ERROR cannot convert untyped nil to T0 */ )
|
||||
_ = T1(1 /* ERROR cannot convert 1 .* to T1 */ )
|
||||
_ = T2(2 /* ERROR cannot convert 2 .* to T2 */ )
|
||||
}
|
||||
|
||||
// test case from issue
|
||||
func f[T interface{[]int}]() {
|
||||
_ = T(1 /* ERROR cannot convert */ )
|
||||
}
|
||||
|
|
@ -109,20 +109,48 @@ func _[
|
|||
)
|
||||
|
||||
var (
|
||||
_ _CC = C
|
||||
_ _SC = C
|
||||
_ _RC = C
|
||||
_ _CC = C // ERROR cannot use C .* as _CC value
|
||||
_ _SC = C // ERROR cannot use C .* as _SC value
|
||||
_ _RC = C // ERROR cannot use C .* as _RC value
|
||||
|
||||
_ CC = _CC(nil)
|
||||
_ SC = _CC(nil)
|
||||
_ RC = _CC(nil)
|
||||
_ CC = _CC /* ERROR cannot use _CC\(nil\) .* as CC value */ (nil)
|
||||
_ SC = _CC /* ERROR cannot use _CC\(nil\) .* as SC value */ (nil)
|
||||
_ RC = _CC /* ERROR cannot use _CC\(nil\) .* as RC value */ (nil)
|
||||
|
||||
_ CC = C
|
||||
_ SC = C // ERROR cannot use C .* as SC value .* cannot assign Chan to SendChan
|
||||
_ RC = C // ERROR cannot use C .* as RC value .* cannot assign Chan to RecvChan
|
||||
_ CC = C // ERROR cannot use C .* as CC value
|
||||
_ SC = C // ERROR cannot use C .* as SC value
|
||||
_ RC = C // ERROR cannot use C .* as RC value
|
||||
)
|
||||
}
|
||||
|
||||
// "x's type V is not a named type and T is a type parameter, and x is assignable to each specific type in T's type set."
|
||||
func _[
|
||||
TP0 any,
|
||||
TP1 ~_Chan,
|
||||
TP2 ~chan int | ~chan byte,
|
||||
]() {
|
||||
var (
|
||||
_ TP0 = c // ERROR cannot use c .* as TP0 value
|
||||
_ TP0 = C // ERROR cannot use C .* as TP0 value
|
||||
_ TP1 = c
|
||||
_ TP1 = C // ERROR cannot use C .* as TP1 value
|
||||
_ TP2 = c // ERROR .* cannot assign chan int to chan byte
|
||||
)
|
||||
}
|
||||
|
||||
// "x's type V is a type parameter and T is not a named type, and values x' of each specific type in V's type set are assignable to T."
|
||||
func _[
|
||||
TP0 Interface,
|
||||
TP1 ~_Chan,
|
||||
TP2 ~chan int | ~chan byte,
|
||||
](X0 TP0, X1 TP1, X2 TP2) {
|
||||
i = X0
|
||||
I = X0
|
||||
c = X1
|
||||
C = X1 // ERROR cannot use X1 .* as Chan value
|
||||
c = X2 // ERROR .* cannot assign chan byte \(in TP2\) to chan int
|
||||
}
|
||||
|
||||
// "x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type"
|
||||
func _[TP Interface](X TP) {
|
||||
b = nil // ERROR cannot use untyped nil
|
||||
|
|
|
|||
|
|
@ -6,6 +6,40 @@ package conversions
|
|||
|
||||
import "unsafe"
|
||||
|
||||
// constant conversions
|
||||
|
||||
func _[T ~byte]() T { return 255 }
|
||||
func _[T ~byte]() T { return 256 /* ERROR cannot use 256 .* as T value */ }
|
||||
|
||||
func _[T ~byte]() {
|
||||
const _ = T /* ERROR T\(0\) .* is not constant */ (0)
|
||||
var _ T = 255
|
||||
var _ T = 256 // ERROR cannot use 256 .* as T value
|
||||
}
|
||||
|
||||
func _[T ~string]() T { return T('a') }
|
||||
func _[T ~int | ~string]() T { return T('a') }
|
||||
func _[T ~byte | ~int | ~string]() T { return T(256 /* ERROR cannot convert 256 .* to T */ ) }
|
||||
|
||||
// implicit conversions never convert to string
|
||||
func _[T ~string]() {
|
||||
var _ string = 0 // ERROR cannot use .* as string value
|
||||
var _ T = 0 // ERROR cannot use .* as T value
|
||||
}
|
||||
|
||||
// failing const conversions of constants to type parameters report a cause
|
||||
func _[
|
||||
T1 any,
|
||||
T2 interface{ m() },
|
||||
T3 ~int | ~float64 | ~bool,
|
||||
T4 ~int | ~string,
|
||||
]() {
|
||||
_ = T1(0 /* ERROR cannot convert 0 .* to T1\n\tT1 does not contain specific types */ )
|
||||
_ = T2(1 /* ERROR cannot convert 1 .* to T2\n\tT2 does not contain specific types */ )
|
||||
_ = T3(2 /* ERROR cannot convert 2 .* to T3\n\tcannot convert 2 .* to bool \(in T3\) */ )
|
||||
_ = T4(3.14 /* ERROR cannot convert 3.14 .* to T4\n\tcannot convert 3.14 .* to int \(in T4\) */ )
|
||||
}
|
||||
|
||||
// "x is assignable to T"
|
||||
// - tested via assignability tests
|
||||
|
||||
|
|
|
|||
|
|
@ -81,10 +81,32 @@ func asTypeParam(t Type) *TypeParam {
|
|||
return u
|
||||
}
|
||||
|
||||
// Exported for the compiler.
|
||||
// Helper functions exported for the compiler.
|
||||
// These functions assume type checking has completed
|
||||
// and Type.Underlying() is returning the fully set up
|
||||
// underlying type. Do not use internally.
|
||||
|
||||
func AsPointer(t Type) *Pointer { return asPointer(t) }
|
||||
func AsNamed(t Type) *Named { return asNamed(t) }
|
||||
func AsSignature(t Type) *Signature { return asSignature(t) }
|
||||
func AsInterface(t Type) *Interface { return asInterface(t) }
|
||||
func AsTypeParam(t Type) *TypeParam { return asTypeParam(t) }
|
||||
func AsPointer(t Type) *Pointer {
|
||||
u, _ := t.Underlying().(*Pointer)
|
||||
return u
|
||||
}
|
||||
|
||||
func AsNamed(t Type) *Named {
|
||||
u, _ := t.(*Named)
|
||||
return u
|
||||
}
|
||||
|
||||
func AsSignature(t Type) *Signature {
|
||||
u, _ := t.Underlying().(*Signature)
|
||||
return u
|
||||
}
|
||||
|
||||
func AsInterface(t Type) *Interface {
|
||||
u, _ := t.Underlying().(*Interface)
|
||||
return u
|
||||
}
|
||||
|
||||
func AsTypeParam(t Type) *TypeParam {
|
||||
u, _ := t.Underlying().(*TypeParam)
|
||||
return u
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,14 @@ func RelativeTo(pkg *Package) Qualifier {
|
|||
// The Qualifier controls the printing of
|
||||
// package-level objects, and may be nil.
|
||||
func TypeString(typ Type, qf Qualifier) string {
|
||||
return typeString(typ, qf, false)
|
||||
}
|
||||
|
||||
func typeString(typ Type, qf Qualifier, debug bool) string {
|
||||
var buf bytes.Buffer
|
||||
WriteType(&buf, typ, qf)
|
||||
w := newTypeWriter(&buf, qf)
|
||||
w.debug = debug
|
||||
w.typ(typ)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
|
|
@ -64,19 +70,20 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
|
|||
}
|
||||
|
||||
type typeWriter struct {
|
||||
buf *bytes.Buffer
|
||||
seen map[Type]bool
|
||||
qf Qualifier
|
||||
ctxt *Context // if non-nil, we are type hashing
|
||||
buf *bytes.Buffer
|
||||
seen map[Type]bool
|
||||
qf Qualifier
|
||||
ctxt *Context // if non-nil, we are type hashing
|
||||
debug bool // if true, write debug annotations
|
||||
}
|
||||
|
||||
func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
|
||||
return &typeWriter{buf, make(map[Type]bool), qf, nil}
|
||||
return &typeWriter{buf, make(map[Type]bool), qf, nil, false}
|
||||
}
|
||||
|
||||
func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
|
||||
assert(ctxt != nil)
|
||||
return &typeWriter{buf, make(map[Type]bool), nil, ctxt}
|
||||
return &typeWriter{buf, make(map[Type]bool), nil, ctxt, false}
|
||||
}
|
||||
|
||||
func (w *typeWriter) byte(b byte) {
|
||||
|
|
@ -266,11 +273,10 @@ func (w *typeWriter) typ(typ Type) {
|
|||
w.error("unnamed type parameter")
|
||||
break
|
||||
}
|
||||
// Optionally write out package for typeparams (like Named).
|
||||
if t.obj.pkg != nil {
|
||||
writePackage(w.buf, t.obj.pkg, w.qf)
|
||||
w.string(t.obj.name)
|
||||
if w.debug || w.ctxt != nil {
|
||||
w.string(subscript(t.id))
|
||||
}
|
||||
w.string(t.obj.name + subscript(t.id))
|
||||
|
||||
default:
|
||||
// For externally defined implementations of Type.
|
||||
|
|
|
|||
|
|
@ -481,6 +481,8 @@ func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def
|
|||
pos = posList[i]
|
||||
}
|
||||
check.softErrorf(pos, err.Error())
|
||||
} else {
|
||||
check.mono.recordInstance(check.pkg, x.Pos(), inst.tparams.list(), inst.targs.list(), posList)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ Finally, to generate modified source code with coverage annotations
|
|||
`
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintln(os.Stderr, usageMessage)
|
||||
fmt.Fprintln(os.Stderr, "Flags:")
|
||||
fmt.Fprint(os.Stderr, usageMessage)
|
||||
fmt.Fprintln(os.Stderr, "\nFlags:")
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprintln(os.Stderr, "\n Only one of -html, -func, or -mode may be set.")
|
||||
os.Exit(2)
|
||||
|
|
|
|||
|
|
@ -1013,7 +1013,7 @@ func (t *tester) internalLink() bool {
|
|||
func (t *tester) internalLinkPIE() bool {
|
||||
switch goos + "-" + goarch {
|
||||
case "darwin-amd64", "darwin-arm64",
|
||||
"linux-amd64", "linux-arm64",
|
||||
"linux-amd64", "linux-arm64", "linux-ppc64le",
|
||||
"android-arm64",
|
||||
"windows-amd64", "windows-386", "windows-arm":
|
||||
return true
|
||||
|
|
@ -1031,7 +1031,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
|
|||
switch pair {
|
||||
case "aix-ppc64",
|
||||
"darwin-amd64", "darwin-arm64", "ios-arm64",
|
||||
"linux-amd64", "linux-386", "linux-ppc64le", "linux-s390x",
|
||||
"linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x",
|
||||
"freebsd-amd64",
|
||||
"windows-amd64", "windows-386":
|
||||
return true
|
||||
|
|
@ -1039,7 +1039,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
|
|||
return false
|
||||
case "c-shared":
|
||||
switch pair {
|
||||
case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x",
|
||||
case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
|
||||
"darwin-amd64", "darwin-arm64",
|
||||
"freebsd-amd64",
|
||||
"android-arm", "android-arm64", "android-386",
|
||||
|
|
|
|||
|
|
@ -323,7 +323,8 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
|
|||
if n.Assign.IsValid() {
|
||||
sep = " = "
|
||||
}
|
||||
return fmt.Sprintf("type %s%s%s", n.Name.Name, sep, pkg.oneLineNodeDepth(n.Type, depth))
|
||||
tparams := pkg.formatTypeParams(n.TypeParams, depth)
|
||||
return fmt.Sprintf("type %s%s%s%s", n.Name.Name, tparams, sep, pkg.oneLineNodeDepth(n.Type, depth))
|
||||
|
||||
case *ast.FuncType:
|
||||
var params []string
|
||||
|
|
@ -342,15 +343,16 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
|
|||
}
|
||||
}
|
||||
|
||||
tparam := pkg.formatTypeParams(n.TypeParams, depth)
|
||||
param := joinStrings(params)
|
||||
if len(results) == 0 {
|
||||
return fmt.Sprintf("func(%s)", param)
|
||||
return fmt.Sprintf("func%s(%s)", tparam, param)
|
||||
}
|
||||
result := joinStrings(results)
|
||||
if !needParens {
|
||||
return fmt.Sprintf("func(%s) %s", param, result)
|
||||
return fmt.Sprintf("func%s(%s) %s", tparam, param, result)
|
||||
}
|
||||
return fmt.Sprintf("func(%s) (%s)", param, result)
|
||||
return fmt.Sprintf("func%s(%s) (%s)", tparam, param, result)
|
||||
|
||||
case *ast.StructType:
|
||||
if n.Fields == nil || len(n.Fields.List) == 0 {
|
||||
|
|
@ -419,6 +421,17 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
|
|||
}
|
||||
}
|
||||
|
||||
func (pkg *Package) formatTypeParams(list *ast.FieldList, depth int) string {
|
||||
if list.NumFields() == 0 {
|
||||
return ""
|
||||
}
|
||||
var tparams []string
|
||||
for _, field := range list.List {
|
||||
tparams = append(tparams, pkg.oneLineField(field, depth))
|
||||
}
|
||||
return "[" + joinStrings(tparams) + "]"
|
||||
}
|
||||
|
||||
// oneLineField returns a one-line summary of the field.
|
||||
func (pkg *Package) oneLineField(field *ast.Field, depth int) string {
|
||||
var names []string
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module cmd
|
|||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/google/pprof v0.0.0-20211001005136-7fe48b4c820b
|
||||
github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31
|
||||
golang.org/x/arch v0.0.0-20210901143047-ebb09ed340f1
|
||||
golang.org/x/mod v0.5.1-0.20210913215816-37dd6891021a
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
|
|
@ -12,8 +12,8 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e // indirect
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/google/pprof v0.0.0-20211001005136-7fe48b4c820b h1:GX4+fGLMW5XTmDXB3R6UhTwZIYqgAOdA19+Ea0+3CU4=
|
||||
github.com/google/pprof v0.0.0-20211001005136-7fe48b4c820b/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31 h1:YvpxjnjGhf/vDEeYOysNbsrtB///PKS8lqkFNSDm1p8=
|
||||
github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d h1:uGg2frlt3IcT7kbV6LEp5ONv4vmoO2FW4qSO+my/aoM=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||
golang.org/x/arch v0.0.0-20210901143047-ebb09ed340f1 h1:MwxAfiDvuwX8Nnnc6iRDhzyMyyc2tz5tYyCP/pZcPCg=
|
||||
golang.org/x/arch v0.0.0-20210901143047-ebb09ed340f1/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||
|
|
@ -13,9 +13,8 @@ golang.org/x/mod v0.5.1-0.20210913215816-37dd6891021a h1:55PVa91KndtPGH2lus5l2gD
|
|||
golang.org/x/mod v0.5.1-0.20210913215816-37dd6891021a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c=
|
||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/tools v0.1.8-0.20211025211149-f916b54a1784 h1:+xP+QoP2SEPgbn+07I/yJTzP+gavj0XKGS6+JU5tlck=
|
||||
|
|
|
|||
|
|
@ -1074,8 +1074,11 @@
|
|||
//
|
||||
// Download downloads the named modules, which can be module patterns selecting
|
||||
// dependencies of the main module or module queries of the form path@version.
|
||||
// With no arguments, download applies to all dependencies of the main module
|
||||
// (equivalent to 'go mod download all').
|
||||
//
|
||||
// With no arguments, download applies to the modules needed to build and test
|
||||
// the packages in the main module: the modules explicitly required by the main
|
||||
// module if it is at 'go 1.17' or higher, or all transitively-required modules
|
||||
// if at 'go 1.16' or lower.
|
||||
//
|
||||
// The go command will automatically download modules as needed during ordinary
|
||||
// execution. The "go mod download" command is useful mainly for pre-filling
|
||||
|
|
@ -2851,11 +2854,11 @@
|
|||
// exhaustive tests.
|
||||
//
|
||||
// -shuffle off,on,N
|
||||
// Randomize the execution order of tests and benchmarks.
|
||||
// It is off by default. If -shuffle is set to on, then it will seed
|
||||
// the randomizer using the system clock. If -shuffle is set to an
|
||||
// integer N, then N will be used as the seed value. In both cases,
|
||||
// the seed will be reported for reproducibility.
|
||||
// Randomize the execution order of tests and benchmarks.
|
||||
// It is off by default. If -shuffle is set to on, then it will seed
|
||||
// the randomizer using the system clock. If -shuffle is set to an
|
||||
// integer N, then N will be used as the seed value. In both cases,
|
||||
// the seed will be reported for reproducibility.
|
||||
//
|
||||
// -timeout d
|
||||
// If a test binary runs longer than duration d, panic.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"internal/godebug"
|
||||
"internal/race"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
|
|
@ -2281,7 +2282,7 @@ func TestUpxCompression(t *testing.T) {
|
|||
|
||||
func TestCacheListStale(t *testing.T) {
|
||||
tooSlow(t)
|
||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
||||
if godebug.Get("gocacheverify") == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
tg := testgo(t)
|
||||
|
|
@ -2304,7 +2305,7 @@ func TestCacheListStale(t *testing.T) {
|
|||
func TestCacheCoverage(t *testing.T) {
|
||||
tooSlow(t)
|
||||
|
||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
||||
if godebug.Get("gocacheverify") == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
|
||||
|
|
@ -2336,7 +2337,7 @@ func TestIssue22588(t *testing.T) {
|
|||
|
||||
func TestIssue22531(t *testing.T) {
|
||||
tooSlow(t)
|
||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
||||
if godebug.Get("gocacheverify") == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
tg := testgo(t)
|
||||
|
|
@ -2365,7 +2366,7 @@ func TestIssue22531(t *testing.T) {
|
|||
|
||||
func TestIssue22596(t *testing.T) {
|
||||
tooSlow(t)
|
||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
||||
if godebug.Get("gocacheverify") == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
tg := testgo(t)
|
||||
|
|
@ -2395,7 +2396,7 @@ func TestIssue22596(t *testing.T) {
|
|||
func TestTestCache(t *testing.T) {
|
||||
tooSlow(t)
|
||||
|
||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
||||
if godebug.Get("gocacheverify") == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
tg := testgo(t)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"cmd/go/internal/modload"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
var cmdDownload = &base.Command{
|
||||
|
|
@ -24,8 +25,11 @@ var cmdDownload = &base.Command{
|
|||
Long: `
|
||||
Download downloads the named modules, which can be module patterns selecting
|
||||
dependencies of the main module or module queries of the form path@version.
|
||||
With no arguments, download applies to all dependencies of the main module
|
||||
(equivalent to 'go mod download all').
|
||||
|
||||
With no arguments, download applies to the modules needed to build and test
|
||||
the packages in the main module: the modules explicitly required by the main
|
||||
module if it is at 'go 1.17' or higher, or all transitively-required modules
|
||||
if at 'go 1.16' or lower.
|
||||
|
||||
The go command will automatically download modules as needed during ordinary
|
||||
execution. The "go mod download" command is useful mainly for pre-filling
|
||||
|
|
@ -87,13 +91,8 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
|||
// Check whether modules are enabled and whether we're in a module.
|
||||
modload.ForceUseModules = true
|
||||
modload.ExplicitWriteGoMod = true
|
||||
if !modload.HasModRoot() && len(args) == 0 {
|
||||
base.Fatalf("go: no modules specified (see 'go help mod download')")
|
||||
}
|
||||
haveExplicitArgs := len(args) > 0
|
||||
if !haveExplicitArgs {
|
||||
args = []string{"all"}
|
||||
}
|
||||
|
||||
if modload.HasModRoot() {
|
||||
modload.LoadModFile(ctx) // to fill MainModules
|
||||
|
||||
|
|
@ -102,16 +101,50 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
|||
}
|
||||
mainModule := modload.MainModules.Versions()[0]
|
||||
|
||||
targetAtUpgrade := mainModule.Path + "@upgrade"
|
||||
targetAtPatch := mainModule.Path + "@patch"
|
||||
for _, arg := range args {
|
||||
switch arg {
|
||||
case mainModule.Path, targetAtUpgrade, targetAtPatch:
|
||||
os.Stderr.WriteString("go: skipping download of " + arg + " that resolves to the main module\n")
|
||||
if haveExplicitArgs {
|
||||
targetAtUpgrade := mainModule.Path + "@upgrade"
|
||||
targetAtPatch := mainModule.Path + "@patch"
|
||||
for _, arg := range args {
|
||||
switch arg {
|
||||
case mainModule.Path, targetAtUpgrade, targetAtPatch:
|
||||
os.Stderr.WriteString("go: skipping download of " + arg + " that resolves to the main module\n")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
modFile := modload.MainModules.ModFile(mainModule)
|
||||
if modFile.Go == nil || semver.Compare("v"+modFile.Go.Version, modload.ExplicitIndirectVersionV) < 0 {
|
||||
if len(modFile.Require) > 0 {
|
||||
args = []string{"all"}
|
||||
}
|
||||
} else {
|
||||
// As of Go 1.17, the go.mod file explicitly requires every module
|
||||
// that provides any package imported by the main module.
|
||||
// 'go mod download' is typically run before testing packages in the
|
||||
// main module, so by default we shouldn't download the others
|
||||
// (which are presumed irrelevant to the packages in the main module).
|
||||
// See https://golang.org/issue/44435.
|
||||
//
|
||||
// However, we also need to load the full module graph, to ensure that
|
||||
// we have downloaded enough of the module graph to run 'go list all',
|
||||
// 'go mod graph', and similar commands.
|
||||
_ = modload.LoadModGraph(ctx, "")
|
||||
|
||||
for _, m := range modFile.Require {
|
||||
args = append(args, m.Mod.Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
if modload.HasModRoot() {
|
||||
os.Stderr.WriteString("go: no module dependencies to download\n")
|
||||
} else {
|
||||
base.Errorf("go: no modules specified (see 'go help mod download')")
|
||||
}
|
||||
base.Exit()
|
||||
}
|
||||
|
||||
downloadModule := func(m *moduleJSON) {
|
||||
var err error
|
||||
m.Info, err = modfetch.InfoFile(m.Path, m.Version)
|
||||
|
|
|
|||
|
|
@ -567,11 +567,11 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
|
|||
if rev != info.Short {
|
||||
switch {
|
||||
case strings.HasPrefix(rev, info.Short):
|
||||
return fmt.Errorf("revision is longer than canonical (%s)", info.Short)
|
||||
return fmt.Errorf("revision is longer than canonical (expected %s)", info.Short)
|
||||
case strings.HasPrefix(info.Short, rev):
|
||||
return fmt.Errorf("revision is shorter than canonical (%s)", info.Short)
|
||||
return fmt.Errorf("revision is shorter than canonical (expected %s)", info.Short)
|
||||
default:
|
||||
return fmt.Errorf("does not match short name of revision (%s)", info.Short)
|
||||
return fmt.Errorf("does not match short name of revision (expected %s)", info.Short)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ func (rs *Requirements) IsDirect(path string) bool {
|
|||
// A ModuleGraph represents the complete graph of module dependencies
|
||||
// of a main module.
|
||||
//
|
||||
// If the main module is lazily loaded, the graph does not include
|
||||
// If the main module supports module graph pruning, the graph does not include
|
||||
// transitive dependencies of non-root (implicit) dependencies.
|
||||
type ModuleGraph struct {
|
||||
g *mvs.Graph
|
||||
|
|
|
|||
|
|
@ -968,7 +968,7 @@ func makeMainModules(ms []module.Version, rootDirs []string, modFiles []*modfile
|
|||
for _, r := range modFiles[i].Replace {
|
||||
if replacedByWorkFile[r.Old.Path] {
|
||||
continue
|
||||
} else if prev, ok := replacements[r.Old]; ok && !curModuleReplaces[r.Old] {
|
||||
} else if prev, ok := replacements[r.Old]; ok && !curModuleReplaces[r.Old] && prev != r.New {
|
||||
base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v\nuse \"go mod editwork -replace %v=[override]\" to resolve", r.Old, prev, r.New, r.Old)
|
||||
}
|
||||
curModuleReplaces[r.Old] = true
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ const (
|
|||
// tests outside of the main module.
|
||||
narrowAllVersionV = "v1.16"
|
||||
|
||||
// explicitIndirectVersionV is the Go version (plus leading "v") at which a
|
||||
// ExplicitIndirectVersionV is the Go version (plus leading "v") at which a
|
||||
// module's go.mod file is expected to list explicit requirements on every
|
||||
// module that provides any package transitively imported by that module.
|
||||
//
|
||||
// Other indirect dependencies of such a module can be safely pruned out of
|
||||
// the module graph; see https://golang.org/ref/mod#graph-pruning.
|
||||
explicitIndirectVersionV = "v1.17"
|
||||
ExplicitIndirectVersionV = "v1.17"
|
||||
|
||||
// separateIndirectVersionV is the Go version (plus leading "v") at which
|
||||
// "// indirect" dependencies are added in a block separate from the direct
|
||||
|
|
@ -123,7 +123,7 @@ const (
|
|||
)
|
||||
|
||||
func pruningForGoVersion(goVersion string) modPruning {
|
||||
if semver.Compare("v"+goVersion, explicitIndirectVersionV) < 0 {
|
||||
if semver.Compare("v"+goVersion, ExplicitIndirectVersionV) < 0 {
|
||||
// The go.mod file does not duplicate relevant information about transitive
|
||||
// dependencies, so they cannot be pruned out.
|
||||
return unpruned
|
||||
|
|
@ -378,7 +378,7 @@ func canonicalizeReplacePath(r module.Version, modRoot string) module.Version {
|
|||
return r
|
||||
}
|
||||
abs := filepath.Join(modRoot, r.Path)
|
||||
if rel, err := filepath.Rel(workFilePath, abs); err == nil {
|
||||
if rel, err := filepath.Rel(filepath.Dir(workFilePath), abs); err == nil {
|
||||
return module.Version{Path: rel, Version: r.Version}
|
||||
}
|
||||
// We couldn't make the version's path relative to the workspace's path,
|
||||
|
|
|
|||
|
|
@ -307,11 +307,11 @@ control the execution of any test:
|
|||
exhaustive tests.
|
||||
|
||||
-shuffle off,on,N
|
||||
Randomize the execution order of tests and benchmarks.
|
||||
It is off by default. If -shuffle is set to on, then it will seed
|
||||
the randomizer using the system clock. If -shuffle is set to an
|
||||
integer N, then N will be used as the seed value. In both cases,
|
||||
the seed will be reported for reproducibility.
|
||||
Randomize the execution order of tests and benchmarks.
|
||||
It is off by default. If -shuffle is set to on, then it will seed
|
||||
the randomizer using the system clock. If -shuffle is set to an
|
||||
integer N, then N will be used as the seed value. In both cases,
|
||||
the seed will be reported for reproducibility.
|
||||
|
||||
-timeout d
|
||||
If a test binary runs longer than duration d, panic.
|
||||
|
|
@ -666,6 +666,12 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
|
|||
if len(pkgs) != 1 {
|
||||
base.Fatalf("cannot use -fuzz flag with multiple packages")
|
||||
}
|
||||
if testCoverProfile != "" {
|
||||
base.Fatalf("cannot use -coverprofile flag with -fuzz flag")
|
||||
}
|
||||
if profileFlag := testProfile(); profileFlag != "" {
|
||||
base.Fatalf("cannot use %s flag with -fuzz flag", profileFlag)
|
||||
}
|
||||
|
||||
// Reject the '-fuzz' flag if the package is outside the main module.
|
||||
// Otherwise, if fuzzing identifies a failure it could corrupt checksums in
|
||||
|
|
@ -1399,15 +1405,25 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
|
|||
if bytes.HasPrefix(out, tooManyTargetsToFuzz[1:]) || bytes.Contains(out, tooManyTargetsToFuzz) {
|
||||
norun = " [will not fuzz, -fuzz matches more than one target]"
|
||||
}
|
||||
if len(out) > 0 && !bytes.HasSuffix(out, []byte("\n")) {
|
||||
// Ensure that the output ends with a newline before the "ok"
|
||||
// line we're about to print (https://golang.org/issue/49317).
|
||||
cmd.Stdout.Write([]byte("\n"))
|
||||
}
|
||||
fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun)
|
||||
c.saveOutput(a)
|
||||
} else {
|
||||
base.SetExitStatus(1)
|
||||
// If there was test output, assume we don't need to print the exit status.
|
||||
// Buf there's no test output, do print the exit status.
|
||||
if len(out) == 0 {
|
||||
// If there was no test output, print the exit status so that the reason
|
||||
// for failure is clear.
|
||||
fmt.Fprintf(cmd.Stdout, "%s\n", err)
|
||||
} else if !bytes.HasSuffix(out, []byte("\n")) {
|
||||
// Otherwise, ensure that the output ends with a newline before the FAIL
|
||||
// line we're about to print (https://golang.org/issue/49317).
|
||||
cmd.Stdout.Write([]byte("\n"))
|
||||
}
|
||||
|
||||
// NOTE(golang.org/issue/37555): test2json reports that a test passes
|
||||
// unless "FAIL" is printed at the beginning of a line. The test may not
|
||||
// actually print that if it panics, exits, or terminates abnormally,
|
||||
|
|
|
|||
|
|
@ -58,8 +58,7 @@ go build -n -ldflags=-X=math.pi=3
|
|||
stderr 'link.* -X=math.pi=3'
|
||||
|
||||
# -ldflags applies to current directory even if GOPATH is funny
|
||||
[windows] cd $WORK/GoPath/src/my/cmd/prog
|
||||
[darwin] cd $WORK/GoPath/src/my/cmd/prog
|
||||
[!case-sensitive] cd $WORK/GoPath/src/my/cmd/prog
|
||||
go build -n -ldflags=-X=math.pi=3
|
||||
stderr 'link.* -X=math.pi=3'
|
||||
|
||||
|
|
|
|||
|
|
@ -128,6 +128,50 @@ rm go.sum
|
|||
go mod download all
|
||||
cmp go.mod.update go.mod
|
||||
grep '^rsc.io/sampler v1.3.0 ' go.sum
|
||||
|
||||
# https://golang.org/issue/44435: At go 1.17 or higher, 'go mod download'
|
||||
# (without arguments) should only download the modules explicitly required in
|
||||
# the go.mod file, not (presumed-irrelevant) transitive dependencies.
|
||||
#
|
||||
# (If the go.mod file is inconsistent, the version downloaded should be the
|
||||
# selected version from the broader graph, but the go.mod file will also be
|
||||
# updated to list the correct versions. If at some point we change 'go mod
|
||||
# download' to stop updating for consistency, then it should fail if the
|
||||
# requirements are inconsistent.)
|
||||
|
||||
rm go.sum
|
||||
cp go.mod.orig go.mod
|
||||
go mod edit -go=1.17
|
||||
cp go.mod.update go.mod.go117
|
||||
go mod edit -go=1.17 go.mod.go117
|
||||
|
||||
go clean -modcache
|
||||
go mod download
|
||||
cmp go.mod go.mod.go117
|
||||
|
||||
go list -e -m all
|
||||
stdout '^rsc.io/quote v1.5.2$'
|
||||
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
|
||||
stdout '^rsc.io/sampler v1.3.0$'
|
||||
! exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.2.1.zip
|
||||
exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.3.0.zip
|
||||
stdout '^golang\.org/x/text v0.0.0-20170915032832-14c0d48ead0c$'
|
||||
! exists $GOPATH/pkg/mod/cache/download/golang.org/x/text/@v/v0.0.0-20170915032832-14c0d48ead0c.zip
|
||||
cmp go.mod go.mod.go117
|
||||
|
||||
# However, 'go mod download all' continues to download the selected version
|
||||
# of every module reported by 'go list -m all'.
|
||||
|
||||
cp go.mod.orig go.mod
|
||||
go mod edit -go=1.17
|
||||
go clean -modcache
|
||||
go mod download all
|
||||
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
|
||||
! exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.2.1.zip
|
||||
exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.3.0.zip
|
||||
exists $GOPATH/pkg/mod/cache/download/golang.org/x/text/@v/v0.0.0-20170915032832-14c0d48ead0c.zip
|
||||
cmp go.mod go.mod.go117
|
||||
|
||||
cd ..
|
||||
|
||||
# allow go mod download without go.mod
|
||||
|
|
|
|||
|
|
@ -57,20 +57,20 @@ cp go.mod.orig go.mod
|
|||
go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0
|
||||
cd outside
|
||||
! go list -m golang.org/x/text
|
||||
stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(14c0d48ead0c\)'
|
||||
stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(expected 14c0d48ead0c\)'
|
||||
cd ..
|
||||
! go list -m golang.org/x/text
|
||||
stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(14c0d48ead0c\)'
|
||||
stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(expected 14c0d48ead0c\)'
|
||||
|
||||
# A pseudo-version with more than 12 digits of SHA-1 prefix is invalid.
|
||||
cp go.mod.orig go.mod
|
||||
go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a
|
||||
cd outside
|
||||
! go list -m golang.org/x/text
|
||||
stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(14c0d48ead0c\)'
|
||||
stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(expected 14c0d48ead0c\)'
|
||||
cd ..
|
||||
! go list -m golang.org/x/text
|
||||
stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(14c0d48ead0c\)'
|
||||
stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(expected 14c0d48ead0c\)'
|
||||
|
||||
# A pseudo-version that does not match the commit timestamp is invalid.
|
||||
cp go.mod.orig go.mod
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
[short] skip
|
||||
|
||||
# In package list mode, output is buffered.
|
||||
# Check that a newline is printed after the buffer's contents.
|
||||
cd fail
|
||||
! go test .
|
||||
! stderr .
|
||||
stdout '^exitcode=1\n'
|
||||
stdout '^FAIL\s+example/fail'
|
||||
|
||||
# In local directory mode output is streamed, so we don't know
|
||||
# whether the test printed anything at all, so we print the exit code
|
||||
# (just in case it failed without emitting any output at all),
|
||||
# and that happens to add the needed newline as well.
|
||||
! go test
|
||||
! stderr .
|
||||
stdout '^exitcode=1exit status 1\n'
|
||||
stdout '^FAIL\s+example/fail'
|
||||
|
||||
# In package list mode, if the test passes the 'ok' message appears
|
||||
# on its own line.
|
||||
cd ../skip
|
||||
go test -v .
|
||||
! stderr .
|
||||
stdout '^skipping\n'
|
||||
stdout '^ok\s+example/skip'
|
||||
|
||||
# If the output is streamed and the test passes, we can't tell whether it ended
|
||||
# in a partial line, and don't want to emit any extra output in the
|
||||
# overwhelmingly common case that it did not.
|
||||
# (In theory we could hook the 'os' package to report whether output
|
||||
# was emitted and whether it ended in a newline, but that seems too invasive.)
|
||||
go test
|
||||
! stderr .
|
||||
stdout '^skippingok\s+example/skip'
|
||||
|
||||
|
||||
-- go.mod --
|
||||
module example
|
||||
|
||||
go 1.18
|
||||
-- fail/fail_test.go --
|
||||
package fail
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Stderr.WriteString("exitcode=1")
|
||||
os.Exit(1)
|
||||
}
|
||||
-- skip/skip_test.go --
|
||||
package skip
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Stderr.WriteString("skipping")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
@ -152,6 +152,7 @@ stdout FAIL
|
|||
# Test that the wrong type given with f.Add will fail.
|
||||
! go test -run FuzzWrongType fuzz_add_test.go
|
||||
! stdout ^ok
|
||||
stdout '\[string int\], want \[\[\]uint8 int8\]'
|
||||
stdout FAIL
|
||||
|
||||
# Test fatal with testdata seed corpus
|
||||
|
|
@ -435,8 +436,8 @@ func FuzzAddDifferentType(f *testing.F) {
|
|||
}
|
||||
|
||||
func FuzzWrongType(f *testing.F) {
|
||||
f.Add("hello")
|
||||
f.Fuzz(func(*testing.T, []byte) {})
|
||||
f.Add("hello", 50)
|
||||
f.Fuzz(func(*testing.T, []byte, int8) {})
|
||||
}
|
||||
|
||||
-- corpustesting/fuzz_testdata_corpus_test.go --
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
[!fuzz] skip
|
||||
|
||||
! go test -fuzz=FuzzTrivial -coverprofile=prof
|
||||
! stdout .
|
||||
stderr '^cannot use -coverprofile flag with -fuzz flag$'
|
||||
|
||||
! go test -fuzz=FuzzTrivial -blockprofile=prof
|
||||
! stdout .
|
||||
stderr '^cannot use -blockprofile flag with -fuzz flag$'
|
||||
|
||||
! go test -fuzz=FuzzTrivial -cpuprofile=prof
|
||||
! stdout .
|
||||
stderr '^cannot use -cpuprofile flag with -fuzz flag$'
|
||||
|
||||
! go test -fuzz=FuzzTrivial -memprofile=prof
|
||||
! stdout .
|
||||
stderr '^cannot use -memprofile flag with -fuzz flag$'
|
||||
|
||||
! go test -fuzz=FuzzTrivial -mutexprofile=prof
|
||||
! stdout .
|
||||
stderr '^cannot use -mutexprofile flag with -fuzz flag$'
|
||||
|
||||
! go test -fuzz=FuzzTrivial -trace=prof
|
||||
! stdout .
|
||||
stderr '^cannot use -trace flag with -fuzz flag$'
|
||||
|
||||
-- go.mod --
|
||||
module example
|
||||
|
||||
go 1.18
|
||||
-- fuzz_test.go --
|
||||
package example
|
||||
|
||||
import "testing"
|
||||
|
||||
func FuzzTrivial(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, _ []byte) {})
|
||||
}
|
||||
|
|
@ -634,6 +634,61 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
|
|||
}
|
||||
|
||||
func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||
if c.ctxt.Flag_maymorestack != "" {
|
||||
// Save LR and make room for REGCTXT.
|
||||
const frameSize = 8
|
||||
// MOVW.W R14,$-8(SP)
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = AMOVW
|
||||
p.Scond |= C_WBIT
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = REGLINK
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Offset = -frameSize
|
||||
p.To.Reg = REGSP
|
||||
p.Spadj = frameSize
|
||||
|
||||
// MOVW REGCTXT, 4(SP)
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = AMOVW
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = REGCTXT
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Offset = 4
|
||||
p.To.Reg = REGSP
|
||||
|
||||
// CALL maymorestack
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = obj.ACALL
|
||||
p.To.Type = obj.TYPE_BRANCH
|
||||
// See ../x86/obj6.go
|
||||
p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
|
||||
|
||||
// Restore REGCTXT and LR.
|
||||
|
||||
// MOVW 4(SP), REGCTXT
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = AMOVW
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Offset = 4
|
||||
p.From.Reg = REGSP
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = REGCTXT
|
||||
|
||||
// MOVW.P 8(SP), R14
|
||||
p.As = AMOVW
|
||||
p.Scond |= C_PBIT
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Offset = frameSize
|
||||
p.From.Reg = REGSP
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = REGLINK
|
||||
p.Spadj = -frameSize
|
||||
}
|
||||
|
||||
// Jump back to here after morestack returns.
|
||||
startPred := p
|
||||
|
||||
// MOVW g_stackguard(g), R1
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
|
||||
|
|
@ -761,7 +816,7 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
|||
b := obj.Appendp(pcdata, c.newprog)
|
||||
b.As = obj.AJMP
|
||||
b.To.Type = obj.TYPE_BRANCH
|
||||
b.To.SetTarget(c.cursym.Func().Text.Link)
|
||||
b.To.SetTarget(startPred.Link)
|
||||
b.Spadj = +framesize
|
||||
|
||||
return end
|
||||
|
|
|
|||
|
|
@ -58,6 +58,91 @@ var noZRreplace = map[obj.As]bool{
|
|||
}
|
||||
|
||||
func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||
if c.ctxt.Flag_maymorestack != "" {
|
||||
p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
|
||||
|
||||
// Save LR and make room for FP, REGCTXT. Leave room
|
||||
// for caller's saved FP.
|
||||
const frameSize = 32
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = AMOVD
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = REGLINK
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.Scond = C_XPRE
|
||||
p.To.Offset = -frameSize
|
||||
p.To.Reg = REGSP
|
||||
p.Spadj = frameSize
|
||||
|
||||
// Save FP.
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = AMOVD
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = REGFP
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Reg = REGSP
|
||||
p.To.Offset = -8
|
||||
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = ASUB
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = 8
|
||||
p.Reg = REGSP
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = REGFP
|
||||
|
||||
// Save REGCTXT (for simplicity we do this whether or
|
||||
// not we need it.)
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = AMOVD
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = REGCTXT
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Reg = REGSP
|
||||
p.To.Offset = 8
|
||||
|
||||
// BL maymorestack
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = ABL
|
||||
p.To.Type = obj.TYPE_BRANCH
|
||||
// See ../x86/obj6.go
|
||||
p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
|
||||
|
||||
// Restore REGCTXT.
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = AMOVD
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Reg = REGSP
|
||||
p.From.Offset = 8
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = REGCTXT
|
||||
|
||||
// Restore FP.
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = AMOVD
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Reg = REGSP
|
||||
p.From.Offset = -8
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = REGFP
|
||||
|
||||
// Restore LR and SP.
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
p.As = AMOVD
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.Scond = C_XPOST
|
||||
p.From.Offset = frameSize
|
||||
p.From.Reg = REGSP
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = REGLINK
|
||||
p.Spadj = -frameSize
|
||||
|
||||
p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
|
||||
}
|
||||
|
||||
// Jump back to here after morestack returns.
|
||||
startPred := p
|
||||
|
||||
// MOV g_stackguard(g), RT1
|
||||
p = obj.Appendp(p, c.newprog)
|
||||
|
||||
|
|
@ -212,7 +297,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
|||
jmp := obj.Appendp(pcdata, c.newprog)
|
||||
jmp.As = AB
|
||||
jmp.To.Type = obj.TYPE_BRANCH
|
||||
jmp.To.SetTarget(c.cursym.Func().Text.Link)
|
||||
jmp.To.SetTarget(startPred.Link)
|
||||
jmp.Spadj = +framesize
|
||||
|
||||
return end
|
||||
|
|
|
|||
|
|
@ -880,7 +880,8 @@ type Link struct {
|
|||
Flag_linkshared bool
|
||||
Flag_optimize bool
|
||||
Flag_locationlists bool
|
||||
Retpoline bool // emit use of retpoline stubs for indirect jmp/call
|
||||
Retpoline bool // emit use of retpoline stubs for indirect jmp/call
|
||||
Flag_maymorestack string // If not "", call this function before stack checks
|
||||
Bso *bufio.Writer
|
||||
Pathname string
|
||||
Pkgpath string // the current package's import path, "" if unknown
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue