This patch updates libgo to the Go1.16.3 release.  Bootstrapped and
ran Go testsuite on x86_64-pc-linux-gnu.  Committed to mainline.

Ian
dfbc12e031900c1f30bb94332823d39e5b241b40
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index a3eef239eca..efb7a772882 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-4bdff733a0c2a9ddc3eff104b1be03df058a79c4
+9782e85bef1c16c72a4980856d921cea104b129c
 
 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 a52dceb182f..81cd0623486 100644
--- a/libgo/MERGE
+++ b/libgo/MERGE
@@ -1,4 +1,4 @@
-3979fb9af9ccfc0b7ccb613dcf256b18c2c295f0
+9baddd3f21230c55f0ad2a10f5f20579dcf0a0bb
 
 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 d0b0a900460..e592dfd1338 100644
--- a/libgo/VERSION
+++ b/libgo/VERSION
@@ -1 +1 @@
-go1.16.2
+go1.16.3
diff --git a/libgo/go/cmd/go.mod b/libgo/go/cmd/go.mod
index 35582f3975f..70b1b0690b3 100644
--- a/libgo/go/cmd/go.mod
+++ b/libgo/go/cmd/go.mod
@@ -6,7 +6,7 @@ require (
        github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2
        golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
        golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
-       golang.org/x/mod v0.4.2-0.20210302225053-d515b24adc21
+       golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea
        golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
        golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff
 )
diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go
index e7c63f0749d..84f89c9d2d2 100644
--- a/libgo/go/cmd/go/alldocs.go
+++ b/libgo/go/cmd/go/alldocs.go
@@ -692,18 +692,22 @@
 // arguments must satisfy the following constraints:
 //
 // - Arguments must be package paths or package patterns (with "..." 
wildcards).
-//   They must not be standard packages (like fmt), meta-patterns (std, cmd,
-//   all), or relative or absolute file paths.
+// They must not be standard packages (like fmt), meta-patterns (std, cmd,
+// all), or relative or absolute file paths.
+//
 // - All arguments must have the same version suffix. Different queries are not
-//   allowed, even if they refer to the same version.
+// allowed, even if they refer to the same version.
+//
 // - All arguments must refer to packages in the same module at the same 
version.
+//
 // - No module is considered the "main" module. If the module containing
-//   packages named on the command line has a go.mod file, it must not contain
-//   directives (replace and exclude) that would cause it to be interpreted
-//   differently than if it were the main module. The module must not require
-//   a higher version of itself.
+// packages named on the command line has a go.mod file, it must not contain
+// directives (replace and exclude) that would cause it to be interpreted
+// differently than if it were the main module. The module must not require
+// a higher version of itself.
+//
 // - Package path arguments must refer to main packages. Pattern arguments
-//   will only match main packages.
+// will only match main packages.
 //
 // If the arguments don't have version suffixes, "go install" may run in
 // module-aware mode or GOPATH mode, depending on the GO111MODULE environment
diff --git a/libgo/go/cmd/go/internal/modfetch/cache.go 
b/libgo/go/cmd/go/internal/modfetch/cache.go
index 3a2ff63721c..07e046c8cba 100644
--- a/libgo/go/cmd/go/internal/modfetch/cache.go
+++ b/libgo/go/cmd/go/internal/modfetch/cache.go
@@ -84,6 +84,7 @@ func DownloadDir(m module.Version) (string, error) {
                return "", err
        }
 
