diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 3f12aa3cbd..eeb503811c 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -721,11 +721,12 @@ func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMe // Struct containing info needed for doing the substitution as we create the // instantiation of a generic function with specified type arguments. type subster struct { - g *genInst - isMethod bool // If a method is being instantiated - newf *ir.Func // Func node for the new stenciled function - ts typecheck.Tsubster - info *instInfo // Place to put extra info in the instantiation + g *genInst + isMethod bool // If a method is being instantiated + newf *ir.Func // Func node for the new stenciled function + ts typecheck.Tsubster + info *instInfo // Place to put extra info in the instantiation + skipClosure bool // Skip substituting closures // Map from non-nil, non-ONAME node n to slice of all m, where m.Defn = n defnMap map[ir.Node][]**ir.Name @@ -978,7 +979,20 @@ func (subst *subster) node(n ir.Node) ir.Node { } } + old := subst.skipClosure + // For unsafe.{Alignof,Offsetof,Sizeof}, subster will transform them to OLITERAL nodes, + // and discard their arguments. However, their children nodes were already process before, + // thus if they contain any closure, the closure was still be added to package declarations + // queue for processing later. Thus, genInst will fail to generate instantiation for the + // closure because of lacking dictionary information, see issue #53390. + if call, ok := m.(*ir.CallExpr); ok && call.X.Op() == ir.ONAME { + switch call.X.Name().BuiltinOp { + case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: + subst.skipClosure = true + } + } ir.EditChildren(m, edit) + subst.skipClosure = old m.SetTypecheck(1) @@ -1123,6 +1137,9 @@ func (subst *subster) node(n ir.Node) ir.Node { } case ir.OCLOSURE: + if subst.skipClosure { + break + } // We're going to create a new closure from scratch, so clear m // to avoid using the ir.Copy by accident until we reassign it. m = nil diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index a7c8c2c769..426df9bc04 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -833,6 +833,7 @@ Outer: for _, m := range mods { list := goSum.m[m] sort.Strings(list) + str.Uniq(&list) for _, h := range list { st := goSum.status[modSum{m, h}] if (!st.dirty || (st.used && keep[m])) && !sumInWorkspaceModulesLocked(m) { diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index 846e2c8b77..a5b5570e05 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -164,13 +164,16 @@ func (b *Builder) toolID(name string) string { cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { - base.Fatalf("%s: %v\n%s%s", desc, err, stdout.Bytes(), stderr.Bytes()) + if stderr.Len() > 0 { + os.Stderr.Write(stderr.Bytes()) + } + base.Fatalf("go: error obtaining buildID for %s: %v", desc, err) } line := stdout.String() f := strings.Fields(line) if len(f) < 3 || f[0] != name && path != VetTool || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") { - base.Fatalf("%s -V=full: unexpected output:\n\t%s", desc, line) + base.Fatalf("go: parsing buildID from %s -V=full: unexpected output:\n\t%s", desc, line) } if f[2] == "devel" { // On the development branch, use the content ID part of the build ID. diff --git a/src/cmd/go/testdata/script/mod_tidy_duplicates.txt b/src/cmd/go/testdata/script/mod_tidy_duplicates.txt new file mode 100644 index 0000000000..d454c8dc82 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_duplicates.txt @@ -0,0 +1,38 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/28456: +# 'go mod tidy' should not leave duplicate lines when re-writing the file. + +go mod tidy +cmp go.sum golden.sum + +-- go.mod -- +module use + +go 1.16 + +require rsc.io/quote v1.5.2 + +-- go.sum -- +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- golden.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- main.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index 6dced31ffb..9aca6216a7 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -177,6 +177,7 @@ func TestImportTypeparamTests(t *testing.T) { "equal.go": "inconsistent embedded sorting", // TODO(rfindley): investigate this. "nested.go": "fails to compile", // TODO(rfindley): investigate this. "issue50417.go": "inconsistent interface member sorting", + "issue53419.go": "fails to compile", } for _, entry := range list { diff --git a/src/go/token/position.go b/src/go/token/position.go index 00f24535bf..bd9ae07b28 100644 --- a/src/go/token/position.go +++ b/src/go/token/position.go @@ -92,7 +92,6 @@ func (p Pos) IsValid() bool { // A File is a handle for a file belonging to a FileSet. // A File has a name, size, and line offset table. type File struct { - set *FileSet name string // file name as provided to AddFile base int // Pos value range for this file is [base...base+size] size int // file size as provided to AddFile @@ -418,7 +417,7 @@ func (s *FileSet) AddFile(filename string, base, size int) *File { panic(fmt.Sprintf("invalid size %d (should be >= 0)", size)) } // base >= s.base && size >= 0 - f := &File{set: s, name: filename, base: base, size: size, lines: []int{0}} + f := &File{name: filename, base: base, size: size, lines: []int{0}} base += size + 1 // +1 because EOF also has a position if base < 0 { panic("token.Pos offset overflow (> 2G of source code in file set)") diff --git a/src/go/token/serialize.go b/src/go/token/serialize.go index ffb69908b9..38c10ebd47 100644 --- a/src/go/token/serialize.go +++ b/src/go/token/serialize.go @@ -31,7 +31,6 @@ func (s *FileSet) Read(decode func(any) error) error { for i := 0; i < len(ss.Files); i++ { f := &ss.Files[i] files[i] = &File{ - set: s, name: f.Name, base: f.Base, size: f.Size, diff --git a/src/go/token/serialize_test.go b/src/go/token/serialize_test.go index 4aa0b0da26..8d9799547a 100644 --- a/src/go/token/serialize_test.go +++ b/src/go/token/serialize_test.go @@ -35,12 +35,6 @@ func equal(p, q *FileSet) error { for i, f := range p.files { g := q.files[i] - if f.set != p { - return fmt.Errorf("wrong fileset for %q", f.name) - } - if g.set != q { - return fmt.Errorf("wrong fileset for %q", g.name) - } if f.name != g.name { return fmt.Errorf("different filenames: %q != %q", f.name, g.name) } diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go index d1cfbf853c..3ad026c490 100644 --- a/src/net/timeout_test.go +++ b/src/net/timeout_test.go @@ -243,8 +243,7 @@ func TestAcceptTimeoutMustNotReturn(t *testing.T) { ln := newLocalListener(t, "tcp") defer ln.Close() - max := time.NewTimer(100 * time.Millisecond) - defer max.Stop() + maxch := make(chan *time.Timer) ch := make(chan error) go func() { if err := ln.(*TCPListener).SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { @@ -253,10 +252,14 @@ func TestAcceptTimeoutMustNotReturn(t *testing.T) { if err := ln.(*TCPListener).SetDeadline(noDeadline); err != nil { t.Error(err) } + maxch <- time.NewTimer(100 * time.Millisecond) _, err := ln.Accept() ch <- err }() + max := <-maxch + defer max.Stop() + select { case err := <-ch: if perr := parseAcceptError(err); perr != nil { @@ -348,8 +351,7 @@ func TestReadTimeoutMustNotReturn(t *testing.T) { } defer c.Close() - max := time.NewTimer(100 * time.Millisecond) - defer max.Stop() + maxch := make(chan *time.Timer) ch := make(chan error) go func() { if err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { @@ -361,11 +363,15 @@ func TestReadTimeoutMustNotReturn(t *testing.T) { if err := c.SetReadDeadline(noDeadline); err != nil { t.Error(err) } + maxch <- time.NewTimer(100 * time.Millisecond) var b [1]byte _, err := c.Read(b[:]) ch <- err }() + max := <-maxch + defer max.Stop() + select { case err := <-ch: if perr := parseReadError(err); perr != nil { @@ -517,8 +523,7 @@ func TestWriteTimeoutMustNotReturn(t *testing.T) { } defer c.Close() - max := time.NewTimer(100 * time.Millisecond) - defer max.Stop() + maxch := make(chan *time.Timer) ch := make(chan error) go func() { if err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { @@ -530,6 +535,7 @@ func TestWriteTimeoutMustNotReturn(t *testing.T) { if err := c.SetWriteDeadline(noDeadline); err != nil { t.Error(err) } + maxch <- time.NewTimer(100 * time.Millisecond) var b [1]byte for { if _, err := c.Write(b[:]); err != nil { @@ -539,6 +545,9 @@ func TestWriteTimeoutMustNotReturn(t *testing.T) { } }() + max := <-maxch + defer max.Stop() + select { case err := <-ch: if perr := parseWriteError(err); perr != nil { diff --git a/src/sync/cond.go b/src/sync/cond.go index 19f986e478..cbf5ba6071 100644 --- a/src/sync/cond.go +++ b/src/sync/cond.go @@ -22,6 +22,17 @@ import ( // In the terminology of the Go memory model, Cond arranges that // a call to Broadcast or Signal “synchronizes before” any Wait call // that it unblocks. +// +// For many simple use cases, users will be better off using channels than a +// Cond (Broadcast corresponds to closing a channel, and Signal corresponds to +// sending on a channel). +// +// For more on replacements for sync.Cond, see [Roberto Clapis's series on +// advanced concurrency patterns], as well as [Bryan Mills's talk on concurrency +// patterns]. +// +// [Roberto Clapis's series on advanced concurrency patterns]: https://blogtitle.github.io/categories/concurrency/ +// [Bryan Mills's talk on concurrency patterns]: https://drive.google.com/file/d/1nPdvhB0PutEJzdCq5ms6UI58dp50fcAN/view type Cond struct { noCopy noCopy @@ -64,6 +75,9 @@ func (c *Cond) Wait() { // // It is allowed but not required for the caller to hold c.L // during the call. +// +// Signal() does not affect goroutine scheduling priority; if other goroutines +// are attempting to lock c.L, they may be awoken before a "waiting" goroutine. func (c *Cond) Signal() { c.checker.check() runtime_notifyListNotifyOne(&c.notify) diff --git a/test/run.go b/test/run.go index cb1622ccc9..8934e23b38 100644 --- a/test/run.go +++ b/test/run.go @@ -1966,6 +1966,7 @@ var types2Failures32Bit = setOf( var go118Failures = setOf( "typeparam/nested.go", // 1.18 compiler doesn't support function-local types with generics "typeparam/issue51521.go", // 1.18 compiler produces bad panic message and link error + "typeparam/issue53419.go", // 1.18 compiler mishandles generic selector resolution ) // In all of these cases, the 1.17 compiler reports reasonable errors, but either the diff --git a/test/typeparam/issue53390.go b/test/typeparam/issue53390.go new file mode 100644 index 0000000000..52098c520b --- /dev/null +++ b/test/typeparam/issue53390.go @@ -0,0 +1,20 @@ +// compile + +// Copyright 2022 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 "unsafe" + +func F[T any](v T) uintptr { + return unsafe.Alignof(func() T { + func(any) {}(struct{ _ T }{}) + return v + }()) +} + +func f() { + F(0) +} diff --git a/test/typeparam/issue53419.go b/test/typeparam/issue53419.go new file mode 100644 index 0000000000..62a226ff9f --- /dev/null +++ b/test/typeparam/issue53419.go @@ -0,0 +1,28 @@ +// run + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type T1 struct{} +type T2 struct{} +type Both struct { + T1 + T2 +} + +func (T1) m() { panic("FAIL") } +func (T2) m() { panic("FAIL") } +func (Both) m() {} + +func f[T interface{ m() }](c T) { + c.m() +} + +func main() { + var b Both + b.m() + f(b) +}