libgo: update to final Go 1.8 release
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 17 Feb 2017 15:43:39 +0000 (15:43 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 17 Feb 2017 15:43:39 +0000 (15:43 +0000)
    Along with the update this fixes a problem that was always present but
    only showed up with the new reflect test.  When a program used a
    **unsafe.Pointer and stored the value in an interface type, the
    generated type descriptor pointed to the GC data for *unsafe.Pointer.
    It did that by name, but we were not generating a variable with the
    right name.

    Reviewed-on: https://go-review.googlesource.com/37144

From-SVN: r245535

20 files changed:
gcc/go/gofrontend/MERGE
libgo/MERGE
libgo/VERSION
libgo/go/cmd/go/alldocs.go
libgo/go/cmd/go/get.go
libgo/go/cmd/go/go_test.go
libgo/go/cmd/go/main.go
libgo/go/crypto/x509/root_linux.go
libgo/go/database/sql/ctxutil.go
libgo/go/database/sql/sql.go
libgo/go/database/sql/sql_test.go
libgo/go/encoding/xml/marshal.go
libgo/go/encoding/xml/marshal_test.go
libgo/go/go/build/build.go
libgo/go/reflect/all_test.go
libgo/go/reflect/type.go
libgo/go/runtime/testdata/testprogcgo/threadpprof.go
libgo/go/runtime/testdata/testprogcgo/traceback.go
libgo/go/testing/testing.go
libgo/runtime/go-unsafe-pointer.c

index 0f5bec0cc6e1c9385789ccbb9777ccc076488f2a..9cf7ec34f4ab8399f4436db0c4856106d0291803 100644 (file)
@@ -1,4 +1,4 @@
-c3935e1f20ad5b1d4c41150f11fb266913c04df7
+893f0e4a707c6f10eb14842b18954486042f0fb3
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index fa155a238d6430621f1717ffb5026c5f195b7b10..16f346a2b8e6832e3f4eb9b29ad7203bc055e5ed 100644 (file)
@@ -1,4 +1,4 @@
-2a5f65a98ca483aad2dd74dc2636a7baecc59cf2
+cd6b6202dd1559b3ac63179b45f1833fcfbe7eca
 
 The first line of this file holds the git revision number of the
 last merge done from the master library sources.
index 8b33af3b6b0b4dc095a289b1ca5eaac196d96c3b..436edd93930654ba96603e796227c537f3534a52 100644 (file)
@@ -1 +1 @@
-go1.8rc3
+go1.8
index e93fd6ebed7775157cdfd0c143d43cac6759fa2b..3d5dd2b39725883fd01bb5541d8604c268ddd4fc 100644 (file)
@@ -17,7 +17,7 @@
 //     clean       remove object files
 //     doc         show documentation for package or symbol
 //     env         print Go environment information
-//     bug         print information for bug reports
+//     bug         start a bug report
 //     fix         run go tool fix on packages
 //     fmt         run gofmt on package sources
 //     generate    generate Go files by processing source
 // each named variable on its own line.
 //
 //
-// Print information for bug reports
+// Start a bug report
 //
 // Usage:
 //
 //     go bug
 //
-// Bug prints information that helps file effective bug reports.
-//
-// Bugs may be reported at https://golang.org/issue/new.
+// Bug opens the default browser and starts a new bug report.
+// The report includes useful system information.
 //
 //
 // Run go tool fix on packages
index 1d7677c615c176e0150576e831bc58ae5f83db52..6fb4235068ec944a94b49c8fe07a972e9824b004 100644 (file)
@@ -428,7 +428,7 @@ func downloadPackage(p *Package) error {
                        return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
                }
                // Guard against people setting GOPATH=$GOROOT.
-               if list[0] == goroot {
+               if filepath.Clean(list[0]) == filepath.Clean(goroot) {
                        return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
                }
                if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
index f26c3660e4b809a1ea76d13b4d1a2176fdf419d4..56de65ce55ae3d65e6bf0db6d7538a2d022572fa 100644 (file)
@@ -1683,173 +1683,111 @@ func homeEnvName() string {
        }
 }
 
-// Test go env missing GOPATH shows default.
-func TestMissingGOPATHEnvShowsDefault(t *testing.T) {
+func TestDefaultGOPATH(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
        tg.parallel()
-       tg.setenv("GOPATH", "")
-       tg.run("env", "GOPATH")
+       tg.tempDir("home/go")
+       tg.setenv(homeEnvName(), tg.path("home"))
 
-       want := filepath.Join(os.Getenv(homeEnvName()), "go")
-       got := strings.TrimSpace(tg.getStdout())
-       if got != want {
-               t.Errorf("got %q; want %q", got, want)
-       }
-}
-
-// Test go get missing GOPATH causes go get to warn if directory doesn't exist.
-func TestMissingGOPATHGetWarnsIfNotExists(t *testing.T) {
-       testenv.MustHaveExternalNetwork(t)
-
-       if _, err := exec.LookPath("git"); err != nil {
-               t.Skip("skipping because git binary not found")
-       }
-
-       tg := testgo(t)
-       defer tg.cleanup()
-
-       // setenv variables for test and defer deleting temporary home directory.
-       tg.setenv("GOPATH", "")
-       tmp, err := ioutil.TempDir("", "")
-       if err != nil {
-               t.Fatalf("could not create tmp home: %v", err)
-       }
-       defer os.RemoveAll(tmp)
-       tg.setenv(homeEnvName(), tmp)
+       tg.run("env", "GOPATH")
+       tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go")
 
-       tg.run("get", "-v", "github.com/golang/example/hello")
+       tg.setenv("GOROOT", tg.path("home/go"))
+       tg.run("env", "GOPATH")
+       tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go")
 
-       want := fmt.Sprintf("created GOPATH=%s; see 'go help gopath'", filepath.Join(tmp, "go"))
-       got := strings.TrimSpace(tg.getStderr())
-       if !strings.Contains(got, want) {
-               t.Errorf("got %q; want %q", got, want)
-       }
+       tg.setenv("GOROOT", tg.path("home/go")+"/")
+       tg.run("env", "GOPATH")
+       tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/")
 }
 
-// Test go get missing GOPATH causes no warning if directory exists.
-func TestMissingGOPATHGetDoesntWarnIfExists(t *testing.T) {
+func TestDefaultGOPATHGet(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)
 
-       if _, err := exec.LookPath("git"); err != nil {
-               t.Skip("skipping because git binary not found")
-       }
-
        tg := testgo(t)
        defer tg.cleanup()
-
-       // setenv variables for test and defer resetting them.
        tg.setenv("GOPATH", "")
-       tmp, err := ioutil.TempDir("", "")
-       if err != nil {
-               t.Fatalf("could not create tmp home: %v", err)
-       }
-       defer os.RemoveAll(tmp)
-       if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
-               t.Fatalf("could not create $HOME/go: %v", err)
-       }
+       tg.tempDir("home")
+       tg.setenv(homeEnvName(), tg.path("home"))
 
-       tg.setenv(homeEnvName(), tmp)
+       // warn for creating directory
+       tg.run("get", "-v", "github.com/golang/example/hello")
+       tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH")
 
+       // no warning if directory already exists
+       tg.must(os.RemoveAll(tg.path("home/go")))
+       tg.tempDir("home/go")
        tg.run("get", "github.com/golang/example/hello")
+       tg.grepStderrNot(".", "expected no output on standard error")
 
-       got := strings.TrimSpace(tg.getStderr())
-       if got != "" {
-               t.Errorf("got %q; wants empty", got)
-       }
-}
-
-// Test go get missing GOPATH fails if pointed file is not a directory.
-func TestMissingGOPATHGetFailsIfItsNotDirectory(t *testing.T) {
-       testenv.MustHaveExternalNetwork(t)
-
-       tg := testgo(t)
-       defer tg.cleanup()
-
-       // setenv variables for test and defer resetting them.
-       tg.setenv("GOPATH", "")
-       tmp, err := ioutil.TempDir("", "")
-       if err != nil {
-               t.Fatalf("could not create tmp home: %v", err)
-       }
-       defer os.RemoveAll(tmp)
-
-       path := filepath.Join(tmp, "go")
-       if err := ioutil.WriteFile(path, nil, 0777); err != nil {
-               t.Fatalf("could not create GOPATH at %s: %v", path, err)
-       }
-       tg.setenv(homeEnvName(), tmp)
-
-       const pkg = "github.com/golang/example/hello"
-       tg.runFail("get", pkg)
-
-       msg := "not a directory"
-       if runtime.GOOS == "windows" {
-               msg = "The system cannot find the path specified."
-       }
-       want := fmt.Sprintf("package %s: mkdir %s: %s", pkg, filepath.Join(tmp, "go"), msg)
-       got := strings.TrimSpace(tg.getStderr())
-       if got != want {
-               t.Errorf("got %q; wants %q", got, want)
-       }
+       // error if $HOME/go is a file
+       tg.must(os.RemoveAll(tg.path("home/go")))
+       tg.tempFile("home/go", "")
+       tg.runFail("get", "github.com/golang/example/hello")
+       tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file")
 }
 
-// Test go install of missing package when missing GOPATH fails and shows default GOPATH.
-func TestMissingGOPATHInstallMissingPackageFailsAndShowsDefault(t *testing.T) {
+func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
-
-       // setenv variables for test and defer resetting them.
        tg.setenv("GOPATH", "")
-       tmp, err := ioutil.TempDir("", "")
-       if err != nil {
-               t.Fatalf("could not create tmp home: %v", err)
-       }
-       defer os.RemoveAll(tmp)
-       if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
-               t.Fatalf("could not create $HOME/go: %v", err)
-       }
-       tg.setenv(homeEnvName(), tmp)
-
-       const pkg = "github.com/golang/example/hello"
-       tg.runFail("install", pkg)
-
-       pkgPath := filepath.Join(strings.Split(pkg, "/")...)
-       want := fmt.Sprintf("can't load package: package %s: cannot find package \"%s\" in any of:", pkg, pkg) +
-               fmt.Sprintf("\n\t%s (from $GOROOT)", filepath.Join(runtime.GOROOT(), "src", pkgPath)) +
-               fmt.Sprintf("\n\t%s (from $GOPATH)", filepath.Join(tmp, "go", "src", pkgPath))
+       tg.tempDir("home")
+       tg.setenv(homeEnvName(), tg.path("home"))
 
-       got := strings.TrimSpace(tg.getStderr())
-       if got != want {
-               t.Errorf("got %q; wants %q", got, want)
-       }
+       tg.runFail("install", "github.com/golang/example/hello")
+       tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")
 }
 
 // Issue 4186.  go get cannot be used to download packages to $GOROOT.
 // Test that without GOPATH set, go get should fail.
