diff --git a/doc/go1.16.html b/doc/go1.16.html
index 6e371b9617..6618240ed1 100644
--- a/doc/go1.16.html
+++ b/doc/go1.16.html
@@ -80,17 +80,16 @@ Do not send CLs removing the interior tags from such phrases.
Go command
-
- TODO
-
-
-
-
-
-
-
Modules
+
+ Module-aware mode is enabled by default, regardless of whether a
+ go.mod file is present in the current working directory or a
+ parent directory. Specifically, the GO111MODULE environment
+ variable now defaults to on. To switch to the previous behavior,
+ set GO111MODULE to auto.
+
+
Build commands like go build and go
test no longer modify go.mod and go.sum
@@ -107,9 +106,7 @@ Do not send CLs removing the interior tags from such phrases.
install to build and install packages in module-aware mode,
ignoring the go.mod file in the current directory or any parent
directory, if there is one. This is useful for installing executables without
- affecting the dependencies of the main module.
- TODO: write and link to section in golang.org/ref/mod
- TODO: write and link to blog post
+ affecting the dependencies of the main module.
@@ -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
by other modules. A module author may retract a version after a severe problem
is discovered or if the version was published unintentionally.
- TODO: write and link to section in golang.org/ref/mod
- TODO: write and link to tutorial or blog post
@@ -138,6 +133,14 @@ Do not send CLs removing the interior tags from such phrases.
resolving missing packages.
+
+ The go command now ignores requirements on module versions
+ excluded by exclude directives in the main module. Previously,
+ the go command used the next version higher than an excluded
+ version, but that version could change over time, resulting in
+ non-reproducible builds.
+
+
go test
@@ -150,6 +153,15 @@ Do not send CLs removing the interior tags from such phrases.
that is still considered to be a passing test.
+
+ go test reports an error when the -c
+ or -i flags are used together with unknown flags. Normally,
+ unknown flags are passed to tests, but when -c or -i
+ are used, tests are not run.
+
+
+go get
+
The go get -insecure flag is
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 go help environment for details.
-go get
-
go get example.com/mod@patch now
requires that some version of example.com/mod already be
@@ -171,6 +181,21 @@ Do not send CLs removing the interior tags from such phrases.
to patch even newly-added dependencies.)
+GOVCS environment variable
+
+
+ GOVCS is a new environment variable that limits which version
+ control tools the go command may use to download source code.
+ This mitigates security issues with tools that are typically used in trusted,
+ authenticated environments. By default, git and hg
+ may be used to download code from any repository. svn,
+ bzr, and fossil may only be used to download code
+ from repositories with module paths or package paths matching patterns in
+ the GOPRIVATE environment variable. See
+ go
+ help vcs for details.
+
+
The all pattern
@@ -380,7 +405,8 @@ Do not send CLs removing the interior tags from such phrases.
- TODO: https://golang.org/cl/246637 : make config.Clone return nil if the source is nil
+ Config.Clone now returns
+ a nil *Config if the source is nil, rather than panicking.
@@ -416,7 +442,9 @@ Do not send CLs removing the interior tags from such phrases.
- TODO: https://golang.org/cl/257257 : return additional chains from Verify on Windows
+ On Windows, Certificate.Verify
+ will now return all certificate chains that are built by the platform
+ certificate verifier, instead of just the highest ranked chain.
@@ -425,16 +453,26 @@ Do not send CLs removing the interior tags from such phrases.
+
encoding/asn1
+
+
+ Unmarshal and
+ UnmarshalWithParams
+ 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 encoding/json .
+
+
+
+
encoding/json
-
- The error message for
- SyntaxError
- now begins with "json: ", matching the other errors in the package.
-
-
- TODO: https://golang.org/cl/234818 : allow semicolon in field key / struct tag
+ The json struct field tags understood by
+ Marshal ,
+ Unmarshal ,
+ and related functionality now permit semicolon characters within
+ a JSON object name for a Go struct field.
@@ -580,7 +618,10 @@ Do not send CLs removing the interior tags from such phrases.
os
- TODO: https://golang.org/cl/242998 : export errFinished as ErrProcessDone
+ Process.Signal now
+ returns ErrProcessDone
+ instead of the unexported errFinished when the process has
+ already finished.
@@ -636,7 +677,10 @@ Do not send CLs removing the interior tags from such phrases.
runtime/debug
- TODO: https://golang.org/cl/249677 : provide Addr method for errors from SetPanicOnFault
+ The runtime.Error values
+ used when SetPanicOnFault is enabled may now have an
+ Addr method. If that method exists, it returns the memory
+ address that triggered the fault.
@@ -672,8 +716,9 @@ Do not send CLs removing the interior tags from such phrases.
text/template
-
- TODO: https://golang.org/cl/254257 : allow newlines inside action delimiters
+
+ Newlines characters are now allowed inside action delimiters,
+ permitting actions to span multiple lines.
diff --git a/doc/go1.html b/doc/go1.html
index 34e305b93c..939ee24df5 100644
--- a/doc/go1.html
+++ b/doc/go1.html
@@ -1647,14 +1647,14 @@ c := signal.Incoming()
is
-c := make(chan os.Signal)
+c := make(chan os.Signal, 1)
signal.Notify(c) // ask for all signals
but most code should list the specific signals it wants to handle instead:
-c := make(chan os.Signal)
+c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT)
diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go
index 75086f1f24..d7b34bd0d8 100644
--- a/src/bufio/bufio_test.go
+++ b/src/bufio/bufio_test.go
@@ -146,7 +146,7 @@ func TestReader(t *testing.T) {
for i := 0; i < len(texts)-1; i++ {
texts[i] = str + "\n"
all += texts[i]
- str += string(rune(i)%26 + 'a')
+ str += string(rune(i%26 + 'a'))
}
texts[len(texts)-1] = all
diff --git a/src/cmd/asm/internal/asm/testdata/riscvenc.s b/src/cmd/asm/internal/asm/testdata/riscvenc.s
index e30a576473..9a49d96ca0 100644
--- a/src/cmd/asm/internal/asm/testdata/riscvenc.s
+++ b/src/cmd/asm/internal/asm/testdata/riscvenc.s
@@ -340,11 +340,11 @@ start:
// Branch pseudo-instructions
BEQZ X5, start // BEQZ X5, 2 // e38602c0
BGEZ X5, start // BGEZ X5, 2 // e3d402c0
- BGT X5, X6, start // BGT X5, X6, 2 // e3c262c0
- BGTU X5, X6, start // BGTU X5, X6, 2 // e3e062c0
+ BGT X5, X6, start // BGT X5, X6, 2 // e34253c0
+ BGTU X5, X6, start // BGTU X5, X6, 2 // e36053c0
BGTZ X5, start // BGTZ X5, 2 // e34e50be
- BLE X5, X6, start // BLE X5, X6, 2 // e3dc62be
- BLEU X5, X6, start // BLEU X5, X6, 2 // e3fa62be
+ BLE X5, X6, start // BLE X5, X6, 2 // e35c53be
+ BLEU X5, X6, start // BLEU X5, X6, 2 // e37a53be
BLEZ X5, start // BLEZ X5, 2 // e35850be
BLTZ X5, start // BLTZ X5, 2 // e3c602be
BNEZ X5, start // BNEZ X5, 2 // e39402be
diff --git a/src/cmd/buildid/buildid.go b/src/cmd/buildid/buildid.go
index 699d977950..8e02a7ae10 100644
--- a/src/cmd/buildid/buildid.go
+++ b/src/cmd/buildid/buildid.go
@@ -62,7 +62,7 @@ func main() {
return
}
- f, err = os.OpenFile(file, os.O_WRONLY, 0)
+ f, err = os.OpenFile(file, os.O_RDWR, 0)
if err != nil {
log.Fatal(err)
}
diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go
index e372259c78..6625ccf5e2 100644
--- a/src/cmd/compile/fmt_test.go
+++ b/src/cmd/compile/fmt_test.go
@@ -52,6 +52,7 @@ import (
"go/types"
"internal/testenv"
"io"
+ "io/fs"
"io/ioutil"
"log"
"os"
@@ -89,7 +90,7 @@ func TestFormats(t *testing.T) {
testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok
// 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.Name() == "testdata" {
return filepath.SkipDir
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index ec2c67c1fa..e6f899a2c7 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -790,10 +790,10 @@ func (f *Func) spSb() (sp, sb *Value) {
}
}
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 {
- sp = f.Entry.NewValue0(initpos, OpSP, f.Config.Types.Uintptr)
+ sp = f.Entry.NewValue0(initpos.WithNotStmt(), OpSP, f.Config.Types.Uintptr)
}
return
}
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
index 946acd4ccc..6637c6cae4 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -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:(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)
-(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LT (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:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LT (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:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LT (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:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (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)
-(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LE (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:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LE (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:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LE (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:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (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)
-(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LT (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:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LT (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:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LT (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:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (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)
-(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LE (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:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LE (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:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LE (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:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (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)
+(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 => (LTnoov (TSTconst [c] x) 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 => (LTnoov (TSTshiftRL 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 => (LTnoov (TSTshiftLLreg 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 => (LTnoov (TSTshiftRAreg x y z) 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 => (LEnoov (TSTconst [c] x) 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 => (LEnoov (TSTshiftRL 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 => (LEnoov (TSTshiftLLreg 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 => (LEnoov (TSTshiftRAreg x y z) 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 => (LTnoov (TEQconst [c] x) 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 => (LTnoov (TEQshiftRL 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 => (LTnoov (TEQshiftLLreg 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 => (LTnoov (TEQshiftRAreg x y z) 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 => (LEnoov (TEQconst [c] x) 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 => (LEnoov (TEQshiftRL 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 => (LEnoov (TEQshiftLLreg 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 => (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:(MULS x y a)) yes no) && l.Uses==1 => (GTnoov (CMP a (MUL x y)) 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:(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)
-(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 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:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftLL x y [c]) 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:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftRA 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:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftRLreg 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)
-(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GE (TST x y) yes no)
-(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GE (TSTconst [c] x) 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:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftRL 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:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftLLreg x y z) 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:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftRAreg x y z) yes no)
-(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GT (TEQ x y) yes no)
-(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GT (TEQconst [c] x) 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:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftRL 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:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftLLreg x y z) 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:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftRAreg x y z) yes no)
-(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GE (TEQ x y) yes no)
-(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GE (TEQconst [c] x) 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:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftRL 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:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftLLreg x y z) 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:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRAreg x y z) yes no)
+(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GTnoov (TST x y) yes no)
+(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TSTconst [c] x) 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:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftRL x y [c]) 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:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftLLreg 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)
+(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftRAreg x y z) yes no)
+(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GEnoov (TST x y) yes no)
+(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TSTconst [c] x) 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:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftRL x y [c]) 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:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftLLreg 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)
+(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftRAreg x y z) yes no)
+(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GTnoov (TEQ x y) yes no)
+(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TEQconst [c] x) 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:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftRL x y [c]) 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:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftLLreg 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)
+(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftRAreg x y z) yes no)
+(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GEnoov (TEQ x y) yes no)
+(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TEQconst [c] x) 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:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftRL x y [c]) 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:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftLLreg 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)))])
(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))])
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index 47fd0a94cc..68495c558c 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -17389,7 +17389,7 @@ func rewriteBlockARM(b *Block) bool {
}
// match: (GE (CMPconst [0] l:(AND x y)) yes no)
// cond: l.Uses==1
- // result: (GE (TST x y) yes no)
+ // result: (GEnoov (TST x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
break
}
// match: (GE (CMPconst [0] l:(ANDconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (GE (TSTconst [c] x) yes no)
+ // result: (GEnoov (TSTconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg(x)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(XOR x y)) yes no)
// cond: l.Uses==1
- // result: (GE (TEQ x y) yes no)
+ // result: (GEnoov (TEQ x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
break
}
// match: (GE (CMPconst [0] l:(XORconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (GE (TEQconst [c] x) yes no)
+ // result: (GEnoov (TEQconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg(x)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
case BlockARMGEnoov:
@@ -18278,34 +18278,6 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGTnoov, v0)
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)
// cond: l.Uses==1
// result: (GTnoov (CMN a (MUL x y)) yes no)
@@ -18331,9 +18303,37 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGTnoov, v0)
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)
// cond: l.Uses==1
- // result: (GT (TSTconst [c] x) yes no)
+ // result: (GTnoov (TSTconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg(x)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(XOR x y)) yes no)
// cond: l.Uses==1
- // result: (GT (TEQ x y) yes no)
+ // result: (GTnoov (TEQ x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
break
}
// match: (GT (CMPconst [0] l:(XORconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (GT (TEQconst [c] x) yes no)
+ // result: (GTnoov (TEQconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg(x)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
case BlockARMGTnoov:
@@ -19312,7 +19312,7 @@ func rewriteBlockARM(b *Block) bool {
}
// match: (LE (CMPconst [0] l:(AND x y)) yes no)
// cond: l.Uses==1
- // result: (LE (TST x y) yes no)
+ // result: (LEnoov (TST x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
break
}
// match: (LE (CMPconst [0] l:(ANDconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (LE (TSTconst [c] x) yes no)
+ // result: (LEnoov (TSTconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg(x)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(XOR x y)) yes no)
// cond: l.Uses==1
- // result: (LE (TEQ x y) yes no)
+ // result: (LEnoov (TEQ x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
break
}
// match: (LE (CMPconst [0] l:(XORconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (LE (TEQconst [c] x) yes no)
+ // result: (LEnoov (TEQconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg(x)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
case BlockARMLEnoov:
@@ -20228,7 +20228,7 @@ func rewriteBlockARM(b *Block) bool {
}
// match: (LT (CMPconst [0] l:(AND x y)) yes no)
// cond: l.Uses==1
- // result: (LT (TST x y) yes no)
+ // result: (LTnoov (TST x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
break
}
// match: (LT (CMPconst [0] l:(ANDconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (LT (TSTconst [c] x) yes no)
+ // result: (LTnoov (TSTconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg(x)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(XOR x y)) yes no)
// cond: l.Uses==1
- // result: (LT (TEQ x y) yes no)
+ // result: (LTnoov (TEQ x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
break
}
// match: (LT (CMPconst [0] l:(XORconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (LT (TEQconst [c] x) yes no)
+ // result: (LTnoov (TEQconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg(x)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
// 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 {
v_0 := b.Controls[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.AuxInt = int32ToAuxInt(c)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
// 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 {
v_0 := b.Controls[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.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
case BlockARMLTnoov:
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index 839579349a..5e1647cbf0 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -55,6 +55,7 @@ var bootstrapDirs = []string{
"cmd/compile/internal/x86",
"cmd/compile/internal/wasm",
"cmd/internal/bio",
+ "cmd/internal/codesign",
"cmd/internal/gcprog",
"cmd/internal/dwarf",
"cmd/internal/edit",
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 2a17ab9cae..955ce2a063 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -1509,6 +1509,7 @@ func (t *tester) makeGOROOTUnwritable() (undo func()) {
}
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 {
if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" {
if suffix == gocacheSubdir {
diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go
index 1cea9a876a..1cedf992cf 100644
--- a/src/cmd/fix/main.go
+++ b/src/cmd/fix/main.go
@@ -234,10 +234,10 @@ func report(err error) {
}
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) {
err = processFile(path, false)
}
@@ -247,7 +247,7 @@ func visitFile(path string, f fs.FileInfo, err error) error {
return nil
}
-func isGoFile(f fs.FileInfo) bool {
+func isGoFile(f fs.DirEntry) bool {
// ignore non-Go files
name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
index 6f55b2d1c8..bfee2c7f06 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -7,7 +7,7 @@ require (
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
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/tools v0.0.0-20201110201400-7099162a900a
)
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
index 8775b754d8..7a743d9f73 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -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/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
+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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index a02231fa98..1b8a21ecfa 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -774,7 +774,7 @@ func (tg *testgoData) cleanup() {
func removeAll(dir string) error {
// module cache has 0444 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 {
// chmod not only directories, but also things that we couldn't even stat
// due to permission errors: they may also be unreadable directories.
if err != nil || info.IsDir() {
@@ -820,8 +820,8 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
} {
srcdir := filepath.Join(testGOROOT, copydir)
tg.tempDir(filepath.Join("goroot", copydir))
- err := filepath.Walk(srcdir,
- func(path string, info fs.FileInfo, err error) error {
+ err := filepath.WalkDir(srcdir,
+ func(path string, info fs.DirEntry, err error) error {
if err != nil {
return err
}
@@ -838,8 +838,8 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
return err
}
tg.tempFile(dest, string(data))
- if err := os.Chmod(tg.path(dest), info.Mode()|0200); err != nil {
- return err
+ if strings.Contains(copydir, filepath.Join("pkg", "tool")) {
+ os.Chmod(tg.path(dest), 0777)
}
return nil
})
diff --git a/src/cmd/go/internal/base/signal.go b/src/cmd/go/internal/base/signal.go
index 54d11876d0..05befcf7f0 100644
--- a/src/cmd/go/internal/base/signal.go
+++ b/src/cmd/go/internal/base/signal.go
@@ -15,7 +15,7 @@ var Interrupted = make(chan struct{})
// processSignals setups signal handler.
func processSignals() {
- sig := make(chan os.Signal)
+ sig := make(chan os.Signal, 1)
signal.Notify(sig, signalsToIgnore...)
go func() {
<-sig
diff --git a/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go
index c5fbb31b2b..286d3f7220 100644
--- a/src/cmd/go/internal/modfetch/codehost/codehost.go
+++ b/src/cmd/go/internal/modfetch/codehost/codehost.go
@@ -264,6 +264,9 @@ func RunWithStdin(dir string, stdin io.Reader, cmdline ...interface{}) ([]byte,
}
cmd := str.StringList(cmdline...)
+ if os.Getenv("TESTGOVCS") == "panic" {
+ panic(fmt.Sprintf("use of vcs: %v", cmd))
+ }
if cfg.BuildX {
text := new(strings.Builder)
if dir != "" {
diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go
index a3e2cd1f9d..2ee78de5b2 100644
--- a/src/cmd/go/internal/modfetch/fetch.go
+++ b/src/cmd/go/internal/modfetch/fetch.go
@@ -318,9 +318,10 @@ func makeDirsReadOnly(dir string) {
mode fs.FileMode
}
var dirs []pathMode // in lexical order
- filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
- if err == nil && info.Mode()&0222 != 0 {
- if info.IsDir() {
+ filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
+ if err == nil && d.IsDir() {
+ info, err := d.Info()
+ if err == nil && info.Mode()&0222 != 0 {
dirs = append(dirs, pathMode{path, info.Mode()})
}
}
@@ -337,7 +338,7 @@ func makeDirsReadOnly(dir string) {
// any permission changes needed to do so.
func RemoveAll(dir string) error {
// 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 {
return nil // ignore errors walking in file system
}
diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go
index ecb0142524..e5f55879ee 100644
--- a/src/cmd/go/internal/modget/get.go
+++ b/src/cmd/go/internal/modget/get.go
@@ -436,32 +436,9 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
work.BuildInit()
pkgs := load.PackagesForBuild(ctx, pkgPatterns)
work.InstallPackages(ctx, pkgPatterns, pkgs)
-
- haveExe := false
- for _, pkg := range pkgs {
- 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.
+ // TODO(#40276): After Go 1.16, print a deprecation notice when building
+ // and installing main packages. 'go install pkg' or
+ // 'go install pkg@version' should be used instead.
}
if !modload.HasModRoot() {
diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go
index a9b77c82b3..1c31a5f90a 100644
--- a/src/cmd/go/internal/modload/init.go
+++ b/src/cmd/go/internal/modload/init.go
@@ -1018,7 +1018,7 @@ func keepSums(addDirect bool) map[module.Version]bool {
}
}
for _, pkg := range loaded.pkgs {
- if pkg.testOf != nil || pkg.inStd {
+ if pkg.testOf != nil || pkg.inStd || module.CheckImportPath(pkg.path) != nil {
continue
}
for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) {
diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go
index e7bef9f591..4894ecdc35 100644
--- a/src/cmd/go/internal/vcs/vcs.go
+++ b/src/cmd/go/internal/vcs/vcs.go
@@ -23,6 +23,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/search"
+ "cmd/go/internal/str"
"cmd/go/internal/web"
"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
// version control system and repository name.
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
repo string // repository 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
// using the mappings defined in vcsPaths.
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
// hg and git require. Diagnose this helpfully.
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+"//")
}
for _, srv := range vcsPaths {
- if !strings.HasPrefix(importPath, srv.prefix) {
+ if !str.HasPathPrefix(importPath, srv.pathPrefix) {
continue
}
m := srv.regexp.FindStringSubmatch(importPath)
if m == nil {
- if srv.prefix != "" {
- return nil, importErrorf(importPath, "invalid %s import path %q", srv.prefix, importPath)
+ if srv.pathPrefix != "" {
+ return nil, importErrorf(importPath, "invalid %s import path %q", srv.pathPrefix, importPath)
}
continue
}
// Build map of named subexpression matches for expand.
match := map[string]string{
- "prefix": srv.prefix,
+ "prefix": srv.pathPrefix + "/",
"import": importPath,
}
for i, name := range srv.regexp.SubexpNames() {
@@ -1098,18 +1113,6 @@ type metaImport struct {
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
// but none match our import path.
type ImportMismatchError struct {
@@ -1133,7 +1136,7 @@ func matchGoImport(imports []metaImport, importPath string) (metaImport, error)
errImportMismatch := ImportMismatchError{importPath: importPath}
for i, im := range imports {
- if !pathPrefix(importPath, im.Prefix) {
+ if !str.HasPathPrefix(importPath, im.Prefix) {
errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix)
continue
}
@@ -1175,52 +1178,52 @@ func expand(match map[string]string, s string) string {
var vcsPaths = []*vcsPath{
// Github
{
- prefix: "github.com/",
- regexp: lazyregexp.New(`^(?Pgithub\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
- vcs: "git",
- repo: "https://{root}",
- check: noVCSSuffix,
+ pathPrefix: "github.com",
+ regexp: lazyregexp.New(`^(?Pgithub\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
+ vcs: "git",
+ repo: "https://{root}",
+ check: noVCSSuffix,
},
// Bitbucket
{
- prefix: "bitbucket.org/",
- regexp: lazyregexp.New(`^(?Pbitbucket\.org/(?P[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
- repo: "https://{root}",
- check: bitbucketVCS,
+ pathPrefix: "bitbucket.org",
+ regexp: lazyregexp.New(`^(?Pbitbucket\.org/(?P[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
+ repo: "https://{root}",
+ check: bitbucketVCS,
},
// IBM DevOps Services (JazzHub)
{
- prefix: "hub.jazz.net/git/",
- regexp: lazyregexp.New(`^(?Phub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
- vcs: "git",
- repo: "https://{root}",
- check: noVCSSuffix,
+ pathPrefix: "hub.jazz.net/git",
+ regexp: lazyregexp.New(`^(?Phub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
+ vcs: "git",
+ repo: "https://{root}",
+ check: noVCSSuffix,
},
// Git at Apache
{
- prefix: "git.apache.org/",
- regexp: lazyregexp.New(`^(?Pgit\.apache\.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`),
- vcs: "git",
- repo: "https://{root}",
+ pathPrefix: "git.apache.org",
+ regexp: lazyregexp.New(`^(?Pgit\.apache\.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`),
+ vcs: "git",
+ repo: "https://{root}",
},
// Git at OpenStack
{
- prefix: "git.openstack.org/",
- regexp: lazyregexp.New(`^(?Pgit\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`),
- vcs: "git",
- repo: "https://{root}",
+ pathPrefix: "git.openstack.org",
+ regexp: lazyregexp.New(`^(?Pgit\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`),
+ vcs: "git",
+ repo: "https://{root}",
},
// chiselapp.com for fossil
{
- prefix: "chiselapp.com/",
- regexp: lazyregexp.New(`^(?Pchiselapp\.com/user/[A-Za-z0-9]+/repository/[A-Za-z0-9_.\-]+)$`),
- vcs: "fossil",
- repo: "https://{root}",
+ pathPrefix: "chiselapp.com",
+ regexp: lazyregexp.New(`^(?Pchiselapp\.com/user/[A-Za-z0-9]+/repository/[A-Za-z0-9_.\-]+)$`),
+ vcs: "fossil",
+ repo: "https://{root}",
},
// General syntax for any server.
@@ -1238,11 +1241,11 @@ var vcsPaths = []*vcsPath{
var vcsPathsAfterDynamic = []*vcsPath{
// Launchpad. See golang.org/issue/11436.
{
- prefix: "launchpad.net/",
- regexp: lazyregexp.New(`^(?Plaunchpad\.net/((?P[A-Za-z0-9_.\-]+)(?P/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
- vcs: "bzr",
- repo: "https://{root}",
- check: launchpadVCS,
+ pathPrefix: "launchpad.net",
+ regexp: lazyregexp.New(`^(?Plaunchpad\.net/((?P[A-Za-z0-9_.\-]+)(?P/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
+ vcs: "bzr",
+ repo: "https://{root}",
+ check: launchpadVCS,
},
}
diff --git a/src/cmd/go/internal/version/version.go b/src/cmd/go/internal/version/version.go
index 44ac24c62d..58cbd32e78 100644
--- a/src/cmd/go/internal/version/version.go
+++ b/src/cmd/go/internal/version/version.go
@@ -88,8 +88,15 @@ func runVersion(ctx context.Context, cmd *base.Command, args []string) {
// scanDir scans a directory for executables to run scanFile on.
func scanDir(dir string) {
- filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
- if info.Mode().IsRegular() || info.Mode()&fs.ModeSymlink != 0 {
+ filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
+ 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)
}
return nil
@@ -120,6 +127,7 @@ func scanFile(file string, info fs.FileInfo, mustPrint bool) {
}
info = i
}
+
if !isExe(file, info) {
if mustPrint {
fmt.Fprintf(os.Stderr, "%s: not executable file\n", file)
diff --git a/src/cmd/go/internal/web/http.go b/src/cmd/go/internal/web/http.go
index e0509808d6..72fa2b2ca6 100644
--- a/src/cmd/go/internal/web/http.go
+++ b/src/cmd/go/internal/web/http.go
@@ -80,6 +80,13 @@ func get(security SecurityMode, url *urlpkg.URL) (*Response, error) {
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) {
// Note: The -v build flag does not mean "print logging information",
// despite its historical misuse for this in GOPATH-based go get.
diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go
index a88544e1af..3c7be5a3e3 100644
--- a/src/cmd/go/internal/work/buildid.go
+++ b/src/cmd/go/internal/work/buildid.go
@@ -647,7 +647,7 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error {
}
if rewrite {
- w, err := os.OpenFile(target, os.O_WRONLY, 0)
+ w, err := os.OpenFile(target, os.O_RDWR, 0)
if err != nil {
return err
}
diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go
index b1d1499038..aee3742f13 100644
--- a/src/cmd/go/script_test.go
+++ b/src/cmd/go/script_test.go
@@ -142,6 +142,9 @@ func (ts *testScript) setup() {
"goversion=" + goVersion(ts),
":=" + string(os.PathListSeparator),
}
+ if !testenv.HasExternalNetwork() {
+ ts.env = append(ts.env, "TESTGONETWORK=panic", "TESTGOVCS=panic")
+ }
if runtime.GOOS == "plan9" {
ts.env = append(ts.env, "path="+testBin+string(filepath.ListSeparator)+os.Getenv("path"))
diff --git a/src/cmd/go/testdata/addmod.go b/src/cmd/go/testdata/addmod.go
index d1b6467c5d..71ac47fdc1 100644
--- a/src/cmd/go/testdata/addmod.go
+++ b/src/cmd/go/testdata/addmod.go
@@ -122,8 +122,8 @@ func main() {
{Name: ".info", Data: info},
}
dir = filepath.Clean(dir)
- err = filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
- if !info.Mode().IsRegular() {
+ err = filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
+ if !info.Type().IsRegular() {
return nil
}
name := info.Name()
diff --git a/src/cmd/go/testdata/savedir.go b/src/cmd/go/testdata/savedir.go
index 04902df61e..75895ee279 100644
--- a/src/cmd/go/testdata/savedir.go
+++ b/src/cmd/go/testdata/savedir.go
@@ -49,7 +49,7 @@ func main() {
a := new(txtar.Archive)
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 {
return nil
}
@@ -60,7 +60,7 @@ func main() {
}
return nil
}
- if !info.Mode().IsRegular() {
+ if !info.Type().IsRegular() {
return nil
}
data, err := ioutil.ReadFile(path)
diff --git a/src/cmd/go/testdata/script/mod_get_deprecate_install.txt b/src/cmd/go/testdata/script/mod_get_deprecate_install.txt
deleted file mode 100644
index 7f5bcad410..0000000000
--- a/src/cmd/go/testdata/script/mod_get_deprecate_install.txt
+++ /dev/null
@@ -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'''
diff --git a/src/cmd/go/testdata/script/mod_gonoproxy.txt b/src/cmd/go/testdata/script/mod_gonoproxy.txt
index 546605da21..204786969f 100644
--- a/src/cmd/go/testdata/script/mod_gonoproxy.txt
+++ b/src/cmd/go/testdata/script/mod_gonoproxy.txt
@@ -21,7 +21,7 @@ go get -d rsc.io/quote
# Download .info files needed for 'go list -m all' later.
# TODO(#42723): either 'go list -m' should not read these files,
# or 'go get' and 'go mod tidy' should download them.
-go list -m all
+go list -m all
stdout '^golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c$'
# When GOPROXY is not empty but contains no entries, an error should be reported.
diff --git a/src/cmd/go/testdata/script/mod_import_issue42891.txt b/src/cmd/go/testdata/script/mod_import_issue42891.txt
new file mode 100644
index 0000000000..a78cab29ba
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_import_issue42891.txt
@@ -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 "/"
diff --git a/src/cmd/go/testdata/script/mod_proxy_invalid.txt b/src/cmd/go/testdata/script/mod_proxy_invalid.txt
index b9418b4df1..6427cc1527 100644
--- a/src/cmd/go/testdata/script/mod_proxy_invalid.txt
+++ b/src/cmd/go/testdata/script/mod_proxy_invalid.txt
@@ -2,7 +2,7 @@ env GO111MODULE=on
env GOPROXY=$GOPROXY/invalid
! 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
-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$'
diff --git a/src/cmd/go/testdata/script/mod_query_empty.txt b/src/cmd/go/testdata/script/mod_query_empty.txt
index 1f13d7ad69..f8b6e3e97e 100644
--- a/src/cmd/go/testdata/script/mod_query_empty.txt
+++ b/src/cmd/go/testdata/script/mod_query_empty.txt
@@ -40,7 +40,7 @@ env GOPROXY=file:///$WORK/gatekeeper
chmod 0000 $WORK/gatekeeper/example.com/join/subpkg/@latest
cp go.mod.orig go.mod
! 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 --
module example.com/othermodule
diff --git a/src/cmd/go/testdata/script/mod_sumdb_proxy.txt b/src/cmd/go/testdata/script/mod_sumdb_proxy.txt
index 7bbc3f9e19..70b8e3fc44 100644
--- a/src/cmd/go/testdata/script/mod_sumdb_proxy.txt
+++ b/src/cmd/go/testdata/script/mod_sumdb_proxy.txt
@@ -17,14 +17,12 @@ rm $GOPATH/pkg/mod/cache/download/sumdb
rm go.sum
# direct access fails (because localhost.localdev does not exist)
-# The text of the error message is hard to predict because some DNS servers
-# will resolve unknown domains like localhost.localdev to a real IP
-# to serve ads.
+# web.get is providing the error message - there's no actual network access.
cp go.mod.orig go.mod
env GOSUMDB=$sumdb
env GOPROXY=direct
! 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 go.sum
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index dba2411eed..719c681a3e 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -74,7 +74,7 @@ func initParserMode() {
}
}
-func isGoFile(f fs.FileInfo) bool {
+func isGoFile(f fs.DirEntry) bool {
// ignore non-Go files
name := f.Name()
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
}
-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) {
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) {
- filepath.Walk(path, visitFile)
+ filepath.WalkDir(path, visitFile)
}
func main() {
diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go
index 28306ce83e..4a821705f1 100644
--- a/src/cmd/gofmt/long_test.go
+++ b/src/cmd/gofmt/long_test.go
@@ -108,12 +108,12 @@ func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
func genFilenames(t *testing.T, filenames chan<- string) {
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 {
t.Error(err)
return nil
}
- if isGoFile(fi) {
+ if isGoFile(d) {
filenames <- filename
nfiles++
}
@@ -124,13 +124,13 @@ func genFilenames(t *testing.T, filenames chan<- string) {
if *files != "" {
for _, filename := range strings.Split(*files, ",") {
fi, err := os.Stat(filename)
- handleFile(filename, fi, err)
+ handleFile(filename, &statDirEntry{fi}, err)
}
return // ignore files under -root
}
// otherwise, test all Go files under *root
- filepath.Walk(*root, handleFile)
+ filepath.WalkDir(*root, handleFile)
}
func TestAll(t *testing.T) {
@@ -164,3 +164,12 @@ func TestAll(t *testing.T) {
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 }
diff --git a/src/cmd/internal/buildid/buildid_test.go b/src/cmd/internal/buildid/buildid_test.go
index 904c2c6f37..e832f9987e 100644
--- a/src/cmd/internal/buildid/buildid_test.go
+++ b/src/cmd/internal/buildid/buildid_test.go
@@ -11,6 +11,7 @@ import (
"io/ioutil"
"os"
"reflect"
+ "strings"
"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])
+ }
+ }
+ }
+}
diff --git a/src/cmd/internal/buildid/rewrite.go b/src/cmd/internal/buildid/rewrite.go
index 5be54552a6..a7928959c4 100644
--- a/src/cmd/internal/buildid/rewrite.go
+++ b/src/cmd/internal/buildid/rewrite.go
@@ -6,7 +6,9 @@ package buildid
import (
"bytes"
+ "cmd/internal/codesign"
"crypto/sha256"
+ "debug/macho"
"fmt"
"io"
)
@@ -26,6 +28,11 @@ func FindAndHash(r io.Reader, id string, bufSize int) (matches []int64, hash [32
zeros := make([]byte, len(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,
// but we need to worry about what happens if id is broken up
// and returned in parts by two different reads.
@@ -87,5 +94,69 @@ func Rewrite(w io.WriterAt, pos []int64, id string) error {
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
}
+
+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
+}
diff --git a/src/cmd/internal/codesign/codesign.go b/src/cmd/internal/codesign/codesign.go
new file mode 100644
index 0000000000..0517a10640
--- /dev/null
+++ b/src/cmd/internal/codesign/codesign.go
@@ -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[:])
+ }
+}
diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go
index 7362e7868b..9ea21873c5 100644
--- a/src/cmd/internal/moddeps/moddeps_test.go
+++ b/src/cmd/internal/moddeps/moddeps_test.go
@@ -33,7 +33,7 @@ func findGorootModules(t *testing.T) []gorootModule {
goBin := testenv.GoToolPath(t)
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 {
return err
}
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 0cffa54fa6..9257a6453a 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -1777,15 +1777,15 @@ func instructionsForProg(p *obj.Prog) []*instruction {
case ABGEZ:
ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
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:
- 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:
ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
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:
- 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:
ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
case ABLTZ:
diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go
index 803ba8c77c..279aeb2c32 100644
--- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go
+++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go
@@ -11,6 +11,8 @@ import (
)
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 testBGT(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 testBLEU(a, b 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 testBNEZ(a int64) (r bool)
@@ -29,30 +33,75 @@ func TestBranchCondition(t *testing.T) {
fn func(a, b int64) 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, -1, testBGT, false},
- {"BGT", -1, 0, testBGT, true},
- {"BGT", 1, 0, testBGT, false},
- {"BGTU", 0, 1, testBGTU, true},
- {"BGTU", 0, -1, testBGTU, true},
- {"BGTU", -1, 0, testBGTU, false},
- {"BGTU", 1, 0, testBGTU, false},
- {"BLE", 0, 1, testBLE, false},
- {"BLE", 0, -1, testBLE, true},
+ {"BGT", 0, -1, testBGT, true},
+ {"BGT", -1, 0, testBGT, false},
+ {"BGT", 1, 0, testBGT, true},
+ {"BGTU", 0, 1, testBGTU, false},
+ {"BGTU", 0, 0, testBGTU, false},
+ {"BGTU", 0, -1, testBGTU, false},
+ {"BGTU", -1, 0, testBGTU, true},
+ {"BGTU", 1, 0, testBGTU, true},
+ {"BLE", 0, 1, testBLE, true},
{"BLE", 0, 0, testBLE, true},
- {"BLE", -1, 0, testBLE, false},
- {"BLE", 1, 0, testBLE, true},
- {"BLEU", 0, 1, testBLEU, false},
- {"BLEU", 0, -1, testBLEU, false},
+ {"BLE", 0, -1, testBLE, false},
+ {"BLE", -1, 0, testBLE, true},
+ {"BLE", 1, 0, testBLE, false},
+ {"BLEU", 0, 1, testBLEU, true},
{"BLEU", 0, 0, testBLEU, true},
- {"BLEU", -1, 0, testBLEU, true},
- {"BLEU", 1, 0, testBLEU, true},
+ {"BLEU", 0, -1, 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 {
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 {
- 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)
}
})
}
diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s
index 6cff235848..8dd6f563af 100644
--- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s
+++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s
@@ -16,6 +16,28 @@ b:
MOV X6, r+8(FP)
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)
TEXT ·testBGEZ(SB),NOSPLIT,$0-0
MOV a+0(FP), X5
@@ -90,6 +112,28 @@ b:
MOV X6, r+8(FP)
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)
TEXT ·testBLTZ(SB),NOSPLIT,$0-0
MOV a+0(FP), X5
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index 360c5338ba..2d09a6160a 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -413,11 +413,7 @@ func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
case objabi.R_CALL:
if siz == 4 {
if ldr.SymType(r.Xsym) == sym.SDYNIMPORT {
- if ctxt.DynlinkingGo() {
- out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
- } else {
- out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
- }
+ out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
} else {
out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
}
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index 0cb3cc25c0..d1e06239a5 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -35,11 +35,12 @@ func (mode *BuildMode) Set(s string) error {
default:
return fmt.Errorf("invalid buildmode: %q", s)
case "exe":
- if objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" {
- *mode = BuildModePIE // On darwin/arm64 everything is PIE.
- break
+ switch objabi.GOOS + "/" + objabi.GOARCH {
+ case "darwin/arm64", "windows/arm": // On these platforms, everything is PIE
+ *mode = BuildModePIE
+ default:
+ *mode = BuildModeExe
}
- *mode = BuildModeExe
case "pie":
switch objabi.GOOS {
case "aix", "android", "linux", "windows", "darwin", "ios":
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 735b84d37d..e1cc7184de 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -298,6 +298,11 @@ func (ctxt *Link) CanUsePlugins() bool {
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 (
dynlib []string
ldflag []string
@@ -1642,6 +1647,12 @@ func (ctxt *Link) hostlink() {
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
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index 51abefc887..f459576420 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -6,6 +6,7 @@ package ld
import (
"bytes"
+ "cmd/internal/codesign"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
@@ -17,6 +18,7 @@ import (
"os"
"sort"
"strings"
+ "unsafe"
)
type MachoHdr struct {
@@ -245,6 +247,8 @@ const (
BIND_SUBOPCODE_THREADED_APPLY = 0x01
)
+const machoHeaderSize64 = 8 * 4 // size of 64-bit Mach-O header
+
// Mach-O file writing
// 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)
+ ldr := ctxt.loader
+
/* apple MACH */
va := *FlagTextAddr - int64(HEADR)
@@ -757,25 +763,27 @@ func asmbMacho(ctxt *Link) {
}
}
+ var codesigOff int64
if !*FlagD {
- ldr := ctxt.loader
-
- // must match domacholink below
+ // must match doMachoLink below
s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
+ s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
if ctxt.LinkMode != LinkExternal {
ms := newMachoSeg("__LINKEDIT", 0)
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.filesize = ms.vsize
ms.prot1 = 1
ms.prot2 = 1
+
+ codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6
}
if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
@@ -814,12 +822,31 @@ func asmbMacho(ctxt *Link) {
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)
if int32(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 {
@@ -1057,7 +1084,6 @@ func machodysymtab(ctxt *Link, base int64) {
func doMachoLink(ctxt *Link) int64 {
machosymtab(ctxt)
-
machoDyldInfo(ctxt)
ldr := ctxt.loader
@@ -1070,6 +1096,8 @@ func doMachoLink(ctxt *Link) int64 {
s5 := ctxt.ArchSyms.LinkEditGOT
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
// boundary. This allows pure (non-cgo) Go binaries
// to be code signed correctly.
@@ -1087,13 +1115,14 @@ func doMachoLink(ctxt *Link) int64 {
// boundary, codesign_allocate will not need to apply
// any alignment padding itself, working around the
// issue.
- s6b := ldr.MakeSymbolUpdater(s6)
- for s6b.Size()%16 != 0 {
- s6b.AddUint8(0)
+ if size%16 != 0 {
+ n := 16 - size%16
+ 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 {
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)
@@ -1104,9 +1133,13 @@ func doMachoLink(ctxt *Link) int64 {
ctxt.Out.Write(ldr.Data(s4))
ctxt.Out.Write(ldr.Data(s5))
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) {
@@ -1378,3 +1411,94 @@ func machoDyldInfo(ctxt *Link) {
// e.g. dlsym'd. But internal linking is not the default in that case, so
// 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
+}
diff --git a/src/cmd/link/internal/ld/outbuf.go b/src/cmd/link/internal/ld/outbuf.go
index 36ec394077..530836ef7c 100644
--- a/src/cmd/link/internal/ld/outbuf.go
+++ b/src/cmd/link/internal/ld/outbuf.go
@@ -113,6 +113,7 @@ func (out *OutBuf) Close() error {
}
if out.isMmapped() {
out.copyHeap()
+ out.purgeSignatureCache()
out.munmap()
}
if out.f == nil {
@@ -135,6 +136,15 @@ func (out *OutBuf) isMmapped() bool {
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
// a copy takes place.
func (out *OutBuf) copyHeap() bool {
diff --git a/src/cmd/link/internal/ld/outbuf_darwin.go b/src/cmd/link/internal/ld/outbuf_darwin.go
index d7e3372230..9444b6567e 100644
--- a/src/cmd/link/internal/ld/outbuf_darwin.go
+++ b/src/cmd/link/internal/ld/outbuf_darwin.go
@@ -36,3 +36,12 @@ func (out *OutBuf) fallocate(size uint64) error {
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.
+}
diff --git a/src/cmd/link/internal/ld/outbuf_notdarwin.go b/src/cmd/link/internal/ld/outbuf_notdarwin.go
new file mode 100644
index 0000000000..8c5666f216
--- /dev/null
+++ b/src/cmd/link/internal/ld/outbuf_notdarwin.go
@@ -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() {}
diff --git a/src/cmd/vendor/golang.org/x/mod/semver/semver.go b/src/cmd/vendor/golang.org/x/mod/semver/semver.go
index 2988e3cf9c..4338f35177 100644
--- a/src/cmd/vendor/golang.org/x/mod/semver/semver.go
+++ b/src/cmd/vendor/golang.org/x/mod/semver/semver.go
@@ -138,6 +138,9 @@ func Compare(v, w string) int {
// Max canonicalizes its arguments and then returns the version string
// 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 {
v = Canonical(v)
w = Canonical(w)
diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt
index f20b6b2be1..21bd6bfe48 100644
--- a/src/cmd/vendor/modules.txt
+++ b/src/cmd/vendor/modules.txt
@@ -29,7 +29,7 @@ golang.org/x/arch/x86/x86asm
golang.org/x/crypto/ed25519
golang.org/x/crypto/ed25519/internal/edwards25519
golang.org/x/crypto/ssh/terminal
-# golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449
+# golang.org/x/mod v0.4.0
## explicit
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
diff --git a/src/compress/gzip/issue14937_test.go b/src/compress/gzip/issue14937_test.go
index 24db3641aa..20da0b6824 100644
--- a/src/compress/gzip/issue14937_test.go
+++ b/src/compress/gzip/issue14937_test.go
@@ -31,7 +31,7 @@ func TestGZIPFilesHaveZeroMTimes(t *testing.T) {
t.Fatal("error evaluating GOROOT: ", err)
}
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 {
return err
}
diff --git a/src/crypto/ed25519/internal/edwards25519/edwards25519.go b/src/crypto/ed25519/internal/edwards25519/edwards25519.go
index fd03c252af..b091481b77 100644
--- a/src/crypto/ed25519/internal/edwards25519/edwards25519.go
+++ b/src/crypto/ed25519/internal/edwards25519/edwards25519.go
@@ -722,7 +722,7 @@ func (p *ExtendedGroupElement) FromBytes(s *[32]byte) bool {
FeOne(&p.Z)
FeSquare(&u, &p.Y)
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
FeSquare(&v3, &v)
diff --git a/src/encoding/json/scanner.go b/src/encoding/json/scanner.go
index c3f5f6372d..9dc1903e2d 100644
--- a/src/encoding/json/scanner.go
+++ b/src/encoding/json/scanner.go
@@ -47,7 +47,7 @@ type SyntaxError struct {
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.
// Callers call scan.reset and then pass bytes in one at a time
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index bf1367355d..e9ed26aa5f 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -510,8 +510,8 @@ func listStdPkgs(goroot string) ([]string, error) {
var pkgs []string
src := filepath.Join(goroot, "src") + string(filepath.Separator)
- walkFn := func(path string, fi fs.FileInfo, err error) error {
- if err != nil || !fi.IsDir() || path == src {
+ walkFn := func(path string, d fs.DirEntry, err error) error {
+ if err != nil || !d.IsDir() || path == src {
return nil
}
@@ -528,7 +528,7 @@ func listStdPkgs(goroot string) ([]string, error) {
pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/"))
return nil
}
- if err := filepath.Walk(src, walkFn); err != nil {
+ if err := filepath.WalkDir(src, walkFn); err != nil {
return nil, err
}
return pkgs, nil
diff --git a/src/go/doc/headscan.go b/src/go/doc/headscan.go
index 8ea462366e..fe26a0ea84 100644
--- a/src/go/doc/headscan.go
+++ b/src/go/doc/headscan.go
@@ -69,8 +69,8 @@ func main() {
flag.Parse()
fset := token.NewFileSet()
nheadings := 0
- err := filepath.Walk(*root, func(path string, fi fs.FileInfo, err error) error {
- if !fi.IsDir() {
+ err := filepath.WalkDir(*root, func(path string, info fs.DirEntry, err error) error {
+ if !info.IsDir() {
return nil
}
pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments)
diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go
index cc7e455c4d..d5c18a9e2d 100644
--- a/src/go/parser/interface.go
+++ b/src/go/parser/interface.go
@@ -140,7 +140,7 @@ func ParseDir(fset *token.FileSet, path string, filter func(fs.FileInfo) bool, m
pkgs = make(map[string]*ast.Package)
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())
if src, err := ParseFile(fset, filename, nil, mode); err == nil {
name := src.Name.Name
diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go
index 7193a329fe..a4f882d368 100644
--- a/src/go/parser/parser_test.go
+++ b/src/go/parser/parser_test.go
@@ -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) {
// just kicking the tires:
// a valid arithmetic expression
diff --git a/src/go/parser/testdata/issue42951/not_a_file.go/invalid.go b/src/go/parser/testdata/issue42951/not_a_file.go/invalid.go
new file mode 100644
index 0000000000..bb698be11c
--- /dev/null
+++ b/src/go/parser/testdata/issue42951/not_a_file.go/invalid.go
@@ -0,0 +1 @@
+This file should not be parsed by ParseDir.
diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
index b6031ea60a..fbc84a7592 100644
--- a/src/html/template/escape_test.go
+++ b/src/html/template/escape_test.go
@@ -243,7 +243,7 @@ func TestEscape(t *testing.T) {
{
"badMarshaler",
``,
- ``,
+ ``,
},
{
"jsMarshaler",
diff --git a/src/index/suffixarray/suffixarray_test.go b/src/index/suffixarray/suffixarray_test.go
index b6a81123b7..a11a98dae0 100644
--- a/src/index/suffixarray/suffixarray_test.go
+++ b/src/index/suffixarray/suffixarray_test.go
@@ -503,7 +503,7 @@ func makeText(name string) ([]byte, error) {
return nil, err
}
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() {
file, err := ioutil.ReadFile(path)
if err != nil {
diff --git a/src/io/ioutil/ioutil.go b/src/io/ioutil/ioutil.go
index a001c86b2f..45682b89c9 100644
--- a/src/io/ioutil/ioutil.go
+++ b/src/io/ioutil/ioutil.go
@@ -3,6 +3,11 @@
// license that can be found in the LICENSE file.
// 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
import (
@@ -26,67 +31,30 @@ func ReadAll(r io.Reader) ([]byte, error) {
// 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.
+//
+// As of Go 1.16, this function simply calls os.ReadFile.
func ReadFile(filename string) ([]byte, error) {
- f, err := os.Open(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
- }
- }
+ return os.ReadFile(filename)
}
// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm
// (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 {
- f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
- if err != nil {
- return err
- }
- _, err = f.Write(data)
- if err1 := f.Close(); err == nil {
- err = err1
- }
- return err
+ return os.WriteFile(filename, data, perm)
}
// 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) {
f, err := os.Open(dirname)
if err != nil {
diff --git a/src/log/log.go b/src/log/log.go
index 8c0f83f0d1..b77af29032 100644
--- a/src/log/log.go
+++ b/src/log/log.go
@@ -75,7 +75,7 @@ func (l *Logger) SetOutput(w io.Writer) {
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 }
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
diff --git a/src/net/http/response.go b/src/net/http/response.go
index 72812f0642..b95abae646 100644
--- a/src/net/http/response.go
+++ b/src/net/http/response.go
@@ -352,10 +352,16 @@ func (r *Response) bodyIsWritable() bool {
return ok
}
-// isProtocolSwitch reports whether r is a response to a successful
-// protocol upgrade.
+// isProtocolSwitch reports whether the response code and header
+// indicate a successful protocol upgrade response.
func (r *Response) isProtocolSwitch() bool {
- return r.StatusCode == StatusSwitchingProtocols &&
- r.Header.Get("Upgrade") != "" &&
- httpguts.HeaderValuesContainsToken(r.Header["Connection"], "Upgrade")
+ return isProtocolSwitchResponse(r.StatusCode, r.Header)
+}
+
+// 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")
}
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index ba54b31a29..b1bf8e6c5e 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -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")
+ }
+}
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 6c7d281705..102e893d5f 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -1468,7 +1468,13 @@ func (cw *chunkWriter) writeHeader(p []byte) {
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")
if w.req.ProtoAtLeast(1, 1) {
setHeader.connection = "close"
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 79b1fc7681..8de0f3a6a0 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -2599,6 +2599,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
var respHeaderTimer <-chan time.Time
cancelChan := req.Request.Cancel
ctxDoneChan := req.Context().Done()
+ pcClosed := pc.closech
for {
testHookWaitResLoop()
select {
@@ -2618,11 +2619,15 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
defer timer.Stop() // prevent leaks
respHeaderTimer = timer.C
}
- case <-pc.closech:
- if debugRoundTrip {
- req.logf("closech recv: %T %#v", pc.closed, pc.closed)
+ case <-pcClosed:
+ pcClosed = nil
+ // 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:
if debugRoundTrip {
req.logf("timeout waiting for response headers.")
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 9086507d57..f22b798035 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -6433,3 +6433,54 @@ func TestErrorWriteLoopRace(t *testing.T) {
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()
+}
diff --git a/src/net/udpsock.go b/src/net/udpsock.go
index ec2bcfa607..571e099abd 100644
--- a/src/net/udpsock.go
+++ b/src/net/udpsock.go
@@ -259,6 +259,9 @@ func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) {
// ListenMulticastUDP is just for convenience of simple, small
// applications. There are golang.org/x/net/ipv4 and
// 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) {
switch network {
case "udp", "udp4", "udp6":
diff --git a/src/os/dir.go b/src/os/dir.go
index 1d90b970e7..5306bcb3ba 100644
--- a/src/os/dir.go
+++ b/src/os/dir.go
@@ -4,7 +4,10 @@
package os
-import "io/fs"
+import (
+ "io/fs"
+ "sort"
+)
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.
// This can be difficult to provoke on some Unix systems otherwise.
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
+}
diff --git a/src/os/example_test.go b/src/os/example_test.go
index fbb277b6f1..3adce51784 100644
--- a/src/os/example_test.go
+++ b/src/os/example_test.go
@@ -9,6 +9,7 @@ import (
"io/fs"
"log"
"os"
+ "path/filepath"
"time"
)
@@ -144,3 +145,98 @@ func ExampleUnsetenv() {
os.Setenv("TMPDIR", "/my/tmp")
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)
+ }
+}
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index cd3d759ebc..fc49b8a332 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -691,6 +691,18 @@ func TestExtraFiles(t *testing.T) {
c.Stdout = &stdout
c.Stderr = &stderr
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()
if err != nil {
t.Fatalf("Run: %v\n--- stdout:\n%s--- stderr:\n%s", err, stdout.Bytes(), stderr.Bytes())
diff --git a/src/os/export_test.go b/src/os/export_test.go
index d66264a68f..f3cb1a2bef 100644
--- a/src/os/export_test.go
+++ b/src/os/export_test.go
@@ -10,3 +10,4 @@ var Atime = atime
var LstatP = &lstat
var ErrWriteAtInAppendMode = errWriteAtInAppendMode
var TestingForceReadDirLstat = &testingForceReadDirLstat
+var ErrPatternHasSeparator = errPatternHasSeparator
diff --git a/src/os/file.go b/src/os/file.go
index 835d44ab8c..304b055dbe 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -406,7 +406,7 @@ func UserCacheDir() (string, error) {
return "", errors.New("%LocalAppData% is not defined")
}
- case "darwin":
+ case "darwin", "ios":
dir = Getenv("HOME")
if dir == "" {
return "", errors.New("$HOME is not defined")
@@ -457,7 +457,7 @@ func UserConfigDir() (string, error) {
return "", errors.New("%AppData% is not defined")
}
- case "darwin":
+ case "darwin", "ios":
dir = Getenv("HOME")
if dir == "" {
return "", errors.New("$HOME is not defined")
@@ -505,10 +505,8 @@ func UserHomeDir() (string, error) {
switch runtime.GOOS {
case "android":
return "/sdcard", nil
- case "darwin":
- if runtime.GOARCH == "arm64" {
- return "/", nil
- }
+ case "ios":
+ return "/", nil
}
return "", errors.New(enverr + " is not defined")
}
@@ -627,3 +625,63 @@ func (dir dirFS) Open(name string) (fs.File, error) {
}
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
+}
diff --git a/src/os/os_test.go b/src/os/os_test.go
index a1c0578887..c5e5cbbb1b 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -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(sysdir.name, sysdir.files, t)
testReaddirnames(t.TempDir(), nil, t)
}
-func TestReaddir(t *testing.T) {
+func TestFileReaddir(t *testing.T) {
testReaddir(".", dot, t)
testReaddir(sysdir.name, sysdir.files, t)
testReaddir(t.TempDir(), nil, t)
}
-func TestReadDir(t *testing.T) {
+func TestFileReadDir(t *testing.T) {
testReadDir(".", dot, t)
testReadDir(sysdir.name, sysdir.files, t)
testReadDir(t.TempDir(), nil, t)
@@ -1235,6 +1235,7 @@ func TestChmod(t *testing.T) {
}
func checkSize(t *testing.T, f *File, size int64) {
+ t.Helper()
dir, err := f.Stat()
if err != nil {
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)
}
}
+
+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)
+ }
+}
diff --git a/src/os/read_test.go b/src/os/read_test.go
new file mode 100644
index 0000000000..5c58d7d7df
--- /dev/null
+++ b/src/os/read_test.go
@@ -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)
+ }
+}
diff --git a/src/os/removeall_test.go b/src/os/removeall_test.go
index bc9c468ce3..90efa313ea 100644
--- a/src/os/removeall_test.go
+++ b/src/os/removeall_test.go
@@ -355,11 +355,12 @@ func TestRemoveAllButReadOnlyAndPathError(t *testing.T) {
// The error should be of type *PathError.
// see issue 30491 for details.
if pathErr, ok := err.(*PathError); ok {
- if g, w := pathErr.Path, filepath.Join(tempDir, "b", "y"); g != w {
- t.Errorf("got %q, expected pathErr.path %q", g, w)
+ want := filepath.Join(tempDir, "b", "y")
+ if pathErr.Path != want {
+ t.Errorf("RemoveAll(%q): err.Path=%q, want %q", tempDir, pathErr.Path, want)
}
} 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 {
diff --git a/src/os/tempfile.go b/src/os/tempfile.go
new file mode 100644
index 0000000000..2728485c32
--- /dev/null
+++ b/src/os/tempfile.go
@@ -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
+}
diff --git a/src/os/tempfile_test.go b/src/os/tempfile_test.go
new file mode 100644
index 0000000000..e71a2444c9
--- /dev/null
+++ b/src/os/tempfile_test.go
@@ -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:
+ // ^[0-9]+xyz$
+ // yet we just want to match
+ // "^/[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)
+ }
+ })
+ }
+}
diff --git a/src/os/testdata/hello b/src/os/testdata/hello
new file mode 100644
index 0000000000..e47c092a51
--- /dev/null
+++ b/src/os/testdata/hello
@@ -0,0 +1 @@
+Hello, Gophers!
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index a12712d254..b01158635f 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -4007,9 +4007,12 @@ var convertTests = []struct {
{V(int16(-3)), V(string("\uFFFD"))},
{V(int32(-4)), 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(uint32(0x110002)), V(string("\uFFFD"))},
{V(uint64(0x110003)), V(string("\uFFFD"))},
+ {V(uint64(1 << 32)), V(string("\uFFFD"))},
{V(uintptr(0x110004)), V(string("\uFFFD"))},
// named string
diff --git a/src/reflect/value.go b/src/reflect/value.go
index bf926a7453..1f185b52e4 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -2681,12 +2681,20 @@ func cvtComplex(v Value, t Type) Value {
// convertOp: intXX -> string
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
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
diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go
index c50d62d552..ebbdbfe5b9 100644
--- a/src/runtime/crash_unix_test.go
+++ b/src/runtime/crash_unix_test.go
@@ -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
// make us less likely to lose the race and signal before the child
// blocks.
- time.Sleep(100*time.Millisecond)
+ time.Sleep(100 * time.Millisecond)
// Send SIGQUIT.
if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil {
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index 3f5bb7cf96..52f3cd1fef 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -283,6 +283,12 @@ func libpreinit() {
func mpreinit(mp *m) {
mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
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).
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index 43307aeab9..b807072485 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -286,6 +286,10 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
broken = true
}
+ case "windows":
+ if runtime.GOARCH == "arm" {
+ broken = true // See https://golang.org/issues/42862
+ }
}
maxDuration := 5 * time.Second
diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go
index 6d98d02598..3af2e39b08 100644
--- a/src/runtime/signal_windows.go
+++ b/src/runtime/signal_windows.go
@@ -43,16 +43,9 @@ func initExceptionHandler() {
//
//go:nosplit
func isAbort(r *context) bool {
- switch GOARCH {
- case "386", "amd64":
- // In the case of an abort, the exception IP is one byte after
- // the INT3 (this differs from UNIX OSes).
- return isAbortPC(r.ip() - 1)
- case "arm":
- return isAbortPC(r.ip())
- default:
- return false
- }
+ // In the case of an abort, the exception IP is one byte after
+ // the INT3 (this differs from UNIX OSes).
+ return isAbortPC(r.ip() - 1)
}
// isgoexception reports whether this exception should be translated
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index d77cb4d460..b55c3c0590 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -133,6 +133,9 @@ func sync_fastrand() uint32 { return fastrand() }
//go:linkname net_fastrand net.fastrand
func net_fastrand() uint32 { return fastrand() }
+//go:linkname os_fastrand os.fastrand
+func os_fastrand() uint32 { return fastrand() }
+
// in internal/bytealg/equal_*.s
//go:noescape
func memequal(a, b unsafe.Pointer, size uintptr) bool
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
index a7983be2ef..c63ba8c6cd 100644
--- a/src/runtime/sys_darwin.go
+++ b/src/runtime/sys_darwin.go
@@ -226,6 +226,13 @@ func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
}
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:cgo_unsafe_args
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_munmap munmap "/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_usleep usleep "/usr/lib/libSystem.B.dylib"
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index 129e1e1a96..9b5b23901d 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -105,6 +105,9 @@ TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
POPQ BP
RET
+TEXT runtime·mlock_trampoline(SB), NOSPLIT, $0
+ UNDEF // unimplemented
+
GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index 88cdb281d4..9d4d116c50 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -120,6 +120,12 @@ TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0
BL libc_madvise(SB)
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
MOVD 8(R0), R1 // arg 2 new
MOVD 16(R0), R2 // arg 3 old
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
index 3827c6ed83..a20573eb6a 100644
--- a/src/runtime/syscall_windows_test.go
+++ b/src/runtime/syscall_windows_test.go
@@ -969,8 +969,9 @@ func TestDLLPreloadMitigation(t *testing.T) {
#include
#include
-uintptr_t cfunc() {
+uintptr_t cfunc(void) {
SetLastError(123);
+ return 0;
}
`
srcname := "nojack.c"
diff --git a/test/blank1.go b/test/blank1.go
index c9a8e6a290..70e01b1a30 100644
--- a/test/blank1.go
+++ b/test/blank1.go
@@ -13,7 +13,7 @@ var t struct {
_ int
}
-func (x int) _() { // ERROR "cannot define new methods on non-local type"
+func (x int) _() { // ERROR "methods on non-local type"
println(x)
}
diff --git a/test/chan/perm.go b/test/chan/perm.go
index 7da88bdae8..0c96d921d1 100644
--- a/test/chan/perm.go
+++ b/test/chan/perm.go
@@ -25,8 +25,8 @@ func main() {
cs = cr // ERROR "illegal types|incompatible|cannot"
var n int
- <-n // ERROR "receive from non-chan"
- n <- 2 // ERROR "send to non-chan"
+ <-n // ERROR "receive from non-chan|expected channel"
+ n <- 2 // ERROR "send to non-chan|must be channel"
c <- 0 // ok
<-c // ok
@@ -66,5 +66,5 @@ func main() {
close(c)
close(cs)
close(cr) // ERROR "receive"
- close(n) // ERROR "invalid operation.*non-chan type"
+ close(n) // ERROR "invalid operation.*non-chan type|must be channel"
}
diff --git a/test/complit1.go b/test/complit1.go
index eb0f920fcb..7c2a4e2996 100644
--- a/test/complit1.go
+++ b/test/complit1.go
@@ -22,9 +22,9 @@ var (
_ = m[0][:] // ERROR "slice of unaddressable value"
_ = f()[:] // ERROR "slice of unaddressable value"
- _ = 301[:] // ERROR "cannot slice"
- _ = 3.1[:] // ERROR "cannot slice"
- _ = true[:] // ERROR "cannot slice"
+ _ = 301[:] // ERROR "cannot slice|attempt to slice object that is not"
+ _ = 3.1[:] // ERROR "cannot slice|attempt to slice object that is not"
+ _ = true[:] // ERROR "cannot slice|attempt to slice object that is not"
// these are okay because they are slicing a pointer to an array
_ = (&[3]int{1, 2, 3})[:]
@@ -46,8 +46,8 @@ var (
_ = &T{0, 0, "", nil} // ok
_ = &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"
- _ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP"
- _ = &Ti{} // ERROR "invalid composite literal type Ti"
+ _ = 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|expected.*type for composite literal"
)
type M map[T]T
diff --git a/test/convlit.go b/test/convlit.go
index de760542da..1c66c89e88 100644
--- a/test/convlit.go
+++ b/test/convlit.go
@@ -21,9 +21,9 @@ var x6 = int(1e100) // ERROR "overflow"
var x7 = float32(1e1000) // ERROR "overflow"
// unsafe.Pointer can only convert to/from uintptr
-var _ = string(unsafe.Pointer(uintptr(65))) // ERROR "convert"
-var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert"
-var _ = int(unsafe.Pointer(uintptr(65))) // ERROR "convert"
+var _ = string(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion"
+var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion"
+var _ = int(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion"
// implicit conversions merit scrutiny
var s string
diff --git a/test/ddd1.go b/test/ddd1.go
index 9857814648..01b9c0eadb 100644
--- a/test/ddd1.go
+++ b/test/ddd1.go
@@ -60,5 +60,5 @@ func bad(args ...int) {
_ = [...]byte("foo") // ERROR "[.][.][.]"
_ = [...][...]int{{1,2,3},{4,5,6}} // ERROR "[.][.][.]"
- Foo(x...) // ERROR "invalid use of [.][.][.] in call"
+ Foo(x...) // ERROR "invalid use of .*[.][.][.]"
}
diff --git a/test/fixedbugs/bug176.go b/test/fixedbugs/bug176.go
index ea3a909747..7001dd081e 100644
--- a/test/fixedbugs/bug176.go
+++ b/test/fixedbugs/bug176.go
@@ -9,6 +9,6 @@ package main
var x int
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}
diff --git a/test/fixedbugs/bug332.go b/test/fixedbugs/bug332.go
index d43c2ddcff..159c8b4e68 100644
--- a/test/fixedbugs/bug332.go
+++ b/test/fixedbugs/bug332.go
@@ -14,4 +14,4 @@ func main() {}
// important: no newline on end of next line.
// 6g used to print instead of bug332.go:111
-func (t *T) F() {} // ERROR "undefined: T"
\ No newline at end of file
+func (t *T) F() {} // ERROR "undefined.*T"
\ No newline at end of file
diff --git a/test/fixedbugs/bug340.go b/test/fixedbugs/bug340.go
index a067940408..542a6eab03 100644
--- a/test/fixedbugs/bug340.go
+++ b/test/fixedbugs/bug340.go
@@ -13,6 +13,6 @@ func main() {
switch t := x.(type) {
case 0: // ERROR "type"
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"
}
}
diff --git a/test/fixedbugs/issue4232.go b/test/fixedbugs/issue4232.go
index 935f3820c6..30d132683a 100644
--- a/test/fixedbugs/issue4232.go
+++ b/test/fixedbugs/issue4232.go
@@ -19,7 +19,7 @@ func f() {
_ = a[10:10]
_ = 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[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
_ = s[-1] // ERROR "invalid slice index -1|index out of bounds"
@@ -30,7 +30,7 @@ func f() {
_ = s[10:10]
_ = s[9: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"
_ = c[-1] // ERROR "invalid string index -1|index out of bounds"
@@ -41,7 +41,7 @@ func f() {
_ = c[10:10]
_ = 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[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
_ = t[-1] // ERROR "invalid string index -1|index out of bounds"
@@ -52,5 +52,5 @@ func f() {
_ = t[10:10]
_ = t[9: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"
}
diff --git a/test/fixedbugs/issue42876.go b/test/fixedbugs/issue42876.go
new file mode 100644
index 0000000000..67cf4919ac
--- /dev/null
+++ b/test/fixedbugs/issue42876.go
@@ -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
+ }
+}
diff --git a/test/fixedbugs/issue4458.go b/test/fixedbugs/issue4458.go
index 98ffea79dc..59cfa9fcee 100644
--- a/test/fixedbugs/issue4458.go
+++ b/test/fixedbugs/issue4458.go
@@ -16,5 +16,5 @@ func (T) foo() {}
func main() {
av := T{}
pav := &av
- (**T).foo(&pav) // ERROR "no method foo|requires named type or pointer to named"
+ (**T).foo(&pav) // ERROR "no method .*foo|requires named type or pointer to named"
}
diff --git a/test/fixedbugs/issue5172.go b/test/fixedbugs/issue5172.go
index 0339935b64..ed92ac6ff2 100644
--- a/test/fixedbugs/issue5172.go
+++ b/test/fixedbugs/issue5172.go
@@ -21,6 +21,6 @@ func main() {
go f.bar() // ERROR "undefined"
defer f.bar() // ERROR "undefined"
- t := T{1} // ERROR "too many values"
+ t := T{1} // ERROR "too many"
go t.Bar()
}
diff --git a/test/init.go b/test/init.go
index 317f2472cb..5e182281da 100644
--- a/test/init.go
+++ b/test/init.go
@@ -14,6 +14,6 @@ func init() {
func main() {
init() // ERROR "undefined.*init"
- runtime.init() // ERROR "undefined.*runtime\.init"
+ runtime.init() // ERROR "undefined.*runtime\.init|reference to undefined name"
var _ = init // ERROR "undefined.*init"
}
diff --git a/test/initializerr.go b/test/initializerr.go
index 990ab60f96..5e2e9a91a0 100644
--- a/test/initializerr.go
+++ b/test/initializerr.go
@@ -23,7 +23,7 @@ var a2 = S { Y: 3, Z: 2, Y: 3 } // ERROR "duplicate"
var a3 = T { S{}, 2, 3, 4, 5, 6 } // ERROR "convert|too many"
var a4 = [5]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } // ERROR "index|too many"
var a5 = []byte { x: 2 } // ERROR "index"
-var a6 = []byte{1: 1, 2: 2, 1: 3} // ERROR "duplicate index"
+var a6 = []byte{1: 1, 2: 2, 1: 3} // ERROR "duplicate"
var ok1 = S { } // should be ok
var ok2 = T { S: ok1 } // should be ok
diff --git a/test/interface/explicit.go b/test/interface/explicit.go
index 1fb3b6a05a..3f9451e8d2 100644
--- a/test/interface/explicit.go
+++ b/test/interface/explicit.go
@@ -57,7 +57,7 @@ func main() {
// cannot type-assert non-interfaces
f := 2.0
- _ = f.(int) // ERROR "non-interface type"
+ _ = f.(int) // ERROR "non-interface type|only valid for interface types"
}
diff --git a/test/label.go b/test/label.go
index 11716cc2c5..7deead6fba 100644
--- a/test/label.go
+++ b/test/label.go
@@ -61,5 +61,5 @@ L10:
goto L10
- goto go2 // ERROR "label go2 not defined"
+ goto go2 // ERROR "label go2 not defined|reference to undefined label .*go2"
}
diff --git a/test/label1.go b/test/label1.go
index b2e0ef09b8..a8eaecbff2 100644
--- a/test/label1.go
+++ b/test/label1.go
@@ -15,11 +15,11 @@ var x int
func f1() {
switch x {
case 1:
- continue // ERROR "continue is not in a loop$"
+ continue // ERROR "continue is not in a loop$|continue statement not within for"
}
select {
default:
- continue // ERROR "continue is not in a loop$"
+ continue // ERROR "continue is not in a loop$|continue statement not within for"
}
}
@@ -103,14 +103,14 @@ L5:
}
}
- continue // ERROR "continue is not in a loop$"
+ continue // ERROR "continue is not in a loop$|continue statement not within for"
for {
- continue on // ERROR "continue label not defined: on"
+ continue on // ERROR "continue label not defined: on|invalid continue label .*on"
}
- break // ERROR "break is not in a loop, switch, or select"
+ break // ERROR "break is not in a loop, switch, or select|break statement not within for or switch or select"
for {
- break dance // ERROR "break label not defined: dance"
+ break dance // ERROR "break label not defined: dance|invalid break label .*dance"
}
for {
diff --git a/test/map1.go b/test/map1.go
index 498c2ec45b..b4aa70755f 100644
--- a/test/map1.go
+++ b/test/map1.go
@@ -61,8 +61,8 @@ type T8 struct { F *T7 }
func main() {
m := make(map[int]int)
- delete() // ERROR "missing arguments"
- delete(m) // ERROR "missing second \(key\) argument"
+ delete() // ERROR "missing arguments|not enough arguments"
+ delete(m) // ERROR "missing second \(key\) argument|not enough arguments"
delete(m, 2, 3) // ERROR "too many arguments"
- delete(1, m) // ERROR "first argument to delete must be map"
-}
\ No newline at end of file
+ delete(1, m) // ERROR "first argument to delete must be map|argument 1 must be a map"
+}
diff --git a/test/method2.go b/test/method2.go
index a45a943156..7feb675055 100644
--- a/test/method2.go
+++ b/test/method2.go
@@ -33,9 +33,9 @@ var _ = (*Val).val // ERROR "method"
var v Val
var pv = &v
-var _ = pv.val() // ERROR "pv.val undefined"
-var _ = pv.val // ERROR "pv.val undefined"
+var _ = pv.val() // ERROR "undefined"
+var _ = pv.val // ERROR "undefined"
func (t *T) g() int { return t.a }
-var _ = (T).g() // ERROR "needs pointer receiver|undefined"
+var _ = (T).g() // ERROR "needs pointer receiver|undefined|method requires pointer"
diff --git a/test/run.go b/test/run.go
index 672861c8d7..4abf32d25c 100644
--- a/test/run.go
+++ b/test/run.go
@@ -14,6 +14,7 @@ import (
"fmt"
"hash/fnv"
"io"
+ "io/fs"
"io/ioutil"
"log"
"os"
@@ -1793,7 +1794,7 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
+ return filepath.WalkDir(srcRoot, func(srcPath string, d fs.DirEntry, err error) error {
if err != nil || srcPath == srcRoot {
return err
}
@@ -1804,14 +1805,16 @@ func overlayDir(dstRoot, srcRoot string) error {
}
dstPath := filepath.Join(dstRoot, suffix)
- perm := info.Mode() & os.ModePerm
- if info.Mode()&os.ModeSymlink != 0 {
+ var info fs.FileInfo
+ if d.Type()&os.ModeSymlink != 0 {
info, err = os.Stat(srcPath)
- if err != nil {
- return err
- }
- perm = info.Mode() & os.ModePerm
+ } else {
+ info, err = d.Info()
}
+ if err != nil {
+ return err
+ }
+ perm := info.Mode() & os.ModePerm
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
diff --git a/test/shift1.go b/test/shift1.go
index df0c032cd5..d6a6c38839 100644
--- a/test/shift1.go
+++ b/test/shift1.go
@@ -73,8 +73,8 @@ func _() {
// non constants arguments trigger a different path
f2 := 1.2
s2 := "hi"
- _ = f2 << 2 // ERROR "shift of type float64"
- _ = s2 << 2 // ERROR "shift of type string"
+ _ = f2 << 2 // ERROR "shift of type float64|non-integer"
+ _ = s2 << 2 // ERROR "shift of type string|non-integer"
}
// shifts in comparisons w/ untyped operands
diff --git a/test/syntax/chan1.go b/test/syntax/chan1.go
index 56103d1d79..88a5b4777b 100644
--- a/test/syntax/chan1.go
+++ b/test/syntax/chan1.go
@@ -10,8 +10,8 @@ var c chan int
var v int
func main() {
- if c <- v { // ERROR "cannot use c <- v as value"
+ if c <- v { // ERROR "cannot use c <- v as value|send statement used as value"
}
}
-var _ = c <- v // ERROR "unexpected <-"
+var _ = c <- v // ERROR "unexpected <-|send statement used as value"
diff --git a/test/syntax/semi4.go b/test/syntax/semi4.go
index f21431b3f5..08c354751b 100644
--- a/test/syntax/semi4.go
+++ b/test/syntax/semi4.go
@@ -8,5 +8,5 @@ package main
func main() {
for x // GCCGO_ERROR "undefined"
- { // ERROR "unexpected {, expecting for loop condition"
- z
+ { // ERROR "unexpected {, expecting for loop condition|expecting .*{.* after for clause"
+ z // GCCGO_ERROR "undefined"
diff --git a/test/syntax/semi6.go b/test/syntax/semi6.go
index 4a04f89ddb..9bc730d43d 100644
--- a/test/syntax/semi6.go
+++ b/test/syntax/semi6.go
@@ -6,6 +6,6 @@
package main
-type T1 // ERROR "unexpected newline in type declaration"
+type T1 // ERROR "newline in type declaration"
-type T2 /* // ERROR "unexpected EOF in type declaration" */
\ No newline at end of file
+type T2 /* // ERROR "(semicolon.*|EOF) in type declaration" */
\ No newline at end of file
diff --git a/test/winbatch.go b/test/winbatch.go
index c3b48d385c..54c2fff134 100644
--- a/test/winbatch.go
+++ b/test/winbatch.go
@@ -27,11 +27,11 @@ func main() {
// Walk the entire Go repository source tree (without GOROOT/pkg),
// skipping directories that start with "." and named "testdata",
// and ensure all .bat files found have exact CRLF line endings.
- err := filepath.Walk(runtime.GOROOT(), func(path string, fi os.FileInfo, err error) error {
+ err := filepath.WalkDir(runtime.GOROOT(), func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
- if fi.IsDir() && (strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata") {
+ if d.IsDir() && (strings.HasPrefix(d.Name(), ".") || d.Name() == "testdata") {
return filepath.SkipDir
}
if path == filepath.Join(runtime.GOROOT(), "pkg") {
@@ -39,7 +39,7 @@ func main() {
// Skip it to avoid false positives. (Also see golang.org/issue/37929.)
return filepath.SkipDir
}
- if filepath.Ext(fi.Name()) == ".bat" {
+ if filepath.Ext(d.Name()) == ".bat" {
enforceBatchStrictCRLF(path)
}
return nil