+       // Check whether the directory itself exists.
        dir := filepath.Join(cfg.GOMODCACHE, enc+"@"+encVer)
        if fi, err := os.Stat(dir); os.IsNotExist(err) {
                return dir, err
@@ -92,6 +93,9 @@ func DownloadDir(m module.Version) (string, error) {
        } else if !fi.IsDir() {
                return dir, &DownloadDirPartialError{dir, errors.New("not a 
directory")}
        }
+
+       // Check if a .partial file exists. This is created at the beginning of
+       // a download and removed after the zip is extracted.
        partialPath, err := CachePath(m, "partial")
        if err != nil {
                return dir, err
@@ -101,6 +105,19 @@ func DownloadDir(m module.Version) (string, error) {
        } else if !os.IsNotExist(err) {
                return dir, err
        }
+
+       // Check if a .ziphash file exists. It should be created before the
+       // zip is extracted, but if it was deleted (by another program?), we 
need
+       // to re-calculate it.
+       ziphashPath, err := CachePath(m, "ziphash")
+       if err != nil {
+               return dir, err
+       }
+       if _, err := os.Stat(ziphashPath); os.IsNotExist(err) {
+               return dir, &DownloadDirPartialError{dir, errors.New("ziphash 
file is missing")}
+       } else if err != nil {
+               return dir, err
+       }
        return dir, nil
 }
 
diff --git a/libgo/go/cmd/go/internal/modfetch/fetch.go 
b/libgo/go/cmd/go/internal/modfetch/fetch.go
index c55c3cf2534..eb7d30e0ab9 100644
--- a/libgo/go/cmd/go/internal/modfetch/fetch.go
+++ b/libgo/go/cmd/go/internal/modfetch/fetch.go
@@ -170,13 +170,16 @@ func DownloadZip(ctx context.Context, mod module.Version) 
(zipfile string, err e
                if err != nil {
                        return cached{"", err}
                }
+               ziphashfile := zipfile + "hash"
 
-               // Skip locking if the zipfile already exists.
+               // Return without locking if the zip and ziphash files exist.
                if _, err := os.Stat(zipfile); err == nil {
-                       return cached{zipfile, nil}
+                       if _, err := os.Stat(ziphashfile); err == nil {
+                               return cached{zipfile, nil}
+                       }
                }
 
-               // The zip file does not exist. Acquire the lock and create it.
+               // The zip or ziphash file does not exist. Acquire the lock and 
create them.
                if cfg.CmdName != "mod download" {
                        fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", 
mod.Path, mod.Version)
                }
@@ -186,14 +189,6 @@ func DownloadZip(ctx context.Context, mod module.Version) 
(zipfile string, err e
                }
                defer unlock()
 
-               // Double-check that the zipfile was not created while we were 
waiting for
-               // the lock.
-               if _, err := os.Stat(zipfile); err == nil {
-                       return cached{zipfile, nil}
-               }
-               if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
-                       return cached{"", err}
-               }
                if err := downloadZip(ctx, mod, zipfile); err != nil {
                        return cached{"", err}
                }
@@ -206,6 +201,25 @@ func downloadZip(ctx context.Context, mod module.Version, 
zipfile string) (err e
        ctx, span := trace.StartSpan(ctx, "modfetch.downloadZip "+zipfile)
        defer span.Done()
 
+       // Double-check that the zipfile was not created while we were waiting 
for
+       // the lock in DownloadZip.
+       ziphashfile := zipfile + "hash"
+       var zipExists, ziphashExists bool
+       if _, err := os.Stat(zipfile); err == nil {
+               zipExists = true
+       }
+       if _, err := os.Stat(ziphashfile); err == nil {
+               ziphashExists = true
+       }
+       if zipExists && ziphashExists {
+               return nil
+       }
+
+       // Create parent directories.
+       if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
+               return err
+       }
+
        // Clean up any remaining tempfiles from previous runs.
        // This is only safe to do because the lock file ensures that their
        // writers are no longer active.
@@ -217,6 +231,12 @@ func downloadZip(ctx context.Context, mod module.Version, 
zipfile string) (err e
                }
        }
 
+       // If the zip file exists, the ziphash file must have been deleted
+       // or lost after a file system crash. Re-hash the zip without 
downloading.
+       if zipExists {
+               return hashZip(mod, zipfile, ziphashfile)
+       }
+
        // From here to the os.Rename call below is functionally almost 
equivalent to
        // renameio.WriteToFile, with one key difference: we want to validate 
the
        // contents of the file (by hashing it) before we commit it. Because 
the file
@@ -289,15 +309,7 @@ func downloadZip(ctx context.Context, mod module.Version, 
zipfile string) (err e
        }
 
        // Hash the zip file and check the sum before renaming to the final 
location.
-       hash, err := dirhash.HashZip(f.Name(), dirhash.DefaultHash)
-       if err != nil {
-               return err
-       }
-       if err := checkModSum(mod, hash); err != nil {
-               return err
-       }
-
-       if err := renameio.WriteFile(zipfile+"hash", []byte(hash), 0666); err 
!= nil {
+       if err := hashZip(mod, f.Name(), ziphashfile); err != nil {
                return err
        }
        if err := os.Rename(f.Name(), zipfile); err != nil {
@@ -309,6 +321,22 @@ func downloadZip(ctx context.Context, mod module.Version, 
zipfile string) (err e
        return nil
 }
 
+// hashZip reads the zip file opened in f, then writes the hash to ziphashfile,
+// overwriting that file if it exists.
+//
+// If the hash does not match go.sum (or the sumdb if enabled), hashZip returns
+// an error and does not write ziphashfile.
+func hashZip(mod module.Version, zipfile, ziphashfile string) error {
+       hash, err := dirhash.HashZip(zipfile, dirhash.DefaultHash)
+       if err != nil {
+               return err
+       }
+       if err := checkModSum(mod, hash); err != nil {
+               return err
+       }
+       return renameio.WriteFile(ziphashfile, []byte(hash), 0666)
+}
+
 // makeDirsReadOnly makes a best-effort attempt to remove write permissions 
for dir
 // and its transitive contents.
 func makeDirsReadOnly(dir string) {
@@ -452,11 +480,6 @@ func HaveSum(mod module.Version) bool {
 
 // checkMod checks the given module's checksum.
 func checkMod(mod module.Version) {
-       if cfg.GOMODCACHE == "" {
-               // Do not use current directory.
-               return
-       }
-
        // Do the file I/O before acquiring the go.sum lock.
        ziphash, err := CachePath(mod, "ziphash")
        if err != nil {
@@ -464,10 +487,6 @@ func checkMod(mod module.Version) {
        }
        data, err := renameio.ReadFile(ziphash)
        if err != nil {
-               if errors.Is(err, fs.ErrNotExist) {
-                       // This can happen if someone does rm -rf 
GOPATH/src/cache/download. So it goes.
-                       return
-               }
                base.Fatalf("verifying %v", module.VersionError(mod, err))
        }
        h := strings.TrimSpace(string(data))
diff --git a/libgo/go/cmd/go/internal/work/build.go 
b/libgo/go/cmd/go/internal/work/build.go
index 780d639c5d9..f024b07b229 100644
--- a/libgo/go/cmd/go/internal/work/build.go
+++ b/libgo/go/cmd/go/internal/work/build.go
@@ -482,18 +482,22 @@ To eliminate ambiguity about which module versions are 
used in the build, the
 arguments must satisfy the following constraints:
 
 - Arguments must be package paths or package patterns (with "..." wildcards).
-  They must not be standard packages (like fmt), meta-patterns (std, cmd,
-  all), or relative or absolute file paths.
+They must not be standard packages (like fmt), meta-patterns (std, cmd,
+all), or relative or absolute file paths.
+
 - All arguments must have the same version suffix. Different queries are not
-  allowed, even if they refer to the same version.
+allowed, even if they refer to the same version.
+
 - All arguments must refer to packages in the same module at the same version.
+
 - No module is considered the "main" module. If the module containing
-  packages named on the command line has a go.mod file, it must not contain
-  directives (replace and exclude) that would cause it to be interpreted
-  differently than if it were the main module. The module must not require
-  a higher version of itself.
+packages named on the command line has a go.mod file, it must not contain
+directives (replace and exclude) that would cause it to be interpreted
+differently than if it were the main module. The module must not require
+a higher version of itself.
+
 - Package path arguments must refer to main packages. Pattern arguments
-  will only match main packages.
+will only match main packages.
 
 If the arguments don't have version suffixes, "go install" may run in
 module-aware mode or GOPATH mode, depending on the GO111MODULE environment
diff --git a/libgo/go/cmd/go/testdata/script/mod_verify.txt 
b/libgo/go/cmd/go/testdata/script/mod_verify.txt
index 43812d069f6..b5106659a9a 100644
--- a/libgo/go/cmd/go/testdata/script/mod_verify.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_verify.txt
@@ -48,10 +48,13 @@ go mod tidy
 grep '^rsc.io/quote v1.1.0/go.mod ' go.sum
 grep '^rsc.io/quote v1.1.0 ' go.sum
 
-# sync should ignore missing ziphash; verify should not
+# verify should fail on a missing ziphash. tidy should restore it.
 rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash
-go mod tidy
 ! go mod verify
+stderr '^rsc.io/quote v1.1.0: missing ziphash: open 
'$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]rsc.io[/\\]quote[/\\]@v[/\\]v1.1.0.ziphash'
+go mod tidy
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash
+go mod verify
 
 # Packages below module root should not be mentioned in go.sum.
 rm go.sum
diff --git a/libgo/go/cmd/vendor/modules.txt b/libgo/go/cmd/vendor/modules.txt
index 10842768a88..ae2c0a00cce 100644
--- a/libgo/go/cmd/vendor/modules.txt
+++ b/libgo/go/cmd/vendor/modules.txt
@@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm
 golang.org/x/crypto/ed25519
 golang.org/x/crypto/ed25519/internal/edwards25519
 golang.org/x/crypto/ssh/terminal
-# golang.org/x/mod v0.4.2-0.20210302225053-d515b24adc21
+# golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea
 ## explicit
 golang.org/x/mod/internal/lazyregexp
 golang.org/x/mod/modfile
diff --git a/libgo/go/golang.org/x/mod/module/module.go 
b/libgo/go/golang.org/x/mod/module/module.go
index 272baeef176..0e03014837c 100644
--- a/libgo/go/golang.org/x/mod/module/module.go
+++ b/libgo/go/golang.org/x/mod/module/module.go
@@ -224,12 +224,16 @@ func firstPathOK(r rune) bool {
                'a' <= r && r <= 'z'
 }
 
-// pathOK reports whether r can appear in an import path element.
+// modPathOK reports whether r can appear in a module path element.
 // Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - 
. _ and ~.
-// This matches what "go get" has historically recognized in import paths.
+//
+// This matches what "go get" has historically recognized in import paths,
+// and avoids confusing sequences like '%20' or '+' that would change meaning
+// if used in a URL.
+//
 // TODO(rsc): We would like to allow Unicode letters, but that requires 
additional
 // care in the safe encoding (see "escaped paths" above).
-func pathOK(r rune) bool {
+func modPathOK(r rune) bool {
        if r < utf8.RuneSelf {
                return r == '-' || r == '.' || r == '_' || r == '~' ||
                        '0' <= r && r <= '9' ||
@@ -239,6 +243,17 @@ func pathOK(r rune) bool {
        return false
 }
 
+// modPathOK reports whether r can appear in a package import path element.
+//
+// Import paths are intermediate between module paths and file paths: we allow
+// disallow characters that would be confusing or ambiguous as arguments to
+// 'go get' (such as '@' and ' ' ), but allow certain characters that are
+// otherwise-unambiguous on the command line and historically used for some
+// binary names (such as '++' as a suffix for compiler binaries and wrappers).
+func importPathOK(r rune) bool {
+       return modPathOK(r) || r == '+'
+}
+
 // fileNameOK reports whether r can appear in a file name.
 // For now we allow all Unicode letters but otherwise limit to pathOK plus a 
few more punctuation characters.
 // If we expand the set of allowed characters here, we have to
@@ -394,12 +409,19 @@ func checkElem(elem string, kind pathKind) error {
        if elem[len(elem)-1] == '.' {
                return fmt.Errorf("trailing dot in path element")
        }
-       charOK := pathOK
-       if kind == filePath {
-               charOK = fileNameOK
-       }
        for _, r := range elem {
-               if !charOK(r) {
+               ok := false
+               switch kind {
+               case modulePath:
+                       ok = modPathOK(r)
+               case importPath:
+                       ok = importPathOK(r)
+               case filePath:
+                       ok = fileNameOK(r)
+               default:
+                       panic(fmt.Sprintf("internal error: invalid kind %v", 
kind))
+               }
+               if !ok {
                        return fmt.Errorf("invalid char %q", r)
                }
        }
diff --git a/libgo/go/runtime/symtab_test.go b/libgo/go/runtime/symtab_test.go
index 807b50de990..ddf64f6854a 100644
--- a/libgo/go/runtime/symtab_test.go
+++ b/libgo/go/runtime/symtab_test.go
@@ -8,6 +8,7 @@ import (
        "runtime"
        "strings"
        "testing"
+       "unsafe"
 )
 
 var _ = runtime.Caller
@@ -171,3 +172,87 @@ func TestNilName(t *testing.T) {
                t.Errorf("Name() = %q, want %q", got, "")
        }
 }
+
+var dummy int
+
+func inlined() {
+       // Side effect to prevent elimination of this entire function.
+       dummy = 42
+}
+
+// A function with an InlTree. Returns a PC within the function body.
+//
+// No inline to ensure this complete function appears in output.
+//
+//go:noinline
+func tracebackFunc(t *testing.T) uintptr {
+       // This body must be more complex than a single call to inlined to get
+       // an inline tree.
+       inlined()
+       inlined()
+
+       // Acquire a PC in this function.
+       pc, _, _, ok := runtime.Caller(0)
+       if !ok {
+               t.Fatalf("Caller(0) got ok false, want true")
+       }
+
+       return pc
+}
+
+// Test that CallersFrames handles PCs in the alignment region between
+// functions (int 3 on amd64) without crashing.
+//
+// Go will never generate a stack trace containing such an address, as it is
+// not a valid call site. However, the cgo traceback function passed to
+// runtime.SetCgoTraceback may not be completely accurate and may incorrect
+// provide PCs in Go code or the alignement region between functions.
+//
+// Go obviously doesn't easily expose the problematic PCs to running programs,
+// so this test is a bit fragile. Some details:
+//
+// * tracebackFunc is our target function. We want to get a PC in the
+//   alignment region following this function. This function also has other
+//   functions inlined into it to ensure it has an InlTree (this was the source
+//   of the bug in issue 44971).
+//
+// * We acquire a PC in tracebackFunc, walking forwards until FuncForPC says
+//   we're in a new function. The last PC of the function according to 
FuncForPC
+//   should be in the alignment region (assuming the function isn't already
+//   perfectly aligned).
+//
+// This is a regression test for issue 44971.
+func TestFunctionAlignmentTraceback(t *testing.T) {
+       pc := tracebackFunc(t)
+
+       // Double-check we got the right PC.
+       f := runtime.FuncForPC(pc)
+       if !strings.HasSuffix(f.Name(), "tracebackFunc") {
+               t.Fatalf("Caller(0) = %+v, want tracebackFunc", f)
+       }
+
+       // Iterate forward until we find a different function. Back up one
+       // instruction is (hopefully) an alignment instruction.
+       for runtime.FuncForPC(pc) == f {
+               pc++
+       }
+       pc--
+
+       // Is this an alignment region filler instruction? We only check this
+       // on amd64 for simplicity. If this function has no filler, then we may
+       // get a false negative, but will never get a false positive.
+       if runtime.GOARCH == "amd64" && runtime.Compiler == "gc" {
+               code := *(*uint8)(unsafe.Pointer(pc))
+               if code != 0xcc { // INT $3
+                       t.Errorf("PC %v code got %#x want 0xcc", pc, code)
+               }
+       }
+
+       // Finally ensure that Frames.Next doesn't crash when processing this
+       // PC.
+       frames := runtime.CallersFrames([]uintptr{pc})
+       frame, _ := frames.Next()
+       if *frame.Func != *f {
+               t.Errorf("frames.Next() got %+v want %+v", frame.Func, f)
+       }
+}
diff --git a/libgo/go/runtime/time.go b/libgo/go/runtime/time.go
index a69db993c9d..327726c09db 100644
--- a/libgo/go/runtime/time.go
+++ b/libgo/go/runtime/time.go
@@ -262,6 +262,9 @@ func addtimer(t *timer) {
 
        when := t.when
 
+       // Disable preemption while using pp to avoid changing another P's heap.
+       mp := acquirem()
+
        pp := getg().m.p.ptr()
        lock(&pp.timersLock)
        cleantimers(pp)
@@ -269,6 +272,8 @@ func addtimer(t *timer) {
        unlock(&pp.timersLock)
 
        wakeNetPoller(when)
+
+       releasem(mp)
 }
 
 // doaddtimer adds t to the current P's heap.
diff --git a/libgo/go/testing/helper_test.go b/libgo/go/testing/helper_test.go
index 8858196cf08..b27fd62ee8f 100644
--- a/libgo/go/testing/helper_test.go
+++ b/libgo/go/testing/helper_test.go
@@ -71,6 +71,38 @@ func TestTBHelperParallel(t *T) {
        }
 }
 
+func TestTBHelperLineNumer(t *T) {
+       var buf bytes.Buffer
+       ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
+       t1 := &T{
+               common: common{
+                       signal: make(chan bool),
+                       w:      &buf,
+               },
+               context: ctx,
+       }
+       t1.Run("Test", func(t *T) {
+               helperA := func(t *T) {
+                       t.Helper()
+                       t.Run("subtest", func(t *T) {
+                               t.Helper()
+                               t.Fatal("fatal error message")
+                       })
+               }
+               helperA(t)
+       })
+
+       want := "helper_test.go:92: fatal error message"
+       got := ""
+       lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
+       if len(lines) > 0 {
+               got = strings.TrimSpace(lines[len(lines)-1])
+       }
+       if got != want {
+               t.Errorf("got output:\n\n%v\nwant:\n\n%v", got, want)
+       }
+}
+
 type noopWriter int
 
 func (nw *noopWriter) Write(b []byte) (int, error) { return len(b), nil }
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index 795ee32ae1d..143d81c08a2 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -509,6 +509,13 @@ func (c *common) frameSkip(skip int) runtime.Frame {
                        }
                        return prevFrame
                }
+               // If more helper PCs have been added since we last did the 
conversion
+               if c.helperNames == nil {
+                       c.helperNames = make(map[string]struct{})
+                       for pc := range c.helperPCs {
+                               c.helperNames[pcToName(pc)] = struct{}{}
+                       }
+               }
                if _, ok := c.helperNames[frame.Function]; !ok {
                        // Found a frame that wasn't inside a helper function.
                        return frame
@@ -521,14 +528,6 @@ func (c *common) frameSkip(skip int) runtime.Frame {
 // and inserts the final newline if needed and indentation spaces for 
formatting.
 // This function must be called with c.mu held.
 func (c *common) decorate(s string, skip int) string {
-       // If more helper PCs have been added since we last did the conversion
-       if c.helperNames == nil {
-               c.helperNames = make(map[string]struct{})
-               for pc := range c.helperPCs {
-                       c.helperNames[pcToName(pc)] = struct{}{}
-               }
-       }
-
        frame := c.frameSkip(skip)
        file := frame.File
        line := frame.Line
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index 86b634c92e4..fb66e70c5fa 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -512,6 +512,22 @@ func TestZeroTimerStopPanics(t *testing.T) {
        tr.Stop()
 }
 
+// Test that zero duration timers aren't missed by the scheduler. Regression 
test for issue 44868.
+func TestZeroTimer(t *testing.T) {
+       if testing.Short() {
+               t.Skip("-short")
+       }
+
+       for i := 0; i < 1000000; i++ {
+               s := Now()
+               ti := NewTimer(0)
+               <-ti.C
+               if diff := Since(s); diff > 2*Second {
+                       t.Errorf("Expected time to get value from Timer channel 
in less than 2 sec, took %v", diff)
+               }
+       }
+}
+
 // Benchmark timer latency when the thread that creates the timer is busy with
 // other work and the timers must be serviced by other threads.
 // https://golang.org/issue/38860
diff --git a/libgo/misc/cgo/testplugin/plugin_test.go 
b/libgo/misc/cgo/testplugin/plugin_test.go
index 2d991012c82..8869528015d 100644
--- a/libgo/misc/cgo/testplugin/plugin_test.go
+++ b/libgo/misc/cgo/testplugin/plugin_test.go
@@ -209,3 +209,10 @@ func TestMethod2(t *testing.T) {
        goCmd(t, "build", "-o", "method2.exe", "./method2/main.go")
        run(t, "./method2.exe")
 }
+
+func TestIssue44956(t *testing.T) {
+       goCmd(t, "build", "-buildmode=plugin", "-o", "issue44956p1.so", 
"./issue44956/plugin1.go")
+       goCmd(t, "build", "-buildmode=plugin", "-o", "issue44956p2.so", 
"./issue44956/plugin2.go")
+       goCmd(t, "build", "-o", "issue44956.exe", "./issue44956/main.go")
+       run(t, "./issue44956.exe")
+}
diff --git a/libgo/misc/cgo/testplugin/testdata/issue44956/base/base.go 
b/libgo/misc/cgo/testplugin/testdata/issue44956/base/base.go
new file mode 100644
index 00000000000..609aa0dff4e
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/testdata/issue44956/base/base.go
@@ -0,0 +1,7 @@
+// 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 base
+
+var X = &map[int]int{123: 456}
diff --git a/libgo/misc/cgo/testplugin/testdata/issue44956/main.go 
b/libgo/misc/cgo/testplugin/testdata/issue44956/main.go
new file mode 100644
index 00000000000..287a60585e0
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/testdata/issue44956/main.go
@@ -0,0 +1,47 @@
+// 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.
+
+// Issue 44956: writable static temp is not exported correctly.
+// In the test below, package base is
+//
+//     X = &map{...}
+//
+// which compiles to
+//
+//     X = &stmp           // static
+//     stmp = makemap(...) // in init function
+//
+// plugin1 and plugin2 both import base. plugin1 doesn't use
+// base.X, so that symbol is deadcoded in plugin1.
+//
+// plugin1 is loaded first. base.init runs at that point, which
+// initialize base.stmp.
+//
+// plugin2 is then loaded. base.init already ran, so it doesn't run
+// again. When base.stmp is not exported, plugin2's base.X points to
+// its own private base.stmp, which is not initialized, fail.
+
+package main
+
+import "plugin"
+
+func main() {
+       _, err := plugin.Open("issue44956p1.so")
+       if err != nil {
+               panic("FAIL")
+       }
+
+       p2, err := plugin.Open("issue44956p2.so")
+       if err != nil {
+               panic("FAIL")
+       }
+       f, err := p2.Lookup("F")
+       if err != nil {
+               panic("FAIL")
+       }
+       x := f.(func() *map[int]int)()
+       if x == nil || (*x)[123] != 456 {
+               panic("FAIL")
+       }
+}
diff --git a/libgo/misc/cgo/testplugin/testdata/issue44956/plugin1.go 
b/libgo/misc/cgo/testplugin/testdata/issue44956/plugin1.go
new file mode 100644
index 00000000000..499fa31abf8
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/testdata/issue44956/plugin1.go
@@ -0,0 +1,9 @@
+// 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
+
+import _ "testplugin/issue44956/base"
+
+func main() {}
diff --git a/libgo/misc/cgo/testplugin/testdata/issue44956/plugin2.go 
b/libgo/misc/cgo/testplugin/testdata/issue44956/plugin2.go
new file mode 100644
index 00000000000..a73542ca716
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/testdata/issue44956/plugin2.go
@@ -0,0 +1,11 @@
+// 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
+
+import "testplugin/issue44956/base"
+
+func F() *map[int]int { return base.X }
+
+func main() {}

Reply via email to