-func TestWithoutGOPATHGoGetFails(t *testing.T) {
+func TestGoGetIntoGOROOT(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)
 
        tg := testgo(t)
        defer tg.cleanup()
        tg.parallel()
        tg.tempDir("src")
-       tg.setenv("GOPATH", "")
+
+       // Fails because GOROOT=GOPATH
+       tg.setenv("GOPATH", tg.path("."))
        tg.setenv("GOROOT", tg.path("."))
-       tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
-}
+       tg.runFail("get", "-d", "github.com/golang/example/hello")
+       tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
+       tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
 
-// Test that with GOPATH=$GOROOT, go get should fail.
-func TestWithGOPATHEqualsGOROOTGoGetFails(t *testing.T) {
-       testenv.MustHaveExternalNetwork(t)
+       // Fails because GOROOT=GOPATH after cleaning.
+       tg.setenv("GOPATH", tg.path(".")+"/")
+       tg.setenv("GOROOT", tg.path("."))
+       tg.runFail("get", "-d", "github.com/golang/example/hello")
+       tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
+       tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
 
-       tg := testgo(t)
-       defer tg.cleanup()
-       tg.parallel()
-       tg.tempDir("src")
        tg.setenv("GOPATH", tg.path("."))
-       tg.setenv("GOROOT", tg.path("."))
-       tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
+       tg.setenv("GOROOT", tg.path(".")+"/")
+       tg.runFail("get", "-d", "github.com/golang/example/hello")
+       tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
+       tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
+
+       // Fails because GOROOT=$HOME/go so default GOPATH unset.
+       tg.tempDir("home/go")
+       tg.setenv(homeEnvName(), tg.path("home"))
+       tg.setenv("GOPATH", "")
+       tg.setenv("GOROOT", tg.path("home/go"))
+       tg.runFail("get", "-d", "github.com/golang/example/hello")
+       tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
+
+       tg.setenv(homeEnvName(), tg.path("home")+"/")
+       tg.setenv("GOPATH", "")
+       tg.setenv("GOROOT", tg.path("home/go"))
+       tg.runFail("get", "-d", "github.com/golang/example/hello")
+       tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
+
+       tg.setenv(homeEnvName(), tg.path("home"))
+       tg.setenv("GOPATH", "")
+       tg.setenv("GOROOT", tg.path("home/go")+"/")
+       tg.runFail("get", "-d", "github.com/golang/example/hello")
+       tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
 }
 
 func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
@@ -3744,6 +3682,13 @@ func TestMatchesOnlySubtestParallelIsOK(t *testing.T) {
        tg.grepBoth(okPattern, "go test did not say ok")
 }
 
