[dev.regabi] all: merge master (d0c0dc682c) into dev.regabi

Change-Id: Ia54d7306ca7550b8d5623f505070558d275faa23
This commit is contained in:
Russ Cox 2020-12-03 12:33:12 -05:00
commit 6e30fc10fc
116 changed files with 2073 additions and 594 deletions

View file

@ -80,17 +80,16 @@ Do not send CLs removing the interior tags from such phrases.
<h3 id="go-command">Go command</h3> <h3 id="go-command">Go command</h3>
<p>
TODO
<!-- CL 237697: https://golang.org/cl/237697: cmd/go: error when -c or -i are used with unknown flags -->
<!-- CL 255052: https://golang.org/cl/255052: cmd/go: default to GO111MODULE=on -->
<!-- CL 266420: https://golang.org/cl/266420: yes (mention go help vcs): cmd/go: add GOVCS setting to control version control usage -->
<!-- CL 244773: https://golang.org/cl/244773: cmd/go/internal/modload: drop requirements on excluded versions -->
</p>
<h4 id="modules">Modules</h4> <h4 id="modules">Modules</h4>
<p><!-- golang.org/issue/41330 -->
Module-aware mode is enabled by default, regardless of whether a
<code>go.mod</code> file is present in the current working directory or a
parent directory. Specifically, the <code>GO111MODULE</code> environment
variable now defaults to <code>on</code>. To switch to the previous behavior,
set <code>GO111MODULE</code> to <code>auto</code>.
</p>
<p><!-- golang.org/issue/40728 --> <p><!-- golang.org/issue/40728 -->
Build commands like <code>go</code> <code>build</code> and <code>go</code> Build commands like <code>go</code> <code>build</code> and <code>go</code>
<code>test</code> no longer modify <code>go.mod</code> and <code>go.sum</code> <code>test</code> no longer modify <code>go.mod</code> and <code>go.sum</code>
@ -107,9 +106,7 @@ Do not send CLs removing the interior tags from such phrases.
<code>install</code> to build and install packages in module-aware mode, <code>install</code> to build and install packages in module-aware mode,
ignoring the <code>go.mod</code> file in the current directory or any parent ignoring the <code>go.mod</code> file in the current directory or any parent
directory, if there is one. This is useful for installing executables without directory, if there is one. This is useful for installing executables without
affecting the dependencies of the main module.<br> affecting the dependencies of the main module.
TODO: write and link to section in golang.org/ref/mod<br>
TODO: write and link to blog post
</p> </p>
<p><!-- golang.org/issue/40276 --> <p><!-- golang.org/issue/40276 -->
@ -127,8 +124,6 @@ Do not send CLs removing the interior tags from such phrases.
to indicate that certain published versions of the module should not be used to indicate that certain published versions of the module should not be used
by other modules. A module author may retract a version after a severe problem by other modules. A module author may retract a version after a severe problem
is discovered or if the version was published unintentionally.<br> is discovered or if the version was published unintentionally.<br>
TODO: write and link to section in golang.org/ref/mod<br>
TODO: write and link to tutorial or blog post
</p> </p>
<p><!-- golang.org/issue/26603 --> <p><!-- golang.org/issue/26603 -->
@ -138,6 +133,14 @@ Do not send CLs removing the interior tags from such phrases.
resolving missing packages. resolving missing packages.
</p> </p>
<p><!-- golang.org/issue/36465 -->
The <code>go</code> command now ignores requirements on module versions
excluded by <code>exclude</code> directives in the main module. Previously,
the <code>go</code> command used the next version higher than an excluded
version, but that version could change over time, resulting in
non-reproducible builds.
</p>
<h4 id="go-test"><code>go</code> <code>test</code></h4> <h4 id="go-test"><code>go</code> <code>test</code></h4>
<p><!-- golang.org/issue/29062 --> <p><!-- golang.org/issue/29062 -->
@ -150,6 +153,15 @@ Do not send CLs removing the interior tags from such phrases.
that is still considered to be a passing test. that is still considered to be a passing test.
</p> </p>
<p><!-- golang.org/issue/39484 -->
<code>go</code> <code>test</code> reports an error when the <code>-c</code>
or <code>-i</code> flags are used together with unknown flags. Normally,
unknown flags are passed to tests, but when <code>-c</code> or <code>-i</code>
are used, tests are not run.
</p>
<h4 id="go-get"><code>go</code> <code>get</code></h4>
<p><!-- golang.org/issue/37519 --> <p><!-- golang.org/issue/37519 -->
The <code>go</code> <code>get</code> <code>-insecure</code> flag is The <code>go</code> <code>get</code> <code>-insecure</code> flag is
deprecated and will be removed in a future version. This flag permits deprecated and will be removed in a future version. This flag permits
@ -161,8 +173,6 @@ Do not send CLs removing the interior tags from such phrases.
See <code>go</code> <code>help</code> <code>environment</code> for details. See <code>go</code> <code>help</code> <code>environment</code> for details.
</p> </p>
<h4 id="go-get"><code>go</code> <code>get</code></h4>
<p><!-- golang.org/cl/263267 --> <p><!-- golang.org/cl/263267 -->
<code>go</code> <code>get</code> <code>example.com/mod@patch</code> now <code>go</code> <code>get</code> <code>example.com/mod@patch</code> now
requires that some version of <code>example.com/mod</code> already be requires that some version of <code>example.com/mod</code> already be
@ -171,6 +181,21 @@ Do not send CLs removing the interior tags from such phrases.
to patch even newly-added dependencies.) to patch even newly-added dependencies.)
</p> </p>
<h4 id="govcs"><code>GOVCS</code> environment variable</h4>
<p><!-- golang.org/issue/266420 -->
<code>GOVCS</code> is a new environment variable that limits which version
control tools the <code>go</code> command may use to download source code.
This mitigates security issues with tools that are typically used in trusted,
authenticated environments. By default, <code>git</code> and <code>hg</code>
may be used to download code from any repository. <code>svn</code>,
<code>bzr</code>, and <code>fossil</code> may only be used to download code
from repositories with module paths or package paths matching patterns in
the <code>GOPRIVATE</code> environment variable. See
<a href="/cmd/go/#hdr-Controlling_version_control_with_GOVCS"><code>go</code>
<code>help</code> <code>vcs</code></a> for details.
</p>
<h4 id="all-pattern">The <code>all</code> pattern</h4> <h4 id="all-pattern">The <code>all</code> pattern</h4>
<p><!-- golang.org/cl/240623 --> <p><!-- golang.org/cl/240623 -->
@ -380,7 +405,8 @@ Do not send CLs removing the interior tags from such phrases.
</p> </p>
<p><!-- CL 246637 --> <p><!-- CL 246637 -->
TODO: <a href="https://golang.org/cl/246637">https://golang.org/cl/246637</a>: make config.Clone return nil if the source is nil <a href="/pkg/crypto/tls/#Config.Clone"><code>Config.Clone</code></a> now returns
a nil <code>*Config</code> if the source is nil, rather than panicking.
</p> </p>
</dd> </dd>
</dl><!-- crypto/tls --> </dl><!-- crypto/tls -->
@ -416,7 +442,9 @@ Do not send CLs removing the interior tags from such phrases.
</p> </p>
<p><!-- CL 257257 --> <p><!-- CL 257257 -->
TODO: <a href="https://golang.org/cl/257257">https://golang.org/cl/257257</a>: return additional chains from Verify on Windows On Windows, <a href="/pkg/crypto/x509/#Certificate.Verify"><code>Certificate.Verify</code></a>
will now return all certificate chains that are built by the platform
certificate verifier, instead of just the highest ranked chain.
</p> </p>
<p><!-- CL 262343 --> <p><!-- CL 262343 -->
@ -425,16 +453,26 @@ Do not send CLs removing the interior tags from such phrases.
</dd> </dd>
</dl><!-- crypto/x509 --> </dl><!-- crypto/x509 -->
<dl id="encoding/asn1"><dt><a href="/pkg/encoding/asn1">encoding/asn1</a></dt>
<dd>
<p><!-- CL 255881 -->
<a href="/pkg/encoding/asn1/#Unmarshal">Unmarshal</a> and
<a href="/pkg/encoding/asn1/#UnmarshalWithParams">UnmarshalWithParams</a>
now return an error instead of panic when the argument is not
a pointer or is nil. This change matches the behavior of other
encoding packages such as <a href="/pkg/encoding/json">encoding/json</a>.
</p>
</dd>
</dl>
<dl id="encoding/json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt> <dl id="encoding/json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
<dd> <dd>
<p><!-- CL 263619 -->
The error message for
<a href="/pkg/encoding/json/#SyntaxError">SyntaxError</a>
now begins with "json: ", matching the other errors in the package.
</p>
<p><!-- CL 234818 --> <p><!-- CL 234818 -->
TODO: <a href="https://golang.org/cl/234818">https://golang.org/cl/234818</a>: allow semicolon in field key / struct tag The <code>json</code> struct field tags understood by
<a href="/pkg/encoding/json/#Marshal"><code>Marshal</code></a>,
<a href="/pkg/encoding/json/#Unmarshal"><code>Unmarshal</code></a>,
and related functionality now permit semicolon characters within
a JSON object name for a Go struct field.
</p> </p>
</dd> </dd>
</dl><!-- encoding/json --> </dl><!-- encoding/json -->
@ -580,7 +618,10 @@ Do not send CLs removing the interior tags from such phrases.
<dl id="os"><dt><a href="/pkg/os/">os</a></dt> <dl id="os"><dt><a href="/pkg/os/">os</a></dt>
<dd> <dd>
<p><!-- CL 242998 --> <p><!-- CL 242998 -->
TODO: <a href="https://golang.org/cl/242998">https://golang.org/cl/242998</a>: export errFinished as ErrProcessDone <a href="/pkg/os/#Process.Signal"><code>Process.Signal</code></a> now
returns <a href="/pkg/os/#ErrProcessDone"><code>ErrProcessDone</code></a>
instead of the unexported <code>errFinished</code> when the process has
already finished.
</p> </p>
</dd> </dd>
</dl><!-- os --> </dl><!-- os -->
@ -636,7 +677,10 @@ Do not send CLs removing the interior tags from such phrases.
<dl id="runtime/debug"><dt><a href="/pkg/runtime/debug/">runtime/debug</a></dt> <dl id="runtime/debug"><dt><a href="/pkg/runtime/debug/">runtime/debug</a></dt>
<dd> <dd>
<p><!-- CL 249677 --> <p><!-- CL 249677 -->
TODO: <a href="https://golang.org/cl/249677">https://golang.org/cl/249677</a>: provide Addr method for errors from SetPanicOnFault The <a href="/pkg/runtime#Error"><code>runtime.Error</code> values
used when <code>SetPanicOnFault</code> is enabled may now have an
<code>Addr</code> method. If that method exists, it returns the memory
address that triggered the fault.
</p> </p>
</dd> </dd>
</dl><!-- runtime/debug --> </dl><!-- runtime/debug -->
@ -672,8 +716,9 @@ Do not send CLs removing the interior tags from such phrases.
<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt> <dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
<dd> <dd>
<p><!-- CL 254257 --> <p><!-- CL 254257, golang.org/issue/29770 -->
TODO: <a href="https://golang.org/cl/254257">https://golang.org/cl/254257</a>: allow newlines inside action delimiters Newlines characters are now allowed inside action delimiters,
permitting actions to span multiple lines.
</p> </p>
</dd> </dd>
</dl><!-- text/template --> </dl><!-- text/template -->

View file

@ -1647,14 +1647,14 @@ c := signal.Incoming()
is is
</p> </p>
<pre> <pre>
c := make(chan os.Signal) c := make(chan os.Signal, 1)
signal.Notify(c) // ask for all signals signal.Notify(c) // ask for all signals
</pre> </pre>
<p> <p>
but most code should list the specific signals it wants to handle instead: but most code should list the specific signals it wants to handle instead:
</p> </p>
<pre> <pre>
c := make(chan os.Signal) c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT) signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT)
</pre> </pre>

View file

@ -146,7 +146,7 @@ func TestReader(t *testing.T) {
for i := 0; i < len(texts)-1; i++ { for i := 0; i < len(texts)-1; i++ {
texts[i] = str + "\n" texts[i] = str + "\n"
all += texts[i] all += texts[i]
str += string(rune(i)%26 + 'a') str += string(rune(i%26 + 'a'))
} }
texts[len(texts)-1] = all texts[len(texts)-1] = all

View file

@ -340,11 +340,11 @@ start:
// Branch pseudo-instructions // Branch pseudo-instructions
BEQZ X5, start // BEQZ X5, 2 // e38602c0 BEQZ X5, start // BEQZ X5, 2 // e38602c0
BGEZ X5, start // BGEZ X5, 2 // e3d402c0 BGEZ X5, start // BGEZ X5, 2 // e3d402c0
BGT X5, X6, start // BGT X5, X6, 2 // e3c262c0 BGT X5, X6, start // BGT X5, X6, 2 // e34253c0
BGTU X5, X6, start // BGTU X5, X6, 2 // e3e062c0 BGTU X5, X6, start // BGTU X5, X6, 2 // e36053c0
BGTZ X5, start // BGTZ X5, 2 // e34e50be BGTZ X5, start // BGTZ X5, 2 // e34e50be
BLE X5, X6, start // BLE X5, X6, 2 // e3dc62be BLE X5, X6, start // BLE X5, X6, 2 // e35c53be
BLEU X5, X6, start // BLEU X5, X6, 2 // e3fa62be BLEU X5, X6, start // BLEU X5, X6, 2 // e37a53be
BLEZ X5, start // BLEZ X5, 2 // e35850be BLEZ X5, start // BLEZ X5, 2 // e35850be
BLTZ X5, start // BLTZ X5, 2 // e3c602be BLTZ X5, start // BLTZ X5, 2 // e3c602be
BNEZ X5, start // BNEZ X5, 2 // e39402be BNEZ X5, start // BNEZ X5, 2 // e39402be

View file

@ -62,7 +62,7 @@ func main() {
return return
} }
f, err = os.OpenFile(file, os.O_WRONLY, 0) f, err = os.OpenFile(file, os.O_RDWR, 0)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View file

@ -52,6 +52,7 @@ import (
"go/types" "go/types"
"internal/testenv" "internal/testenv"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
@ -89,7 +90,7 @@ func TestFormats(t *testing.T) {
testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok
// process all directories // process all directories
filepath.Walk(".", func(path string, info os.FileInfo, err error) error { filepath.WalkDir(".", func(path string, info fs.DirEntry, err error) error {
if info.IsDir() { if info.IsDir() {
if info.Name() == "testdata" { if info.Name() == "testdata" {
return filepath.SkipDir return filepath.SkipDir

View file

@ -790,10 +790,10 @@ func (f *Func) spSb() (sp, sb *Value) {
} }
} }
if sb == nil { if sb == nil {
sb = f.Entry.NewValue0(initpos, OpSB, f.Config.Types.Uintptr) sb = f.Entry.NewValue0(initpos.WithNotStmt(), OpSB, f.Config.Types.Uintptr)
} }
if sp == nil { if sp == nil {
sp = f.Entry.NewValue0(initpos, OpSP, f.Config.Types.Uintptr) sp = f.Entry.NewValue0(initpos.WithNotStmt(), OpSP, f.Config.Types.Uintptr)
} }
return return
} }

View file

@ -1369,38 +1369,38 @@
(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftLLreg x y z) yes no) (LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftLLreg x y z) yes no)
(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRLreg x y z) yes no) (LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRLreg x y z) yes no)
(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRAreg x y z) yes no) (LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRAreg x y z) yes no)
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LT (TST x y) yes no) (LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LTnoov (TST x y) yes no)
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LT (TSTconst [c] x) yes no) (LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LTnoov (TSTconst [c] x) yes no)
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftLL x y [c]) yes no) (LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftLL x y [c]) yes no)
(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftRL x y [c]) yes no) (LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftRL x y [c]) yes no)
(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftRA x y [c]) yes no) (LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftRA x y [c]) yes no)
(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftLLreg x y z) yes no) (LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftLLreg x y z) yes no)
(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftRLreg x y z) yes no) (LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftRLreg x y z) yes no)
(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftRAreg x y z) yes no) (LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftRAreg x y z) yes no)
(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LE (TST x y) yes no) (LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LEnoov (TST x y) yes no)
(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LE (TSTconst [c] x) yes no) (LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LEnoov (TSTconst [c] x) yes no)
(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftLL x y [c]) yes no) (LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftLL x y [c]) yes no)
(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftRL x y [c]) yes no) (LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftRL x y [c]) yes no)
(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftRA x y [c]) yes no) (LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftRA x y [c]) yes no)
(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftLLreg x y z) yes no) (LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftLLreg x y z) yes no)
(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftRLreg x y z) yes no) (LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftRLreg x y z) yes no)
(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftRAreg x y z) yes no) (LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftRAreg x y z) yes no)
(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LT (TEQ x y) yes no) (LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LTnoov (TEQ x y) yes no)
(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LT (TEQconst [c] x) yes no) (LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LTnoov (TEQconst [c] x) yes no)
(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftLL x y [c]) yes no) (LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftLL x y [c]) yes no)
(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftRL x y [c]) yes no) (LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftRL x y [c]) yes no)
(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftRA x y [c]) yes no) (LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftRA x y [c]) yes no)
(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftLLreg x y z) yes no) (LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftLLreg x y z) yes no)
(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftRLreg x y z) yes no) (LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftRLreg x y z) yes no)
(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftRAreg x y z) yes no) (LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftRAreg x y z) yes no)
(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LE (TEQ x y) yes no) (LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LEnoov (TEQ x y) yes no)
(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LE (TEQconst [c] x) yes no) (LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LEnoov (TEQconst [c] x) yes no)
(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftLL x y [c]) yes no) (LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftLL x y [c]) yes no)
(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftRL x y [c]) yes no) (LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftRL x y [c]) yes no)
(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftRA x y [c]) yes no) (LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftRA x y [c]) yes no)
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftLLreg x y z) yes no) (LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftLLreg x y z) yes no)
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftRLreg x y z) yes no) (LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftRLreg x y z) yes no)
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftRAreg x y z) yes no) (LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftRAreg x y z) yes no)
(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (GTnoov (CMP x y) yes no) (GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (GTnoov (CMP x y) yes no)
(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (GTnoov (CMP a (MUL <x.Type> x y)) yes no) (GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (GTnoov (CMPconst [c] x) yes no) (GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (GTnoov (CMPconst [c] x) yes no)
@ -1436,39 +1436,39 @@
(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftLLreg x y z) yes no) (GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftLLreg x y z) yes no)
(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRLreg x y z) yes no) (GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRAreg x y z) yes no) (GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRAreg x y z) yes no)
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GT (TST x y) yes no)
(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 => (GTnoov (CMN a (MUL <x.Type> x y)) yes no) (GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 => (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GT (TSTconst [c] x) yes no) (GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GTnoov (TST x y) yes no)
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftLL x y [c]) yes no) (GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TSTconst [c] x) yes no)
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftRL x y [c]) yes no) (GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftLL x y [c]) yes no)
(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftRA x y [c]) yes no) (GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftRL x y [c]) yes no)
(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftLLreg x y z) yes no) (GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftRA x y [c]) yes no)
(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftRLreg x y z) yes no) (GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftLLreg x y z) yes no)
(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftRAreg x y z) yes no) (GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GE (TST x y) yes no) (GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftRAreg x y z) yes no)
(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GE (TSTconst [c] x) yes no) (GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GEnoov (TST x y) yes no)
(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftLL x y [c]) yes no) (GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TSTconst [c] x) yes no)
(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftRL x y [c]) yes no) (GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftLL x y [c]) yes no)
(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftRA x y [c]) yes no) (GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftRL x y [c]) yes no)
(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftLLreg x y z) yes no) (GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftRA x y [c]) yes no)
(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftRLreg x y z) yes no) (GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftLLreg x y z) yes no)
(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftRAreg x y z) yes no) (GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftRLreg x y z) yes no)
(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GT (TEQ x y) yes no) (GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftRAreg x y z) yes no)
(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GT (TEQconst [c] x) yes no) (GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GTnoov (TEQ x y) yes no)
(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftLL x y [c]) yes no) (GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TEQconst [c] x) yes no)
(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftRL x y [c]) yes no) (GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftLL x y [c]) yes no)
(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftRA x y [c]) yes no) (GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftRL x y [c]) yes no)
(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftLLreg x y z) yes no) (GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftRA x y [c]) yes no)
(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftRLreg x y z) yes no) (GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftLLreg x y z) yes no)
(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftRAreg x y z) yes no) (GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GE (TEQ x y) yes no) (GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftRAreg x y z) yes no)
(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GE (TEQconst [c] x) yes no) (GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GEnoov (TEQ x y) yes no)
(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftLL x y [c]) yes no) (GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TEQconst [c] x) yes no)
(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftRL x y [c]) yes no) (GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftLL x y [c]) yes no)
(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftRA x y [c]) yes no) (GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftRL x y [c]) yes no)
(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftLLreg x y z) yes no) (GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftRA x y [c]) yes no)
(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRLreg x y z) yes no) (GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftLLreg x y z) yes no)
(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRAreg x y z) yes no) (GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftRAreg x y z) yes no)
(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read8(sym, int64(off)))]) (MOVBUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read8(sym, int64(off)))])
(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))])

