Merge branch 'master' into neilalexander/doc330852

This commit is contained in:
Neil Alexander 2021-11-05 22:26:35 +00:00 committed by GitHub
commit 99306054bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
464 changed files with 32876 additions and 10113 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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 -->

View File

@ -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)
}
}

View File

@ -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() {
}

16
misc/cgo/testcarchive/testdata/main8.c vendored Normal file
View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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)
})
}
}

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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])
}

View File

@ -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.
}

View File

@ -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.
}

View File

@ -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]
}

View File

@ -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)
}
}

View File

@ -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",

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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)

View File

@ -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"
`

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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
}

View File

@ -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.

View File

@ -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]()
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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()
}

View File

@ -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

View File

@ -2202,4 +2202,4 @@ var (
var SimType [NTYPE]Kind
var ShapePkg = NewPkg(".shape", ".shape")
var ShapePkg = NewPkg("go.shape", "go.shape")

View File

@ -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`},

View File

@ -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

View File

@ -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`},

View File

@ -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

View File

@ -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}

View File

@ -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
}

View File

@ -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) {

View File

@ -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

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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.

View File

@ -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,
})
}

View File

@ -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] }",
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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.

View File

@ -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
}

View File

@ -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() {

View File

@ -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")
}
}

View File

@ -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] }

View File

@ -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)
}

View File

@ -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)
}

View File

@ -8,7 +8,7 @@ type Fooer interface {
Foo()
}
type Fooable[F Fooer] struct {
type Fooable[F /* ERROR instantiation cycle */ Fooer] struct {
ptr F
}

View File

@ -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))
}

View File

@ -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 */))
}

View File

@ -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 */ )
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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.

View File

@ -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)
}
}

View File

@ -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)

View File

@ -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",

View File

@ -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

View File

@ -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
)

View File

@ -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=

View File

@ -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.

View File

@ -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)

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -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 --

View File

@ -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) {})
}

View File

@ -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

View File

@ -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

View File

@ -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