This patch updates libgo to the final Go 1.17 release.  (I'm aware of
a couple of bug reports building libgo, I haven't had time to get to
them yet.)  Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.
Committed to mainline.

Ian

patch.txt
1d98014a8ae3c357071478d337f0169edec2ce0c
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 950f1797b55..e9f38d449a4 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-77bc32767b61feb6499ca7921e96b356603517dc
+b3fad6957a04520013197ea7cab11bec3298d552
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
diff --git a/libgo/MERGE b/libgo/MERGE
index 4286d5c5433..d037d8d06a2 100644
--- a/libgo/MERGE
+++ b/libgo/MERGE
@@ -1,4 +1,4 @@
-72ab3ff68b1ec894fe5599ec82b8849f3baa9d94
+ec5170397c724a8ae440b2bc529f857c86f0e6b1
 
 The first line of this file holds the git revision number of the
 last merge done from the master library sources.
diff --git a/libgo/VERSION b/libgo/VERSION
index 904eb73bd5c..efcff2916b0 100644
--- a/libgo/VERSION
+++ b/libgo/VERSION
@@ -1 +1 @@
-go1.17rc2
+go1.17
diff --git a/libgo/go/cmd/go/internal/modload/buildlist.go 
b/libgo/go/cmd/go/internal/modload/buildlist.go
index 604a57b4373..bf695673167 100644
--- a/libgo/go/cmd/go/internal/modload/buildlist.go
+++ b/libgo/go/cmd/go/internal/modload/buildlist.go
@@ -191,6 +191,19 @@ func (rs *Requirements) rootSelected(path string) (version 
string, ok bool) {
        return "", false
 }
 
+// hasRedundantRoot returns true if the root list contains multiple 
requirements
+// of the same module or a requirement on any version of the main module.
+// Redundant requirements should be pruned, but they may influence version
+// selection.
+func (rs *Requirements) hasRedundantRoot() bool {
+       for i, m := range rs.rootModules {
+               if m.Path == Target.Path || (i > 0 && m.Path == 
rs.rootModules[i-1].Path) {
+                       return true
+               }
+       }
+       return false
+}
+
 // Graph returns the graph of module requirements loaded from the current
 // root modules (as reported by RootModules).
 //