View file

@ -17389,7 +17389,7 @@ func rewriteBlockARM(b *Block) bool {
} }
// match: (GE (CMPconst [0] l:(AND x y)) yes no) // match: (GE (CMPconst [0] l:(AND x y)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TST x y) yes no) // result: (GEnoov (TST x y) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17410,14 +17410,14 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
break break
} }
// match: (GE (CMPconst [0] l:(ANDconst [c] x)) yes no) // match: (GE (CMPconst [0] l:(ANDconst [c] x)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TSTconst [c] x) yes no) // result: (GEnoov (TSTconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17435,12 +17435,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg(x) v0.AddArg(x)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) // match: (GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TSTshiftLL x y [c]) yes no) // result: (GEnoov (TSTshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17459,12 +17459,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) // match: (GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TSTshiftRL x y [c]) yes no) // result: (GEnoov (TSTshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17483,12 +17483,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) // match: (GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TSTshiftRA x y [c]) yes no) // result: (GEnoov (TSTshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17507,12 +17507,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) // match: (GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TSTshiftLLreg x y z) yes no) // result: (GEnoov (TSTshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17530,12 +17530,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) // match: (GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TSTshiftRLreg x y z) yes no) // result: (GEnoov (TSTshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17553,12 +17553,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) // match: (GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TSTshiftRAreg x y z) yes no) // result: (GEnoov (TSTshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17576,12 +17576,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(XOR x y)) yes no) // match: (GE (CMPconst [0] l:(XOR x y)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TEQ x y) yes no) // result: (GEnoov (TEQ x y) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17602,14 +17602,14 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
break break
} }
// match: (GE (CMPconst [0] l:(XORconst [c] x)) yes no) // match: (GE (CMPconst [0] l:(XORconst [c] x)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TEQconst [c] x) yes no) // result: (GEnoov (TEQconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17627,12 +17627,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg(x) v0.AddArg(x)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) // match: (GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TEQshiftLL x y [c]) yes no) // result: (GEnoov (TEQshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17651,12 +17651,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) // match: (GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TEQshiftRL x y [c]) yes no) // result: (GEnoov (TEQshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17675,12 +17675,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) // match: (GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TEQshiftRA x y [c]) yes no) // result: (GEnoov (TEQshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17699,12 +17699,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) // match: (GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TEQshiftLLreg x y z) yes no) // result: (GEnoov (TEQshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17722,12 +17722,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) // match: (GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TEQshiftRLreg x y z) yes no) // result: (GEnoov (TEQshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17745,12 +17745,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
// match: (GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) // match: (GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GE (TEQshiftRAreg x y z) yes no) // result: (GEnoov (TEQshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -17768,7 +17768,7 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGE, v0) b.resetWithControl(BlockARMGEnoov, v0)
return true return true
} }
case BlockARMGEnoov: case BlockARMGEnoov:
@ -18278,34 +18278,6 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGTnoov, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(AND x y)) yes no)
// cond: l.Uses==1
// result: (GT (TST x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
break
}
l := v_0.Args[0]
if l.Op != OpARMAND {
break
}
_ = l.Args[1]
l_0 := l.Args[0]
l_1 := l.Args[1]
for _i0 := 0; _i0 <= 1; _i0, l_0, l_1 = _i0+1, l_1, l_0 {
x := l_0
y := l_1
if !(l.Uses == 1) {
continue
}
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
v0.AddArg2(x, y)
b.resetWithControl(BlockARMGT, v0)
return true
}
break
}
// match: (GT (CMPconst [0] l:(MULA x y a)) yes no) // match: (GT (CMPconst [0] l:(MULA x y a)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GTnoov (CMN a (MUL <x.Type> x y)) yes no) // result: (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
@ -18331,9 +18303,37 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGTnoov, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(AND x y)) yes no)
// cond: l.Uses==1
// result: (GTnoov (TST x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
break
}
l := v_0.Args[0]
if l.Op != OpARMAND {
break
}
_ = l.Args[1]
l_0 := l.Args[0]
l_1 := l.Args[1]
for _i0 := 0; _i0 <= 1; _i0, l_0, l_1 = _i0+1, l_1, l_0 {
x := l_0
y := l_1
if !(l.Uses == 1) {
continue
}
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
v0.AddArg2(x, y)
b.resetWithControl(BlockARMGTnoov, v0)
return true
}
break
}
// match: (GT (CMPconst [0] l:(ANDconst [c] x)) yes no) // match: (GT (CMPconst [0] l:(ANDconst [c] x)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TSTconst [c] x) yes no) // result: (GTnoov (TSTconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18351,12 +18351,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg(x) v0.AddArg(x)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) // match: (GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TSTshiftLL x y [c]) yes no) // result: (GTnoov (TSTshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18375,12 +18375,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) // match: (GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TSTshiftRL x y [c]) yes no) // result: (GTnoov (TSTshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18399,12 +18399,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) // match: (GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TSTshiftRA x y [c]) yes no) // result: (GTnoov (TSTshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18423,12 +18423,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) // match: (GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TSTshiftLLreg x y z) yes no) // result: (GTnoov (TSTshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18446,12 +18446,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) // match: (GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TSTshiftRLreg x y z) yes no) // result: (GTnoov (TSTshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18469,12 +18469,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) // match: (GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TSTshiftRAreg x y z) yes no) // result: (GTnoov (TSTshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18492,12 +18492,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(XOR x y)) yes no) // match: (GT (CMPconst [0] l:(XOR x y)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TEQ x y) yes no) // result: (GTnoov (TEQ x y) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18518,14 +18518,14 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
break break
} }
// match: (GT (CMPconst [0] l:(XORconst [c] x)) yes no) // match: (GT (CMPconst [0] l:(XORconst [c] x)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TEQconst [c] x) yes no) // result: (GTnoov (TEQconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18543,12 +18543,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg(x) v0.AddArg(x)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) // match: (GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TEQshiftLL x y [c]) yes no) // result: (GTnoov (TEQshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18567,12 +18567,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) // match: (GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TEQshiftRL x y [c]) yes no) // result: (GTnoov (TEQshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18591,12 +18591,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) // match: (GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TEQshiftRA x y [c]) yes no) // result: (GTnoov (TEQshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18615,12 +18615,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) // match: (GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TEQshiftLLreg x y z) yes no) // result: (GTnoov (TEQshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18638,12 +18638,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) // match: (GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TEQshiftRLreg x y z) yes no) // result: (GTnoov (TEQshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18661,12 +18661,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
// match: (GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) // match: (GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (GT (TEQshiftRAreg x y z) yes no) // result: (GTnoov (TEQshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -18684,7 +18684,7 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMGT, v0) b.resetWithControl(BlockARMGTnoov, v0)
return true return true
} }
case BlockARMGTnoov: case BlockARMGTnoov:
@ -19312,7 +19312,7 @@ func rewriteBlockARM(b *Block) bool {
} }
// match: (LE (CMPconst [0] l:(AND x y)) yes no) // match: (LE (CMPconst [0] l:(AND x y)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TST x y) yes no) // result: (LEnoov (TST x y) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19333,14 +19333,14 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
break break
} }
// match: (LE (CMPconst [0] l:(ANDconst [c] x)) yes no) // match: (LE (CMPconst [0] l:(ANDconst [c] x)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TSTconst [c] x) yes no) // result: (LEnoov (TSTconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19358,12 +19358,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg(x) v0.AddArg(x)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) // match: (LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TSTshiftLL x y [c]) yes no) // result: (LEnoov (TSTshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19382,12 +19382,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) // match: (LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TSTshiftRL x y [c]) yes no) // result: (LEnoov (TSTshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19406,12 +19406,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) // match: (LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TSTshiftRA x y [c]) yes no) // result: (LEnoov (TSTshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19430,12 +19430,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) // match: (LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TSTshiftLLreg x y z) yes no) // result: (LEnoov (TSTshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19453,12 +19453,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) // match: (LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TSTshiftRLreg x y z) yes no) // result: (LEnoov (TSTshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19476,12 +19476,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) // match: (LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TSTshiftRAreg x y z) yes no) // result: (LEnoov (TSTshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19499,12 +19499,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(XOR x y)) yes no) // match: (LE (CMPconst [0] l:(XOR x y)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TEQ x y) yes no) // result: (LEnoov (TEQ x y) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19525,14 +19525,14 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
break break
} }
// match: (LE (CMPconst [0] l:(XORconst [c] x)) yes no) // match: (LE (CMPconst [0] l:(XORconst [c] x)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TEQconst [c] x) yes no) // result: (LEnoov (TEQconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19550,12 +19550,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg(x) v0.AddArg(x)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) // match: (LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TEQshiftLL x y [c]) yes no) // result: (LEnoov (TEQshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19574,12 +19574,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) // match: (LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TEQshiftRL x y [c]) yes no) // result: (LEnoov (TEQshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19598,12 +19598,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) // match: (LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TEQshiftRA x y [c]) yes no) // result: (LEnoov (TEQshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19622,12 +19622,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) // match: (LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TEQshiftLLreg x y z) yes no) // result: (LEnoov (TEQshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19645,12 +19645,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) // match: (LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TEQshiftRLreg x y z) yes no) // result: (LEnoov (TEQshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19668,12 +19668,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
// match: (LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) // match: (LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LE (TEQshiftRAreg x y z) yes no) // result: (LEnoov (TEQshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -19691,7 +19691,7 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLE, v0) b.resetWithControl(BlockARMLEnoov, v0)
return true return true
} }
case BlockARMLEnoov: case BlockARMLEnoov:
@ -20228,7 +20228,7 @@ func rewriteBlockARM(b *Block) bool {
} }
// match: (LT (CMPconst [0] l:(AND x y)) yes no) // match: (LT (CMPconst [0] l:(AND x y)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TST x y) yes no) // result: (LTnoov (TST x y) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20249,14 +20249,14 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
break break
} }
// match: (LT (CMPconst [0] l:(ANDconst [c] x)) yes no) // match: (LT (CMPconst [0] l:(ANDconst [c] x)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TSTconst [c] x) yes no) // result: (LTnoov (TSTconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20274,12 +20274,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg(x) v0.AddArg(x)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) // match: (LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TSTshiftLL x y [c]) yes no) // result: (LTnoov (TSTshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20298,12 +20298,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) // match: (LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TSTshiftRL x y [c]) yes no) // result: (LTnoov (TSTshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20322,12 +20322,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) // match: (LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TSTshiftRA x y [c]) yes no) // result: (LTnoov (TSTshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20346,12 +20346,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) // match: (LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TSTshiftLLreg x y z) yes no) // result: (LTnoov (TSTshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20369,12 +20369,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) // match: (LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TSTshiftRLreg x y z) yes no) // result: (LTnoov (TSTshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20392,12 +20392,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) // match: (LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TSTshiftRAreg x y z) yes no) // result: (LTnoov (TSTshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20415,12 +20415,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(XOR x y)) yes no) // match: (LT (CMPconst [0] l:(XOR x y)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TEQ x y) yes no) // result: (LTnoov (TEQ x y) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20441,14 +20441,14 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
break break
} }
// match: (LT (CMPconst [0] l:(XORconst [c] x)) yes no) // match: (LT (CMPconst [0] l:(XORconst [c] x)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TEQconst [c] x) yes no) // result: (LTnoov (TEQconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20466,12 +20466,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg(x) v0.AddArg(x)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) // match: (LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TEQshiftLL x y [c]) yes no) // result: (LTnoov (TEQshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20490,12 +20490,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) // match: (LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TEQshiftRL x y [c]) yes no) // result: (LTnoov (TEQshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20514,12 +20514,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) // match: (LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TEQshiftRA x y [c]) yes no) // result: (LTnoov (TEQshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20538,12 +20538,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(c) v0.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y) v0.AddArg2(x, y)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) // match: (LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TEQshiftLLreg x y z) yes no) // result: (LTnoov (TEQshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20561,12 +20561,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) // match: (LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TEQshiftRLreg x y z) yes no) // result: (LTnoov (TEQshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20584,12 +20584,12 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
// match: (LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) // match: (LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
// cond: l.Uses==1 // cond: l.Uses==1
// result: (LT (TEQshiftRAreg x y z) yes no) // result: (LTnoov (TEQshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst { for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0] v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 { if auxIntToInt32(v_0.AuxInt) != 0 {
@ -20607,7 +20607,7 @@ func rewriteBlockARM(b *Block) bool {
} }
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z) v0.AddArg3(x, y, z)
b.resetWithControl(BlockARMLT, v0) b.resetWithControl(BlockARMLTnoov, v0)
return true return true
} }
case BlockARMLTnoov: case BlockARMLTnoov:

View file

