diff options
author | Cherry Mui <cherryyz@google.com> | 2023-07-12 17:23:11 -0400 |
---|---|---|
committer | Cherry Mui <cherryyz@google.com> | 2023-07-12 17:23:13 -0400 |
commit | cc0cb3020dee801d733bc9c20c4a5bbaa650a6d4 (patch) | |
tree | 522c40137c7c8854d88dd3ed1ca55f1edcf624f7 | |
parent | d8117459c513e048eb72f11988d5416110dff359 (diff) | |
parent | 6244b1946bc2101b01955468f1be502dbadd6807 (diff) | |
download | go-cc0cb3020dee801d733bc9c20c4a5bbaa650a6d4.tar.gz go-cc0cb3020dee801d733bc9c20c4a5bbaa650a6d4.zip |
[release-branch.go1.21] all: merge master (6244b19) into release-branch.go1.21
Merge List:
+ 2023-07-12 6244b1946b all: update vendored dependencies
+ 2023-07-12 b4872ea187 cmd/go: fix go get go@badversion
+ 2023-07-12 87350393e6 cmd/go: fix GOTOOLCHAIN parsing for +auto
+ 2023-07-12 230e549142 doc/go1.21: add a release note for CL 463177
+ 2023-07-12 5e4000ad7f cmd/compile: on PPC64, fix sign/zero extension when masking
+ 2023-07-11 af8f94e3c5 src/README.vendor: s/latest/master/
+ 2023-07-11 3eaee3d5dd testing/slogtest: check for no group with empty record
+ 2023-07-11 167c8b73bf net/http/fcgi: eliminate goroutine leaks in tests
+ 2023-07-11 cb7a091d72 os/exec: ignore context.Canceled errors in TestConcurrentExec
+ 2023-07-11 651869716a log/slog: replace nil contexts with context.Background()
+ 2023-07-11 3f8b04bfb5 log/slog: change XXXCtx functions to XXXContext
+ 2023-07-11 4c58d6bf52 time: increase arbitrary upper bound in TestReset to 10s
+ 2023-07-11 6a063b01b0 net: mptcp: force using MPTCP with GODEBUG
+ 2023-07-10 07ede7a543 syscall: serialize locks on ForkLock on platforms where forkExecPipe is not atomic
+ 2023-07-10 7dc62f3bda test: add test cases for index value with range array clear
+ 2023-07-10 0b65b02ba5 cmd/compile: fix clear on slice with zero size elem
+ 2023-07-10 c4db811e44 cmd/compile: don't ICE on unaligned offsets for pointer writes
+ 2023-07-07 5c15498609 os: support reading empty root directories on Windows
+ 2023-07-07 894d24d617 src/database/sql: run gofmt
+ 2023-07-07 ac9137f8d3 go/types, types2: do not mutate arguments in NewChecker
+ 2023-07-07 158d11196f math: add test that covers riscv64 fnm{add,sub} codegen
+ 2023-07-07 d3d78b4bcc log/slog: handle recursively empty groups
+ 2023-07-06 39c5070712 os: do not skip directory entries with zero inodes on wasip1
+ 2023-07-06 e6ec2a34dc runtime: print output on failure in TestMemPprof
+ 2023-07-06 449ef3795d net: only build cgo_stub.go on unix or wasip1
+ 2023-07-06 6305d7fdd3 cmd/go: pass GoVersion in vet config
+ 2023-07-06 b490bdc27d go/types: record Config.GoVersion for reporting in Package.GoVersion method
+ 2023-07-06 36ea4f9680 log/slog: fix faulty test
+ 2023-07-05 3fce111535 cmd/compile: fix FMA negative commutativity of riscv64
+ 2023-07-05 c8dad424bf math: fix portable FMA when x*y < 0 and x*y == -z
+ 2023-07-05 cd6676126b database/sql: prevent internal context error from being returned from Rows.Err()
+ 2023-07-05 b2215e49c7 runtime,runtime/metrics: clarify OS stack metrics
+ 2023-07-04 e126572f8a runtime: have ReadMemStats do a nil check before switching stacks
+ 2023-07-04 e4ed92a355 os, syscall: update unreachable link about =C: envs
+ 2023-07-04 5c1a15df41 test/codegen: enable Mul2 DivPow2 test for riscv64
+ 2023-06-30 5b72f45dd1 runtime: check GOFLAGS not GCFLAGS
+ 2023-06-29 18e17e2cb1 net: enable pure Go resolver for wasip1
+ 2023-06-29 1e97c51536 syscall: stub Getrlimit on wasip1
+ 2023-06-29 683f51d307 cmd/asm/internal/lex: fix comment, remove the first "has"
+ 2023-06-29 2db31efdba cmd/compile/internal/types2: make TestIssue43124 match the go/types version
+ 2023-06-29 499458f7ca net/http: validate Host header before sending
+ 2023-06-29 fe73c186eb cmd/{go,compile}: run gofmt
+ 2023-06-29 da5d8fdd0c runtime: run wasip1 tests with wazero
+ 2023-06-29 411c99671a slices, maps: add examples; doc comment fixes
+ 2023-06-29 03cd8a7b0e internal/bytealg: fix alignment code in equal_riscv64.s
+ 2023-06-28 8b5fe5980c cmd/compile: handle min/max correctly in mayCall
+ 2023-06-28 79d4defa75 cmd/compile/internal/ssagen: fix min/max codegen, again
+ 2023-06-28 a3093eca64 cmd/go: enable slog vet check during 'go test'
+ 2023-06-27 6691f438c3 cmd/dist, internal/abi: support bootstrapping with gccgo
+ 2023-06-27 942c1c12d8 runtime: fix trace.Stop deadlock when built with faketime
+ 2023-06-27 4ad4128d3c cmd/compile: fix bad order of evaluation for min/max builtin
+ 2023-06-27 4f36f7e4dd encoding: document that base32 and base64 do not use UTF-8
+ 2023-06-27 8008c0840f syscall: clarify which handles are affected by SysProcAttr.NoInheritHandles
+ 2023-06-27 13529cc5f4 syscall: try non-blocking stdio on wasip1
+ 2023-06-26 1dbbafc70f go/types, types2: replace TODO with clarifying comment
+ 2023-06-26 7cc0740596 slices: add godoc links
+ 2023-06-26 d49017a7c3 go/types, types2: fix interface unification
+ 2023-06-26 b3ca8d2b3c types2, go/types: record final type for min/max arguments
+ 2023-06-26 ee361ce66c go/types, types2: more readable inference trace
+ 2023-06-26 9f6e87ff74 doc/go1.21: document changes in crypto/x509
+ 2023-06-26 f5015b5164 doc/go1.21: context.Background and TODO may now appear equal
+ 2023-06-24 a031f4ef83 cmd/compile: fix min/max builtin code generation
+ 2023-06-24 ea927e560d slices: clarify MinFunc/MaxFunc result for equal elements
+ 2023-06-23 3619255777 crypto/x509: rename duplicated test
+ 2023-06-23 48dbb6227a runtime: set raceignore to zero when starting a new goroutine
+ 2023-06-23 3adcce5ae7 crypto: document non-determinism of GenerateKey
+ 2023-06-23 6dce882b3a cmd/compile: scanning closures body when visiting wrapper function
+ 2023-06-23 164aceea08 log/slog: fix broken link to AnyValue in comment
+ 2023-06-23 82e17c4d11 log/slog: fix broken link to Record.Clone in package docs
+ 2023-06-22 25e46693a1 cmd/go: impersonate 'go tool dist list' if 'go tool dist' is not present
+ 2023-06-22 f8616b8484 internal/platform,cmd/dist: export the list of supported platforms
+ 2023-06-22 51885c1fa2 cmd/{go,cover}: enable response file args for cmd/cover
+ 2023-06-22 3479e1e543 internal/fuzz: fix typo in comment
+ 2023-06-22 20313660f5 crypto/x509: tolerate multiple matching chains in testVerify
+ 2023-06-21 78c3aba470 net/mail: permit more characters in mail headers
+ 2023-06-21 633b742ae0 test: add test that caused a gofrontend crash
+ 2023-06-21 ad2c517708 doc/go1.21: correct GOOS to GOARCH (another location)
+ 2023-06-21 b23cae8095 doc/go1.21: correct GOOS to GOARCH
+ 2023-06-21 b1f1fb2950 go/types, types2: avoid spurious "declared and not used" error
+ 2023-06-21 e45202f215 runtime: relate GODEBUG=gctrace output to runtime/metrics
+ 2023-06-21 36edde9d9f cmd/go: shorten longest 5 tests
+ 2023-06-21 413e6c0499 cmd/compile/internal/ir: typo
+ 2023-06-20 f3bf18117b log/slog: fix HandlerOptions.ReplaceAttr doc
+ 2023-06-20 e122ebabb6 encoding/binary: on invalid type return -1 from Size
+ 2023-06-20 8484f2fe02 cmd/go: add comment for intentional misspelling
Change-Id: Ie91c398dde7ca2a210b286c7865d3e7a905d6ea9
230 files changed, 5279 insertions, 1023 deletions
diff --git a/.gitignore b/.gitignore index 52263cdb80..7978d68b76 100644 --- a/.gitignore +++ b/.gitignore @@ -33,12 +33,10 @@ _testmain.go /src/cmd/cgo/zdefaultcc.go /src/cmd/dist/dist /src/cmd/go/internal/cfg/zdefaultcc.go -/src/cmd/go/internal/cfg/zosarch.go /src/cmd/internal/objabi/zbootstrap.go /src/go/build/zcgo.go /src/go/doc/headscan /src/internal/buildcfg/zbootstrap.go -/src/internal/platform/zosarch.go /src/runtime/internal/sys/zversion.go /src/unicode/maketables /src/time/tzdata/zzipdata.go diff --git a/api/go1.21.txt b/api/go1.21.txt index 6435d10914..def0fa84e4 100644 --- a/api/go1.21.txt +++ b/api/go1.21.txt @@ -174,6 +174,7 @@ pkg go/build, type Package struct, Directives []Directive #56986 pkg go/build, type Package struct, TestDirectives []Directive #56986 pkg go/build, type Package struct, XTestDirectives []Directive #56986 pkg go/token, method (*File) Lines() []int #57708 +pkg go/types, method (*Package) GoVersion() string #61175 pkg html/template, const ErrJSTemplate = 12 #59584 pkg html/template, const ErrJSTemplate ErrorCode #59584 pkg io/fs, func FormatDirEntry(DirEntry) string #54451 @@ -218,18 +219,18 @@ pkg log/slog, func Any(string, interface{}) Attr #56345 pkg log/slog, func AnyValue(interface{}) Value #56345 pkg log/slog, func Bool(string, bool) Attr #56345 pkg log/slog, func BoolValue(bool) Value #56345 -pkg log/slog, func DebugCtx(context.Context, string, ...interface{}) #56345 +pkg log/slog, func DebugContext(context.Context, string, ...interface{}) #61200 pkg log/slog, func Debug(string, ...interface{}) #56345 pkg log/slog, func Default() *Logger #56345 pkg log/slog, func Duration(string, time.Duration) Attr #56345 pkg log/slog, func DurationValue(time.Duration) Value #56345 -pkg log/slog, func ErrorCtx(context.Context, string, ...interface{}) #56345 +pkg log/slog, func ErrorContext(context.Context, string, ...interface{}) #61200 pkg log/slog, func Error(string, ...interface{}) #56345 pkg log/slog, func Float64(string, float64) Attr #56345 pkg log/slog, func Float64Value(float64) Value #56345 pkg log/slog, func Group(string, ...interface{}) Attr #59204 pkg log/slog, func GroupValue(...Attr) Value #56345 -pkg log/slog, func InfoCtx(context.Context, string, ...interface{}) #56345 +pkg log/slog, func InfoContext(context.Context, string, ...interface{}) #61200 pkg log/slog, func Info(string, ...interface{}) #56345 pkg log/slog, func Int64(string, int64) Attr #56345 pkg log/slog, func Int64Value(int64) Value #56345 @@ -249,7 +250,7 @@ pkg log/slog, func Time(string, time.Time) Attr #56345 pkg log/slog, func TimeValue(time.Time) Value #56345 pkg log/slog, func Uint64(string, uint64) Attr #56345 pkg log/slog, func Uint64Value(uint64) Value #56345 -pkg log/slog, func WarnCtx(context.Context, string, ...interface{}) #56345 +pkg log/slog, func WarnContext(context.Context, string, ...interface{}) #61200 pkg log/slog, func Warn(string, ...interface{}) #56345 pkg log/slog, func With(...interface{}) *Logger #56345 pkg log/slog, method (Attr) Equal(Attr) bool #56345 @@ -270,17 +271,17 @@ pkg log/slog, method (*LevelVar) MarshalText() ([]uint8, error) #56345 pkg log/slog, method (*LevelVar) Set(Level) #56345 pkg log/slog, method (*LevelVar) String() string #56345 pkg log/slog, method (*LevelVar) UnmarshalText([]uint8) error #56345 -pkg log/slog, method (*Logger) DebugCtx(context.Context, string, ...interface{}) #56345 +pkg log/slog, method (*Logger) DebugContext(context.Context, string, ...interface{}) #61200 pkg log/slog, method (*Logger) Debug(string, ...interface{}) #56345 pkg log/slog, method (*Logger) Enabled(context.Context, Level) bool #56345 -pkg log/slog, method (*Logger) ErrorCtx(context.Context, string, ...interface{}) #56345 +pkg log/slog, method (*Logger) ErrorContext(context.Context, string, ...interface{}) #61200 pkg log/slog, method (*Logger) Error(string, ...interface{}) #56345 pkg log/slog, method (*Logger) Handler() Handler #56345 -pkg log/slog, method (*Logger) InfoCtx(context.Context, string, ...interface{}) #56345 +pkg log/slog, method (*Logger) InfoContext(context.Context, string, ...interface{}) #61200 pkg log/slog, method (*Logger) Info(string, ...interface{}) #56345 pkg log/slog, method (*Logger) LogAttrs(context.Context, Level, string, ...Attr) #56345 pkg log/slog, method (*Logger) Log(context.Context, Level, string, ...interface{}) #56345 -pkg log/slog, method (*Logger) WarnCtx(context.Context, string, ...interface{}) #56345 +pkg log/slog, method (*Logger) WarnContext(context.Context, string, ...interface{}) #61200 pkg log/slog, method (*Logger) Warn(string, ...interface{}) #56345 pkg log/slog, method (*Logger) WithGroup(string) *Logger #56345 pkg log/slog, method (*Logger) With(...interface{}) *Logger #56345 diff --git a/doc/go1.21.html b/doc/go1.21.html index 1d49084325..6c58cb0590 100644 --- a/doc/go1.21.html +++ b/doc/go1.21.html @@ -473,6 +473,16 @@ Do not send CLs removing the interior tags from such phrases. The new <a href="/pkg/context/#AfterFunc"><code>AfterFunc</code></a> function registers a function to run after a context has been cancelled. </p> + + <p><!-- CL 455455 --> + An optimization means that the results of calling + <a href="/pkg/context/#Background"><code>Background</code></a> + and <a href="/pkg/context/#TODO"><code>TODO</code></a> and + converting them to a shared type can be considered equal. + In previous releases they were always different. Comparing + <a href="/pkg/context/#Context"><code>Context</code></a> values + for equality has never been well-defined, so this is not + considered to be an incompatible change. </dd> </dl> @@ -495,7 +505,7 @@ Do not send CLs removing the interior tags from such phrases. <dl id="crypto/rsa"><dt><a href="/pkg/crypto/rsa/">crypto/rsa</a></dt> <dd> <p><!-- CL 471259, CL 492935 --> - The performance of private RSA operations (decryption and signing) is now better than Go 1.19 for <code>GOOS=amd64</code> and <code>GOOS=arm64</code>. It had regressed in Go 1.20. + The performance of private RSA operations (decryption and signing) is now better than Go 1.19 for <code>GOARCH=amd64</code> and <code>GOARCH=arm64</code>. It had regressed in Go 1.20. </p> <p> Due to the addition of private fields to <a href="/pkg/crypto/rsa/#PrecomputedValues"><code>PrecomputedValues</code></a>, <a href="/pkg/crypto/rsa/#PrivateKey.Precompute"><code>PrivateKey.Precompute</code></a> must be called for optimal performance even if deserializing (for example from JSON) a previously-precomputed private key. @@ -511,7 +521,7 @@ Do not send CLs removing the interior tags from such phrases. <dl id="crypto/sha256"><dt><a href="/pkg/crypto/sha256/">crypto/sha256</a></dt> <dd> <p><!-- https://go.dev/issue/50543, CL 408795 --> - SHA-224 and SHA-256 operations now use native instructions when available when <code>GOOS=amd64</code>, providing a performance improvement on the order of 3-4x. + SHA-224 and SHA-256 operations now use native instructions when available when <code>GOARCH=amd64</code>, providing a performance improvement on the order of 3-4x. </p> </dd> </dl><!-- crypto/sha256 --> @@ -579,7 +589,7 @@ Do not send CLs removing the interior tags from such phrases. <dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt> <dd> <p><!-- https://go.dev/issue/53573, CL 468875 --> - <a href="/pkg/crypto/x509/#RevocationList.RevokedCertificates"><code>RevocationList.RevokedCertificates</code></a> has been deprecated and replaced with the new <a href="/pkg/crypto/x509/#RevocationList.Entries"><code>RevocationList.Entries</code></a> field, which is a slice of <a href="/pkg/crypto/x509/#RevocationListEntry"><code>RevocationListEntry</code></a>. <a href="/pkg/crypto/x509/#RevocationListEntry"><code>RevocationListEntry</code></a> contains all of the fields in <a href="/pkg/crypto/x509/#pkix.RevokedCertificate"><code>pkix.RevokedCertificate</code></a>, as well as the revocation reason code. + <a href="/pkg/crypto/x509/#RevocationList.RevokedCertificates"><code>RevocationList.RevokedCertificates</code></a> has been deprecated and replaced with the new <a href="/pkg/crypto/x509/#RevocationList.RevokedCertificateEntries"><code>RevokedCertificateEntries</code></a> field, which is a slice of <a href="/pkg/crypto/x509/#RevocationListEntry"><code>RevocationListEntry</code></a>. <a href="/pkg/crypto/x509/#RevocationListEntry"><code>RevocationListEntry</code></a> contains all of the fields in <a href="/pkg/crypto/x509/pkix#RevokedCertificate"><code>pkix.RevokedCertificate</code></a>, as well as the revocation reason code. </p> </dd> </dl><!-- crypto/x509 --> @@ -907,6 +917,12 @@ Do not send CLs removing the interior tags from such phrases. names, stored as UTF-16, can't be represented as valid UTF-8. </p> + <p><!-- CL 463177 --> + On Windows <a href="/pkg/os/#Lstat"><code>Lstat</code></a> now resolves + symbolic links for paths ending with a path separator, consistent with its + behavior on POSIX platforms. + </p> + <p><!-- https://go.dev/issue/54451, CL 491175 --> The implementation of the <a href="/pkg/io/fs/#DirEntry"><code>io/fs.DirEntry</code></a> diff --git a/doc/godebug.md b/doc/godebug.md index 43dbcd645a..7a6d70e487 100644 --- a/doc/godebug.md +++ b/doc/godebug.md @@ -142,6 +142,10 @@ forms, controlled by the respectively. This behavior was backported to Go 1.19.8+ and Go 1.20.3+. +Go 1.21 adds the support of Multipath TCP but it is only used if the application +explicitly asked for it. This behavior can be controlled by the +[`multipathtcp` setting](/pkg/net#Dialer.SetMultipathTCP). + There is no plan to remove any of these settings. ### Go 1.20 diff --git a/src/README.vendor b/src/README.vendor index 4b6bdb8e74..43821b2900 100644 --- a/src/README.vendor +++ b/src/README.vendor @@ -38,7 +38,7 @@ The vendor directory may be updated with 'go mod vendor'. A typical sequence might be: cd src - go get golang.org/x/net@latest + go get golang.org/x/net@master go mod tidy go mod vendor diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go index 05c0090b61..f0733edd3f 100644 --- a/src/bytes/bytes_test.go +++ b/src/bytes/bytes_test.go @@ -652,6 +652,38 @@ func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) { } } +func BenchmarkEqualBothUnaligned(b *testing.B) { + sizes := []int{64, 4 << 10} + if !isRaceBuilder { + sizes = append(sizes, []int{4 << 20, 64 << 20}...) + } + maxSize := 2 * (sizes[len(sizes)-1] + 8) + if len(bmbuf) < maxSize { + bmbuf = make([]byte, maxSize) + } + + for _, n := range sizes { + for _, off := range []int{0, 1, 4, 7} { + buf1 := bmbuf[off : off+n] + buf2Start := (len(bmbuf) / 2) + off + buf2 := bmbuf[buf2Start : buf2Start+n] + buf1[n-1] = 'x' + buf2[n-1] = 'x' + b.Run(fmt.Sprint(n, off), func(b *testing.B) { + b.SetBytes(int64(n)) + for i := 0; i < b.N; i++ { + eq := Equal(buf1, buf2) + if !eq { + b.Fatal("bad equal") + } + } + }) + buf1[n-1] = '\x00' + buf2[n-1] = '\x00' + } + } +} + func BenchmarkIndex(b *testing.B) { benchBytes(b, indexSizes, func(b *testing.B, n int) { buf := bmbuf[0:n] diff --git a/src/cmd/asm/internal/lex/slice.go b/src/cmd/asm/internal/lex/slice.go index 8ee0c7035f..61b15dd963 100644 --- a/src/cmd/asm/internal/lex/slice.go +++ b/src/cmd/asm/internal/lex/slice.go @@ -65,7 +65,7 @@ func (s *Slice) Col() int { // #define A #define B(x) x // and // #define A #define B (x) x - // The first has definition of B has an argument, the second doesn't. Because we let + // The first definition of B has an argument, the second doesn't. Because we let // text/scanner strip the blanks for us, this is extremely rare, hard to fix, and not worth it. return s.pos } diff --git a/src/cmd/compile/internal/devirtualize/devirtualize.go b/src/cmd/compile/internal/devirtualize/devirtualize.go index cfeb8d8ee9..b156b66312 100644 --- a/src/cmd/compile/internal/devirtualize/devirtualize.go +++ b/src/cmd/compile/internal/devirtualize/devirtualize.go @@ -4,11 +4,11 @@ // Package devirtualize implements two "devirtualization" optimization passes: // -// - "Static" devirtualization which replaces interface method calls with -// direct concrete-type method calls where possible. -// - "Profile-guided" devirtualization which replaces indirect calls with a -// conditional direct call to the hottest concrete callee from a profile, as -// well as a fallback using the original indirect call. +// - "Static" devirtualization which replaces interface method calls with +// direct concrete-type method calls where possible. +// - "Profile-guided" devirtualization which replaces indirect calls with a +// conditional direct call to the hottest concrete callee from a profile, as +// well as a fallback using the original indirect call. package devirtualize import ( diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index 7f8ca023f2..769340e9cd 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -52,7 +52,6 @@ type Node interface { // 0 means the node is not typechecked // 1 means the node is completely typechecked // 2 means typechecking of the node is in progress - // 3 means the node has its type from types2, but may need transformation Typecheck() uint8 SetTypecheck(x uint8) NonNil() bool diff --git a/src/cmd/compile/internal/ir/visit.go b/src/cmd/compile/internal/ir/visit.go index 016467081e..73ec1de544 100644 --- a/src/cmd/compile/internal/ir/visit.go +++ b/src/cmd/compile/internal/ir/visit.go @@ -115,6 +115,17 @@ func VisitList(list Nodes, visit func(Node)) { } } +// VisitFuncAndClosures calls visit on each non-nil node in fn.Body, +// including any nested closure bodies. +func VisitFuncAndClosures(fn *Func, visit func(n Node)) { + VisitList(fn.Body, func(n Node) { + visit(n) + if n, ok := n.(*ClosureExpr); ok && n.Op() == OCLOSURE { + VisitFuncAndClosures(n.Func, visit) + } + }) +} + // Any looks for a non-nil node x in the IR tree rooted at n // for which cond(x) returns true. // Any considers nodes in a depth-first, preorder traversal. diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 70f51e2253..610d02c07c 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -3919,7 +3919,11 @@ func finishWrapperFunc(fn *ir.Func, target *ir.Package) { // The body of wrapper function after inlining may reveal new ir.OMETHVALUE node, // we don't know whether wrapper function has been generated for it or not, so // generate one immediately here. - ir.VisitList(fn.Body, func(n ir.Node) { + // + // Further, after CL 492017, function that construct closures is allowed to be inlined, + // even though the closure itself can't be inline. So we also need to visit body of any + // closure that we see when visiting body of the wrapper function. + ir.VisitFuncAndClosures(fn, func(n ir.Node) { if n, ok := n.(*ir.SelectorExpr); ok && n.Op() == ir.OMETHVALUE { wrapMethodValue(n.X.Type(), n.Selection, target, true) } diff --git a/src/cmd/compile/internal/ssa/_gen/PPC64.rules b/src/cmd/compile/internal/ssa/_gen/PPC64.rules index cbce468ad5..97e592fd7e 100644 --- a/src/cmd/compile/internal/ssa/_gen/PPC64.rules +++ b/src/cmd/compile/internal/ssa/_gen/PPC64.rules @@ -588,16 +588,16 @@ // small and of zero-extend => either zero-extend or small and (Select0 (ANDCCconst [c] y:(MOVBZreg _))) && c&0xFF == 0xFF => y -(Select0 (ANDCCconst [0xFF] y:(MOVBreg _))) => y +(Select0 (ANDCCconst [0xFF] (MOVBreg x))) => (MOVBZreg x) (Select0 (ANDCCconst [c] y:(MOVHZreg _))) && c&0xFFFF == 0xFFFF => y -(Select0 (ANDCCconst [0xFFFF] y:(MOVHreg _))) => y +(Select0 (ANDCCconst [0xFFFF] (MOVHreg x))) => (MOVHZreg x) (AND (MOVDconst [c]) y:(MOVWZreg _)) && c&0xFFFFFFFF == 0xFFFFFFFF => y (AND (MOVDconst [0xFFFFFFFF]) y:(MOVWreg x)) => (MOVWZreg x) // normal case -(Select0 (ANDCCconst [c] (MOV(B|BZ)reg x))) => (Select0 (ANDCCconst [c&0xFF] x)) -(Select0 (ANDCCconst [c] (MOV(H|HZ)reg x))) => (Select0 (ANDCCconst [c&0xFFFF] x)) -(Select0 (ANDCCconst [c] (MOV(W|WZ)reg x))) => (Select0 (ANDCCconst [c&0xFFFFFFFF] x)) +(Select0 (ANDCCconst [c] (MOVBZreg x))) => (Select0 (ANDCCconst [c&0xFF] x)) +(Select0 (ANDCCconst [c] (MOVHZreg x))) => (Select0 (ANDCCconst [c&0xFFFF] x)) +(Select0 (ANDCCconst [c] (MOVWZreg x))) => (Select0 (ANDCCconst [c&0xFFFFFFFF] x)) // Eliminate unnecessary sign/zero extend following right shift (MOV(B|H|W)Zreg (SRWconst [c] (MOVBZreg x))) => (SRWconst [c] (MOVBZreg x)) diff --git a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules index eb1f10de96..9a6fcebdc5 100644 --- a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules +++ b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules @@ -836,11 +836,11 @@ // // Key: // -// [+ -](x * y) [+ -] z. -// _ N A S -// D U -// D B +// [+ -](x * y [+ -] z). +// _ N A S +// D U +// D B // // Note: multiplication commutativity handled by rule generator. -(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMADD|MADD|NMSUB|MSUB)D x y z) +(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMSUB|MSUB|NMADD|MADD)D x y z) (F(MADD|NMADD|MSUB|NMSUB)D x y neg:(FNEGD z)) && neg.Uses == 1 => (F(MSUB|NMSUB|MADD|NMADD)D x y z) diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go index a380b4aeaf..d1c0c2b07f 100644 --- a/src/cmd/compile/internal/ssa/rewritePPC64.go +++ b/src/cmd/compile/internal/ssa/rewritePPC64.go @@ -14410,17 +14410,19 @@ func rewriteValuePPC64_OpSelect0(v *Value) bool { v.copyOf(y) return true } - // match: (Select0 (ANDCCconst [0xFF] y:(MOVBreg _))) - // result: y + // match: (Select0 (ANDCCconst [0xFF] (MOVBreg x))) + // result: (MOVBZreg x) for { if v_0.Op != OpPPC64ANDCCconst || auxIntToInt64(v_0.AuxInt) != 0xFF { break } - y := v_0.Args[0] - if y.Op != OpPPC64MOVBreg { + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpPPC64MOVBreg { break } - v.copyOf(y) + x := v_0_0.Args[0] + v.reset(OpPPC64MOVBZreg) + v.AddArg(x) return true } // match: (Select0 (ANDCCconst [c] y:(MOVHZreg _))) @@ -14438,36 +14440,19 @@ func rewriteValuePPC64_OpSelect0(v *Value) bool { v.copyOf(y) return true } - // match: (Select0 (ANDCCconst [0xFFFF] y:(MOVHreg _))) - // result: y + // match: (Select0 (ANDCCconst [0xFFFF] (MOVHreg x))) + // result: (MOVHZreg x) for { if v_0.Op != OpPPC64ANDCCconst || auxIntToInt64(v_0.AuxInt) != 0xFFFF { break } - y := v_0.Args[0] - if y.Op != OpPPC64MOVHreg { - break - } - v.copyOf(y) - return true - } - // match: (Select0 (ANDCCconst [c] (MOVBreg x))) - // result: (Select0 (ANDCCconst [c&0xFF] x)) - for { - if v_0.Op != OpPPC64ANDCCconst { - break - } - c := auxIntToInt64(v_0.AuxInt) v_0_0 := v_0.Args[0] - if v_0_0.Op != OpPPC64MOVBreg { + if v_0_0.Op != OpPPC64MOVHreg { break } x := v_0_0.Args[0] - v.reset(OpSelect0) - v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.NewTuple(typ.Int, types.TypeFlags)) - v0.AuxInt = int64ToAuxInt(c & 0xFF) - v0.AddArg(x) - v.AddArg(v0) + v.reset(OpPPC64MOVHZreg) + v.AddArg(x) return true } // match: (Select0 (ANDCCconst [c] (MOVBZreg x))) @@ -14489,25 +14474,6 @@ func rewriteValuePPC64_OpSelect0(v *Value) bool { v.AddArg(v0) return true } - // match: (Select0 (ANDCCconst [c] (MOVHreg x))) - // result: (Select0 (ANDCCconst [c&0xFFFF] x)) - for { - if v_0.Op != OpPPC64ANDCCconst { - break - } - c := auxIntToInt64(v_0.AuxInt) - v_0_0 := v_0.Args[0] - if v_0_0.Op != OpPPC64MOVHreg { - break - } - x := v_0_0.Args[0] - v.reset(OpSelect0) - v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.NewTuple(typ.Int, types.TypeFlags)) - v0.AuxInt = int64ToAuxInt(c & 0xFFFF) - v0.AddArg(x) - v.AddArg(v0) - return true - } // match: (Select0 (ANDCCconst [c] (MOVHZreg x))) // result: (Select0 (ANDCCconst [c&0xFFFF] x)) for { @@ -14527,25 +14493,6 @@ func rewriteValuePPC64_OpSelect0(v *Value) bool { v.AddArg(v0) return true } - // match: (Select0 (ANDCCconst [c] (MOVWreg x))) - // result: (Select0 (ANDCCconst [c&0xFFFFFFFF] x)) - for { - if v_0.Op != OpPPC64ANDCCconst { - break - } - c := auxIntToInt64(v_0.AuxInt) - v_0_0 := v_0.Args[0] - if v_0_0.Op != OpPPC64MOVWreg { - break - } - x := v_0_0.Args[0] - v.reset(OpSelect0) - v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.NewTuple(typ.Int, types.TypeFlags)) - v0.AuxInt = int64ToAuxInt(c & 0xFFFFFFFF) - v0.AddArg(x) - v.AddArg(v0) - return true - } // match: (Select0 (ANDCCconst [c] (MOVWZreg x))) // result: (Select0 (ANDCCconst [c&0xFFFFFFFF] x)) for { diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go index f1debe0c21..ffbeb1df47 100644 --- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go +++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go @@ -3322,7 +3322,7 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool { v_0 := v.Args[0] // match: (FMADDD neg:(FNEGD x) y z) // cond: neg.Uses == 1 - // result: (FNMADDD x y z) + // result: (FNMSUBD x y z) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { neg := v_0 @@ -3335,7 +3335,7 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool { if !(neg.Uses == 1) { continue } - v.reset(OpRISCV64FNMADDD) + v.reset(OpRISCV64FNMSUBD) v.AddArg3(x, y, z) return true } @@ -3367,7 +3367,7 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool { v_0 := v.Args[0] // match: (FMSUBD neg:(FNEGD x) y z) // cond: neg.Uses == 1 - // result: (FNMSUBD x y z) + // result: (FNMADDD x y z) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { neg := v_0 @@ -3380,7 +3380,7 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool { if !(neg.Uses == 1) { continue } - v.reset(OpRISCV64FNMSUBD) + v.reset(OpRISCV64FNMADDD) v.AddArg3(x, y, z) return true } @@ -3412,7 +3412,7 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool { v_0 := v.Args[0] // match: (FNMADDD neg:(FNEGD x) y z) // cond: neg.Uses == 1 - // result: (FMADDD x y z) + // result: (FMSUBD x y z) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { neg := v_0 @@ -3425,7 +3425,7 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool { if !(neg.Uses == 1) { continue } - v.reset(OpRISCV64FMADDD) + v.reset(OpRISCV64FMSUBD) v.AddArg3(x, y, z) return true } @@ -3457,7 +3457,7 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool { v_0 := v.Args[0] // match: (FNMSUBD neg:(FNEGD x) y z) // cond: neg.Uses == 1 - // result: (FMSUBD x y z) + // result: (FMADDD x y z) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { neg := v_0 @@ -3470,7 +3470,7 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool { if !(neg.Uses == 1) { continue } - v.reset(OpRISCV64FMSUBD) + v.reset(OpRISCV64FMADDD) v.AddArg3(x, y, z) return true } diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go index 5df65bfaa3..bd9e0b8268 100644 --- a/src/cmd/compile/internal/ssa/writebarrier.go +++ b/src/cmd/compile/internal/ssa/writebarrier.go @@ -53,7 +53,10 @@ func mightContainHeapPointer(ptr *Value, size int64, mem *Value, zeroes map[ID]Z } ptrSize := ptr.Block.Func.Config.PtrSize - if off%ptrSize != 0 || size%ptrSize != 0 { + if off%ptrSize != 0 { + return true // see issue 61187 + } + if size%ptrSize != 0 { ptr.Fatalf("unaligned pointer write") } if off < 0 || off+size > 64*ptrSize { @@ -130,7 +133,7 @@ func needWBdst(ptr, mem *Value, zeroes map[ID]ZeroRegion) bool { } ptrSize := ptr.Block.Func.Config.PtrSize if off%ptrSize != 0 { - ptr.Fatalf("unaligned pointer write") + return true // see issue 61187 } if off < 0 || off >= 64*ptrSize { // write goes off end of tracked offsets diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 88fee51d33..678e1ebc11 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -3620,8 +3620,13 @@ func (s *state) minMax(n *ir.CallExpr) *ssa.Value { // ternary emits code to evaluate cond ? x : y. func (s *state) ternary(cond, x, y *ssa.Value) *ssa.Value { + // Note that we need a new ternaryVar each time (unlike okVar where we can + // reuse the variable) because it might have a different type every time. + ternaryVar := ssaMarker("ternary") + bThen := s.f.NewBlock(ssa.BlockPlain) bElse := s.f.NewBlock(ssa.BlockPlain) + bEnd := s.f.NewBlock(ssa.BlockPlain) b := s.endBlock() b.Kind = ssa.BlockIf @@ -3629,11 +3634,18 @@ func (s *state) ternary(cond, x, y *ssa.Value) *ssa.Value { b.AddEdgeTo(bThen) b.AddEdgeTo(bElse) + s.startBlock(bThen) + s.vars[ternaryVar] = x + s.endBlock().AddEdgeTo(bEnd) + s.startBlock(bElse) - s.endBlock().AddEdgeTo(bThen) + s.vars[ternaryVar] = y + s.endBlock().AddEdgeTo(bEnd) - s.startBlock(bThen) - return s.newValue2(ssa.OpPhi, x.Type, x, y) + s.startBlock(bEnd) + r := s.variable(ternaryVar, x.Type) + delete(s.vars, ternaryVar) + return r } // condBranch evaluates the boolean expression cond and branches to yes diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go index c434ff9118..9dea261bb9 100644 --- a/src/cmd/compile/internal/typecheck/stmt.go +++ b/src/cmd/compile/internal/typecheck/stmt.go @@ -607,7 +607,7 @@ func tcSwitchType(n *ir.SwitchStmt) { if !n1.Type().IsInterface() { why := ImplementsExplain(n1.Type(), t) if why != "" { - base.ErrorfAt(ncase.Pos(), errors.ImpossibleAssert, "impossible type switch case: %L cannot have dynamic type %v (%s)" , guard.X, n1.Type(), why) + base.ErrorfAt(ncase.Pos(), errors.ImpossibleAssert, "impossible type switch case: %L cannot have dynamic type %v (%s)", guard.X, n1.Type(), why) } continue } diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 8554805fa6..2bb978a0fa 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -713,12 +713,12 @@ func ImplementsExplain(t, iface *types.Type) string { return fmt.Sprintf("%v does not implement %v (%v method is marked 'nointerface')", t, iface, missing.Sym) } else if have != nil && have.Sym == missing.Sym { return fmt.Sprintf("%v does not implement %v (wrong type for %v method)\n"+ - "\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) + "\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) } else if ptr != 0 { return fmt.Sprintf("%v does not implement %v (%v method has pointer receiver)", t, iface, missing.Sym) } else if have != nil { return fmt.Sprintf("%v does not implement %v (missing %v method)\n"+ - "\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) + "\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) } return fmt.Sprintf("%v does not implement %v (missing %v method)", t, iface, missing.Sym) } diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index a3e1981af6..f3763862ec 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -578,6 +578,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( x.mode = value } + // Use the final type computed above for all arguments. + for _, a := range args { + check.updateExprType(a.expr, x.typ, true) + } + if check.recordTypes() && x.mode != constant_ { types := make([]Type, nargs) for i := range types { diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index b2a9eb0dbc..0a2a49062b 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "go/constant" + "internal/goversion" . "internal/types/errors" ) @@ -231,19 +232,19 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker { info = new(Info) } - version, err := parseGoVersion(conf.GoVersion) - if err != nil { - panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err)) - } + // Note: clients may call NewChecker with the Unsafe package, which is + // globally shared and must not be mutated. Therefore NewChecker must not + // mutate *pkg. + // + // (previously, pkg.goVersion was mutated here: go.dev/issue/61212) return &Checker{ - conf: conf, - ctxt: conf.Context, - pkg: pkg, - Info: info, - version: version, - objMap: make(map[Object]*declInfo), - impMap: make(map[importKey]*Package), + conf: conf, + ctxt: conf.Context, + pkg: pkg, + Info: info, + objMap: make(map[Object]*declInfo), + impMap: make(map[importKey]*Package), } } @@ -333,6 +334,20 @@ func (check *Checker) Files(files []*syntax.File) error { return check.checkFile var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together") func (check *Checker) checkFiles(files []*syntax.File) (err error) { + if check.pkg == Unsafe { + // Defensive handling for Unsafe, which cannot be type checked, and must + // not be mutated. See https://go.dev/issue/61212 for an example of where + // Unsafe is passed to NewChecker. + return nil + } + + check.version, err = parseGoVersion(check.conf.GoVersion) + if err != nil { + return err + } + if check.version.after(version{1, goversion.Version}) { + return fmt.Errorf("package requires newer Go version %v", check.version) + } if check.conf.FakeImportC && check.conf.go115UsesCgo { return errBadCgo } @@ -377,6 +392,7 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) { check.monomorph() } + check.pkg.goVersion = check.conf.GoVersion check.pkg.complete = true // no longer needed - release memory diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index 4fbe064da6..3ebe851355 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -184,6 +184,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo if !valid { check.errorf(e.Pos(), NonSliceableOperand, invalidOp+"cannot index %s", x) + check.use(e.Index) x.mode = invalid return false } diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go index 8bd42a5271..5e0ae213dc 100644 --- a/src/cmd/compile/internal/types2/issues_test.go +++ b/src/cmd/compile/internal/types2/issues_test.go @@ -497,14 +497,14 @@ func TestIssue43088(t *testing.T) { // _ T2 // } // } - n1 := NewTypeName(syntax.Pos{}, nil, "T1", nil) + n1 := NewTypeName(nopos, nil, "T1", nil) T1 := NewNamed(n1, nil, nil) - n2 := NewTypeName(syntax.Pos{}, nil, "T2", nil) + n2 := NewTypeName(nopos, nil, "T2", nil) T2 := NewNamed(n2, nil, nil) - s1 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil) + s1 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil) T1.SetUnderlying(s1) - s2 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil) - s3 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", s2, false)}, nil) + s2 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil) + s3 := NewStruct([]*Var{NewField(nopos, nil, "_", s2, false)}, nil) T2.SetUnderlying(s3) // These calls must terminate (no endless recursion). @@ -535,38 +535,69 @@ func TestIssue44515(t *testing.T) { } func TestIssue43124(t *testing.T) { - testenv.MustHaveGoBuild(t) + // TODO(rFindley) move this to testdata by enhancing support for importing. + + testenv.MustHaveGoBuild(t) // The go command is needed for the importer to determine the locations of stdlib .a files. // All involved packages have the same name (template). Error messages should // disambiguate between text/template and html/template by printing the full // path. const ( asrc = `package a; import "text/template"; func F(template.Template) {}; func G(int) {}` - bsrc = `package b; import ("a"; "html/template"); func _() { a.F(template.Template{}) }` - csrc = `package c; import ("a"; "html/template"); func _() { a.G(template.Template{}) }` - ) + bsrc = ` +package b - a := mustTypecheck(asrc, nil, nil) - conf := Config{Importer: importHelper{pkg: a, fallback: defaultImporter()}} +import ( + "a" + "html/template" +) +func _() { // Packages should be fully qualified when there is ambiguity within the // error string itself. - _, err := typecheck(bsrc, &conf, nil) - if err == nil { - t.Fatal("package b had no errors") - } - if !strings.Contains(err.Error(), "text/template") || !strings.Contains(err.Error(), "html/template") { - t.Errorf("type checking error for b does not disambiguate package template: %q", err) - } + a.F(template /* ERRORx "cannot use.*html/template.* as .*text/template" */ .Template{}) +} +` + csrc = ` +package c - // ...and also when there is any ambiguity in reachable packages. - _, err = typecheck(csrc, &conf, nil) - if err == nil { - t.Fatal("package c had no errors") - } - if !strings.Contains(err.Error(), "html/template") { - t.Errorf("type checking error for c does not disambiguate package template: %q", err) +import ( + "a" + "fmt" + "html/template" +) + +// go.dev/issue/46905: make sure template is not the first package qualified. +var _ fmt.Stringer = 1 // ERRORx "cannot use 1.*as fmt\\.Stringer" + +// Packages should be fully qualified when there is ambiguity in reachable +// packages. In this case both a (and for that matter html/template) import +// text/template. +func _() { a.G(template /* ERRORx "cannot use .*html/template.*Template" */ .Template{}) } +` + + tsrc = ` +package template + +import "text/template" + +type T int + +// Verify that the current package name also causes disambiguation. +var _ T = template /* ERRORx "cannot use.*text/template.* as T value" */.Template{} +` + ) + + a := mustTypecheck(asrc, nil, nil) + imp := importHelper{pkg: a, fallback: defaultImporter()} + + withImporter := func(cfg *Config) { + cfg.Importer = imp } + + testFiles(t, []string{"b.go"}, [][]byte{[]byte(bsrc)}, 0, false, withImporter) + testFiles(t, []string{"c.go"}, [][]byte{[]byte(csrc)}, 0, false, withImporter) + testFiles(t, []string{"t.go"}, [][]byte{[]byte(tsrc)}, 0, false, withImporter) } func TestIssue50646(t *testing.T) { diff --git a/src/cmd/compile/internal/types2/package.go b/src/cmd/compile/internal/types2/package.go index 61670f6718..e08099d81f 100644 --- a/src/cmd/compile/internal/types2/package.go +++ b/src/cmd/compile/internal/types2/package.go @@ -10,13 +10,14 @@ import ( // A Package describes a Go package. type Package struct { - path string - name string - scope *Scope - imports []*Package - complete bool - fake bool // scope lookup errors are silently dropped if package is fake (internal use only) - cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go + path string + name string + scope *Scope + imports []*Package + complete bool + fake bool // scope lookup errors are silently dropped if package is fake (internal use only) + cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go + goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod) } // NewPackage returns a new Package for the given package path and name. @@ -35,6 +36,12 @@ func (pkg *Package) Name() string { return pkg.name } // SetName sets the package name. func (pkg *Package) SetName(name string) { pkg.name = name } +// GoVersion returns the minimum Go version required by this package. +// If the minimum version is unknown, GoVersion returns the empty string. +// Individual source files may specify a different minimum Go version, +// as reported in the [go/ast.File.GoVersion] field. +func (pkg *Package) GoVersion() string { return pkg.goVersion } + // Scope returns the (complete or incomplete) package scope // holding the objects declared at package level (TypeNames, // Consts, Vars, and Funcs). diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index af82b3fa7a..740dbc9276 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -47,7 +47,7 @@ func TestSizeof(t *testing.T) { // Misc {Scope{}, 60, 104}, - {Package{}, 36, 72}, + {Package{}, 44, 88}, {_TypeSet{}, 28, 56}, } diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 48adc185c3..94830e94f7 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -124,6 +124,20 @@ const ( exact ) +func (m unifyMode) String() string { + switch m { + case 0: + return "inexact" + case assign: + return "assign" + case exact: + return "exact" + case assign | exact: + return "assign, exact" + } + return fmt.Sprintf("mode %d", m) +} + // unify attempts to unify x and y and reports whether it succeeded. // As a side-effect, types may be inferred for type parameters. // The mode parameter controls how types are compared. @@ -256,6 +270,15 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type { return list } +// asInterface returns the underlying type of x as an interface if +// it is a non-type parameter interface. Otherwise it returns nil. +func asInterface(x Type) (i *Interface) { + if _, ok := x.(*TypeParam); !ok { + i, _ = under(x).(*Interface) + } + return i +} + // nify implements the core unification algorithm which is an // adapted version of Checker.identical. For changes to that // code the corresponding changes should be made here. @@ -263,7 +286,7 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type { func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { u.depth++ if traceInference { - u.tracef("%s ≡ %s (mode %d)", x, y, mode) + u.tracef("%s ≡ %s\t// %s", x, y, mode) } defer func() { if traceInference && !result { @@ -294,7 +317,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // - type parameter recorded with u, make sure one is in x if _, ok := x.(*Named); ok || u.asTypeParam(y) != nil { if traceInference { - u.tracef("%s ≡ %s (swap)", y, x) + u.tracef("%s ≡ %s\t// swap", y, x) } x, y = y, x } @@ -350,11 +373,49 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { if x := u.at(px); x != nil { // x has an inferred type which must match y if u.nify(x, y, mode, p) { - // If we have a match, possibly through underlying types, - // and y is a defined type, make sure we record that type + // We have a match, possibly through underlying types. + xi := asInterface(x) + yi := asInterface(y) + _, xn := x.(*Named) + _, yn := y.(*Named) + // If we have two interfaces, what to do depends on + // whether they are named and their method sets. + if xi != nil && yi != nil { + // Both types are interfaces. + // If both types are defined types, they must be identical + // because unification doesn't know which type has the "right" name. + if xn && yn { + return Identical(x, y) + } + // In all other cases, the method sets must match. + // The types unified so we know that corresponding methods + // match and we can simply compare the number of methods. + // TODO(gri) We may be able to relax this rule and select + // the more general interface. But if one of them is a defined + // type, it's not clear how to choose and whether we introduce + // an order dependency or not. Requiring the same method set + // is conservative. + if len(xi.typeSet().methods) != len(yi.typeSet().methods) { + return false + } + } else if xi != nil || yi != nil { + // One but not both of them are interfaces. + // In this case, either x or y could be viable matches for the corresponding + // type parameter, which means choosing either introduces an order dependence. + // Therefore, we must fail unification (go.dev/issue/60933). + return false + } + // If y is a defined type, make sure we record that type // for type parameter x, which may have until now only // recorded an underlying type (go.dev/issue/43056). - if _, ok := y.(*Named); ok { + // Either both types are interfaces, or neither type is. + // If both are interfaces, they have the same methods. + // + // Note: Changing the recorded type for a type parameter to + // a defined type is only ok when unification is inexact. + // But in exact unification, if we have a match, x and y must + // be identical, so changing the recorded type for x is a no-op. + if yn { u.set(px, y) } return true @@ -384,14 +445,8 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { if enableInterfaceInference && mode&exact == 0 { // One or both interfaces may be defined types. // Look under the name, but not under type parameters (go.dev/issue/60564). - var xi *Interface - if _, ok := x.(*TypeParam); !ok { - xi, _ = under(x).(*Interface) - } - var yi *Interface - if _, ok := y.(*TypeParam); !ok { - yi, _ = under(y).(*Interface) - } + xi := asInterface(x) + yi := asInterface(y) // If we have two interfaces, check the type terms for equivalence, // and unify common methods if possible. if xi != nil && yi != nil { @@ -492,7 +547,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // TODO(gri) Factor out type parameter handling from the switch. if isTypeParam(y) { if traceInference { - u.tracef("%s ≡ %s (swap)", y, x) + u.tracef("%s ≡ %s\t// swap", y, x) } x, y = y, x } diff --git a/src/cmd/compile/internal/types2/version.go b/src/cmd/compile/internal/types2/version.go index 7d01b829a9..e525f16470 100644 --- a/src/cmd/compile/internal/types2/version.go +++ b/src/cmd/compile/internal/types2/version.go @@ -6,7 +6,6 @@ package types2 import ( "cmd/compile/internal/syntax" - "errors" "fmt" "strings" ) @@ -44,23 +43,24 @@ var ( go1_21 = version{1, 21} ) -var errVersionSyntax = errors.New("invalid Go version syntax") - // parseGoVersion parses a Go version string (such as "go1.12") // and returns the version, or an error. If s is the empty // string, the version is 0.0. func parseGoVersion(s string) (v version, err error) { + bad := func() (version, error) { + return version{}, fmt.Errorf("invalid Go version syntax %q", s) + } if s == "" { return } if !strings.HasPrefix(s, "go") { - return version{}, errVersionSyntax + return bad() } s = s[len("go"):] i := 0 for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { if i >= 10 || i == 0 && s[i] == '0' { - return version{}, errVersionSyntax + return bad() } v.major = 10*v.major + int(s[i]) - '0' } @@ -68,7 +68,7 @@ func parseGoVersion(s string) (v version, err error) { return } if i == 0 || s[i] != '.' { - return version{}, errVersionSyntax + return bad() } s = s[i+1:] if s == "0" { @@ -81,14 +81,15 @@ func parseGoVersion(s string) (v version, err error) { i = 0 for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { if i >= 10 || i == 0 && s[i] == '0' { - return version{}, errVersionSyntax + return bad() } v.minor = 10*v.minor + int(s[i]) - '0' } - if i > 0 && i == len(s) { - return - } - return version{}, errVersionSyntax + // Accept any suffix after the minor number. + // We are only looking for the language version (major.minor) + // but want to accept any valid Go version, like go1.21.0 + // and go1.21rc2. + return } // langCompat reports an error if the representation of a numeric diff --git a/src/cmd/compile/internal/types2/version_test.go b/src/cmd/compile/internal/types2/version_test.go new file mode 100644 index 0000000000..651758e1b0 --- /dev/null +++ b/src/cmd/compile/internal/types2/version_test.go @@ -0,0 +1,24 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types2 + +import "testing" + +var parseGoVersionTests = []struct { + in string + out version +}{ + {"go1.21", version{1, 21}}, + {"go1.21.0", version{1, 21}}, + {"go1.21rc2", version{1, 21}}, +} + +func TestParseGoVersion(t *testing.T) { + for _, tt := range parseGoVersionTests { + if out, err := parseGoVersion(tt.in); out != tt.out || err != nil { + t.Errorf("parseGoVersion(%q) = %v, %v, want %v, nil", tt.in, out, err, tt.out) + } + } +} diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go index 5c924a90c5..786c31313c 100644 --- a/src/cmd/compile/internal/walk/builtin.go +++ b/src/cmd/compile/internal/walk/builtin.go @@ -135,7 +135,11 @@ func walkClear(n *ir.UnaryExpr) ir.Node { typ := n.X.Type() switch { case typ.IsSlice(): - return arrayClear(n.X.Pos(), n.X, nil) + if n := arrayClear(n.X.Pos(), n.X, nil); n != nil { + return n + } + // If n == nil, we are clearing an array which takes zero memory, do nothing. + return ir.NewBlockStmt(n.Pos(), nil) case typ.IsMap(): return mapClear(n.X, reflectdata.TypePtrAt(n.X.Pos(), n.X.Type())) } diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 1e76761de3..057e0b75b8 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -755,7 +755,7 @@ func (o *orderState) stmt(n ir.Node) { o.out = append(o.out, n) o.popTemp(t) - case ir.OMAX, ir.OMIN, ir.OPRINT, ir.OPRINTN, ir.ORECOVERFP: + case ir.OPRINT, ir.OPRINTN, ir.ORECOVERFP: n := n.(*ir.CallExpr) t := o.markTemp() o.call(n) @@ -1247,6 +1247,8 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node { ir.OMAKEMAP, ir.OMAKESLICE, ir.OMAKESLICECOPY, + ir.OMAX, + ir.OMIN, ir.ONEW, ir.OREAL, ir.ORECOVERFP, diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go index 265066200c..778b95d547 100644 --- a/src/cmd/compile/internal/walk/walk.go +++ b/src/cmd/compile/internal/walk/walk.go @@ -337,10 +337,14 @@ func mayCall(n ir.Node) bool { n := n.(*ir.ConvExpr) return ssagen.Arch.SoftFloat && (isSoftFloat(n.Type()) || isSoftFloat(n.X.Type())) + case ir.OMIN, ir.OMAX: + // string or float requires runtime call, see (*ssagen.state).minmax method. + return n.Type().IsString() || n.Type().IsFloat() + case ir.OLITERAL, ir.ONIL, ir.ONAME, ir.OLINKSYMOFFSET, ir.OMETHEXPR, ir.OAND, ir.OANDNOT, ir.OLSH, ir.OOR, ir.ORSH, ir.OXOR, ir.OCOMPLEX, ir.OEFACE, ir.OADDR, ir.OBITNOT, ir.ONOT, ir.OPLUS, - ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL, ir.OMIN, ir.OMAX, + ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL, ir.OCONVNOP, ir.ODOT, ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.OSPTR, ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OSLICEHEADER, ir.OSTRINGHEADER: diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go index ea6562c999..a4b837c9ad 100644 --- a/src/cmd/cover/cover.go +++ b/src/cmd/cover/cover.go @@ -95,7 +95,7 @@ const ( func main() { objabi.AddVersionFlag() flag.Usage = usage - flag.Parse() + objabi.Flagparse(usage) // Usage information when no arguments. if flag.NFlag() == 0 && flag.NArg() == 0 { diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 4b77ed36f7..8973a87168 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -631,7 +631,6 @@ var gentab = []struct { }{ {"go/build", "zcgo.go", mkzcgo}, {"cmd/go/internal/cfg", "zdefaultcc.go", mkzdefaultcc}, - {"internal/platform", "zosarch.go", mkzosarch}, {"runtime/internal/sys", "zversion.go", mkzversion}, {"time/tzdata", "zzipdata.go", mktzdata}, } @@ -1899,11 +1898,12 @@ func cmdversion() { // cmdlist lists all supported platforms. func cmdlist() { jsonFlag := flag.Bool("json", false, "produce JSON output") + brokenFlag := flag.Bool("broken", false, "include broken ports") xflagparse(0) var plats []string for p := range cgoEnabled { - if broken[p] { + if broken[p] && !*brokenFlag { continue } plats = append(plats, p) @@ -1922,6 +1922,7 @@ func cmdlist() { GOARCH string CgoSupported bool FirstClass bool + Broken bool `json:",omitempty"` } var results []jsonResult for _, p := range plats { @@ -1930,7 +1931,9 @@ func cmdlist() { GOOS: fields[0], GOARCH: fields[1], CgoSupported: cgoEnabled[p], - FirstClass: firstClass[p]}) + FirstClass: firstClass[p], + Broken: broken[p], + }) } out, err := json.MarshalIndent(results, "", "\t") if err != nil { diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go index b3fe8b02d8..1de78f0fdb 100644 --- a/src/cmd/dist/buildruntime.go +++ b/src/cmd/dist/buildruntime.go @@ -6,7 +6,6 @@ package main import ( "fmt" - "sort" "strings" ) @@ -80,25 +79,3 @@ func mkobjabi(file string) { writefile(buf.String(), file, writeSkipSame) } - -// mkzosarch writes zosarch.go for internal/platform. -func mkzosarch(dir, file string) { - // sort for deterministic file contents. - var list []string - for plat := range cgoEnabled { - list = append(list, plat) - } - sort.Strings(list) - - var buf strings.Builder - writeHeader(&buf) - fmt.Fprintf(&buf, "package platform\n") - fmt.Fprintln(&buf) - fmt.Fprintf(&buf, "var osArchSupportsCgo = map[string]bool{\n") - for _, plat := range list { - fmt.Fprintf(&buf, "\t\t%s: %v,\n", quote(plat), cgoEnabled[plat]) - } - fmt.Fprintf(&buf, "}\n") - - writefile(buf.String(), file, writeSkipSame) -} diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index 5e026f7bed..a528d7aa76 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -70,6 +70,11 @@ var bootstrapDirs = []string{ "internal/goexperiment", "internal/goroot", "internal/goversion", + // internal/lazyregexp is provided by Go 1.17, which permits it to + // be imported by other packages in this list, but is not provided + // by the Go 1.17 version of gccgo. It's on this list only to + // support gccgo, and can be removed if we require gccgo 14 or later. + "internal/lazyregexp", "internal/pkgbits", "internal/platform", "internal/profile", @@ -126,7 +131,6 @@ func bootstrapBuildTools() { mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot)) mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot)) - mkzosarch("", pathf("%s/src/internal/platform/zosarch.go", goroot)) // Use $GOROOT/pkg/bootstrap as the bootstrap workspace root. // We use a subdirectory of $GOROOT/pkg because that's the diff --git a/src/cmd/dist/main.go b/src/cmd/dist/main.go index 5f3e5bc9bd..f3425a9dd8 100644 --- a/src/cmd/dist/main.go +++ b/src/cmd/dist/main.go @@ -16,14 +16,14 @@ func usage() { xprintf(`usage: go tool dist [command] Commands are: -banner print installation banner -bootstrap rebuild everything -clean deletes all built files -env [-p] print environment (-p: include $PATH) -install [dir] install individual directory -list [-json] list all supported platforms -test [-h] run Go test(s) -version print Go version +banner print installation banner +bootstrap rebuild everything +clean deletes all built files +env [-p] print environment (-p: include $PATH) +install [dir] install individual directory +list [-json] [-broken] list all supported platforms +test [-h] run Go test(s) +version print Go version All commands take -v flags to emit extra information. `) diff --git a/src/cmd/distpack/pack.go b/src/cmd/distpack/pack.go index 6867ac17c2..e8b5255e63 100644 --- a/src/cmd/distpack/pack.go +++ b/src/cmd/distpack/pack.go @@ -127,7 +127,6 @@ func main() { // Generated during cmd/dist. See ../dist/build.go:/gentab. "src/cmd/go/internal/cfg/zdefaultcc.go", "src/go/build/zcgo.go", - "src/internal/platform/zosarch.go", "src/runtime/internal/sys/zversion.go", "src/time/tzdata/zzipdata.go", diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 6b36e7cd45..ac8c9e4976 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -4,12 +4,12 @@ go 1.21 require ( github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 - golang.org/x/arch v0.3.0 - golang.org/x/mod v0.10.1-0.20230606122920-62c7e578f1a7 - golang.org/x/sync v0.2.1-0.20230601203510-93782cc822b6 - golang.org/x/sys v0.9.0 - golang.org/x/term v0.9.0 - golang.org/x/tools v0.9.4-0.20230613194514-c6c983054920 + golang.org/x/arch v0.4.0 + golang.org/x/mod v0.12.0 + golang.org/x/sync v0.3.0 + golang.org/x/sys v0.10.0 + golang.org/x/term v0.10.0 + golang.org/x/tools v0.11.1-0.20230712164437-1ca21856af7b ) require github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 // indirect diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 59e3f831ea..b7245ea447 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -2,15 +2,15 @@ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbu github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 h1:rcanfLhLDA8nozr/K289V1zcntHr3V+SHlXwzz1ZI2g= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/mod v0.10.1-0.20230606122920-62c7e578f1a7 h1:OSEstGpBW1+G0wiXI0bBgOnI8nRJQKX3GCNxF75VR1s= -golang.org/x/mod v0.10.1-0.20230606122920-62c7e578f1a7/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/sync v0.2.1-0.20230601203510-93782cc822b6 h1:kiysxTbHE5FVnrNyc9BC/yeJi3DTUBHIJtNbC9uvXk4= -golang.org/x/sync v0.2.1-0.20230601203510-93782cc822b6/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/tools v0.9.4-0.20230613194514-c6c983054920 h1:FJIPEU9owLOeJgghpx63YhobtkWkORJ3O5ZnbFr8Bzs= -golang.org/x/tools v0.9.4-0.20230613194514-c6c983054920/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= +golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/tools v0.11.1-0.20230712164437-1ca21856af7b h1:KIZCni6lCdxd4gxHx49Zp9mhckTFRbI/ZPDbR3jKu90= +golang.org/x/tools v0.11.1-0.20230712164437-1ca21856af7b/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= diff --git a/src/cmd/go/internal/base/tool.go b/src/cmd/go/internal/base/tool.go index 202e314b94..ab623da426 100644 --- a/src/cmd/go/internal/base/tool.go +++ b/src/cmd/go/internal/base/tool.go @@ -11,20 +11,31 @@ import ( "path/filepath" "cmd/go/internal/cfg" + "cmd/go/internal/par" ) // Tool returns the path to the named tool (for example, "vet"). // If the tool cannot be found, Tool exits the process. func Tool(toolName string) string { - toolPath := filepath.Join(build.ToolDir, toolName) + cfg.ToolExeSuffix() - if len(cfg.BuildToolexec) > 0 { - return toolPath - } - // Give a nice message if there is no tool with that name. - if _, err := os.Stat(toolPath); err != nil { + toolPath, err := ToolPath(toolName) + if err != nil && len(cfg.BuildToolexec) == 0 { + // Give a nice message if there is no tool with that name. fmt.Fprintf(os.Stderr, "go: no such tool %q\n", toolName) SetExitStatus(2) Exit() } return toolPath } + +// Tool returns the path at which we expect to find the named tool +// (for example, "vet"), and the error (if any) from statting that path. +func ToolPath(toolName string) (string, error) { + toolPath := filepath.Join(build.ToolDir, toolName) + cfg.ToolExeSuffix() + err := toolStatCache.Do(toolPath, func() error { + _, err := os.Stat(toolPath) + return err + }) + return toolPath, err +} + +var toolStatCache par.Cache[string, error] diff --git a/src/cmd/go/internal/gover/gover.go b/src/cmd/go/internal/gover/gover.go index 247717125b..b2a8261feb 100644 --- a/src/cmd/go/internal/gover/gover.go +++ b/src/cmd/go/internal/gover/gover.go @@ -111,7 +111,6 @@ func IsPrerelease(x string) bool { // // Prev("1.2") = "1.1" // Prev("1.3rc4") = "1.2" -// func Prev(x string) string { v := parse(x) if cmpInt(v.minor, "1") <= 0 { @@ -180,6 +179,9 @@ func parse(x string) version { // Parse prerelease. i := 0 for i < len(x) && (x[i] < '0' || '9' < x[i]) { + if x[i] < 'a' || 'z' < x[i] { + return version{} + } i++ } if i == 0 { diff --git a/src/cmd/go/internal/gover/gover_test.go b/src/cmd/go/internal/gover/gover_test.go index 97b3b761c8..3a0bf10fc5 100644 --- a/src/cmd/go/internal/gover/gover_test.go +++ b/src/cmd/go/internal/gover/gover_test.go @@ -95,6 +95,25 @@ var prevTests = []testCase1[string, string]{ {"1.40000000000000000", "1.39999999999999999"}, } +func TestIsValid(t *testing.T) { test1(t, isValidTests, "IsValid", IsValid) } + +var isValidTests = []testCase1[string, bool]{ + {"1.2rc3", true}, + {"1.2.3", true}, + {"1.999testmod", true}, + {"1.600+auto", false}, + {"1.22", true}, + {"1.21.0", true}, + {"1.21rc2", true}, + {"1.21", true}, + {"1.20.0", true}, + {"1.20", true}, + {"1.19", true}, + {"1.3", true}, + {"1.2", true}, + {"1", true}, +} + type testCase1[In, Out any] struct { in In out Out diff --git a/src/cmd/go/internal/gover/toolchain.go b/src/cmd/go/internal/gover/toolchain.go index efa2de46a5..b520277618 100644 --- a/src/cmd/go/internal/gover/toolchain.go +++ b/src/cmd/go/internal/gover/toolchain.go @@ -15,7 +15,7 @@ import ( // FromToolchain returns the Go version for the named toolchain, // derived from the name itself (not by running the toolchain). // A toolchain is named "goVERSION". -// A suffix after the VERSION introduced by a +, -, space, or tab is removed. +// A suffix after the VERSION introduced by a -, space, or tab is removed. // Examples: // // FromToolchain("go1.2.3") == "1.2.3" diff --git a/src/cmd/go/internal/modfetch/toolchain.go b/src/cmd/go/internal/modfetch/toolchain.go index 623f68f97b..1669ab92e7 100644 --- a/src/cmd/go/internal/modfetch/toolchain.go +++ b/src/cmd/go/internal/modfetch/toolchain.go @@ -60,6 +60,15 @@ func (r *toolchainRepo) Versions(ctx context.Context, prefix string) (*Versions, } } + // Always include our own version. + // This means that the development branch of Go 1.21 (say) will allow 'go get go@1.21' + // even though there are no Go 1.21 releases yet. + // Once there is a release, 1.21 will be treated as a query matching the latest available release. + // Before then, 1.21 will be treated as a query that resolves to this entry we are adding (1.21). + if v := gover.Local(); !have[v] { + list = append(list, goPrefix+v) + } + if r.path == "go" { sort.Slice(list, func(i, j int) bool { return gover.Compare(list[i], list[j]) < 0 @@ -74,20 +83,27 @@ func (r *toolchainRepo) Versions(ctx context.Context, prefix string) (*Versions, } func (r *toolchainRepo) Stat(ctx context.Context, rev string) (*RevInfo, error) { - // If we're asking about "go" (not "toolchain"), pretend to have - // all earlier Go versions available without network access: - // we will provide those ourselves, at least in GOTOOLCHAIN=auto mode. - if r.path == "go" && gover.Compare(rev, gover.Local()) <= 0 { - return &RevInfo{Version: rev}, nil - } - // Convert rev to DL version and stat that to make sure it exists. + // In theory the go@ versions should be like 1.21.0 + // and the toolchain@ versions should be like go1.21.0 + // but people will type the wrong one, and so we accept + // both and silently correct it to the standard form. prefix := "" v := rev v = strings.TrimPrefix(v, "go") if r.path == "toolchain" { prefix = "go" } + + if !gover.IsValid(v) { + return nil, fmt.Errorf("invalid %s version %s", r.path, rev) + } + // If we're asking about "go" (not "toolchain"), pretend to have + // all earlier Go versions available without network access: + // we will provide those ourselves, at least in GOTOOLCHAIN=auto mode. + if r.path == "go" && gover.Compare(v, gover.Local()) <= 0 { + return &RevInfo{Version: prefix + v}, nil + } if gover.IsLang(v) { return nil, fmt.Errorf("go language version %s is not a toolchain version", rev) } diff --git a/src/cmd/go/internal/modget/query.go b/src/cmd/go/internal/modget/query.go index 68706e7c79..b78c1c4621 100644 --- a/src/cmd/go/internal/modget/query.go +++ b/src/cmd/go/internal/modget/query.go @@ -239,10 +239,13 @@ func (q *query) matchesPath(path string) bool { // canMatchInModule reports whether the given module path can potentially // contain q.pattern. func (q *query) canMatchInModule(mPath string) bool { + if gover.IsToolchain(mPath) { + return false + } if q.canMatchWildcardInModule != nil { return q.canMatchWildcardInModule(mPath) } - return str.HasPathPrefix(q.pattern, mPath) && !gover.IsToolchain(mPath) + return str.HasPathPrefix(q.pattern, mPath) } // pathOnce invokes f to generate the pathSet for the given path, diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index 81c32d27a1..f8ddf1101a 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -473,7 +473,11 @@ func newQueryMatcher(path string, query, current string, allowed AllowedFunc) (* // AllowedFunc of qm. func (qm *queryMatcher) allowsVersion(ctx context.Context, v string) bool { if qm.prefix != "" && !strings.HasPrefix(v, qm.prefix) { - return false + if gover.IsToolchain(qm.path) && strings.TrimSuffix(qm.prefix, ".") == v { + // Allow 1.21 to match "1.21." prefix. + } else { + return false + } } if qm.filter != nil && !qm.filter(v) { return false diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 995da15c90..7df6f421d6 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -660,6 +660,7 @@ var defaultVetFlags = []string{ "-printf", // "-rangeloops", // "-shift", + "-slog", "-stringintconv", // "-structtags", // "-tests", diff --git a/src/cmd/go/internal/tool/tool.go b/src/cmd/go/internal/tool/tool.go index 069968b1b6..ebe189bb81 100644 --- a/src/cmd/go/internal/tool/tool.go +++ b/src/cmd/go/internal/tool/tool.go @@ -7,8 +7,11 @@ package tool import ( "context" + "encoding/json" + "flag" "fmt" "go/build" + "internal/platform" "os" "os/exec" "os/signal" @@ -68,10 +71,25 @@ func runTool(ctx context.Context, cmd *base.Command, args []string) { return } } - toolPath := base.Tool(toolName) - if toolPath == "" { - return + + toolPath, err := base.ToolPath(toolName) + if err != nil { + if toolName == "dist" && len(args) > 1 && args[1] == "list" { + // cmd/distpack removes the 'dist' tool from the toolchain to save space, + // since it is normally only used for building the toolchain in the first + // place. However, 'go tool dist list' is useful for listing all supported + // platforms. + // + // If the dist tool does not exist, impersonate this command. + if impersonateDistList(args[2:]) { + return + } + } + + // Emit the usual error for the missing tool. + _ = base.Tool(toolName) } + if toolN { cmd := toolPath if len(args) > 1 { @@ -88,7 +106,7 @@ func runTool(ctx context.Context, cmd *base.Command, args []string) { Stdout: os.Stdout, Stderr: os.Stderr, } - err := toolCmd.Start() + err = toolCmd.Start() if err == nil { c := make(chan os.Signal, 100) signal.Notify(c) @@ -145,3 +163,62 @@ func listTools() { fmt.Println(name) } } + +func impersonateDistList(args []string) (handled bool) { + fs := flag.NewFlagSet("go tool dist list", flag.ContinueOnError) + jsonFlag := fs.Bool("json", false, "produce JSON output") + brokenFlag := fs.Bool("broken", false, "include broken ports") + + // The usage for 'go tool dist' claims that + // “All commands take -v flags to emit extra information”, + // but list -v appears not to have any effect. + _ = fs.Bool("v", false, "emit extra information") + + if err := fs.Parse(args); err != nil || len(fs.Args()) > 0 { + // Unrecognized flag or argument. + // Force fallback to the real 'go tool dist'. + return false + } + + if !*jsonFlag { + for _, p := range platform.List { + if !*brokenFlag && platform.Broken(p.GOOS, p.GOARCH) { + continue + } + fmt.Println(p) + } + return true + } + + type jsonResult struct { + GOOS string + GOARCH string + CgoSupported bool + FirstClass bool + Broken bool `json:",omitempty"` + } + + var results []jsonResult + for _, p := range platform.List { + broken := platform.Broken(p.GOOS, p.GOARCH) + if broken && !*brokenFlag { + continue + } + if *jsonFlag { + results = append(results, jsonResult{ + GOOS: p.GOOS, + GOARCH: p.GOARCH, + CgoSupported: platform.CgoSupported(p.GOOS, p.GOARCH), + FirstClass: platform.FirstClass(p.GOOS, p.GOARCH), + Broken: broken, + }) + } + } + out, err := json.MarshalIndent(results, "", "\t") + if err != nil { + return false + } + + os.Stdout.Write(out) + return true +} diff --git a/src/cmd/go/internal/toolchain/select.go b/src/cmd/go/internal/toolchain/select.go index 8b1a0b94be..a44f393bc0 100644 --- a/src/cmd/go/internal/toolchain/select.go +++ b/src/cmd/go/internal/toolchain/select.go @@ -131,7 +131,7 @@ func Select() { } else { min, suffix, plus := strings.Cut(gotoolchain, "+") // go1.2.3+auto if min != "local" { - v := gover.FromToolchain(gotoolchain) + v := gover.FromToolchain(min) if v == "" { if plus { base.Fatalf("invalid GOTOOLCHAIN %q: invalid minimum toolchain %q", gotoolchain, min) diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index eb05c91f30..13d2a78a97 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -1115,6 +1115,7 @@ type vetConfig struct { PackageVetx map[string]string // map package path to vetx data from earlier vet run VetxOnly bool // only compute vetx data; don't report detected problems VetxOutput string // write vetx data to this output file + GoVersion string // Go version for package SucceedOnTypecheckFailure bool // awful hack; see #18395 and below } @@ -1149,6 +1150,13 @@ func buildVetConfig(a *Action, srcfiles []string) { PackageFile: make(map[string]string), Standard: make(map[string]bool), } + if a.Package.Module != nil { + v := a.Package.Module.GoVersion + if v == "" { + v = gover.DefaultGoModVersion + } + vcfg.GoVersion = "go" + v + } a.vetCfg = vcfg for i, raw := range a.Package.Internal.RawImports { final := a.Package.Imports[i] @@ -3886,7 +3894,7 @@ func useResponseFile(path string, argLen int) bool { // TODO: Note that other toolchains like CC are missing here for now. prog := strings.TrimSuffix(filepath.Base(path), ".exe") switch prog { - case "compile", "link", "cgo", "asm": + case "compile", "link", "cgo", "asm", "cover": default: return false } diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go index 6043ad5353..26b4e0f490 100644 --- a/src/cmd/go/internal/work/gc.go +++ b/src/cmd/go/internal/work/gc.go @@ -85,19 +85,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg if p.Module != nil { v := p.Module.GoVersion if v == "" { - // We started adding a 'go' directive to the go.mod file unconditionally - // as of Go 1.12, so any module that still lacks such a directive must - // either have been authored before then, or have a hand-edited go.mod - // file that hasn't been updated by cmd/go since that edit. - // - // Unfortunately, through at least Go 1.16 we didn't add versions to - // vendor/modules.txt. So this could also be a vendored 1.16 dependency. - // - // Fortunately, there were no breaking changes to the language between Go - // 1.11 and 1.16, so if we assume Go 1.16 semantics we will not introduce - // any spurious errors — we will only mask errors, and not particularly - // important ones at that. - v = "1.16" + v = gover.DefaultGoModVersion } if allowedVersion(v) { defaultGcFlags = append(defaultGcFlags, "-lang=go"+gover.Lang(v)) diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index 00b0a2b78b..2898c68049 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -300,10 +300,10 @@ func maybeStartTrace(pctx context.Context) context.Context { // // We have to handle the -C flag this way for two reasons: // -// 1. Toolchain selection needs to be in the right directory to look for go.mod and go.work. +// 1. Toolchain selection needs to be in the right directory to look for go.mod and go.work. // -// 2. A toolchain switch later on reinvokes the new go command with the same arguments. -// The parent toolchain has already done the chdir; the child must not try to do it again. +// 2. A toolchain switch later on reinvokes the new go command with the same arguments. +// The parent toolchain has already done the chdir; the child must not try to do it again. func handleChdirFlag() { _, used := lookupCmd(os.Args[1:]) used++ // because of [1:] diff --git a/src/cmd/go/testdata/script/build_pgo_auto.txt b/src/cmd/go/testdata/script/build_pgo_auto.txt index bb5b0e4828..5dd799a77f 100644 --- a/src/cmd/go/testdata/script/build_pgo_auto.txt +++ b/src/cmd/go/testdata/script/build_pgo_auto.txt @@ -3,7 +3,7 @@ [short] skip 'compiles and links executables' # use default.pgo for a single main package -go build -a -x -pgo=auto -o a1.exe ./a/a1 +go build -n -pgo=auto -o a1.exe ./a/a1 stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go' # check that pgo applied to dependencies @@ -12,25 +12,22 @@ stderr 'compile.*-p test/dep.*-pgoprofile=.*default\.pgo' # check that pgo appears in build info # N.B. we can't start the stdout check with -pgo because the script assumes that # if the first arg starts with - it is a grep flag. -go version -m a1.exe -stdout 'build\s+-pgo=.*default\.pgo' +stderr 'build\\t-pgo=.*default\.pgo' # use default.pgo for ... with a single main package -go build -a -x -pgo=auto ./a/... +go build -n -pgo=auto ./a/... stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go' # check that pgo appears in build info -go version -m a1$GOEXE -stdout 'build\s+-pgo=.*default\.pgo' +stderr 'build\\t-pgo=.*default\.pgo' # build succeeds without PGO when default.pgo file is absent -go build -a -x -pgo=auto -o nopgo.exe ./nopgo +go build -n -pgo=auto -o nopgo.exe ./nopgo stderr 'compile.*nopgo.go' ! stderr 'compile.*-pgoprofile' # check that pgo doesn't appear in build info -go version -m nopgo.exe -! stdout 'build\s+-pgo=' +! stderr 'build\\t-pgo=' # other build-related commands go install -a -n -pgo=auto ./a/a1 @@ -52,30 +49,27 @@ go list -deps -pgo=auto ./a/a1 # -pgo=auto is the default. Commands without explicit -pgo=auto # should work as -pgo=auto. -go build -a -x -o a1.exe ./a/a1 +go build -a -n -o a1.exe ./a/a1 stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go' stderr 'compile.*-p test/dep.*-pgoprofile=.*default\.pgo' # check that pgo appears in build info -go version -m a1.exe -stdout 'build\s+-pgo=.*default\.pgo' +stderr 'build\\t-pgo=.*default\.pgo' -go build -a -x -o nopgo.exe ./nopgo +go build -a -n -o nopgo.exe ./nopgo stderr 'compile.*nopgo.go' ! stderr 'compile.*-pgoprofile' # check that pgo doesn't appear in build info -go version -m nopgo.exe -! stdout 'build\s+-pgo=' +! stderr 'build\\t-pgo=' # -pgo=off should turn off PGO. -go build -a -x -pgo=off -o a1.exe ./a/a1 +go build -a -n -pgo=off -o a1.exe ./a/a1 stderr 'compile.*a1.go' ! stderr 'compile.*-pgoprofile' # check that pgo doesn't appear in build info -go version -m a1.exe -! stdout 'build\s+-pgo=' +! stderr 'build\\t-pgo=' -- go.mod -- module test diff --git a/src/cmd/go/testdata/script/build_pgo_auto_multi.txt b/src/cmd/go/testdata/script/build_pgo_auto_multi.txt index 66dc9128dc..9ac57ce0c1 100644 --- a/src/cmd/go/testdata/script/build_pgo_auto_multi.txt +++ b/src/cmd/go/testdata/script/build_pgo_auto_multi.txt @@ -1,9 +1,6 @@ # Test go build -pgo=auto flag with multiple main packages. -[short] skip 'compiles and links executables' - -env GOBIN=$WORK/bin -go install -a -x -pgo=auto ./a ./b ./nopgo +go install -a -n -pgo=auto ./a ./b ./nopgo # a/default.pgo applies to package a and (transitive) # dependencies. @@ -36,16 +33,9 @@ stderr -count=3 'compile.*dep3(/|\\\\)dep3.go' stderr -count=2 'compile.*-pgoprofile=.*dep3(/|\\\\)dep3\.go' # check that pgo appears or not in build info as expected -# N.B. we can't start the stdout check with -pgo because the script assumes that -# if the first arg starts with - it is a grep flag. -go version -m $GOBIN/a$GOEXE -stdout 'build\s+-pgo=.*a'${/}'default\.pgo' - -go version -m $GOBIN/b$GOEXE -stdout 'build\s+-pgo=.*b'${/}'default\.pgo' - -go version -m $GOBIN/nopgo$GOEXE -! stdout 'build\s+-pgo=' +stderr 'path\\ttest/a\\n.*build\\t-pgo=.*a(/|\\\\)default\.pgo' +stderr 'path\\ttest/b\\n.*build\\t-pgo=.*b(/|\\\\)default\.pgo' +! stderr 'path\\ttest/nopgo\\n.*build\\t-pgo=' # go test works the same way go test -a -n -pgo=auto ./a ./b ./nopgo diff --git a/src/cmd/go/testdata/script/build_unsupported_goos.txt b/src/cmd/go/testdata/script/build_unsupported_goos.txt index 8c1212934e..c94d6d252e 100644 --- a/src/cmd/go/testdata/script/build_unsupported_goos.txt +++ b/src/cmd/go/testdata/script/build_unsupported_goos.txt @@ -1,6 +1,6 @@ [compiler:gccgo] skip # gccgo assumes cross-compilation is always possible -env GOOS=windwos +env GOOS=windwos # intentional misspelling of windows ! go build -n exclude -stderr 'unsupported GOOS/GOARCH pair'
\ No newline at end of file +stderr 'unsupported GOOS/GOARCH pair' diff --git a/src/cmd/go/testdata/script/dist_list_missing.txt b/src/cmd/go/testdata/script/dist_list_missing.txt new file mode 100644 index 0000000000..affaa009d9 --- /dev/null +++ b/src/cmd/go/testdata/script/dist_list_missing.txt @@ -0,0 +1,57 @@ +# Regression test for #60939: when 'go tool dist' is missing, +# 'go tool dist list' should inject its output. + + +# Set GOROOT to a directory that definitely does not include +# a compiled 'dist' tool. 'go tool dist list' should still +# work, because 'cmd/go' itself can impersonate this command. + +mkdir $WORK/goroot/bin +mkdir $WORK/goroot/pkg/tool/${GOOS}_${GOARCH} +env GOROOT=$WORK/goroot + +! go tool -n dist +stderr 'go: no such tool "dist"' + +go tool dist list +stdout linux/amd64 +cp stdout tool.txt + +go tool dist list -v +stdout linux/amd64 +cp stdout tool-v.txt + +go tool dist list -broken +stdout $GOOS/$GOARCH +cp stdout tool-broken.txt + +go tool dist list -json +stdout '"GOOS": "linux",\n\s*"GOARCH": "amd64",\n' +cp stdout tool-json.txt + +go tool dist list -json -broken +stdout '"GOOS": "'$GOOS'",\n\s*"GOARCH": "'$GOARCH'",\n' +cp stdout tool-json-broken.txt + +[short] stop + + +# Check against the real cmd/dist as the source of truth. + +env GOROOT=$TESTGO_GOROOT +go build -o dist.exe cmd/dist + +exec ./dist.exe list +cmp stdout tool.txt + +exec ./dist.exe list -v +cmp stdout tool-v.txt + +exec ./dist.exe list -broken +cmp stdout tool-broken.txt + +exec ./dist.exe list -json +cmp stdout tool-json.txt + +exec ./dist.exe list -json -broken +cmp stdout tool-json-broken.txt diff --git a/src/cmd/go/testdata/script/gcflags_patterns.txt b/src/cmd/go/testdata/script/gcflags_patterns.txt index 918c32d679..cc7b2fc0ad 100644 --- a/src/cmd/go/testdata/script/gcflags_patterns.txt +++ b/src/cmd/go/testdata/script/gcflags_patterns.txt @@ -3,17 +3,15 @@ env GO111MODULE=off [!compiler:gc] skip 'using -gcflags and -ldflags' [short] skip -env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache. - # -gcflags=-e applies to named packages, not dependencies -go build -n -v -gcflags=-e z1 z2 +go build -a -n -v -gcflags=-e z1 z2 stderr 'compile.* -p z1.* -e ' stderr 'compile.* -p z2.* -e ' stderr 'compile.* -p y' ! stderr 'compile.* -p [^z].* -e ' # -gcflags can specify package=flags, and can be repeated; last match wins -go build -n -v -gcflags=-e -gcflags=z1=-N z1 z2 +go build -a -n -v -gcflags=-e -gcflags=z1=-N z1 z2 stderr 'compile.* -p z1.* -N ' ! stderr 'compile.* -p z1.* -e ' ! stderr 'compile.* -p z2.* -N ' @@ -23,11 +21,11 @@ stderr 'compile.* -p y' ! stderr 'compile.* -p [^z].* -N ' # -gcflags can have arbitrary spaces around the flags -go build -n -v -gcflags=' z1 = -e ' z1 +go build -a -n -v -gcflags=' z1 = -e ' z1 stderr 'compile.* -p z1.* -e ' # -gcflags='all=-e' should apply to all packages, even with go test -go test -c -n -gcflags='all=-e' z1 +go test -a -c -n -gcflags='all=-e' z1 stderr 'compile.* -p z3.* -e ' # this particular -gcflags argument made the compiler crash @@ -39,31 +37,31 @@ stderr 'PhaseOptions usage' stderr 'invalid value' # -ldflags for implicit test package applies to test binary -go test -c -n -gcflags=-N -ldflags=-X=x.y=z z1 +go test -a -c -n -gcflags=-N -ldflags=-X=x.y=z z1 stderr 'compile.* -N .*z_test.go' stderr 'link.* -X=x.y=z' # -ldflags for explicit test package applies to test binary -go test -c -n -gcflags=z1=-N -ldflags=z1=-X=x.y=z z1 +go test -a -c -n -gcflags=z1=-N -ldflags=z1=-X=x.y=z z1 stderr 'compile.* -N .*z_test.go' stderr 'link.* -X=x.y=z' # -ldflags applies to link of command -go build -n -ldflags=-X=math.pi=3 my/cmd/prog +go build -a -n -ldflags=-X=math.pi=3 my/cmd/prog stderr 'link.* -X=math.pi=3' # -ldflags applies to link of command even with strange directory name -go build -n -ldflags=-X=math.pi=3 my/cmd/prog/ +go build -a -n -ldflags=-X=math.pi=3 my/cmd/prog/ stderr 'link.* -X=math.pi=3' # -ldflags applies to current directory cd my/cmd/prog -go build -n -ldflags=-X=math.pi=3 +go build -a -n -ldflags=-X=math.pi=3 stderr 'link.* -X=math.pi=3' # -ldflags applies to current directory even if GOPATH is funny [!case-sensitive] cd $WORK/GoPath/src/my/cmd/prog -go build -n -ldflags=-X=math.pi=3 +go build -a -n -ldflags=-X=math.pi=3 stderr 'link.* -X=math.pi=3' # cgo.a should not be a dependency of internally-linked go package diff --git a/src/cmd/go/testdata/script/gotoolchain_local.txt b/src/cmd/go/testdata/script/gotoolchain_local.txt index 0e08207f45..93f557008a 100644 --- a/src/cmd/go/testdata/script/gotoolchain_local.txt +++ b/src/cmd/go/testdata/script/gotoolchain_local.txt @@ -34,9 +34,9 @@ env GOTOOLCHAIN=go1.600+auto go version stdout go1.600 -env GOTOOLCHAIN=go1.400+auto +env GOTOOLCHAIN=go1.400.0+auto go version -stdout go1.400 +stdout go1.400.0 # GOTOOLCHAIN=version+path sets a minimum too. env GOTOOLCHAIN=go1.600+path diff --git a/src/cmd/go/testdata/script/mod_get_toolchain.txt b/src/cmd/go/testdata/script/mod_get_toolchain.txt index 143ad32a4e..758142d668 100644 --- a/src/cmd/go/testdata/script/mod_get_toolchain.txt +++ b/src/cmd/go/testdata/script/mod_get_toolchain.txt @@ -1,5 +1,5 @@ # setup -env TESTGO_VERSION=go1.99.0 +env TESTGO_VERSION=go1.99rc1 env TESTGO_VERSION_SWITCH=switch # go get go should use the latest Go 1.23 @@ -7,28 +7,28 @@ cp go.mod.orig go.mod go get go stderr '^go: upgraded go 1.21 => 1.23.9$' grep 'go 1.23.9' go.mod -grep 'toolchain go1.99.0' go.mod +grep 'toolchain go1.99rc1' go.mod # go get go@1.23 should use the latest Go 1.23 cp go.mod.orig go.mod go get go@1.23 stderr '^go: upgraded go 1.21 => 1.23.9$' grep 'go 1.23.9' go.mod -grep 'toolchain go1.99.0' go.mod +grep 'toolchain go1.99rc1' go.mod # go get go@1.22 should use the latest Go 1.22 cp go.mod.orig go.mod go get go@1.22 stderr '^go: upgraded go 1.21 => 1.22.9$' grep 'go 1.22.9' go.mod -grep 'toolchain go1.99.0' go.mod +grep 'toolchain go1.99rc1' go.mod # go get go@patch should use the latest patch release go get go@1.22.1 go get go@patch stderr '^go: upgraded go 1.22.1 => 1.22.9$' grep 'go 1.22.9' go.mod -grep 'toolchain go1.99.0' go.mod +grep 'toolchain go1.99rc1' go.mod # go get go@1.24 does NOT find the release candidate cp go.mod.orig go.mod @@ -40,20 +40,20 @@ cp go.mod.orig go.mod go get go@1.24rc1 stderr '^go: upgraded go 1.21 => 1.24rc1$' grep 'go 1.24rc1' go.mod -grep 'toolchain go1.99.0' go.mod +grep 'toolchain go1.99rc1' go.mod # go get go@latest finds the latest Go 1.23 cp go.mod.orig go.mod go get go@latest stderr '^go: upgraded go 1.21 => 1.23.9$' grep 'go 1.23.9' go.mod -grep 'toolchain go1.99.0' go.mod +grep 'toolchain go1.99rc1' go.mod # Again, with toolchains. # go get toolchain should find go1.999testmod. go get toolchain -stderr '^go: upgraded toolchain go1.99.0 => go1.999testmod$' +stderr '^go: upgraded toolchain go1.99rc1 => go1.999testmod$' grep 'go 1.23.9' go.mod grep 'toolchain go1.999testmod' go.mod @@ -96,6 +96,33 @@ stderr '^go: added toolchain go1.999testmod$' grep 'go 1.21' go.mod grep 'toolchain go1.999testmod' go.mod +# Bug fixes. + +# go get go@garbage should fail but not crash +! go get go@garbage +! stderr panic +stderr '^go: invalid go version garbage$' + +# go get go@go1.21.0 is OK - we silently correct to 1.21.0 +go get go@1.19 +go get go@go1.21.0 +stderr '^go: upgraded go 1.19 => 1.21.0' + +# go get toolchain@1.24rc1 is OK too. +go get toolchain@1.24rc1 +stderr '^go: downgraded toolchain go1.999testmod => go1.24rc1$' + +# go get go@1.21 should work if we are the Go 1.21 language version, +# even though there's no toolchain for it. +# (Older versions resolve to the latest release in that version, so for example +# go get go@1.20 might resolve to 1.20.9, but if we're the devel copy of +# Go 1.21, there's no release yet to resolve to, so we resolve to ourselves.) +env TESTGO_VERSION=go1.21 +go get go@1.19 toolchain@none +go get go@1.21 +grep 'go 1.21$' go.mod +! grep toolchain go.mod + -- go.mod.orig -- module m diff --git a/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt b/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt index 896bbab9fc..195f7b1527 100644 --- a/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt +++ b/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt @@ -5,33 +5,12 @@ env GO111MODULE=on # Regression test for golang.org/issue/29667: # spurious 'failed to cache compiled Go files' errors. -# This test failed reliably when run with -count=10 -# on a Linux workstation. env GOCACHE=$WORK/gocache mkdir $GOCACHE go list -json -compiled -test=false -export=false -deps=true -- . & go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & -go list -json -compiled -test=false -export=false -deps=true -- . & - wait -- go.mod -- diff --git a/src/cmd/go/testdata/script/vet_flags.txt b/src/cmd/go/testdata/script/vet_flags.txt index 1c130b579e..73f4e4135b 100644 --- a/src/cmd/go/testdata/script/vet_flags.txt +++ b/src/cmd/go/testdata/script/vet_flags.txt @@ -52,27 +52,25 @@ env GOFLAGS='-unsafeptr' stderr 'go: parsing \$GOFLAGS: unknown flag -unsafeptr' env GOFLAGS= -env GOCACHE=$WORK/gocache - # "go test" on a user package should by default enable an explicit list of analyzers. -go test -x -run=none . +go test -n -run=none . stderr '[/\\]vet'$GOEXE'["]? .* -errorsas .* ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' # An explicitly-empty -vet argument should imply the default analyzers. -go test -x -vet= -run=none . +go test -n -vet= -run=none . stderr '[/\\]vet'$GOEXE'["]? .* -errorsas .* ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' # "go test" on a standard package should by default disable an explicit list. -go test -x -run=none encoding/binary +go test -n -run=none encoding/binary stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' -go test -x -vet= -run=none encoding/binary +go test -n -vet= -run=none encoding/binary stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' # Both should allow users to override via the -vet flag. -go test -x -vet=unreachable -run=none . +go test -n -vet=unreachable -run=none . stderr '[/\\]vet'$GOEXE'["]? -unreachable ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' -go test -x -vet=unreachable -run=none encoding/binary +go test -n -vet=unreachable -run=none encoding/binary stderr '[/\\]vet'$GOEXE'["]? -unreachable ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' -- go.mod -- diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go index de417946a4..9e866d87b6 100644 --- a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go +++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go @@ -83,6 +83,12 @@ func GoSyntax(inst Inst, pc uint64, symname SymLookup) string { } } + if inst.Op == CMP { + // Use reads-left-to-right ordering for comparisons. + // See issue 60920. + args[0], args[1] = args[1], args[0] + } + if args != nil { op += " " + strings.Join(args, ", ") } diff --git a/src/cmd/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go b/src/cmd/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go index 2681af35af..150f887e7a 100644 --- a/src/cmd/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go +++ b/src/cmd/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go @@ -13,7 +13,7 @@ import ( "sync" ) -// Regexp is a wrapper around regexp.Regexp, where the underlying regexp will be +// Regexp is a wrapper around [regexp.Regexp], where the underlying regexp will be // compiled the first time it is needed. type Regexp struct { str string diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/read.go b/src/cmd/vendor/golang.org/x/mod/modfile/read.go index a503bc2105..5b5bb5e115 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/read.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/read.go @@ -65,7 +65,7 @@ type Comments struct { } // Comment returns the receiver. This isn't useful by itself, but -// a Comments struct is embedded into all the expression +// a [Comments] struct is embedded into all the expression // implementation types, and this gives each of those a Comment // method to satisfy the Expr interface. func (c *Comments) Comment() *Comments { diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go index b4dd7997b6..930b6c59bc 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go @@ -5,17 +5,17 @@ // Package modfile implements a parser and formatter for go.mod files. // // The go.mod syntax is described in -// https://golang.org/cmd/go/#hdr-The_go_mod_file. +// https://pkg.go.dev/cmd/go/#hdr-The_go_mod_file. // -// The Parse and ParseLax functions both parse a go.mod file and return an +// The [Parse] and [ParseLax] functions both parse a go.mod file and return an // abstract syntax tree. ParseLax ignores unknown statements and may be used to // parse go.mod files that may have been developed with newer versions of Go. // -// The File struct returned by Parse and ParseLax represent an abstract -// go.mod file. File has several methods like AddNewRequire and DropReplace -// that can be used to programmatically edit a file. +// The [File] struct returned by Parse and ParseLax represent an abstract +// go.mod file. File has several methods like [File.AddNewRequire] and +// [File.DropReplace] that can be used to programmatically edit a file. // -// The Format function formats a File back to a byte slice which can be +// The [Format] function formats a File back to a byte slice which can be // written to a file. package modfile @@ -226,7 +226,7 @@ var dontFixRetract VersionFixer = func(_, vers string) (string, error) { // data is the content of the file. // // fix is an optional function that canonicalizes module versions. -// If fix is nil, all module versions must be canonical (module.CanonicalVersion +// If fix is nil, all module versions must be canonical ([module.CanonicalVersion] // must return the same string). func Parse(file string, data []byte, fix VersionFixer) (*File, error) { return parseToFile(file, data, fix, true) @@ -923,7 +923,7 @@ func (f *File) Format() ([]byte, error) { } // Cleanup cleans up the file f after any edit operations. -// To avoid quadratic behavior, modifications like DropRequire +// To avoid quadratic behavior, modifications like [File.DropRequire] // clear the entry but do not remove it from the slice. // Cleanup cleans out all the cleared entries. func (f *File) Cleanup() { @@ -1075,8 +1075,8 @@ func (f *File) AddNewRequire(path, vers string, indirect bool) { // The requirements in req must specify at most one distinct version for each // module path. // -// If any existing requirements may be removed, the caller should call Cleanup -// after all edits are complete. +// If any existing requirements may be removed, the caller should call +// [File.Cleanup] after all edits are complete. func (f *File) SetRequire(req []*Require) { type elem struct { version string diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/work.go b/src/cmd/vendor/golang.org/x/mod/modfile/work.go index 75dc1c5491..d7b99376eb 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/work.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/work.go @@ -34,7 +34,7 @@ type Use struct { // data is the content of the file. // // fix is an optional function that canonicalizes module versions. -// If fix is nil, all module versions must be canonical (module.CanonicalVersion +// If fix is nil, all module versions must be canonical ([module.CanonicalVersion] // must return the same string). func ParseWork(file string, data []byte, fix VersionFixer) (*WorkFile, error) { fs, err := parse(file, data) @@ -83,7 +83,7 @@ func ParseWork(file string, data []byte, fix VersionFixer) (*WorkFile, error) { } // Cleanup cleans up the file f after any edit operations. -// To avoid quadratic behavior, modifications like DropRequire +// To avoid quadratic behavior, modifications like [WorkFile.DropRequire] // clear the entry but do not remove it from the slice. // Cleanup cleans out all the cleared entries. func (f *WorkFile) Cleanup() { diff --git a/src/cmd/vendor/golang.org/x/mod/module/module.go b/src/cmd/vendor/golang.org/x/mod/module/module.go index e9dec6e614..2a364b229b 100644 --- a/src/cmd/vendor/golang.org/x/mod/module/module.go +++ b/src/cmd/vendor/golang.org/x/mod/module/module.go @@ -4,7 +4,7 @@ // Package module defines the module.Version type along with support code. // -// The module.Version type is a simple Path, Version pair: +// The [module.Version] type is a simple Path, Version pair: // // type Version struct { // Path string @@ -12,7 +12,7 @@ // } // // There are no restrictions imposed directly by use of this structure, -// but additional checking functions, most notably Check, verify that +// but additional checking functions, most notably [Check], verify that // a particular path, version pair is valid. // // # Escaped Paths @@ -140,7 +140,7 @@ type ModuleError struct { Err error } -// VersionError returns a ModuleError derived from a Version and error, +// VersionError returns a [ModuleError] derived from a [Version] and error, // or err itself if it is already such an error. func VersionError(v Version, err error) error { var mErr *ModuleError @@ -169,7 +169,7 @@ func (e *ModuleError) Unwrap() error { return e.Err } // An InvalidVersionError indicates an error specific to a version, with the // module path unknown or specified externally. // -// A ModuleError may wrap an InvalidVersionError, but an InvalidVersionError +// A [ModuleError] may wrap an InvalidVersionError, but an InvalidVersionError // must not wrap a ModuleError. type InvalidVersionError struct { Version string @@ -193,8 +193,8 @@ func (e *InvalidVersionError) Error() string { func (e *InvalidVersionError) Unwrap() error { return e.Err } // An InvalidPathError indicates a module, import, or file path doesn't -// satisfy all naming constraints. See CheckPath, CheckImportPath, -// and CheckFilePath for specific restrictions. +// satisfy all naming constraints. See [CheckPath], [CheckImportPath], +// and [CheckFilePath] for specific restrictions. type InvalidPathError struct { Kind string // "module", "import", or "file" Path string @@ -294,7 +294,7 @@ func fileNameOK(r rune) bool { } // CheckPath checks that a module path is valid. -// A valid module path is a valid import path, as checked by CheckImportPath, +// A valid module path is a valid import path, as checked by [CheckImportPath], // with three additional constraints. // First, the leading path element (up to the first slash, if any), // by convention a domain name, must contain only lower-case ASCII letters, @@ -380,7 +380,7 @@ const ( // checkPath returns an error describing why the path is not valid. // Because these checks apply to module, import, and file paths, // and because other checks may be applied, the caller is expected to wrap -// this error with InvalidPathError. +// this error with [InvalidPathError]. func checkPath(path string, kind pathKind) error { if !utf8.ValidString(path) { return fmt.Errorf("invalid UTF-8") @@ -532,7 +532,7 @@ var badWindowsNames = []string{ // they require ".vN" instead of "/vN", and for all N, not just N >= 2. // SplitPathVersion returns with ok = false when presented with // a path whose last path element does not satisfy the constraints -// applied by CheckPath, such as "example.com/pkg/v1" or "example.com/pkg/v1.2". +// applied by [CheckPath], such as "example.com/pkg/v1" or "example.com/pkg/v1.2". func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) { if strings.HasPrefix(path, "gopkg.in/") { return splitGopkgIn(path) @@ -582,7 +582,7 @@ func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) { // MatchPathMajor reports whether the semantic version v // matches the path major version pathMajor. // -// MatchPathMajor returns true if and only if CheckPathMajor returns nil. +// MatchPathMajor returns true if and only if [CheckPathMajor] returns nil. func MatchPathMajor(v, pathMajor string) bool { return CheckPathMajor(v, pathMajor) == nil } @@ -622,7 +622,7 @@ func CheckPathMajor(v, pathMajor string) error { // PathMajorPrefix returns the major-version tag prefix implied by pathMajor. // An empty PathMajorPrefix allows either v0 or v1. // -// Note that MatchPathMajor may accept some versions that do not actually begin +// Note that [MatchPathMajor] may accept some versions that do not actually begin // with this prefix: namely, it accepts a 'v0.0.0-' prefix for a '.v1' // pathMajor, even though that pathMajor implies 'v1' tagging. func PathMajorPrefix(pathMajor string) string { @@ -643,7 +643,7 @@ func PathMajorPrefix(pathMajor string) string { } // CanonicalVersion returns the canonical form of the version string v. -// It is the same as semver.Canonical(v) except that it preserves the special build suffix "+incompatible". +// It is the same as [semver.Canonical] except that it preserves the special build suffix "+incompatible". func CanonicalVersion(v string) string { cv := semver.Canonical(v) if semver.Build(v) == "+incompatible" { @@ -652,8 +652,8 @@ func CanonicalVersion(v string) string { return cv } -// Sort sorts the list by Path, breaking ties by comparing Version fields. -// The Version fields are interpreted as semantic versions (using semver.Compare) +// Sort sorts the list by Path, breaking ties by comparing [Version] fields. +// The Version fields are interpreted as semantic versions (using [semver.Compare]) // optionally followed by a tie-breaking suffix introduced by a slash character, // like in "v0.0.1/go.mod". func Sort(list []Version) { @@ -793,7 +793,7 @@ func unescapeString(escaped string) (string, bool) { } // MatchPrefixPatterns reports whether any path prefix of target matches one of -// the glob patterns (as defined by path.Match) in the comma-separated globs +// the glob patterns (as defined by [path.Match]) in the comma-separated globs // list. This implements the algorithm used when matching a module path to the // GOPRIVATE environment variable, as described by 'go help module-private'. // diff --git a/src/cmd/vendor/golang.org/x/mod/module/pseudo.go b/src/cmd/vendor/golang.org/x/mod/module/pseudo.go index f04ad37886..9cf19d3254 100644 --- a/src/cmd/vendor/golang.org/x/mod/module/pseudo.go +++ b/src/cmd/vendor/golang.org/x/mod/module/pseudo.go @@ -125,7 +125,7 @@ func IsPseudoVersion(v string) bool { } // IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base, -// timestamp, and revision, as returned by ZeroPseudoVersion. +// timestamp, and revision, as returned by [ZeroPseudoVersion]. func IsZeroPseudoVersion(v string) bool { return v == ZeroPseudoVersion(semver.Major(v)) } 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 a30a22bf20..9a2dfd33a7 100644 --- a/src/cmd/vendor/golang.org/x/mod/semver/semver.go +++ b/src/cmd/vendor/golang.org/x/mod/semver/semver.go @@ -140,7 +140,7 @@ 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 +// 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) @@ -151,7 +151,7 @@ func Max(v, w string) string { return w } -// ByVersion implements sort.Interface for sorting semantic version strings. +// ByVersion implements [sort.Interface] for sorting semantic version strings. type ByVersion []string func (vs ByVersion) Len() int { return len(vs) } @@ -164,7 +164,7 @@ func (vs ByVersion) Less(i, j int) bool { return vs[i] < vs[j] } -// Sort sorts a list of semantic version strings using ByVersion. +// Sort sorts a list of semantic version strings using [ByVersion]. func Sort(list []string) { sort.Sort(ByVersion(list)) } diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/client.go b/src/cmd/vendor/golang.org/x/mod/sumdb/client.go index 1c1b0297f0..aecdc68849 100644 --- a/src/cmd/vendor/golang.org/x/mod/sumdb/client.go +++ b/src/cmd/vendor/golang.org/x/mod/sumdb/client.go @@ -19,7 +19,7 @@ import ( ) // A ClientOps provides the external operations -// (file caching, HTTP fetches, and so on) needed by the Client. +// (file caching, HTTP fetches, and so on) needed by the [Client]. // The methods must be safe for concurrent use by multiple goroutines. type ClientOps interface { // ReadRemote reads and returns the content served at the given path @@ -72,7 +72,7 @@ type ClientOps interface { // ErrWriteConflict signals a write conflict during Client.WriteConfig. var ErrWriteConflict = errors.New("write conflict") -// ErrSecurity is returned by Client operations that invoke Client.SecurityError. +// ErrSecurity is returned by [Client] operations that invoke Client.SecurityError. var ErrSecurity = errors.New("security error: misbehaving server") // A Client is a client connection to a checksum database. @@ -102,7 +102,7 @@ type Client struct { tileSaved map[tlog.Tile]bool // which tiles have been saved using c.ops.WriteCache already } -// NewClient returns a new Client using the given Client. +// NewClient returns a new [Client] using the given [ClientOps]. func NewClient(ops ClientOps) *Client { return &Client{ ops: ops, @@ -155,7 +155,7 @@ func (c *Client) initWork() { } // SetTileHeight sets the tile height for the Client. -// Any call to SetTileHeight must happen before the first call to Lookup. +// Any call to SetTileHeight must happen before the first call to [Client.Lookup]. // If SetTileHeight is not called, the Client defaults to tile height 8. // SetTileHeight can be called at most once, // and if so it must be called before the first call to Lookup. @@ -174,7 +174,7 @@ func (c *Client) SetTileHeight(height int) { // SetGONOSUMDB sets the list of comma-separated GONOSUMDB patterns for the Client. // For any module path matching one of the patterns, -// Lookup will return ErrGONOSUMDB. +// [Client.Lookup] will return ErrGONOSUMDB. // SetGONOSUMDB can be called at most once, // and if so it must be called before the first call to Lookup. func (c *Client) SetGONOSUMDB(list string) { @@ -187,8 +187,8 @@ func (c *Client) SetGONOSUMDB(list string) { c.nosumdb = list } -// ErrGONOSUMDB is returned by Lookup for paths that match -// a pattern listed in the GONOSUMDB list (set by SetGONOSUMDB, +// ErrGONOSUMDB is returned by [Client.Lookup] for paths that match +// a pattern listed in the GONOSUMDB list (set by [Client.SetGONOSUMDB], // usually from the environment variable). var ErrGONOSUMDB = errors.New("skipped (listed in GONOSUMDB)") diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go b/src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go index 8c22b19d31..db9865c317 100644 --- a/src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go +++ b/src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go @@ -20,45 +20,45 @@ // // # Verifying Notes // -// A Verifier allows verification of signatures by one server public key. +// A [Verifier] allows verification of signatures by one server public key. // It can report the name of the server and the uint32 hash of the key, // and it can verify a purported signature by that key. // // The standard implementation of a Verifier is constructed -// by NewVerifier starting from a verifier key, which is a +// by [NewVerifier] starting from a verifier key, which is a // plain text string of the form "<name>+<hash>+<keydata>". // -// A Verifiers allows looking up a Verifier by the combination +// A [Verifiers] allows looking up a Verifier by the combination // of server name and key hash. // // The standard implementation of a Verifiers is constructed // by VerifierList from a list of known verifiers. // -// A Note represents a text with one or more signatures. +// A [Note] represents a text with one or more signatures. // An implementation can reject a note with too many signatures // (for example, more than 100 signatures). // -// A Signature represents a signature on a note, verified or not. +// A [Signature] represents a signature on a note, verified or not. // -// The Open function takes as input a signed message +// The [Open] function takes as input a signed message // and a set of known verifiers. It decodes and verifies -// the message signatures and returns a Note structure +// the message signatures and returns a [Note] structure // containing the message text and (verified or unverified) signatures. // // # Signing Notes // -// A Signer allows signing a text with a given key. +// A [Signer] allows signing a text with a given key. // It can report the name of the server and the hash of the key // and can sign a raw text using that key. // // The standard implementation of a Signer is constructed -// by NewSigner starting from an encoded signer key, which is a +// by [NewSigner] starting from an encoded signer key, which is a // plain text string of the form "PRIVATE+KEY+<name>+<hash>+<keydata>". // Anyone with an encoded signer key can sign messages using that key, // so it must be kept secret. The encoding begins with the literal text // "PRIVATE+KEY" to avoid confusion with the public server key. // -// The Sign function takes as input a Note and a list of Signers +// The [Sign] function takes as input a Note and a list of Signers // and returns an encoded, signed message. // // # Signed Note Format @@ -88,7 +88,7 @@ // although doing so will require deploying the new algorithms to all clients // before starting to depend on them for signatures. // -// The GenerateKey function generates and returns a new signer +// The [GenerateKey] function generates and returns a new signer // and corresponding verifier. // // # Example @@ -123,9 +123,9 @@ // base URLs, the only syntactic requirement is that they // not contain spaces or newlines). // -// If Open is given access to a Verifiers including the -// Verifier for this key, then it will succeed at verifying -// the encoded message and returning the parsed Note: +// If [Open] is given access to a [Verifiers] including the +// [Verifier] for this key, then it will succeed at verifying +// the encoded message and returning the parsed [Note]: // // vkey := "PeterNeumann+c74f20a3+ARpc2QcUPDhMQegwxbzhKqiBfsVkmqq/LDE4izWy10TW" // msg := []byte("If you think cryptography is the answer to your problem,\n" + @@ -238,7 +238,7 @@ func isValidName(name string) bool { return name != "" && utf8.ValidString(name) && strings.IndexFunc(name, unicode.IsSpace) < 0 && !strings.Contains(name, "+") } -// NewVerifier construct a new Verifier from an encoded verifier key. +// NewVerifier construct a new [Verifier] from an encoded verifier key. func NewVerifier(vkey string) (Verifier, error) { name, vkey := chop(vkey, "+") hash16, key64 := chop(vkey, "+") @@ -295,7 +295,7 @@ func (v *verifier) Name() string { return v.name } func (v *verifier) KeyHash() uint32 { return v.hash } func (v *verifier) Verify(msg, sig []byte) bool { return v.verify(msg, sig) } -// NewSigner constructs a new Signer from an encoded signer key. +// NewSigner constructs a new [Signer] from an encoded signer key. func NewSigner(skey string) (Signer, error) { priv1, skey := chop(skey, "+") priv2, skey := chop(skey, "+") @@ -409,7 +409,7 @@ func (e *UnknownVerifierError) Error() string { } // An ambiguousVerifierError indicates that the given name and hash -// match multiple keys passed to VerifierList. +// match multiple keys passed to [VerifierList]. // (If this happens, some malicious actor has taken control of the // verifier list, at which point we may as well give up entirely, // but we diagnose the problem instead.) @@ -422,7 +422,7 @@ func (e *ambiguousVerifierError) Error() string { return fmt.Sprintf("ambiguous key %s+%08x", e.name, e.hash) } -// VerifierList returns a Verifiers implementation that uses the given list of verifiers. +// VerifierList returns a [Verifiers] implementation that uses the given list of verifiers. func VerifierList(list ...Verifier) Verifiers { m := make(verifierMap) for _, v := range list { @@ -510,7 +510,7 @@ var ( // If known.Verifier returns any other error, Open returns that error. // // If no known verifier has signed an otherwise valid note, -// Open returns an UnverifiedNoteError. +// Open returns an [UnverifiedNoteError]. // In this case, the unverified note can be fetched from inside the error. func Open(msg []byte, known Verifiers) (*Note, error) { if known == nil { diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/server.go b/src/cmd/vendor/golang.org/x/mod/sumdb/server.go index 899bd462bc..1e1779d025 100644 --- a/src/cmd/vendor/golang.org/x/mod/sumdb/server.go +++ b/src/cmd/vendor/golang.org/x/mod/sumdb/server.go @@ -17,7 +17,7 @@ import ( ) // A ServerOps provides the external operations -// (underlying database access and so on) needed by the Server. +// (underlying database access and so on) needed by the [Server]. type ServerOps interface { // Signed returns the signed hash of the latest tree. Signed(ctx context.Context) ([]byte, error) @@ -36,7 +36,7 @@ type ServerOps interface { // A Server is the checksum database HTTP server, // which implements http.Handler and should be invoked -// to serve the paths listed in ServerPaths. +// to serve the paths listed in [ServerPaths]. type Server struct { ops ServerOps } diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/test.go b/src/cmd/vendor/golang.org/x/mod/sumdb/test.go index c2755b8495..fb772452d9 100644 --- a/src/cmd/vendor/golang.org/x/mod/sumdb/test.go +++ b/src/cmd/vendor/golang.org/x/mod/sumdb/test.go @@ -14,15 +14,15 @@ import ( "golang.org/x/mod/sumdb/tlog" ) -// NewTestServer constructs a new TestServer +// NewTestServer constructs a new [TestServer] // that will sign its tree with the given signer key -// (see golang.org/x/mod/sumdb/note) +// (see [golang.org/x/mod/sumdb/note]) // and fetch new records as needed by calling gosum. func NewTestServer(signer string, gosum func(path, vers string) ([]byte, error)) *TestServer { return &TestServer{signer: signer, gosum: gosum} } -// A TestServer is an in-memory implementation of Server for testing. +// A TestServer is an in-memory implementation of [ServerOps] for testing. type TestServer struct { signer string gosum func(path, vers string) ([]byte, error) diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tile.go b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tile.go index e4aeb14eff..857d487551 100644 --- a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tile.go +++ b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tile.go @@ -28,7 +28,7 @@ import ( // is tile/3/4/x001/x234/067.p/1, and // Tile{H: 3, L: 4, N: 1234067, W: 8}'s path // is tile/3/4/x001/x234/067. -// See Tile's Path method and the ParseTilePath function. +// See the [Tile.Path] method and the [ParseTilePath] function. // // The special level L=-1 holds raw record data instead of hashes. // In this case, the level encodes into a tile path as the path element @@ -46,7 +46,7 @@ type Tile struct { // TileForIndex returns the tile of fixed height h ≥ 1 // and least width storing the given hash storage index. // -// If h ≤ 0, TileForIndex panics. +// If h ≤ 0, [TileForIndex] panics. func TileForIndex(h int, index int64) Tile { if h <= 0 { panic(fmt.Sprintf("TileForIndex: invalid height %d", h)) @@ -105,7 +105,7 @@ func tileHash(data []byte) Hash { // size newTreeSize to replace a tree of size oldTreeSize. // (No tiles need to be published for a tree of size zero.) // -// If h ≤ 0, TileForIndex panics. +// If h ≤ 0, NewTiles panics. func NewTiles(h int, oldTreeSize, newTreeSize int64) []Tile { if h <= 0 { panic(fmt.Sprintf("NewTiles: invalid height %d", h)) @@ -272,7 +272,7 @@ type TileReader interface { // TileHashReader returns a HashReader that satisfies requests // by loading tiles of the given tree. // -// The returned HashReader checks that loaded tiles are +// The returned [HashReader] checks that loaded tiles are // valid for the given tree. Therefore, any hashes returned // by the HashReader are already proven to be in the tree. func TileHashReader(tree Tree, tr TileReader) HashReader { diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go index ae065f8557..6a11a752f9 100644 --- a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go +++ b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go @@ -131,7 +131,7 @@ func StoredHashIndex(level int, n int64) int64 { return i + int64(level) } -// SplitStoredHashIndex is the inverse of StoredHashIndex. +// SplitStoredHashIndex is the inverse of [StoredHashIndex]. // That is, SplitStoredHashIndex(StoredHashIndex(level, n)) == level, n. func SplitStoredHashIndex(index int64) (level int, n int64) { // Determine level 0 record before index. @@ -183,7 +183,7 @@ func StoredHashes(n int64, data []byte, r HashReader) ([]Hash, error) { return StoredHashesForRecordHash(n, RecordHash(data), r) } -// StoredHashesForRecordHash is like StoredHashes but takes +// StoredHashesForRecordHash is like [StoredHashes] but takes // as its second argument RecordHash(data) instead of data itself. func StoredHashesForRecordHash(n int64, h Hash, r HashReader) ([]Hash, error) { // Start with the record hash. @@ -227,7 +227,7 @@ type HashReader interface { ReadHashes(indexes []int64) ([]Hash, error) } -// A HashReaderFunc is a function implementing HashReader. +// A HashReaderFunc is a function implementing [HashReader]. type HashReaderFunc func([]int64) ([]Hash, error) func (f HashReaderFunc) ReadHashes(indexes []int64) ([]Hash, error) { diff --git a/src/cmd/vendor/golang.org/x/mod/zip/zip.go b/src/cmd/vendor/golang.org/x/mod/zip/zip.go index 7b48a2a2f0..574f83f220 100644 --- a/src/cmd/vendor/golang.org/x/mod/zip/zip.go +++ b/src/cmd/vendor/golang.org/x/mod/zip/zip.go @@ -10,31 +10,31 @@ // // • All file paths within a zip file must start with "<module>@<version>/", // where "<module>" is the module path and "<version>" is the version. -// The module path must be valid (see golang.org/x/mod/module.CheckPath). +// The module path must be valid (see [golang.org/x/mod/module.CheckPath]). // The version must be valid and canonical (see -// golang.org/x/mod/module.CanonicalVersion). The path must have a major +// [golang.org/x/mod/module.CanonicalVersion]). The path must have a major // version suffix consistent with the version (see -// golang.org/x/mod/module.Check). The part of the file path after the +// [golang.org/x/mod/module.Check]). The part of the file path after the // "<module>@<version>/" prefix must be valid (see -// golang.org/x/mod/module.CheckFilePath). +// [golang.org/x/mod/module.CheckFilePath]). // // • No two file paths may be equal under Unicode case-folding (see -// strings.EqualFold). +// [strings.EqualFold]). // // • A go.mod file may or may not appear in the top-level directory. If present, // it must be named "go.mod", not any other case. Files named "go.mod" // are not allowed in any other directory. // -// • The total size in bytes of a module zip file may be at most MaxZipFile +// • The total size in bytes of a module zip file may be at most [MaxZipFile] // bytes (500 MiB). The total uncompressed size of the files within the -// zip may also be at most MaxZipFile bytes. +// zip may also be at most [MaxZipFile] bytes. // // • Each file's uncompressed size must match its declared 64-bit uncompressed // size in the zip file header. // // • If the zip contains files named "<module>@<version>/go.mod" or // "<module>@<version>/LICENSE", their sizes in bytes may be at most -// MaxGoMod or MaxLICENSE, respectively (both are 16 MiB). +// [MaxGoMod] or [MaxLICENSE], respectively (both are 16 MiB). // // • Empty directories are ignored. File permissions and timestamps are also // ignored. @@ -42,7 +42,7 @@ // • Symbolic links and other irregular files are not allowed. // // Note that this package does not provide hashing functionality. See -// golang.org/x/mod/sumdb/dirhash. +// [golang.org/x/mod/sumdb/dirhash]. package zip import ( @@ -56,6 +56,7 @@ import ( "path" "path/filepath" "strings" + "time" "unicode" "unicode/utf8" @@ -117,8 +118,9 @@ type CheckedFiles struct { SizeError error } -// Err returns an error if CheckedFiles does not describe a valid module zip -// file. SizeError is returned if that field is set. A FileErrorList is returned +// Err returns an error if [CheckedFiles] does not describe a valid module zip +// file. [CheckedFiles.SizeError] is returned if that field is set. +// A [FileErrorList] is returned // if there are one or more invalid files. Other errors may be returned in the // future. func (cf CheckedFiles) Err() error { @@ -321,17 +323,17 @@ func checkFiles(files []File) (cf CheckedFiles, validFiles []File, validSizes [] } // CheckDir reports whether the files in dir satisfy the name and size -// constraints listed in the package documentation. The returned CheckedFiles +// constraints listed in the package documentation. The returned [CheckedFiles] // record contains lists of valid, invalid, and omitted files. If a directory is // omitted (for example, a nested module or vendor directory), it will appear in // the omitted list, but its files won't be listed. // // CheckDir returns an error if it encounters an I/O error or if the returned -// CheckedFiles does not describe a valid module zip file (according to -// CheckedFiles.Err). The returned CheckedFiles is still populated when such +// [CheckedFiles] does not describe a valid module zip file (according to +// [CheckedFiles.Err]). The returned [CheckedFiles] is still populated when such // an error is returned. // -// Note that CheckDir will not open any files, so CreateFromDir may still fail +// Note that CheckDir will not open any files, so [CreateFromDir] may still fail // when CheckDir is successful due to I/O errors. func CheckDir(dir string) (CheckedFiles, error) { // List files (as CreateFromDir would) and check which ones are omitted @@ -362,13 +364,13 @@ func CheckDir(dir string) (CheckedFiles, error) { // CheckZip reports whether the files contained in a zip file satisfy the name // and size constraints listed in the package documentation. // -// CheckZip returns an error if the returned CheckedFiles does not describe -// a valid module zip file (according to CheckedFiles.Err). The returned +// CheckZip returns an error if the returned [CheckedFiles] does not describe +// a valid module zip file (according to [CheckedFiles.Err]). The returned // CheckedFiles is still populated when an error is returned. CheckZip will // also return an error if the module path or version is malformed or if it // encounters an error reading the zip file. // -// Note that CheckZip does not read individual files, so Unzip may still fail +// Note that CheckZip does not read individual files, so [Unzip] may still fail // when CheckZip is successful due to I/O errors. func CheckZip(m module.Version, zipFile string) (CheckedFiles, error) { f, err := os.Open(zipFile) @@ -476,7 +478,7 @@ func checkZip(m module.Version, f *os.File) (*zip.Reader, CheckedFiles, error) { // and writes it to w. // // Create verifies the restrictions described in the package documentation -// and should not produce an archive that Unzip cannot extract. Create does not +// and should not produce an archive that [Unzip] cannot extract. Create does not // include files in the output archive if they don't belong in the module zip. // In particular, Create will not include files in modules found in // subdirectories, most files in vendor directories, or irregular files (such @@ -543,12 +545,12 @@ func Create(w io.Writer, m module.Version, files []File) (err error) { // a directory, dir. The zip content is written to w. // // CreateFromDir verifies the restrictions described in the package -// documentation and should not produce an archive that Unzip cannot extract. +// documentation and should not produce an archive that [Unzip] cannot extract. // CreateFromDir does not include files in the output archive if they don't // belong in the module zip. In particular, CreateFromDir will not include // files in modules found in subdirectories, most files in vendor directories, // or irregular files (such as symbolic links) in the output archive. -// Additionally, unlike Create, CreateFromDir will not include directories +// Additionally, unlike [Create], CreateFromDir will not include directories // named ".bzr", ".git", ".hg", or ".svn". func CreateFromDir(w io.Writer, m module.Version, dir string) (err error) { defer func() { @@ -580,8 +582,8 @@ func CreateFromDir(w io.Writer, m module.Version, dir string) (err error) { // "sub/dir". To create a zip from the base of the repository, pass an empty // string. // -// If CreateFromVCS returns ErrUnrecognizedVCS, consider falling back to -// CreateFromDir. +// If CreateFromVCS returns [UnrecognizedVCSError], consider falling back to +// [CreateFromDir]. func CreateFromVCS(w io.Writer, m module.Version, repoRoot, revision, subdir string) (err error) { defer func() { if zerr, ok := err.(*zipError); ok { @@ -653,6 +655,7 @@ func filesInGitRepo(dir, rev, subdir string) ([]File, error) { return nil, err } + haveLICENSE := false var fs []File for _, zf := range zipReader.File { if !strings.HasPrefix(zf.Name, subdir) || strings.HasSuffix(zf.Name, "/") { @@ -669,6 +672,23 @@ func filesInGitRepo(dir, rev, subdir string) ([]File, error) { name: n, f: zf, }) + if n == "LICENSE" { + haveLICENSE = true + } + } + + if !haveLICENSE && subdir != "" { + // Note: this method of extracting the license from the root copied from + // https://go.googlesource.com/go/+/refs/tags/go1.20.4/src/cmd/go/internal/modfetch/coderepo.go#1118 + // https://go.googlesource.com/go/+/refs/tags/go1.20.4/src/cmd/go/internal/modfetch/codehost/git.go#657 + cmd := exec.Command("git", "cat-file", "blob", rev+":LICENSE") + cmd.Dir = dir + cmd.Env = append(os.Environ(), "PWD="+dir) + stdout := bytes.Buffer{} + cmd.Stdout = &stdout + if err := cmd.Run(); err == nil { + fs = append(fs, dataFile{name: "LICENSE", data: stdout.Bytes()}) + } } return fs, nil @@ -710,6 +730,26 @@ func (f zipFile) Path() string { return f.name } func (f zipFile) Lstat() (os.FileInfo, error) { return f.f.FileInfo(), nil } func (f zipFile) Open() (io.ReadCloser, error) { return f.f.Open() } +type dataFile struct { + name string + data []byte +} + +func (f dataFile) Path() string { return f.name } +func (f dataFile) Lstat() (os.FileInfo, error) { return dataFileInfo{f}, nil } +func (f dataFile) Open() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(f.data)), nil } + +type dataFileInfo struct { + f dataFile +} + +func (fi dataFileInfo) Name() string { return path.Base(fi.f.name) } +func (fi dataFileInfo) Size() int64 { return int64(len(fi.f.data)) } +func (fi dataFileInfo) Mode() os.FileMode { return 0644 } +func (fi dataFileInfo) ModTime() time.Time { return time.Time{} } +func (fi dataFileInfo) IsDir() bool { return false } +func (fi dataFileInfo) Sys() interface{} { return nil } + // isVendoredPackage attempts to report whether the given filename is contained // in a package whose import path contains (but does not end with) the component // "vendor". diff --git a/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh b/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh index 3156462715..0c4d14929a 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -519,7 +519,7 @@ ccflags="$@" $2 ~ /^LOCK_(SH|EX|NB|UN)$/ || $2 ~ /^LO_(KEY|NAME)_SIZE$/ || $2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ || - $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ || + $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MREMAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ || $2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ || $2 ~ /^NFC_.*_(MAX)?SIZE$/ || $2 ~ /^RAW_PAYLOAD_/ || diff --git a/src/cmd/vendor/golang.org/x/sys/unix/mremap.go b/src/cmd/vendor/golang.org/x/sys/unix/mremap.go new file mode 100644 index 0000000000..86213c05d6 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/sys/unix/mremap.go @@ -0,0 +1,40 @@ +// Copyright 2023 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. + +//go:build linux +// +build linux + +package unix + +import "unsafe" + +type mremapMmapper struct { + mmapper + mremap func(oldaddr uintptr, oldlength uintptr, newlength uintptr, flags int, newaddr uintptr) (xaddr uintptr, err error) +} + +func (m *mremapMmapper) Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) { + if newLength <= 0 || len(oldData) == 0 || len(oldData) != cap(oldData) || flags&MREMAP_FIXED != 0 { + return nil, EINVAL + } + + pOld := &oldData[cap(oldData)-1] + m.Lock() + defer m.Unlock() + bOld := m.active[pOld] + if bOld == nil || &bOld[0] != &oldData[0] { + return nil, EINVAL + } + newAddr, errno := m.mremap(uintptr(unsafe.Pointer(&bOld[0])), uintptr(len(bOld)), uintptr(newLength), flags, 0) + if errno != nil { + return nil, errno + } + bNew := unsafe.Slice((*byte)(unsafe.Pointer(newAddr)), newLength) + pNew := &bNew[cap(bNew)-1] + if flags&MREMAP_DONTUNMAP == 0 { + delete(m.active, pOld) + } + m.active[pNew] = bNew + return bNew, nil +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go index 6de486befe..39de5f1430 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -2124,11 +2124,15 @@ func writevRacedetect(iovecs []Iovec, n int) { // mmap varies by architecture; see syscall_linux_*.go. //sys munmap(addr uintptr, length uintptr) (err error) +//sys mremap(oldaddr uintptr, oldlength uintptr, newlength uintptr, flags int, newaddr uintptr) (xaddr uintptr, err error) -var mapper = &mmapper{ - active: make(map[*byte][]byte), - mmap: mmap, - munmap: munmap, +var mapper = &mremapMmapper{ + mmapper: mmapper{ + active: make(map[*byte][]byte), + mmap: mmap, + munmap: munmap, + }, + mremap: mremap, } func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { @@ -2139,6 +2143,10 @@ func Munmap(b []byte) (err error) { return mapper.Munmap(b) } +func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) { + return mapper.Mremap(oldData, newLength, flags) +} + //sys Madvise(b []byte, advice int) (err error) //sys Mprotect(b []byte, prot int) (err error) //sys Mlock(b []byte) (err error) @@ -2487,7 +2495,6 @@ func Getresgid() (rgid, egid, sgid int) { // MqTimedreceive // MqTimedsend // MqUnlink -// Mremap // Msgctl // Msgget // Msgrcv diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go index de936b677b..3784f402e5 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -493,6 +493,7 @@ const ( BPF_F_TEST_RUN_ON_CPU = 0x1 BPF_F_TEST_STATE_FREQ = 0x8 BPF_F_TEST_XDP_LIVE_FRAMES = 0x2 + BPF_F_XDP_DEV_BOUND_ONLY = 0x40 BPF_F_XDP_HAS_FRAGS = 0x20 BPF_H = 0x8 BPF_IMM = 0x0 @@ -826,9 +827,9 @@ const ( DM_UUID_FLAG = 0x4000 DM_UUID_LEN = 0x81 DM_VERSION = 0xc138fd00 - DM_VERSION_EXTRA = "-ioctl (2022-07-28)" + DM_VERSION_EXTRA = "-ioctl (2023-03-01)" DM_VERSION_MAJOR = 0x4 - DM_VERSION_MINOR = 0x2f + DM_VERSION_MINOR = 0x30 DM_VERSION_PATCHLEVEL = 0x0 DT_BLK = 0x6 DT_CHR = 0x2 @@ -1197,6 +1198,7 @@ const ( FAN_EVENT_METADATA_LEN = 0x18 FAN_EVENT_ON_CHILD = 0x8000000 FAN_FS_ERROR = 0x8000 + FAN_INFO = 0x20 FAN_MARK_ADD = 0x1 FAN_MARK_DONT_FOLLOW = 0x4 FAN_MARK_EVICTABLE = 0x200 @@ -1233,6 +1235,8 @@ const ( FAN_REPORT_PIDFD = 0x80 FAN_REPORT_TARGET_FID = 0x1000 FAN_REPORT_TID = 0x100 + FAN_RESPONSE_INFO_AUDIT_RULE = 0x1 + FAN_RESPONSE_INFO_NONE = 0x0 FAN_UNLIMITED_MARKS = 0x20 FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 @@ -1860,6 +1864,7 @@ const ( MEMWRITEOOB64 = 0xc0184d15 MFD_ALLOW_SEALING = 0x2 MFD_CLOEXEC = 0x1 + MFD_EXEC = 0x10 MFD_HUGETLB = 0x4 MFD_HUGE_16GB = 0x88000000 MFD_HUGE_16MB = 0x60000000 @@ -1875,6 +1880,7 @@ const ( MFD_HUGE_8MB = 0x5c000000 MFD_HUGE_MASK = 0x3f MFD_HUGE_SHIFT = 0x1a + MFD_NOEXEC_SEAL = 0x8 MINIX2_SUPER_MAGIC = 0x2468 MINIX2_SUPER_MAGIC2 = 0x2478 MINIX3_SUPER_MAGIC = 0x4d5a @@ -1898,6 +1904,9 @@ const ( MOUNT_ATTR_SIZE_VER0 = 0x20 MOUNT_ATTR_STRICTATIME = 0x20 MOUNT_ATTR__ATIME = 0x70 + MREMAP_DONTUNMAP = 0x4 + MREMAP_FIXED = 0x2 + MREMAP_MAYMOVE = 0x1 MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 @@ -2204,6 +2213,7 @@ const ( PACKET_USER = 0x6 PACKET_VERSION = 0xa PACKET_VNET_HDR = 0xf + PACKET_VNET_HDR_SZ = 0x18 PARITY_CRC16_PR0 = 0x2 PARITY_CRC16_PR0_CCITT = 0x4 PARITY_CRC16_PR1 = 0x3 @@ -2221,6 +2231,7 @@ const ( PERF_ATTR_SIZE_VER5 = 0x70 PERF_ATTR_SIZE_VER6 = 0x78 PERF_ATTR_SIZE_VER7 = 0x80 + PERF_ATTR_SIZE_VER8 = 0x88 PERF_AUX_FLAG_COLLISION = 0x8 PERF_AUX_FLAG_CORESIGHT_FORMAT_CORESIGHT = 0x0 PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW = 0x100 @@ -2361,6 +2372,7 @@ const ( PR_FP_EXC_UND = 0x40000 PR_FP_MODE_FR = 0x1 PR_FP_MODE_FRE = 0x2 + PR_GET_AUXV = 0x41555856 PR_GET_CHILD_SUBREAPER = 0x25 PR_GET_DUMPABLE = 0x3 PR_GET_ENDIAN = 0x13 @@ -2369,6 +2381,8 @@ const ( PR_GET_FP_MODE = 0x2e PR_GET_IO_FLUSHER = 0x3a PR_GET_KEEPCAPS = 0x7 + PR_GET_MDWE = 0x42 + PR_GET_MEMORY_MERGE = 0x44 PR_GET_NAME = 0x10 PR_GET_NO_NEW_PRIVS = 0x27 PR_GET_PDEATHSIG = 0x2 @@ -2389,6 +2403,7 @@ const ( PR_MCE_KILL_GET = 0x22 PR_MCE_KILL_LATE = 0x0 PR_MCE_KILL_SET = 0x1 + PR_MDWE_REFUSE_EXEC_GAIN = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b PR_MTE_TAG_MASK = 0x7fff8 @@ -2423,6 +2438,8 @@ const ( PR_SET_FP_MODE = 0x2d PR_SET_IO_FLUSHER = 0x39 PR_SET_KEEPCAPS = 0x8 + PR_SET_MDWE = 0x41 + PR_SET_MEMORY_MERGE = 0x43 PR_SET_MM = 0x23 PR_SET_MM_ARG_END = 0x9 PR_SET_MM_ARG_START = 0x8 @@ -2506,6 +2523,7 @@ const ( PTRACE_GETSIGMASK = 0x420a PTRACE_GET_RSEQ_CONFIGURATION = 0x420f PTRACE_GET_SYSCALL_INFO = 0x420e + PTRACE_GET_SYSCALL_USER_DISPATCH_CONFIG = 0x4211 PTRACE_INTERRUPT = 0x4207 PTRACE_KILL = 0x8 PTRACE_LISTEN = 0x4208 @@ -2536,6 +2554,7 @@ const ( PTRACE_SETREGSET = 0x4205 PTRACE_SETSIGINFO = 0x4203 PTRACE_SETSIGMASK = 0x420b + PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG = 0x4210 PTRACE_SINGLESTEP = 0x9 PTRACE_SYSCALL = 0x18 PTRACE_SYSCALL_INFO_ENTRY = 0x1 @@ -3072,7 +3091,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0xd + TASKSTATS_VERSION = 0xe TCIFLUSH = 0x0 TCIOFF = 0x2 TCIOFLUSH = 0x2 @@ -3238,6 +3257,7 @@ const ( TP_STATUS_COPY = 0x2 TP_STATUS_CSUMNOTREADY = 0x8 TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_GSO_TCP = 0x100 TP_STATUS_KERNEL = 0x0 TP_STATUS_LOSING = 0x4 TP_STATUS_SENDING = 0x2 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 9d5352c3e4..12a9a1389e 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -443,6 +443,7 @@ const ( TIOCSWINSZ = 0x5414 TIOCVHANGUP = 0x5437 TOSTOP = 0x100 + TPIDR2_MAGIC = 0x54504902 TUNATTACHFILTER = 0x401054d5 TUNDETACHFILTER = 0x401054d6 TUNGETDEVNETNS = 0x54e3 @@ -515,6 +516,7 @@ const ( XCASE = 0x4 XTABS = 0x1800 ZA_MAGIC = 0x54366345 + ZT_MAGIC = 0x5a544e01 _HIDIOCGRAWNAME = 0x80804804 _HIDIOCGRAWPHYS = 0x80404805 _HIDIOCGRAWUNIQ = 0x80404808 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go index 722c29a008..7ceec233fb 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go @@ -1868,6 +1868,17 @@ func munmap(addr uintptr, length uintptr) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func mremap(oldaddr uintptr, oldlength uintptr, newlength uintptr, flags int, newaddr uintptr) (xaddr uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MREMAP, uintptr(oldaddr), uintptr(oldlength), uintptr(newlength), uintptr(flags), uintptr(newaddr), 0) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Madvise(b []byte, advice int) (err error) { var _p0 unsafe.Pointer if len(b) > 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index 7ea465204b..e6ed7d637d 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -372,6 +372,7 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 444 SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 + SYS_MEMFD_SECRET = 447 SYS_PROCESS_MRELEASE = 448 SYS_FUTEX_WAITV = 449 SYS_SET_MEMPOLICY_HOME_NODE = 450 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go index 00c3b8c20f..02e2462c8f 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -1538,6 +1538,10 @@ const ( IFLA_GRO_MAX_SIZE = 0x3a IFLA_TSO_MAX_SIZE = 0x3b IFLA_TSO_MAX_SEGS = 0x3c + IFLA_ALLMULTI = 0x3d + IFLA_DEVLINK_PORT = 0x3e + IFLA_GSO_IPV4_MAX_SIZE = 0x3f + IFLA_GRO_IPV4_MAX_SIZE = 0x40 IFLA_PROTO_DOWN_REASON_UNSPEC = 0x0 IFLA_PROTO_DOWN_REASON_MASK = 0x1 IFLA_PROTO_DOWN_REASON_VALUE = 0x2 @@ -1968,7 +1972,7 @@ const ( NFT_MSG_GETFLOWTABLE = 0x17 NFT_MSG_DELFLOWTABLE = 0x18 NFT_MSG_GETRULE_RESET = 0x19 - NFT_MSG_MAX = 0x1a + NFT_MSG_MAX = 0x21 NFTA_LIST_UNSPEC = 0x0 NFTA_LIST_ELEM = 0x1 NFTA_HOOK_UNSPEC = 0x0 @@ -3651,7 +3655,7 @@ const ( ETHTOOL_MSG_PSE_GET = 0x24 ETHTOOL_MSG_PSE_SET = 0x25 ETHTOOL_MSG_RSS_GET = 0x26 - ETHTOOL_MSG_USER_MAX = 0x26 + ETHTOOL_MSG_USER_MAX = 0x2b ETHTOOL_MSG_KERNEL_NONE = 0x0 ETHTOOL_MSG_STRSET_GET_REPLY = 0x1 ETHTOOL_MSG_LINKINFO_GET_REPLY = 0x2 @@ -3691,7 +3695,7 @@ const ( ETHTOOL_MSG_MODULE_NTF = 0x24 ETHTOOL_MSG_PSE_GET_REPLY = 0x25 ETHTOOL_MSG_RSS_GET_REPLY = 0x26 - ETHTOOL_MSG_KERNEL_MAX = 0x26 + ETHTOOL_MSG_KERNEL_MAX = 0x2b ETHTOOL_A_HEADER_UNSPEC = 0x0 ETHTOOL_A_HEADER_DEV_INDEX = 0x1 ETHTOOL_A_HEADER_DEV_NAME = 0x2 @@ -3795,7 +3799,7 @@ const ( ETHTOOL_A_RINGS_TCP_DATA_SPLIT = 0xb ETHTOOL_A_RINGS_CQE_SIZE = 0xc ETHTOOL_A_RINGS_TX_PUSH = 0xd - ETHTOOL_A_RINGS_MAX = 0xd + ETHTOOL_A_RINGS_MAX = 0x10 ETHTOOL_A_CHANNELS_UNSPEC = 0x0 ETHTOOL_A_CHANNELS_HEADER = 0x1 ETHTOOL_A_CHANNELS_RX_MAX = 0x2 @@ -3833,14 +3837,14 @@ const ( ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 0x17 ETHTOOL_A_COALESCE_USE_CQE_MODE_TX = 0x18 ETHTOOL_A_COALESCE_USE_CQE_MODE_RX = 0x19 - ETHTOOL_A_COALESCE_MAX = 0x19 + ETHTOOL_A_COALESCE_MAX = 0x1c ETHTOOL_A_PAUSE_UNSPEC = 0x0 ETHTOOL_A_PAUSE_HEADER = 0x1 ETHTOOL_A_PAUSE_AUTONEG = 0x2 ETHTOOL_A_PAUSE_RX = 0x3 ETHTOOL_A_PAUSE_TX = 0x4 ETHTOOL_A_PAUSE_STATS = 0x5 - ETHTOOL_A_PAUSE_MAX = 0x5 + ETHTOOL_A_PAUSE_MAX = 0x6 ETHTOOL_A_PAUSE_STAT_UNSPEC = 0x0 ETHTOOL_A_PAUSE_STAT_PAD = 0x1 ETHTOOL_A_PAUSE_STAT_TX_FRAMES = 0x2 @@ -4490,7 +4494,7 @@ const ( NL80211_ATTR_MAC_HINT = 0xc8 NL80211_ATTR_MAC_MASK = 0xd7 NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca - NL80211_ATTR_MAX = 0x141 + NL80211_ATTR_MAX = 0x145 NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4 NL80211_ATTR_MAX_CSA_COUNTERS = 0xce NL80211_ATTR_MAX_MATCH_SETS = 0x85 @@ -4719,7 +4723,7 @@ const ( NL80211_BAND_ATTR_HT_CAPA = 0x4 NL80211_BAND_ATTR_HT_MCS_SET = 0x3 NL80211_BAND_ATTR_IFTYPE_DATA = 0x9 - NL80211_BAND_ATTR_MAX = 0xb + NL80211_BAND_ATTR_MAX = 0xd NL80211_BAND_ATTR_RATES = 0x2 NL80211_BAND_ATTR_VHT_CAPA = 0x8 NL80211_BAND_ATTR_VHT_MCS_SET = 0x7 @@ -4860,7 +4864,7 @@ const ( NL80211_CMD_LEAVE_IBSS = 0x2c NL80211_CMD_LEAVE_MESH = 0x45 NL80211_CMD_LEAVE_OCB = 0x6d - NL80211_CMD_MAX = 0x98 + NL80211_CMD_MAX = 0x99 NL80211_CMD_MICHAEL_MIC_FAILURE = 0x29 NL80211_CMD_MODIFY_LINK_STA = 0x97 NL80211_CMD_NAN_MATCH = 0x78 @@ -5841,6 +5845,8 @@ const ( TUN_F_TSO6 = 0x4 TUN_F_TSO_ECN = 0x8 TUN_F_UFO = 0x10 + TUN_F_USO4 = 0x20 + TUN_F_USO6 = 0x40 ) const ( @@ -5850,9 +5856,10 @@ const ( ) const ( - VIRTIO_NET_HDR_GSO_NONE = 0x0 - VIRTIO_NET_HDR_GSO_TCPV4 = 0x1 - VIRTIO_NET_HDR_GSO_UDP = 0x3 - VIRTIO_NET_HDR_GSO_TCPV6 = 0x4 - VIRTIO_NET_HDR_GSO_ECN = 0x80 + VIRTIO_NET_HDR_GSO_NONE = 0x0 + VIRTIO_NET_HDR_GSO_TCPV4 = 0x1 + VIRTIO_NET_HDR_GSO_UDP = 0x3 + VIRTIO_NET_HDR_GSO_TCPV6 = 0x4 + VIRTIO_NET_HDR_GSO_UDP_L4 = 0x5 + VIRTIO_NET_HDR_GSO_ECN = 0x80 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index 4ecc1495cd..6d8acbcc57 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -337,6 +337,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint32 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index 34fddff964..59293c6884 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -350,6 +350,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index 3b14a6031f..40cfa38c29 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -328,6 +328,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint32 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index 0517651ab3..055bc4216d 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -329,6 +329,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go index 3b0c518134..f28affbc60 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go @@ -330,6 +330,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go index fccdf4dd0f..9d71e7ccd8 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -333,6 +333,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint32 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index 500de8fc07..fd5ccd332a 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -332,6 +332,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index d0434cd2c6..7704de77a2 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -332,6 +332,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go index 84206ba534..df00b87571 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -333,6 +333,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint32 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go index ab078cf1f5..0942840db6 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go @@ -340,6 +340,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint32 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index 42eb2c4cef..0348743950 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -339,6 +339,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index 31304a4e8b..bad0670475 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -339,6 +339,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index c311f9612d..9ea54b7b86 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -357,6 +357,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index bba3cefac1..aa268d025c 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -352,6 +352,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go index ad8a013804..444045b6c5 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go @@ -334,6 +334,8 @@ type Taskstats struct { Ac_exe_inode uint64 Wpcopy_count uint64 Wpcopy_delay_total uint64 + Irq_count uint64 + Irq_delay_total uint64 } type cpuMask uint64 diff --git a/src/cmd/vendor/golang.org/x/sys/windows/service.go b/src/cmd/vendor/golang.org/x/sys/windows/service.go index c964b6848d..c44a1b9636 100644 --- a/src/cmd/vendor/golang.org/x/sys/windows/service.go +++ b/src/cmd/vendor/golang.org/x/sys/windows/service.go @@ -218,6 +218,10 @@ type SERVICE_FAILURE_ACTIONS struct { Actions *SC_ACTION } +type SERVICE_FAILURE_ACTIONS_FLAG struct { + FailureActionsOnNonCrashFailures int32 +} + type SC_ACTION struct { Type uint32 Delay uint32 diff --git a/src/cmd/vendor/golang.org/x/term/term_unix.go b/src/cmd/vendor/golang.org/x/term/term_unix.go index a4e31ab1b2..62c2b3f41f 100644 --- a/src/cmd/vendor/golang.org/x/term/term_unix.go +++ b/src/cmd/vendor/golang.org/x/term/term_unix.go @@ -60,7 +60,7 @@ func restore(fd int, state *State) error { func getSize(fd int) (width, height int, err error) { ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) if err != nil { - return -1, -1, err + return 0, 0, err } return int(ws.Col), int(ws.Row), nil } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go index afff0d82d8..c18b84b714 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go @@ -271,6 +271,7 @@ func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*a Sizes: sizes, Error: func(error) {}, // ignore errors (e.g. unused import) } + setGoVersion(tc, pkg) // It's tempting to record the new types in the // existing pass.TypesInfo, but we don't own it. diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go120.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go120.go new file mode 100644 index 0000000000..06b54946d7 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go120.go @@ -0,0 +1,13 @@ +// Copyright 2023 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. + +//go:build !go1.21 + +package cgocall + +import "go/types" + +func setGoVersion(tc *types.Config, pkg *types.Package) { + // no types.Package.GoVersion until Go 1.21 +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go121.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go121.go new file mode 100644 index 0000000000..2a3e1fad22 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go121.go @@ -0,0 +1,13 @@ +// Copyright 2023 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. + +//go:build go1.21 + +package cgocall + +import "go/types" + +func setGoVersion(tc *types.Config, pkg *types.Package) { + tc.GoVersion = pkg.GoVersion() +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go index 6d8039fe2b..ac37e4784e 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go @@ -118,12 +118,3 @@ func Imports(pkg *types.Package, path string) bool { } return false } - -// IsNamed reports whether t is exactly a named type in a package with a given path. -func IsNamed(t types.Type, path, name string) bool { - if n, ok := t.(*types.Named); ok { - obj := n.Obj() - return obj.Pkg().Path() == path && obj.Name() == name - } - return false -} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go index 8429eab935..92c1da8ef4 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go @@ -139,7 +139,7 @@ func run(pass *analysis.Pass) (any, error) { } func isAttr(t types.Type) bool { - return analysisutil.IsNamed(t, "log/slog", "Attr") + return isNamed(t, "log/slog", "Attr") } // shortName returns a name for the function that is shorter than FullName. @@ -195,28 +195,28 @@ func kvFuncSkipArgs(fn *types.Func) (int, bool) { // The first key is the dereferenced receiver type name, or "" for a function. var kvFuncs = map[string]map[string]int{ "": map[string]int{ - "Debug": 1, - "Info": 1, - "Warn": 1, - "Error": 1, - "DebugCtx": 2, - "InfoCtx": 2, - "WarnCtx": 2, - "ErrorCtx": 2, - "Log": 3, - "Group": 1, + "Debug": 1, + "Info": 1, + "Warn": 1, + "Error": 1, + "DebugContext": 2, + "InfoContext": 2, + "WarnContext": 2, + "ErrorContext": 2, + "Log": 3, + "Group": 1, }, "Logger": map[string]int{ - "Debug": 1, - "Info": 1, - "Warn": 1, - "Error": 1, - "DebugCtx": 2, - "InfoCtx": 2, - "WarnCtx": 2, - "ErrorCtx": 2, - "Log": 3, - "With": 0, + "Debug": 1, + "Info": 1, + "Warn": 1, + "Error": 1, + "DebugContext": 2, + "InfoContext": 2, + "WarnContext": 2, + "ErrorContext": 2, + "Log": 3, + "With": 0, }, "Record": map[string]int{ "Add": 0, @@ -232,3 +232,12 @@ func isMethodExpr(info *types.Info, c *ast.CallExpr) bool { sel := info.Selections[s] return sel != nil && sel.Kind() == types.MethodExpr } + +// isNamed reports whether t is exactly a named type in a package with a given path. +func isNamed(t types.Type, path, name string) bool { + if n, ok := t.(*types.Named); ok { + obj := n.Obj() + return obj.Pkg() != nil && obj.Pkg().Path() == path && obj.Name() == name + } + return false +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go index ff22d23ce5..10c76bc627 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go @@ -62,6 +62,7 @@ type Config struct { Compiler string Dir string ImportPath string + GoVersion string // minimum required Go version, such as "go1.21.0" GoFiles []string NonGoFiles []string IgnoredFiles []string @@ -217,8 +218,9 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re return compilerImporter.Import(path) }) tc := &types.Config{ - Importer: importer, - Sizes: types.SizesFor("gc", build.Default.GOARCH), // assume gccgo ≡ gc? + Importer: importer, + Sizes: types.SizesFor("gc", build.Default.GOARCH), // assume gccgo ≡ gc? + GoVersion: cfg.GoVersion, } info := &types.Info{ Types: make(map[ast.Expr]types.TypeAndValue), diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go index 3fbfebf369..1fc1de0bd1 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go +++ b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go @@ -64,8 +64,9 @@ type event struct { // depth-first order. It calls f(n) for each node n before it visits // n's children. // +// The complete traversal sequence is determined by ast.Inspect. // The types argument, if non-empty, enables type-based filtering of -// events. The function f if is called only for nodes whose type +// events. The function f is called only for nodes whose type // matches an element of the types slice. func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { // Because it avoids postorder calls to f, and the pruning @@ -97,6 +98,7 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { // of the non-nil children of the node, followed by a call of // f(n, false). // +// The complete traversal sequence is determined by ast.Inspect. // The types argument, if non-empty, enables type-based filtering of // events. The function f if is called only for nodes whose type // matches an element of the types slice. diff --git a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go index 549aa9e54c..f2ce77fd59 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go +++ b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go @@ -137,6 +137,17 @@ type Encoder struct { // These objects are sufficient to define the API of their package. // The objects described by a package's export data are drawn from this set. // +// The set of objects accessible from a package's Scope depends on +// whether the package was produced by type-checking syntax, or +// reading export data; the latter may have a smaller Scope since +// export data trims objects that are not reachable from an exported +// declaration. For example, the For function will return a path for +// an exported method of an unexported type that is not reachable +// from any public declaration; this path will cause the Object +// function to fail if called on a package loaded from export data. +// TODO(adonovan): is this a bug or feature? Should this package +// compute accessibility in the same way? +// // For does not return a path for predeclared names, imported package // names, local names, and unexported package-level names (except // types). diff --git a/src/cmd/vendor/golang.org/x/tools/internal/facts/facts.go b/src/cmd/vendor/golang.org/x/tools/internal/facts/facts.go index 81df45161a..954b42d696 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/facts/facts.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/facts/facts.go @@ -158,24 +158,52 @@ type gobFact struct { // for the same package. Each call to Decode returns an independent // fact set. type Decoder struct { - pkg *types.Package - packages map[string]*types.Package + pkg *types.Package + getPackage GetPackageFunc } // NewDecoder returns a fact decoder for the specified package. +// +// It uses a brute-force recursive approach to enumerate all objects +// defined by dependencies of pkg, so that it can learn the set of +// package paths that may be mentioned in the fact encoding. This does +// not scale well; use [NewDecoderFunc] where possible. func NewDecoder(pkg *types.Package) *Decoder { // Compute the import map for this package. // See the package doc comment. - return &Decoder{pkg, importMap(pkg.Imports())} + m := importMap(pkg.Imports()) + getPackageFunc := func(path string) *types.Package { return m[path] } + return NewDecoderFunc(pkg, getPackageFunc) +} + +// NewDecoderFunc returns a fact decoder for the specified package. +// +// It calls the getPackage function for the package path string of +// each dependency (perhaps indirect) that it encounters in the +// encoding. If the function returns nil, the fact is discarded. +// +// This function is preferred over [NewDecoder] when the client is +// capable of efficient look-up of packages by package path. +func NewDecoderFunc(pkg *types.Package, getPackage GetPackageFunc) *Decoder { + return &Decoder{ + pkg: pkg, + getPackage: getPackage, + } } -// Decode decodes all the facts relevant to the analysis of package pkg. -// The read function reads serialized fact data from an external source -// for one of of pkg's direct imports. The empty file is a valid -// encoding of an empty fact set. +// A GetPackageFunc function returns the package denoted by a package path. +type GetPackageFunc = func(pkgPath string) *types.Package + +// Decode decodes all the facts relevant to the analysis of package +// pkg. The read function reads serialized fact data from an external +// source for one of pkg's direct imports, identified by package path. +// The empty file is a valid encoding of an empty fact set. // // It is the caller's responsibility to call gob.Register on all // necessary fact types. +// +// Concurrent calls to Decode are safe, so long as the +// [GetPackageFunc] (if any) is also concurrency-safe. func (d *Decoder) Decode(read func(*types.Package) ([]byte, error)) (*Set, error) { // Read facts from imported packages. // Facts may describe indirectly imported packages, or their objects. @@ -202,13 +230,11 @@ func (d *Decoder) Decode(read func(*types.Package) ([]byte, error)) (*Set, error if err := gob.NewDecoder(bytes.NewReader(data)).Decode(&gobFacts); err != nil { return nil, fmt.Errorf("decoding facts for %q: %v", imp.Path(), err) } - if debug { - logf("decoded %d facts: %v", len(gobFacts), gobFacts) - } + logf("decoded %d facts: %v", len(gobFacts), gobFacts) // Parse each one into a key and a Fact. for _, f := range gobFacts { - factPkg := d.packages[f.PkgPath] + factPkg := d.getPackage(f.PkgPath) // possibly an indirect dependency if factPkg == nil { // Fact relates to a dependency that was // unused in this translation unit. Skip. diff --git a/src/cmd/vendor/golang.org/x/tools/internal/facts/imports.go b/src/cmd/vendor/golang.org/x/tools/internal/facts/imports.go index 7b21668660..b18e62d1d7 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/facts/imports.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/facts/imports.go @@ -21,6 +21,10 @@ import ( // Packages in the map that are only indirectly imported may be // incomplete (!pkg.Complete()). // +// This function scales very poorly with packages' transitive object +// references, which can be more than a million for each package near +// the top of a large project. (This was a significant contributor to +// #60621.) // TODO(adonovan): opt: compute this information more efficiently // by obtaining it from the internals of the gcexportdata decoder. func importMap(imports []*types.Package) map[string]*types.Package { diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index f3bdde6b54..fe71cb4d3b 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -17,13 +17,13 @@ github.com/google/pprof/third_party/svgpan # github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 ## explicit; go 1.12 github.com/ianlancetaylor/demangle -# golang.org/x/arch v0.3.0 +# golang.org/x/arch v0.4.0 ## explicit; go 1.17 golang.org/x/arch/arm/armasm golang.org/x/arch/arm64/arm64asm golang.org/x/arch/ppc64/ppc64asm golang.org/x/arch/x86/x86asm -# golang.org/x/mod v0.10.1-0.20230606122920-62c7e578f1a7 +# golang.org/x/mod v0.12.0 ## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile @@ -34,19 +34,19 @@ golang.org/x/mod/sumdb/dirhash golang.org/x/mod/sumdb/note golang.org/x/mod/sumdb/tlog golang.org/x/mod/zip -# golang.org/x/sync v0.2.1-0.20230601203510-93782cc822b6 +# golang.org/x/sync v0.3.0 ## explicit; go 1.17 golang.org/x/sync/semaphore -# golang.org/x/sys v0.9.0 +# golang.org/x/sys v0.10.0 ## explicit; go 1.17 golang.org/x/sys/internal/unsafeheader golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/term v0.9.0 +# golang.org/x/term v0.10.0 ## explicit; go 1.17 golang.org/x/term -# golang.org/x/tools v0.9.4-0.20230613194514-c6c983054920 +# golang.org/x/tools v0.11.1-0.20230712164437-1ca21856af7b ## explicit; go 1.18 golang.org/x/tools/cmd/bisect golang.org/x/tools/cover diff --git a/src/crypto/ecdh/ecdh.go b/src/crypto/ecdh/ecdh.go index 74420559b5..b86f521787 100644 --- a/src/crypto/ecdh/ecdh.go +++ b/src/crypto/ecdh/ecdh.go @@ -16,7 +16,11 @@ import ( ) type Curve interface { - // GenerateKey generates a new PrivateKey from rand. + // GenerateKey generates a random PrivateKey. + // + // Most applications should use [crypto/rand.Reader] as rand. Note that the + // returned key does not depend deterministically on the bytes read from rand, + // and may change between calls and/or between versions. GenerateKey(rand io.Reader) (*PrivateKey, error) // NewPrivateKey checks that key is valid and returns a PrivateKey. diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index 1c93cefdbf..e1503779ae 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -150,7 +150,11 @@ func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOp return SignASN1(rand, priv, digest) } -// GenerateKey generates a public and private key pair. +// GenerateKey generates a new ECDSA private key for the specified curve. +// +// Most applications should use [crypto/rand.Reader] as rand. Note that the +// returned key does not depend deterministically on the bytes read from rand, +// and may change between calls and/or between versions. func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) { randutil.MaybeReadByte(rand) @@ -245,6 +249,10 @@ var errNoAsm = errors.New("no assembly implementation available") // using the private key, priv. If the hash is longer than the bit-length of the // private key's curve order, the hash will be truncated to that length. It // returns the ASN.1 encoded signature. +// +// The signature is randomized. Most applications should use [crypto/rand.Reader] +// as rand. Note that the returned signature does not depend deterministically on +// the bytes read from rand, and may change between calls and/or between versions. func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) { randutil.MaybeReadByte(rand) diff --git a/src/crypto/ed25519/ed25519.go b/src/crypto/ed25519/ed25519.go index 32a8d9e86c..1dda9e5e9a 100644 --- a/src/crypto/ed25519/ed25519.go +++ b/src/crypto/ed25519/ed25519.go @@ -76,7 +76,7 @@ func (priv PrivateKey) Seed() []byte { return bytes.Clone(priv[:SeedSize]) } -// Sign signs the given message with priv. rand is ignored. +// Sign signs the given message with priv. rand is ignored and can be nil. // // If opts.HashFunc() is [crypto.SHA512], the pre-hashed variant Ed25519ph is used // and message is expected to be a SHA-512 hash, otherwise opts.HashFunc() must @@ -132,6 +132,9 @@ func (o *Options) HashFunc() crypto.Hash { return o.Hash } // GenerateKey generates a public/private key pair using entropy from rand. // If rand is nil, [crypto/rand.Reader] will be used. +// +// The output of this function is deterministic, and equivalent to reading +// [SeedSize] bytes from rand, and passing them to [NewKeyFromSeed]. func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { if rand == nil { rand = cryptorand.Reader diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go index 489555358d..55fea1ab93 100644 --- a/src/crypto/rsa/pkcs1v15.go +++ b/src/crypto/rsa/pkcs1v15.go @@ -31,7 +31,10 @@ type PKCS1v15DecryptOptions struct { // // The random parameter is used as a source of entropy to ensure that // encrypting the same message twice doesn't result in the same -// ciphertext. +// ciphertext. Most applications should use [crypto/rand.Reader] +// as random. Note that the returned ciphertext does not depend +// deterministically on the bytes read from random, and may change +// between calls and/or between versions. // // WARNING: use of this function to encrypt plaintexts other than // session keys is dangerous. Use RSA OAEP in new protocols. @@ -79,7 +82,7 @@ func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, erro } // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS #1 v1.5. -// The random parameter is legacy and ignored, and it can be as nil. +// The random parameter is legacy and ignored, and it can be nil. // // Note that whether this function returns an error or not discloses secret // information. If an attacker can cause this function to run repeatedly and @@ -275,7 +278,7 @@ var hashPrefixes = map[crypto.Hash][]byte{ // function. If hash is zero, hashed is signed directly. This isn't // advisable except for interoperability. // -// The random parameter is legacy and ignored, and it can be as nil. +// The random parameter is legacy and ignored, and it can be nil. // // This function is deterministic. Thus, if the set of possible // messages is small, an attacker may be able to build a map from diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go index f7d23b55ef..3a377cc9db 100644 --- a/src/crypto/rsa/pss.go +++ b/src/crypto/rsa/pss.go @@ -285,7 +285,17 @@ var invalidSaltLenErr = errors.New("crypto/rsa: PSSOptions.SaltLength cannot be // digest must be the result of hashing the input message using the given hash // function. The opts argument may be nil, in which case sensible defaults are // used. If opts.Hash is set, it overrides hash. +// +// The signature is randomized depending on the message, key, and salt size, +// using bytes from rand. Most applications should use [crypto/rand.Reader] as +// rand. func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, opts *PSSOptions) ([]byte, error) { + // Note that while we don't commit to deterministic execution with respect + // to the rand stream, we also don't apply MaybeReadByte, so per Hyrum's Law + // it's probably relied upon by some. It's a tolerable promise because a + // well-specified number of random bytes is included in the signature, in a + // well-specified way. + if boring.Enabled && rand == boring.RandReader { bkey, err := boringPrivateKey(priv) if err != nil { diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go index 88e44508cd..f0aef1f542 100644 --- a/src/crypto/rsa/rsa.go +++ b/src/crypto/rsa/rsa.go @@ -263,8 +263,11 @@ func (priv *PrivateKey) Validate() error { return nil } -// GenerateKey generates an RSA keypair of the given bit size using the -// random source random (for example, crypto/rand.Reader). +// GenerateKey generates a random RSA private key of the given bit size. +// +// Most applications should use [crypto/rand.Reader] as rand. Note that the +// returned key does not depend deterministically on the bytes read from rand, +// and may change between calls and/or between versions. func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) { return GenerateMultiPrimeKey(random, 2, bits) } @@ -500,6 +503,7 @@ func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) { // // The random parameter is used as a source of entropy to ensure that // encrypting the same message twice doesn't result in the same ciphertext. +// Most applications should use [crypto/rand.Reader] as random. // // The label parameter may contain arbitrary data that will not be encrypted, // but which gives important context to the message. For example, if a given @@ -510,6 +514,12 @@ func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) { // The message must be no longer than the length of the public modulus minus // twice the hash length, minus a further 2. func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) { + // Note that while we don't commit to deterministic execution with respect + // to the random stream, we also don't apply MaybeReadByte, so per Hyrum's + // Law it's probably relied upon by some. It's a tolerable promise because a + // well-specified number of random bytes is included in the ciphertext, in a + // well-specified way. + if err := checkPub(pub); err != nil { return nil, err } @@ -691,7 +701,7 @@ func decrypt(priv *PrivateKey, ciphertext []byte, check bool) ([]byte, error) { // Encryption and decryption of a given message must use the same hash function // and sha256.New() is a reasonable choice. // -// The random parameter is legacy and ignored, and it can be as nil. +// The random parameter is legacy and ignored, and it can be nil. // // The label parameter must match the value given when encrypting. See // EncryptOAEP for details. diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go index df7ca99308..e6b52e9f91 100644 --- a/src/crypto/x509/root_darwin_test.go +++ b/src/crypto/x509/root_darwin_test.go @@ -12,7 +12,9 @@ import ( "time" ) -func TestPlatformVerifier(t *testing.T) { +func TestPlatformVerifierLegacy(t *testing.T) { + // TODO(#52108): This can be removed once the synthetic test root is deployed on + // builders. if !testenv.HasExternalNetwork() { t.Skip() } diff --git a/src/crypto/x509/root_windows_test.go b/src/crypto/x509/root_windows_test.go index 54dbc161dc..1372c043b2 100644 --- a/src/crypto/x509/root_windows_test.go +++ b/src/crypto/x509/root_windows_test.go @@ -16,7 +16,9 @@ import ( "time" ) -func TestPlatformVerifier(t *testing.T) { +func TestPlatformVerifierLegacy(t *testing.T) { + // TODO(#52108): This can be removed once the synthetic test root is deployed on + // builders. if !testenv.HasExternalNetwork() { t.Skip() } diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go index ce6605d972..3551b470ce 100644 --- a/src/crypto/x509/verify_test.go +++ b/src/crypto/x509/verify_test.go @@ -512,22 +512,21 @@ func testVerify(t *testing.T, test verifyTest, useSystemRoots bool) { return true } - // Every expected chain should match 1 returned chain + // Every expected chain should match one (or more) returned chain. We tolerate multiple + // matches, as due to root store semantics it is plausible that (at least on the system + // verifiers) multiple identical (looking) chains may be returned when two roots with the + // same subject are present. for _, expectedChain := range test.expectedChains { - nChainMatched := 0 + var match bool for _, chain := range chains { if doesMatch(expectedChain, chain) { - nChainMatched++ + match = true + break } } - if nChainMatched != 1 { - t.Errorf("Got %v matches instead of %v for expected chain %v", nChainMatched, 1, expectedChain) - for _, chain := range chains { - if doesMatch(expectedChain, chain) { - t.Errorf("\t matched %v", chainToDebugString(chain)) - } - } + if !match { + t.Errorf("No match found for %v", expectedChain) } } diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index a77d63dc5e..836fe83e2e 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -2944,15 +2944,17 @@ func (rs *Rows) initContextClose(ctx, txctx context.Context) { if bypassRowsAwaitDone { return } - ctx, rs.cancel = context.WithCancel(ctx) - go rs.awaitDone(ctx, txctx) + closectx, cancel := context.WithCancel(ctx) + rs.cancel = cancel + go rs.awaitDone(ctx, txctx, closectx) } -// awaitDone blocks until either ctx or txctx is canceled. The ctx is provided -// from the query context and is canceled when the query Rows is closed. +// awaitDone blocks until ctx, txctx, or closectx is canceled. +// The ctx is provided from the query context. // If the query was issued in a transaction, the transaction's context -// is also provided in txctx to ensure Rows is closed if the Tx is closed. -func (rs *Rows) awaitDone(ctx, txctx context.Context) { +// is also provided in txctx, to ensure Rows is closed if the Tx is closed. +// The closectx is closed by an explicit call to rs.Close. +func (rs *Rows) awaitDone(ctx, txctx, closectx context.Context) { var txctxDone <-chan struct{} if txctx != nil { txctxDone = txctx.Done() @@ -2964,6 +2966,9 @@ func (rs *Rows) awaitDone(ctx, txctx context.Context) { case <-txctxDone: err := txctx.Err() rs.contextDone.Store(&err) + case <-closectx.Done(): + // rs.cancel was called via Close(); don't store this into contextDone + // to ensure Err() is unaffected. } rs.close(ctx.Err()) } diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index 718056c351..e6a5cd912a 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -4493,6 +4493,31 @@ func TestContextCancelBetweenNextAndErr(t *testing.T) { } } +func TestNilErrorAfterClose(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + + // This WithCancel is important; Rows contains an optimization to avoid + // spawning a goroutine when the query/transaction context cannot be + // canceled, but this test tests a bug which is caused by said goroutine. + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + r, err := db.QueryContext(ctx, "SELECT|people|name|") + if err != nil { + t.Fatal(err) + } + + if err := r.Close(); err != nil { + t.Fatal(err) + } + + time.Sleep(10 * time.Millisecond) // increase odds of seeing failure + if err := r.Err(); err != nil { + t.Fatal(err) + } +} + // badConn implements a bad driver.Conn, for TestBadDriver. // The Exec method panics. type badConn struct{} diff --git a/src/encoding/base32/base32.go b/src/encoding/base32/base32.go index 41d343aaac..3dc37b0aa7 100644 --- a/src/encoding/base32/base32.go +++ b/src/encoding/base32/base32.go @@ -50,7 +50,8 @@ const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV" // NewEncoding returns a new Encoding defined by the given alphabet, -// which must be a 32-byte string. +// which must be a 32-byte string. The alphabet is treated as sequence +// of byte values without any special treatment for multi-byte UTF-8. func NewEncoding(encoder string) *Encoding { if len(encoder) != 32 { panic("encoding alphabet is not 32-bytes long") @@ -80,6 +81,8 @@ var HexEncoding = NewEncoding(encodeHex) // The padding character must not be '\r' or '\n', must not // be contained in the encoding's alphabet and must be a rune equal or // below '\xff'. +// Padding characters above '\x7f' are encoded as their exact byte value +// rather than using the UTF-8 representation of the codepoint. func (enc Encoding) WithPadding(padding rune) *Encoding { if padding == '\r' || padding == '\n' || padding > 0xff { panic("invalid padding") diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go index 0e12d90d29..6aa8a15bdc 100644 --- a/src/encoding/base64/base64.go +++ b/src/encoding/base64/base64.go @@ -54,7 +54,8 @@ const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678 // NewEncoding returns a new padded Encoding defined by the given alphabet, // which must be a 64-byte string that does not contain the padding character -// or CR / LF ('\r', '\n'). +// or CR / LF ('\r', '\n'). The alphabet is treated as sequence of byte values +// without any special treatment for multi-byte UTF-8. // The resulting Encoding uses the default padding character ('='), // which may be changed or disabled via WithPadding. func NewEncoding(encoder string) *Encoding { @@ -83,6 +84,8 @@ func NewEncoding(encoder string) *Encoding { // The padding character must not be '\r' or '\n', must not // be contained in the encoding's alphabet and must be a rune equal or // below '\xff'. +// Padding characters above '\x7f' are encoded as their exact byte value +// rather than using the UTF-8 representation of the codepoint. func (enc Encoding) WithPadding(padding rune) *Encoding { if padding == '\r' || padding == '\n' || padding > 0xff { panic("invalid padding") diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go index 158e3e9d7f..3fb18a7a03 100644 --- a/src/encoding/binary/binary.go +++ b/src/encoding/binary/binary.go @@ -479,7 +479,6 @@ func dataSize(v reflect.Value) int { if s := sizeof(v.Type().Elem()); s >= 0 { return s * v.Len() } - return -1 case reflect.Struct: t := v.Type() @@ -491,8 +490,12 @@ func dataSize(v reflect.Value) int { return size default: - return sizeof(v.Type()) + if v.IsValid() { + return sizeof(v.Type()) + } } + + return -1 } // sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable. diff --git a/src/encoding/binary/binary_test.go b/src/encoding/binary/binary_test.go index 4e1fb59f03..4b22b28843 100644 --- a/src/encoding/binary/binary_test.go +++ b/src/encoding/binary/binary_test.go @@ -351,6 +351,26 @@ func TestSizeStructCache(t *testing.T) { } } +func TestSizeInvalid(t *testing.T) { + testcases := []any{ + int(0), + new(int), + (*int)(nil), + [1]uint{}, + new([1]uint), + (*[1]uint)(nil), + []int{}, + []int(nil), + new([]int), + (*[]int)(nil), + } + for _, tc := range testcases { + if got := Size(tc); got != -1 { + t.Errorf("Size(%T) = %d, want -1", tc, got) + } + } +} + // An attempt to read into a struct with an unexported field will // panic. This is probably not the best choice, but at this point // anything else would be an API change. diff --git a/src/go.mod b/src/go.mod index 5ef63d4e3b..25829e17f2 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,11 +3,11 @@ module std go 1.21 require ( - golang.org/x/crypto v0.10.0 - golang.org/x/net v0.11.1-0.20230613203745-f5464ddb689c + golang.org/x/crypto v0.11.1-0.20230711161743-2e82bdd1719d + golang.org/x/net v0.12.1-0.20230712162946-57553cbff163 ) require ( - golang.org/x/sys v0.9.0 // indirect - golang.org/x/text v0.10.1-0.20230613190012-2df65d769a9e // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect ) diff --git a/src/go.sum b/src/go.sum index 93d34efbe8..e474b8be31 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,8 +1,8 @@ -golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/net v0.11.1-0.20230613203745-f5464ddb689c h1:icjsA5jFPWsTcuIb/yIeU6mgXRHPQBfo0Lzd1GQmKZI= -golang.org/x/net v0.11.1-0.20230613203745-f5464ddb689c/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.10.1-0.20230613190012-2df65d769a9e h1:GTf7SHdimRGQ2uYYuJ0eJUoAEJ9ufU2ocSTVWnbeVQc= -golang.org/x/text v0.10.1-0.20230613190012-2df65d769a9e/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/crypto v0.11.1-0.20230711161743-2e82bdd1719d h1:LiA25/KWKuXfIq5pMIBq1s5hz3HQxhJJSu/SUGlD+SM= +golang.org/x/crypto v0.11.1-0.20230711161743-2e82bdd1719d/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/net v0.12.1-0.20230712162946-57553cbff163 h1:1EDKNuaCsog7zGLEml1qRuO4gt23jORUQX2f0IKZ860= +golang.org/x/net v0.12.1-0.20230712162946-57553cbff163/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index be8ac30f9d..2f335068b8 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -286,7 +286,7 @@ var depsRules = ` math/big, go/token < go/constant; - container/heap, go/constant, go/parser, internal/types/errors + container/heap, go/constant, go/parser, internal/goversion, internal/types/errors < go/types; # The vast majority of standard library packages should not be resorting to regexp. diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 837a9b5e14..7795f2552d 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -577,6 +577,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b x.mode = value } + // Use the final type computed above for all arguments. + for _, a := range args { + check.updateExprType(a.expr, x.typ, true) + } + if check.recordTypes() && x.mode != constant_ { types := make([]Type, nargs) for i := range types { diff --git a/src/go/types/check.go b/src/go/types/check.go index 5381b5db68..3b0f5e4fdf 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -12,6 +12,7 @@ import ( "go/ast" "go/constant" "go/token" + "internal/goversion" . "internal/types/errors" ) @@ -233,20 +234,20 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch info = new(Info) } - version, err := parseGoVersion(conf.GoVersion) - if err != nil { - panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err)) - } + // Note: clients may call NewChecker with the Unsafe package, which is + // globally shared and must not be mutated. Therefore NewChecker must not + // mutate *pkg. + // + // (previously, pkg.goVersion was mutated here: go.dev/issue/61212) return &Checker{ - conf: conf, - ctxt: conf.Context, - fset: fset, - pkg: pkg, - Info: info, - version: version, - objMap: make(map[Object]*declInfo), - impMap: make(map[importKey]*Package), + conf: conf, + ctxt: conf.Context, + fset: fset, + pkg: pkg, + Info: info, + objMap: make(map[Object]*declInfo), + impMap: make(map[importKey]*Package), } } @@ -342,6 +343,20 @@ func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(f var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together") func (check *Checker) checkFiles(files []*ast.File) (err error) { + if check.pkg == Unsafe { + // Defensive handling for Unsafe, which cannot be type checked, and must + // not be mutated. See https://go.dev/issue/61212 for an example of where + // Unsafe is passed to NewChecker. + return nil + } + + check.version, err = parseGoVersion(check.conf.GoVersion) + if err != nil { + return err + } + if check.version.after(version{1, goversion.Version}) { + return fmt.Errorf("package requires newer Go version %v", check.version) + } if check.conf.FakeImportC && check.conf.go115UsesCgo { return errBadCgo } @@ -386,6 +401,7 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) { check.monomorph() } + check.pkg.goVersion = check.conf.GoVersion check.pkg.complete = true // no longer needed - release memory diff --git a/src/go/types/generate_test.go b/src/go/types/generate_test.go index 05a848be31..75fda025ee 100644 --- a/src/go/types/generate_test.go +++ b/src/go/types/generate_test.go @@ -141,6 +141,7 @@ var filemap = map[string]action{ "universe.go": fixGlobalTypVarDecl, "util_test.go": fixTokenPos, "validtype.go": nil, + "version_test.go": nil, } // TODO(gri) We should be able to make these rewriters more configurable/composable. diff --git a/src/go/types/index.go b/src/go/types/index.go index 1bcfb38feb..c1c0f40e87 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -186,6 +186,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst if !valid { // types2 uses the position of '[' for the error check.errorf(x, NonIndexableOperand, invalidOp+"cannot index %s", x) + check.use(e.Indices...) x.mode = invalid return false } diff --git a/src/go/types/package.go b/src/go/types/package.go index 7aa62fb7a3..0f52d5f489 100644 --- a/src/go/types/package.go +++ b/src/go/types/package.go @@ -12,13 +12,14 @@ import ( // A Package describes a Go package. type Package struct { - path string - name string - scope *Scope - imports []*Package - complete bool - fake bool // scope lookup errors are silently dropped if package is fake (internal use only) - cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go + path string + name string + scope *Scope + imports []*Package + complete bool + fake bool // scope lookup errors are silently dropped if package is fake (internal use only) + cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go + goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod) } // NewPackage returns a new Package for the given package path and name. @@ -37,6 +38,12 @@ func (pkg *Package) Name() string { return pkg.name } // SetName sets the package name. func (pkg *Package) SetName(name string) { pkg.name = name } +// GoVersion returns the minimum Go version required by this package. +// If the minimum version is unknown, GoVersion returns the empty string. +// Individual source files may specify a different minimum Go version, +// as reported in the [go/ast.File.GoVersion] field. +func (pkg *Package) GoVersion() string { return pkg.goVersion } + // Scope returns the (complete or incomplete) package scope // holding the objects declared at package level (TypeNames, // Consts, Vars, and Funcs). diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index f17a1781f5..9e5b5f8b20 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -46,7 +46,7 @@ func TestSizeof(t *testing.T) { // Misc {Scope{}, 44, 88}, - {Package{}, 36, 72}, + {Package{}, 44, 88}, {_TypeSet{}, 28, 56}, } for _, test := range tests { diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 3ecc80f161..bef851f423 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -126,6 +126,20 @@ const ( exact ) +func (m unifyMode) String() string { + switch m { + case 0: + return "inexact" + case assign: + return "assign" + case exact: + return "exact" + case assign | exact: + return "assign, exact" + } + return fmt.Sprintf("mode %d", m) +} + // unify attempts to unify x and y and reports whether it succeeded. // As a side-effect, types may be inferred for type parameters. // The mode parameter controls how types are compared. @@ -258,6 +272,15 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type { return list } +// asInterface returns the underlying type of x as an interface if +// it is a non-type parameter interface. Otherwise it returns nil. +func asInterface(x Type) (i *Interface) { + if _, ok := x.(*TypeParam); !ok { + i, _ = under(x).(*Interface) + } + return i +} + // nify implements the core unification algorithm which is an // adapted version of Checker.identical. For changes to that // code the corresponding changes should be made here. @@ -265,7 +288,7 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type { func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { u.depth++ if traceInference { - u.tracef("%s ≡ %s (mode %d)", x, y, mode) + u.tracef("%s ≡ %s\t// %s", x, y, mode) } defer func() { if traceInference && !result { @@ -296,7 +319,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // - type parameter recorded with u, make sure one is in x if _, ok := x.(*Named); ok || u.asTypeParam(y) != nil { if traceInference { - u.tracef("%s ≡ %s (swap)", y, x) + u.tracef("%s ≡ %s\t// swap", y, x) } x, y = y, x } @@ -352,11 +375,49 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { if x := u.at(px); x != nil { // x has an inferred type which must match y if u.nify(x, y, mode, p) { - // If we have a match, possibly through underlying types, - // and y is a defined type, make sure we record that type + // We have a match, possibly through underlying types. + xi := asInterface(x) + yi := asInterface(y) + _, xn := x.(*Named) + _, yn := y.(*Named) + // If we have two interfaces, what to do depends on + // whether they are named and their method sets. + if xi != nil && yi != nil { + // Both types are interfaces. + // If both types are defined types, they must be identical + // because unification doesn't know which type has the "right" name. + if xn && yn { + return Identical(x, y) + } + // In all other cases, the method sets must match. + // The types unified so we know that corresponding methods + // match and we can simply compare the number of methods. + // TODO(gri) We may be able to relax this rule and select + // the more general interface. But if one of them is a defined + // type, it's not clear how to choose and whether we introduce + // an order dependency or not. Requiring the same method set + // is conservative. + if len(xi.typeSet().methods) != len(yi.typeSet().methods) { + return false + } + } else if xi != nil || yi != nil { + // One but not both of them are interfaces. + // In this case, either x or y could be viable matches for the corresponding + // type parameter, which means choosing either introduces an order dependence. + // Therefore, we must fail unification (go.dev/issue/60933). + return false + } + // If y is a defined type, make sure we record that type // for type parameter x, which may have until now only // recorded an underlying type (go.dev/issue/43056). - if _, ok := y.(*Named); ok { + // Either both types are interfaces, or neither type is. + // If both are interfaces, they have the same methods. + // + // Note: Changing the recorded type for a type parameter to + // a defined type is only ok when unification is inexact. + // But in exact unification, if we have a match, x and y must + // be identical, so changing the recorded type for x is a no-op. + if yn { u.set(px, y) } return true @@ -386,14 +447,8 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { if enableInterfaceInference && mode&exact == 0 { // One or both interfaces may be defined types. // Look under the name, but not under type parameters (go.dev/issue/60564). - var xi *Interface - if _, ok := x.(*TypeParam); !ok { - xi, _ = under(x).(*Interface) - } - var yi *Interface - if _, ok := y.(*TypeParam); !ok { - yi, _ = under(y).(*Interface) - } + xi := asInterface(x) + yi := asInterface(y) // If we have two interfaces, check the type terms for equivalence, // and unify common methods if possible. if xi != nil && yi != nil { @@ -494,7 +549,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // TODO(gri) Factor out type parameter handling from the switch. if isTypeParam(y) { if traceInference { - u.tracef("%s ≡ %s (swap)", y, x) + u.tracef("%s ≡ %s\t// swap", y, x) } x, y = y, x } diff --git a/src/go/types/version.go b/src/go/types/version.go index 07a42a79ee..108d9b34a0 100644 --- a/src/go/types/version.go +++ b/src/go/types/version.go @@ -5,7 +5,6 @@ package types import ( - "errors" "fmt" "go/ast" "go/token" @@ -45,23 +44,24 @@ var ( go1_21 = version{1, 21} ) -var errVersionSyntax = errors.New("invalid Go version syntax") - // parseGoVersion parses a Go version string (such as "go1.12") // and returns the version, or an error. If s is the empty // string, the version is 0.0. func parseGoVersion(s string) (v version, err error) { + bad := func() (version, error) { + return version{}, fmt.Errorf("invalid Go version syntax %q", s) + } if s == "" { return } if !strings.HasPrefix(s, "go") { - return version{}, errVersionSyntax + return bad() } s = s[len("go"):] i := 0 for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { if i >= 10 || i == 0 && s[i] == '0' { - return version{}, errVersionSyntax + return bad() } v.major = 10*v.major + int(s[i]) - '0' } @@ -69,7 +69,7 @@ func parseGoVersion(s string) (v version, err error) { return } if i == 0 || s[i] != '.' { - return version{}, errVersionSyntax + return bad() } s = s[i+1:] if s == "0" { @@ -82,14 +82,15 @@ func parseGoVersion(s string) (v version, err error) { i = 0 for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { if i >= 10 || i == 0 && s[i] == '0' { - return version{}, errVersionSyntax + return bad() } v.minor = 10*v.minor + int(s[i]) - '0' } - if i > 0 && i == len(s) { - return - } - return version{}, errVersionSyntax + // Accept any suffix after the minor number. + // We are only looking for the language version (major.minor) + // but want to accept any valid Go version, like go1.21.0 + // and go1.21rc2. + return } // langCompat reports an error if the representation of a numeric diff --git a/src/go/types/version_test.go b/src/go/types/version_test.go new file mode 100644 index 0000000000..d25f7f5e67 --- /dev/null +++ b/src/go/types/version_test.go @@ -0,0 +1,26 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. + +// Copyright 2023 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 types + +import "testing" + +var parseGoVersionTests = []struct { + in string + out version +}{ + {"go1.21", version{1, 21}}, + {"go1.21.0", version{1, 21}}, + {"go1.21rc2", version{1, 21}}, +} + +func TestParseGoVersion(t *testing.T) { + for _, tt := range parseGoVersionTests { + if out, err := parseGoVersion(tt.in); out != tt.out || err != nil { + t.Errorf("parseGoVersion(%q) = %v, %v, want %v, nil", tt.in, out, err, tt.out) + } + } +} diff --git a/src/internal/abi/funcpc.go b/src/internal/abi/funcpc.go index 4db848ee15..e038d36584 100644 --- a/src/internal/abi/funcpc.go +++ b/src/internal/abi/funcpc.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !gccgo + package abi // FuncPC* intrinsics. diff --git a/src/internal/abi/funcpc_gccgo.go b/src/internal/abi/funcpc_gccgo.go new file mode 100644 index 0000000000..ad5fa52c54 --- /dev/null +++ b/src/internal/abi/funcpc_gccgo.go @@ -0,0 +1,21 @@ +// Copyright 2023 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. + +// For bootstrapping with gccgo. + +//go:build gccgo + +package abi + +import "unsafe" + +func FuncPCABI0(f interface{}) uintptr { + words := (*[2]unsafe.Pointer)(unsafe.Pointer(&f)) + return *(*uintptr)(unsafe.Pointer(words[1])) +} + +func FuncPCABIInternal(f interface{}) uintptr { + words := (*[2]unsafe.Pointer)(unsafe.Pointer(&f)) + return *(*uintptr)(unsafe.Pointer(words[1])) +} diff --git a/src/internal/bytealg/equal_riscv64.s b/src/internal/bytealg/equal_riscv64.s index 3834083ec9..503aac5751 100644 --- a/src/internal/bytealg/equal_riscv64.s +++ b/src/internal/bytealg/equal_riscv64.s @@ -37,6 +37,8 @@ TEXT memequal<>(SB),NOSPLIT|NOFRAME,$0 BEQZ X9, loop32_check // Check one byte at a time until we reach 8 byte alignment. + SUB X9, X0, X9 + ADD $8, X9, X9 SUB X9, X12, X12 align: ADD $-1, X9 diff --git a/src/internal/fuzz/counters_unsupported.go b/src/internal/fuzz/counters_unsupported.go index 028065ce30..287bb4bd3c 100644 --- a/src/internal/fuzz/counters_unsupported.go +++ b/src/internal/fuzz/counters_unsupported.go @@ -6,7 +6,7 @@ // the instrumentation is OS specific, but only amd64 and arm64 are // supported in the runtime. See src/runtime/libfuzzer*. // -// If you update this constraint, also update internal/platform.FuzzInstrumeted. +// If you update this constraint, also update internal/platform.FuzzInstrumented. // //go:build !((darwin || linux || windows || freebsd) && (amd64 || arm64)) diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go index 0fdd146b24..243f9efce1 100644 --- a/src/internal/godebugs/table.go +++ b/src/internal/godebugs/table.go @@ -37,6 +37,7 @@ var All = []Info{ //{Name: "multipartfiles", Package: "mime/multipart"}, {Name: "multipartmaxheaders", Package: "mime/multipart"}, {Name: "multipartmaxparts", Package: "mime/multipart"}, + {Name: "multipathtcp", Package: "net"}, {Name: "netdns", Package: "net", Opaque: true}, {Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"}, {Name: "randautoseed", Package: "math/rand"}, diff --git a/src/internal/platform/supported.go b/src/internal/platform/supported.go index e762bb304e..230a952d2d 100644 --- a/src/internal/platform/supported.go +++ b/src/internal/platform/supported.go @@ -2,8 +2,19 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:generate go test . -run=TestGenerated -fix + package platform +// An OSArch is a pair of GOOS and GOARCH values indicating a platform. +type OSArch struct { + GOOS, GOARCH string +} + +func (p OSArch) String() string { + return p.GOOS + "/" + p.GOARCH +} + // RaceDetectorSupported reports whether goos/goarch supports the race // detector. There is a copy of this function in cmd/dist/test.go. // Race detector only supports 48-bit VMA on arm64. But it will always @@ -123,11 +134,11 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { return true } - platform := goos + "/" + goarch - if _, ok := osArchSupportsCgo[platform]; !ok { + if _, ok := distInfo[OSArch{goos, goarch}]; !ok { return false // platform unrecognized } + platform := goos + "/" + goarch switch buildmode { case "archive": return true @@ -239,11 +250,6 @@ func DefaultPIE(goos, goarch string, isRace bool) bool { return false } -// CgoSupported reports whether goos/goarch supports cgo. -func CgoSupported(goos, goarch string) bool { - return osArchSupportsCgo[goos+"/"+goarch] -} - // ExecutableHasDWARF reports whether the linked executable includes DWARF // symbols on goos/goarch. func ExecutableHasDWARF(goos, goarch string) bool { @@ -253,3 +259,28 @@ func ExecutableHasDWARF(goos, goarch string) bool { } return true } + +// osArchInfo describes information about an OSArch extracted from cmd/dist and +// stored in the generated distInfo map. +type osArchInfo struct { + CgoSupported bool + FirstClass bool + Broken bool +} + +// CgoSupported reports whether goos/goarch supports cgo. +func CgoSupported(goos, goarch string) bool { + return distInfo[OSArch{goos, goarch}].CgoSupported +} + +// FirstClass reports whether goos/goarch is considered a “first class” port. +// (See https://go.dev/wiki/PortingPolicy#first-class-ports.) +func FirstClass(goos, goarch string) bool { + return distInfo[OSArch{goos, goarch}].FirstClass +} + +// Broken reportsr whether goos/goarch is considered a broken port. +// (See https://go.dev/wiki/PortingPolicy#broken-ports.) +func Broken(goos, goarch string) bool { + return distInfo[OSArch{goos, goarch}].Broken +} diff --git a/src/internal/platform/zosarch.go b/src/internal/platform/zosarch.go new file mode 100644 index 0000000000..7f5a290332 --- /dev/null +++ b/src/internal/platform/zosarch.go @@ -0,0 +1,114 @@ +// Code generated by go test internal/platform -fix. DO NOT EDIT. + +// To change the information in this file, edit the cgoEnabled and/or firstClass +// maps in cmd/dist/build.go, then run 'go generate internal/platform'. + +package platform + +// List is the list of all valid GOOS/GOARCH combinations, +// including known-broken ports. +var List = []OSArch{ + {"aix", "ppc64"}, + {"android", "386"}, + {"android", "amd64"}, + {"android", "arm"}, + {"android", "arm64"}, + {"darwin", "amd64"}, + {"darwin", "arm64"}, + {"dragonfly", "amd64"}, + {"freebsd", "386"}, + {"freebsd", "amd64"}, + {"freebsd", "arm"}, + {"freebsd", "arm64"}, + {"freebsd", "riscv64"}, + {"illumos", "amd64"}, + {"ios", "amd64"}, + {"ios", "arm64"}, + {"js", "wasm"}, + {"linux", "386"}, + {"linux", "amd64"}, + {"linux", "arm"}, + {"linux", "arm64"}, + {"linux", "loong64"}, + {"linux", "mips"}, + {"linux", "mips64"}, + {"linux", "mips64le"}, + {"linux", "mipsle"}, + {"linux", "ppc64"}, + {"linux", "ppc64le"}, + {"linux", "riscv64"}, + {"linux", "s390x"}, + {"linux", "sparc64"}, + {"netbsd", "386"}, + {"netbsd", "amd64"}, + {"netbsd", "arm"}, + {"netbsd", "arm64"}, + {"openbsd", "386"}, + {"openbsd", "amd64"}, + {"openbsd", "arm"}, + {"openbsd", "arm64"}, + {"openbsd", "mips64"}, + {"openbsd", "ppc64"}, + {"plan9", "386"}, + {"plan9", "amd64"}, + {"plan9", "arm"}, + {"solaris", "amd64"}, + {"wasip1", "wasm"}, + {"windows", "386"}, + {"windows", "amd64"}, + {"windows", "arm"}, + {"windows", "arm64"}, +} + +var distInfo = map[OSArch]osArchInfo{ + {"aix", "ppc64"}: {CgoSupported: true}, + {"android", "386"}: {CgoSupported: true}, + {"android", "amd64"}: {CgoSupported: true}, + {"android", "arm"}: {CgoSupported: true}, + {"android", "arm64"}: {CgoSupported: true}, + {"darwin", "amd64"}: {CgoSupported: true, FirstClass: true}, + {"darwin", "arm64"}: {CgoSupported: true, FirstClass: true}, + {"dragonfly", "amd64"}: {CgoSupported: true}, + {"freebsd", "386"}: {CgoSupported: true}, + {"freebsd", "amd64"}: {CgoSupported: true}, + {"freebsd", "arm"}: {CgoSupported: true}, + {"freebsd", "arm64"}: {CgoSupported: true}, + {"freebsd", "riscv64"}: {CgoSupported: true}, + {"illumos", "amd64"}: {CgoSupported: true}, + {"ios", "amd64"}: {CgoSupported: true}, + {"ios", "arm64"}: {CgoSupported: true}, + {"js", "wasm"}: {}, + {"linux", "386"}: {CgoSupported: true, FirstClass: true}, + {"linux", "amd64"}: {CgoSupported: true, FirstClass: true}, + {"linux", "arm"}: {CgoSupported: true, FirstClass: true}, + {"linux", "arm64"}: {CgoSupported: true, FirstClass: true}, + {"linux", "loong64"}: {CgoSupported: true}, + {"linux", "mips"}: {CgoSupported: true}, + {"linux", "mips64"}: {CgoSupported: true}, + {"linux", "mips64le"}: {CgoSupported: true}, + {"linux", "mipsle"}: {CgoSupported: true}, + {"linux", "ppc64"}: {}, + {"linux", "ppc64le"}: {CgoSupported: true}, + {"linux", "riscv64"}: {CgoSupported: true}, + {"linux", "s390x"}: {CgoSupported: true}, + {"linux", "sparc64"}: {CgoSupported: true, Broken: true}, + {"netbsd", "386"}: {CgoSupported: true}, + {"netbsd", "amd64"}: {CgoSupported: true}, + {"netbsd", "arm"}: {CgoSupported: true}, + {"netbsd", "arm64"}: {CgoSupported: true}, + {"openbsd", "386"}: {CgoSupported: true}, + {"openbsd", "amd64"}: {CgoSupported: true}, + {"openbsd", "arm"}: {CgoSupported: true}, + {"openbsd", "arm64"}: {CgoSupported: true}, + {"openbsd", "mips64"}: {CgoSupported: true, Broken: true}, + {"openbsd", "ppc64"}: {Broken: true}, + {"plan9", "386"}: {}, + {"plan9", "amd64"}: {}, + {"plan9", "arm"}: {}, + {"solaris", "amd64"}: {CgoSupported: true}, + {"wasip1", "wasm"}: {}, + {"windows", "386"}: {CgoSupported: true, FirstClass: true}, + {"windows", "amd64"}: {CgoSupported: true, FirstClass: true}, + {"windows", "arm"}: {}, + {"windows", "arm64"}: {CgoSupported: true}, +} diff --git a/src/internal/platform/zosarch_test.go b/src/internal/platform/zosarch_test.go new file mode 100644 index 0000000000..e8ffe9e75d --- /dev/null +++ b/src/internal/platform/zosarch_test.go @@ -0,0 +1,109 @@ +// Copyright 2023 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 platform_test + +import ( + "bytes" + "encoding/json" + "flag" + "internal/diff" + "internal/testenv" + "os" + "os/exec" + "testing" + "text/template" +) + +var flagFix = flag.Bool("fix", false, "if true, fix out-of-date generated files") + +// TestGenerated verifies that zosarch.go is up to date, +// or regenerates it if the -fix flag is set. +func TestGenerated(t *testing.T) { + testenv.MustHaveGoRun(t) + + // Here we use 'go run cmd/dist' instead of 'go tool dist' in case the + // installed cmd/dist is stale or missing. We don't want to miss a + // skew in the data due to a stale binary. + cmd := testenv.Command(t, "go", "run", "cmd/dist", "list", "-json", "-broken") + + // cmd/dist requires GOROOT to be set explicitly in the environment. + cmd.Env = append(cmd.Environ(), "GOROOT="+testenv.GOROOT(t)) + + out, err := cmd.Output() + if err != nil { + if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 { + t.Logf("stderr:\n%s", ee.Stderr) + } + t.Fatalf("%v: %v", cmd, err) + } + + type listEntry struct { + GOOS, GOARCH string + CgoSupported bool + FirstClass bool + Broken bool + } + var entries []listEntry + if err := json.Unmarshal(out, &entries); err != nil { + t.Fatal(err) + } + + tmplOut := new(bytes.Buffer) + tmpl := template.Must(template.New("zosarch").Parse(zosarchTmpl)) + err = tmpl.Execute(tmplOut, entries) + if err != nil { + t.Fatal(err) + } + + cmd = testenv.Command(t, "gofmt") + cmd.Stdin = bytes.NewReader(tmplOut.Bytes()) + want, err := cmd.Output() + if err != nil { + t.Logf("stdin:\n%s", tmplOut.Bytes()) + if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 { + t.Logf("stderr:\n%s", ee.Stderr) + } + t.Fatalf("%v: %v", cmd, err) + } + + got, err := os.ReadFile("zosarch.go") + if err == nil && bytes.Equal(got, want) { + return + } + + if !*flagFix { + if err != nil { + t.Log(err) + } else { + t.Logf("diff:\n%s", diff.Diff("zosarch.go", got, "want", want)) + } + t.Fatalf("zosarch.go is missing or out of date; to regenerate, run\ngo generate internal/platform") + } + + if err := os.WriteFile("zosarch.go", want, 0666); err != nil { + t.Fatal(err) + } +} + +const zosarchTmpl = `// Code generated by go test internal/platform -fix. DO NOT EDIT. + +// To change the information in this file, edit the cgoEnabled and/or firstClass +// maps in cmd/dist/build.go, then run 'go generate internal/platform'. + +package platform + +// List is the list of all valid GOOS/GOARCH combinations, +// including known-broken ports. +var List = []OSArch{ +{{range .}} { {{ printf "%q" .GOOS }}, {{ printf "%q" .GOARCH }} }, +{{end}} +} + +var distInfo = map[OSArch]osArchInfo { +{{range .}} { {{ printf "%q" .GOOS }}, {{ printf "%q" .GOARCH }} }: +{ {{if .CgoSupported}}CgoSupported: true, {{end}}{{if .FirstClass}}FirstClass: true, {{end}}{{if .Broken}} Broken: true, {{end}} }, +{{end}} +} +` diff --git a/src/internal/types/testdata/fixedbugs/issue60906.go b/src/internal/types/testdata/fixedbugs/issue60906.go new file mode 100644 index 0000000000..2744e89455 --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue60906.go @@ -0,0 +1,11 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func _() { + var x int + var f func() []int + _ = f /* ERROR "cannot index f" */ [x] +} diff --git a/src/internal/types/testdata/fixedbugs/issue60933.go b/src/internal/types/testdata/fixedbugs/issue60933.go new file mode 100644 index 0000000000..9b10237e5d --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue60933.go @@ -0,0 +1,67 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +import ( + "io" + "os" +) + +func g[T any](...T) {} + +// Interface and non-interface types do not match. +func _() { + var file *os.File + g(file, io /* ERROR "type io.Writer of io.Discard does not match inferred type *os.File for T" */ .Discard) + g(file, os.Stdout) +} + +func _() { + var a *os.File + var b any + g(a, a) + g(a, b /* ERROR "type any of b does not match inferred type *os.File for T" */) +} + +var writer interface { + Write(p []byte) (n int, err error) +} + +func _() { + var file *os.File + g(file, writer /* ERROR "type interface{Write(p []byte) (n int, err error)} of writer does not match inferred type *os.File for T" */) + g(writer, file /* ERROR "type *os.File of file does not match inferred type interface{Write(p []byte) (n int, err error)} for T" */) +} + +// Different named interface types do not match. +func _() { + g(io.ReadWriter(nil), io.ReadWriter(nil)) + g(io.ReadWriter(nil), io /* ERROR "does not match" */ .Writer(nil)) + g(io.Writer(nil), io /* ERROR "does not match" */ .ReadWriter(nil)) +} + +// Named and unnamed interface types match if they have the same methods. +func _() { + g(io.Writer(nil), writer) + g(io.ReadWriter(nil), writer /* ERROR "does not match" */ ) +} + +// There must be no order dependency for named and unnamed interfaces. +func f[T interface{ m(T) }](a, b T) {} + +type F interface { + m(F) +} + +func _() { + var i F + var j interface { + m(F) + } + + // order doesn't matter + f(i, j) + f(j, i) +}
\ No newline at end of file diff --git a/src/internal/types/testdata/fixedbugs/issue60946.go b/src/internal/types/testdata/fixedbugs/issue60946.go new file mode 100644 index 0000000000..a66254b6d0 --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue60946.go @@ -0,0 +1,38 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type Tn interface{ m() } +type T1 struct{} +type T2 struct{} + +func (*T1) m() {} +func (*T2) m() {} + +func g[P any](...P) {} + +func _() { + var t interface{ m() } + var tn Tn + var t1 *T1 + var t2 *T2 + + // these are ok (interface types only) + g(t, t) + g(t, tn) + g(tn, t) + g(tn, tn) + + // these are not ok (interface and non-interface types) + g(t, t1 /* ERROR "does not match" */) + g(t1, t /* ERROR "does not match" */) + g(tn, t1 /* ERROR "does not match" */) + g(t1, tn /* ERROR "does not match" */) + + g(t, t1 /* ERROR "does not match" */, t2) + g(t1, t2 /* ERROR "does not match" */, t) + g(tn, t1 /* ERROR "does not match" */, t2) + g(t1, t2 /* ERROR "does not match" */, tn) +} diff --git a/src/log/slog/attr.go b/src/log/slog/attr.go index a180d0e1d3..90e343b319 100644 --- a/src/log/slog/attr.go +++ b/src/log/slog/attr.go @@ -81,7 +81,7 @@ func argsToAttrSlice(args []any) []Attr { } // Any returns an Attr for the supplied value. -// See [Value.AnyValue] for how values are treated. +// See [AnyValue] for how values are treated. func Any(key string, value any) Attr { return Attr{key, AnyValue(value)} } diff --git a/src/log/slog/doc.go b/src/log/slog/doc.go index 8237b4e3d5..088df61c6d 100644 --- a/src/log/slog/doc.go +++ b/src/log/slog/doc.go @@ -174,9 +174,9 @@ argument, as do their corresponding top-level functions. Although the convenience methods on Logger (Info and so on) and the corresponding top-level functions do not take a context, the alternatives ending -in "Ctx" do. For example, +in "Context" do. For example, - slog.InfoCtx(ctx, "message") + slog.InfoContext(ctx, "message") It is recommended to pass a context to an output method if one is available. @@ -206,7 +206,7 @@ keys and values; this allows it, too, to avoid allocation. The call - logger.LogAttrs(nil, slog.LevelInfo, "hello", slog.Int("count", 3)) + logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) is the most efficient way to achieve the same output as @@ -255,7 +255,7 @@ and hidden fields that refer to state (such as attributes) indirectly. This means that modifying a simple copy of a Record (e.g. by calling [Record.Add] or [Record.AddAttrs] to add attributes) may have unexpected effects on the original. -Before modifying a Record, use [Clone] to +Before modifying a Record, use [Record.Clone] to create a copy that shares no state with the original, or create a new Record with [NewRecord] and build up its Attrs by traversing the old ones with [Record.Attrs]. diff --git a/src/log/slog/example_custom_levels_test.go b/src/log/slog/example_custom_levels_test.go index 2f230320bc..7351ca493b 100644 --- a/src/log/slog/example_custom_levels_test.go +++ b/src/log/slog/example_custom_levels_test.go @@ -5,6 +5,7 @@ package slog_test import ( + "context" "log/slog" "os" ) @@ -72,13 +73,14 @@ func ExampleHandlerOptions_customLevels() { }) logger := slog.New(th) - logger.Log(nil, LevelEmergency, "missing pilots") + ctx := context.Background() + logger.Log(ctx, LevelEmergency, "missing pilots") logger.Error("failed to start engines", "err", "missing fuel") logger.Warn("falling back to default value") - logger.Log(nil, LevelNotice, "all systems are running") + logger.Log(ctx, LevelNotice, "all systems are running") logger.Info("initiating launch") logger.Debug("starting background job") - logger.Log(nil, LevelTrace, "button clicked") + logger.Log(ctx, LevelTrace, "button clicked") // Output: // sev=EMERGENCY msg="missing pilots" diff --git a/src/log/slog/handler.go b/src/log/slog/handler.go index 8cd1e563eb..e479ca8a4c 100644 --- a/src/log/slog/handler.go +++ b/src/log/slog/handler.go @@ -140,7 +140,7 @@ type HandlerOptions struct { // ReplaceAttr is called to rewrite each non-group attribute before it is logged. // The attribute's value has been resolved (see [Value.Resolve]). - // If ReplaceAttr returns an Attr with Key == "", the attribute is discarded. + // If ReplaceAttr returns a zero Attr, the attribute is discarded. // // The built-in attributes with keys "time", "level", "source", and "msg" // are passed to this function, except that time is omitted @@ -221,6 +221,11 @@ func (h *commonHandler) enabled(l Level) bool { } func (h *commonHandler) withAttrs(as []Attr) *commonHandler { + // We are going to ignore empty groups, so if the entire slice consists of + // them, there is nothing to do. + if countEmptyGroups(as) == len(as) { + return h + } h2 := h.clone() // Pre-format the attributes as an optimization. state := h2.newHandleState((*buffer.Buffer)(&h2.preformattedAttrs), false, "") @@ -308,15 +313,20 @@ func (s *handleState) appendNonBuiltIns(r Record) { } // Attrs in Record -- unlike the built-in ones, they are in groups started // from WithGroup. - s.prefix.WriteString(s.h.groupPrefix) - s.openGroups() - r.Attrs(func(a Attr) bool { - s.appendAttr(a) - return true - }) + // If the record has no Attrs, don't output any groups. + nOpenGroups := s.h.nOpenGroups + if r.NumAttrs() > 0 { + s.prefix.WriteString(s.h.groupPrefix) + s.openGroups() + nOpenGroups = len(s.h.groups) + r.Attrs(func(a Attr) bool { + s.appendAttr(a) + return true + }) + } if s.h.json { // Close all open groups. - for range s.h.groups { + for range s.h.groups[:nOpenGroups] { s.buf.WriteByte('}') } // Close the top-level object. diff --git a/src/log/slog/handler_test.go b/src/log/slog/handler_test.go index 741e86a826..3fb7360fc2 100644 --- a/src/log/slog/handler_test.go +++ b/src/log/slog/handler_test.go @@ -108,8 +108,6 @@ func TestDefaultHandle(t *testing.T) { // Verify the common parts of TextHandler and JSONHandler. func TestJSONAndTextHandlers(t *testing.T) { - ctx := context.Background() - // remove all Attrs removeAll := func(_ []string, a Attr) Attr { return Attr{} } @@ -215,6 +213,28 @@ func TestJSONAndTextHandlers(t *testing.T) { wantJSON: `{"msg":"message","h":{"a":1}}`, }, { + name: "nested empty group", + replace: removeKeys(TimeKey, LevelKey), + attrs: []Attr{ + Group("g", + Group("h", + Group("i"), Group("j"))), + }, + wantText: `msg=message`, + wantJSON: `{"msg":"message"}`, + }, + { + name: "nested non-empty group", + replace: removeKeys(TimeKey, LevelKey), + attrs: []Attr{ + Group("g", + Group("h", + Group("i"), Group("j", Int("a", 1)))), + }, + wantText: `msg=message g.h.j.a=1`, + wantJSON: `{"msg":"message","g":{"h":{"j":{"a":1}}}}`, + }, + { name: "escapes", replace: removeKeys(TimeKey, LevelKey), attrs: []Attr{ @@ -282,6 +302,34 @@ func TestJSONAndTextHandlers(t *testing.T) { wantJSON: `{"msg":"message","p1":1,"s1":{"s2":{"a":"one","b":2}}}`, }, { + name: "empty with-groups", + replace: removeKeys(TimeKey, LevelKey), + with: func(h Handler) Handler { + return h.WithGroup("x").WithGroup("y") + }, + wantText: "msg=message", + wantJSON: `{"msg":"message"}`, + }, + { + name: "empty with-groups, no non-empty attrs", + replace: removeKeys(TimeKey, LevelKey), + with: func(h Handler) Handler { + return h.WithGroup("x").WithAttrs([]Attr{Group("g")}).WithGroup("y") + }, + wantText: "msg=message", + wantJSON: `{"msg":"message"}`, + }, + { + name: "one empty with-group", + replace: removeKeys(TimeKey, LevelKey), + with: func(h Handler) Handler { + return h.WithGroup("x").WithAttrs([]Attr{Int("a", 1)}).WithGroup("y") + }, + attrs: []Attr{Group("g", Group("h"))}, + wantText: "msg=message x.a=1", + wantJSON: `{"msg":"message","x":{"a":1}}`, + }, + { name: "GroupValue as Attr value", replace: removeKeys(TimeKey, LevelKey), attrs: []Attr{{"v", AnyValue(IntValue(3))}}, @@ -362,7 +410,7 @@ func TestJSONAndTextHandlers(t *testing.T) { h = test.with(h) } buf.Reset() - if err := h.Handle(ctx, r); err != nil { + if err := h.Handle(nil, r); err != nil { t.Fatal(err) } want := strings.ReplaceAll(handler.want, "$LINE", line) diff --git a/src/log/slog/json_handler_test.go b/src/log/slog/json_handler_test.go index dcfd701dd4..65130f2426 100644 --- a/src/log/slog/json_handler_test.go +++ b/src/log/slog/json_handler_test.go @@ -174,6 +174,7 @@ func BenchmarkJSONHandler(b *testing.B) { }}, } { b.Run(bench.name, func(b *testing.B) { + ctx := context.Background() l := New(NewJSONHandler(io.Discard, &bench.opts)).With( String("program", "my-test-program"), String("package", "log/slog"), @@ -182,7 +183,7 @@ func BenchmarkJSONHandler(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - l.LogAttrs(nil, LevelInfo, "this is a typical log message", + l.LogAttrs(ctx, LevelInfo, "this is a typical log message", String("module", "github.com/google/go-cmp"), String("version", "v1.23.4"), Int("count", 23), @@ -238,12 +239,13 @@ func BenchmarkPreformatting(b *testing.B) { {"struct", io.Discard, structAttrs}, {"struct file", outFile, structAttrs}, } { + ctx := context.Background() b.Run(bench.name, func(b *testing.B) { l := New(NewJSONHandler(bench.wc, nil)).With(bench.attrs...) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - l.LogAttrs(nil, LevelInfo, "this is a typical log message", + l.LogAttrs(ctx, LevelInfo, "this is a typical log message", String("module", "github.com/google/go-cmp"), String("version", "v1.23.4"), Int("count", 23), diff --git a/src/log/slog/logger.go b/src/log/slog/logger.go index 2bad5dfccc..a068085f47 100644 --- a/src/log/slog/logger.go +++ b/src/log/slog/logger.go @@ -165,41 +165,41 @@ func (l *Logger) LogAttrs(ctx context.Context, level Level, msg string, attrs .. // Debug logs at LevelDebug. func (l *Logger) Debug(msg string, args ...any) { - l.log(nil, LevelDebug, msg, args...) + l.log(context.Background(), LevelDebug, msg, args...) } -// DebugCtx logs at LevelDebug with the given context. -func (l *Logger) DebugCtx(ctx context.Context, msg string, args ...any) { +// DebugContext logs at LevelDebug with the given context. +func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) { l.log(ctx, LevelDebug, msg, args...) } // Info logs at LevelInfo. func (l *Logger) Info(msg string, args ...any) { - l.log(nil, LevelInfo, msg, args...) + l.log(context.Background(), LevelInfo, msg, args...) } -// InfoCtx logs at LevelInfo with the given context. -func (l *Logger) InfoCtx(ctx context.Context, msg string, args ...any) { +// InfoContext logs at LevelInfo with the given context. +func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) { l.log(ctx, LevelInfo, msg, args...) } // Warn logs at LevelWarn. func (l *Logger) Warn(msg string, args ...any) { - l.log(nil, LevelWarn, msg, args...) + l.log(context.Background(), LevelWarn, msg, args...) } -// WarnCtx logs at LevelWarn with the given context. -func (l *Logger) WarnCtx(ctx context.Context, msg string, args ...any) { +// WarnContext logs at LevelWarn with the given context. +func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) { l.log(ctx, LevelWarn, msg, args...) } // Error logs at LevelError. func (l *Logger) Error(msg string, args ...any) { - l.log(nil, LevelError, msg, args...) + l.log(context.Background(), LevelError, msg, args...) } -// ErrorCtx logs at LevelError with the given context. -func (l *Logger) ErrorCtx(ctx context.Context, msg string, args ...any) { +// ErrorContext logs at LevelError with the given context. +func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any) { l.log(ctx, LevelError, msg, args...) } @@ -247,41 +247,41 @@ func (l *Logger) logAttrs(ctx context.Context, level Level, msg string, attrs .. // Debug calls Logger.Debug on the default logger. func Debug(msg string, args ...any) { - Default().log(nil, LevelDebug, msg, args...) + Default().log(context.Background(), LevelDebug, msg, args...) } -// DebugCtx calls Logger.DebugCtx on the default logger. -func DebugCtx(ctx context.Context, msg string, args ...any) { +// DebugContext calls Logger.DebugContext on the default logger. +func DebugContext(ctx context.Context, msg string, args ...any) { Default().log(ctx, LevelDebug, msg, args...) } // Info calls Logger.Info on the default logger. func Info(msg string, args ...any) { - Default().log(nil, LevelInfo, msg, args...) + Default().log(context.Background(), LevelInfo, msg, args...) } -// InfoCtx calls Logger.InfoCtx on the default logger. -func InfoCtx(ctx context.Context, msg string, args ...any) { +// InfoContext calls Logger.InfoContext on the default logger. +func InfoContext(ctx context.Context, msg string, args ...any) { Default().log(ctx, LevelInfo, msg, args...) } // Warn calls Logger.Warn on the default logger. func Warn(msg string, args ...any) { - Default().log(nil, LevelWarn, msg, args...) + Default().log(context.Background(), LevelWarn, msg, args...) } -// WarnCtx calls Logger.WarnCtx on the default logger. -func WarnCtx(ctx context.Context, msg string, args ...any) { +// WarnContext calls Logger.WarnContext on the default logger. +func WarnContext(ctx context.Context, msg string, args ...any) { Default().log(ctx, LevelWarn, msg, args...) } // Error calls Logger.Error on the default logger. func Error(msg string, args ...any) { - Default().log(nil, LevelError, msg, args...) + Default().log(context.Background(), LevelError, msg, args...) } -// ErrorCtx calls Logger.ErrorCtx on the default logger. -func ErrorCtx(ctx context.Context, msg string, args ...any) { +// ErrorContext calls Logger.ErrorContext on the default logger. +func ErrorContext(ctx context.Context, msg string, args ...any) { Default().log(ctx, LevelError, msg, args...) } diff --git a/src/log/slog/logger_test.go b/src/log/slog/logger_test.go index d151c0490c..2f5b31939c 100644 --- a/src/log/slog/logger_test.go +++ b/src/log/slog/logger_test.go @@ -25,6 +25,7 @@ import ( const timeRE = `\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}(Z|[+-]\d{2}:\d{2})` func TestLogTextHandler(t *testing.T) { + ctx := context.Background() var buf bytes.Buffer l := New(NewTextHandler(&buf, nil)) @@ -51,10 +52,10 @@ func TestLogTextHandler(t *testing.T) { l.Error("bad", "a", 1) check(`level=ERROR msg=bad a=1`) - l.Log(nil, LevelWarn+1, "w", Int("a", 1), String("b", "two")) + l.Log(ctx, LevelWarn+1, "w", Int("a", 1), String("b", "two")) check(`level=WARN\+1 msg=w a=1 b=two`) - l.LogAttrs(nil, LevelInfo+1, "a b c", Int("a", 1), String("b", "two")) + l.LogAttrs(ctx, LevelInfo+1, "a b c", Int("a", 1), String("b", "two")) check(`level=INFO\+1 msg="a b c" a=1 b=two`) l.Info("info", "a", []Attr{Int("i", 1)}) @@ -106,7 +107,7 @@ func TestConnections(t *testing.T) { // log.Logger's output goes through the handler. SetDefault(New(NewTextHandler(&slogbuf, &HandlerOptions{AddSource: true}))) log.Print("msg2") - checkLogOutput(t, slogbuf.String(), "time="+timeRE+` level=INFO source=.*logger_test.go:\d{3} msg=msg2`) + checkLogOutput(t, slogbuf.String(), "time="+timeRE+` level=INFO source=.*logger_test.go:\d{3}"? msg=msg2`) // The default log.Logger always outputs at Info level. slogbuf.Reset() @@ -156,6 +157,7 @@ func TestAttrs(t *testing.T) { } func TestCallDepth(t *testing.T) { + ctx := context.Background() h := &captureHandler{} var startLine int @@ -181,9 +183,9 @@ func TestCallDepth(t *testing.T) { startLine = f.Line + 4 // Do not change the number of lines between here and the call to check(0). - logger.Log(nil, LevelInfo, "") + logger.Log(ctx, LevelInfo, "") check(0) - logger.LogAttrs(nil, LevelInfo, "") + logger.LogAttrs(ctx, LevelInfo, "") check(1) logger.Debug("") check(2) @@ -201,13 +203,14 @@ func TestCallDepth(t *testing.T) { check(8) Error("") check(9) - Log(nil, LevelInfo, "") + Log(ctx, LevelInfo, "") check(10) - LogAttrs(nil, LevelInfo, "") + LogAttrs(ctx, LevelInfo, "") check(11) } func TestAlloc(t *testing.T) { + ctx := context.Background() dl := New(discardHandler{}) defer SetDefault(Default()) // restore SetDefault(dl) @@ -222,7 +225,7 @@ func TestAlloc(t *testing.T) { wantAllocs(t, 0, func() { dl.Info("hello") }) }) t.Run("logger.Log", func(t *testing.T) { - wantAllocs(t, 0, func() { dl.Log(nil, LevelDebug, "hello") }) + wantAllocs(t, 0, func() { dl.Log(ctx, LevelDebug, "hello") }) }) t.Run("2 pairs", func(t *testing.T) { s := "abc" @@ -239,7 +242,7 @@ func TestAlloc(t *testing.T) { s := "abc" i := 2000 wantAllocs(t, 2, func() { - l.Log(nil, LevelInfo, "hello", + l.Log(ctx, LevelInfo, "hello", "n", i, "s", s, ) @@ -250,8 +253,8 @@ func TestAlloc(t *testing.T) { s := "abc" i := 2000 wantAllocs(t, 0, func() { - if l.Enabled(nil, LevelInfo) { - l.Log(nil, LevelInfo, "hello", + if l.Enabled(ctx, LevelInfo) { + l.Log(ctx, LevelInfo, "hello", "n", i, "s", s, ) @@ -273,30 +276,30 @@ func TestAlloc(t *testing.T) { wantAllocs(t, 0, func() { dl.Info("", "error", io.EOF) }) }) t.Run("attrs1", func(t *testing.T) { - wantAllocs(t, 0, func() { dl.LogAttrs(nil, LevelInfo, "", Int("a", 1)) }) - wantAllocs(t, 0, func() { dl.LogAttrs(nil, LevelInfo, "", Any("error", io.EOF)) }) + wantAllocs(t, 0, func() { dl.LogAttrs(ctx, LevelInfo, "", Int("a", 1)) }) + wantAllocs(t, 0, func() { dl.LogAttrs(ctx, LevelInfo, "", Any("error", io.EOF)) }) }) t.Run("attrs3", func(t *testing.T) { wantAllocs(t, 0, func() { - dl.LogAttrs(nil, LevelInfo, "hello", Int("a", 1), String("b", "two"), Duration("c", time.Second)) + dl.LogAttrs(ctx, LevelInfo, "hello", Int("a", 1), String("b", "two"), Duration("c", time.Second)) }) }) t.Run("attrs3 disabled", func(t *testing.T) { logger := New(discardHandler{disabled: true}) wantAllocs(t, 0, func() { - logger.LogAttrs(nil, LevelInfo, "hello", Int("a", 1), String("b", "two"), Duration("c", time.Second)) + logger.LogAttrs(ctx, LevelInfo, "hello", Int("a", 1), String("b", "two"), Duration("c", time.Second)) }) }) t.Run("attrs6", func(t *testing.T) { wantAllocs(t, 1, func() { - dl.LogAttrs(nil, LevelInfo, "hello", + dl.LogAttrs(ctx, LevelInfo, "hello", Int("a", 1), String("b", "two"), Duration("c", time.Second), Int("d", 1), String("e", "two"), Duration("f", time.Second)) }) }) t.Run("attrs9", func(t *testing.T) { wantAllocs(t, 1, func() { - dl.LogAttrs(nil, LevelInfo, "hello", + dl.LogAttrs(ctx, LevelInfo, "hello", Int("a", 1), String("b", "two"), Duration("c", time.Second), Int("d", 1), String("e", "two"), Duration("f", time.Second), Int("d", 1), String("e", "two"), Duration("f", time.Second)) @@ -395,14 +398,14 @@ func TestContext(t *testing.T) { f func(context.Context, string, ...any) wantLevel Level }{ - {l.DebugCtx, LevelDebug}, - {l.InfoCtx, LevelInfo}, - {l.WarnCtx, LevelWarn}, - {l.ErrorCtx, LevelError}, - {DebugCtx, LevelDebug}, - {InfoCtx, LevelInfo}, - {WarnCtx, LevelWarn}, - {ErrorCtx, LevelError}, + {l.DebugContext, LevelDebug}, + {l.InfoContext, LevelInfo}, + {l.WarnContext, LevelWarn}, + {l.ErrorContext, LevelError}, + {DebugContext, LevelDebug}, + {InfoContext, LevelInfo}, + {WarnContext, LevelWarn}, + {ErrorContext, LevelError}, } { h.clear() ctx := context.WithValue(context.Background(), "L", test.wantLevel) @@ -511,27 +514,27 @@ func BenchmarkNopLog(b *testing.B) { b.Run("no attrs", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - l.LogAttrs(nil, LevelInfo, "msg") + l.LogAttrs(ctx, LevelInfo, "msg") } }) b.Run("attrs", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - l.LogAttrs(nil, LevelInfo, "msg", Int("a", 1), String("b", "two"), Bool("c", true)) + l.LogAttrs(ctx, LevelInfo, "msg", Int("a", 1), String("b", "two"), Bool("c", true)) } }) b.Run("attrs-parallel", func(b *testing.B) { b.ReportAllocs() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - l.LogAttrs(nil, LevelInfo, "msg", Int("a", 1), String("b", "two"), Bool("c", true)) + l.LogAttrs(ctx, LevelInfo, "msg", Int("a", 1), String("b", "two"), Bool("c", true)) } }) }) b.Run("keys-values", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - l.Log(nil, LevelInfo, "msg", "a", 1, "b", "two", "c", true) + l.Log(ctx, LevelInfo, "msg", "a", 1, "b", "two", "c", true) } }) b.Run("WithContext", func(b *testing.B) { diff --git a/src/log/slog/record.go b/src/log/slog/record.go index 972552d519..67b76f34e1 100644 --- a/src/log/slog/record.go +++ b/src/log/slog/record.go @@ -93,9 +93,17 @@ func (r Record) Attrs(f func(Attr) bool) { } // AddAttrs appends the given Attrs to the Record's list of Attrs. +// It omits empty groups. func (r *Record) AddAttrs(attrs ...Attr) { - n := copy(r.front[r.nFront:], attrs) - r.nFront += n + var i int + for i = 0; i < len(attrs) && r.nFront < len(r.front); i++ { + a := attrs[i] + if a.Value.isEmptyGroup() { + continue + } + r.front[r.nFront] = a + r.nFront++ + } // Check if a copy was modified by slicing past the end // and seeing if the Attr there is non-zero. if cap(r.back) > len(r.back) { @@ -104,15 +112,25 @@ func (r *Record) AddAttrs(attrs ...Attr) { panic("copies of a slog.Record were both modified") } } - r.back = append(r.back, attrs[n:]...) + ne := countEmptyGroups(attrs[i:]) + r.back = slices.Grow(r.back, len(attrs[i:])-ne) + for _, a := range attrs[i:] { + if !a.Value.isEmptyGroup() { + r.back = append(r.back, a) + } + } } // Add converts the args to Attrs as described in [Logger.Log], // then appends the Attrs to the Record's list of Attrs. +// It omits empty groups. func (r *Record) Add(args ...any) { var a Attr for len(args) > 0 { a, args = argsToAttr(args) + if a.Value.isEmptyGroup() { + continue + } if r.nFront < len(r.front) { r.front[r.nFront] = a r.nFront++ diff --git a/src/log/slog/value.go b/src/log/slog/value.go index 71a59d2639..224848f695 100644 --- a/src/log/slog/value.go +++ b/src/log/slog/value.go @@ -164,9 +164,32 @@ func DurationValue(v time.Duration) Value { // GroupValue returns a new Value for a list of Attrs. // The caller must not subsequently mutate the argument slice. func GroupValue(as ...Attr) Value { + // Remove empty groups. + // It is simpler overall to do this at construction than + // to check each Group recursively for emptiness. + if n := countEmptyGroups(as); n > 0 { + as2 := make([]Attr, 0, len(as)-n) + for _, a := range as { + if !a.Value.isEmptyGroup() { + as2 = append(as2, a) + } + } + as = as2 + } return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))} } +// countEmptyGroups returns the number of empty group values in its argument. +func countEmptyGroups(as []Attr) int { + n := 0 + for _, a := range as { + if a.Value.isEmptyGroup() { + n++ + } + } + return n +} + // AnyValue returns a Value for the supplied value. // // If the supplied value is of type Value, it is returned @@ -399,6 +422,17 @@ func (v Value) Equal(w Value) bool { } } +// isEmptyGroup reports whether v is a group that has no attributes. +func (v Value) isEmptyGroup() bool { + if v.Kind() != KindGroup { + return false + } + // We do not need to recursively examine the group's Attrs for emptiness, + // because GroupValue removed them when the group was constructed, and + // groups are immutable. + return len(v.group()) == 0 +} + // append appends a text representation of v to dst. // v is formatted as with fmt.Sprint. func (v Value) append(dst []byte) []byte { diff --git a/src/log/slog/value_test.go b/src/log/slog/value_test.go index 615bed79d9..923a4e0ccc 100644 --- a/src/log/slog/value_test.go +++ b/src/log/slog/value_test.go @@ -229,6 +229,18 @@ func TestZeroTime(t *testing.T) { } } +func TestEmptyGroup(t *testing.T) { + g := GroupValue( + Int("a", 1), + Group("g1", Group("g2")), + Group("g3", Group("g4", Int("b", 2)))) + got := g.Group() + want := []Attr{Int("a", 1), Group("g3", Group("g4", Int("b", 2)))} + if !attrsEqual(got, want) { + t.Errorf("\ngot %v\nwant %v", got, want) + } +} + type replace struct { v Value } diff --git a/src/maps/example_test.go b/src/maps/example_test.go new file mode 100644 index 0000000000..779c66dcef --- /dev/null +++ b/src/maps/example_test.go @@ -0,0 +1,45 @@ +// Copyright 2023 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 maps_test + +import ( + "fmt" + "maps" + "strings" +) + +func ExampleDeleteFunc() { + m := map[string]int{ + "one": 1, + "two": 2, + "three": 3, + "four": 4, + } + maps.DeleteFunc(m, func(k string, v int) bool { + return v%2 != 0 // delete odd values + }) + fmt.Println(m) + // Output: + // map[four:4 two:2] +} + +func ExampleEqualFunc() { + m1 := map[int]string{ + 1: "one", + 10: "Ten", + 1000: "THOUSAND", + } + m2 := map[int][]byte{ + 1: []byte("One"), + 10: []byte("Ten"), + 1000: []byte("Thousand"), + } + eq := maps.EqualFunc(m1, m2, func(v1 string, v2 []byte) bool { + return strings.ToLower(v1) == strings.ToLower(string(v2)) + }) + fmt.Println(eq) + // Output: + // true +} diff --git a/src/math/all_test.go b/src/math/all_test.go index 886267bc17..af3c38c2a6 100644 --- a/src/math/all_test.go +++ b/src/math/all_test.go @@ -2059,6 +2059,9 @@ var fmaC = []struct{ x, y, z, want float64 }{ // Special {0, 0, 0, 0}, + {Copysign(0, -1), 0, 0, 0}, + {0, 0, Copysign(0, -1), 0}, + {Copysign(0, -1), 0, Copysign(0, -1), Copysign(0, -1)}, {-1.1754226043408471e-38, NaN(), Inf(0), NaN()}, {0, 0, 2.22507385643494e-308, 2.22507385643494e-308}, {-8.65697792e+09, NaN(), -7.516192799999999e+09, NaN()}, @@ -2077,6 +2080,10 @@ var fmaC = []struct{ x, y, z, want float64 }{ {4.612811918325842e+18, 1.4901161193847641e-08, 2.6077032311277997e-08, 6.873625395187494e+10}, {-9.094947033611148e-13, 4.450691014249257e-308, 2.086006742350485e-308, 2.086006742346437e-308}, {-7.751454006381804e-05, 5.588653777189071e-308, -2.2207280111272877e-308, -2.2211612130544025e-308}, + + // Issue #61130 + {-1, 1, 1, 0}, + {1, 1, -1, 0}, } var sqrt32 = []float32{ @@ -3099,6 +3106,45 @@ func TestFMA(t *testing.T) { } } +//go:noinline +func fmsub(x, y, z float64) float64 { + return FMA(x, y, -z) +} + +//go:noinline +func fnmsub(x, y, z float64) float64 { + return FMA(-x, y, z) +} + +//go:noinline +func fnmadd(x, y, z float64) float64 { + return FMA(-x, y, -z) +} + +func TestFMANegativeArgs(t *testing.T) { + // Some architectures have instructions for fused multiply-subtract and + // also negated variants of fused multiply-add and subtract. This test + // aims to check that the optimizations that generate those instructions + // are applied correctly, if they exist. + for _, c := range fmaC { + want := PortableFMA(c.x, c.y, -c.z) + got := fmsub(c.x, c.y, c.z) + if !alike(got, want) { + t.Errorf("FMA(%g, %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want) + } + want = PortableFMA(-c.x, c.y, c.z) + got = fnmsub(c.x, c.y, c.z) + if !alike(got, want) { + t.Errorf("FMA(-(%g), %g, %g) == %g, want %g", c.x, c.y, c.z, got, want) + } + want = PortableFMA(-c.x, c.y, -c.z) + got = fnmadd(c.x, c.y, c.z) + if !alike(got, want) { + t.Errorf("FMA(-(%g), %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want) + } + } +} + // Check that math functions of high angle values // return accurate results. [Since (vf[i] + large) - large != vf[i], // testing for Trig(vf[i] + large) == Trig(vf[i]), where large is diff --git a/src/math/fma.go b/src/math/fma.go index ca0bf99f21..ba03fbe8a9 100644 --- a/src/math/fma.go +++ b/src/math/fma.go @@ -132,6 +132,11 @@ func FMA(x, y, z float64) float64 { ps, pe, pm1, pm2, zs, ze, zm1, zm2 = zs, ze, zm1, zm2, ps, pe, pm1, pm2 } + // Special case: if p == -z the result is always +0 since neither operand is zero. + if ps != zs && pe == ze && pm1 == zm1 && pm2 == zm2 { + return 0 + } + // Align significands zm1, zm2 = shrcompress(zm1, zm2, uint(pe-ze)) diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go index bd483110b5..b26b11af8b 100644 --- a/src/net/cgo_stub.go +++ b/src/net/cgo_stub.go @@ -3,12 +3,13 @@ // license that can be found in the LICENSE file. // This file holds stub versions of the cgo functions called on Unix systems. -// We build this file if using the netgo build tag, or if cgo is not -// enabled and we are using a Unix system other than Darwin. -// Darwin is exempted because it always provides the cgo routines, -// in cgo_unix_syscall.go. +// We build this file: +// - if using the netgo build tag on a Unix system +// - on a Unix system without the cgo resolver functions +// (Darwin always provides the cgo functions, in cgo_unix_syscall.go) +// - on wasip1, where cgo is never available -//go:build netgo || (!cgo && unix && !darwin) +//go:build (netgo && unix) || (unix && !cgo && !darwin) || wasip1 package net diff --git a/src/net/conf.go b/src/net/conf.go index 1db166c9e3..77cc635592 100644 --- a/src/net/conf.go +++ b/src/net/conf.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !js && !wasip1 +//go:build !js package net diff --git a/src/net/dial.go b/src/net/dial.go index fd1da1ebef..79bc4958bb 100644 --- a/src/net/dial.go +++ b/src/net/dial.go @@ -6,6 +6,7 @@ package net import ( "context" + "internal/godebug" "internal/nettrace" "syscall" "time" @@ -21,6 +22,8 @@ const ( defaultMPTCPEnabled = false ) +var multipathtcp = godebug.New("multipathtcp") + // mptcpStatus is a tristate for Multipath TCP, see go.dev/issue/56539 type mptcpStatus uint8 @@ -39,6 +42,13 @@ func (m *mptcpStatus) get() bool { return false } + // If MPTCP is forced via GODEBUG=multipathtcp=1 + if multipathtcp.Value() == "1" { + multipathtcp.IncNonDefault() + + return true + } + return defaultMPTCPEnabled } @@ -329,7 +339,7 @@ func (d *Dialer) MultipathTCP() bool { // SetMultipathTCP directs the Dial methods to use, or not use, MPTCP, // if supported by the operating system. This method overrides the -// system default. +// system default and the GODEBUG=multipathtcp=... setting if any. // // If MPTCP is not available on the host or not supported by the server, // the Dial methods will fall back to TCP. @@ -690,7 +700,7 @@ func (lc *ListenConfig) MultipathTCP() bool { // SetMultipathTCP directs the Listen method to use, or not use, MPTCP, // if supported by the operating system. This method overrides the -// system default. +// system default and the GODEBUG=multipathtcp=... setting if any. // // If MPTCP is not available on the host or not supported by the client, // the Listen method will fall back to TCP. diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index f3c075c83f..dab5144e5d 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !js && !wasip1 +//go:build !js // DNS client: see RFC 1035. // Has to be linked into package net for Dial. diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go index d5f34e5300..69b300410a 100644 --- a/src/net/dnsconfig_unix.go +++ b/src/net/dnsconfig_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !js && !wasip1 && !windows +//go:build !js && !windows // Read system DNS config from /etc/resolv.conf diff --git a/src/net/http/fcgi/fcgi.go b/src/net/http/fcgi/fcgi.go index fb822f8a6d..56f7d40789 100644 --- a/src/net/http/fcgi/fcgi.go +++ b/src/net/http/fcgi/fcgi.go @@ -99,8 +99,10 @@ func (h *header) init(recType recType, reqId uint16, contentLength int) { // conn sends records over rwc type conn struct { - mutex sync.Mutex - rwc io.ReadWriteCloser + mutex sync.Mutex + rwc io.ReadWriteCloser + closeErr error + closed bool // to avoid allocations buf bytes.Buffer @@ -111,10 +113,15 @@ func newConn(rwc io.ReadWriteCloser) *conn { return &conn{rwc: rwc} } +// Close closes the conn if it is not already closed. func (c *conn) Close() error { c.mutex.Lock() defer c.mutex.Unlock() - return c.rwc.Close() + if !c.closed { + c.closeErr = c.rwc.Close() + c.closed = true + } + return c.closeErr } type record struct { diff --git a/src/net/http/fcgi/fcgi_test.go b/src/net/http/fcgi/fcgi_test.go index 7a344ff31d..03c422420f 100644 --- a/src/net/http/fcgi/fcgi_test.go +++ b/src/net/http/fcgi/fcgi_test.go @@ -241,7 +241,7 @@ func TestChildServeCleansUp(t *testing.T) { input := make([]byte, len(tt.input)) copy(input, tt.input) rc := nopWriteCloser{bytes.NewReader(input)} - done := make(chan bool) + done := make(chan struct{}) c := newChild(rc, http.HandlerFunc(func( w http.ResponseWriter, r *http.Request, @@ -252,9 +252,9 @@ func TestChildServeCleansUp(t *testing.T) { t.Errorf("Expected %#v, got %#v", tt.err, err) } // not reached if body of request isn't closed - done <- true + close(done) })) - go c.serve() + c.serve() // wait for body of request to be closed or all goroutines to block <-done } @@ -331,7 +331,7 @@ func TestChildServeReadsEnvVars(t *testing.T) { input := make([]byte, len(tt.input)) copy(input, tt.input) rc := nopWriteCloser{bytes.NewReader(input)} - done := make(chan bool) + done := make(chan struct{}) c := newChild(rc, http.HandlerFunc(func( w http.ResponseWriter, r *http.Request, @@ -343,9 +343,9 @@ func TestChildServeReadsEnvVars(t *testing.T) { } else if env[tt.envVar] != tt.expectedVal { t.Errorf("Expected %s, got %s", tt.expectedVal, env[tt.envVar]) } - done <- true + close(done) })) - go c.serve() + c.serve() <-done } } @@ -381,7 +381,7 @@ func TestResponseWriterSniffsContentType(t *testing.T) { input := make([]byte, len(streamFullRequestStdin)) copy(input, streamFullRequestStdin) rc := nopWriteCloser{bytes.NewReader(input)} - done := make(chan bool) + done := make(chan struct{}) var resp *response c := newChild(rc, http.HandlerFunc(func( w http.ResponseWriter, @@ -389,10 +389,9 @@ func TestResponseWriterSniffsContentType(t *testing.T) { ) { io.WriteString(w, tt.body) resp = w.(*response) - done <- true + close(done) })) - defer c.cleanUp() - go c.serve() + c.serve() <-done if got := resp.Header().Get("Content-Type"); got != tt.wantCT { t.Errorf("got a Content-Type of %q; expected it to start with %q", got, tt.wantCT) @@ -401,25 +400,27 @@ func TestResponseWriterSniffsContentType(t *testing.T) { } } -type signalingNopCloser struct { - io.Reader +type signalingNopWriteCloser struct { + io.ReadCloser closed chan bool } -func (*signalingNopCloser) Write(buf []byte) (int, error) { +func (*signalingNopWriteCloser) Write(buf []byte) (int, error) { return len(buf), nil } -func (rc *signalingNopCloser) Close() error { +func (rc *signalingNopWriteCloser) Close() error { close(rc.closed) - return nil + return rc.ReadCloser.Close() } // Test whether server properly closes connection when processing slow // requests func TestSlowRequest(t *testing.T) { pr, pw := io.Pipe() - go func(w io.Writer) { + + writerDone := make(chan struct{}) + go func() { for _, buf := range [][]byte{ streamBeginTypeStdin, makeRecord(typeStdin, 1, nil), @@ -427,9 +428,14 @@ func TestSlowRequest(t *testing.T) { pw.Write(buf) time.Sleep(100 * time.Millisecond) } - }(pw) - - rc := &signalingNopCloser{pr, make(chan bool)} + close(writerDone) + }() + defer func() { + <-writerDone + pw.Close() + }() + + rc := &signalingNopWriteCloser{pr, make(chan bool)} handlerDone := make(chan bool) c := newChild(rc, http.HandlerFunc(func( @@ -439,16 +445,9 @@ func TestSlowRequest(t *testing.T) { w.WriteHeader(200) close(handlerDone) })) - go c.serve() - defer c.cleanUp() - - timeout := time.After(2 * time.Second) + c.serve() <-handlerDone - select { - case <-rc.closed: - t.Log("FastCGI child closed connection") - case <-timeout: - t.Error("FastCGI child did not close socket after handling request") - } + <-rc.closed + t.Log("FastCGI child closed connection") } diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index ebc004a30d..dc3e099c83 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -7540,11 +7540,14 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) { func http2authorityAddr(scheme string, authority string) (addr string) { host, port, err := net.SplitHostPort(authority) if err != nil { // authority didn't have a port + host = authority + port = "" + } + if port == "" { // authority's port was empty port = "443" if scheme == "http" { port = "80" } - host = authority } if a, err := idna.ToASCII(host); err == nil { host = a @@ -8290,22 +8293,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { cancelRequest := func(cs *http2clientStream, err error) error { cs.cc.mu.Lock() - cs.abortStreamLocked(err) bodyClosed := cs.reqBodyClosed - if cs.ID != 0 { - // This request may have failed because of a problem with the connection, - // or for some unrelated reason. (For example, the user might have canceled - // the request without waiting for a response.) Mark the connection as - // not reusable, since trying to reuse a dead connection is worse than - // unnecessarily creating a new one. - // - // If cs.ID is 0, then the request was never allocated a stream ID and - // whatever went wrong was unrelated to the connection. We might have - // timed out waiting for a stream slot when StrictMaxConcurrentStreams - // is set, for example, in which case retrying on a different connection - // will not help. - cs.cc.doNotReuse = true - } cs.cc.mu.Unlock() // Wait for the request body to be closed. // @@ -8340,11 +8328,14 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { return handleResponseHeaders() default: waitDone() - return nil, cancelRequest(cs, cs.abortErr) + return nil, cs.abortErr } case <-ctx.Done(): - return nil, cancelRequest(cs, ctx.Err()) + err := ctx.Err() + cs.abortStream(err) + return nil, cancelRequest(cs, err) case <-cs.reqCancel: + cs.abortStream(http2errRequestCanceled) return nil, cancelRequest(cs, http2errRequestCanceled) } } @@ -8902,6 +8893,9 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail if err != nil { return nil, err } + if !httpguts.ValidHostHeader(host) { + return nil, errors.New("http2: invalid Host header") + } var path string if req.Method != "CONNECT" { diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go index 1c9fb33b69..91bb1b2620 100644 --- a/src/net/http/http_test.go +++ b/src/net/http/http_test.go @@ -48,35 +48,6 @@ func TestForeachHeaderElement(t *testing.T) { } } -func TestCleanHost(t *testing.T) { - tests := []struct { - in, want string - }{ - {"www.google.com", "www.google.com"}, - {"www.google.com foo", "www.google.com"}, - {"www.google.com/foo", "www.google.com"}, - {" first character is a space", ""}, - {"[1::6]:8080", "[1::6]:8080"}, - - // Punycode: - {"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"}, - {"bücher.de", "xn--bcher-kva.de"}, - {"bücher.de:8080", "xn--bcher-kva.de:8080"}, - // Verify we convert to lowercase before punycode: - {"BÜCHER.de", "xn--bcher-kva.de"}, - {"BÜCHER.de:8080", "xn--bcher-kva.de:8080"}, - // Verify we normalize to NFC before punycode: - {"gophér.nfc", "xn--gophr-esa.nfc"}, // NFC input; no work needed - {"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input - } - for _, tt := range tests { - got := cleanHost(tt.in) - if tt.want != got { - t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want) - } - } -} - // Test that cmd/go doesn't link in the HTTP server. // // This catches accidental dependencies between the HTTP transport and diff --git a/src/net/http/request.go b/src/net/http/request.go index 4e9190493c..bd868373c5 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -17,7 +17,6 @@ import ( "io" "mime" "mime/multipart" - "net" "net/http/httptrace" "net/http/internal/ascii" "net/textproto" @@ -27,6 +26,7 @@ import ( "strings" "sync" + "golang.org/x/net/http/httpguts" "golang.org/x/net/idna" ) @@ -580,12 +580,19 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF // is not given, use the host from the request URL. // // Clean the host, in case it arrives with unexpected stuff in it. - host := cleanHost(r.Host) + host := r.Host if host == "" { if r.URL == nil { return errMissingHost } - host = cleanHost(r.URL.Host) + host = r.URL.Host + } + host, err = httpguts.PunycodeHostPort(host) + if err != nil { + return err + } + if !httpguts.ValidHostHeader(host) { + return errors.New("http: invalid Host header") } // According to RFC 6874, an HTTP client, proxy, or other @@ -742,40 +749,6 @@ func idnaASCII(v string) (string, error) { return idna.Lookup.ToASCII(v) } -// cleanHost cleans up the host sent in request's Host header. -// -// It both strips anything after '/' or ' ', and puts the value -// into Punycode form, if necessary. -// -// Ideally we'd clean the Host header according to the spec: -// -// https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]") -// https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host) -// https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host) -// -// But practically, what we are trying to avoid is the situation in -// issue 11206, where a malformed Host header used in the proxy context -// would create a bad request. So it is enough to just truncate at the -// first offending character. -func cleanHost(in string) string { - if i := strings.IndexAny(in, " /"); i != -1 { - in = in[:i] - } - host, port, err := net.SplitHostPort(in) - if err != nil { // input was just a host - a, err := idnaASCII(in) - if err != nil { - return in // garbage in, garbage out - } - return a - } - a, err := idnaASCII(host) - if err != nil { - return in // garbage in, garbage out - } - return net.JoinHostPort(a, port) -} - // removeZone removes IPv6 zone identifier from host. // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" func removeZone(host string) string { diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go index 78b968f23c..0892bc255f 100644 --- a/src/net/http/request_test.go +++ b/src/net/http/request_test.go @@ -775,15 +775,8 @@ func TestRequestBadHost(t *testing.T) { } req.Host = "foo.com with spaces" req.URL.Host = "foo.com with spaces" - req.Write(logWrites{t, &got}) - want := []string{ - "GET /after HTTP/1.1\r\n", - "Host: foo.com\r\n", - "User-Agent: " + DefaultUserAgent + "\r\n", - "\r\n", - } - if !reflect.DeepEqual(got, want) { - t.Errorf("Writes = %q\n Want = %q", got, want) + if err := req.Write(logWrites{t, &got}); err == nil { + t.Errorf("Writing request with invalid Host: succeded, want error") } } diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 172aba679b..028fecc961 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -6731,3 +6731,22 @@ func testHandlerAbortRacesBodyRead(t *testing.T, mode testMode) { } wg.Wait() } + +func TestRequestSanitization(t *testing.T) { run(t, testRequestSanitization) } +func testRequestSanitization(t *testing.T, mode testMode) { + if mode == http2Mode { + // Remove this after updating x/net. + t.Skip("https://go.dev/issue/60374 test fails when run with HTTP/2") + } + ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) { + if h, ok := req.Header["X-Evil"]; ok { + t.Errorf("request has X-Evil header: %q", h) + } + })).ts + req, _ := NewRequest("GET", ts.URL, nil) + req.Host = "go.dev\r\nX-Evil:evil" + resp, _ := ts.Client().Do(req) + if resp != nil { + resp.Body.Close() + } +} diff --git a/src/net/lookup_fake.go b/src/net/lookup_fake.go index 45146e1c95..c27eae4ba5 100644 --- a/src/net/lookup_fake.go +++ b/src/net/lookup_fake.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (js && wasm) || wasip1 +//go:build js && wasm package net diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go index dc75e0a3b6..56ae11e961 100644 --- a/src/net/lookup_unix.go +++ b/src/net/lookup_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build unix +//go:build unix || wasip1 package net diff --git a/src/net/mail/message.go b/src/net/mail/message.go index a416007fdb..af516fc30f 100644 --- a/src/net/mail/message.go +++ b/src/net/mail/message.go @@ -14,6 +14,7 @@ Notable divergences: such as breaking addresses across lines. - No unicode normalization is performed. - The special characters ()[]:;@\, are allowed to appear unquoted in names. + - A leading From line is permitted, as in mbox format (RFC 4155). */ package mail @@ -53,7 +54,7 @@ type Message struct { func ReadMessage(r io.Reader) (msg *Message, err error) { tp := textproto.NewReader(bufio.NewReader(r)) - hdr, err := tp.ReadMIMEHeader() + hdr, err := readHeader(tp) if err != nil && (err != io.EOF || len(hdr) == 0) { return nil, err } @@ -64,6 +65,54 @@ func ReadMessage(r io.Reader) (msg *Message, err error) { }, nil } +// readHeader reads the message headers from r. +// This is like textproto.ReadMIMEHeader, but doesn't validate. +// The fix for issue #53188 tightened up net/textproto to enforce +// restrictions of RFC 7230. +// This package implements RFC 5322, which does not have those restrictions. +// This function copies the relevant code from net/textproto, +// simplified for RFC 5322. +func readHeader(r *textproto.Reader) (map[string][]string, error) { + m := make(map[string][]string) + + // The first line cannot start with a leading space. + if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { + line, err := r.ReadLine() + if err != nil { + return m, err + } + return m, errors.New("malformed initial line: " + line) + } + + for { + kv, err := r.ReadContinuedLine() + if kv == "" { + return m, err + } + + // Key ends at first colon. + k, v, ok := strings.Cut(kv, ":") + if !ok { + return m, errors.New("malformed header line: " + kv) + } + key := textproto.CanonicalMIMEHeaderKey(k) + + // Permit empty key, because that is what we did in the past. + if key == "" { + continue + } + + // Skip initial spaces in value. + value := strings.TrimLeft(v, " \t") + + m[key] = append(m[key], value) + + if err != nil { + return m, err + } + } +} + // Layouts suitable for passing to time.Parse. // These are tried in order. var ( diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go index 4b581ccc73..1e1bb4092f 100644 --- a/src/net/mail/message_test.go +++ b/src/net/mail/message_test.go @@ -52,6 +52,34 @@ Version: 1 }, body: "", }, + { + // RFC 5322 permits any printable ASCII character, + // except colon, in a header key. Issue #58862. + in: `From: iant@golang.org +Custom/Header: v + +Body +`, + header: Header{ + "From": []string{"iant@golang.org"}, + "Custom/Header": []string{"v"}, + }, + body: "Body\n", + }, + { + // RFC 4155 mbox format. We've historically permitted this, + // so we continue to permit it. Issue #60332. + in: `From iant@golang.org Mon Jun 19 00:00:00 2023 +From: iant@golang.org + +Hello, gophers! +`, + header: Header{ + "From": []string{"iant@golang.org"}, + "From iant@golang.org Mon Jun 19 00": []string{"00:00 2023"}, + }, + body: "Hello, gophers!\n", + }, } func TestParsing(t *testing.T) { diff --git a/src/net/mptcpsock_linux_test.go b/src/net/mptcpsock_linux_test.go index bf8fc951c5..5134aba75e 100644 --- a/src/net/mptcpsock_linux_test.go +++ b/src/net/mptcpsock_linux_test.go @@ -12,15 +12,22 @@ import ( "testing" ) -func newLocalListenerMPTCP(t *testing.T) Listener { +func newLocalListenerMPTCP(t *testing.T, envVar bool) Listener { lc := &ListenConfig{} - if lc.MultipathTCP() { - t.Error("MultipathTCP should be off by default") - } - lc.SetMultipathTCP(true) - if !lc.MultipathTCP() { - t.Fatal("MultipathTCP is not on after having been forced to on") + if envVar { + if !lc.MultipathTCP() { + t.Fatal("MultipathTCP Listen is not on despite GODEBUG=multipathtcp=1") + } + } else { + if lc.MultipathTCP() { + t.Error("MultipathTCP should be off by default") + } + + lc.SetMultipathTCP(true) + if !lc.MultipathTCP() { + t.Fatal("MultipathTCP is not on after having been forced to on") + } } ln, err := lc.Listen(context.Background(), "tcp", "127.0.0.1:0") @@ -64,15 +71,22 @@ func postAcceptMPTCP(ls *localServer, ch chan<- error) { } } -func dialerMPTCP(t *testing.T, addr string) { +func dialerMPTCP(t *testing.T, addr string, envVar bool) { d := &Dialer{} - if d.MultipathTCP() { - t.Error("MultipathTCP should be off by default") - } - d.SetMultipathTCP(true) - if !d.MultipathTCP() { - t.Fatal("MultipathTCP is not on after having been forced to on") + if envVar { + if !d.MultipathTCP() { + t.Fatal("MultipathTCP Dialer is not on despite GODEBUG=multipathtcp=1") + } + } else { + if d.MultipathTCP() { + t.Error("MultipathTCP should be off by default") + } + + d.SetMultipathTCP(true) + if !d.MultipathTCP() { + t.Fatal("MultipathTCP is not on after having been forced to on") + } } c, err := d.Dial("tcp", addr) @@ -128,12 +142,16 @@ func canCreateMPTCPSocket() bool { return true } -func TestMultiPathTCP(t *testing.T) { - if !canCreateMPTCPSocket() { - t.Skip("Cannot create MPTCP sockets") +func testMultiPathTCP(t *testing.T, envVar bool) { + if envVar { + t.Log("Test with GODEBUG=multipathtcp=1") + t.Setenv("GODEBUG", "multipathtcp=1") + } else { + t.Log("Test with GODEBUG=multipathtcp=0") + t.Setenv("GODEBUG", "multipathtcp=0") } - ln := newLocalListenerMPTCP(t) + ln := newLocalListenerMPTCP(t, envVar) // similar to tcpsock_test:TestIPv6LinkLocalUnicastTCP ls := (&streamListener{Listener: ln}).newLocalServer() @@ -153,7 +171,7 @@ func TestMultiPathTCP(t *testing.T) { t.Fatal(err) } - dialerMPTCP(t, ln.Addr().String()) + dialerMPTCP(t, ln.Addr().String(), envVar) if err := <-genericCh; err != nil { t.Error(err) @@ -162,3 +180,13 @@ func TestMultiPathTCP(t *testing.T) { t.Error(err) } } + +func TestMultiPathTCP(t *testing.T) { + if !canCreateMPTCPSocket() { + t.Skip("Cannot create MPTCP sockets") + } + + for _, envVar := range []bool{false, true} { + testMultiPathTCP(t, envVar) + } +} diff --git a/src/net/net_fake.go b/src/net/net_fake.go index 68d36966ca..908767a1f6 100644 --- a/src/net/net_fake.go +++ b/src/net/net_fake.go @@ -15,8 +15,6 @@ import ( "sync" "syscall" "time" - - "golang.org/x/net/dns/dnsmessage" ) var listenersMu sync.Mutex @@ -406,7 +404,3 @@ func (fd *fakeNetFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, func (fd *fakeNetFD) dup() (f *os.File, err error) { return nil, syscall.ENOSYS } - -func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) { - panic("unreachable") -} diff --git a/src/net/net_fake_js.go b/src/net/net_fake_js.go index 1fc0b50b7d..7ba108b664 100644 --- a/src/net/net_fake_js.go +++ b/src/net/net_fake_js.go @@ -8,7 +8,12 @@ package net -import "internal/poll" +import ( + "context" + "internal/poll" + + "golang.org/x/net/dns/dnsmessage" +) // Network file descriptor. type netFD struct { @@ -25,3 +30,7 @@ type netFD struct { pfd poll.FD isConnected bool // handshake completed or use of association with peer } + +func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) { + panic("unreachable") +} diff --git a/src/os/dir_darwin.go b/src/os/dir_darwin.go index deba3eb37f..e6d5bda24b 100644 --- a/src/os/dir_darwin.go +++ b/src/os/dir_darwin.go @@ -54,6 +54,15 @@ func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEn if entptr == nil { // EOF break } + // Darwin may return a zero inode when a directory entry has been + // deleted but not yet removed from the directory. The man page for + // getdirentries(2) states that programs are responsible for skipping + // those entries: + // + // Users of getdirentries() should skip entries with d_fileno = 0, + // as such entries represent files which have been deleted but not + // yet removed from the directory entry. + // if dirent.Ino == 0 { continue } diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go index 004b9fbb2b..266a78acaf 100644 --- a/src/os/dir_unix.go +++ b/src/os/dir_unix.go @@ -89,7 +89,11 @@ func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEn if !ok { break } - if ino == 0 { + // When building to wasip1, the host runtime might be running on Windows + // or might expose a remote file system which does not have the concept + // of inodes. Therefore, we cannot make the assumption that it is safe + // to skip entries with zero inodes. + if ino == 0 && runtime.GOOS != "wasip1" { continue } const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name)) diff --git a/src/os/dir_windows.go b/src/os/dir_windows.go index 7792d03040..1724af58d5 100644 --- a/src/os/dir_windows.go +++ b/src/os/dir_windows.go @@ -84,6 +84,18 @@ func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []Di if err == syscall.ERROR_NO_MORE_FILES { break } + if infoClass == windows.FileIdBothDirectoryRestartInfo && err == syscall.ERROR_FILE_NOT_FOUND { + // GetFileInformationByHandleEx doesn't document the return error codes when the info class is FileIdBothDirectoryRestartInfo, + // but MS-FSA 2.1.5.6.3 [1] specifies that the underlying file system driver should return STATUS_NO_SUCH_FILE when + // reading an empty root directory, which is mapped to ERROR_FILE_NOT_FOUND by Windows. + // Note that some file system drivers may never return this error code, as the spec allows to return the "." and ".." + // entries in such cases, making the directory appear non-empty. + // The chances of false positive are very low, as we know that the directory exists, else GetVolumeInformationByHandle + // would have failed, and that the handle is still valid, as we haven't closed it. + // See go.dev/issue/61159. + // [1] https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fsa/fa8194e0-53ec-413b-8315-e8fa85396fd8 + break + } if s, _ := file.Stat(); s != nil && !s.IsDir() { err = &PathError{Op: "readdir", Path: file.name, Err: syscall.ENOTDIR} } else { diff --git a/src/os/env_test.go b/src/os/env_test.go index 1b9e26594c..5809f4b866 100644 --- a/src/os/env_test.go +++ b/src/os/env_test.go @@ -130,7 +130,7 @@ func TestClearenv(t *testing.T) { defer func(origEnv []string) { for _, pair := range origEnv { // Environment variables on Windows can begin with = - // https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx + // https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133 i := strings.Index(pair[1:], "=") + 1 if err := Setenv(pair[:i], pair[i+1:]); err != nil { t.Errorf("Setenv(%q, %q) failed during reset: %v", pair[:i], pair[i+1:], err) diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index 67cd446f42..473f92ba8e 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -1708,3 +1708,77 @@ func TestCancelErrors(t *testing.T) { } }) } + +// TestConcurrentExec is a regression test for https://go.dev/issue/61080. +// +// Forking multiple child processes concurrently would sometimes hang on darwin. +// (This test hung on a gomote with -count=100 after only a few iterations.) +func TestConcurrentExec(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + + // This test will spawn nHangs subprocesses that hang reading from stdin, + // and nExits subprocesses that exit immediately. + // + // When issue #61080 was present, a long-lived "hang" subprocess would + // occasionally inherit the fork/exec status pipe from an "exit" subprocess, + // causing the parent process (which expects to see an EOF on that pipe almost + // immediately) to unexpectedly block on reading from the pipe. + var ( + nHangs = runtime.GOMAXPROCS(0) + nExits = runtime.GOMAXPROCS(0) + hangs, exits sync.WaitGroup + ) + hangs.Add(nHangs) + exits.Add(nExits) + + // ready is done when the goroutines have done as much work as possible to + // prepare to create subprocesses. It isn't strictly necessary for the test, + // but helps to increase the repro rate by making it more likely that calls to + // syscall.StartProcess for the "hang" and "exit" goroutines overlap. + var ready sync.WaitGroup + ready.Add(nHangs + nExits) + + for i := 0; i < nHangs; i++ { + go func() { + defer hangs.Done() + + cmd := helperCommandContext(t, ctx, "pipetest") + stdin, err := cmd.StdinPipe() + if err != nil { + ready.Done() + t.Error(err) + return + } + cmd.Cancel = stdin.Close + ready.Done() + + ready.Wait() + if err := cmd.Start(); err != nil { + if !errors.Is(err, context.Canceled) { + t.Error(err) + } + return + } + + cmd.Wait() + }() + } + + for i := 0; i < nExits; i++ { + go func() { + defer exits.Done() + + cmd := helperCommandContext(t, ctx, "exit", "0") + ready.Done() + + ready.Wait() + if err := cmd.Run(); err != nil { + t.Error(err) + } + }() + } + + exits.Wait() + cancel() + hangs.Wait() +} diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index cd978cc34b..8f11333b46 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -534,7 +534,7 @@ func TestMemPprof(t *testing.T) { got, err := testenv.CleanCmdEnv(exec.Command(exe, "MemProf")).CombinedOutput() if err != nil { - t.Fatal(err) + t.Fatalf("testprog failed: %s, output:\n%s", err, got) } fn := strings.TrimSpace(string(got)) defer os.Remove(fn) diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go index 07060b8fab..6bca2ac66e 100644 --- a/src/runtime/crash_unix_test.go +++ b/src/runtime/crash_unix_test.go @@ -76,7 +76,7 @@ func TestCrashDumpsAllThreads(t *testing.T) { testenv.MustHaveGoBuild(t) - if strings.Contains(os.Getenv("GCFLAGS"), "mayMoreStackPreempt") { + if strings.Contains(os.Getenv("GOFLAGS"), "mayMoreStackPreempt") { // This test occasionally times out in this debug mode. This is probably // revealing a real bug in the scheduler, but since it seems to only // affect this test and this is itself a test of a debug mode, it's not diff --git a/src/runtime/extern.go b/src/runtime/extern.go index ac07119cb9..26dcf0bd52 100644 --- a/src/runtime/extern.go +++ b/src/runtime/extern.go @@ -87,7 +87,8 @@ It is a comma-separated list of name=val pairs setting these named variables: gctrace: setting gctrace=1 causes the garbage collector to emit a single line to standard error at each collection, summarizing the amount of memory collected and the - length of the pause. The format of this line is subject to change. + length of the pause. The format of this line is subject to change. Included in + the explanation below is also the relevant runtime/metrics metric for each field. Currently, it is: gc # @#s #%: #+#+# ms clock, #+#/#/#+# ms cpu, #->#-># MB, # MB goal, # MB stacks, #MB globals, # P where the fields are as follows: @@ -95,11 +96,11 @@ It is a comma-separated list of name=val pairs setting these named variables: @#s time in seconds since program start #% percentage of time spent in GC since program start #+...+# wall-clock/CPU times for the phases of the GC - #->#-># MB heap size at GC start, at GC end, and live heap - # MB goal goal heap size - # MB stacks estimated scannable stack size - # MB globals scannable global size - # P number of processors used + #->#-># MB heap size at GC start, at GC end, and live heap, or /gc/scan/heap:bytes + # MB goal goal heap size, or /gc/heap/goal:bytes + # MB stacks estimated scannable stack size, or /gc/scan/stack:bytes + # MB globals scannable global size, or /gc/scan/globals:bytes + # P number of processors used, or /sched/gomaxprocs:threads The phases are stop-the-world (STW) sweep termination, concurrent mark and scan, and STW mark termination. The CPU times for mark/scan are broken down in to assist time (GC performed in diff --git a/src/runtime/internal/wasitest/nonblock_test.go b/src/runtime/internal/wasitest/nonblock_test.go index 8fb2860e4b..3072b96ed8 100644 --- a/src/runtime/internal/wasitest/nonblock_test.go +++ b/src/runtime/internal/wasitest/nonblock_test.go @@ -37,8 +37,6 @@ func TestNonblock(t *testing.T) { } switch os.Getenv("GOWASIRUNTIME") { - case "wazero", "": - t.Skip("wazero does not support non-blocking I/O") case "wasmer": t.Skip("wasmer does not support non-blocking I/O") } diff --git a/src/runtime/internal/wasitest/tcpecho_test.go b/src/runtime/internal/wasitest/tcpecho_test.go index 506e6fe40a..c56af2cc85 100644 --- a/src/runtime/internal/wasitest/tcpecho_test.go +++ b/src/runtime/internal/wasitest/tcpecho_test.go @@ -44,6 +44,8 @@ func TestTCPEcho(t *testing.T) { subProcess.Env = append(os.Environ(), "GOOS=wasip1", "GOARCH=wasm") switch os.Getenv("GOWASIRUNTIME") { + case "wazero", "": + subProcess.Env = append(subProcess.Env, "GOWASIRUNTIMEARGS=--listen="+host) case "wasmtime": subProcess.Env = append(subProcess.Env, "GOWASIRUNTIMEARGS=--tcplisten="+host) default: diff --git a/src/runtime/metrics/description.go b/src/runtime/metrics/description.go index aea51c7f75..745691b24f 100644 --- a/src/runtime/metrics/description.go +++ b/src/runtime/metrics/description.go @@ -339,9 +339,11 @@ var allDesc = []Description{ Kind: KindUint64, }, { - Name: "/memory/classes/heap/stacks:bytes", - Description: "Memory allocated from the heap that is reserved for stack space, whether or not it is currently in-use.", - Kind: KindUint64, + Name: "/memory/classes/heap/stacks:bytes", + Description: "Memory allocated from the heap that is reserved for stack space, whether or not it is currently in-use. " + + "Currently, this represents all stack memory for goroutines. It also includes all OS thread stacks in non-cgo programs. " + + "Note that stacks may be allocated differently in the future, and this may change.", + Kind: KindUint64, }, { Name: "/memory/classes/heap/unused:bytes", @@ -374,9 +376,13 @@ var allDesc = []Description{ Kind: KindUint64, }, { - Name: "/memory/classes/os-stacks:bytes", - Description: "Stack memory allocated by the underlying operating system.", - Kind: KindUint64, + Name: "/memory/classes/os-stacks:bytes", + Description: "Stack memory allocated by the underlying operating system. " + + "In non-cgo programs this metric is currently zero. This may change in the future." + + "In cgo programs this metric includes OS thread stacks allocated directly from the OS. " + + "Currently, this only accounts for one stack in c-shared and c-archive build modes, " + + "and other sources of stacks from the OS are not measured. This too may change in the future.", + Kind: KindUint64, }, { Name: "/memory/classes/other:bytes", diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go index 5238bcea8e..b4d32d135a 100644 --- a/src/runtime/metrics/doc.go +++ b/src/runtime/metrics/doc.go @@ -273,6 +273,10 @@ Below is the full list of supported metrics, ordered lexicographically. the mime/multipart package due to a non-default GODEBUG=multipartmaxparts=... setting. + /godebug/non-default-behavior/multipathtcp:events + The number of non-default behaviors executed by the net package + due to a non-default GODEBUG=multipathtcp=... setting. + /godebug/non-default-behavior/panicnil:events The number of non-default behaviors executed by the runtime package due to a non-default GODEBUG=panicnil=... setting. @@ -318,7 +322,10 @@ Below is the full list of supported metrics, ordered lexicographically. /memory/classes/heap/stacks:bytes Memory allocated from the heap that is reserved for stack space, - whether or not it is currently in-use. + whether or not it is currently in-use. Currently, this + represents all stack memory for goroutines. It also includes all + OS thread stacks in non-cgo programs. Note that stacks may be + allocated differently in the future, and this may change. /memory/classes/heap/unused:bytes Memory that is reserved for heap objects but is not currently @@ -345,6 +352,12 @@ Below is the full list of supported metrics, ordered lexicographically. /memory/classes/os-stacks:bytes Stack memory allocated by the underlying operating system. + In non-cgo programs this metric is currently zero. This may + change in the future.In cgo programs this metric includes + OS thread stacks allocated directly from the OS. Currently, + this only accounts for one stack in c-shared and c-archive build + modes, and other sources of stacks from the OS are not measured. + This too may change in the future. /memory/classes/other:bytes Memory used by execution trace buffers, structures for debugging diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index ab383dd8e3..9cdc565137 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -199,7 +199,17 @@ type MemStats struct { // StackSys is bytes of stack memory obtained from the OS. // // StackSys is StackInuse, plus any memory obtained directly - // from the OS for OS thread stacks (which should be minimal). + // from the OS for OS thread stacks. + // + // In non-cgo programs this metric is currently equal to StackInuse + // (but this should not be relied upon, and the value may change in + // the future). + // + // In cgo programs this metric includes OS thread stacks allocated + // directly from the OS. Currently, this only accounts for one stack in + // c-shared and c-archive build modes and other sources of stacks from + // the OS (notably, any allocated by C code) are not currently measured. + // Note this too may change in the future. StackSys uint64 // Off-heap memory statistics. @@ -347,6 +357,7 @@ func init() { // which is a snapshot as of the most recently completed garbage // collection cycle. func ReadMemStats(m *MemStats) { + _ = m.Alloc // nil check test before we switch stacks, see issue 61158 stopTheWorld(stwReadMemStats) systemstack(func() { diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 3cecd1a057..9fd200ea32 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4570,6 +4570,7 @@ func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g { pp.goidcache++ if raceenabled { newg.racectx = racegostart(callerpc) + newg.raceignore = 0 if newg.labels != nil { // See note in proflabel.go on labelSync's role in synchronizing // with the reads in the signal handler. diff --git a/src/runtime/race/testdata/mop_test.go b/src/runtime/race/testdata/mop_test.go index 0da539fc01..6b1069fcca 100644 --- a/src/runtime/race/testdata/mop_test.go +++ b/src/runtime/race/testdata/mop_test.go @@ -2093,3 +2093,40 @@ func TestNoRaceTinyAlloc(t *testing.T) { <-done } } + +func TestNoRaceIssue60934(t *testing.T) { + // Test that runtime.RaceDisable state doesn't accidentally get applied to + // new goroutines. + + // Create several goroutines that end after calling runtime.RaceDisable. + var wg sync.WaitGroup + ready := make(chan struct{}) + wg.Add(32) + for i := 0; i < 32; i++ { + go func() { + <-ready // ensure we have multiple goroutines running at the same time + runtime.RaceDisable() + wg.Done() + }() + } + close(ready) + wg.Wait() + + // Make sure race detector still works. If the runtime.RaceDisable state + // leaks, the happens-before edges here will be ignored and a race on x will + // be reported. + var x int + ch := make(chan struct{}, 0) + wg.Add(2) + go func() { + x = 1 + ch <- struct{}{} + wg.Done() + }() + go func() { + <-ch + _ = x + wg.Done() + }() + wg.Wait() +} diff --git a/src/runtime/trace.go b/src/runtime/trace.go index ac80ca2902..a4d50d77a0 100644 --- a/src/runtime/trace.go +++ b/src/runtime/trace.go @@ -453,12 +453,17 @@ func StopTrace() { } } + // Wait for startNanotime != endNanotime. On Windows the default interval between + // system clock ticks is typically between 1 and 15 milliseconds, which may not + // have passed since the trace started. Without nanotime moving forward, trace + // tooling has no way of identifying how much real time each cputicks time deltas + // represent. for { trace.endTime = traceClockNow() trace.endTicks = cputicks() trace.endNanotime = nanotime() - // Windows time can tick only every 15ms, wait for at least one tick. - if trace.endNanotime != trace.startNanotime { + + if trace.endNanotime != trace.startNanotime || faketime != 0 { break } osyield() diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index d6f89210a4..86df1155b5 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -1147,6 +1147,7 @@ func showfuncinfo(sf srcFunc, firstFrame bool, calleeID abi.FuncID) bool { // isExportedRuntime reports whether name is an exported runtime function. // It is only for runtime functions, so ASCII A-Z is fine. +// TODO: this handles exported functions but not exported methods. func isExportedRuntime(name string) bool { const n = len("runtime.") return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' diff --git a/src/slices/example_test.go b/src/slices/example_test.go new file mode 100644 index 0000000000..3e76907bb7 --- /dev/null +++ b/src/slices/example_test.go @@ -0,0 +1,322 @@ +// Copyright 2023 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 slices_test + +import ( + "cmp" + "fmt" + "slices" + "strconv" + "strings" +) + +func ExampleBinarySearch() { + names := []string{"Alice", "Bob", "Vera"} + n, found := slices.BinarySearch(names, "Vera") + fmt.Println("Vera:", n, found) + n, found = slices.BinarySearch(names, "Bill") + fmt.Println("Bill:", n, found) + // Output: + // Vera: 2 true + // Bill: 1 false +} + +func ExampleBinarySearchFunc() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Alice", 55}, + {"Bob", 24}, + {"Gopher", 13}, + } + n, found := slices.BinarySearchFunc(people, Person{"Bob", 0}, func(a, b Person) int { + return cmp.Compare(a.Name, b.Name) + }) + fmt.Println("Bob:", n, found) + // Output: + // Bob: 1 true +} + +func ExampleCompact() { + seq := []int{0, 1, 1, 2, 3, 5, 8} + seq = slices.Compact(seq) + fmt.Println(seq) + // Output: + // [0 1 2 3 5 8] +} + +func ExampleCompactFunc() { + names := []string{"bob", "Bob", "alice", "Vera", "VERA"} + names = slices.CompactFunc(names, func(a, b string) bool { + return strings.ToLower(a) == strings.ToLower(b) + }) + fmt.Println(names) + // Output: + // [bob alice Vera] +} + +func ExampleCompare() { + names := []string{"Alice", "Bob", "Vera"} + fmt.Println("Equal:", slices.Compare(names, []string{"Alice", "Bob", "Vera"})) + fmt.Println("V < X:", slices.Compare(names, []string{"Alice", "Bob", "Xena"})) + fmt.Println("V > C:", slices.Compare(names, []string{"Alice", "Bob", "Cat"})) + fmt.Println("3 > 2:", slices.Compare(names, []string{"Alice", "Bob"})) + // Output: + // Equal: 0 + // V < X: -1 + // V > C: 1 + // 3 > 2: 1 +} + +func ExampleCompareFunc() { + numbers := []int{0, 43, 8} + strings := []string{"0", "0", "8"} + result := slices.CompareFunc(numbers, strings, func(n int, s string) int { + sn, err := strconv.Atoi(s) + if err != nil { + return 1 + } + return cmp.Compare(n, sn) + }) + fmt.Println(result) + // Output: + // 1 +} + +func ExampleContainsFunc() { + numbers := []int{0, 42, -10, 8} + hasNegative := slices.ContainsFunc(numbers, func(n int) bool { + return n < 0 + }) + fmt.Println("Has a negative:", hasNegative) + hasOdd := slices.ContainsFunc(numbers, func(n int) bool { + return n%2 != 0 + }) + fmt.Println("Has an odd number:", hasOdd) + // Output: + // Has a negative: true + // Has an odd number: false +} + +func ExampleDelete() { + letters := []string{"a", "b", "c", "d", "e"} + letters = slices.Delete(letters, 1, 4) + fmt.Println(letters) + // Output: + // [a e] +} + +func ExampleDeleteFunc() { + seq := []int{0, 1, 1, 2, 3, 5, 8} + seq = slices.DeleteFunc(seq, func(n int) bool { + return n%2 != 0 // delete the odd numbers + }) + fmt.Println(seq) + // Output: + // [0 2 8] +} + +func ExampleEqual() { + numbers := []int{0, 42, 8} + fmt.Println(slices.Equal(numbers, []int{0, 42, 8})) + fmt.Println(slices.Equal(numbers, []int{10})) + // Output: + // true + // false +} + +func ExampleEqualFunc() { + numbers := []int{0, 42, 8} + strings := []string{"000", "42", "0o10"} + equal := slices.EqualFunc(numbers, strings, func(n int, s string) bool { + sn, err := strconv.ParseInt(s, 0, 64) + if err != nil { + return false + } + return n == int(sn) + }) + fmt.Println(equal) + // Output: + // true +} + +func ExampleIndex() { + numbers := []int{0, 42, 8} + fmt.Println(slices.Index(numbers, 8)) + fmt.Println(slices.Index(numbers, 7)) + // Output: + // 2 + // -1 +} + +func ExampleIndexFunc() { + numbers := []int{0, 42, -10, 8} + i := slices.IndexFunc(numbers, func(n int) bool { + return n < 0 + }) + fmt.Println("First negative at index", i) + // Output: + // First negative at index 2 +} + +func ExampleInsert() { + names := []string{"Alice", "Bob", "Vera"} + names = slices.Insert(names, 1, "Bill", "Billie") + names = slices.Insert(names, len(names), "Zac") + fmt.Println(names) + // Output: + // [Alice Bill Billie Bob Vera Zac] +} + +func ExampleIsSorted() { + fmt.Println(slices.IsSorted([]string{"Alice", "Bob", "Vera"})) + fmt.Println(slices.IsSorted([]int{0, 2, 1})) + // Output: + // true + // false +} + +func ExampleIsSortedFunc() { + names := []string{"alice", "Bob", "VERA"} + isSortedInsensitive := slices.IsSortedFunc(names, func(a, b string) int { + return cmp.Compare(strings.ToLower(a), strings.ToLower(b)) + }) + fmt.Println(isSortedInsensitive) + fmt.Println(slices.IsSorted(names)) + // Output: + // true + // false +} + +func ExampleMax() { + numbers := []int{0, 42, -10, 8} + fmt.Println(slices.Max(numbers)) + // Output: + // 42 +} + +func ExampleMaxFunc() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Gopher", 13}, + {"Alice", 55}, + {"Vera", 24}, + {"Bob", 55}, + } + firstOldest := slices.MaxFunc(people, func(a, b Person) int { + return cmp.Compare(a.Age, b.Age) + }) + fmt.Println(firstOldest.Name) + // Output: + // Alice +} + +func ExampleMin() { + numbers := []int{0, 42, -10, 8} + fmt.Println(slices.Min(numbers)) + // Output: + // -10 +} + +func ExampleMinFunc() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Gopher", 13}, + {"Bob", 5}, + {"Vera", 24}, + {"Bill", 5}, + } + firstYoungest := slices.MinFunc(people, func(a, b Person) int { + return cmp.Compare(a.Age, b.Age) + }) + fmt.Println(firstYoungest.Name) + // Output: + // Bob +} + +func ExampleReplace() { + names := []string{"Alice", "Bob", "Vera", "Zac"} + names = slices.Replace(names, 1, 3, "Bill", "Billie", "Cat") + fmt.Println(names) + // Output: + // [Alice Bill Billie Cat Zac] +} + +func ExampleReverse() { + names := []string{"alice", "Bob", "VERA"} + slices.Reverse(names) + fmt.Println(names) + // Output: + // [VERA Bob alice] +} + +func ExampleSort() { + smallInts := []int8{0, 42, -10, 8} + slices.Sort(smallInts) + fmt.Println(smallInts) + // Output: + // [-10 0 8 42] +} + +func ExampleSortFunc_caseInsensitive() { + names := []string{"Bob", "alice", "VERA"} + slices.SortFunc(names, func(a, b string) int { + return cmp.Compare(strings.ToLower(a), strings.ToLower(b)) + }) + fmt.Println(names) + // Output: + // [alice Bob VERA] +} + +func ExampleSortFunc_multiField() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Gopher", 13}, + {"Alice", 55}, + {"Bob", 24}, + {"Alice", 20}, + } + slices.SortFunc(people, func(a, b Person) int { + if n := cmp.Compare(a.Name, b.Name); n != 0 { + return n + } + // If names are equal, order by age + return cmp.Compare(a.Age, b.Age) + }) + fmt.Println(people) + // Output: + // [{Alice 20} {Alice 55} {Bob 24} {Gopher 13}] +} + +func ExampleSortStableFunc() { + type Person struct { + Name string + Age int + } + people := []Person{ + {"Gopher", 13}, + {"Alice", 20}, + {"Bob", 24}, + {"Alice", 55}, + } + // Stable sort by name, keeping age ordering of Alices intact + slices.SortStableFunc(people, func(a, b Person) int { + return cmp.Compare(a.Name, b.Name) + }) + fmt.Println(people) + // Output: + // [{Alice 20} {Alice 55} {Bob 24} {Gopher 13}] +} diff --git a/src/slices/slices.go b/src/slices/slices.go index c8eacae90e..afeed0afb5 100644 --- a/src/slices/slices.go +++ b/src/slices/slices.go @@ -27,7 +27,7 @@ func Equal[S ~[]E, E comparable](s1, s2 S) bool { return true } -// EqualFunc reports whether two slices are equal using a comparison +// EqualFunc reports whether two slices are equal using an equality // function on each pair of elements. If the lengths are different, // EqualFunc returns false. Otherwise, the elements are compared in // increasing index order, and the comparison stops at the first index @@ -68,7 +68,7 @@ func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) int { return 0 } -// CompareFunc is like Compare but uses a custom comparison function on each +// CompareFunc is like [Compare] but uses a custom comparison function on each // pair of elements. // The result is the first non-zero result of cmp; if cmp always // returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2), @@ -210,7 +210,6 @@ func Insert[S ~[]E, E any](s S, i int, v ...E) S { // Delete removes the elements s[i:j] from s, returning the modified slice. // Delete panics if s[i:j] is not a valid slice of s. -// Delete modifies the contents of the slice s; it does not create a new slice. // Delete is O(len(s)-j), so if many items must be deleted, it is better to // make a single call deleting them all together than to delete one at a time. // Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those @@ -224,8 +223,6 @@ func Delete[S ~[]E, E any](s S, i, j int) S { // DeleteFunc removes any elements from s for which del returns true, // returning the modified slice. -// DeleteFunc modifies the contents of the slice s; -// it does not create a new slice. // When DeleteFunc removes m elements, it might not modify the elements // s[len(s)-m:len(s)]. If those elements contain pointers you might consider // zeroing those elements so that objects they reference can be garbage @@ -348,7 +345,8 @@ func Clone[S ~[]E, E any](s S) S { // Compact replaces consecutive runs of equal elements with a single copy. // This is like the uniq command found on Unix. -// Compact modifies the contents of the slice s; it does not create a new slice. +// Compact modifies the contents of the slice s and returns the modified slice, +// which may have a smaller length. // When Compact discards m elements in total, it might not modify the elements // s[len(s)-m:len(s)]. If those elements contain pointers you might consider // zeroing those elements so that objects they reference can be garbage collected. @@ -368,7 +366,8 @@ func Compact[S ~[]E, E comparable](s S) S { return s[:i] } -// CompactFunc is like Compact but uses a comparison function. +// CompactFunc is like [Compact] but uses an equality function to compare elements. +// For runs of elements that compare equal, CompactFunc keeps the first one. func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { if len(s) < 2 { return s diff --git a/src/slices/sort.go b/src/slices/sort.go index 24fc6e26b6..822f2fceb4 100644 --- a/src/slices/sort.go +++ b/src/slices/sort.go @@ -29,7 +29,7 @@ func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { } // SortStableFunc sorts the slice x while keeping the original order of equal -// elements, using cmp to compare elements. +// elements, using cmp to compare elements in the same way as [SortFunc]. func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { stableCmpFunc(x, len(x), cmp) } @@ -45,7 +45,7 @@ func IsSorted[S ~[]E, E cmp.Ordered](x S) bool { } // IsSortedFunc reports whether x is sorted in ascending order, with cmp as the -// comparison function. +// comparison function as defined by [SortFunc]. func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool { for i := len(x) - 1; i > 0; i-- { if cmp(x[i], x[i-1]) < 0 { @@ -70,7 +70,8 @@ func Min[S ~[]E, E cmp.Ordered](x S) E { } // MinFunc returns the minimal value in x, using cmp to compare elements. -// It panics if x is empty. +// It panics if x is empty. If there is more than one minimal element +// according to the cmp function, MinFunc returns the first one. func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E { if len(x) < 1 { panic("slices.MinFunc: empty list") @@ -99,7 +100,8 @@ func Max[S ~[]E, E cmp.Ordered](x S) E { } // MaxFunc returns the maximal value in x, using cmp to compare elements. -// It panics if x is empty. +// It panics if x is empty. If there is more than one maximal element +// according to the cmp function, MaxFunc returns the first one. func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E { if len(x) < 1 { panic("slices.MaxFunc: empty list") @@ -136,7 +138,7 @@ func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) { return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target))) } -// BinarySearchFunc works like BinarySearch, but uses a custom comparison +// BinarySearchFunc works like [BinarySearch], but uses a custom comparison // function. The slice must be sorted in increasing order, where "increasing" // is defined by cmp. cmp should return 0 if the slice element matches // the target, a negative number if the slice element precedes the target, diff --git a/src/slices/sort_test.go b/src/slices/sort_test.go index 0e9df92b63..af0585935d 100644 --- a/src/slices/sort_test.go +++ b/src/slices/sort_test.go @@ -173,6 +173,15 @@ func TestStability(t *testing.T) { } } +type S struct { + a int + b string +} + +func cmpS(s1, s2 S) int { + return cmp.Compare(s1.a, s2.a) +} + func TestMinMax(t *testing.T) { intCmp := func(a, b int) int { return a - b } @@ -214,6 +223,25 @@ func TestMinMax(t *testing.T) { } }) } + + svals := []S{ + {1, "a"}, + {2, "a"}, + {1, "b"}, + {2, "b"}, + } + + gotMin := MinFunc(svals, cmpS) + wantMin := S{1, "a"} + if gotMin != wantMin { + t.Errorf("MinFunc(%v) = %v, want %v", svals, gotMin, wantMin) + } + + gotMax := MaxFunc(svals, cmpS) + wantMax := S{2, "a"} + if gotMax != wantMax { + t.Errorf("MaxFunc(%v) = %v, want %v", svals, gotMax, wantMax) + } } func TestMinMaxNaNs(t *testing.T) { diff --git a/src/syscall/dirent.go b/src/syscall/dirent.go index eee94bf73c..1a0f1eec11 100644 --- a/src/syscall/dirent.go +++ b/src/syscall/dirent.go @@ -6,7 +6,10 @@ package syscall -import "unsafe" +import ( + "runtime" + "unsafe" +) // readInt returns the size-bytes unsigned integer in native byte order at offset off. func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { @@ -75,7 +78,9 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, if !ok { break } - if ino == 0 { // File absent in directory. + // See src/os/dir_unix.go for the reason why this condition is + // excluded on wasip1. + if ino == 0 && runtime.GOOS != "wasip1" { // File absent in directory. continue } const namoff = uint64(unsafe.Offsetof(Dirent{}.Name)) diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go index 20d74b51e0..220a005e1a 100644 --- a/src/syscall/env_windows.go +++ b/src/syscall/env_windows.go @@ -62,7 +62,7 @@ func Clearenv() { for _, s := range Environ() { // Environment variables can begin with = // so start looking for the separator = at j=1. - // https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx + // https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133 for j := 1; j < len(s); j++ { if s[j] == '=' { Unsetenv(s[0:j]) diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index feb1e26432..dfbb38ac16 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -641,11 +641,6 @@ childerror: } } -// Try to open a pipe with O_CLOEXEC set on both file descriptors. -func forkExecPipe(p []int) (err error) { - return Pipe2(p, O_CLOEXEC) -} - func formatIDMappings(idMap []SysProcIDMap) []byte { var data []byte for _, im := range idMap { diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go index 14edd023d3..9a5f2d3295 100644 --- a/src/syscall/exec_unix.go +++ b/src/syscall/exec_unix.go @@ -241,89 +241,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) return pid, nil } -var ( - // Guard the forking variable. - forkingLock sync.Mutex - // Number of goroutines currently forking, and thus the - // number of goroutines holding a conceptual write lock - // on ForkLock. - forking int -) - -// hasWaitingReaders reports whether any goroutine is waiting -// to acquire a read lock on rw. It is defined in the sync package. -func hasWaitingReaders(rw *sync.RWMutex) bool - -// acquireForkLock acquires a write lock on ForkLock. -// ForkLock is exported and we've promised that during a fork -// we will call ForkLock.Lock, so that no other threads create -// new fds that are not yet close-on-exec before we fork. -// But that forces all fork calls to be serialized, which is bad. -// But we haven't promised that serialization, and it is essentially -// undetectable by other users of ForkLock, which is good. -// Avoid the serialization by ensuring that ForkLock is locked -// at the first fork and unlocked when there are no more forks. -func acquireForkLock() { - forkingLock.Lock() - defer forkingLock.Unlock() - - if forking == 0 { - // There is no current write lock on ForkLock. - ForkLock.Lock() - forking++ - return - } - - // ForkLock is currently locked for writing. - - if hasWaitingReaders(&ForkLock) { - // ForkLock is locked for writing, and at least one - // goroutine is waiting to read from it. - // To avoid lock starvation, allow readers to proceed. - // The simple way to do this is for us to acquire a - // read lock. That will block us until all current - // conceptual write locks are released. - // - // Note that this case is unusual on modern systems - // with O_CLOEXEC and SOCK_CLOEXEC. On those systems - // the standard library should never take a read - // lock on ForkLock. - - forkingLock.Unlock() - - ForkLock.RLock() - ForkLock.RUnlock() - - forkingLock.Lock() - - // Readers got a chance, so now take the write lock. - - if forking == 0 { - ForkLock.Lock() - } - } - - forking++ -} - -// releaseForkLock releases the conceptual write lock on ForkLock -// acquired by acquireForkLock. -func releaseForkLock() { - forkingLock.Lock() - defer forkingLock.Unlock() - - if forking <= 0 { - panic("syscall.releaseForkLock: negative count") - } - - forking-- - - if forking == 0 { - // No more conceptual write locks. - ForkLock.Unlock() - } -} - // Combination of fork and exec, careful to be thread safe. func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { return forkExec(argv0, argv, attr) diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index 45295dedff..0a93bc0a80 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -247,7 +247,7 @@ type SysProcAttr struct { Token Token // if set, runs new process in the security context represented by the token ProcessAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the new process ThreadAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the main thread of the new process - NoInheritHandles bool // if set, each inheritable handle in the calling process is not inherited by the new process + NoInheritHandles bool // if set, no handles are inherited by the new process, not even the standard handles, contained in ProcAttr.Files, nor the ones contained in AdditionalInheritedHandles AdditionalInheritedHandles []Handle // a list of additional handles, already marked as inheritable, that will be inherited by the new process ParentProcess Handle // if non-zero, the new process regards the process given by this handle as its parent process, and AdditionalInheritedHandles, if set, should exist in this parent process } diff --git a/src/syscall/forkpipe.go b/src/syscall/forkpipe.go index 5082abc41c..1f4292f686 100644 --- a/src/syscall/forkpipe.go +++ b/src/syscall/forkpipe.go @@ -6,7 +6,8 @@ package syscall -// Try to open a pipe with O_CLOEXEC set on both file descriptors. +// forkExecPipe opens a pipe and non-atomically sets O_CLOEXEC on both file +// descriptors. func forkExecPipe(p []int) error { err := Pipe(p) if err != nil { @@ -19,3 +20,11 @@ func forkExecPipe(p []int) error { _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC) return err } + +func acquireForkLock() { + ForkLock.Lock() +} + +func releaseForkLock() { + ForkLock.Unlock() +} diff --git a/src/syscall/forkpipe2.go b/src/syscall/forkpipe2.go index 6ab1391c12..bbecfdabf8 100644 --- a/src/syscall/forkpipe2.go +++ b/src/syscall/forkpipe2.go @@ -2,10 +2,97 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build dragonfly || freebsd || netbsd || openbsd || solaris +//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris package syscall +import "sync" + +// forkExecPipe atomically opens a pipe with O_CLOEXEC set on both file +// descriptors. func forkExecPipe(p []int) error { return Pipe2(p, O_CLOEXEC) } + +var ( + // Guard the forking variable. + forkingLock sync.Mutex + // Number of goroutines currently forking, and thus the + // number of goroutines holding a conceptual write lock + // on ForkLock. + forking int +) + +// hasWaitingReaders reports whether any goroutine is waiting +// to acquire a read lock on rw. It is defined in the sync package. +func hasWaitingReaders(rw *sync.RWMutex) bool + +// acquireForkLock acquires a write lock on ForkLock. +// ForkLock is exported and we've promised that during a fork +// we will call ForkLock.Lock, so that no other threads create +// new fds that are not yet close-on-exec before we fork. +// But that forces all fork calls to be serialized, which is bad. +// But we haven't promised that serialization, and it is essentially +// undetectable by other users of ForkLock, which is good. +// Avoid the serialization by ensuring that ForkLock is locked +// at the first fork and unlocked when there are no more forks. +func acquireForkLock() { + forkingLock.Lock() + defer forkingLock.Unlock() + + if forking == 0 { + // There is no current write lock on ForkLock. + ForkLock.Lock() + forking++ + return + } + + // ForkLock is currently locked for writing. + + if hasWaitingReaders(&ForkLock) { + // ForkLock is locked for writing, and at least one + // goroutine is waiting to read from it. + // To avoid lock starvation, allow readers to proceed. + // The simple way to do this is for us to acquire a + // read lock. That will block us until all current + // conceptual write locks are released. + // + // Note that this case is unusual on modern systems + // with O_CLOEXEC and SOCK_CLOEXEC. On those systems + // the standard library should never take a read + // lock on ForkLock. + + forkingLock.Unlock() + + ForkLock.RLock() + ForkLock.RUnlock() + + forkingLock.Lock() + + // Readers got a chance, so now take the write lock. + + if forking == 0 { + ForkLock.Lock() + } + } + + forking++ +} + +// releaseForkLock releases the conceptual write lock on ForkLock +// acquired by acquireForkLock. +func releaseForkLock() { + forkingLock.Lock() + defer forkingLock.Unlock() + + if forking <= 0 { + panic("syscall.releaseForkLock: negative count") + } + + forking-- + + if forking == 0 { + // No more conceptual write locks. + ForkLock.Unlock() + } +} diff --git a/src/syscall/fs_wasip1.go b/src/syscall/fs_wasip1.go index d60ab0b53e..4ad3f9610b 100644 --- a/src/syscall/fs_wasip1.go +++ b/src/syscall/fs_wasip1.go @@ -11,6 +11,20 @@ import ( "unsafe" ) +func init() { + // Try to set stdio to non-blocking mode before the os package + // calls NewFile for each fd. NewFile queries the non-blocking flag + // but doesn't change it, even if the runtime supports non-blocking + // stdio. Since WebAssembly modules are single-threaded, blocking + // system calls temporarily halt execution of the module. If the + // runtime supports non-blocking stdio, the Go runtime is able to + // use the WASI net poller to poll for read/write readiness and is + // able to schedule goroutines while waiting. + SetNonblock(0, true) + SetNonblock(1, true) + SetNonblock(2, true) +} + type uintptr32 = uint32 type size = uint32 type fdflags = uint32 diff --git a/src/syscall/syscall_wasip1.go b/src/syscall/syscall_wasip1.go index 5d19c000ae..e66afee5e9 100644 --- a/src/syscall/syscall_wasip1.go +++ b/src/syscall/syscall_wasip1.go @@ -478,3 +478,16 @@ func SetNonblock(fd int, nonblocking bool) error { errno := fd_fdstat_set_flags(int32(fd), flags) return errnoErr(errno) } + +type Rlimit struct { + Cur uint64 + Max uint64 +} + +const ( + RLIMIT_NOFILE = iota +) + +func Getrlimit(which int, lim *Rlimit) error { + return ENOSYS +} diff --git a/src/testing/slogtest/slogtest.go b/src/testing/slogtest/slogtest.go index 71076e52f4..b16d1227dc 100644 --- a/src/testing/slogtest/slogtest.go +++ b/src/testing/slogtest/slogtest.go @@ -163,6 +163,20 @@ func TestHandler(h slog.Handler, results func() []map[string]any) error { }, }, { + explanation: withSource("a Handler should not output groups for an empty Record"), + f: func(l *slog.Logger) { + l.With("a", "b").WithGroup("G").With("c", "d").WithGroup("H").Info("msg") + }, + checks: []check{ + hasKey(slog.TimeKey), + hasKey(slog.LevelKey), + hasAttr(slog.MessageKey, "msg"), + hasAttr("a", "b"), + inGroup("G", hasAttr("c", "d")), + inGroup("G", missingKey("H")), + }, + }, + { explanation: withSource("a Handler should call Resolve on attribute values"), f: func(l *slog.Logger) { l.Info("msg", "k", &replace{"replaced"}) diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go index 8aac3b68f6..2f791240f9 100644 --- a/src/time/sleep_test.go +++ b/src/time/sleep_test.go @@ -418,22 +418,22 @@ func TestReset(t *testing.T) { // We try to run this test with increasingly larger multiples // until one works so slow, loaded hardware isn't as flaky, // but without slowing down fast machines unnecessarily. - const unit = 25 * Millisecond - tries := []Duration{ - 1 * unit, - 3 * unit, - 7 * unit, - 15 * unit, - } - var err error - for _, d := range tries { - err = testReset(d) + // + // (maxDuration is several orders of magnitude longer than we + // expect this test to actually take on a fast, unloaded machine.) + d := 1 * Millisecond + const maxDuration = 10 * Second + for { + err := testReset(d) if err == nil { - t.Logf("passed using duration %v", d) - return + break } + d *= 2 + if d > maxDuration { + t.Error(err) + } + t.Logf("%v; trying duration %v", err, d) } - t.Error(err) } // Test that sleeping (via Sleep or Timer) for an interval so large it diff --git a/src/vendor/golang.org/x/net/dns/dnsmessage/message.go b/src/vendor/golang.org/x/net/dns/dnsmessage/message.go index 1577d4a19d..37da3de4d3 100644 --- a/src/vendor/golang.org/x/net/dns/dnsmessage/message.go +++ b/src/vendor/golang.org/x/net/dns/dnsmessage/message.go @@ -527,12 +527,14 @@ func (r *Resource) pack(msg []byte, compression map[string]int, compressionOff i // When parsing is started, the Header is parsed. Next, each Question can be // either parsed or skipped. Alternatively, all Questions can be skipped at // once. When all Questions have been parsed, attempting to parse Questions -// will return (nil, nil) and attempting to skip Questions will return -// (true, nil). After all Questions have been either parsed or skipped, all +// will return the [ErrSectionDone] error. +// After all Questions have been either parsed or skipped, all // Answers, Authorities and Additionals can be either parsed or skipped in the // same way, and each type of Resource must be fully parsed or skipped before // proceeding to the next type of Resource. // +// Parser is safe to copy to preserve the parsing state. +// // Note that there is no requirement to fully skip or parse the message. type Parser struct { msg []byte diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 88d2554c04..2b5f965f8f 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -1,4 +1,4 @@ -# golang.org/x/crypto v0.10.0 +# golang.org/x/crypto v0.11.1-0.20230711161743-2e82bdd1719d ## explicit; go 1.17 golang.org/x/crypto/chacha20 golang.org/x/crypto/chacha20poly1305 @@ -7,7 +7,7 @@ golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/hkdf golang.org/x/crypto/internal/alias golang.org/x/crypto/internal/poly1305 -# golang.org/x/net v0.11.1-0.20230613203745-f5464ddb689c +# golang.org/x/net v0.12.1-0.20230712162946-57553cbff163 ## explicit; go 1.17 golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts @@ -17,10 +17,10 @@ golang.org/x/net/idna golang.org/x/net/lif golang.org/x/net/nettest golang.org/x/net/route -# golang.org/x/sys v0.9.0 +# golang.org/x/sys v0.10.0 ## explicit; go 1.17 golang.org/x/sys/cpu -# golang.org/x/text v0.10.1-0.20230613190012-2df65d769a9e +# golang.org/x/text v0.11.0 ## explicit; go 1.17 golang.org/x/text/secure/bidirule golang.org/x/text/transform diff --git a/test/codegen/bits.go b/test/codegen/bits.go index 4f70627c25..018f5b909e 100644 --- a/test/codegen/bits.go +++ b/test/codegen/bits.go @@ -374,3 +374,23 @@ func foldConstOutOfRange(a uint64) uint64 { // arm64: "MOVD\t[$]19088744",-"ADD\t[$]19088744" return a + 0x1234568 } + +// Verify sign-extended values are not zero-extended under a bit mask (#61297) +func signextendAndMask8to64(a int8) (s, z uint64) { + // ppc64x: "MOVB", "ANDCC\t[$]1015," + s = uint64(a) & 0x3F7 + // ppc64x: -"MOVB", "ANDCC\t[$]247," + z = uint64(uint8(a)) & 0x3F7 + return + +} + +// Verify zero-extended values are not sign-extended under a bit mask (#61297) +func zeroextendAndMask8to64(a int8, b int16) (x, y uint64) { + // ppc64x: -"MOVB\t", -"ANDCC", "MOVBZ" + x = uint64(a) & 0xFF + // ppc64x: -"MOVH\t", -"ANDCC", "MOVHZ" + y = uint64(b) & 0xFFFF + return + +} diff --git a/test/codegen/floats.go b/test/codegen/floats.go index 81471082d4..9cb62e031a 100644 --- a/test/codegen/floats.go +++ b/test/codegen/floats.go @@ -20,6 +20,7 @@ func Mul2(f float64) float64 { // arm/7:"ADDD",-"MULD" // arm64:"FADDD",-"FMULD" // ppc64x:"FADD",-"FMUL" + // riscv64:"FADDD",-"FMULD" return f * 2.0 } @@ -29,6 +30,7 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) { // arm/7:"MULD",-"DIVD" // arm64:"FMULD",-"FDIVD" // ppc64x:"FMUL",-"FDIV" + // riscv64:"FMULD",-"FDIVD" x := f1 / 16.0 // 386/sse2:"MULSD",-"DIVSD" @@ -36,6 +38,7 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) { // arm/7:"MULD",-"DIVD" // arm64:"FMULD",-"FDIVD" // ppc64x:"FMUL",-"FDIVD" + // riscv64:"FMULD",-"FDIVD" y := f2 / 0.125 // 386/sse2:"ADDSD",-"DIVSD",-"MULSD" @@ -43,6 +46,7 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) { // arm/7:"ADDD",-"MULD",-"DIVD" // arm64:"FADDD",-"FMULD",-"FDIVD" // ppc64x:"FADD",-"FMUL",-"FDIV" + // riscv64:"FADDD",-"FMULD",-"FDIVD" z := f3 / 0.5 return x, y, z diff --git a/test/codegen/math.go b/test/codegen/math.go index 6a7d304afd..331ebbe609 100644 --- a/test/codegen/math.go +++ b/test/codegen/math.go @@ -143,13 +143,13 @@ func fms(x, y, z float64) float64 { return math.FMA(x, y, -z) } -func fnma(x, y, z float64) float64 { - // riscv64:"FNMADDD" +func fnms(x, y, z float64) float64 { + // riscv64:"FNMSUBD",-"FNMADDD" return math.FMA(-x, y, z) } -func fnms(x, y, z float64) float64 { - // riscv64:"FNMSUBD" +func fnma(x, y, z float64) float64 { + // riscv64:"FNMADDD",-"FNMSUBD" return math.FMA(x, -y, -z) } diff --git a/test/fixedbugs/bug516.go b/test/fixedbugs/bug516.go new file mode 100644 index 0000000000..e52eb215ef --- /dev/null +++ b/test/fixedbugs/bug516.go @@ -0,0 +1,13 @@ +// compile + +// Copyright 2023 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. + +// Caused a gofrontend crash. + +package p + +func F(b []byte, i int) { + *(*[1]byte)(b[i*2:]) = [1]byte{} +} diff --git a/test/fixedbugs/issue60945.dir/a.go b/test/fixedbugs/issue60945.dir/a.go new file mode 100644 index 0000000000..663a0cfc69 --- /dev/null +++ b/test/fixedbugs/issue60945.dir/a.go @@ -0,0 +1,22 @@ +// Copyright 2023 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 a + +type S struct{} + +func callClosure(closure func()) { + closure() +} + +func (s *S) M() { + callClosure(func() { + defer f(s.m) // prevent closures to be inlined. + }) +} + +func (s *S) m() {} + +//go:noinline +func f(a ...any) {} diff --git a/test/fixedbugs/issue60945.dir/b.go b/test/fixedbugs/issue60945.dir/b.go new file mode 100644 index 0000000000..e60d9dc7c1 --- /dev/null +++ b/test/fixedbugs/issue60945.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2023 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 b + +import "./a" + +var _ = (&a.S{}).M diff --git a/test/fixedbugs/issue60945.go b/test/fixedbugs/issue60945.go new file mode 100644 index 0000000000..5c4c5c0a8f --- /dev/null +++ b/test/fixedbugs/issue60945.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2023 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 ignored diff --git a/test/fixedbugs/issue60982.go b/test/fixedbugs/issue60982.go new file mode 100644 index 0000000000..4e5fc34646 --- /dev/null +++ b/test/fixedbugs/issue60982.go @@ -0,0 +1,2023 @@ +// compile + +// Copyright 2023 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 + +func f(x int, b bool) int { + if x >= 1000 { + if b { // from #61041 + var a struct{ f int64 } + _ = max(0, a.f) + } + + return max(x, 2000) + } + // generate 1000 basic blocks to put this function + // well into the "large function" phi generation algorithm. + switch x { + case 0: + return 0 + case 1: + return 1 + case 2: + return 2 + case 3: + return 3 + case 4: + return 4 + case 5: + return 5 + case 6: + return 6 + case 7: + return 7 + case 8: + return 8 + case 9: + return 9 + case 10: + return 10 + case 11: + return 11 + case 12: + return 12 + case 13: + return 13 + case 14: + return 14 + case 15: + return 15 + case 16: + return 16 + case 17: + return 17 + case 18: + return 18 + case 19: + return 19 + case 20: + return 20 + case 21: + return 21 + case 22: + return 22 + case 23: + return 23 + case 24: + return 24 + case 25: + return 25 + case 26: + return 26 + case 27: + return 27 + case 28: + return 28 + case 29: + return 29 + case 30: + return 30 + case 31: + return 31 + case 32: + return 32 + case 33: + return 33 + case 34: + return 34 + case 35: + return 35 + case 36: + return 36 + case 37: + return 37 + case 38: + return 38 + case 39: + return 39 + case 40: + return 40 + case 41: + return 41 + case 42: + return 42 + case 43: + return 43 + case 44: + return 44 + case 45: + return 45 + case 46: + return 46 + case 47: + return 47 + case 48: + return 48 + case 49: + return 49 + case 50: + return 50 + case 51: + return 51 + case 52: + return 52 + case 53: + return 53 + case 54: + return 54 + case 55: + return 55 + case 56: + return 56 + case 57: + return 57 + case 58: + return 58 + case 59: + return 59 + case 60: + return 60 + case 61: + return 61 + case 62: + return 62 + case 63: + return 63 + case 64: + return 64 + case 65: + return 65 + case 66: + return 66 + case 67: + return 67 + case 68: + return 68 + case 69: + return 69 + case 70: + return 70 + case 71: + return 71 + case 72: + return 72 + case 73: + return 73 + case 74: + return 74 + case 75: + return 75 + case 76: + return 76 + case 77: + return 77 + case 78: + return 78 + case 79: + return 79 + case 80: + return 80 + case 81: + return 81 + case 82: + return 82 + case 83: + return 83 + case 84: + return 84 + case 85: + return 85 + case 86: + return 86 + case 87: + return 87 + case 88: + return 88 + case 89: + return 89 + case 90: + return 90 + case 91: + return 91 + case 92: + return 92 + case 93: + return 93 + case 94: + return 94 + case 95: + return 95 + case 96: + return 96 + case 97: + return 97 + case 98: + return 98 + case 99: + return 99 + case 100: + return 100 + case 101: + return 101 + case 102: + return 102 + case 103: + return 103 + case 104: + return 104 + case 105: + return 105 + case 106: + return 106 + case 107: + return 107 + case 108: + return 108 + case 109: + return 109 + case 110: + return 110 + case 111: + return 111 + case 112: + return 112 + case 113: + return 113 + case 114: + return 114 + case 115: + return 115 + case 116: + return 116 + case 117: + return 117 + case 118: + return 118 + case 119: + return 119 + case 120: + return 120 + case 121: + return 121 + case 122: + return 122 + case 123: + return 123 + case 124: + return 124 + case 125: + return 125 + case 126: + return 126 + case 127: + return 127 + case 128: + return 128 + case 129: + return 129 + case 130: + return 130 + case 131: + return 131 + case 132: + return 132 + case 133: + return 133 + case 134: + return 134 + case 135: + return 135 + case 136: + return 136 + case 137: + return 137 + case 138: + return 138 + case 139: + return 139 + case 140: + return 140 + case 141: + return 141 + case 142: + return 142 + case 143: + return 143 + case 144: + return 144 + case 145: + return 145 + case 146: + return 146 + case 147: + return 147 + case 148: + return 148 + case 149: + return 149 + case 150: + return 150 + case 151: + return 151 + case 152: + return 152 + case 153: + return 153 + case 154: + return 154 + case 155: + return 155 + case 156: + return 156 + case 157: + return 157 + case 158: + return 158 + case 159: + return 159 + case 160: + return 160 + case 161: + return 161 + case 162: + return 162 + case 163: + return 163 + case 164: + return 164 + case 165: + return 165 + case 166: + return 166 + case 167: + return 167 + case 168: + return 168 + case 169: + return 169 + case 170: + return 170 + case 171: + return 171 + case 172: + return 172 + case 173: + return 173 + case 174: + return 174 + case 175: + return 175 + case 176: + return 176 + case 177: + return 177 + case 178: + return 178 + case 179: + return 179 + case 180: + return 180 + case 181: + return 181 + case 182: + return 182 + case 183: + return 183 + case 184: + return 184 + case 185: + return 185 + case 186: + return 186 + case 187: + return 187 + case 188: + return 188 + case 189: + return 189 + case 190: + return 190 + case 191: + return 191 + case 192: + return 192 + case 193: + return 193 + case 194: + return 194 + case 195: + return 195 + case 196: + return 196 + case 197: + return 197 + case 198: + return 198 + case 199: + return 199 + case 200: + return 200 + case 201: + return 201 + case 202: + return 202 + case 203: + return 203 + case 204: + return 204 + case 205: + return 205 + case 206: + return 206 + case 207: + return 207 + case 208: + return 208 + case 209: + return 209 + case 210: + return 210 + case 211: + return 211 + case 212: + return 212 + case 213: + return 213 + case 214: + return 214 + case 215: + return 215 + case 216: + return 216 + case 217: + return 217 + case 218: + return 218 + case 219: + return 219 + case 220: + return 220 + case 221: + return 221 + case 222: + return 222 + case 223: + return 223 + case 224: + return 224 + case 225: + return 225 + case 226: + return 226 + case 227: + return 227 + case 228: + return 228 + case 229: + return 229 + case 230: + return 230 + case 231: + return 231 + case 232: + return 232 + case 233: + return 233 + case 234: + return 234 + case 235: + return 235 + case 236: + return 236 + case 237: + return 237 + case 238: + return 238 + case 239: + return 239 + case 240: + return 240 + case 241: + return 241 + case 242: + return 242 + case 243: + return 243 + case 244: + return 244 + case 245: + return 245 + case 246: + return 246 + case 247: + return 247 + case 248: + return 248 + case 249: + return 249 + case 250: + return 250 + case 251: + return 251 + case 252: + return 252 + case 253: + return 253 + case 254: + return 254 + case 255: + return 255 + case 256: + return 256 + case 257: + return 257 + case 258: + return 258 + case 259: + return 259 + case 260: + return 260 + case 261: + return 261 + case 262: + return 262 + case 263: + return 263 + case 264: + return 264 + case 265: + return 265 + case 266: + return 266 + case 267: + return 267 + case 268: + return 268 + case 269: + return 269 + case 270: + return 270 + case 271: + return 271 + case 272: + return 272 + case 273: + return 273 + case 274: + return 274 + case 275: + return 275 + case 276: + return 276 + case 277: + return 277 + case 278: + return 278 + case 279: + return 279 + case 280: + return 280 + case 281: + return 281 + case 282: + return 282 + case 283: + return 283 + case 284: + return 284 + case 285: + return 285 + case 286: + return 286 + case 287: + return 287 + case 288: + return 288 + case 289: + return 289 + case 290: + return 290 + case 291: + return 291 + case 292: + return 292 + case 293: + return 293 + case 294: + return 294 + case 295: + return 295 + case 296: + return 296 + case 297: + return 297 + case 298: + return 298 + case 299: + return 299 + case 300: + return 300 + case 301: + return 301 + case 302: + return 302 + case 303: + return 303 + case 304: + return 304 + case 305: + return 305 + case 306: + return 306 + case 307: + return 307 + case 308: + return 308 + case 309: + return 309 + case 310: + return 310 + case 311: + return 311 + case 312: + return 312 + case 313: + return 313 + case 314: + return 314 + case 315: + return 315 + case 316: + return 316 + case 317: + return 317 + case 318: + return 318 + case 319: + return 319 + case 320: + return 320 + case 321: + return 321 + case 322: + return 322 + case 323: + return 323 + case 324: + return 324 + case 325: + return 325 + case 326: + return 326 + case 327: + return 327 + case 328: + return 328 + case 329: + return 329 + case 330: + return 330 + case 331: + return 331 + case 332: + return 332 + case 333: + return 333 + case 334: + return 334 + case 335: + return 335 + case 336: + return 336 + case 337: + return 337 + case 338: + return 338 + case 339: + return 339 + case 340: + return 340 + case 341: + return 341 + case 342: + return 342 + case 343: + return 343 + case 344: + return 344 + case 345: + return 345 + case 346: + return 346 + case 347: + return 347 + case 348: + return 348 + case 349: + return 349 + case 350: + return 350 + case 351: + return 351 + case 352: + return 352 + case 353: + return 353 + case 354: + return 354 + case 355: + return 355 + case 356: + return 356 + case 357: + return 357 + case 358: + return 358 + case 359: + return 359 + case 360: + return 360 + case 361: + return 361 + case 362: + return 362 + case 363: + return 363 + case 364: + return 364 + case 365: + return 365 + case 366: + return 366 + case 367: + return 367 + case 368: + return 368 + case 369: + return 369 + case 370: + return 370 + case 371: + return 371 + case 372: + return 372 + case 373: + return 373 + case 374: + return 374 + case 375: + return 375 + case 376: + return 376 + case 377: + return 377 + case 378: + return 378 + case 379: + return 379 + case 380: + return 380 + case 381: + return 381 + case 382: + return 382 + case 383: + return 383 + case 384: + return 384 + case 385: + return 385 + case 386: + return 386 + case 387: + return 387 + case 388: + return 388 + case 389: + return 389 + case 390: + return 390 + case 391: + return 391 + case 392: + return 392 + case 393: + return 393 + case 394: + return 394 + case 395: + return 395 + case 396: + return 396 + case 397: + return 397 + case 398: + return 398 + case 399: + return 399 + case 400: + return 400 + case 401: + return 401 + case 402: + return 402 + case 403: + return 403 + case 404: + return 404 + case 405: + return 405 + case 406: + return 406 + case 407: + return 407 + case 408: + return 408 + case 409: + return 409 + case 410: + return 410 + case 411: + return 411 + case 412: + return 412 + case 413: + return 413 + case 414: + return 414 + case 415: + return 415 + case 416: + return 416 + case 417: + return 417 + case 418: + return 418 + case 419: + return 419 + case 420: + return 420 + case 421: + return 421 + case 422: + return 422 + case 423: + return 423 + case 424: + return 424 + case 425: + return 425 + case 426: + return 426 + case 427: + return 427 + case 428: + return 428 + case 429: + return 429 + case 430: + return 430 + case 431: + return 431 + case 432: + return 432 + case 433: + return 433 + case 434: + return 434 + case 435: + return 435 + case 436: + return 436 + case 437: + return 437 + case 438: + return 438 + case 439: + return 439 + case 440: + return 440 + case 441: + return 441 + case 442: + return 442 + case 443: + return 443 + case 444: + return 444 + case 445: + return 445 + case 446: + return 446 + case 447: + return 447 + case 448: + return 448 + case 449: + return 449 + case 450: + return 450 + case 451: + return 451 + case 452: + return 452 + case 453: + return 453 + case 454: + return 454 + case 455: + return 455 + case 456: + return 456 + case 457: + return 457 + case 458: + return 458 + case 459: + return 459 + case 460: + return 460 + case 461: + return 461 + case 462: + return 462 + case 463: + return 463 + case 464: + return 464 + case 465: + return 465 + case 466: + return 466 + case 467: + return 467 + case 468: + return 468 + case 469: + return 469 + case 470: + return 470 + case 471: + return 471 + case 472: + return 472 + case 473: + return 473 + case 474: + return 474 + case 475: + return 475 + case 476: + return 476 + case 477: + return 477 + case 478: + return 478 + case 479: + return 479 + case 480: + return 480 + case 481: + return 481 + case 482: + return 482 + case 483: + return 483 + case 484: + return 484 + case 485: + return 485 + case 486: + return 486 + case 487: + return 487 + case 488: + return 488 + case 489: + return 489 + case 490: + return 490 + case 491: + return 491 + case 492: + return 492 + case 493: + return 493 + case 494: + return 494 + case 495: + return 495 + case 496: + return 496 + case 497: + return 497 + case 498: + return 498 + case 499: + return 499 + case 500: + return 500 + case 501: + return 501 + case 502: + return 502 + case 503: + return 503 + case 504: + return 504 + case 505: + return 505 + case 506: + return 506 + case 507: + return 507 + case 508: + return 508 + case 509: + return 509 + case 510: + return 510 + case 511: + return 511 + case 512: + return 512 + case 513: + return 513 + case 514: + return 514 + case 515: + return 515 + case 516: + return 516 + case 517: + return 517 + case 518: + return 518 + case 519: + return 519 + case 520: + return 520 + case 521: + return 521 + case 522: + return 522 + case 523: + return 523 + case 524: + return 524 + case 525: + return 525 + case 526: + return 526 + case 527: + return 527 + case 528: + return 528 + case 529: + return 529 + case 530: + return 530 + case 531: + return 531 + case 532: + return 532 + case 533: + return 533 + case 534: + return 534 + case 535: + return 535 + case 536: + return 536 + case 537: + return 537 + case 538: + return 538 + case 539: + return 539 + case 540: + return 540 + case 541: + return 541 + case 542: + return 542 + case 543: + return 543 + case 544: + return 544 + case 545: + return 545 + case 546: + return 546 + case 547: + return 547 + case 548: + return 548 + case 549: + return 549 + case 550: + return 550 + case 551: + return 551 + case 552: + return 552 + case 553: + return 553 + case 554: + return 554 + case 555: + return 555 + case 556: + return 556 + case 557: + return 557 + case 558: + return 558 + case 559: + return 559 + case 560: + return 560 + case 561: + return 561 + case 562: + return 562 + case 563: + return 563 + case 564: + return 564 + case 565: + return 565 + case 566: + return 566 + case 567: + return 567 + case 568: + return 568 + case 569: + return 569 + case 570: + return 570 + case 571: + return 571 + case 572: + return 572 + case 573: + return 573 + case 574: + return 574 + case 575: + return 575 + case 576: + return 576 + case 577: + return 577 + case 578: + return 578 + case 579: + return 579 + case 580: + return 580 + case 581: + return 581 + case 582: + return 582 + case 583: + return 583 + case 584: + return 584 + case 585: + return 585 + case 586: + return 586 + case 587: + return 587 + case 588: + return 588 + case 589: + return 589 + case 590: + return 590 + case 591: + return 591 + case 592: + return 592 + case 593: + return 593 + case 594: + return 594 + case 595: + return 595 + case 596: + return 596 + case 597: + return 597 + case 598: + return 598 + case 599: + return 599 + case 600: + return 600 + case 601: + return 601 + case 602: + return 602 + case 603: + return 603 + case 604: + return 604 + case 605: + return 605 + case 606: + return 606 + case 607: + return 607 + case 608: + return 608 + case 609: + return 609 + case 610: + return 610 + case 611: + return 611 + case 612: + return 612 + case 613: + return 613 + case 614: + return 614 + case 615: + return 615 + case 616: + return 616 + case 617: + return 617 + case 618: + return 618 + case 619: + return 619 + case 620: + return 620 + case 621: + return 621 + case 622: + return 622 + case 623: + return 623 + case 624: + return 624 + case 625: + return 625 + case 626: + return 626 + case 627: + return 627 + case 628: + return 628 + case 629: + return 629 + case 630: + return 630 + case 631: + return 631 + case 632: + return 632 + case 633: + return 633 + case 634: + return 634 + case 635: + return 635 + case 636: + return 636 + case 637: + return 637 + case 638: + return 638 + case 639: + return 639 + case 640: + return 640 + case 641: + return 641 + case 642: + return 642 + case 643: + return 643 + case 644: + return 644 + case 645: + return 645 + case 646: + return 646 + case 647: + return 647 + case 648: + return 648 + case 649: + return 649 + case 650: + return 650 + case 651: + return 651 + case 652: + return 652 + case 653: + return 653 + case 654: + return 654 + case 655: + return 655 + case 656: + return 656 + case 657: + return 657 + case 658: + return 658 + case 659: + return 659 + case 660: + return 660 + case 661: + return 661 + case 662: + return 662 + case 663: + return 663 + case 664: + return 664 + case 665: + return 665 + case 666: + return 666 + case 667: + return 667 + case 668: + return 668 + case 669: + return 669 + case 670: + return 670 + case 671: + return 671 + case 672: + return 672 + case 673: + return 673 + case 674: + return 674 + case 675: + return 675 + case 676: + return 676 + case 677: + return 677 + case 678: + return 678 + case 679: + return 679 + case 680: + return 680 + case 681: + return 681 + case 682: + return 682 + case 683: + return 683 + case 684: + return 684 + case 685: + return 685 + case 686: + return 686 + case 687: + return 687 + case 688: + return 688 + case 689: + return 689 + case 690: + return 690 + case 691: + return 691 + case 692: + return 692 + case 693: + return 693 + case 694: + return 694 + case 695: + return 695 + case 696: + return 696 + case 697: + return 697 + case 698: + return 698 + case 699: + return 699 + case 700: + return 700 + case 701: + return 701 + case 702: + return 702 + case 703: + return 703 + case 704: + return 704 + case 705: + return 705 + case 706: + return 706 + case 707: + return 707 + case 708: + return 708 + case 709: + return 709 + case 710: + return 710 + case 711: + return 711 + case 712: + return 712 + case 713: + return 713 + case 714: + return 714 + case 715: + return 715 + case 716: + return 716 + case 717: + return 717 + case 718: + return 718 + case 719: + return 719 + case 720: + return 720 + case 721: + return 721 + case 722: + return 722 + case 723: + return 723 + case 724: + return 724 + case 725: + return 725 + case 726: + return 726 + case 727: + return 727 + case 728: + return 728 + case 729: + return 729 + case 730: + return 730 + case 731: + return 731 + case 732: + return 732 + case 733: + return 733 + case 734: + return 734 + case 735: + return 735 + case 736: + return 736 + case 737: + return 737 + case 738: + return 738 + case 739: + return 739 + case 740: + return 740 + case 741: + return 741 + case 742: + return 742 + case 743: + return 743 + case 744: + return 744 + case 745: + return 745 + case 746: + return 746 + case 747: + return 747 + case 748: + return 748 + case 749: + return 749 + case 750: + return 750 + case 751: + return 751 + case 752: + return 752 + case 753: + return 753 + case 754: + return 754 + case 755: + return 755 + case 756: + return 756 + case 757: + return 757 + case 758: + return 758 + case 759: + return 759 + case 760: + return 760 + case 761: + return 761 + case 762: + return 762 + case 763: + return 763 + case 764: + return 764 + case 765: + return 765 + case 766: + return 766 + case 767: + return 767 + case 768: + return 768 + case 769: + return 769 + case 770: + return 770 + case 771: + return 771 + case 772: + return 772 + case 773: + return 773 + case 774: + return 774 + case 775: + return 775 + case 776: + return 776 + case 777: + return 777 + case 778: + return 778 + case 779: + return 779 + case 780: + return 780 + case 781: + return 781 + case 782: + return 782 + case 783: + return 783 + case 784: + return 784 + case 785: + return 785 + case 786: + return 786 + case 787: + return 787 + case 788: + return 788 + case 789: + return 789 + case 790: + return 790 + case 791: + return 791 + case 792: + return 792 + case 793: + return 793 + case 794: + return 794 + case 795: + return 795 + case 796: + return 796 + case 797: + return 797 + case 798: + return 798 + case 799: + return 799 + case 800: + return 800 + case 801: + return 801 + case 802: + return 802 + case 803: + return 803 + case 804: + return 804 + case 805: + return 805 + case 806: + return 806 + case 807: + return 807 + case 808: + return 808 + case 809: + return 809 + case 810: + return 810 + case 811: + return 811 + case 812: + return 812 + case 813: + return 813 + case 814: + return 814 + case 815: + return 815 + case 816: + return 816 + case 817: + return 817 + case 818: + return 818 + case 819: + return 819 + case 820: + return 820 + case 821: + return 821 + case 822: + return 822 + case 823: + return 823 + case 824: + return 824 + case 825: + return 825 + case 826: + return 826 + case 827: + return 827 + case 828: + return 828 + case 829: + return 829 + case 830: + return 830 + case 831: + return 831 + case 832: + return 832 + case 833: + return 833 + case 834: + return 834 + case 835: + return 835 + case 836: + return 836 + case 837: + return 837 + case 838: + return 838 + case 839: + return 839 + case 840: + return 840 + case 841: + return 841 + case 842: + return 842 + case 843: + return 843 + case 844: + return 844 + case 845: + return 845 + case 846: + return 846 + case 847: + return 847 + case 848: + return 848 + case 849: + return 849 + case 850: + return 850 + case 851: + return 851 + case 852: + return 852 + case 853: + return 853 + case 854: + return 854 + case 855: + return 855 + case 856: + return 856 + case 857: + return 857 + case 858: + return 858 + case 859: + return 859 + case 860: + return 860 + case 861: + return 861 + case 862: + return 862 + case 863: + return 863 + case 864: + return 864 + case 865: + return 865 + case 866: + return 866 + case 867: + return 867 + case 868: + return 868 + case 869: + return 869 + case 870: + return 870 + case 871: + return 871 + case 872: + return 872 + case 873: + return 873 + case 874: + return 874 + case 875: + return 875 + case 876: + return 876 + case 877: + return 877 + case 878: + return 878 + case 879: + return 879 + case 880: + return 880 + case 881: + return 881 + case 882: + return 882 + case 883: + return 883 + case 884: + return 884 + case 885: + return 885 + case 886: + return 886 + case 887: + return 887 + case 888: + return 888 + case 889: + return 889 + case 890: + return 890 + case 891: + return 891 + case 892: + return 892 + case 893: + return 893 + case 894: + return 894 + case 895: + return 895 + case 896: + return 896 + case 897: + return 897 + case 898: + return 898 + case 899: + return 899 + case 900: + return 900 + case 901: + return 901 + case 902: + return 902 + case 903: + return 903 + case 904: + return 904 + case 905: + return 905 + case 906: + return 906 + case 907: + return 907 + case 908: + return 908 + case 909: + return 909 + case 910: + return 910 + case 911: + return 911 + case 912: + return 912 + case 913: + return 913 + case 914: + return 914 + case 915: + return 915 + case 916: + return 916 + case 917: + return 917 + case 918: + return 918 + case 919: + return 919 + case 920: + return 920 + case 921: + return 921 + case 922: + return 922 + case 923: + return 923 + case 924: + return 924 + case 925: + return 925 + case 926: + return 926 + case 927: + return 927 + case 928: + return 928 + case 929: + return 929 + case 930: + return 930 + case 931: + return 931 + case 932: + return 932 + case 933: + return 933 + case 934: + return 934 + case 935: + return 935 + case 936: + return 936 + case 937: + return 937 + case 938: + return 938 + case 939: + return 939 + case 940: + return 940 + case 941: + return 941 + case 942: + return 942 + case 943: + return 943 + case 944: + return 944 + case 945: + return 945 + case 946: + return 946 + case 947: + return 947 + case 948: + return 948 + case 949: + return 949 + case 950: + return 950 + case 951: + return 951 + case 952: + return 952 + case 953: + return 953 + case 954: + return 954 + case 955: + return 955 + case 956: + return 956 + case 957: + return 957 + case 958: + return 958 + case 959: + return 959 + case 960: + return 960 + case 961: + return 961 + case 962: + return 962 + case 963: + return 963 + case 964: + return 964 + case 965: + return 965 + case 966: + return 966 + case 967: + return 967 + case 968: + return 968 + case 969: + return 969 + case 970: + return 970 + case 971: + return 971 + case 972: + return 972 + case 973: + return 973 + case 974: + return 974 + case 975: + return 975 + case 976: + return 976 + case 977: + return 977 + case 978: + return 978 + case 979: + return 979 + case 980: + return 980 + case 981: + return 981 + case 982: + return 982 + case 983: + return 983 + case 984: + return 984 + case 985: + return 985 + case 986: + return 986 + case 987: + return 987 + case 988: + return 988 + case 989: + return 989 + case 990: + return 990 + case 991: + return 991 + case 992: + return 992 + case 993: + return 993 + case 994: + return 994 + case 995: + return 995 + case 996: + return 996 + case 997: + return 997 + case 998: + return 998 + case 999: + return 999 + } + return 0 +} diff --git a/test/fixedbugs/issue60990.go b/test/fixedbugs/issue60990.go new file mode 100644 index 0000000000..ce94fa7197 --- /dev/null +++ b/test/fixedbugs/issue60990.go @@ -0,0 +1,31 @@ +// compile + +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type T struct{ _, _ []int } + +func F[_ int]() { + var f0, f1 float64 + var b bool + _ = func(T, float64) bool { + b = deepEqual(0, 1) + return func() bool { + f1 = min(f0, 0) + return b + }() + }(T{nil, nil}, min(0, f1)) + f0 = min(0, 1) +} + +//go:noinline +func deepEqual(x, y any) bool { + return x == y +} + +func init() { + F[int]() +} diff --git a/test/fixedbugs/issue60991.go b/test/fixedbugs/issue60991.go new file mode 100644 index 0000000000..e1d51e4300 --- /dev/null +++ b/test/fixedbugs/issue60991.go @@ -0,0 +1,13 @@ +// build + +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +import "math" + +func f() { + _ = min(0.1, 0.2, math.Sqrt(1)) +} diff --git a/test/fixedbugs/issue61127.go b/test/fixedbugs/issue61127.go new file mode 100644 index 0000000000..c8ee5c5ee4 --- /dev/null +++ b/test/fixedbugs/issue61127.go @@ -0,0 +1,13 @@ +// compile + +// Copyright 2023 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 V = []struct{}{} + +func main() { + clear(V) +} diff --git a/test/fixedbugs/issue61187.go b/test/fixedbugs/issue61187.go new file mode 100644 index 0000000000..5e1762808d --- /dev/null +++ b/test/fixedbugs/issue61187.go @@ -0,0 +1,22 @@ +// compile + +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "reflect" + "unsafe" +) + +var slice = []byte{'H', 'e', 'l', 'l', 'o', ','} + +func main() { + ptr := uintptr(unsafe.Pointer(&slice)) + 100 + header := (*reflect.SliceHeader)(unsafe.Pointer(ptr)) + header.Data += 1 + fmt.Printf("%d %d\n", cap(slice), header.Cap) +} diff --git a/test/for.go b/test/for.go index 8a50090657..cfb7f6dad2 100644 --- a/test/for.go +++ b/test/for.go @@ -44,15 +44,33 @@ func main() { for sum < 100 { sum = sum + 9 } - assertequal(sum, 99 + 9, "only one") + assertequal(sum, 99+9, "only one") sum = 0 for i := 0; i <= 10; i++ { - if i % 2 == 0 { + if i%2 == 0 { continue } sum = sum + i } assertequal(sum, 1+3+5+7+9, "continue") + i = 0 + for i = range [5]struct{}{} { + } + assertequal(i, 4, " incorrect index value after range loop") + + i = 0 + var a1 [5]struct{} + for i = range a1 { + a1[i] = struct{}{} + } + assertequal(i, 4, " incorrect index value after array with zero size elem range clear") + + i = 0 + var a2 [5]int + for i = range a2 { + a2[i] = 0 + } + assertequal(i, 4, " incorrect index value after array range clear") } |