@@ -882,6 +895,12 @@ func updateLazyRoots(ctx context.Context, direct 
map[string]bool, rs *Requiremen
                // and (trivially) version.
 
                if !rootsUpgraded {
+                       if cfg.BuildMod != "mod" {
+                               // The only changes to the root set (if any) 
were to remove duplicates.
+                               // The requirements are consistent (if perhaps 
redundant), so keep the
+                               // original rs to preserve its ModuleGraph.
+                               return rs, nil
+                       }
                        // The root set has converged: every root going into 
this iteration was
                        // already at its selected version, although we have 
have removed other
                        // (redundant) roots for the same path.
diff --git a/libgo/go/cmd/go/internal/modload/init.go 
b/libgo/go/cmd/go/internal/modload/init.go
index a8cbd9fe16d..45f724d5e36 100644
--- a/libgo/go/cmd/go/internal/modload/init.go
+++ b/libgo/go/cmd/go/internal/modload/init.go
@@ -449,13 +449,22 @@ func loadModFile(ctx context.Context) (rs *Requirements, 
needCommit bool) {
        }
 
        setDefaultBuildMod() // possibly enable automatic vendoring
-       rs = requirementsFromModFile(ctx)
-
+       rs = requirementsFromModFile()
        if cfg.BuildMod == "vendor" {
                readVendorList()
                checkVendorConsistency()
                rs.initVendor(vendorList)
        }
+       if rs.hasRedundantRoot() {
+               // If any module path appears more than once in the roots, we 
know that the
+               // go.mod file needs to be updated even though we have not yet 
loaded any
+               // transitive dependencies.
+               rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
+               if err != nil {
+                       base.Fatalf("go: %v", err)
+               }
+       }
+
        if index.goVersionV == "" {
                // TODO(#45551): Do something more principled instead of 
checking
                // cfg.CmdName directly here.
@@ -530,7 +539,12 @@ func CreateModFile(ctx context.Context, modPath string) {
                base.Fatalf("go: %v", err)
        }
 
-       commitRequirements(ctx, modFileGoVersion(), 
requirementsFromModFile(ctx))
+       rs := requirementsFromModFile()
+       rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
+       if err != nil {
+               base.Fatalf("go: %v", err)
+       }
+       commitRequirements(ctx, modFileGoVersion(), rs)
 
        // Suggest running 'go mod tidy' unless the project is empty. Even if we
        // imported all the correct requirements above, we're probably missing
@@ -641,9 +655,8 @@ func initTarget(m module.Version) {
 
 // requirementsFromModFile returns the set of non-excluded requirements from
 // the global modFile.
-func requirementsFromModFile(ctx context.Context) *Requirements {
+func requirementsFromModFile() *Requirements {
        roots := make([]module.Version, 0, len(modFile.Require))
-       mPathCount := map[string]int{Target.Path: 1}
        direct := map[string]bool{}
        for _, r := range modFile.Require {
                if index != nil && index.exclude[r.Mod] {
@@ -656,28 +669,12 @@ func requirementsFromModFile(ctx context.Context) 
*Requirements {
                }
 
                roots = append(roots, r.Mod)
-               mPathCount[r.Mod.Path]++
                if !r.Indirect {
                        direct[r.Mod.Path] = true
                }
        }
        module.Sort(roots)
        rs := newRequirements(modDepthFromGoVersion(modFileGoVersion()), roots, 
direct)
-
-       // If any module path appears more than once in the roots, we know that 
the
-       // go.mod file needs to be updated even though we have not yet loaded 
any
-       // transitive dependencies.
-       for _, n := range mPathCount {
-               if n > 1 {
-                       var err error
-                       rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, 
false)
-                       if err != nil {
-                               base.Fatalf("go: %v", err)
-                       }
-                       break
-               }
-       }
-
        return rs
 }
 
diff --git a/libgo/go/cmd/go/testdata/script/mod_tidy_lazy_self.txt 
b/libgo/go/cmd/go/testdata/script/mod_tidy_lazy_self.txt
index ffcea186035..9abbabd2ebe 100644
--- a/libgo/go/cmd/go/testdata/script/mod_tidy_lazy_self.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_tidy_lazy_self.txt
@@ -2,18 +2,13 @@
 # 'go mod tidy' should not panic if the main module initially
 # requires an older version of itself.
 
+# A module may require an older version of itself without error. This is
+# inconsistent (the required version is never selected), but we still get
+# a reproducible build list.
+go list -m all
+stdout '^golang.org/issue/46078$'
 
-# A module that explicitly requires an older version of itself should be
-# rejected as inconsistent: we enforce that every explicit requirement is the
-# selected version of its module path, but the selected version of the main
-# module is always itself — not some explicit version.
-
-! go list -m all
-stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$'
-
-
-# The suggested 'go mod tidy' command should succeed (not crash).
-
+# 'go mod tidy' should fix this (and not crash).
 go mod tidy
 
 
diff --git a/libgo/go/io/fs/fs.go b/libgo/go/io/fs/fs.go
index e1be32478e0..e603afadb0b 100644
--- a/libgo/go/io/fs/fs.go
+++ b/libgo/go/io/fs/fs.go
@@ -86,7 +86,7 @@ type File interface {
 type DirEntry interface {
        // Name returns the name of the file (or subdirectory) described by the 
entry.
        // This name is only the final element of the path (the base name), not 
the entire path.
-       // For example, Name would return "hello.go" not 
"/home/gopher/hello.go".
+       // For example, Name would return "hello.go" not "home/gopher/hello.go".
        Name() string
 
        // IsDir reports whether the entry describes a directory.
diff --git a/libgo/go/net/http/transport_test.go 
b/libgo/go/net/http/transport_test.go
index cae54643ddd..7e14749f838 100644
--- a/libgo/go/net/http/transport_test.go
+++ b/libgo/go/net/http/transport_test.go
@@ -6445,10 +6445,11 @@ func TestErrorWriteLoopRace(t *testing.T) {
 // Test that a new request which uses the connection of an active request
 // cannot cause it to be canceled as well.
 func TestCancelRequestWhenSharingConnection(t *testing.T) {
-       if testing.Short() {
-               t.Skip("skipping in short mode")
-       }
+       reqc := make(chan chan struct{}, 2)
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req 
*Request) {
+               ch := make(chan struct{}, 1)
+               reqc <- ch
+               <-ch
                w.Header().Add("Content-Length", "0")
        }))
        defer ts.Close()
@@ -6460,34 +6461,58 @@ func TestCancelRequestWhenSharingConnection(t 
*testing.T) {
 
        var wg sync.WaitGroup
 
-       ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+       wg.Add(1)
+       putidlec := make(chan chan struct{})
+       go func() {
+               defer wg.Done()
+               ctx := httptrace.WithClientTrace(context.Background(), 
&httptrace.ClientTrace{
+                       PutIdleConn: func(error) {
+                               // Signal that the idle conn has been returned 
to the pool,
+                               // and wait for the order to proceed.
+                               ch := make(chan struct{})
+                               putidlec <- ch
+                               <-ch
+                       },
+               })
+               req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil)
+               res, err := client.Do(req)
+               if err == nil {
+                       res.Body.Close()
+               }
+               if err != nil {
+                       t.Errorf("request 1: got err %v, want nil", err)
+               }
+       }()
 
-       for i := 0; i < 10; i++ {
-               wg.Add(1)
-               go func() {
-                       defer wg.Done()
-                       for ctx.Err() == nil {
-                               reqctx, reqcancel := context.WithCancel(ctx)
-                               go reqcancel()
-                               req, _ := NewRequestWithContext(reqctx, "GET", 
ts.URL, nil)
-                               res, err := client.Do(req)
-                               if err == nil {
-                                       res.Body.Close()
-                               }
-                       }
-               }()
-       }
+       // Wait for the first request to receive a response and return the
+       // connection to the idle pool.
+       r1c := <-reqc
+       close(r1c)
+       idlec := <-putidlec
 
-       for ctx.Err() == nil {
-               req, _ := NewRequest("GET", ts.URL, nil)
-               if res, err := client.Do(req); err != nil {
-                       t.Errorf("unexpected: %p %v", req, err)
-                       break
-               } else {
+       wg.Add(1)
+       cancelctx, cancel := context.WithCancel(context.Background())
+       go func() {
+               defer wg.Done()
+               req, _ := NewRequestWithContext(cancelctx, "GET", ts.URL, nil)
+               res, err := client.Do(req)
+               if err == nil {
                        res.Body.Close()
                }
-       }
+               if !errors.Is(err, context.Canceled) {
+                       t.Errorf("request 2: got err %v, want Canceled", err)
+               }
+       }()
 
+       // Wait for the second request to arrive at the server, and then cancel
+       // the request context.
+       r2c := <-reqc
        cancel()
+
+       // Give the cancelation a moment to take effect, and then unblock the 
first request.
+       time.Sleep(1 * time.Millisecond)
+       close(idlec)
+
+       close(r2c)
        wg.Wait()
 }
diff --git a/libgo/go/runtime/mfinal.go b/libgo/go/runtime/mfinal.go
index 90598890fcb..b4afaee0613 100644
--- a/libgo/go/runtime/mfinal.go
+++ b/libgo/go/runtime/mfinal.go
@@ -402,6 +402,10 @@ okarg:
 // Without the KeepAlive call, the finalizer could run at the start of
 // syscall.Read, closing the file descriptor before syscall.Read makes
 // the actual system call.
+//
+// Note: KeepAlive should only be used to prevent finalizers from
+// running prematurely. In particular, when used with unsafe.Pointer,
+// the rules for valid uses of unsafe.Pointer still apply.
 func KeepAlive(x interface{}) {
        // Introduce a use of x that the compiler can't eliminate.
        // This makes sure x is alive on entry. We need x to be alive
diff --git a/libgo/go/sync/atomic/value.go b/libgo/go/sync/atomic/value.go
index 61f81d8fd37..3500cd22f4e 100644
--- a/libgo/go/sync/atomic/value.go
+++ b/libgo/go/sync/atomic/value.go
@@ -126,7 +126,7 @@ func (v *Value) Swap(new interface{}) (old interface{}) {
        }
 }
 
-// CompareAndSwapPointer executes the compare-and-swap operation for the Value.
+// CompareAndSwap executes the compare-and-swap operation for the Value.
 //
 // All calls to CompareAndSwap for a given Value must use values of the same
 // concrete type. CompareAndSwap of an inconsistent type panics, as does
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index bb173a21c2d..f4b4f48142f 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -77,9 +77,9 @@ import "errors"
 // The formats  and 002 are space-padded and zero-padded
 // three-character day of year; there is no unpadded day of year format.
 //
-// A decimal point followed by one or more zeros represents a fractional
-// second, printed to the given number of decimal places.
-// Either a comma or decimal point followed by one or more nines represents
+// A comma or decimal point followed by one or more zeros represents
+// a fractional second, printed to the given number of decimal places.
+// A comma or decimal point followed by one or more nines represents
 // a fractional second, printed to the given number of decimal places, with
 // trailing zeros removed.
 // For example "15:04:05,000" or "15:04:05.000" formats or parses with
diff --git a/libgo/misc/cgo/testsanitizers/msan_test.go 
b/libgo/misc/cgo/testsanitizers/msan_test.go
index 2a3494fbfc1..5ee9947a585 100644
--- a/libgo/misc/cgo/testsanitizers/msan_test.go
+++ b/libgo/misc/cgo/testsanitizers/msan_test.go
@@ -42,6 +42,7 @@ func TestMSAN(t *testing.T) {
                {src: "msan5.go"},
                {src: "msan6.go"},
                {src: "msan7.go"},
+               {src: "msan8.go"},
                {src: "msan_fail.go", wantErr: true},
        }
        for _, tc := range cases {
diff --git a/libgo/misc/cgo/testsanitizers/testdata/msan8.go 
b/libgo/misc/cgo/testsanitizers/testdata/msan8.go
new file mode 100644
index 00000000000..1cb5c5677fa
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/testdata/msan8.go
@@ -0,0 +1,109 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+
+#include <sanitizer/msan_interface.h>
+
+// cgoTracebackArg is the type of the argument passed to msanGoTraceback.
+struct cgoTracebackArg {
+       uintptr_t context;
+       uintptr_t sigContext;
+       uintptr_t* buf;
+       uintptr_t max;
+};
+
+// msanGoTraceback is registered as the cgo traceback function.
+// This will be called when a signal occurs.
+void msanGoTraceback(void* parg) {
+       struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+        arg->buf[0] = 0;
+}
+
+// msanGoWait will be called with all registers undefined as far as
+// msan is concerned. It just waits for a signal.
+// Because the registers are msan-undefined, the signal handler will
+// be invoked with all registers msan-undefined.
+__attribute__((noinline))
+void msanGoWait(unsigned long a1, unsigned long a2, unsigned long a3, unsigned 
long a4, unsigned long a5, unsigned long a6) {
+       sigset_t mask;
+
+       sigemptyset(&mask);
+        sigsuspend(&mask);
+}
+
+// msanGoSignalThread is the thread ID of the msanGoLoop thread.
+static pthread_t msanGoSignalThread;
+
+// msanGoSignalThreadSet is used to record that msanGoSignalThread
+// has been initialized. This is accessed atomically.
+static int32_t msanGoSignalThreadSet;
+
+// uninit is explicitly poisoned, so that we can make all registers
+// undefined by calling msanGoWait.
+static unsigned long uninit;
+
+// msanGoLoop loops calling msanGoWait, with the arguments passed
+// such that msan thinks that they are undefined. msan permits
+// undefined values to be used as long as they are not used to
+// for conditionals or for memory access.
+void msanGoLoop() {
+       int i;
+
+       msanGoSignalThread = pthread_self();
+        __atomic_store_n(&msanGoSignalThreadSet, 1, __ATOMIC_SEQ_CST);
+
+       // Force uninit to be undefined for msan.
+       __msan_poison(&uninit, sizeof uninit);
+       for (i = 0; i < 100; i++) {
+               msanGoWait(uninit, uninit, uninit, uninit, uninit, uninit);
+        }
+}
+
+// msanGoReady returns whether msanGoSignalThread is set.
+int msanGoReady() {
+       return __atomic_load_n(&msanGoSignalThreadSet, __ATOMIC_SEQ_CST) != 0;
+}
+
+// msanGoSendSignal sends a signal to the msanGoLoop thread.
+void msanGoSendSignal() {
+       pthread_kill(msanGoSignalThread, SIGWINCH);
+}
+*/
+import "C"
+
+import (
+       "runtime"
+       "time"
+)
+
+func main() {
+       runtime.SetCgoTraceback(0, C.msanGoTraceback, nil, nil)
+
+       c := make(chan bool)
+       go func() {
+               defer func() { c <- true }()
+               C.msanGoLoop()
+       }()
+
+       for C.msanGoReady() == 0 {
+               time.Sleep(time.Microsecond)
+       }
+
+loop:
+       for {
+               select {
+               case <-c:
+                       break loop
+               default:
+                       C.msanGoSendSignal()
+                       time.Sleep(time.Microsecond)
+               }
+       }
+}

Reply via email to