@ -55,6 +55,7 @@ var bootstrapDirs = []string{
"cmd/compile/internal/x86", "cmd/compile/internal/x86",
"cmd/compile/internal/wasm", "cmd/compile/internal/wasm",
"cmd/internal/bio", "cmd/internal/bio",
"cmd/internal/codesign",
"cmd/internal/gcprog", "cmd/internal/gcprog",
"cmd/internal/dwarf", "cmd/internal/dwarf",
"cmd/internal/edit", "cmd/internal/edit",

View file

@ -1509,6 +1509,7 @@ func (t *tester) makeGOROOTUnwritable() (undo func()) {
} }
gocacheSubdir, _ := filepath.Rel(dir, gocache) gocacheSubdir, _ := filepath.Rel(dir, gocache)
// Note: Can't use WalkDir here, because this has to compile with Go 1.4.
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" { if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" {
if suffix == gocacheSubdir { if suffix == gocacheSubdir {

View file

@ -234,10 +234,10 @@ func report(err error) {
} }
func walkDir(path string) { func walkDir(path string) {
filepath.Walk(path, visitFile) filepath.WalkDir(path, visitFile)
} }
func visitFile(path string, f fs.FileInfo, err error) error { func visitFile(path string, f fs.DirEntry, err error) error {
if err == nil && isGoFile(f) { if err == nil && isGoFile(f) {
err = processFile(path, false) err = processFile(path, false)
} }
@ -247,7 +247,7 @@ func visitFile(path string, f fs.FileInfo, err error) error {
return nil return nil
} }
func isGoFile(f fs.FileInfo) bool { func isGoFile(f fs.DirEntry) bool {
// ignore non-Go files // ignore non-Go files
name := f.Name() name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")

View file

@ -7,7 +7,7 @@ require (
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 golang.org/x/mod v0.4.0
golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65 // indirect golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65 // indirect
golang.org/x/tools v0.0.0-20201110201400-7099162a900a golang.org/x/tools v0.0.0-20201110201400-7099162a900a
) )

View file

@ -15,8 +15,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ= golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=

View file

@ -774,7 +774,7 @@ func (tg *testgoData) cleanup() {
func removeAll(dir string) error { func removeAll(dir string) error {
// module cache has 0444 directories; // module cache has 0444 directories;
// make them writable in order to remove content. // make them writable in order to remove content.
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
// chmod not only directories, but also things that we couldn't even stat // chmod not only directories, but also things that we couldn't even stat
// due to permission errors: they may also be unreadable directories. // due to permission errors: they may also be unreadable directories.
if err != nil || info.IsDir() { if err != nil || info.IsDir() {
@ -820,8 +820,8 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
} { } {
srcdir := filepath.Join(testGOROOT, copydir) srcdir := filepath.Join(testGOROOT, copydir)
tg.tempDir(filepath.Join("goroot", copydir)) tg.tempDir(filepath.Join("goroot", copydir))
err := filepath.Walk(srcdir, err := filepath.WalkDir(srcdir,
func(path string, info fs.FileInfo, err error) error { func(path string, info fs.DirEntry, err error) error {
if err != nil { if err != nil {
return err return err
} }
@ -838,8 +838,8 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
return err return err
} }
tg.tempFile(dest, string(data)) tg.tempFile(dest, string(data))
if err := os.Chmod(tg.path(dest), info.Mode()|0200); err != nil { if strings.Contains(copydir, filepath.Join("pkg", "tool")) {
return err os.Chmod(tg.path(dest), 0777)
} }
return nil return nil
}) })

View file

@ -15,7 +15,7 @@ var Interrupted = make(chan struct{})
// processSignals setups signal handler. // processSignals setups signal handler.
func processSignals() { func processSignals() {
sig := make(chan os.Signal) sig := make(chan os.Signal, 1)
signal.Notify(sig, signalsToIgnore...) signal.Notify(sig, signalsToIgnore...)
go func() { go func() {
<-sig <-sig

View file

@ -264,6 +264,9 @@ func RunWithStdin(dir string, stdin io.Reader, cmdline ...interface{}) ([]byte,
} }
cmd := str.StringList(cmdline...) cmd := str.StringList(cmdline...)
if os.Getenv("TESTGOVCS") == "panic" {
panic(fmt.Sprintf("use of vcs: %v", cmd))
}
if cfg.BuildX { if cfg.BuildX {
text := new(strings.Builder) text := new(strings.Builder)
if dir != "" { if dir != "" {

View file

@ -318,9 +318,10 @@ func makeDirsReadOnly(dir string) {
mode fs.FileMode mode fs.FileMode
} }
var dirs []pathMode // in lexical order var dirs []pathMode // in lexical order
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if err == nil && info.Mode()&0222 != 0 { if err == nil && d.IsDir() {
if info.IsDir() { info, err := d.Info()
if err == nil && info.Mode()&0222 != 0 {
dirs = append(dirs, pathMode{path, info.Mode()}) dirs = append(dirs, pathMode{path, info.Mode()})
} }
} }
@ -337,7 +338,7 @@ func makeDirsReadOnly(dir string) {
// any permission changes needed to do so. // any permission changes needed to do so.
func RemoveAll(dir string) error { func RemoveAll(dir string) error {
// Module cache has 0555 directories; make them writable in order to remove content. // Module cache has 0555 directories; make them writable in order to remove content.
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
if err != nil { if err != nil {
return nil // ignore errors walking in file system return nil // ignore errors walking in file system
} }

View file

@ -436,32 +436,9 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
work.BuildInit() work.BuildInit()
pkgs := load.PackagesForBuild(ctx, pkgPatterns) pkgs := load.PackagesForBuild(ctx, pkgPatterns)
work.InstallPackages(ctx, pkgPatterns, pkgs) work.InstallPackages(ctx, pkgPatterns, pkgs)
// TODO(#40276): After Go 1.16, print a deprecation notice when building
haveExe := false // and installing main packages. 'go install pkg' or
for _, pkg := range pkgs { // 'go install pkg@version' should be used instead.
if pkg.Name == "main" {
haveExe = true
break
}
}
if haveExe {
fmt.Fprint(os.Stderr, "go get: installing executables with 'go get' in module mode is deprecated.")
var altMsg string
if modload.HasModRoot() {
altMsg = `
To adjust dependencies of the current module, use 'go get -d'.
To install using requirements of the current module, use 'go install'.
To install ignoring the current module, use 'go install' with a version,
like 'go install example.com/cmd@latest'.
`
} else {
altMsg = "\n\tUse 'go install pkg@version' instead.\n"
}
fmt.Fprint(os.Stderr, altMsg)
fmt.Fprint(os.Stderr, "\tSee 'go help get' and 'go help install' for more information.\n")
}
// TODO(golang.org/issue/40276): link to HTML documentation explaining
// what's changing and gives more examples.
} }
if !modload.HasModRoot() { if !modload.HasModRoot() {

View file

@ -1018,7 +1018,7 @@ func keepSums(addDirect bool) map[module.Version]bool {
} }
} }
for _, pkg := range loaded.pkgs { for _, pkg := range loaded.pkgs {
if pkg.testOf != nil || pkg.inStd { if pkg.testOf != nil || pkg.inStd || module.CheckImportPath(pkg.path) != nil {
continue continue
} }
for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) { for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) {

View file

@ -23,6 +23,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/search" "cmd/go/internal/search"
"cmd/go/internal/str"
"cmd/go/internal/web" "cmd/go/internal/web"
"golang.org/x/mod/module" "golang.org/x/mod/module"
@ -539,7 +540,7 @@ func (v *Cmd) TagSync(dir, tag string) error {
// A vcsPath describes how to convert an import path into a // A vcsPath describes how to convert an import path into a
// version control system and repository name. // version control system and repository name.
type vcsPath struct { type vcsPath struct {
prefix string // prefix this description applies to pathPrefix string // prefix this description applies to
regexp *lazyregexp.Regexp // compiled pattern for import path regexp *lazyregexp.Regexp // compiled pattern for import path
repo string // repository to use (expand with match of re) repo string // repository to use (expand with match of re)
vcs string // version control system to use (expand with match of re) vcs string // version control system to use (expand with match of re)
@ -826,6 +827,20 @@ var errUnknownSite = errors.New("dynamic lookup required to find mapping")
// repoRootFromVCSPaths attempts to map importPath to a repoRoot // repoRootFromVCSPaths attempts to map importPath to a repoRoot
// using the mappings defined in vcsPaths. // using the mappings defined in vcsPaths.
func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths []*vcsPath) (*RepoRoot, error) { func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths []*vcsPath) (*RepoRoot, error) {
if str.HasPathPrefix(importPath, "example.net") {
// TODO(rsc): This should not be necessary, but it's required to keep
// tests like ../../testdata/script/mod_get_extra.txt from using the network.
// That script has everything it needs in the replacement set, but it is still
// doing network calls.
return nil, fmt.Errorf("no modules on example.net")
}
if importPath == "rsc.io" {
// This special case allows tests like ../../testdata/script/govcs.txt
// to avoid making any network calls. The module lookup for a path
// like rsc.io/nonexist.svn/foo needs to not make a network call for
// a lookup on rsc.io.
return nil, fmt.Errorf("rsc.io is not a module")
}
// A common error is to use https://packagepath because that's what // A common error is to use https://packagepath because that's what
// hg and git require. Diagnose this helpfully. // hg and git require. Diagnose this helpfully.
if prefix := httpPrefix(importPath); prefix != "" { if prefix := httpPrefix(importPath); prefix != "" {
@ -834,20 +849,20 @@ func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths
return nil, fmt.Errorf("%q not allowed in import path", prefix+"//") return nil, fmt.Errorf("%q not allowed in import path", prefix+"//")
} }
for _, srv := range vcsPaths { for _, srv := range vcsPaths {
if !strings.HasPrefix(importPath, srv.prefix) { if !str.HasPathPrefix(importPath, srv.pathPrefix) {
continue continue
} }
m := srv.regexp.FindStringSubmatch(importPath) m := srv.regexp.FindStringSubmatch(importPath)
if m == nil { if m == nil {
if srv.prefix != "" { if srv.pathPrefix != "" {
return nil, importErrorf(importPath, "invalid %s import path %q", srv.prefix, importPath) return nil, importErrorf(importPath, "invalid %s import path %q", srv.pathPrefix, importPath)
} }
continue continue
} }
// Build map of named subexpression matches for expand. // Build map of named subexpression matches for expand.
match := map[string]string{ match := map[string]string{
"prefix": srv.prefix, "prefix": srv.pathPrefix + "/",
"import": importPath, "import": importPath,
} }
for i, name := range srv.regexp.SubexpNames() { for i, name := range srv.regexp.SubexpNames() {
@ -1098,18 +1113,6 @@ type metaImport struct {
Prefix, VCS, RepoRoot string Prefix, VCS, RepoRoot string
} }
// pathPrefix reports whether sub is a prefix of s,
// only considering entire path components.
func pathPrefix(s, sub string) bool {
// strings.HasPrefix is necessary but not sufficient.
if !strings.HasPrefix(s, sub) {
return false
}
// The remainder after the prefix must either be empty or start with a slash.
rem := s[len(sub):]
return rem == "" || rem[0] == '/'
}
// A ImportMismatchError is returned where metaImport/s are present // A ImportMismatchError is returned where metaImport/s are present
// but none match our import path. // but none match our import path.
type ImportMismatchError struct { type ImportMismatchError struct {
@ -1133,7 +1136,7 @@ func matchGoImport(imports []metaImport, importPath string) (metaImport, error)
errImportMismatch := ImportMismatchError{importPath: importPath} errImportMismatch := ImportMismatchError{importPath: importPath}
for i, im := range imports { for i, im := range imports {
if !pathPrefix(importPath, im.Prefix) { if !str.HasPathPrefix(importPath, im.Prefix) {
errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix) errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix)
continue continue
} }
@ -1175,52 +1178,52 @@ func expand(match map[string]string, s string) string {
var vcsPaths = []*vcsPath{ var vcsPaths = []*vcsPath{
// Github // Github
{ {
prefix: "github.com/", pathPrefix: "github.com",
regexp: lazyregexp.New(`^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`), regexp: lazyregexp.New(`^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
vcs: "git", vcs: "git",
repo: "https://{root}", repo: "https://{root}",
check: noVCSSuffix, check: noVCSSuffix,
}, },
// Bitbucket // Bitbucket
{ {
prefix: "bitbucket.org/", pathPrefix: "bitbucket.org",
regexp: lazyregexp.New(`^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`), regexp: lazyregexp.New(`^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
repo: "https://{root}", repo: "https://{root}",
check: bitbucketVCS, check: bitbucketVCS,
}, },
// IBM DevOps Services (JazzHub) // IBM DevOps Services (JazzHub)
{ {
prefix: "hub.jazz.net/git/", pathPrefix: "hub.jazz.net/git",
regexp: lazyregexp.New(`^(?P<root>hub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`), regexp: lazyregexp.New(`^(?P<root>hub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
vcs: "git", vcs: "git",
repo: "https://{root}", repo: "https://{root}",
check: noVCSSuffix, check: noVCSSuffix,
}, },
// Git at Apache // Git at Apache
{ {
prefix: "git.apache.org/", pathPrefix: "git.apache.org",
regexp: lazyregexp.New(`^(?P<root>git\.apache\.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`), regexp: lazyregexp.New(`^(?P<root>git\.apache\.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`),
vcs: "git", vcs: "git",
repo: "https://{root}", repo: "https://{root}",
}, },
// Git at OpenStack // Git at OpenStack
{ {
prefix: "git.openstack.org/", pathPrefix: "git.openstack.org",
regexp: lazyregexp.New(`^(?P<root>git\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`), regexp: lazyregexp.New(`^(?P<root>git\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`),
vcs: "git", vcs: "git",
repo: "https://{root}", repo: "https://{root}",
}, },
// chiselapp.com for fossil // chiselapp.com for fossil
{ {
prefix: "chiselapp.com/", pathPrefix: "chiselapp.com",
regexp: lazyregexp.New(`^(?P<root>chiselapp\.com/user/[A-Za-z0-9]+/repository/[A-Za-z0-9_.\-]+)$`), regexp: lazyregexp.New(`^(?P<root>chiselapp\.com/user/[A-Za-z0-9]+/repository/[A-Za-z0-9_.\-]+)$`),
vcs: "fossil", vcs: "fossil",
repo: "https://{root}", repo: "https://{root}",
}, },
// General syntax for any server. // General syntax for any server.
@ -1238,11 +1241,11 @@ var vcsPaths = []*vcsPath{
var vcsPathsAfterDynamic = []*vcsPath{ var vcsPathsAfterDynamic = []*vcsPath{
// Launchpad. See golang.org/issue/11436. // Launchpad. See golang.org/issue/11436.
{ {
prefix: "launchpad.net/", pathPrefix: "launchpad.net",
regexp: lazyregexp.New(`^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`), regexp: lazyregexp.New(`^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
vcs: "bzr", vcs: "bzr",
repo: "https://{root}", repo: "https://{root}",
check: launchpadVCS, check: launchpadVCS,
}, },
} }

View file

@ -88,8 +88,15 @@ func runVersion(ctx context.Context, cmd *base.Command, args []string) {
// scanDir scans a directory for executables to run scanFile on. // scanDir scans a directory for executables to run scanFile on.
func scanDir(dir string) { func scanDir(dir string) {
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if info.Mode().IsRegular() || info.Mode()&fs.ModeSymlink != 0 { if d.Type().IsRegular() || d.Type()&fs.ModeSymlink != 0 {
info, err := d.Info()
if err != nil {
if *versionV {
fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
}
return nil
}
scanFile(path, info, *versionV) scanFile(path, info, *versionV)
} }
return nil return nil
@ -120,6 +127,7 @@ func scanFile(file string, info fs.FileInfo, mustPrint bool) {
} }
info = i info = i
} }
if !isExe(file, info) { if !isExe(file, info) {
if mustPrint { if mustPrint {
fmt.Fprintf(os.Stderr, "%s: not executable file\n", file) fmt.Fprintf(os.Stderr, "%s: not executable file\n", file)

View file

@ -80,6 +80,13 @@ func get(security SecurityMode, url *urlpkg.URL) (*Response, error) {
return res, nil return res, nil
} }
if url.Host == "localhost.localdev" {
return nil, fmt.Errorf("no such host localhost.localdev")
}
if os.Getenv("TESTGONETWORK") == "panic" && !strings.HasPrefix(url.Host, "127.0.0.1") && !strings.HasPrefix(url.Host, "0.0.0.0") {
panic("use of network: " + url.String())
}
fetch := func(url *urlpkg.URL) (*urlpkg.URL, *http.Response, error) { fetch := func(url *urlpkg.URL) (*urlpkg.URL, *http.Response, error) {
// Note: The -v build flag does not mean "print logging information", // Note: The -v build flag does not mean "print logging information",
// despite its historical misuse for this in GOPATH-based go get. // despite its historical misuse for this in GOPATH-based go get.

View file

@ -647,7 +647,7 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error {
} }
if rewrite { if rewrite {
w, err := os.OpenFile(target, os.O_WRONLY, 0) w, err := os.OpenFile(target, os.O_RDWR, 0)
if err != nil { if err != nil {
return err return err
} }

View file

@ -142,6 +142,9 @@ func (ts *testScript) setup() {
"goversion=" + goVersion(ts), "goversion=" + goVersion(ts),
":=" + string(os.PathListSeparator), ":=" + string(os.PathListSeparator),
} }
if !testenv.HasExternalNetwork() {
ts.env = append(ts.env, "TESTGONETWORK=panic", "TESTGOVCS=panic")
}
if runtime.GOOS == "plan9" { if runtime.GOOS == "plan9" {
ts.env = append(ts.env, "path="+testBin+string(filepath.ListSeparator)+os.Getenv("path")) ts.env = append(ts.env, "path="+testBin+string(filepath.ListSeparator)+os.Getenv("path"))

View file

@ -122,8 +122,8 @@ func main() {
{Name: ".info", Data: info}, {Name: ".info", Data: info},
} }
dir = filepath.Clean(dir) dir = filepath.Clean(dir)
err = filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { err = filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
if !info.Mode().IsRegular() { if !info.Type().IsRegular() {
return nil return nil
} }
name := info.Name() name := info.Name()

View file

@ -49,7 +49,7 @@ func main() {
a := new(txtar.Archive) a := new(txtar.Archive)
dir = filepath.Clean(dir) dir = filepath.Clean(dir)
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
if path == dir { if path == dir {
return nil return nil
} }
@ -60,7 +60,7 @@ func main() {
} }
return nil return nil
} }
if !info.Mode().IsRegular() { if !info.Type().IsRegular() {
return nil return nil
} }
data, err := ioutil.ReadFile(path) data, err := ioutil.ReadFile(path)

View file

@ -1,22 +0,0 @@
[short] skip
env GO111MODULE=on
# 'go get' outside a module with an executable prints a deprecation message.
go get example.com/cmd/a
stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$'
stderr 'Use ''go install pkg@version'' instead.'
go mod init m
# 'go get' inside a module with a non-main package does not print a message.
# This will stop building in the future, but it's the command we want to use.
go get rsc.io/quote
! stderr deprecated
# 'go get' inside a module with an executable prints a different
# deprecation message.
go get example.com/cmd/a
stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$'
stderr 'To adjust dependencies of the current module, use ''go get -d'''

View file

@ -0,0 +1,14 @@
# If an import declaration is an absolute path, most commands should report
# an error instead of going into an infinite loop.
# Verifies golang.org/issue/42891.
go list .
stdout '^m$'
-- go.mod --
module m
go 1.16
-- m.go --
package m
import "/"

View file

@ -2,7 +2,7 @@ env GO111MODULE=on
env GOPROXY=$GOPROXY/invalid env GOPROXY=$GOPROXY/invalid
! go list -m rsc.io/quote@latest ! go list -m rsc.io/quote@latest
stderr '^go list -m: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": json: invalid character ''i'' looking for beginning of value$' stderr '^go list -m: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'
! go list -m rsc.io/quote@1.5.2 ! go list -m rsc.io/quote@1.5.2
stderr '^go list -m: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": json: invalid character ''i'' looking for beginning of value$' stderr '^go list -m: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'

View file

@ -40,7 +40,7 @@ env GOPROXY=file:///$WORK/gatekeeper
chmod 0000 $WORK/gatekeeper/example.com/join/subpkg/@latest chmod 0000 $WORK/gatekeeper/example.com/join/subpkg/@latest
cp go.mod.orig go.mod cp go.mod.orig go.mod
! go get -d example.com/join/subpkg ! go get -d example.com/join/subpkg
stderr 'go get: module example.com/join/subpkg: (invalid response from proxy ".+": json: invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)' stderr 'go get: module example.com/join/subpkg: (invalid response from proxy ".+": invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)'
-- go.mod.orig -- -- go.mod.orig --
module example.com/othermodule module example.com/othermodule

View file

@ -17,14 +17,12 @@ rm $GOPATH/pkg/mod/cache/download/sumdb
rm go.sum rm go.sum
# direct access fails (because localhost.localdev does not exist) # direct access fails (because localhost.localdev does not exist)
# The text of the error message is hard to predict because some DNS servers # web.get is providing the error message - there's no actual network access.
# will resolve unknown domains like localhost.localdev to a real IP
# to serve ads.
cp go.mod.orig go.mod cp go.mod.orig go.mod
env GOSUMDB=$sumdb env GOSUMDB=$sumdb
env GOPROXY=direct env GOPROXY=direct
! go get -d rsc.io/fortune@v1.0.0 ! go get -d rsc.io/fortune@v1.0.0
stderr 'verifying.*localhost.localdev' stderr 'verifying module: rsc.io/fortune@v1.0.0: .*: no such host localhost.localdev'
rm $GOPATH/pkg/mod/cache/download/sumdb rm $GOPATH/pkg/mod/cache/download/sumdb
rm go.sum rm go.sum

View file

@ -74,7 +74,7 @@ func initParserMode() {
} }
} }
func isGoFile(f fs.FileInfo) bool { func isGoFile(f fs.DirEntry) bool {
// ignore non-Go files // ignore non-Go files
name := f.Name() name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
@ -164,7 +164,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
return err return err
} }
func visitFile(path string, f fs.FileInfo, err error) error { func visitFile(path string, f fs.DirEntry, err error) error {
if err == nil && isGoFile(f) { if err == nil && isGoFile(f) {
err = processFile(path, nil, os.Stdout, false) err = processFile(path, nil, os.Stdout, false)
} }
@ -177,7 +177,7 @@ func visitFile(path string, f fs.FileInfo, err error) error {
} }
func walkDir(path string) { func walkDir(path string) {
filepath.Walk(path, visitFile) filepath.WalkDir(path, visitFile)
} }
func main() { func main() {

View file

@ -108,12 +108,12 @@ func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
func genFilenames(t *testing.T, filenames chan<- string) { func genFilenames(t *testing.T, filenames chan<- string) {
defer close(filenames) defer close(filenames)
handleFile := func(filename string, fi fs.FileInfo, err error) error { handleFile := func(filename string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return nil return nil
} }
if isGoFile(fi) { if isGoFile(d) {
filenames <- filename filenames <- filename
nfiles++ nfiles++
} }
@ -124,13 +124,13 @@ func genFilenames(t *testing.T, filenames chan<- string) {
if *files != "" { if *files != "" {
for _, filename := range strings.Split(*files, ",") { for _, filename := range strings.Split(*files, ",") {
fi, err := os.Stat(filename) fi, err := os.Stat(filename)
handleFile(filename, fi, err) handleFile(filename, &statDirEntry{fi}, err)
} }
return // ignore files under -root return // ignore files under -root
} }
// otherwise, test all Go files under *root // otherwise, test all Go files under *root
filepath.Walk(*root, handleFile) filepath.WalkDir(*root, handleFile)
} }
func TestAll(t *testing.T) { func TestAll(t *testing.T) {
@ -164,3 +164,12 @@ func TestAll(t *testing.T) {
fmt.Printf("processed %d files\n", nfiles) fmt.Printf("processed %d files\n", nfiles)
} }
} }
type statDirEntry struct {
info fs.FileInfo
}
func (d *statDirEntry) Name() string { return d.info.Name() }
func (d *statDirEntry) IsDir() bool { return d.info.IsDir() }
func (d *statDirEntry) Type() fs.FileMode { return d.info.Mode().Type() }
func (d *statDirEntry) Info() (fs.FileInfo, error) { return d.info, nil }

View file

@ -11,6 +11,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"reflect" "reflect"
"strings"
"testing" "testing"
) )
@ -146,3 +147,33 @@ func TestFindAndHash(t *testing.T) {
} }
} }
} }
func TestExcludedReader(t *testing.T) {
const s = "0123456789abcdefghijklmn"
tests := []struct {
start, end int64 // excluded range
results []string // expected results of reads
}{
{12, 15, []string{"0123456789", "ab\x00\x00\x00fghij", "klmn"}}, // within one read
{8, 21, []string{"01234567\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "\x00lmn"}}, // across multiple reads
{10, 20, []string{"0123456789", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "klmn"}}, // a whole read
{0, 5, []string{"\x00\x00\x00\x00\x0056789", "abcdefghij", "klmn"}}, // start
{12, 24, []string{"0123456789", "ab\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00"}}, // end
}
p := make([]byte, 10)
for _, test := range tests {
r := &excludedReader{strings.NewReader(s), 0, test.start, test.end}
for _, res := range test.results {
n, err := r.Read(p)
if err != nil {
t.Errorf("read failed: %v", err)
}
if n != len(res) {
t.Errorf("unexpected number of bytes read: want %d, got %d", len(res), n)
}
if string(p[:n]) != res {
t.Errorf("unexpected bytes: want %q, got %q", res, p[:n])
}
}
}
}

View file

@ -6,7 +6,9 @@ package buildid
import ( import (
"bytes" "bytes"
"cmd/internal/codesign"
"crypto/sha256" "crypto/sha256"
"debug/macho"
"fmt" "fmt"
"io" "io"
) )
@ -26,6 +28,11 @@ func FindAndHash(r io.Reader, id string, bufSize int) (matches []int64, hash [32
zeros := make([]byte, len(id)) zeros := make([]byte, len(id))
idBytes := []byte(id) idBytes := []byte(id)
// For Mach-O files, we want to exclude the code signature.
// The code signature contains hashes of the whole file (except the signature
// itself), including the buildid. So the buildid cannot contain the signature.
r = excludeMachoCodeSignature(r)
// The strategy is to read the file through buf, looking for id, // The strategy is to read the file through buf, looking for id,
// but we need to worry about what happens if id is broken up // but we need to worry about what happens if id is broken up
// and returned in parts by two different reads. // and returned in parts by two different reads.
@ -87,5 +94,69 @@ func Rewrite(w io.WriterAt, pos []int64, id string) error {
return err return err
} }
} }
// Update Mach-O code signature, if any.
if f, cmd, ok := findMachoCodeSignature(w); ok {
if codesign.Size(int64(cmd.Dataoff), "a.out") == int64(cmd.Datasize) {
// Update the signature if the size matches, so we don't need to
// fix up headers. Binaries generated by the Go linker should have
// the expected size. Otherwise skip.
text := f.Segment("__TEXT")
cs := make([]byte, cmd.Datasize)
codesign.Sign(cs, w.(io.Reader), "a.out", int64(cmd.Dataoff), int64(text.Offset), int64(text.Filesz), f.Type == macho.TypeExec)
if _, err := w.WriteAt(cs, int64(cmd.Dataoff)); err != nil {
return err
}
}
}
return nil return nil
} }
func excludeMachoCodeSignature(r io.Reader) io.Reader {
_, cmd, ok := findMachoCodeSignature(r)
if !ok {
return r
}
return &excludedReader{r, 0, int64(cmd.Dataoff), int64(cmd.Dataoff + cmd.Datasize)}
}
// excludedReader wraps an io.Reader. Reading from it returns the bytes from
// the underlying reader, except that when the byte offset is within the
// range between start and end, it returns zero bytes.
type excludedReader struct {
r io.Reader
off int64 // current offset
start, end int64 // the range to be excluded (read as zero)
}
func (r *excludedReader) Read(p []byte) (int, error) {
n, err := r.r.Read(p)
if n > 0 && r.off+int64(n) > r.start && r.off < r.end {
cstart := r.start - r.off
if cstart < 0 {
cstart = 0
}
cend := r.end - r.off
if cend > int64(n) {
cend = int64(n)
}
zeros := make([]byte, cend-cstart)
copy(p[cstart:cend], zeros)
}
r.off += int64(n)
return n, err
}
func findMachoCodeSignature(r interface{}) (*macho.File, codesign.CodeSigCmd, bool) {
ra, ok := r.(io.ReaderAt)
if !ok {
return nil, codesign.CodeSigCmd{}, false
}
f, err := macho.NewFile(ra)
if err != nil {
return nil, codesign.CodeSigCmd{}, false
}
cmd, ok := codesign.FindCodeSigCmd(f)
return f, cmd, ok
}

View file

@ -0,0 +1,268 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package codesign provides basic functionalities for
// ad-hoc code signing of Mach-O files.
//
// This is not a general tool for code-signing. It is made
// specifically for the Go toolchain. It uses the same
// ad-hoc signing algorithm as the Darwin linker.
package codesign
import (
"crypto/sha256"
"debug/macho"
"encoding/binary"
"io"
)
// Code signature layout.
//
// The code signature is a block of bytes that contains
// a SuperBlob, which contains one or more Blobs. For ad-hoc
// signing, a single CodeDirectory Blob suffices.
//
// A SuperBlob starts with its header (the binary representation
// of the SuperBlob struct), followed by a list of (in our case,
// one) Blobs (offset and size). A CodeDirectory Blob starts
// with its head (the binary representation of CodeDirectory struct),
// followed by the identifier (as a C string) and the hashes, at
// the corresponding offsets.
//
// The signature data must be included in the __LINKEDIT segment.
// In the Mach-O file header, an LC_CODE_SIGNATURE load command
// points to the data.
const (
pageSizeBits = 12
pageSize = 1 << pageSizeBits
)
const LC_CODE_SIGNATURE = 0x1d
// Constants and struct layouts are from
// https://opensource.apple.com/source/xnu/xnu-4903.270.47/osfmk/kern/cs_blobs.h
const (
CSMAGIC_REQUIREMENT = 0xfade0c00 // single Requirement blob
CSMAGIC_REQUIREMENTS = 0xfade0c01 // Requirements vector (internal requirements)
CSMAGIC_CODEDIRECTORY = 0xfade0c02 // CodeDirectory blob
CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 // embedded form of signature data
CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1 // multi-arch collection of embedded signatures
CSSLOT_CODEDIRECTORY = 0 // slot index for CodeDirectory
)
const (
CS_HASHTYPE_SHA1 = 1
CS_HASHTYPE_SHA256 = 2
CS_HASHTYPE_SHA256_TRUNCATED = 3
CS_HASHTYPE_SHA384 = 4
)
const (
CS_EXECSEG_MAIN_BINARY = 0x1 // executable segment denotes main binary
CS_EXECSEG_ALLOW_UNSIGNED = 0x10 // allow unsigned pages (for debugging)
CS_EXECSEG_DEBUGGER = 0x20 // main binary is debugger
CS_EXECSEG_JIT = 0x40 // JIT enabled
CS_EXECSEG_SKIP_LV = 0x80 // skip library validation
CS_EXECSEG_CAN_LOAD_CDHASH = 0x100 // can bless cdhash for execution
CS_EXECSEG_CAN_EXEC_CDHASH = 0x200 // can execute blessed cdhash
)
type Blob struct {
typ uint32 // type of entry
offset uint32 // offset of entry
// data follows
}
func (b *Blob) put(out []byte) []byte {
out = put32be(out, b.typ)
out = put32be(out, b.offset)
return out
}
const blobSize = 2 * 4
type SuperBlob struct {
magic uint32 // magic number
length uint32 // total length of SuperBlob
count uint32 // number of index entries following
// blobs []Blob
}
func (s *SuperBlob) put(out []byte) []byte {
out = put32be(out, s.magic)
out = put32be(out, s.length)
out = put32be(out, s.count)
return out
}
const superBlobSize = 3 * 4
type CodeDirectory struct {
magic uint32 // magic number (CSMAGIC_CODEDIRECTORY)
length uint32 // total length of CodeDirectory blob
version uint32 // compatibility version
flags uint32 // setup and mode flags
hashOffset uint32 // offset of hash slot element at index zero
identOffset uint32 // offset of identifier string
nSpecialSlots uint32 // number of special hash slots
nCodeSlots uint32 // number of ordinary (code) hash slots
codeLimit uint32 // limit to main image signature range
hashSize uint8 // size of each hash in bytes
hashType uint8 // type of hash (cdHashType* constants)
_pad1 uint8 // unused (must be zero)
pageSize uint8 // log2(page size in bytes); 0 => infinite
_pad2 uint32 // unused (must be zero)
scatterOffset uint32
teamOffset uint32
_pad3 uint32
codeLimit64 uint64
execSegBase uint64
execSegLimit uint64
execSegFlags uint64
// data follows
}
func (c *CodeDirectory) put(out []byte) []byte {
out = put32be(out, c.magic)
out = put32be(out, c.length)
out = put32be(out, c.version)
out = put32be(out, c.flags)
out = put32be(out, c.hashOffset)
out = put32be(out, c.identOffset)
out = put32be(out, c.nSpecialSlots)
out = put32be(out, c.nCodeSlots)
out = put32be(out, c.codeLimit)
out = put8(out, c.hashSize)
out = put8(out, c.hashType)
out = put8(out, c._pad1)
out = put8(out, c.pageSize)
out = put32be(out, c._pad2)
out = put32be(out, c.scatterOffset)
out = put32be(out, c.teamOffset)
out = put32be(out, c._pad3)
out = put64be(out, c.codeLimit64)
out = put64be(out, c.execSegBase)
out = put64be(out, c.execSegLimit)
out = put64be(out, c.execSegFlags)
return out
}
const codeDirectorySize = 13*4 + 4 + 4*8
// CodeSigCmd is Mach-O LC_CODE_SIGNATURE load command.
type CodeSigCmd struct {
Cmd uint32 // LC_CODE_SIGNATURE
Cmdsize uint32 // sizeof this command (16)
Dataoff uint32 // file offset of data in __LINKEDIT segment
Datasize uint32 // file size of data in __LINKEDIT segment
}
func FindCodeSigCmd(f *macho.File) (CodeSigCmd, bool) {
get32 := f.ByteOrder.Uint32
for _, l := range f.Loads {
data := l.Raw()
cmd := get32(data)
if cmd == LC_CODE_SIGNATURE {
return CodeSigCmd{
cmd,
get32(data[4:]),
get32(data[8:]),
get32(data[12:]),
}, true
}
}
return CodeSigCmd{}, false
}
func put32be(b []byte, x uint32) []byte { binary.BigEndian.PutUint32(b, x); return b[4:] }
func put64be(b []byte, x uint64) []byte { binary.BigEndian.PutUint64(b, x); return b[8:] }
func put8(b []byte, x uint8) []byte { b[0] = x; return b[1:] }
func puts(b, s []byte) []byte { n := copy(b, s); return b[n:] }
// Size computes the size of the code signature.
// id is the identifier used for signing (a field in CodeDirectory blob, which
// has no significance in ad-hoc signing).
func Size(codeSize int64, id string) int64 {
nhashes := (codeSize + pageSize - 1) / pageSize
idOff := int64(codeDirectorySize)
hashOff := idOff + int64(len(id)+1)
cdirSz := hashOff + nhashes*sha256.Size
return int64(superBlobSize+blobSize) + cdirSz
}
// Sign generates an ad-hoc code signature and writes it to out.
// out must have length at least Size(codeSize, id).
// data is the file content without the signature, of size codeSize.
// textOff and textSize is the file offset and size of the text segment.
// isMain is true if this is a main executable.
// id is the identifier used for signing (a field in CodeDirectory blob, which
// has no significance in ad-hoc signing).
func Sign(out []byte, data io.Reader, id string, codeSize, textOff, textSize int64, isMain bool) {
nhashes := (codeSize + pageSize - 1) / pageSize
idOff := int64(codeDirectorySize)
hashOff := idOff + int64(len(id)+1)
sz := Size(codeSize, id)
// emit blob headers
sb := SuperBlob{
magic: CSMAGIC_EMBEDDED_SIGNATURE,
length: uint32(sz),
count: 1,
}
blob := Blob{
typ: CSSLOT_CODEDIRECTORY,
offset: superBlobSize + blobSize,
}
cdir := CodeDirectory{
magic: CSMAGIC_CODEDIRECTORY,
length: uint32(sz) - (superBlobSize + blobSize),
version: 0x20400,
flags: 0x20002, // adhoc | linkerSigned
hashOffset: uint32(hashOff),
identOffset: uint32(idOff),
nCodeSlots: uint32(nhashes),
codeLimit: uint32(codeSize),
hashSize: sha256.Size,
hashType: CS_HASHTYPE_SHA256,
pageSize: uint8(pageSizeBits),
execSegBase: uint64(textOff),
execSegLimit: uint64(textSize),
}
if isMain {
cdir.execSegFlags = CS_EXECSEG_MAIN_BINARY
}
outp := out
outp = sb.put(outp)
outp = blob.put(outp)
outp = cdir.put(outp)
// emit the identifier
outp = puts(outp, []byte(id+"\000"))
// emit hashes
var buf [pageSize]byte
h := sha256.New()
p := 0
for p < int(codeSize) {
n, err := io.ReadFull(data, buf[:])
if err == io.EOF {
break
}
if err != nil && err != io.ErrUnexpectedEOF {
panic(err)
}
if p+n > int(codeSize) {
n = int(codeSize) - p
}
p += n
h.Reset()
h.Write(buf[:n])
b := h.Sum(nil)
outp = puts(outp, b[:])
}
}

View file

@ -33,7 +33,7 @@ func findGorootModules(t *testing.T) []gorootModule {
goBin := testenv.GoToolPath(t) goBin := testenv.GoToolPath(t)
goroot.once.Do(func() { goroot.once.Do(func() {
goroot.err = filepath.Walk(runtime.GOROOT(), func(path string, info fs.FileInfo, err error) error { goroot.err = filepath.WalkDir(runtime.GOROOT(), func(path string, info fs.DirEntry, err error) error {
if err != nil { if err != nil {
return err return err
} }

View file

@ -1777,15 +1777,15 @@ func instructionsForProg(p *obj.Prog) []*instruction {
case ABGEZ: case ABGEZ:
ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg) ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
case ABGT: case ABGT:
ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.Reg), uint32(p.From.Reg) ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg)
case ABGTU: case ABGTU:
ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.Reg), uint32(p.From.Reg) ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg)
case ABGTZ: case ABGTZ:
ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
case ABLE: case ABLE:
ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.Reg), uint32(p.From.Reg) ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg)
case ABLEU: case ABLEU:
ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.Reg), uint32(p.From.Reg) ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg)
case ABLEZ: case ABLEZ:
ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
case ABLTZ: case ABLTZ:

View file

@ -11,6 +11,8 @@ import (
) )
func testBEQZ(a int64) (r bool) func testBEQZ(a int64) (r bool)
func testBGE(a, b int64) (r bool)
func testBGEU(a, b int64) (r bool)
func testBGEZ(a int64) (r bool) func testBGEZ(a int64) (r bool)
func testBGT(a, b int64) (r bool) func testBGT(a, b int64) (r bool)
func testBGTU(a, b int64) (r bool) func testBGTU(a, b int64) (r bool)
@ -18,6 +20,8 @@ func testBGTZ(a int64) (r bool)
func testBLE(a, b int64) (r bool) func testBLE(a, b int64) (r bool)
func testBLEU(a, b int64) (r bool) func testBLEU(a, b int64) (r bool)
func testBLEZ(a int64) (r bool) func testBLEZ(a int64) (r bool)
func testBLT(a, b int64) (r bool)
func testBLTU(a, b int64) (r bool)
func testBLTZ(a int64) (r bool) func testBLTZ(a int64) (r bool)
func testBNEZ(a int64) (r bool) func testBNEZ(a int64) (r bool)
@ -29,30 +33,75 @@ func TestBranchCondition(t *testing.T) {
fn func(a, b int64) bool fn func(a, b int64) bool
want bool want bool
}{ }{
{"BGT", 0, 1, testBGT, true}, {"BGE", 0, 1, testBGE, false},
{"BGE", 0, 0, testBGE, true},
{"BGE", 0, -1, testBGE, true},
{"BGE", -1, 0, testBGE, false},
{"BGE", 1, 0, testBGE, true},
{"BGEU", 0, 1, testBGEU, false},
{"BGEU", 0, 0, testBGEU, true},
{"BGEU", 0, -1, testBGEU, false},
{"BGEU", -1, 0, testBGEU, true},
{"BGEU", 1, 0, testBGEU, true},
{"BGT", 0, 1, testBGT, false},
{"BGT", 0, 0, testBGT, false}, {"BGT", 0, 0, testBGT, false},
{"BGT", 0, -1, testBGT, false}, {"BGT", 0, -1, testBGT, true},
{"BGT", -1, 0, testBGT, true}, {"BGT", -1, 0, testBGT, false},
{"BGT", 1, 0, testBGT, false}, {"BGT", 1, 0, testBGT, true},
{"BGTU", 0, 1, testBGTU, true}, {"BGTU", 0, 1, testBGTU, false},
{"BGTU", 0, -1, testBGTU, true}, {"BGTU", 0, 0, testBGTU, false},
{"BGTU", -1, 0, testBGTU, false}, {"BGTU", 0, -1, testBGTU, false},
{"BGTU", 1, 0, testBGTU, false}, {"BGTU", -1, 0, testBGTU, true},
{"BLE", 0, 1, testBLE, false}, {"BGTU", 1, 0, testBGTU, true},
{"BLE", 0, -1, testBLE, true}, {"BLE", 0, 1, testBLE, true},
{"BLE", 0, 0, testBLE, true}, {"BLE", 0, 0, testBLE, true},
{"BLE", -1, 0, testBLE, false}, {"BLE", 0, -1, testBLE, false},
{"BLE", 1, 0, testBLE, true}, {"BLE", -1, 0, testBLE, true},
{"BLEU", 0, 1, testBLEU, false}, {"BLE", 1, 0, testBLE, false},
{"BLEU", 0, -1, testBLEU, false}, {"BLEU", 0, 1, testBLEU, true},
{"BLEU", 0, 0, testBLEU, true}, {"BLEU", 0, 0, testBLEU, true},
{"BLEU", -1, 0, testBLEU, true}, {"BLEU", 0, -1, testBLEU, true},
{"BLEU", 1, 0, testBLEU, true}, {"BLEU", -1, 0, testBLEU, false},
{"BLEU", 1, 0, testBLEU, false},
{"BLT", 0, 1, testBLT, true},
{"BLT", 0, 0, testBLT, false},
{"BLT", 0, -1, testBLT, false},
{"BLT", -1, 0, testBLT, true},
{"BLT", 1, 0, testBLT, false},
{"BLTU", 0, 1, testBLTU, true},
{"BLTU", 0, 0, testBLTU, false},
{"BLTU", 0, -1, testBLTU, true},
{"BLTU", -1, 0, testBLTU, false},
{"BLTU", 1, 0, testBLTU, false},
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.ins, func(t *testing.T) { t.Run(test.ins, func(t *testing.T) {
var fn func(a, b int64) bool
switch test.ins {
case "BGE":
fn = func(a, b int64) bool { return a >= b }
case "BGEU":
fn = func(a, b int64) bool { return uint64(a) >= uint64(b) }
case "BGT":
fn = func(a, b int64) bool { return a > b }
case "BGTU":
fn = func(a, b int64) bool { return uint64(a) > uint64(b) }
case "BLE":
fn = func(a, b int64) bool { return a <= b }
case "BLEU":
fn = func(a, b int64) bool { return uint64(a) <= uint64(b) }
case "BLT":
fn = func(a, b int64) bool { return a < b }
case "BLTU":
fn = func(a, b int64) bool { return uint64(a) < uint64(b) }
default:
t.Fatalf("Unknown instruction %q", test.ins)
}
if got := fn(test.a, test.b); got != test.want {
t.Errorf("Go %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want)
}
if got := test.fn(test.a, test.b); got != test.want { if got := test.fn(test.a, test.b); got != test.want {
t.Errorf("%v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want) t.Errorf("Assembly %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want)
} }
}) })
} }

View file

@ -16,6 +16,28 @@ b:
MOV X6, r+8(FP) MOV X6, r+8(FP)
RET RET
// func testBGE(a, b int64) (r bool)
TEXT ·testBGE(SB),NOSPLIT,$0-0
MOV a+0(FP), X5
MOV b+8(FP), X6
MOV $1, X7
BGE X5, X6, b
MOV $0, X7
b:
MOV X7, r+16(FP)
RET
// func testBGEU(a, b int64) (r bool)
TEXT ·testBGEU(SB),NOSPLIT,$0-0
MOV a+0(FP), X5
MOV b+8(FP), X6
MOV $1, X7
BGEU X5, X6, b
MOV $0, X7
b:
MOV X7, r+16(FP)
RET
// func testBGEZ(a int64) (r bool) // func testBGEZ(a int64) (r bool)
TEXT ·testBGEZ(SB),NOSPLIT,$0-0 TEXT ·testBGEZ(SB),NOSPLIT,$0-0
MOV a+0(FP), X5 MOV a+0(FP), X5
@ -90,6 +112,28 @@ b:
MOV X6, r+8(FP) MOV X6, r+8(FP)
RET RET
// func testBLT(a, b int64) (r bool)
TEXT ·testBLT(SB),NOSPLIT,$0-0
MOV a+0(FP), X5
MOV b+8(FP), X6
MOV $1, X7
BLT X5, X6, b
MOV $0, X7
b:
MOV X7, r+16(FP)
RET
// func testBLTU(a, b int64) (r bool)
TEXT ·testBLTU(SB),NOSPLIT,$0-0
MOV a+0(FP), X5
MOV b+8(FP), X6
MOV $1, X7
BLTU X5, X6, b
MOV $0, X7
b:
MOV X7, r+16(FP)
RET
// func testBLTZ(a int64) (r bool) // func testBLTZ(a int64) (r bool)
TEXT ·testBLTZ(SB),NOSPLIT,$0-0 TEXT ·testBLTZ(SB),NOSPLIT,$0-0
MOV a+0(FP), X5 MOV a+0(FP), X5

View file

@ -413,11 +413,7 @@ func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
case objabi.R_CALL: case objabi.R_CALL:
if siz == 4 { if siz == 4 {
if ldr.SymType(r.Xsym) == sym.SDYNIMPORT { if ldr.SymType(r.Xsym) == sym.SDYNIMPORT {
if ctxt.DynlinkingGo() { out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
} else {
out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
}
} else { } else {
out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32) out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
} }

View file

@ -35,11 +35,12 @@ func (mode *BuildMode) Set(s string) error {
default: default:
return fmt.Errorf("invalid buildmode: %q", s) return fmt.Errorf("invalid buildmode: %q", s)
case "exe": case "exe":
if objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" { switch objabi.GOOS + "/" + objabi.GOARCH {
*mode = BuildModePIE // On darwin/arm64 everything is PIE. case "darwin/arm64", "windows/arm": // On these platforms, everything is PIE
break *mode = BuildModePIE
default:
*mode = BuildModeExe
} }
*mode = BuildModeExe
case "pie": case "pie":
switch objabi.GOOS { switch objabi.GOOS {
case "aix", "android", "linux", "windows", "darwin", "ios": case "aix", "android", "linux", "windows", "darwin", "ios":

View file

@ -298,6 +298,11 @@ func (ctxt *Link) CanUsePlugins() bool {
return ctxt.canUsePlugins return ctxt.canUsePlugins
} }
// NeedCodeSign reports whether we need to code-sign the output binary.
func (ctxt *Link) NeedCodeSign() bool {
return ctxt.IsDarwin() && ctxt.IsARM64()
}
var ( var (
dynlib []string dynlib []string
ldflag []string ldflag []string
@ -1642,6 +1647,12 @@ func (ctxt *Link) hostlink() {
Exitf("%s: %v", os.Args[0], err) Exitf("%s: %v", os.Args[0], err)
} }
} }
if ctxt.NeedCodeSign() {
err := machoCodeSign(ctxt, *flagOutfile)
if err != nil {
Exitf("%s: code signing failed: %v", os.Args[0], err)
}
}
} }
var createTrivialCOnce sync.Once var createTrivialCOnce sync.Once

View file

@ -6,6 +6,7 @@ package ld
import ( import (
"bytes" "bytes"
"cmd/internal/codesign"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/loader" "cmd/link/internal/loader"
@ -17,6 +18,7 @@ import (
"os" "os"
"sort" "sort"
"strings" "strings"
"unsafe"
) )
type MachoHdr struct { type MachoHdr struct {
@ -245,6 +247,8 @@ const (
BIND_SUBOPCODE_THREADED_APPLY = 0x01 BIND_SUBOPCODE_THREADED_APPLY = 0x01
) )
const machoHeaderSize64 = 8 * 4 // size of 64-bit Mach-O header
// Mach-O file writing // Mach-O file writing
// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html // https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
@ -643,6 +647,8 @@ func asmbMacho(ctxt *Link) {
} }
ctxt.Out.SeekSet(0) ctxt.Out.SeekSet(0)
ldr := ctxt.loader
/* apple MACH */ /* apple MACH */
va := *FlagTextAddr - int64(HEADR) va := *FlagTextAddr - int64(HEADR)
@ -757,25 +763,27 @@ func asmbMacho(ctxt *Link) {
} }
} }
var codesigOff int64
if !*FlagD { if !*FlagD {
ldr := ctxt.loader // must match doMachoLink below
// must match domacholink below
s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0)) s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
s2 := ldr.SymSize(ldr.Lookup(".machobind", 0)) s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0)) s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT) s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT) s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0)) s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
if ctxt.LinkMode != LinkExternal { if ctxt.LinkMode != LinkExternal {
ms := newMachoSeg("__LINKEDIT", 0) ms := newMachoSeg("__LINKEDIT", 0)
ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound))) ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound)))
ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6) ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + s7)
ms.fileoffset = uint64(linkoff) ms.fileoffset = uint64(linkoff)
ms.filesize = ms.vsize ms.filesize = ms.vsize
ms.prot1 = 1 ms.prot1 = 1
ms.prot2 = 1 ms.prot2 = 1
codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6
} }
if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() { if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
@ -814,12 +822,31 @@ func asmbMacho(ctxt *Link) {
stringtouint32(ml.data[4:], lib) stringtouint32(ml.data[4:], lib)
} }
} }
if ctxt.IsInternal() && ctxt.NeedCodeSign() {
ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2)
ml.data[0] = uint32(codesigOff)
ml.data[1] = uint32(s7)
}
} }
a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode) a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
if int32(a) > HEADR { if int32(a) > HEADR {
Exitf("HEADR too small: %d > %d", a, HEADR) Exitf("HEADR too small: %d > %d", a, HEADR)
} }
// Now we have written everything. Compute the code signature (which
// is a hash of the file content, so it must be done at last.)
if ctxt.IsInternal() && ctxt.NeedCodeSign() {
cs := ldr.Lookup(".machocodesig", 0)
data := ctxt.Out.Data()
if int64(len(data)) != codesigOff {
panic("wrong size")
}
codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(Segtext.Fileoff), int64(Segtext.Filelen), ctxt.IsExe() || ctxt.IsPIE())
ctxt.Out.SeekSet(codesigOff)
ctxt.Out.Write(ldr.Data(cs))
}
} }
func symkind(ldr *loader.Loader, s loader.Sym) int { func symkind(ldr *loader.Loader, s loader.Sym) int {
@ -1057,7 +1084,6 @@ func machodysymtab(ctxt *Link, base int64) {
func doMachoLink(ctxt *Link) int64 { func doMachoLink(ctxt *Link) int64 {
machosymtab(ctxt) machosymtab(ctxt)
machoDyldInfo(ctxt) machoDyldInfo(ctxt)
ldr := ctxt.loader ldr := ctxt.loader
@ -1070,6 +1096,8 @@ func doMachoLink(ctxt *Link) int64 {
s5 := ctxt.ArchSyms.LinkEditGOT s5 := ctxt.ArchSyms.LinkEditGOT
s6 := ldr.Lookup(".machosymstr", 0) s6 := ldr.Lookup(".machosymstr", 0)
size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
// Force the linkedit section to end on a 16-byte // Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries // boundary. This allows pure (non-cgo) Go binaries
// to be code signed correctly. // to be code signed correctly.
@ -1087,13 +1115,14 @@ func doMachoLink(ctxt *Link) int64 {
// boundary, codesign_allocate will not need to apply // boundary, codesign_allocate will not need to apply
// any alignment padding itself, working around the // any alignment padding itself, working around the
// issue. // issue.
s6b := ldr.MakeSymbolUpdater(s6) if size%16 != 0 {
for s6b.Size()%16 != 0 { n := 16 - size%16
s6b.AddUint8(0) s6b := ldr.MakeSymbolUpdater(s6)
s6b.Grow(s6b.Size() + n)
s6b.SetSize(s6b.Size() + n)
size += n
} }
size := int(ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6))
if size > 0 { if size > 0 {
linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segrelrodata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound)) linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segrelrodata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
ctxt.Out.SeekSet(linkoff) ctxt.Out.SeekSet(linkoff)
@ -1104,9 +1133,13 @@ func doMachoLink(ctxt *Link) int64 {
ctxt.Out.Write(ldr.Data(s4)) ctxt.Out.Write(ldr.Data(s4))
ctxt.Out.Write(ldr.Data(s5)) ctxt.Out.Write(ldr.Data(s5))
ctxt.Out.Write(ldr.Data(s6)) ctxt.Out.Write(ldr.Data(s6))
// Add code signature if necessary. This must be the last.
s7 := machoCodeSigSym(ctxt, linkoff+size)
size += ldr.SymSize(s7)
} }
return Rnd(int64(size), int64(*FlagRound)) return Rnd(size, int64(*FlagRound))
} }
func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) { func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
@ -1378,3 +1411,94 @@ func machoDyldInfo(ctxt *Link) {
// e.g. dlsym'd. But internal linking is not the default in that case, so // e.g. dlsym'd. But internal linking is not the default in that case, so
// it is fine. // it is fine.
} }
// machoCodeSigSym creates and returns a symbol for code signature.
// The symbol context is left as zeros, which will be generated at the end
// (as it depends on the rest of the file).
func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
ldr := ctxt.loader
cs := ldr.CreateSymForUpdate(".machocodesig", 0)
if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
return cs.Sym()
}
sz := codesign.Size(codeSize, "a.out")
cs.Grow(sz)
cs.SetSize(sz)
return cs.Sym()
}
// machoCodeSign code-signs Mach-O file fname with an ad-hoc signature.
// This is used for updating an external linker generated binary.
func machoCodeSign(ctxt *Link, fname string) error {
f, err := os.OpenFile(fname, os.O_RDWR, 0)
if err != nil {
return err
}
defer f.Close()
mf, err := macho.NewFile(f)
if err != nil {
return err
}
if mf.Magic != macho.Magic64 {
Exitf("not 64-bit Mach-O file: %s", fname)
}
// Find existing LC_CODE_SIGNATURE and __LINKEDIT segment
var sigOff, sigSz, csCmdOff, linkeditOff int64
var linkeditSeg, textSeg *macho.Segment
loadOff := int64(machoHeaderSize64)
get32 := mf.ByteOrder.Uint32
for _, l := range mf.Loads {
data := l.Raw()
cmd, sz := get32(data), get32(data[4:])
if cmd == LC_CODE_SIGNATURE {
sigOff = int64(get32(data[8:]))
sigSz = int64(get32(data[12:]))
csCmdOff = loadOff
}
if seg, ok := l.(*macho.Segment); ok {
switch seg.Name {
case "__LINKEDIT":
linkeditSeg = seg
linkeditOff = loadOff
case "__TEXT":
textSeg = seg
}
}
loadOff += int64(sz)
}
if sigOff == 0 {
// The C linker doesn't generate a signed binary, for some reason.
// Skip.
return nil
}
sz := codesign.Size(sigOff, "a.out")
if sz != sigSz {
// Update the load command,
var tmp [8]byte
mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
_, err = f.WriteAt(tmp[:4], csCmdOff+12)
if err != nil {
return err
}
// Uodate the __LINKEDIT segment.
segSz := sigOff + sz - int64(linkeditSeg.Offset)
mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
if err != nil {
return err
}
_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
if err != nil {
return err
}
}
cs := make([]byte, sz)
codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
_, err = f.WriteAt(cs, sigOff)
return err
}