+// Issue 18845
+func TestBenchTimeout(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go")
+}
+
 func TestLinkXImportPathEscape(t *testing.T) {
        // golang.org/issue/16710
        tg := testgo(t)
index 07fc4e2a9050d836efba2df98be15d40218ed29f..d80ff2da5fe67d28a711d3ff72436db032d3c965 100644 (file)
@@ -136,7 +136,7 @@ func main() {
        // Diagnose common mistake: GOPATH==GOROOT.
        // This setting is equivalent to not setting GOPATH at all,
        // which is not what most people want when they do it.
-       if gopath := buildContext.GOPATH; gopath == runtime.GOROOT() {
+       if gopath := buildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
                fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
        } else {
                for _, p := range filepath.SplitList(gopath) {
index 38dd72d3ed66623a82226197c00ca18b80eeeffd..aa1785e4c637508f2d01d0679f271f7ea3d3bc51 100644 (file)
@@ -7,8 +7,8 @@ package x509
 // Possible certificate files; stop after finding one.
 var certFiles = []string{
        "/etc/ssl/certs/ca-certificates.crt",                // Debian/Ubuntu/Gentoo etc.
-       "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
        "/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
        "/etc/ssl/ca-bundle.pem",                            // OpenSUSE
        "/etc/pki/tls/cacert.pem",                           // OpenELEC
+       "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
 }
index 1071446227fb4f25caf22600715e0c47fde02ce3..bd652b54625337b211fe1b9466239acfa104b190 100644 (file)
@@ -35,15 +35,12 @@ func ctxDriverExec(ctx context.Context, execer driver.Execer, query string, nvda
                return nil, err
        }
 
-       resi, err := execer.Exec(query, dargs)
-       if err == nil {
-               select {
-               default:
-               case <-ctx.Done():
-                       return resi, ctx.Err()
-               }
+       select {
+       default:
+       case <-ctx.Done():
+               return nil, ctx.Err()
        }
-       return resi, err
+       return execer.Exec(query, dargs)
 }
 
 func ctxDriverQuery(ctx context.Context, queryer driver.Queryer, query string, nvdargs []driver.NamedValue) (driver.Rows, error) {
@@ -56,16 +53,12 @@ func ctxDriverQuery(ctx context.Context, queryer driver.Queryer, query string, n
                return nil, err
        }
 
-       rowsi, err := queryer.Query(query, dargs)
-       if err == nil {
-               select {
-               default:
-               case <-ctx.Done():
-                       rowsi.Close()
-                       return nil, ctx.Err()
-               }
+       select {
+       default:
+       case <-ctx.Done():
+               return nil, ctx.Err()
        }
-       return rowsi, err
+       return queryer.Query(query, dargs)
 }
 
 func ctxDriverStmtExec(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Result, error) {
@@ -77,15 +70,12 @@ func ctxDriverStmtExec(ctx context.Context, si driver.Stmt, nvdargs []driver.Nam
                return nil, err
        }
 
-       resi, err := si.Exec(dargs)
-       if err == nil {
-               select {
-               default:
-               case <-ctx.Done():
-                       return resi, ctx.Err()
-               }
+       select {
+       default:
+       case <-ctx.Done():
+               return nil, ctx.Err()
        }
-       return resi, err
+       return si.Exec(dargs)
 }
 
 func ctxDriverStmtQuery(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Rows, error) {
@@ -97,16 +87,12 @@ func ctxDriverStmtQuery(ctx context.Context, si driver.Stmt, nvdargs []driver.Na
                return nil, err
        }
 
-       rowsi, err := si.Query(dargs)
-       if err == nil {
-               select {
-               default:
-               case <-ctx.Done():
-                       rowsi.Close()
-                       return nil, ctx.Err()
-               }
+       select {
+       default:
+       case <-ctx.Done():
+               return nil, ctx.Err()
        }
-       return rowsi, err
+       return si.Query(dargs)
 }
 
 var errLevelNotSupported = errors.New("sql: selected isolation level is not supported")
index feb91223a9e9b99f48fa65e041afd6f7d309e791..c016681fca13c305aaea2cbfd6fc0707135c5827 100644 (file)
@@ -305,8 +305,9 @@ type DB struct {
 
        mu           sync.Mutex // protects following fields
        freeConn     []*driverConn
-       connRequests []chan connRequest
-       numOpen      int // number of opened and pending open connections
+       connRequests map[uint64]chan connRequest
+       nextRequest  uint64 // Next key to use in connRequests.
+       numOpen      int    // number of opened and pending open connections
        // Used to signal the need for new connections
        // a goroutine running connectionOpener() reads on this chan and
        // maybeOpenNewConnections sends on the chan (one send per needed connection)
@@ -572,10 +573,11 @@ func Open(driverName, dataSourceName string) (*DB, error) {
                return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
        }
        db := &DB{
-               driver:   driveri,
-               dsn:      dataSourceName,
-               openerCh: make(chan struct{}, connectionRequestQueueSize),
-               lastPut:  make(map[*driverConn]string),
+               driver:       driveri,
+               dsn:          dataSourceName,
+               openerCh:     make(chan struct{}, connectionRequestQueueSize),
+               lastPut:      make(map[*driverConn]string),
+               connRequests: make(map[uint64]chan connRequest),
        }
        go db.connectionOpener()
        return db, nil
@@ -881,6 +883,14 @@ type connRequest struct {
 
 var errDBClosed = errors.New("sql: database is closed")
 
+// nextRequestKeyLocked returns the next connection request key.
+// It is assumed that nextRequest will not overflow.
+func (db *DB) nextRequestKeyLocked() uint64 {
+       next := db.nextRequest
+       db.nextRequest++
+       return next
+}
+
 // conn returns a newly-opened or cached *driverConn.
 func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error) {
        db.mu.Lock()
@@ -918,12 +928,25 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn
                // Make the connRequest channel. It's buffered so that the
                // connectionOpener doesn't block while waiting for the req to be read.
                req := make(chan connRequest, 1)
-               db.connRequests = append(db.connRequests, req)
+               reqKey := db.nextRequestKeyLocked()
+               db.connRequests[reqKey] = req
                db.mu.Unlock()
 
                // Timeout the connection request with the context.
                select {
                case <-ctx.Done():
+                       // Remove the connection request and ensure no value has been sent
+                       // on it after removing.
+                       db.mu.Lock()
+                       delete(db.connRequests, reqKey)
+                       db.mu.Unlock()
+                       select {
+                       default:
+                       case ret, ok := <-req:
+                               if ok {
+                                       db.putConn(ret.conn, ret.err)
+                               }
+                       }
                        return nil, ctx.Err()
                case ret, ok := <-req:
                        if !ok {
@@ -1044,12 +1067,12 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
                return false
        }
        if c := len(db.connRequests); c > 0 {
-               req := db.connRequests[0]
-               // This copy is O(n) but in practice faster than a linked list.
-               // TODO: consider compacting it down less often and
-               // moving the base instead?
-               copy(db.connRequests, db.connRequests[1:])
-               db.connRequests = db.connRequests[:c-1]
+               var req chan connRequest
+               var reqKey uint64
+               for reqKey, req = range db.connRequests {
+                       break
+               }
+               delete(db.connRequests, reqKey) // Remove from pending requests.
                if err == nil {
                        dc.inUse = true
                }
@@ -2071,14 +2094,21 @@ type Rows struct {
        dc          *driverConn // owned; must call releaseConn when closed to release
        releaseConn func(error)
        rowsi       driver.Rows
+       cancel      func()      // called when Rows is closed, may be nil.
+       closeStmt   *driverStmt // if non-nil, statement to Close on close
 
-       // closed value is 1 when the Rows is closed.
-       // Use atomic operations on value when checking value.
-       closed    int32
-       cancel    func() // called when Rows is closed, may be nil.
-       lastcols  []driver.Value
-       lasterr   error       // non-nil only if closed is true
-       closeStmt *driverStmt // if non-nil, statement to Close on close
+       // closemu prevents Rows from closing while there
+       // is an active streaming result. It is held for read during non-close operations
+       // and exclusively during close.
+       //
+       // closemu guards lasterr and closed.
+       closemu sync.RWMutex
+       closed  bool
+       lasterr error // non-nil only if closed is true
+
+       // lastcols is only used in Scan, Next, and NextResultSet which are expected
+       // not not be called concurrently.
+       lastcols []driver.Value
 }
 
 func (rs *Rows) initContextClose(ctx context.Context) {
@@ -2089,7 +2119,7 @@ func (rs *Rows) initContextClose(ctx context.Context) {
 // awaitDone blocks until the rows are closed or the context canceled.
 func (rs *Rows) awaitDone(ctx context.Context) {
        <-ctx.Done()
-       rs.Close()
+       rs.close(ctx.Err())
 }
 
 // Next prepares the next result row for reading with the Scan method. It
@@ -2099,8 +2129,19 @@ func (rs *Rows) awaitDone(ctx context.Context) {
 //
 // Every call to Scan, even the first one, must be preceded by a call to Next.
 func (rs *Rows) Next() bool {
-       if rs.isClosed() {
-               return false
+       var doClose, ok bool
+       withLock(rs.closemu.RLocker(), func() {
+               doClose, ok = rs.nextLocked()
+       })
+       if doClose {
+               rs.Close()
+       }
+       return ok
+}
+
+func (rs *Rows) nextLocked() (doClose, ok bool) {
+       if rs.closed {
+               return false, false
        }
        if rs.lastcols == nil {
                rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns()))
@@ -2109,23 +2150,21 @@ func (rs *Rows) Next() bool {
        if rs.lasterr != nil {
                // Close the connection if there is a driver error.
                if rs.lasterr != io.EOF {
-                       rs.Close()
-                       return false
+                       return true, false
                }
                nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
                if !ok {
-                       rs.Close()
-                       return false
+                       return true, false
                }
                // The driver is at the end of the current result set.
                // Test to see if there is another result set after the current one.
                // Only close Rows if there is no further result sets to read.
                if !nextResultSet.HasNextResultSet() {
-                       rs.Close()
+                       doClose = true
                }
-               return false
+               return doClose, false
        }
-       return true
+       return false, true
 }
 
 // NextResultSet prepares the next result set for reading. It returns true if
@@ -2137,18 +2176,28 @@ func (rs *Rows) Next() bool {
 // scanning. If there are further result sets they may not have rows in the result
 // set.
 func (rs *Rows) NextResultSet() bool {
-       if rs.isClosed() {
+       var doClose bool
+       defer func() {
+               if doClose {
+                       rs.Close()
+               }
+       }()
+       rs.closemu.RLock()
+       defer rs.closemu.RUnlock()
+
+       if rs.closed {
                return false
        }
+
        rs.lastcols = nil
        nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
        if !ok {
-               rs.Close()
+               doClose = true
                return false
        }
        rs.lasterr = nextResultSet.NextResultSet()
        if rs.lasterr != nil {
-               rs.Close()
+               doClose = true
                return false
        }
        return true
@@ -2157,6 +2206,8 @@ func (rs *Rows) NextResultSet() bool {
 // Err returns the error, if any, that was encountered during iteration.
 // Err may be called after an explicit or implicit Close.
 func (rs *Rows) Err() error {
+       rs.closemu.RLock()
+       defer rs.closemu.RUnlock()
        if rs.lasterr == io.EOF {
                return nil
        }
@@ -2167,7 +2218,9 @@ func (rs *Rows) Err() error {
 // Columns returns an error if the rows are closed, or if the rows
 // are from QueryRow and there was a deferred error.
 func (rs *Rows) Columns() ([]string, error) {
-       if rs.isClosed() {
+       rs.closemu.RLock()
+       defer rs.closemu.RUnlock()
+       if rs.closed {
                return nil, errors.New("sql: Rows are closed")
        }
        if rs.rowsi == nil {
@@ -2179,7 +2232,9 @@ func (rs *Rows) Columns() ([]string, error) {
 // ColumnTypes returns column information such as column type, length,
 // and nullable. Some information may not be available from some drivers.
 func (rs *Rows) ColumnTypes() ([]*ColumnType, error) {
-       if rs.isClosed() {
+       rs.closemu.RLock()
+       defer rs.closemu.RUnlock()
+       if rs.closed {
                return nil, errors.New("sql: Rows are closed")
        }
        if rs.rowsi == nil {
@@ -2329,9 +2384,13 @@ func rowsColumnInfoSetup(rowsi driver.Rows) []*ColumnType {
 // For scanning into *bool, the source may be true, false, 1, 0, or
 // string inputs parseable by strconv.ParseBool.
 func (rs *Rows) Scan(dest ...interface{}) error {
-       if rs.isClosed() {
+       rs.closemu.RLock()
+       if rs.closed {
+               rs.closemu.RUnlock()
                return errors.New("sql: Rows are closed")
        }
+       rs.closemu.RUnlock()
+
        if rs.lastcols == nil {
                return errors.New("sql: Scan called without calling Next")
        }
@@ -2351,20 +2410,28 @@ func (rs *Rows) Scan(dest ...interface{}) error {
 // hook throug a test only mutex.
 var rowsCloseHook = func() func(*Rows, *error) { return nil }
 
-func (rs *Rows) isClosed() bool {
-       return atomic.LoadInt32(&rs.closed) != 0
-}
-
 // Close closes the Rows, preventing further enumeration. If Next is called
 // and returns false and there are no further result sets,
 // the Rows are closed automatically and it will suffice to check the
 // result of Err. Close is idempotent and does not affect the result of Err.
 func (rs *Rows) Close() error {
-       if !atomic.CompareAndSwapInt32(&rs.closed, 0, 1) {
+       return rs.close(nil)
+}
+
+func (rs *Rows) close(err error) error {
+       rs.closemu.Lock()
+       defer rs.closemu.Unlock()
+
+       if rs.closed {
                return nil
        }
+       rs.closed = true
+
+       if rs.lasterr == nil {
+               rs.lasterr = err
+       }
 
-       err := rs.rowsi.Close()
+       err = rs.rowsi.Close()
        if fn := rowsCloseHook(); fn != nil {
                fn(rs, &err)
        }
index 898df3b455b22cac915bdb19510cc9ba22f83cbe..450e5f1f8c961d1c0885a4bc97f3de8bcf26bd44 100644 (file)
@@ -153,8 +153,13 @@ func closeDB(t testing.TB, db *DB) {
        if err != nil {
                t.Fatalf("error closing DB: %v", err)
        }
-       if count := db.numOpenConns(); count != 0 {
-               t.Fatalf("%d connections still open after closing DB", count)
+
+       var numOpen int
+       if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+               numOpen = db.numOpenConns()
+               return numOpen == 0
+       }) {
+               t.Fatalf("%d connections still open after closing DB", numOpen)
        }
 }
 
@@ -276,6 +281,7 @@ func TestQuery(t *testing.T) {
        }
 }
 
+// TestQueryContext tests canceling the context while scanning the rows.
 func TestQueryContext(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
@@ -297,7 +303,7 @@ func TestQueryContext(t *testing.T) {
        for rows.Next() {
                if index == 2 {
                        cancel()
-                       time.Sleep(10 * time.Millisecond)
+                       waitForRowsClose(t, rows, 5*time.Second)
                }
                var r row
                err = rows.Scan(&r.age, &r.name)
@@ -313,9 +319,13 @@ func TestQueryContext(t *testing.T) {
                got = append(got, r)
                index++
        }
-       err = rows.Err()
-       if err != nil {
-               t.Fatalf("Err: %v", err)
+       select {
+       case <-ctx.Done():
+               if err := ctx.Err(); err != context.Canceled {
+                       t.Fatalf("context err = %v; want context.Canceled")
+               }
+       default:
+               t.Fatalf("context err = nil; want context.Canceled")
        }
        want := []row{
                {age: 1, name: "Alice"},
@@ -327,6 +337,7 @@ func TestQueryContext(t *testing.T) {
 
        // And verify that the final rows.Next() call, which hit EOF,
        // also closed the rows connection.
+       waitForRowsClose(t, rows, 5*time.Second)
        waitForFree(t, db, 5*time.Second, 1)
        if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
                t.Errorf("executed %d Prepare statements; want 1", prepares)
@@ -356,12 +367,27 @@ func waitForFree(t *testing.T, db *DB, maxWait time.Duration, want int) {
        }
 }
 
+func waitForRowsClose(t *testing.T, rows *Rows, maxWait time.Duration) {
+       if !waitCondition(maxWait, 5*time.Millisecond, func() bool {
+               rows.closemu.RLock()
+               defer rows.closemu.RUnlock()
+               return rows.closed
+       }) {
+               t.Fatal("failed to close rows")
+       }
+}
+
+// TestQueryContextWait ensures that rows and all internal statements are closed when
+// a query context is closed during execution.
 func TestQueryContextWait(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
        prepares0 := numPrepares(t, db)
 
-       ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*15)
+       // TODO(kardianos): convert this from using a timeout to using an explicit
+       // cancel when the query signals that is is "executing" the query.
+       ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
+       defer cancel()
 
        // This will trigger the *fakeConn.Prepare method which will take time
        // performing the query. The ctxDriverPrepare func will check the context
@@ -374,10 +400,15 @@ func TestQueryContextWait(t *testing.T) {
        // Verify closed rows connection after error condition.
        waitForFree(t, db, 5*time.Second, 1)
        if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
-               t.Errorf("executed %d Prepare statements; want 1", prepares)
+               // TODO(kardianos): if the context timeouts before the db.QueryContext
+               // executes this check may fail. After adjusting how the context
+               // is canceled above revert this back to a Fatal error.
+               t.Logf("executed %d Prepare statements; want 1", prepares)
        }
 }
 
+// TestTxContextWait tests the transaction behavior when the tx context is canceled
+// during execution of the query.
 func TestTxContextWait(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
@@ -386,6 +417,10 @@ func TestTxContextWait(t *testing.T) {
 
        tx, err := db.BeginTx(ctx, nil)
        if err != nil {
+               // Guard against the context being canceled before BeginTx completes.
+               if err == context.DeadlineExceeded {
+                       t.Skip("tx context canceled prior to first use")
+               }
                t.Fatal(err)
        }
 
@@ -398,12 +433,6 @@ func TestTxContextWait(t *testing.T) {
        }
 
        waitForFree(t, db, 5*time.Second, 0)
-
-       // Ensure the dropped connection allows more connections to be made.
-       // Checked on DB Close.
-       waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
-               return db.numOpenConns() == 0
-       })
 }
 
 func TestMultiResultSetQuery(t *testing.T) {
@@ -527,6 +556,63 @@ func TestQueryNamedArg(t *testing.T) {
        }
 }
 
+func TestPoolExhaustOnCancel(t *testing.T) {
+       if testing.Short() {
+               t.Skip("long test")
+       }
+       db := newTestDB(t, "people")
+       defer closeDB(t, db)
+
+       max := 3
+
+       db.SetMaxOpenConns(max)
+
+       // First saturate the connection pool.
+       // Then start new requests for a connection that is cancelled after it is requested.
+
+       var saturate, saturateDone sync.WaitGroup
+       saturate.Add(max)
+       saturateDone.Add(max)
+
+       for i := 0; i < max; i++ {
+               go func() {
+                       saturate.Done()
+                       rows, err := db.Query("WAIT|500ms|SELECT|people|name,photo|")
+                       if err != nil {
+                               t.Fatalf("Query: %v", err)
+                       }
+                       rows.Close()
+                       saturateDone.Done()
+               }()
+       }
+
+       saturate.Wait()
+
+       // Now cancel the request while it is waiting.
+       ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
+       defer cancel()
+
+       for i := 0; i < max; i++ {
+               ctxReq, cancelReq := context.WithCancel(ctx)
+               go func() {
+                       time.Sleep(time.Millisecond * 100)
+                       cancelReq()
+               }()
+               err := db.PingContext(ctxReq)
+               if err != context.Canceled {
+                       t.Fatalf("PingContext (Exhaust): %v", err)
+               }
+       }
+
+       saturateDone.Wait()
+
+       // Now try to open a normal connection.
+       err := db.PingContext(ctx)
+       if err != nil {
+               t.Fatalf("PingContext (Normal): %v", err)
+       }
+}
+
 func TestByteOwnership(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
@@ -2677,7 +2763,6 @@ func TestIssue18429(t *testing.T) {
                }()
        }
        wg.Wait()
-       time.Sleep(milliWait * 3 * time.Millisecond)
 }
 
 // TestIssue18719 closes the context right before use. The sql.driverConn
@@ -2720,14 +2805,8 @@ func TestIssue18719(t *testing.T) {
        // Do not explicitly rollback. The rollback will happen from the
        // canceled context.
 
-       // Wait for connections to return to pool.
-       var numOpen int
-       if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
-               numOpen = db.numOpenConns()
-               return numOpen == 0
-       }) {
-               t.Fatalf("open conns after hitting EOF = %d; want 0", numOpen)
-       }
+       cancel()
+       waitForRowsClose(t, rows, 5*time.Second)
 }
 
 func TestConcurrency(t *testing.T) {
index 1176f5d717d0b47692d84f511570fcf09045985e..4c6ba8c1a5abee01f1be377661fbb588ef5438a1 100644 (file)
@@ -775,6 +775,20 @@ func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []
 
 var ddBytes = []byte("--")
 
+// indirect drills into interfaces and pointers, returning the pointed-at value.
+// If it encounters a nil interface or pointer, indirect returns that nil value.
+// This can turn into an infinite loop given a cyclic chain,
+// but it matches the Go 1 behavior.
+func indirect(vf reflect.Value) reflect.Value {
+       for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
+               if vf.IsNil() {
+                       return vf
+               }
+               vf = vf.Elem()
+       }
+       return vf
+}
+
 func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
        s := parentStack{p: p}
        for i := range tinfo.fields {
@@ -816,17 +830,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
                                        continue
                                }
                        }
-                       // Drill into interfaces and pointers.
-                       // This can turn into an infinite loop given a cyclic chain,
-                       // but it matches the Go 1 behavior.
-                       for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
-                               if vf.IsNil() {
-                                       return nil
-                               }
-                               vf = vf.Elem()
-                       }
 
                        var scratch [64]byte
+                       vf = indirect(vf)
                        switch vf.Kind() {
                        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
                                if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil {
@@ -861,6 +867,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
                        if err := s.trim(finfo.parents); err != nil {
                                return err
                        }
+                       vf = indirect(vf)
                        k := vf.Kind()
                        if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
                                return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
@@ -901,6 +908,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
                        continue
 
                case fInnerXml:
+                       vf = indirect(vf)
                        iface := vf.Interface()
                        switch raw := iface.(type) {
                        case []byte:
index d79b99a1e0b7264eaebe05c0fdd439090c5355f1..5ec7ececa4d039331bfec347269bccf2e2b71e31 100644 (file)
@@ -386,6 +386,140 @@ func ifaceptr(x interface{}) interface{} {
        return &x
 }
 
+func stringptr(x string) *string {
+       return &x
+}
+
+type T1 struct{}
+type T2 struct{}
+type T3 struct{}
+
+type IndirComment struct {
+       T1      T1
+       Comment *string `xml:",comment"`
+       T2      T2
+}
+
+type DirectComment struct {
+       T1      T1
+       Comment string `xml:",comment"`
+       T2      T2
+}
+
+type IfaceComment struct {
+       T1      T1
+       Comment interface{} `xml:",comment"`
+       T2      T2
+}
+
+type IndirChardata struct {
+       T1       T1
+       Chardata *string `xml:",chardata"`
+       T2       T2
+}
+
+type DirectChardata struct {
+       T1       T1
+       Chardata string `xml:",chardata"`
+       T2       T2
+}
+
+type IfaceChardata struct {
+       T1       T1
+       Chardata interface{} `xml:",chardata"`
+       T2       T2
+}
+
+type IndirCDATA struct {
+       T1    T1
+       CDATA *string `xml:",cdata"`
+       T2    T2
+}
+
+type DirectCDATA struct {
+       T1    T1
+       CDATA string `xml:",cdata"`
+       T2    T2
+}
+
+type IfaceCDATA struct {
+       T1    T1
+       CDATA interface{} `xml:",cdata"`
+       T2    T2
+}
+
+type IndirInnerXML struct {
+       T1       T1
+       InnerXML *string `xml:",innerxml"`
+       T2       T2
+}
+
+type DirectInnerXML struct {
+       T1       T1
+       InnerXML string `xml:",innerxml"`
+       T2       T2
+}
+
+type IfaceInnerXML struct {
+       T1       T1
+       InnerXML interface{} `xml:",innerxml"`
+       T2       T2
+}
+
+type IndirElement struct {
+       T1      T1
+       Element *string
+       T2      T2
+}
+
+type DirectElement struct {
+       T1      T1
+       Element string
+       T2      T2
+}
+
+type IfaceElement struct {
+       T1      T1
+       Element interface{}
+       T2      T2
+}
+
+type IndirOmitEmpty struct {
+       T1        T1
+       OmitEmpty *string `xml:",omitempty"`
+       T2        T2
+}
+
+type DirectOmitEmpty struct {
+       T1        T1
+       OmitEmpty string `xml:",omitempty"`
+       T2        T2
+}
+
+type IfaceOmitEmpty struct {
+       T1        T1
+       OmitEmpty interface{} `xml:",omitempty"`
+       T2        T2
+}
+
+type IndirAny struct {
+       T1  T1
+       Any *string `xml:",any"`
+       T2  T2
+}
+
+type DirectAny struct {
+       T1  T1
+       Any string `xml:",any"`
+       T2  T2
+}
+
+type IfaceAny struct {
+       T1  T1
+       Any interface{} `xml:",any"`
+       T2  T2
+}
+
 var (
        nameAttr     = "Sarah"
        ageAttr      = uint(12)
@@ -398,10 +532,12 @@ var (
 // please try to make them two-way as well to ensure that
 // marshaling and unmarshaling are as symmetrical as feasible.
 var marshalTests = []struct {
-       Value         interface{}
-       ExpectXML     string
-       MarshalOnly   bool
-       UnmarshalOnly bool
+       Value          interface{}
+       ExpectXML      string
+       MarshalOnly    bool
+       MarshalError   string
+       UnmarshalOnly  bool
+       UnmarshalError string
 }{
        // Test nil marshals to nothing
        {Value: nil, ExpectXML: ``, MarshalOnly: true},
@@ -1133,6 +1269,382 @@ var marshalTests = []struct {
                ExpectXML: `<NestedAndCData><A><B></B><B></B></A><![CDATA[test]]></NestedAndCData>`,
                Value:     &NestedAndCData{AB: make([]string, 2), CDATA: "test"},
        },
+       // Test pointer indirection in various kinds of fields.
+       // https://golang.org/issue/19063
+       {
+               ExpectXML:   `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
+               Value:       &IndirComment{Comment: stringptr("hi")},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:   `<IndirComment><T1></T1><T2></T2></IndirComment>`,
+               Value:       &IndirComment{Comment: stringptr("")},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:    `<IndirComment><T1></T1><T2></T2></IndirComment>`,
+               Value:        &IndirComment{Comment: nil},
+               MarshalError: "xml: bad type for comment field of xml.IndirComment",
+       },
+       {
+               ExpectXML:     `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
+               Value:         &IndirComment{Comment: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:   `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
+               Value:       &IfaceComment{Comment: "hi"},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
+               Value:         &IfaceComment{Comment: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:    `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
+               Value:        &IfaceComment{Comment: nil},
+               MarshalError: "xml: bad type for comment field of xml.IfaceComment",
+       },
+       {
+               ExpectXML:     `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
+               Value:         &IfaceComment{Comment: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<DirectComment><T1></T1><!--hi--><T2></T2></DirectComment>`,
+               Value:     &DirectComment{Comment: string("hi")},
+       },
+       {
+               ExpectXML: `<DirectComment><T1></T1><T2></T2></DirectComment>`,
+               Value:     &DirectComment{Comment: string("")},
+       },
+       {
+               ExpectXML: `<IndirChardata><T1></T1>hi<T2></T2></IndirChardata>`,
+               Value:     &IndirChardata{Chardata: stringptr("hi")},
+       },
+       {
+               ExpectXML:     `<IndirChardata><T1></T1><![CDATA[hi]]><T2></T2></IndirChardata>`,
+               Value:         &IndirChardata{Chardata: stringptr("hi")},
+               UnmarshalOnly: true, // marshals without CDATA
+       },
+       {
+               ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
+               Value:     &IndirChardata{Chardata: stringptr("")},
+       },
+       {
+               ExpectXML:   `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
+               Value:       &IndirChardata{Chardata: nil},
+               MarshalOnly: true, // unmarshal leaves Chardata=stringptr("")
+       },
+       {
+               ExpectXML:      `<IfaceChardata><T1></T1>hi<T2></T2></IfaceChardata>`,
+               Value:          &IfaceChardata{Chardata: string("hi")},
+               UnmarshalError: "cannot unmarshal into interface {}",
+       },
+       {
+               ExpectXML:      `<IfaceChardata><T1></T1><![CDATA[hi]]><T2></T2></IfaceChardata>`,
+               Value:          &IfaceChardata{Chardata: string("hi")},
+               UnmarshalOnly:  true, // marshals without CDATA
+               UnmarshalError: "cannot unmarshal into interface {}",
+       },
+       {
+               ExpectXML:      `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
+               Value:          &IfaceChardata{Chardata: string("")},
+               UnmarshalError: "cannot unmarshal into interface {}",
+       },
+       {
+               ExpectXML:      `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
+               Value:          &IfaceChardata{Chardata: nil},
+               UnmarshalError: "cannot unmarshal into interface {}",
+       },
+       {
+               ExpectXML: `<DirectChardata><T1></T1>hi<T2></T2></DirectChardata>`,
+               Value:     &DirectChardata{Chardata: string("hi")},
+       },
+       {
+               ExpectXML:     `<DirectChardata><T1></T1><![CDATA[hi]]><T2></T2></DirectChardata>`,
+               Value:         &DirectChardata{Chardata: string("hi")},
+               UnmarshalOnly: true, // marshals without CDATA
+       },
+       {
+               ExpectXML: `<DirectChardata><T1></T1><T2></T2></DirectChardata>`,
+               Value:     &DirectChardata{Chardata: string("")},
+       },
+       {
+               ExpectXML: `<IndirCDATA><T1></T1><![CDATA[hi]]><T2></T2></IndirCDATA>`,
+               Value:     &IndirCDATA{CDATA: stringptr("hi")},
+       },
+       {
+               ExpectXML:     `<IndirCDATA><T1></T1>hi<T2></T2></IndirCDATA>`,
+               Value:         &IndirCDATA{CDATA: stringptr("hi")},
+               UnmarshalOnly: true, // marshals with CDATA
+       },
+       {
+               ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
+               Value:     &IndirCDATA{CDATA: stringptr("")},
+       },
+       {
+               ExpectXML:   `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
+               Value:       &IndirCDATA{CDATA: nil},
+               MarshalOnly: true, // unmarshal leaves CDATA=stringptr("")
+       },
+       {
+               ExpectXML:      `<IfaceCDATA><T1></T1><![CDATA[hi]]><T2></T2></IfaceCDATA>`,
+               Value:          &IfaceCDATA{CDATA: string("hi")},
+               UnmarshalError: "cannot unmarshal into interface {}",
+       },
+       {
+               ExpectXML:      `<IfaceCDATA><T1></T1>hi<T2></T2></IfaceCDATA>`,
+               Value:          &IfaceCDATA{CDATA: string("hi")},
+               UnmarshalOnly:  true, // marshals with CDATA
+               UnmarshalError: "cannot unmarshal into interface {}",
+       },
+       {
+               ExpectXML:      `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
+               Value:          &IfaceCDATA{CDATA: string("")},
+               UnmarshalError: "cannot unmarshal into interface {}",
+       },
+       {
+               ExpectXML:      `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
+               Value:          &IfaceCDATA{CDATA: nil},
+               UnmarshalError: "cannot unmarshal into interface {}",
+       },
+       {
+               ExpectXML: `<DirectCDATA><T1></T1><![CDATA[hi]]><T2></T2></DirectCDATA>`,
+               Value:     &DirectCDATA{CDATA: string("hi")},
+       },
+       {
+               ExpectXML:     `<DirectCDATA><T1></T1>hi<T2></T2></DirectCDATA>`,
+               Value:         &DirectCDATA{CDATA: string("hi")},
+               UnmarshalOnly: true, // marshals with CDATA
+       },
+       {
+               ExpectXML: `<DirectCDATA><T1></T1><T2></T2></DirectCDATA>`,
+               Value:     &DirectCDATA{CDATA: string("")},
+       },
+       {
+               ExpectXML:   `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
+               Value:       &IndirInnerXML{InnerXML: stringptr("<hi/>")},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:   `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
+               Value:       &IndirInnerXML{InnerXML: stringptr("")},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
+               Value:     &IndirInnerXML{InnerXML: nil},
+       },
+       {
+               ExpectXML:     `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
+               Value:         &IndirInnerXML{InnerXML: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:   `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
+               Value:       &IfaceInnerXML{InnerXML: "<hi/>"},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
+               Value:         &IfaceInnerXML{InnerXML: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
+               Value:     &IfaceInnerXML{InnerXML: nil},
+       },
+       {
+               ExpectXML:     `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
+               Value:         &IfaceInnerXML{InnerXML: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:   `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
+               Value:       &DirectInnerXML{InnerXML: string("<hi/>")},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
+               Value:         &DirectInnerXML{InnerXML: string("<T1></T1><hi/><T2></T2>")},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:   `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
+               Value:       &DirectInnerXML{InnerXML: string("")},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
+               Value:         &DirectInnerXML{InnerXML: string("<T1></T1><T2></T2>")},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<IndirElement><T1></T1><Element>hi</Element><T2></T2></IndirElement>`,
+               Value:     &IndirElement{Element: stringptr("hi")},
+       },
+       {
+               ExpectXML: `<IndirElement><T1></T1><Element></Element><T2></T2></IndirElement>`,
+               Value:     &IndirElement{Element: stringptr("")},
+       },
+       {
+               ExpectXML: `<IndirElement><T1></T1><T2></T2></IndirElement>`,
+               Value:     &IndirElement{Element: nil},
+       },
+       {
+               ExpectXML:   `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
+               Value:       &IfaceElement{Element: "hi"},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
+               Value:         &IfaceElement{Element: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
+               Value:     &IfaceElement{Element: nil},
+       },
+       {
+               ExpectXML:     `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
+               Value:         &IfaceElement{Element: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<DirectElement><T1></T1><Element>hi</Element><T2></T2></DirectElement>`,
+               Value:     &DirectElement{Element: string("hi")},
+       },
+       {
+               ExpectXML: `<DirectElement><T1></T1><Element></Element><T2></T2></DirectElement>`,
+               Value:     &DirectElement{Element: string("")},
+       },
+       {
+               ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IndirOmitEmpty>`,
+               Value:     &IndirOmitEmpty{OmitEmpty: stringptr("hi")},
+       },
+       {
+               // Note: Changed in Go 1.8 to include <OmitEmpty> element (because x.OmitEmpty != nil).
+               ExpectXML:   `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
+               Value:       &IndirOmitEmpty{OmitEmpty: stringptr("")},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
+               Value:         &IndirOmitEmpty{OmitEmpty: stringptr("")},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<IndirOmitEmpty><T1></T1><T2></T2></IndirOmitEmpty>`,
+               Value:     &IndirOmitEmpty{OmitEmpty: nil},
+       },
+       {
+               ExpectXML:   `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
+               Value:       &IfaceOmitEmpty{OmitEmpty: "hi"},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
+               Value:         &IfaceOmitEmpty{OmitEmpty: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
+               Value:     &IfaceOmitEmpty{OmitEmpty: nil},
+       },
+       {
+               ExpectXML:     `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
+               Value:         &IfaceOmitEmpty{OmitEmpty: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<DirectOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></DirectOmitEmpty>`,
+               Value:     &DirectOmitEmpty{OmitEmpty: string("hi")},
+       },
+       {
+               ExpectXML: `<DirectOmitEmpty><T1></T1><T2></T2></DirectOmitEmpty>`,
+               Value:     &DirectOmitEmpty{OmitEmpty: string("")},
+       },
+       {
+               ExpectXML: `<IndirAny><T1></T1><Any>hi</Any><T2></T2></IndirAny>`,
+               Value:     &IndirAny{Any: stringptr("hi")},
+       },
+       {
+               ExpectXML: `<IndirAny><T1></T1><Any></Any><T2></T2></IndirAny>`,
+               Value:     &IndirAny{Any: stringptr("")},
+       },
+       {
+               ExpectXML: `<IndirAny><T1></T1><T2></T2></IndirAny>`,
+               Value:     &IndirAny{Any: nil},
+       },
+       {
+               ExpectXML:   `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
+               Value:       &IfaceAny{Any: "hi"},
+               MarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
+               Value:         &IfaceAny{Any: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
+               Value:     &IfaceAny{Any: nil},
+       },
+       {
+               ExpectXML:     `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
+               Value:         &IfaceAny{Any: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML: `<DirectAny><T1></T1><Any>hi</Any><T2></T2></DirectAny>`,
+               Value:     &DirectAny{Any: string("hi")},
+       },
+       {
+               ExpectXML: `<DirectAny><T1></T1><Any></Any><T2></T2></DirectAny>`,
+               Value:     &DirectAny{Any: string("")},
+       },
+       {
+               ExpectXML:     `<IndirFoo><T1></T1><Foo>hi</Foo><T2></T2></IndirFoo>`,
+               Value:         &IndirAny{Any: stringptr("hi")},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IndirFoo><T1></T1><Foo></Foo><T2></T2></IndirFoo>`,
+               Value:         &IndirAny{Any: stringptr("")},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IndirFoo><T1></T1><T2></T2></IndirFoo>`,
+               Value:         &IndirAny{Any: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IfaceFoo><T1></T1><Foo>hi</Foo><T2></T2></IfaceFoo>`,
+               Value:         &IfaceAny{Any: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
+               Value:         &IfaceAny{Any: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
+               Value:         &IfaceAny{Any: nil},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<DirectFoo><T1></T1><Foo>hi</Foo><T2></T2></DirectFoo>`,
+               Value:         &DirectAny{Any: string("hi")},
+               UnmarshalOnly: true,
+       },
+       {
+               ExpectXML:     `<DirectFoo><T1></T1><Foo></Foo><T2></T2></DirectFoo>`,
+               Value:         &DirectAny{Any: string("")},
+               UnmarshalOnly: true,
+       },
 }
 
 func TestMarshal(t *testing.T) {
@@ -1142,7 +1654,17 @@ func TestMarshal(t *testing.T) {
                }
                data, err := Marshal(test.Value)
                if err != nil {
-                       t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
+                       if test.MarshalError == "" {
+                               t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
+                               continue
+                       }
+                       if !strings.Contains(err.Error(), test.MarshalError) {
+                               t.Errorf("#%d: marshal(%#v): %s, want %q", idx, test.Value, err, test.MarshalError)
+                       }
+                       continue
+               }
+               if test.MarshalError != "" {
+                       t.Errorf("#%d: Marshal succeeded, want error %q", idx, test.MarshalError)
                        continue
                }
                if got, want := string(data), test.ExpectXML; got != want {
@@ -1268,8 +1790,16 @@ func TestUnmarshal(t *testing.T) {
                }
 
                if err != nil {
-                       t.Errorf("#%d: unexpected error: %#v", i, err)
-               } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
+                       if test.UnmarshalError == "" {
+                               t.Errorf("#%d: unmarshal(%#v): %s", i, test.ExpectXML, err)
+                               continue
+                       }
+                       if !strings.Contains(err.Error(), test.UnmarshalError) {
+                               t.Errorf("#%d: unmarshal(%#v): %s, want %q", i, test.ExpectXML, err, test.UnmarshalError)
+                       }
+                       continue
+               }
+               if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
                        t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
                }
        }
index cb053ebbed27345ea6d277fa2c3ebe3c2ab734ca..4e1b29fecd997b518cee8a57905e2d7a31f2bd07 100644 (file)
@@ -266,7 +266,7 @@ func defaultGOPATH() string {
        }
        if home := os.Getenv(env); home != "" {
                def := filepath.Join(home, "go")
-               if def == runtime.GOROOT() {
+               if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
                        // Don't set the default GOPATH to GOROOT,
                        // as that will trigger warnings from the go tool.
                        return ""
index 6b143df00e11604a07d7ef723196cffeb3c17cef..859de7c86706c0bae9ad5e27adc10df1394f7fe3 100644 (file)
@@ -2481,17 +2481,24 @@ func TestNumMethodOnDDD(t *testing.T) {
 }
 
 func TestPtrTo(t *testing.T) {
+       // This block of code means that the ptrToThis field of the
+       // reflect data for *unsafe.Pointer is non zero, see
+       // https://golang.org/issue/19003
+       var x unsafe.Pointer
+       var y = &x
+       var z = &y
+
        var i int
 
-       typ := TypeOf(i)
+       typ := TypeOf(z)
        for i = 0; i < 100; i++ {
                typ = PtrTo(typ)
        }
        for i = 0; i < 100; i++ {
                typ = typ.Elem()
        }
-       if typ != TypeOf(i) {
-               t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(i))
+       if typ != TypeOf(z) {
+               t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(z))
        }
 }
 
index 29d89f7176d6501e45d9a002dcd75ba945905127..0325260455682a88ee2c1ea8d54fcb41e516babc 100644 (file)
@@ -1174,6 +1174,7 @@ func (t *rtype) ptrTo() *rtype {
        pp := *prototype
 
        pp.string = &s
+       pp.ptrToThis = nil
 
        // For the type structures linked into the binary, the
        // compiler provides a good hash of the string.
index 44afb91d96f1a252f3f87f1771200697c008f110..3da82961b9b74a21d5fe6da480e55d38a91180bf 100644 (file)
@@ -61,7 +61,7 @@ static void* cpuHogDriver(void* arg __attribute__ ((unused))) {
        return 0;
 }
 
-void runCPUHogThread() {
+void runCPUHogThread(void) {
        pthread_t tid;
        pthread_create(&tid, 0, cpuHogDriver, 0);
 }
index e8b0a04556a0f135f22e8ac9597d2fb96930101f..2a023f66caeb74f49933e2f9111b20beac3faa69 100644 (file)
@@ -15,16 +15,16 @@ package main
 
 char *p;
 
-static int f3() {
+static int f3(void) {
        *p = 0;
        return 0;
 }
 
-static int f2() {
+static int f2(void) {
        return f3();
 }
 
-static int f1() {
+static int f1(void) {
        return f2();
 }
 
index bbeb95692a1dd3d81bd331710a56cd39f0a21139..b002aa0bf10a850ce702413b4a49db145c9939c3 100644 (file)
@@ -821,6 +821,7 @@ func (m *M) Run() int {
        haveExamples = len(m.examples) > 0
        testRan, testOk := runTests(m.deps.MatchString, m.tests)
        exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
+       stopAlarm()
        if !testRan && !exampleRan && *matchBenchmarks == "" {
                fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
        }
index cce2e95ac289307dcf78366f6aa960e976cd5473..3a97ee1d4adc5b65195ce9d2e191e003e07ee475 100644 (file)
@@ -85,6 +85,12 @@ static const String preflection_string =
   sizeof PREFLECTION - 1,
 };
 
+extern const uintptr pointer_unsafe_Pointer_gc[]
+  __asm__ (GOSYM_PREFIX "__go_td_pN14_unsafe.Pointer$gc");
+
+const uintptr pointer_unsafe_Pointer_gc[] __attribute__((aligned(4))) =
+  {sizeof(void*), GC_APTR, 0, GC_END};
+
 const struct __go_ptr_type pointer_unsafe_Pointer =
 {
   /* __common */
@@ -104,7 +110,7 @@ const struct __go_ptr_type pointer_unsafe_Pointer =
     /* __equalfn */
     &runtime_pointerequal_descriptor,
     /* __gc */
-    unsafe_Pointer_gc,
+    pointer_unsafe_Pointer_gc,
     /* __reflection */
     &preflection_string,
     /* __uncommon */