View file

@ -113,6 +113,7 @@ func (out *OutBuf) Close() error {
} }
if out.isMmapped() { if out.isMmapped() {
out.copyHeap() out.copyHeap()
out.purgeSignatureCache()
out.munmap() out.munmap()
} }
if out.f == nil { if out.f == nil {
@ -135,6 +136,15 @@ func (out *OutBuf) isMmapped() bool {
return len(out.buf) != 0 return len(out.buf) != 0
} }
// Data returns the whole written OutBuf as a byte slice.
func (out *OutBuf) Data() []byte {
if out.isMmapped() {
out.copyHeap()
return out.buf
}
return out.heap
}
// copyHeap copies the heap to the mmapped section of memory, returning true if // copyHeap copies the heap to the mmapped section of memory, returning true if
// a copy takes place. // a copy takes place.
func (out *OutBuf) copyHeap() bool { func (out *OutBuf) copyHeap() bool {

View file

@ -36,3 +36,12 @@ func (out *OutBuf) fallocate(size uint64) error {
return nil return nil
} }
func (out *OutBuf) purgeSignatureCache() {
// Apparently, the Darwin kernel may cache the code signature at mmap.
// When we mmap the output buffer, it doesn't have a code signature
// (as we haven't generated one). Invalidate the kernel cache now that
// we have generated the signature. See issue #42684.
syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&out.buf[0])), uintptr(len(out.buf)), syscall.MS_INVALIDATE)
// Best effort. Ignore error.
}

View file

@ -0,0 +1,9 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !darwin
package ld
func (out *OutBuf) purgeSignatureCache() {}

View file

@ -138,6 +138,9 @@ func Compare(v, w string) int {
// Max canonicalizes its arguments and then returns the version string // Max canonicalizes its arguments and then returns the version string
// that compares greater. // that compares greater.
//
// Deprecated: use Compare instead. In most cases, returning a canonicalized
// version is not expected or desired.
func Max(v, w string) string { func Max(v, w string) string {
v = Canonical(v) v = Canonical(v)
w = Canonical(w) w = Canonical(w)

View file

@ -29,7 +29,7 @@ golang.org/x/arch/x86/x86asm
golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519
golang.org/x/crypto/ed25519/internal/edwards25519 golang.org/x/crypto/ed25519/internal/edwards25519
golang.org/x/crypto/ssh/terminal golang.org/x/crypto/ssh/terminal
# golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 # golang.org/x/mod v0.4.0
## explicit ## explicit
golang.org/x/mod/internal/lazyregexp golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile golang.org/x/mod/modfile

View file

@ -31,7 +31,7 @@ func TestGZIPFilesHaveZeroMTimes(t *testing.T) {
t.Fatal("error evaluating GOROOT: ", err) t.Fatal("error evaluating GOROOT: ", err)
} }
var files []string var files []string
err = filepath.Walk(goroot, func(path string, info fs.FileInfo, err error) error { err = filepath.WalkDir(goroot, func(path string, info fs.DirEntry, err error) error {
if err != nil { if err != nil {
return err return err
} }

View file

@ -722,7 +722,7 @@ func (p *ExtendedGroupElement) FromBytes(s *[32]byte) bool {
FeOne(&p.Z) FeOne(&p.Z)
FeSquare(&u, &p.Y) FeSquare(&u, &p.Y)
FeMul(&v, &u, &d) FeMul(&v, &u, &d)
FeSub(&u, &u, &p.Z) // y = y^2-1 FeSub(&u, &u, &p.Z) // u = y^2-1
FeAdd(&v, &v, &p.Z) // v = dy^2+1 FeAdd(&v, &v, &p.Z) // v = dy^2+1
FeSquare(&v3, &v) FeSquare(&v3, &v)

View file

@ -47,7 +47,7 @@ type SyntaxError struct {
Offset int64 // error occurred after reading Offset bytes Offset int64 // error occurred after reading Offset bytes
} }
func (e *SyntaxError) Error() string { return "json: " + e.msg } func (e *SyntaxError) Error() string { return e.msg }
// A scanner is a JSON scanning state machine. // A scanner is a JSON scanning state machine.
// Callers call scan.reset and then pass bytes in one at a time // Callers call scan.reset and then pass bytes in one at a time

View file

@ -510,8 +510,8 @@ func listStdPkgs(goroot string) ([]string, error) {
var pkgs []string var pkgs []string
src := filepath.Join(goroot, "src") + string(filepath.Separator) src := filepath.Join(goroot, "src") + string(filepath.Separator)
walkFn := func(path string, fi fs.FileInfo, err error) error { walkFn := func(path string, d fs.DirEntry, err error) error {
if err != nil || !fi.IsDir() || path == src { if err != nil || !d.IsDir() || path == src {
return nil return nil
} }
@ -528,7 +528,7 @@ func listStdPkgs(goroot string) ([]string, error) {
pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/")) pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/"))
return nil return nil
} }
if err := filepath.Walk(src, walkFn); err != nil { if err := filepath.WalkDir(src, walkFn); err != nil {
return nil, err return nil, err
} }
return pkgs, nil return pkgs, nil

View file

@ -69,8 +69,8 @@ func main() {
flag.Parse() flag.Parse()
fset := token.NewFileSet() fset := token.NewFileSet()
nheadings := 0 nheadings := 0
err := filepath.Walk(*root, func(path string, fi fs.FileInfo, err error) error { err := filepath.WalkDir(*root, func(path string, info fs.DirEntry, err error) error {
if !fi.IsDir() { if !info.IsDir() {
return nil return nil
} }
pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments) pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments)

View file

@ -140,7 +140,7 @@ func ParseDir(fset *token.FileSet, path string, filter func(fs.FileInfo) bool, m
pkgs = make(map[string]*ast.Package) pkgs = make(map[string]*ast.Package)
for _, d := range list { for _, d := range list {
if strings.HasSuffix(d.Name(), ".go") && (filter == nil || filter(d)) { if !d.IsDir() && strings.HasSuffix(d.Name(), ".go") && (filter == nil || filter(d)) {
filename := filepath.Join(path, d.Name()) filename := filepath.Join(path, d.Name())
if src, err := ParseFile(fset, filename, nil, mode); err == nil { if src, err := ParseFile(fset, filename, nil, mode); err == nil {
name := src.Name.Name name := src.Name.Name

View file

@ -82,6 +82,14 @@ func TestParseDir(t *testing.T) {
} }
} }
func TestIssue42951(t *testing.T) {
path := "./testdata/issue42951"
_, err := ParseDir(token.NewFileSet(), path, nil, 0)
if err != nil {
t.Errorf("ParseDir(%s): %v", path, err)
}
}
func TestParseExpr(t *testing.T) { func TestParseExpr(t *testing.T) {
// just kicking the tires: // just kicking the tires:
// a valid arithmetic expression // a valid arithmetic expression

View file

@ -0,0 +1 @@
This file should not be parsed by ParseDir.

View file

@ -243,7 +243,7 @@ func TestEscape(t *testing.T) {
{ {
"badMarshaler", "badMarshaler",
`<button onclick='alert(1/{{.B}}in numbers)'>`, `<button onclick='alert(1/{{.B}}in numbers)'>`,
`<button onclick='alert(1/ /* json: error calling MarshalJSON for type *template.badMarshaler: json: invalid character &#39;f&#39; looking for beginning of object key string */null in numbers)'>`, `<button onclick='alert(1/ /* json: error calling MarshalJSON for type *template.badMarshaler: invalid character &#39;f&#39; looking for beginning of object key string */null in numbers)'>`,
}, },
{ {
"jsMarshaler", "jsMarshaler",

View file

@ -503,7 +503,7 @@ func makeText(name string) ([]byte, error) {
return nil, err return nil, err
} }
case "go": case "go":
err := filepath.Walk("../..", func(path string, info fs.FileInfo, err error) error { err := filepath.WalkDir("../..", func(path string, info fs.DirEntry, err error) error {
if err == nil && strings.HasSuffix(path, ".go") && !info.IsDir() { if err == nil && strings.HasSuffix(path, ".go") && !info.IsDir() {
file, err := ioutil.ReadFile(path) file, err := ioutil.ReadFile(path)
if err != nil { if err != nil {

View file

@ -3,6 +3,11 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package ioutil implements some I/O utility functions. // Package ioutil implements some I/O utility functions.
//
// As of Go 1.16, the same functionality is now provided
// by package io or package os, and those implementations
// should be preferred in new code.
// See the specific function documentation for details.
package ioutil package ioutil
import ( import (
@ -26,67 +31,30 @@ func ReadAll(r io.Reader) ([]byte, error) {
// A successful call returns err == nil, not err == EOF. Because ReadFile // A successful call returns err == nil, not err == EOF. Because ReadFile
// reads the whole file, it does not treat an EOF from Read as an error // reads the whole file, it does not treat an EOF from Read as an error
// to be reported. // to be reported.
//
// As of Go 1.16, this function simply calls os.ReadFile.
func ReadFile(filename string) ([]byte, error) { func ReadFile(filename string) ([]byte, error) {
f, err := os.Open(filename) return os.ReadFile(filename)
if err != nil {
return nil, err
}
defer f.Close()
// It's a good but not certain bet that FileInfo will tell us exactly how much to
// read, so let's try it but be prepared for the answer to be wrong.
const minRead = 512
var n int64 = minRead
if fi, err := f.Stat(); err == nil {
// As initial capacity for readAll, use Size + a little extra in case Size
// is zero, and to avoid another allocation after Read has filled the
// buffer. The readAll call will read into its allocated internal buffer
// cheaply. If the size was wrong, we'll either waste some space off the end
// or reallocate as needed, but in the overwhelmingly common case we'll get
// it just right.
if size := fi.Size() + minRead; size > n {
n = size
}
}
if int64(int(n)) != n {
n = minRead
}
b := make([]byte, 0, n)
for {
if len(b) == cap(b) {
// Add more capacity (let append pick how much).
b = append(b, 0)[:len(b)]
}
n, err := f.Read(b[len(b):cap(b)])
b = b[:len(b)+n]
if err != nil {
if err == io.EOF {
err = nil
}
return b, err
}
}
} }
// WriteFile writes data to a file named by filename. // WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm // If the file does not exist, WriteFile creates it with permissions perm
// (before umask); otherwise WriteFile truncates it before writing, without changing permissions. // (before umask); otherwise WriteFile truncates it before writing, without changing permissions.
//
// As of Go 1.16, this function simply calls os.WriteFile.
func WriteFile(filename string, data []byte, perm fs.FileMode) error { func WriteFile(filename string, data []byte, perm fs.FileMode) error {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) return os.WriteFile(filename, data, perm)
if err != nil {
return err
}
_, err = f.Write(data)
if err1 := f.Close(); err == nil {
err = err1
}
return err
} }
// ReadDir reads the directory named by dirname and returns // ReadDir reads the directory named by dirname and returns
// a list of directory entries sorted by filename. // a list of fs.FileInfo for the directory's contents,
// sorted by filename. If an error occurs reading the directory,
// ReadDir returns no directory entries along with the error.
//
// As of Go 1.16, os.ReadDir is a more efficient and correct choice:
// it returns a list of fs.DirEntry instead of fs.FileInfo,
// and it returns partial results in the case of an error
// midway through reading a directory.
func ReadDir(dirname string) ([]fs.FileInfo, error) { func ReadDir(dirname string) ([]fs.FileInfo, error) {
f, err := os.Open(dirname) f, err := os.Open(dirname)
if err != nil { if err != nil {

View file

@ -75,7 +75,7 @@ func (l *Logger) SetOutput(w io.Writer) {
var std = New(os.Stderr, "", LstdFlags) var std = New(os.Stderr, "", LstdFlags)
// Default returns the *Logger used by the package-level output functions. // Default returns the standard logger used by the package-level output functions.
func Default() *Logger { return std } func Default() *Logger { return std }
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding. // Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.

View file

@ -352,10 +352,16 @@ func (r *Response) bodyIsWritable() bool {
return ok return ok
} }
// isProtocolSwitch reports whether r is a response to a successful // isProtocolSwitch reports whether the response code and header
// protocol upgrade. // indicate a successful protocol upgrade response.
func (r *Response) isProtocolSwitch() bool { func (r *Response) isProtocolSwitch() bool {
return r.StatusCode == StatusSwitchingProtocols && return isProtocolSwitchResponse(r.StatusCode, r.Header)
r.Header.Get("Upgrade") != "" && }
httpguts.HeaderValuesContainsToken(r.Header["Connection"], "Upgrade")
// isProtocolSwitchResponse reports whether the response code and
// response header indicate a successful protocol upgrade response.
func isProtocolSwitchResponse(code int, h Header) bool {
return code == StatusSwitchingProtocols &&
h.Get("Upgrade") != "" &&
httpguts.HeaderValuesContainsToken(h["Connection"], "Upgrade")
} }

View file

@ -6448,3 +6448,56 @@ func BenchmarkResponseStatusLine(b *testing.B) {
} }
}) })
} }
func TestDisableKeepAliveUpgrade(t *testing.T) {
if testing.Short() {
t.Skip("skipping in short mode")
}
setParallel(t)
defer afterTest(t)
s := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Connection", "Upgrade")
w.Header().Set("Upgrade", "someProto")
w.WriteHeader(StatusSwitchingProtocols)
c, _, err := w.(Hijacker).Hijack()
if err != nil {
return
}
defer c.Close()
io.Copy(c, c)
}))
s.Config.SetKeepAlivesEnabled(false)
s.Start()
defer s.Close()
cl := s.Client()
cl.Transport.(*Transport).DisableKeepAlives = true
resp, err := cl.Get(s.URL)
if err != nil {
t.Fatalf("failed to perform request: %v", err)
}
defer resp.Body.Close()
rwc, ok := resp.Body.(io.ReadWriteCloser)
if !ok {
t.Fatalf("Response.Body is not a io.ReadWriteCloser: %T", resp.Body)
}
_, err = rwc.Write([]byte("hello"))
if err != nil {
t.Fatalf("failed to write to body: %v", err)
}
b := make([]byte, 5)
_, err = io.ReadFull(rwc, b)
if err != nil {
t.Fatalf("failed to read from body: %v", err)
}
if string(b) != "hello" {
t.Fatalf("unexpected value read from body:\ngot: %q\nwant: %q", b, "hello")
}
}

View file

@ -1468,7 +1468,13 @@ func (cw *chunkWriter) writeHeader(p []byte) {
return return
} }
if w.closeAfterReply && (!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) { // Only override the Connection header if it is not a successful
// protocol switch response and if KeepAlives are not enabled.
// See https://golang.org/issue/36381.
delConnectionHeader := w.closeAfterReply &&
(!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) &&
!isProtocolSwitchResponse(w.status, header)
if delConnectionHeader {
delHeader("Connection") delHeader("Connection")
if w.req.ProtoAtLeast(1, 1) { if w.req.ProtoAtLeast(1, 1) {
setHeader.connection = "close" setHeader.connection = "close"

View file

@ -2599,6 +2599,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
var respHeaderTimer <-chan time.Time var respHeaderTimer <-chan time.Time
cancelChan := req.Request.Cancel cancelChan := req.Request.Cancel
ctxDoneChan := req.Context().Done() ctxDoneChan := req.Context().Done()
pcClosed := pc.closech
for { for {
testHookWaitResLoop() testHookWaitResLoop()
select { select {
@ -2618,11 +2619,15 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
defer timer.Stop() // prevent leaks defer timer.Stop() // prevent leaks
respHeaderTimer = timer.C respHeaderTimer = timer.C
} }
case <-pc.closech: case <-pcClosed:
if debugRoundTrip { pcClosed = nil
req.logf("closech recv: %T %#v", pc.closed, pc.closed) // check if we are still using the connection
if pc.t.replaceReqCanceler(req.cancelKey, nil) {
if debugRoundTrip {
req.logf("closech recv: %T %#v", pc.closed, pc.closed)
}
return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed)
} }
return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed)
case <-respHeaderTimer: case <-respHeaderTimer:
if debugRoundTrip { if debugRoundTrip {
req.logf("timeout waiting for response headers.") req.logf("timeout waiting for response headers.")

View file

@ -6433,3 +6433,54 @@ func TestErrorWriteLoopRace(t *testing.T) {
testTransportRace(req) testTransportRace(req)
} }
} }
// Issue 41600
// Test that a new request which uses the connection of an active request
// cannot cause it to be canceled as well.
func TestCancelRequestWhenSharingConnection(t *testing.T) {
if testing.Short() {
t.Skip("skipping in short mode")
}
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req *Request) {
w.Header().Add("Content-Length", "0")
}))
defer ts.Close()
client := ts.Client()
transport := client.Transport.(*Transport)
transport.MaxIdleConns = 1
transport.MaxConnsPerHost = 1
var wg sync.WaitGroup
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for ctx.Err() == nil {
reqctx, reqcancel := context.WithCancel(ctx)
go reqcancel()
req, _ := NewRequestWithContext(reqctx, "GET", ts.URL, nil)
res, err := client.Do(req)
if err == nil {
res.Body.Close()
}
}
}()
}
for ctx.Err() == nil {
req, _ := NewRequest("GET", ts.URL, nil)
if res, err := client.Do(req); err != nil {
t.Errorf("unexpected: %p %v", req, err)
break
} else {
res.Body.Close()
}
}
cancel()
wg.Wait()
}

View file

@ -259,6 +259,9 @@ func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) {
// ListenMulticastUDP is just for convenience of simple, small // ListenMulticastUDP is just for convenience of simple, small
// applications. There are golang.org/x/net/ipv4 and // applications. There are golang.org/x/net/ipv4 and
// golang.org/x/net/ipv6 packages for general purpose uses. // golang.org/x/net/ipv6 packages for general purpose uses.
//
// Note that ListenMulticastUDP will set the IP_MULTICAST_LOOP socket option
// to 0 under IPPROTO_IP, to disable loopback of multicast packets.
func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
switch network { switch network {
case "udp", "udp4", "udp6": case "udp", "udp4", "udp6":

View file

@ -4,7 +4,10 @@
package os package os
import "io/fs" import (
"io/fs"
"sort"
)
type readdirMode int type readdirMode int
@ -103,3 +106,20 @@ func (f *File) ReadDir(n int) ([]DirEntry, error) {
// testingForceReadDirLstat forces ReadDir to call Lstat, for testing that code path. // testingForceReadDirLstat forces ReadDir to call Lstat, for testing that code path.
// This can be difficult to provoke on some Unix systems otherwise. // This can be difficult to provoke on some Unix systems otherwise.
var testingForceReadDirLstat bool var testingForceReadDirLstat bool
// ReadDir reads the named directory,
// returning all its directory entries sorted by filename.
// If an error occurs reading the directory,
// ReadDir returns the entries it was able to read before the error,
// along with the error.
func ReadDir(name string) ([]DirEntry, error) {
f, err := Open(name)
if err != nil {
return nil, err
}
defer f.Close()
dirs, err := f.ReadDir(-1)
sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
return dirs, err
}

View file

@ -9,6 +9,7 @@ import (
"io/fs" "io/fs"
"log" "log"
"os" "os"
"path/filepath"
"time" "time"
) )
@ -144,3 +145,98 @@ func ExampleUnsetenv() {
os.Setenv("TMPDIR", "/my/tmp") os.Setenv("TMPDIR", "/my/tmp")
defer os.Unsetenv("TMPDIR") defer os.Unsetenv("TMPDIR")
} }
func ExampleReadDir() {
files, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, file := range files {
fmt.Println(file.Name())
}
}
func ExampleMkdirTemp() {
dir, err := os.MkdirTemp("", "example")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(dir) // clean up
file := filepath.Join(dir, "tmpfile")
if err := os.WriteFile(file, []byte("content"), 0666); err != nil {
log.Fatal(err)
}
}
func ExampleMkdirTemp_suffix() {
logsDir, err := os.MkdirTemp("", "*-logs")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(logsDir) // clean up
// Logs can be cleaned out earlier if needed by searching
// for all directories whose suffix ends in *-logs.
globPattern := filepath.Join(os.TempDir(), "*-logs")
matches, err := filepath.Glob(globPattern)
if err != nil {
log.Fatalf("Failed to match %q: %v", globPattern, err)
}
for _, match := range matches {
if err := os.RemoveAll(match); err != nil {
log.Printf("Failed to remove %q: %v", match, err)
}
}
}
func ExampleCreateTemp() {
f, err := os.CreateTemp("", "example")
if err != nil {
log.Fatal(err)
}
defer os.Remove(f.Name()) // clean up
if _, err := f.Write([]byte("content")); err != nil {
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}
func ExampleCreateTemp_suffix() {
f, err := os.CreateTemp("", "example.*.txt")
if err != nil {
log.Fatal(err)
}
defer os.Remove(f.Name()) // clean up
if _, err := f.Write([]byte("content")); err != nil {
f.Close()
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}
func ExampleReadFile() {
data, err := os.ReadFile("testdata/hello")
if err != nil {
log.Fatal(err)
}
os.Stdout.Write(data)
// Output:
// Hello, Gophers!
}
func ExampleWriteFile() {
err := os.WriteFile("testdata/hello", []byte("Hello, Gophers!"), 0666)
if err != nil {
log.Fatal(err)
}
}

View file

@ -691,6 +691,18 @@ func TestExtraFiles(t *testing.T) {
c.Stdout = &stdout c.Stdout = &stdout
c.Stderr = &stderr c.Stderr = &stderr
c.ExtraFiles = []*os.File{tf} c.ExtraFiles = []*os.File{tf}
if runtime.GOOS == "illumos" {
// Some facilities in illumos are implemented via access
// to /proc by libc; such accesses can briefly occupy a
// low-numbered fd. If this occurs concurrently with the
// test that checks for leaked descriptors, the check can
// become confused and report a spurious leaked descriptor.
// (See issue #42431 for more detailed analysis.)
//
// Attempt to constrain the use of additional threads in the
// child process to make this test less flaky:
c.Env = append(os.Environ(), "GOMAXPROCS=1")
}
err = c.Run() err = c.Run()
if err != nil { if err != nil {
t.Fatalf("Run: %v\n--- stdout:\n%s--- stderr:\n%s", err, stdout.Bytes(), stderr.Bytes()) t.Fatalf("Run: %v\n--- stdout:\n%s--- stderr:\n%s", err, stdout.Bytes(), stderr.Bytes())

View file

@ -10,3 +10,4 @@ var Atime = atime
var LstatP = &lstat var LstatP = &lstat
var ErrWriteAtInAppendMode = errWriteAtInAppendMode var ErrWriteAtInAppendMode = errWriteAtInAppendMode
var TestingForceReadDirLstat = &testingForceReadDirLstat var TestingForceReadDirLstat = &testingForceReadDirLstat
var ErrPatternHasSeparator = errPatternHasSeparator

View file

@ -406,7 +406,7 @@ func UserCacheDir() (string, error) {
return "", errors.New("%LocalAppData% is not defined") return "", errors.New("%LocalAppData% is not defined")
} }
case "darwin": case "darwin", "ios":
dir = Getenv("HOME") dir = Getenv("HOME")
if dir == "" { if dir == "" {
return "", errors.New("$HOME is not defined") return "", errors.New("$HOME is not defined")
@ -457,7 +457,7 @@ func UserConfigDir() (string, error) {
return "", errors.New("%AppData% is not defined") return "", errors.New("%AppData% is not defined")
} }
case "darwin": case "darwin", "ios":
dir = Getenv("HOME") dir = Getenv("HOME")
if dir == "" { if dir == "" {
return "", errors.New("$HOME is not defined") return "", errors.New("$HOME is not defined")
@ -505,10 +505,8 @@ func UserHomeDir() (string, error) {
switch runtime.GOOS { switch runtime.GOOS {
case "android": case "android":
return "/sdcard", nil return "/sdcard", nil
case "darwin": case "ios":
if runtime.GOARCH == "arm64" { return "/", nil
return "/", nil
}
} }
return "", errors.New(enverr + " is not defined") return "", errors.New(enverr + " is not defined")
} }
@ -627,3 +625,63 @@ func (dir dirFS) Open(name string) (fs.File, error) {
} }
return f, nil return f, nil
} }
// ReadFile reads the named file and returns the contents.
// A successful call returns err == nil, not err == EOF.
// Because ReadFile reads the whole file, it does not treat an EOF from Read
// as an error to be reported.
func ReadFile(name string) ([]byte, error) {
f, err := Open(name)
if err != nil {
return nil, err
}
defer f.Close()
var size int
if info, err := f.Stat(); err == nil {
size64 := info.Size()
if int64(int(size64)) == size64 {
size = int(size64)
}
}
size++ // one byte for final read at EOF
// If a file claims a small size, read at least 512 bytes.
// In particular, files in Linux's /proc claim size 0 but
// then do not work right if read in small pieces,
// so an initial read of 1 byte would not work correctly.
if size < 512 {
size = 512
}
data := make([]byte, 0, size)
for {
if len(data) >= cap(data) {
d := append(data[:cap(data)], 0)
data = d[:len(data)]
}
n, err := f.Read(data[len(data):cap(data)])
data = data[:len(data)+n]
if err != nil {
if err == io.EOF {
err = nil
}
return data, err
}
}
}
// WriteFile writes data to the named file, creating it if necessary.
// If the file does not exist, WriteFile creates it with permissions perm (before umask);
// otherwise WriteFile truncates it before writing, without changing permissions.
func WriteFile(name string, data []byte, perm FileMode) error {
f, err := OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, perm)
if err != nil {
return err
}
_, err = f.Write(data)
if err1 := f.Close(); err1 != nil && err == nil {
err = err1
}
return err
}

View file

@ -419,19 +419,19 @@ func testReadDir(dir string, contents []string, t *testing.T) {
} }
} }
func TestReaddirnames(t *testing.T) { func TestFileReaddirnames(t *testing.T) {
testReaddirnames(".", dot, t) testReaddirnames(".", dot, t)
testReaddirnames(sysdir.name, sysdir.files, t) testReaddirnames(sysdir.name, sysdir.files, t)
testReaddirnames(t.TempDir(), nil, t) testReaddirnames(t.TempDir(), nil, t)
} }
func TestReaddir(t *testing.T) { func TestFileReaddir(t *testing.T) {
testReaddir(".", dot, t) testReaddir(".", dot, t)
testReaddir(sysdir.name, sysdir.files, t) testReaddir(sysdir.name, sysdir.files, t)
testReaddir(t.TempDir(), nil, t) testReaddir(t.TempDir(), nil, t)
} }
func TestReadDir(t *testing.T) { func TestFileReadDir(t *testing.T) {
testReadDir(".", dot, t) testReadDir(".", dot, t)
testReadDir(sysdir.name, sysdir.files, t) testReadDir(sysdir.name, sysdir.files, t)
testReadDir(t.TempDir(), nil, t) testReadDir(t.TempDir(), nil, t)
@ -1235,6 +1235,7 @@ func TestChmod(t *testing.T) {
} }
func checkSize(t *testing.T, f *File, size int64) { func checkSize(t *testing.T, f *File, size int64) {
t.Helper()
dir, err := f.Stat() dir, err := f.Stat()
if err != nil { if err != nil {
t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err) t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
@ -2690,3 +2691,22 @@ func TestDirFS(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestReadFileProc(t *testing.T) {
// Linux files in /proc report 0 size,
// but then if ReadFile reads just a single byte at offset 0,
// the read at offset 1 returns EOF instead of more data.
// ReadFile has a minimum read size of 512 to work around this,
// but test explicitly that it's working.
name := "/proc/sys/fs/pipe-max-size"
if _, err := Stat(name); err != nil {
t.Skip(err)
}
data, err := ReadFile(name)
if err != nil {
t.Fatal(err)
}
if len(data) == 0 || data[len(data)-1] != '\n' {
t.Fatalf("read %s: not newline-terminated: %q", name, data)
}
}

127
src/os/read_test.go Normal file
View file

@ -0,0 +1,127 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os_test
import (
"bytes"
. "os"
"path/filepath"
"testing"
)
func checkNamedSize(t *testing.T, path string, size int64) {
dir, err := Stat(path)
if err != nil {
t.Fatalf("Stat %q (looking for size %d): %s", path, size, err)
}
if dir.Size() != size {
t.Errorf("Stat %q: size %d want %d", path, dir.Size(), size)
}
}
func TestReadFile(t *testing.T) {
filename := "rumpelstilzchen"
contents, err := ReadFile(filename)
if err == nil {
t.Fatalf("ReadFile %s: error expected, none found", filename)
}
filename = "read_test.go"
contents, err = ReadFile(filename)
if err != nil {
t.Fatalf("ReadFile %s: %v", filename, err)
}
checkNamedSize(t, filename, int64(len(contents)))
}
func TestWriteFile(t *testing.T) {
f, err := CreateTemp("", "ioutil-test")
if err != nil {
t.Fatal(err)
}
defer f.Close()
defer Remove(f.Name())
msg := "Programming today is a race between software engineers striving to " +
"build bigger and better idiot-proof programs, and the Universe trying " +
"to produce bigger and better idiots. So far, the Universe is winning."
if err := WriteFile(f.Name(), []byte(msg), 0644); err != nil {
t.Fatalf("WriteFile %s: %v", f.Name(), err)
}
data, err := ReadFile(f.Name())
if err != nil {
t.Fatalf("ReadFile %s: %v", f.Name(), err)
}
if string(data) != msg {
t.Fatalf("ReadFile: wrong data:\nhave %q\nwant %q", string(data), msg)
}
}
func TestReadOnlyWriteFile(t *testing.T) {
if Getuid() == 0 {
t.Skipf("Root can write to read-only files anyway, so skip the read-only test.")
}
// We don't want to use CreateTemp directly, since that opens a file for us as 0600.
tempDir, err := MkdirTemp("", t.Name())
if err != nil {
t.Fatal(err)
}
defer RemoveAll(tempDir)
filename := filepath.Join(tempDir, "blurp.txt")
shmorp := []byte("shmorp")
florp := []byte("florp")
err = WriteFile(filename, shmorp, 0444)
if err != nil {
t.Fatalf("WriteFile %s: %v", filename, err)
}
err = WriteFile(filename, florp, 0444)
if err == nil {
t.Fatalf("Expected an error when writing to read-only file %s", filename)
}
got, err := ReadFile(filename)
if err != nil {
t.Fatalf("ReadFile %s: %v", filename, err)
}
if !bytes.Equal(got, shmorp) {
t.Fatalf("want %s, got %s", shmorp, got)
}
}
func TestReadDir(t *testing.T) {
dirname := "rumpelstilzchen"
_, err := ReadDir(dirname)
if err == nil {
t.Fatalf("ReadDir %s: error expected, none found", dirname)
}
dirname = "."
list, err := ReadDir(dirname)
if err != nil {
t.Fatalf("ReadDir %s: %v", dirname, err)
}
foundFile := false
foundSubDir := false
for _, dir := range list {
switch {
case !dir.IsDir() && dir.Name() == "read_test.go":
foundFile = true
case dir.IsDir() && dir.Name() == "exec":
foundSubDir = true
}
}
if !foundFile {
t.Fatalf("ReadDir %s: read_test.go file not found", dirname)
}
if !foundSubDir {
t.Fatalf("ReadDir %s: exec directory not found", dirname)
}
}

View file

@ -355,11 +355,12 @@ func TestRemoveAllButReadOnlyAndPathError(t *testing.T) {
// The error should be of type *PathError. // The error should be of type *PathError.
// see issue 30491 for details. // see issue 30491 for details.
if pathErr, ok := err.(*PathError); ok { if pathErr, ok := err.(*PathError); ok {
if g, w := pathErr.Path, filepath.Join(tempDir, "b", "y"); g != w { want := filepath.Join(tempDir, "b", "y")
t.Errorf("got %q, expected pathErr.path %q", g, w) if pathErr.Path != want {
t.Errorf("RemoveAll(%q): err.Path=%q, want %q", tempDir, pathErr.Path, want)
} }
} else { } else {
t.Errorf("got %T, expected *fs.PathError", err) t.Errorf("RemoveAll(%q): error has type %T, want *fs.PathError", tempDir, err)
} }
for _, dir := range dirs { for _, dir := range dirs {

118
src/os/tempfile.go Normal file
View file

@ -0,0 +1,118 @@
// Copyright 2010 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 os
import (
"errors"
"strings"
)
// fastrand provided by runtime.
// We generate random temporary file names so that there's a good
// chance the file doesn't exist yet - keeps the number of tries in
// TempFile to a minimum.
func fastrand() uint32
func nextRandom() string {
return uitoa(uint(fastrand()))
}
// CreateTemp creates a new temporary file in the directory dir,
// opens the file for reading and writing, and returns the resulting file.
// The filename is generated by taking pattern and adding a random string to the end.
// If pattern includes a "*", the random string replaces the last "*".
// If dir is the empty string, TempFile uses the default directory for temporary files, as returned by TempDir.
// Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file.
// The caller can use the file's Name method to find the pathname of the file.
// It is the caller's responsibility to remove the file when it is no longer needed.
func CreateTemp(dir, pattern string) (*File, error) {
if dir == "" {
dir = TempDir()
}
prefix, suffix, err := prefixAndSuffix(pattern)
if err != nil {
return nil, &PathError{Op: "createtemp", Path: pattern, Err: err}
}
prefix = joinPath(dir, prefix)
try := 0
for {
name := prefix + nextRandom() + suffix
f, err := OpenFile(name, O_RDWR|O_CREATE|O_EXCL, 0600)
if IsExist(err) {
if try++; try < 10000 {
continue
}
return nil, &PathError{Op: "createtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist}
}
return f, err
}
}
var errPatternHasSeparator = errors.New("pattern contains path separator")
// prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
// returning prefix as the part before "*" and suffix as the part after "*".
func prefixAndSuffix(pattern string) (prefix, suffix string, err error) {
for i := 0; i < len(pattern); i++ {
if IsPathSeparator(pattern[i]) {
return "", "", errPatternHasSeparator
}
}
if pos := strings.LastIndex(pattern, "*"); pos != -1 {
prefix, suffix = pattern[:pos], pattern[pos+1:]
} else {
prefix = pattern
}
return prefix, suffix, nil
}
// MkdirTemp creates a new temporary directory in the directory dir
// and returns the pathname of the new directory.
// The new directory's name is generated by adding a random string to the end of pattern.
// If pattern includes a "*", the random string replaces the last "*" instead.
// If dir is the empty string, TempFile uses the default directory for temporary files, as returned by TempDir.
// Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory.
// It is the caller's responsibility to remove the directory when it is no longer needed.
func MkdirTemp(dir, pattern string) (string, error) {
if dir == "" {
dir = TempDir()
}
prefix, suffix, err := prefixAndSuffix(pattern)
if err != nil {
return "", &PathError{Op: "mkdirtemp", Path: pattern, Err: err}
}
prefix = joinPath(dir, prefix)
try := 0
for {
name := prefix + nextRandom() + suffix
err := Mkdir(name, 0700)
if err == nil {
return name, nil
}
if IsExist(err) {
if try++; try < 10000 {
continue
}
return "", &PathError{Op: "mkdirtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist}
}
if IsNotExist(err) {
if _, err := Stat(dir); IsNotExist(err) {
return "", err
}
}
return "", err
}
}
func joinPath(dir, name string) string {
if len(dir) > 0 && IsPathSeparator(dir[len(dir)-1]) {
return dir + name
}
return dir + string(PathSeparator) + name
}

193
src/os/tempfile_test.go Normal file
View file

@ -0,0 +1,193 @@
// Copyright 2010 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 os_test
import (
"errors"
"io/fs"
. "os"
"path/filepath"
"regexp"
"strings"
"testing"
)
func TestCreateTemp(t *testing.T) {
dir, err := MkdirTemp("", "TestCreateTempBadDir")
if err != nil {
t.Fatal(err)
}
defer RemoveAll(dir)
nonexistentDir := filepath.Join(dir, "_not_exists_")
f, err := CreateTemp(nonexistentDir, "foo")
if f != nil || err == nil {
t.Errorf("CreateTemp(%q, `foo`) = %v, %v", nonexistentDir, f, err)
}
}
func TestCreateTempPattern(t *testing.T) {
tests := []struct{ pattern, prefix, suffix string }{
{"tempfile_test", "tempfile_test", ""},
{"tempfile_test*", "tempfile_test", ""},
{"tempfile_test*xyz", "tempfile_test", "xyz"},
}
for _, test := range tests {
f, err := CreateTemp("", test.pattern)
if err != nil {
t.Errorf("CreateTemp(..., %q) error: %v", test.pattern, err)
continue
}
defer Remove(f.Name())
base := filepath.Base(f.Name())
f.Close()
if !(strings.HasPrefix(base, test.prefix) && strings.HasSuffix(base, test.suffix)) {
t.Errorf("CreateTemp pattern %q created bad name %q; want prefix %q & suffix %q",
test.pattern, base, test.prefix, test.suffix)
}
}
}
func TestCreateTempBadPattern(t *testing.T) {
tmpDir, err := MkdirTemp("", t.Name())
if err != nil {
t.Fatal(err)
}
defer RemoveAll(tmpDir)
const sep = string(PathSeparator)
tests := []struct {
pattern string
wantErr bool
}{
{"ioutil*test", false},
{"tempfile_test*foo", false},
{"tempfile_test" + sep + "foo", true},
{"tempfile_test*" + sep + "foo", true},
{"tempfile_test" + sep + "*foo", true},
{sep + "tempfile_test" + sep + "*foo", true},
{"tempfile_test*foo" + sep, true},
}
for _, tt := range tests {
t.Run(tt.pattern, func(t *testing.T) {
tmpfile, err := CreateTemp(tmpDir, tt.pattern)
if tmpfile != nil {
defer tmpfile.Close()
}
if tt.wantErr {
if err == nil {
t.Errorf("CreateTemp(..., %#q) succeeded, expected error", tt.pattern)
}
if !errors.Is(err, ErrPatternHasSeparator) {
t.Errorf("CreateTemp(..., %#q): %v, expected ErrPatternHasSeparator", tt.pattern, err)
}
} else if err != nil {
t.Errorf("CreateTemp(..., %#q): %v", tt.pattern, err)
}
})
}
}
func TestMkdirTemp(t *testing.T) {
name, err := MkdirTemp("/_not_exists_", "foo")
if name != "" || err == nil {
t.Errorf("MkdirTemp(`/_not_exists_`, `foo`) = %v, %v", name, err)
}
tests := []struct {
pattern string
wantPrefix, wantSuffix string
}{
{"tempfile_test", "tempfile_test", ""},
{"tempfile_test*", "tempfile_test", ""},
{"tempfile_test*xyz", "tempfile_test", "xyz"},
}
dir := filepath.Clean(TempDir())
runTestMkdirTemp := func(t *testing.T, pattern, wantRePat string) {
name, err := MkdirTemp(dir, pattern)
if name == "" || err != nil {
t.Fatalf("MkdirTemp(dir, `tempfile_test`) = %v, %v", name, err)
}
defer Remove(name)
re := regexp.MustCompile(wantRePat)
if !re.MatchString(name) {
t.Errorf("MkdirTemp(%q, %q) created bad name\n\t%q\ndid not match pattern\n\t%q", dir, pattern, name, wantRePat)
}
}
for _, tt := range tests {
t.Run(tt.pattern, func(t *testing.T) {
wantRePat := "^" + regexp.QuoteMeta(filepath.Join(dir, tt.wantPrefix)) + "[0-9]+" + regexp.QuoteMeta(tt.wantSuffix) + "$"
runTestMkdirTemp(t, tt.pattern, wantRePat)
})
}
// Separately testing "*xyz" (which has no prefix). That is when constructing the
// pattern to assert on, as in the previous loop, using filepath.Join for an empty
// prefix filepath.Join(dir, ""), produces the pattern:
// ^<DIR>[0-9]+xyz$
// yet we just want to match
// "^<DIR>/[0-9]+xyz"
t.Run("*xyz", func(t *testing.T) {
wantRePat := "^" + regexp.QuoteMeta(filepath.Join(dir)) + regexp.QuoteMeta(string(filepath.Separator)) + "[0-9]+xyz$"
runTestMkdirTemp(t, "*xyz", wantRePat)
})
}
// test that we return a nice error message if the dir argument to TempDir doesn't
// exist (or that it's empty and TempDir doesn't exist)
func TestMkdirTempBadDir(t *testing.T) {
dir, err := MkdirTemp("", "MkdirTempBadDir")
if err != nil {
t.Fatal(err)
}
defer RemoveAll(dir)
badDir := filepath.Join(dir, "not-exist")
_, err = MkdirTemp(badDir, "foo")
if pe, ok := err.(*fs.PathError); !ok || !IsNotExist(err) || pe.Path != badDir {
t.Errorf("TempDir error = %#v; want PathError for path %q satisifying IsNotExist", err, badDir)
}
}
func TestMkdirTempBadPattern(t *testing.T) {
tmpDir, err := MkdirTemp("", t.Name())
if err != nil {
t.Fatal(err)
}
defer RemoveAll(tmpDir)
const sep = string(PathSeparator)
tests := []struct {
pattern string
wantErr bool
}{
{"ioutil*test", false},
{"tempfile_test*foo", false},
{"tempfile_test" + sep + "foo", true},
{"tempfile_test*" + sep + "foo", true},
{"tempfile_test" + sep + "*foo", true},
{sep + "tempfile_test" + sep + "*foo", true},
{"tempfile_test*foo" + sep, true},
}
for _, tt := range tests {
t.Run(tt.pattern, func(t *testing.T) {
_, err := MkdirTemp(tmpDir, tt.pattern)
if tt.wantErr {
if err == nil {
t.Errorf("MkdirTemp(..., %#q) succeeded, expected error", tt.pattern)
}
if !errors.Is(err, ErrPatternHasSeparator) {
t.Errorf("MkdirTemp(..., %#q): %v, expected ErrPatternHasSeparator", tt.pattern, err)
}
} else if err != nil {
t.Errorf("MkdirTemp(..., %#q): %v", tt.pattern, err)
}
})
}
}

1
src/os/testdata/hello vendored Normal file
View file

@ -0,0 +1 @@
Hello, Gophers!

View file

@ -4007,9 +4007,12 @@ var convertTests = []struct {
{V(int16(-3)), V(string("\uFFFD"))}, {V(int16(-3)), V(string("\uFFFD"))},
{V(int32(-4)), V(string("\uFFFD"))}, {V(int32(-4)), V(string("\uFFFD"))},
{V(int64(-5)), V(string("\uFFFD"))}, {V(int64(-5)), V(string("\uFFFD"))},
{V(int64(-1 << 32)), V(string("\uFFFD"))},
{V(int64(1 << 32)), V(string("\uFFFD"))},
{V(uint(0x110001)), V(string("\uFFFD"))}, {V(uint(0x110001)), V(string("\uFFFD"))},
{V(uint32(0x110002)), V(string("\uFFFD"))}, {V(uint32(0x110002)), V(string("\uFFFD"))},
{V(uint64(0x110003)), V(string("\uFFFD"))}, {V(uint64(0x110003)), V(string("\uFFFD"))},
{V(uint64(1 << 32)), V(string("\uFFFD"))},
{V(uintptr(0x110004)), V(string("\uFFFD"))}, {V(uintptr(0x110004)), V(string("\uFFFD"))},
// named string // named string

View file

@ -2681,12 +2681,20 @@ func cvtComplex(v Value, t Type) Value {
// convertOp: intXX -> string // convertOp: intXX -> string
func cvtIntString(v Value, t Type) Value { func cvtIntString(v Value, t Type) Value {
return makeString(v.flag.ro(), string(rune(v.Int())), t) s := "\uFFFD"
if x := v.Int(); int64(rune(x)) == x {
s = string(rune(x))
}
return makeString(v.flag.ro(), s, t)
} }
// convertOp: uintXX -> string // convertOp: uintXX -> string
func cvtUintString(v Value, t Type) Value { func cvtUintString(v Value, t Type) Value {
return makeString(v.flag.ro(), string(rune(v.Uint())), t) s := "\uFFFD"
if x := v.Uint(); uint64(rune(x)) == x {
s = string(rune(x))
}
return makeString(v.flag.ro(), s, t)
} }
// convertOp: []byte -> string // convertOp: []byte -> string

View file

@ -244,7 +244,7 @@ func TestPanicSystemstack(t *testing.T) {
// we don't have a way to know when it is fully blocked, sleep a bit to // we don't have a way to know when it is fully blocked, sleep a bit to
// make us less likely to lose the race and signal before the child // make us less likely to lose the race and signal before the child
// blocks. // blocks.
time.Sleep(100*time.Millisecond) time.Sleep(100 * time.Millisecond)
// Send SIGQUIT. // Send SIGQUIT.
if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil { if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil {

View file

@ -283,6 +283,12 @@ func libpreinit() {
func mpreinit(mp *m) { func mpreinit(mp *m) {
mp.gsignal = malg(32 * 1024) // OS X wants >= 8K mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
mp.gsignal.m = mp mp.gsignal.m = mp
if GOOS == "darwin" && GOARCH == "arm64" {
// mlock the signal stack to work around a kernel bug where it may
// SIGILL when the signal stack is not faulted in while a signal
// arrives. See issue 42774.
mlock(unsafe.Pointer(mp.gsignal.stack.hi-physPageSize), physPageSize)
}
} }
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).

View file

@ -286,6 +286,10 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
broken = true broken = true
} }
case "windows":
if runtime.GOARCH == "arm" {
broken = true // See https://golang.org/issues/42862
}
} }
maxDuration := 5 * time.Second maxDuration := 5 * time.Second

View file

@ -43,16 +43,9 @@ func initExceptionHandler() {
// //
//go:nosplit //go:nosplit
func isAbort(r *context) bool { func isAbort(r *context) bool {
switch GOARCH { // In the case of an abort, the exception IP is one byte after
case "386", "amd64": // the INT3 (this differs from UNIX OSes).
// In the case of an abort, the exception IP is one byte after return isAbortPC(r.ip() - 1)
// the INT3 (this differs from UNIX OSes).
return isAbortPC(r.ip() - 1)
case "arm":
return isAbortPC(r.ip())
default:
return false
}
} }
// isgoexception reports whether this exception should be translated // isgoexception reports whether this exception should be translated

View file

@ -133,6 +133,9 @@ func sync_fastrand() uint32 { return fastrand() }
//go:linkname net_fastrand net.fastrand //go:linkname net_fastrand net.fastrand
func net_fastrand() uint32 { return fastrand() } func net_fastrand() uint32 { return fastrand() }
//go:linkname os_fastrand os.fastrand
func os_fastrand() uint32 { return fastrand() }
// in internal/bytealg/equal_*.s // in internal/bytealg/equal_*.s
//go:noescape //go:noescape
func memequal(a, b unsafe.Pointer, size uintptr) bool func memequal(a, b unsafe.Pointer, size uintptr) bool

View file

@ -226,6 +226,13 @@ func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
} }
func madvise_trampoline() func madvise_trampoline()
//go:nosplit
//go:cgo_unsafe_args
func mlock(addr unsafe.Pointer, n uintptr) {
libcCall(unsafe.Pointer(funcPC(mlock_trampoline)), unsafe.Pointer(&addr))
}
func mlock_trampoline()
//go:nosplit //go:nosplit
//go:cgo_unsafe_args //go:cgo_unsafe_args
func read(fd int32, p unsafe.Pointer, n int32) int32 { func read(fd int32, p unsafe.Pointer, n int32) int32 {
@ -465,6 +472,7 @@ func setNonblock(fd int32) {
//go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_error __error "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_error __error "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_usleep usleep "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_usleep usleep "/usr/lib/libSystem.B.dylib"

View file

@ -105,6 +105,9 @@ TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
POPQ BP POPQ BP
RET RET
TEXT runtime·mlock_trampoline(SB), NOSPLIT, $0
UNDEF // unimplemented
GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size) GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0 TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0

View file

@ -120,6 +120,12 @@ TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0
BL libc_madvise(SB) BL libc_madvise(SB)
RET RET
TEXT runtime·mlock_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 len
MOVD 0(R0), R0 // arg 1 addr
BL libc_mlock(SB)
RET
TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 new MOVD 8(R0), R1 // arg 2 new
MOVD 16(R0), R2 // arg 3 old MOVD 16(R0), R2 // arg 3 old

View file

@ -969,8 +969,9 @@ func TestDLLPreloadMitigation(t *testing.T) {
#include <stdint.h> #include <stdint.h>
#include <windows.h> #include <windows.h>
uintptr_t cfunc() { uintptr_t cfunc(void) {
SetLastError(123); SetLastError(123);
return 0;
} }
` `
srcname := "nojack.c" srcname := "nojack.c"

View file

@ -13,7 +13,7 @@ var t struct {
_ int _ int
} }
func (x int) _() { // ERROR "cannot define new methods on non-local type" func (x int) _() { // ERROR "methods on non-local type"
println(x) println(x)
} }

View file

@ -25,8 +25,8 @@ func main() {
cs = cr // ERROR "illegal types|incompatible|cannot" cs = cr // ERROR "illegal types|incompatible|cannot"
var n int var n int
<-n // ERROR "receive from non-chan" <-n // ERROR "receive from non-chan|expected channel"
n <- 2 // ERROR "send to non-chan" n <- 2 // ERROR "send to non-chan|must be channel"
c <- 0 // ok c <- 0 // ok
<-c // ok <-c // ok
@ -66,5 +66,5 @@ func main() {
close(c) close(c)
close(cs) close(cs)
close(cr) // ERROR "receive" close(cr) // ERROR "receive"
close(n) // ERROR "invalid operation.*non-chan type" close(n) // ERROR "invalid operation.*non-chan type|must be channel"
} }

View file

@ -22,9 +22,9 @@ var (
_ = m[0][:] // ERROR "slice of unaddressable value" _ = m[0][:] // ERROR "slice of unaddressable value"
_ = f()[:] // ERROR "slice of unaddressable value" _ = f()[:] // ERROR "slice of unaddressable value"
_ = 301[:] // ERROR "cannot slice" _ = 301[:] // ERROR "cannot slice|attempt to slice object that is not"
_ = 3.1[:] // ERROR "cannot slice" _ = 3.1[:] // ERROR "cannot slice|attempt to slice object that is not"
_ = true[:] // ERROR "cannot slice" _ = true[:] // ERROR "cannot slice|attempt to slice object that is not"
// these are okay because they are slicing a pointer to an array // these are okay because they are slicing a pointer to an array
_ = (&[3]int{1, 2, 3})[:] _ = (&[3]int{1, 2, 3})[:]
@ -46,8 +46,8 @@ var (
_ = &T{0, 0, "", nil} // ok _ = &T{0, 0, "", nil} // ok
_ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal" _ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal"
_ = &T{0, 0, "", {}} // ERROR "missing type in composite literal|omit types within composite literal" _ = &T{0, 0, "", {}} // ERROR "missing type in composite literal|omit types within composite literal"
_ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP" _ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP|omit types within composite literal"
_ = &Ti{} // ERROR "invalid composite literal type Ti" _ = &Ti{} // ERROR "invalid composite literal type Ti|expected.*type for composite literal"
) )
type M map[T]T type M map[T]T

View file

@ -21,9 +21,9 @@ var x6 = int(1e100) // ERROR "overflow"
var x7 = float32(1e1000) // ERROR "overflow" var x7 = float32(1e1000) // ERROR "overflow"
// unsafe.Pointer can only convert to/from uintptr // unsafe.Pointer can only convert to/from uintptr
var _ = string(unsafe.Pointer(uintptr(65))) // ERROR "convert" var _ = string(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion"
var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert" var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion"
var _ = int(unsafe.Pointer(uintptr(65))) // ERROR "convert" var _ = int(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion"
// implicit conversions merit scrutiny // implicit conversions merit scrutiny
var s string var s string

View file

@ -60,5 +60,5 @@ func bad(args ...int) {
_ = [...]byte("foo") // ERROR "[.][.][.]" _ = [...]byte("foo") // ERROR "[.][.][.]"
_ = [...][...]int{{1,2,3},{4,5,6}} // ERROR "[.][.][.]" _ = [...][...]int{{1,2,3},{4,5,6}} // ERROR "[.][.][.]"
Foo(x...) // ERROR "invalid use of [.][.][.] in call" Foo(x...) // ERROR "invalid use of .*[.][.][.]"
} }

View file

@ -9,6 +9,6 @@ package main
var x int var x int
var a = []int{ x: 1} // ERROR "constant" var a = []int{ x: 1} // ERROR "constant"
var b = [...]int{x: 1} var b = [...]int{x: 1} // GCCGO_ERROR "constant"
var c = map[int]int{ x: 1} var c = map[int]int{ x: 1}

View file

@ -14,4 +14,4 @@ func main() {}
// important: no newline on end of next line. // important: no newline on end of next line.
// 6g used to print <epoch> instead of bug332.go:111 // 6g used to print <epoch> instead of bug332.go:111
func (t *T) F() {} // ERROR "undefined: T" func (t *T) F() {} // ERROR "undefined.*T"

View file

@ -13,6 +13,6 @@ func main() {
switch t := x.(type) { switch t := x.(type) {
case 0: // ERROR "type" case 0: // ERROR "type"
t.x = 1 t.x = 1
x.x = 1 // ERROR "type interface \{\}|reference to undefined field or method" x.x = 1 // ERROR "type interface \{\}|reference to undefined field or method|interface with no methods"
} }
} }

View file

@ -19,7 +19,7 @@ func f() {
_ = a[10:10] _ = a[10:10]
_ = a[9:12] // ERROR "invalid slice index 12|index out of bounds" _ = a[9:12] // ERROR "invalid slice index 12|index out of bounds"
_ = a[11:12] // ERROR "invalid slice index 11|index out of bounds" _ = a[11:12] // ERROR "invalid slice index 11|index out of bounds"
_ = a[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" _ = a[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds"
var s []int var s []int
_ = s[-1] // ERROR "invalid slice index -1|index out of bounds" _ = s[-1] // ERROR "invalid slice index -1|index out of bounds"
@ -30,7 +30,7 @@ func f() {
_ = s[10:10] _ = s[10:10]
_ = s[9:12] _ = s[9:12]
_ = s[11:12] _ = s[11:12]
_ = s[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" _ = s[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds"
const c = "foofoofoof" const c = "foofoofoof"
_ = c[-1] // ERROR "invalid string index -1|index out of bounds" _ = c[-1] // ERROR "invalid string index -1|index out of bounds"
@ -41,7 +41,7 @@ func f() {
_ = c[10:10] _ = c[10:10]
_ = c[9:12] // ERROR "invalid slice index 12|index out of bounds" _ = c[9:12] // ERROR "invalid slice index 12|index out of bounds"
_ = c[11:12] // ERROR "invalid slice index 11|index out of bounds" _ = c[11:12] // ERROR "invalid slice index 11|index out of bounds"
_ = c[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" _ = c[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds"
var t string var t string
_ = t[-1] // ERROR "invalid string index -1|index out of bounds" _ = t[-1] // ERROR "invalid string index -1|index out of bounds"
@ -52,5 +52,5 @@ func f() {
_ = t[10:10] _ = t[10:10]
_ = t[9:12] _ = t[9:12]
_ = t[11:12] _ = t[11:12]
_ = t[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" _ = t[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds"
} }

View file

@ -0,0 +1,18 @@
// run
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
var x = [4]int32{-0x7fffffff, 0x7fffffff, 2, 4}
func main() {
if x[0] > x[1] {
panic("fail 1")
}
if x[2]&x[3] < 0 {
panic("fail 2") // Fails here
}
}

Some files were not shown because too many files have changed in this diff Show more