libgo: update to Go1.13
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 12 Sep 2019 23:22:53 +0000 (23:22 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 12 Sep 2019 23:22:53 +0000 (23:22 +0000)
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/194698

From-SVN: r275691

206 files changed:
gcc/go/gofrontend/MERGE
libgo/MERGE
libgo/Makefile.am
libgo/Makefile.in
libgo/VERSION
libgo/check-packages.txt
libgo/go/cmd/cgo/gcc.go
libgo/go/cmd/cgo/out.go
libgo/go/cmd/go/alldocs.go
libgo/go/cmd/go/go_test.go
libgo/go/cmd/go/internal/cache/cache.go
libgo/go/cmd/go/internal/cfg/cfg.go
libgo/go/cmd/go/internal/get/vcs.go
libgo/go/cmd/go/internal/help/help.go
libgo/go/cmd/go/internal/help/helpdoc.go
libgo/go/cmd/go/internal/list/list.go
libgo/go/cmd/go/internal/load/pkg.go
libgo/go/cmd/go/internal/load/test.go
libgo/go/cmd/go/internal/modcmd/download.go
libgo/go/cmd/go/internal/modfetch/codehost/vcs.go
libgo/go/cmd/go/internal/modfetch/coderepo.go
libgo/go/cmd/go/internal/modfetch/coderepo_test.go
libgo/go/cmd/go/internal/modfetch/fetch.go
libgo/go/cmd/go/internal/modfetch/proxy.go
libgo/go/cmd/go/internal/modfetch/repo.go
libgo/go/cmd/go/internal/modfetch/sumdb.go
libgo/go/cmd/go/internal/modget/get.go
libgo/go/cmd/go/internal/modload/build.go
libgo/go/cmd/go/internal/modload/help.go
libgo/go/cmd/go/internal/modload/import.go
libgo/go/cmd/go/internal/modload/list.go
libgo/go/cmd/go/internal/modload/load.go
libgo/go/cmd/go/internal/modload/query.go
libgo/go/cmd/go/internal/modload/query_test.go
libgo/go/cmd/go/internal/mvs/mvs.go
libgo/go/cmd/go/internal/mvs/mvs_test.go
libgo/go/cmd/go/internal/test/test.go
libgo/go/cmd/go/internal/version/exe.go
libgo/go/cmd/go/internal/work/build.go
libgo/go/cmd/go/internal/work/buildid.go
libgo/go/cmd/go/internal/work/exec.go
libgo/go/cmd/go/testdata/flag_test.go
libgo/go/cmd/go/testdata/mod/example.com_badchain_c_v1.1.0.txt
libgo/go/cmd/go/testdata/script/build_cache_output.txt
libgo/go/cmd/go/testdata/script/cmd_import_error.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_doc.txt
libgo/go/cmd/go/testdata/script/mod_dot.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_download.txt
libgo/go/cmd/go/testdata/script/mod_download_latest.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt
libgo/go/cmd/go/testdata/script/mod_get_fallback.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_get_main.txt
libgo/go/cmd/go/testdata/script/mod_get_newcycle.txt
libgo/go/cmd/go/testdata/script/mod_get_patterns.txt
libgo/go/cmd/go/testdata/script/mod_get_svn.txt
libgo/go/cmd/go/testdata/script/mod_get_upgrade_pseudo.txt
libgo/go/cmd/go/testdata/script/mod_gobuild_import.txt
libgo/go/cmd/go/testdata/script/mod_indirect.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_indirect_main.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_indirect_tidy.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_invalid_version.txt
libgo/go/cmd/go/testdata/script/mod_list.txt
libgo/go/cmd/go/testdata/script/mod_list_compiled_concurrent.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_list_dir.txt
libgo/go/cmd/go/testdata/script/mod_list_direct.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_list_replace_dir.txt
libgo/go/cmd/go/testdata/script/mod_list_upgrade.txt
libgo/go/cmd/go/testdata/script/mod_load_badchain.txt
libgo/go/cmd/go/testdata/script/mod_query.txt
libgo/go/cmd/go/testdata/script/mod_query_empty.txt
libgo/go/cmd/go/testdata/script/mod_sumdb.txt
libgo/go/cmd/go/testdata/script/mod_sumdb_cache.txt
libgo/go/cmd/go/testdata/script/mod_sumdb_file_path.txt
libgo/go/cmd/go/testdata/script/mod_sumdb_golang.txt
libgo/go/cmd/go/testdata/script/mod_sumdb_proxy.txt
libgo/go/cmd/go/testdata/script/mod_test_cached.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_tidy_error.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/mod_vendor.txt
libgo/go/cmd/go/testdata/script/test_go111module_cache.txt [new file with mode: 0644]
libgo/go/cmd/go/testdata/script/test_init.txt [deleted file]
libgo/go/cmd/go/testdata/script/version.txt
libgo/go/cmd/go/testdata/standalone_testmain_flag_test.go [new file with mode: 0644]
libgo/go/cmd/gofmt/testdata/go2numbers.golden [new file with mode: 0644]
libgo/go/cmd/gofmt/testdata/go2numbers.input [new file with mode: 0644]
libgo/go/cmd/gofmt/testdata/import.golden
libgo/go/cmd/gofmt/testdata/import.input
libgo/go/cmd/gofmt/testdata/rewrite9.golden [new file with mode: 0644]
libgo/go/cmd/gofmt/testdata/rewrite9.input [new file with mode: 0644]
libgo/go/cmd/gofmt/testdata/typealias.golden [new file with mode: 0644]
libgo/go/cmd/gofmt/testdata/typealias.input [new file with mode: 0644]
libgo/go/cmd/internal/objabi/flag.go
libgo/go/context/context.go
libgo/go/context/context_test.go
libgo/go/crypto/rsa/rsa.go
libgo/go/crypto/tls/common.go
libgo/go/crypto/tls/handshake_server_test.go
libgo/go/crypto/tls/handshake_test.go
libgo/go/crypto/tls/tls_test.go
libgo/go/debug/elf/file.go
libgo/go/debug/elf/symbols_test.go
libgo/go/encoding/csv/writer.go
libgo/go/encoding/json/decode.go
libgo/go/encoding/json/decode_test.go
libgo/go/encoding/json/encode.go
libgo/go/encoding/json/fuzz.go
libgo/go/encoding/json/indent.go
libgo/go/encoding/json/stream_test.go
libgo/go/errors/errors.go
libgo/go/errors/wrap.go
libgo/go/expvar/expvar.go
libgo/go/fmt/errors.go
libgo/go/fmt/scan.go
libgo/go/go/ast/import.go
libgo/go/go/build/build.go
libgo/go/go/build/deps_test.go
libgo/go/go/build/doc.go
libgo/go/go/doc/testdata/issue10858.go [deleted file]
libgo/go/go/importer/importer.go
libgo/go/go/parser/parser.go
libgo/go/go/types/scope.go
libgo/go/go/types/typestring.go
libgo/go/golang.org/x/net/route/zsys_darwin.go
libgo/go/golang.org/x/net/route/zsys_dragonfly.go
libgo/go/golang.org/x/net/route/zsys_freebsd_386.go
libgo/go/golang.org/x/net/route/zsys_freebsd_amd64.go
libgo/go/golang.org/x/net/route/zsys_freebsd_arm.go
libgo/go/golang.org/x/net/route/zsys_netbsd.go
libgo/go/golang.org/x/net/route/zsys_openbsd.go
libgo/go/internal/cfg/cfg.go [new file with mode: 0644]
libgo/go/internal/oserror/errors.go
libgo/go/internal/oserror/errors_test.go [deleted file]
libgo/go/internal/poll/fd.go
libgo/go/internal/testenv/testenv.go
libgo/go/net/cgo_unix.go
libgo/go/net/http/example_test.go
libgo/go/net/http/export_test.go
libgo/go/net/http/h2_bundle.go
libgo/go/net/http/header.go
libgo/go/net/http/header_test.go
libgo/go/net/http/httputil/reverseproxy.go
libgo/go/net/http/httputil/reverseproxy_test.go
libgo/go/net/http/request.go
libgo/go/net/http/response.go
libgo/go/net/http/serve_test.go
libgo/go/net/http/server.go
libgo/go/net/http/socks_bundle.go
libgo/go/net/http/transport.go
libgo/go/net/http/transport_test.go
libgo/go/net/ip.go
libgo/go/net/mail/message.go
libgo/go/net/net.go
libgo/go/net/net_test.go
libgo/go/net/pipe.go
libgo/go/net/timeout_test.go
libgo/go/net/url/url.go
libgo/go/net/url/url_test.go
libgo/go/os/dir.go
libgo/go/os/error.go
libgo/go/os/error_errno.go [new file with mode: 0644]
libgo/go/os/error_plan9.go [new file with mode: 0644]
libgo/go/os/error_test.go
libgo/go/os/file.go
libgo/go/os/os_test.go
libgo/go/os/removeall_at.go
libgo/go/os/signal/signal_cgo_test.go
libgo/go/path/path_test.go
libgo/go/reflect/all_test.go
libgo/go/runtime/cpuprof.go
libgo/go/runtime/export_test.go
libgo/go/runtime/malloc.go
libgo/go/runtime/mcache.go
libgo/go/runtime/mgcscavenge.go
libgo/go/runtime/mheap.go
libgo/go/runtime/panic.go
libgo/go/runtime/pprof/runtime.go
libgo/go/runtime/proc.go
libgo/go/runtime/proc_test.go
libgo/go/runtime/sigqueue.go
libgo/go/runtime/sigqueue_note.go [new file with mode: 0644]
libgo/go/strconv/atof.go
libgo/go/strconv/atoi.go
libgo/go/strings/example_test.go
libgo/go/strings/replace.go
libgo/go/strings/strings.go
libgo/go/sync/export_test.go
libgo/go/sync/once.go
libgo/go/sync/pool_test.go
libgo/go/syscall/exec_bsd.go
libgo/go/syscall/exec_darwin.go
libgo/go/syscall/exec_linux.go
libgo/go/syscall/syscall_errno.go
libgo/go/syscall/syscall_freebsd.go
libgo/go/syscall/syscall_js.go
libgo/go/testing/testing.go
libgo/go/text/scanner/scanner.go
libgo/go/text/scanner/scanner_test.go
libgo/go/time/sleep.go
libgo/go/time/time.go
libgo/go/time/time_test.go
libgo/libgo-packages.txt
libgo/misc/cgo/errors/errors_test.go
libgo/misc/cgo/errors/ptr_test.go
libgo/misc/cgo/errors/testdata/issue33061.go [new file with mode: 0644]
libgo/misc/cgo/testshared/shared_test.go
libgo/misc/cgo/testshared/testdata/issue30768/issue30768lib/lib.go [new file with mode: 0644]
libgo/misc/cgo/testshared/testdata/issue30768/x_test.go [new file with mode: 0644]

index 8098eb047dae5d7849c2458a63dca7b00b03cfaf..f950ecdb0e32505b05a96b0c8982f569573d93b4 100644 (file)
@@ -1,4 +1,4 @@
-0950e905939f88c1421f8667ac4dc9e14528471c
+ceb1e4f5614b4772eed44f9cf57780e52f44753e
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 533c99da98483052171040c22b2ef7a3cc76d59e..0be22963bb808acf31bc8e6036f07baa7b546740 100644 (file)
@@ -1,4 +1,4 @@
-60f14fddfee107dedd76c0be6b422a3d8ccc841a
+cc8838d645b2b7026c1f3aaceb011775c5ca3a08
 
 The first line of this file holds the git revision number of the
 last merge done from the master library sources.
index b46f920d8eef9ce62156318e9a71be96fe736366..1192b4497819c6b814922741132c921cf5a330ab 100644 (file)
@@ -401,6 +401,7 @@ toolexeclibgounicode_DATA = \
 # Force them to be built.
 noinst_DATA = \
        golang.org/x/net/nettest.gox \
+       internal/cfg.gox \
        internal/testenv.gox \
        internal/trace.gox \
        net/internal/socktest.gox \
index eeec5fc7c983b98dca4e5e0d0f6bd02b87f16cce..89cccaccdf9762b1b8d324d6fdefb1d303f64435 100644 (file)
@@ -856,10 +856,10 @@ toolexeclibgounicode_DATA = \
 # Some packages are only needed for tests, so unlike the other
 # internal packages nothing will explicitly depend on them.
 # Force them to be built.
-noinst_DATA = golang.org/x/net/nettest.gox internal/testenv.gox \
-       internal/trace.gox net/internal/socktest.gox \
-       os/signal/internal/pty.gox runtime/pprof/internal/profile.gox \
-       zdefaultcc.go
+noinst_DATA = golang.org/x/net/nettest.gox internal/cfg.gox \
+       internal/testenv.gox internal/trace.gox \
+       net/internal/socktest.gox os/signal/internal/pty.gox \
+       runtime/pprof/internal/profile.gox zdefaultcc.go
 @LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file = 
 @LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
 runtime_files = \
index a49377394febbccc7622f9baadcf636ae37747e9..e0f726521a465416f368e95eb7bc9436e04ce382 100644 (file)
@@ -1 +1 @@
-go1.13beta1
+go1.13
index a13624303dde9fb5d03473b94800508aa9e139e0..156a2bd4593243d6934d9a0d89b488da09652aec 100644 (file)
@@ -106,7 +106,6 @@ image/png
 index/suffixarray
 internal/cpu
 internal/fmtsort
-internal/oserror
 internal/poll
 internal/reflectlite
 internal/singleflight
index 70be6dc9a921f26ecbbaeedfefd9552cd7e59880..526d4c2bddfb8e75f85da1161b32846915ab07d5 100644 (file)
@@ -811,10 +811,10 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
        params := name.FuncType.Params
        args := call.Call.Args
 
-       // Avoid a crash if the number of arguments is
-       // less than the number of parameters.
+       // Avoid a crash if the number of arguments doesn't match
+       // the number of parameters.
        // This will be caught when the generated file is compiled.
-       if len(args) < len(params) {
+       if len(args) != len(params) {
                return "", false
        }
 
@@ -1257,6 +1257,8 @@ func (p *Package) isType(t ast.Expr) bool {
                if strings.HasPrefix(t.Name, "_Ctype_") {
                        return true
                }
+       case *ast.ParenExpr:
+               return p.isType(t.X)
        case *ast.StarExpr:
                return p.isType(t.X)
        case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,
index 77e9108dd23061343c30463117956522571f559f..7282933e3c5be8da3d0d67cc1ed629546e6986ca 100644 (file)
@@ -273,6 +273,35 @@ func (p *Package) writeDefs() {
        }
 }
 
+// elfImportedSymbols is like elf.File.ImportedSymbols, but it
+// includes weak symbols.
+//
+// A bug in some versions of LLD (at least LLD 8) cause it to emit
+// several pthreads symbols as weak, but we need to import those. See
+// issue #31912 or https://bugs.llvm.org/show_bug.cgi?id=42442.
+//
+// When doing external linking, we hand everything off to the external
+// linker, which will create its own dynamic symbol tables. For
+// internal linking, this may turn weak imports into strong imports,
+// which could cause dynamic linking to fail if a symbol really isn't
+// defined. However, the standard library depends on everything it
+// imports, and this is the primary use of dynamic symbol tables with
+// internal linking.
+func elfImportedSymbols(f *elf.File) []elf.ImportedSymbol {
+       syms, _ := f.DynamicSymbols()
+       var imports []elf.ImportedSymbol
+       for _, s := range syms {
+               if (elf.ST_BIND(s.Info) == elf.STB_GLOBAL || elf.ST_BIND(s.Info) == elf.STB_WEAK) && s.Section == elf.SHN_UNDEF {
+                       imports = append(imports, elf.ImportedSymbol{
+                               Name:    s.Name,
+                               Library: s.Library,
+                               Version: s.Version,
+                       })
+               }
+       }
+       return imports
+}
+
 func dynimport(obj string) {
        stdout := os.Stdout
        if *dynout != "" {
@@ -295,7 +324,7 @@ func dynimport(obj string) {
                                }
                        }
                }
-               sym, _ := f.ImportedSymbols()
+               sym := elfImportedSymbols(f)
                for _, s := range sym {
                        targ := s.Name
                        if s.Version != "" {
index fa60fb63b57cb1e2954a2c8a3b7154c41d4e9243..ebbead5d3169a53fe97df56cfaa096c0a7d31abd 100644 (file)
@@ -78,6 +78,8 @@
 // If the arguments to build are a list of .go files from a single directory,
 // build treats them as a list of source files specifying a single package.
 //
+// When compiling packages, build ignores files that end in '_test.go'.
+//
 // When compiling a single main package, build writes
 // the resulting executable to an output file named after
 // the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
@@ -88,8 +90,6 @@
 // build compiles the packages but discards the resulting object,
 // serving only as a check that the packages can be built.
 //
-// When compiling packages, build ignores files that end in '_test.go'.
-//
 // The -o flag forces build to write the resulting executable or object
 // to the named output file or directory, instead of the default behavior described
 // in the last two paragraphs. If the named output is a directory that exists,
 // The first step is to resolve which dependencies to add.
 //
 // For each named package or package pattern, get must decide which version of
-// the corresponding module to use. By default, get chooses the latest tagged
+// the corresponding module to use. By default, get looks up the latest tagged
 // release version, such as v0.4.5 or v1.2.3. If there are no tagged release
-// versions, get chooses the latest tagged pre-release version, such as
-// v0.0.1-pre1. If there are no tagged versions at all, get chooses the latest
-// known commit.
+// versions, get looks up the latest tagged pre-release version, such as
+// v0.0.1-pre1. If there are no tagged versions at all, get looks up the latest
+// known commit. If the module is not already required at a later version
+// (for example, a pre-release newer than the latest release), get will use
+// the version it looked up. Otherwise, get will use the currently
+// required version.
 //
 // This default version selection can be overridden by adding an @version
 // suffix to the package argument, as in 'go get golang.org/x/text@v0.3.0'.
+// The version may be a prefix: @v1 denotes the latest available version starting
+// with v1. See 'go help modules' under the heading 'Module queries' for the
+// full query syntax.
+//
 // For modules stored in source control repositories, the version suffix can
 // also be a commit hash, branch identifier, or other syntax known to the
-// source control system, as in 'go get golang.org/x/text@master'.
+// source control system, as in 'go get golang.org/x/text@master'. Note that
+// branches with names that overlap with other module query syntax cannot be
+// selected explicitly. For example, the suffix @v2 means the latest version
+// starting with v2, not the branch named v2.
 //
 // If a module under consideration is already a dependency of the current
 // development module, then get will update the required version.
 // depending on it as needed.
 //
 // The version suffix @latest explicitly requests the latest minor release of the
-// given path. The suffix @patch requests the latest patch release: if the path
-// is already in the build list, the selected version will have the same minor
-// version. If the path is not already in the build list, @patch is equivalent
-// to @latest. Neither @latest nor @patch will cause 'go get' to downgrade a module
-// in the build list if it is required at a newer pre-release version that is
-// newer than the latest released version.
+// module named by the given path. The suffix @upgrade is like @latest but
+// will not downgrade a module if it is already required at a revision or
+// pre-release version newer than the latest released version. The suffix
+// @patch requests the latest patch release: the latest released version
+// with the same major and minor version numbers as the currently required
+// version. Like @upgrade, @patch will not downgrade a module already required
+// at a newer version. If the path is not already required, @upgrade and @patch
+// are equivalent to @latest.
 //
 // Although get defaults to using the latest version of the module containing
 // a named package, it does not use the latest version of that module's
 //         Dir      string // absolute path to cached source root directory
 //         Sum      string // checksum for path, version (as in go.sum)
 //         GoModSum string // checksum for go.mod (as in go.sum)
+//         Latest   bool   // would @latest resolve to this version?
 //     }
 //
 // See 'go help modules' for more about module queries.
 //     GOCACHE
 //             The directory where the go command will store cached
 //             information for reuse in future builds.
+//     GODEBUG
+//             Enable various debugging facilities. See 'go doc runtime'
+//             for details.
 //     GOENV
 //             The location of the Go environment configuration file.
 //             Cannot be set using 'go env -w'.
 // The string "latest" matches the latest available tagged version,
 // or else the underlying source repository's latest untagged revision.
 //
-// A revision identifier for the underlying source repository,
-// such as a commit hash prefix, revision tag, or branch name,
-// selects that specific code revision. If the revision is
-// also tagged with a semantic version, the query evaluates to
-// that semantic version. Otherwise the query evaluates to a
-// pseudo-version for the commit.
+// The string "upgrade" is like "latest", but if the module is
+// currently required at a later version than the version "latest"
+// would select (for example, a newer pre-release version), "upgrade"
+// will select the later version instead.
+//
+// The string "patch" matches the latest available tagged version
+// of a module with the same major and minor version numbers as the
+// currently required version. If no version is currently required,
+// "patch" is equivalent to "latest".
+//
+// A revision identifier for the underlying source repository, such as
+// a commit hash prefix, revision tag, or branch name, selects that
+// specific code revision. If the revision is also tagged with a
+// semantic version, the query evaluates to that semantic version.
+// Otherwise the query evaluates to a pseudo-version for the commit.
+// Note that branches and tags with names that are matched by other
+// query syntax cannot be selected this way. For example, the query
+// "v2" means the latest version starting with "v2", not the branch
+// named "v2".
 //
 // All queries prefer release versions to pre-release versions.
 // For example, "<v1.2.3" will prefer to return "v1.2.2"
 //     GOSUMDB="sum.golang.org+<publickey>"
 //     GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"
 //
-// The go command knows the public key of sum.golang.org; use of any other
-// database requires giving the public key explicitly. The URL defaults to
-// "https://" followed by the database name.
+// The go command knows the public key of sum.golang.org, and also that the name
+// sum.golang.google.cn (available inside mainland China) connects to the
+// sum.golang.org checksum database; use of any other database requires giving
+// the public key explicitly.
+// The URL defaults to "https://" followed by the database name.
 //
 // GOSUMDB defaults to "sum.golang.org", the Go checksum database run by Google.
 // See https://sum.golang.org/privacy for the service's privacy policy.
index 0ae2fa297eb02a34fe64a42c64063c33db538685..f936d703c078a8ce2929252b910159c78e4f78b9 100644 (file)
@@ -3177,6 +3177,12 @@ func TestGoTestFooTestWorks(t *testing.T) {
        tg.run("test", "testdata/standalone_test.go")
 }
 
+func TestGoTestTestMainSeesTestingFlags(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.run("test", "testdata/standalone_testmain_flag_test.go")
+}
+
 // Issue 22388
 func TestGoTestMainWithWrongSignature(t *testing.T) {
        tg := testgo(t)
index 116279c977d466041b4da1014d23e64e359b7e40..a05a08f75fcc3f0627f6a3357b929a30700a13f4 100644 (file)
@@ -173,7 +173,7 @@ func (c *Cache) get(id ActionID) (Entry, error) {
                i++
        }
        tm, err := strconv.ParseInt(string(etime[i:]), 10, 64)
-       if err != nil || size < 0 {
+       if err != nil || tm < 0 {
                return missing()
        }
 
@@ -322,7 +322,7 @@ func (c *Cache) putIndexEntry(id ActionID, out OutputID, size int64, allowVerify
        // in verify mode we are double-checking that the cache entries
        // are entirely reproducible. As just noted, this may be unrealistic
        // in some cases but the check is also useful for shaking out real bugs.
-       entry := []byte(fmt.Sprintf("v1 %x %x %20d %20d\n", id, out, size, time.Now().UnixNano()))
+       entry := fmt.Sprintf("v1 %x %x %20d %20d\n", id, out, size, time.Now().UnixNano())
        if verify && allowVerify {
                old, err := c.get(id)
                if err == nil && (old.OutputID != out || old.Size != size) {
@@ -332,7 +332,28 @@ func (c *Cache) putIndexEntry(id ActionID, out OutputID, size int64, allowVerify
                }
        }
        file := c.fileName(id, "a")
-       if err := ioutil.WriteFile(file, entry, 0666); err != nil {
+
+       // Copy file to cache directory.
+       mode := os.O_WRONLY | os.O_CREATE
+       f, err := os.OpenFile(file, mode, 0666)
+       if err != nil {
+               return err
+       }
+       _, err = f.WriteString(entry)
+       if err == nil {
+               // Truncate the file only *after* writing it.
+               // (This should be a no-op, but truncate just in case of previous corruption.)
+               //
+               // This differs from ioutil.WriteFile, which truncates to 0 *before* writing
+               // via os.O_TRUNC. Truncating only after writing ensures that a second write
+               // of the same content to the same file is idempotent, and does not — even
+               // temporarily! — undo the effect of the first write.
+               err = f.Truncate(int64(len(entry)))
+       }
+       if closeErr := f.Close(); err == nil {
+               err = closeErr
+       }
+       if err != nil {
                // TODO(bcmills): This Remove potentially races with another go command writing to file.
                // Can we eliminate it?
                os.Remove(file)
index a0b51a72c33d12cdcd5c3b8f7de5c82f8bb37233..a3277a6c3f0ac12019ba8139d0ce89f4e3994547 100644 (file)
@@ -10,6 +10,7 @@ import (
        "bytes"
        "fmt"
        "go/build"
+       "internal/cfg"
        "io/ioutil"
        "os"
        "path/filepath"
@@ -221,61 +222,9 @@ func Getenv(key string) string {
 
 // CanGetenv reports whether key is a valid go/env configuration key.
 func CanGetenv(key string) bool {
-       return strings.Contains(knownEnv, "\t"+key+"\n")
+       return strings.Contains(cfg.KnownEnv, "\t"+key+"\n")
 }
 
-var knownEnv = `
-       AR
-       CC
-       CGO_CFLAGS
-       CGO_CFLAGS_ALLOW
-       CGO_CFLAGS_DISALLOW
-       CGO_CPPFLAGS
-       CGO_CPPFLAGS_ALLOW
-       CGO_CPPFLAGS_DISALLOW
-       CGO_CXXFLAGS
-       CGO_CXXFLAGS_ALLOW
-       CGO_CXXFLAGS_DISALLOW
-       CGO_ENABLED
-       CGO_FFLAGS
-       CGO_FFLAGS_ALLOW
-       CGO_FFLAGS_DISALLOW
-       CGO_LDFLAGS
-       CGO_LDFLAGS_ALLOW
-       CGO_LDFLAGS_DISALLOW
-       CXX
-       FC
-       GCCGO
-       GO111MODULE
-       GO386
-       GOARCH
-       GOARM
-       GOBIN
-       GOCACHE
-       GOENV
-       GOEXE
-       GOFLAGS
-       GOGCCFLAGS
-       GOHOSTARCH
-       GOHOSTOS
-       GOMIPS
-       GOMIPS64
-       GONOPROXY
-       GONOSUMDB
-       GOOS
-       GOPATH
-       GOPPC64
-       GOPRIVATE
-       GOPROXY
-       GOROOT
-       GOSUMDB
-       GOTMPDIR
-       GOTOOLDIR
-       GOWASM
-       GO_EXTLINK_ENABLED
-       PKG_CONFIG
-`
-
 var (
        GOROOT       = BuildContext.GOROOT
        GOBIN        = Getenv("GOBIN")
index fca78b515fd8ecb829f00b1edd818ca5e5fca7a7..705bb66dbe2142ce95d9608cc3281478a66f557e 100644 (file)
@@ -164,8 +164,14 @@ var vcsGit = &vcsCmd{
        // See golang.org/issue/9032.
        tagSyncDefault: []string{"submodule update --init --recursive"},
 
-       scheme:     []string{"git", "https", "http", "git+ssh", "ssh"},
-       pingCmd:    "ls-remote -- {scheme}://{repo}",
+       scheme: []string{"git", "https", "http", "git+ssh", "ssh"},
+
+       // Leave out the '--' separator in the ls-remote command: git 2.7.4 does not
+       // support such a separator for that command, and this use should be safe
+       // without it because the {scheme} value comes from the predefined list above.
+       // See golang.org/issue/33836.
+       pingCmd: "ls-remote {scheme}://{repo}",
+
        remoteRepo: gitRemoteRepo,
 }
 
index d373771ab5a74789e3691dc36fd6f38f02aefac1..edb4a2a23caa838d4320dbc2ddf541776ca2cc5b 100644 (file)
@@ -63,7 +63,7 @@ Args:
                // helpSuccess is the help command using as many args as possible that would succeed.
                helpSuccess := "go help"
                if i > 0 {
-                       helpSuccess = " " + strings.Join(args[:i], " ")
+                       helpSuccess += " " + strings.Join(args[:i], " ")
                }
                fmt.Fprintf(os.Stderr, "go help %s: unknown help topic. Run '%s'.\n", strings.Join(args, " "), helpSuccess)
                base.SetExitStatus(2) // failed at 'go help cmd'
index c2b5fb4b83071048221136d6cf3d581b37e8c288..dfb89d4910bf7c8dc3ee2eff9bd6e1705c627f32 100644 (file)
@@ -493,6 +493,9 @@ General-purpose environment variables:
        GOCACHE
                The directory where the go command will store cached
                information for reuse in future builds.
+       GODEBUG
+               Enable various debugging facilities. See 'go doc runtime'
+               for details.
        GOENV
                The location of the Go environment configuration file.
                Cannot be set using 'go env -w'.
index e7e78e7c597a097e48f21b16d9f4a925345b1590..a5f1abe64ae643a25918c6ba783069e7fd803e53 100644 (file)
@@ -390,7 +390,7 @@ func runList(cmd *base.Command, args []string) {
                if !*listE {
                        for _, m := range mods {
                                if m.Error != nil {
-                                       base.Errorf("go list -m %s: %v", m.Path, m.Error.Err)
+                                       base.Errorf("go list -m: %v", m.Error.Err)
                                }
                        }
                        base.ExitIfErrors()
@@ -459,7 +459,7 @@ func runList(cmd *base.Command, args []string) {
                                }
                                if pmain != nil {
                                        pkgs = append(pkgs, pmain)
-                                       data := pmain.Internal.TestmainGo
+                                       data := *pmain.Internal.TestmainGo
                                        h := cache.NewHash("testmain")
                                        h.Write([]byte("testmain\n"))
                                        h.Write(data)
index 958356070c514331c43ea99e75429056326fe698..a50450ee0546653aa7e9f872b1c66595ee349ca7 100644 (file)
@@ -64,7 +64,7 @@ type PackagePublic struct {
        Doc           string                `json:",omitempty"` // package documentation string
        Target        string                `json:",omitempty"` // installed target for this package (may be executable)
        Shlib         string                `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
-       Root          string                `json:",omitempty"` // Go root or Go path dir containing this package
+       Root          string                `json:",omitempty"` // Go root, Go path dir, or module root dir containing this package
        ConflictDir   string                `json:",omitempty"` // Dir is hidden by this other directory
        ForTest       string                `json:",omitempty"` // package is only for use in named test
        Export        string                `json:",omitempty"` // file containing export data (set by go list -export)
@@ -177,8 +177,7 @@ type PackageInternal struct {
        OmitDebug         bool                 // tell linker not to write debug information
        GobinSubdir       bool                 // install target would be subdir of GOBIN
        BuildInfo         string               // add this info to package main
-       TestinginitGo     []byte               // content for _testinginit.go
-       TestmainGo        []byte               // content for _testmain.go
+       TestmainGo        *[]byte              // content for _testmain.go
 
        Asmflags   []string // -asmflags for this package
        Gcflags    []string // -gcflags for this package
@@ -647,9 +646,14 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
                                buildMode = build.ImportComment
                        }
                        data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode)
+                       if data.p.Root == "" && cfg.ModulesEnabled {
+                               if info := ModPackageModuleInfo(path); info != nil {
+                                       data.p.Root = info.Dir
+                               }
+                       }
                } else if r.err != nil {
                        data.p = new(build.Package)
-                       data.err = fmt.Errorf("unknown import path %q: %v", r.path, r.err)
+                       data.err = r.err
                } else if cfg.ModulesEnabled && path != "unsafe" {
                        data.p = new(build.Package)
                        data.err = fmt.Errorf("unknown import path %q: internal error: module loader did not resolve import", r.path)
index c247d56c8127f5624c9610b6fcab94a9c36bc372..afff5deaaa905c616308f909f010493fce280675 100644 (file)
@@ -102,7 +102,6 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
        var stk ImportStack
        stk.Push(p.ImportPath + " (test)")
        rawTestImports := str.StringList(p.TestImports)
-       var ptestImportsTesting, pxtestImportsTesting bool
        for i, path := range p.TestImports {
                p1 := loadImport(pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
                if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
@@ -117,9 +116,6 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
                }
                p.TestImports[i] = p1.ImportPath
                imports = append(imports, p1)
-               if path == "testing" {
-                       ptestImportsTesting = true
-               }
        }
        stk.Pop()
        stk.Push(p.ImportPath + "_test")
@@ -133,9 +129,6 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
                        ximports = append(ximports, p1)
                }
                p.XTestImports[i] = p1.ImportPath
-               if path == "testing" {
-                       pxtestImportsTesting = true
-               }
        }
        stk.Pop()
 
@@ -145,9 +138,6 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
                *ptest = *p
                ptest.Error = ptestErr
                ptest.ForTest = p.ImportPath
-               if ptestImportsTesting {
-                       ptest.Internal.TestinginitGo = formatTestinginit(p)
-               }
                ptest.GoFiles = nil
                ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
                ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
@@ -212,9 +202,6 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
                                Gccgoflags: p.Internal.Gccgoflags,
                        },
                }
-               if pxtestImportsTesting {
-                       pxtest.Internal.TestinginitGo = formatTestinginit(pxtest)
-               }
                if pxtestNeedsPtest {
                        pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
                }
@@ -337,7 +324,9 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
        if err != nil && pmain.Error == nil {
                pmain.Error = &PackageError{Err: err.Error()}
        }
-       pmain.Internal.TestmainGo = data
+       if data != nil {
+               pmain.Internal.TestmainGo = &data
+       }
 
        return pmain, ptest, pxtest
 }
@@ -485,15 +474,6 @@ func loadTestFuncs(ptest *Package) (*testFuncs, error) {
        return t, err
 }
 
-// formatTestinginit returns the content of the _testinginit.go file for p.
-func formatTestinginit(p *Package) []byte {
-       var buf bytes.Buffer
-       if err := testinginitTmpl.Execute(&buf, p); err != nil {
-               panic("testinginit template execution failed") // shouldn't be possible
-       }
-       return buf.Bytes()
-}
-
 // formatTestmain returns the content of the _testmain.go file for t.
 func formatTestmain(t *testFuncs) ([]byte, error) {
        var buf bytes.Buffer
@@ -623,23 +603,6 @@ func checkTestFunc(fn *ast.FuncDecl, arg string) error {
        return nil
 }
 
-var testinginitTmpl = lazytemplate.New("init", `
-package {{.Name}}
-
-import _go_testing "testing"
-
-{{/*
-Call testing.Init before any other user initialization code runs.
-(This file is passed to the compiler first.)
-This provides the illusion of the old behavior where testing flags
-were registered as part of the testing package's initialization.
-*/}}
-var _ = func() bool {
-       _go_testing.Init()
-       return true
-}()
-`)
-
 var testmainTmpl = lazytemplate.New("main", `
 // Code generated by 'go test'. DO NOT EDIT.
 
index 71b660d6fde326e7f468794db4a5f1c8673fff43..60d0d5b6e2b4fb362d2b62b829ba9a18353bfed8 100644 (file)
@@ -43,6 +43,7 @@ corresponding to this Go struct:
         Dir      string // absolute path to cached source root directory
         Sum      string // checksum for path, version (as in go.sum)
         GoModSum string // checksum for go.mod (as in go.sum)
+        Latest   bool   // would @latest resolve to this version?
     }
 
 See 'go help modules' for more about module queries.
@@ -65,6 +66,7 @@ type moduleJSON struct {
        Dir      string `json:",omitempty"`
        Sum      string `json:",omitempty"`
        GoModSum string `json:",omitempty"`
+       Latest   bool   `json:",omitempty"`
 }
 
 func runDownload(cmd *base.Command, args []string) {
@@ -87,7 +89,8 @@ func runDownload(cmd *base.Command, args []string) {
                if info.Replace != nil {
                        info = info.Replace
                }
-               if info.Version == "" {
+               if info.Version == "" && info.Error == nil {
+                       // main module
                        continue
                }
                m := &moduleJSON{
@@ -95,9 +98,38 @@ func runDownload(cmd *base.Command, args []string) {
                        Version: info.Version,
                }
                mods = append(mods, m)
+               if info.Error != nil {
+                       m.Error = info.Error.Err
+                       continue
+               }
                work.Add(m)
        }
 
+       latest := map[string]string{} // path → version
+       if *downloadJSON {
+               // We need to populate the Latest field, but if the main module depends on a
+               // version newer than latest — or if the version requested on the command
+               // line is itself newer than latest — that's not trivial to determine from
+               // the info returned by ListModules. Instead, we issue a separate
+               // ListModules request for "latest", which should be inexpensive relative to
+               // downloading the modules.
+               var latestArgs []string
+               for _, m := range mods {
+                       if m.Error != "" {
+                               continue
+                       }
+                       latestArgs = append(latestArgs, m.Path+"@latest")
+               }
+
+               if len(latestArgs) > 0 {
+                       for _, info := range modload.ListModules(latestArgs, listU, listVersions) {
+                               if info.Version != "" {
+                                       latest[info.Path] = info.Version
+                               }
+                       }
+               }
+       }
+
        work.Do(10, func(item interface{}) {
                m := item.(*moduleJSON)
                var err error
@@ -128,6 +160,9 @@ func runDownload(cmd *base.Command, args []string) {
                        m.Error = err.Error()
                        return
                }
+               if latest[m.Path] == m.Version {
+                       m.Latest = true
+               }
        })
 
        if *downloadJSON {
@@ -144,7 +179,7 @@ func runDownload(cmd *base.Command, args []string) {
        } else {
                for _, m := range mods {
                        if m.Error != "" {
-                               base.Errorf("%s@%s: %s\n", m.Path, m.Version, m.Error)
+                               base.Errorf("%s", m.Error)
                        }
                }
                base.ExitIfErrors()
index b1845f5c65067691ee6edc3bcd2f107c7c3e420e..48238f176c6dae63b0f09c1d76e966df2c9feee2 100644 (file)
@@ -341,7 +341,9 @@ func (r *vcsRepo) Stat(rev string) (*RevInfo, error) {
 }
 
 func (r *vcsRepo) fetch() {
-       _, r.fetchErr = Run(r.dir, r.cmd.fetch)
+       if len(r.cmd.fetch) > 0 {
+               _, r.fetchErr = Run(r.dir, r.cmd.fetch)
+       }
 }
 
 func (r *vcsRepo) statLocal(rev string) (*RevInfo, error) {
index 267b76349dd49b2590a140fe4843adecc4ec5326..f15ce67d46012a1b434f5006528083762731d83e 100644 (file)
@@ -31,7 +31,7 @@ type codeRepo struct {
        codeRoot string
        // codeDir is the directory (relative to root) at which we expect to find the module.
        // If pathMajor is non-empty and codeRoot is not the full modPath,
-       // then we look in both codeDir and codeDir+modPath
+       // then we look in both codeDir and codeDir/pathMajor[1:].
        codeDir string
 
        // pathMajor is the suffix of modPath that indicates its major version,
@@ -192,7 +192,13 @@ func (r *codeRepo) Stat(rev string) (*RevInfo, error) {
        codeRev := r.revToRev(rev)
        info, err := r.code.Stat(codeRev)
        if err != nil {
-               return nil, err
+               return nil, &module.ModuleError{
+                       Path: r.modPath,
+                       Err: &module.InvalidVersionError{
+                               Version: rev,
+                               Err:     err,
+                       },
+               }
        }
        return r.convert(info, rev)
 }
@@ -248,20 +254,25 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
        // exist as required by info2.Version and the module path represented by r.
        checkGoMod := func() (*RevInfo, error) {
                // If r.codeDir is non-empty, then the go.mod file must exist: the module
-               // author, not the module consumer, gets to decide how to carve up the repo
+               // author — not the module consumer, — gets to decide how to carve up the repo
                // into modules.
-               if r.codeDir != "" {
-                       _, _, _, err := r.findDir(info2.Version)
-                       if err != nil {
-                               // TODO: It would be nice to return an error like "not a module".
-                               // Right now we return "missing go.mod", which is a little confusing.
-                               return nil, &module.ModuleError{
-                                       Path: r.modPath,
-                                       Err: &module.InvalidVersionError{
-                                               Version: info2.Version,
-                                               Err:     notExistError(err.Error()),
-                                       },
-                               }
+               //
+               // Conversely, if the go.mod file exists, the module author — not the module
+               // consumer — gets to determine the module's path
+               //
+               // r.findDir verifies both of these conditions. Execute it now so that
+               // r.Stat will correctly return a notExistError if the go.mod location or
+               // declared module path doesn't match.
+               _, _, _, err := r.findDir(info2.Version)
+               if err != nil {
+                       // TODO: It would be nice to return an error like "not a module".
+                       // Right now we return "missing go.mod", which is a little confusing.
+                       return nil, &module.ModuleError{
+                               Path: r.modPath,
+                               Err: &module.InvalidVersionError{
+                                       Version: info2.Version,
+                                       Err:     notExistError(err.Error()),
+                               },
                        }
                }
 
@@ -474,6 +485,11 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
                return fmt.Errorf("does not match version-control timestamp (%s)", info.Time.UTC().Format(time.RFC3339))
        }
 
+       tagPrefix := ""
+       if r.codeDir != "" {
+               tagPrefix = r.codeDir + "/"
+       }
+
        // A pseudo-version should have a precedence just above its parent revisions,
        // and no higher. Otherwise, it would be possible for library authors to "pin"
        // dependency versions (and bypass the usual minimum version selection) by
@@ -499,11 +515,26 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
                        return fmt.Errorf("major version without preceding tag must be v0, not v1")
                }
                return nil
-       }
-
-       tagPrefix := ""
-       if r.codeDir != "" {
-               tagPrefix = r.codeDir + "/"
+       } else {
+               for _, tag := range info.Tags {
+                       versionOnly := strings.TrimPrefix(tag, tagPrefix)
+                       if versionOnly == base {
+                               // The base version is canonical, so if the version from the tag is
+                               // literally equal (not just equivalent), then the tag is canonical too.
+                               //
+                               // We allow pseudo-versions to be derived from non-canonical tags on the
+                               // same commit, so that tags like "v1.1.0+some-metadata" resolve as
+                               // close as possible to the canonical version ("v1.1.0") while still
+                               // enforcing a total ordering ("v1.1.1-0.[…]" with a unique suffix).
+                               //
+                               // However, canonical tags already have a total ordering, so there is no
+                               // reason not to use the canonical tag directly, and we know that the
+                               // canonical tag must already exist because the pseudo-version is
+                               // derived from it. In that case, referring to the revision by a
+                               // pseudo-version derived from its own canonical tag is just confusing.
+                               return fmt.Errorf("tag (%s) found on revision %s is already canonical, so should not be replaced with a pseudo-version derived from that tag", tag, rev)
+                       }
+               }
        }
 
        tags, err := r.code.Tags(tagPrefix + base)
@@ -571,6 +602,10 @@ func (r *codeRepo) versionToRev(version string) (rev string, err error) {
        return r.revToRev(version), nil
 }
 
+// findDir locates the directory within the repo containing the module.
+//
+// If r.pathMajor is non-empty, this can be either r.codeDir or — if a go.mod
+// file exists — r.codeDir/r.pathMajor[1:].
 func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err error) {
        rev, err = r.versionToRev(version)
        if err != nil {
index 5fc9bc3439722abf9db56a4236c659462a959398..1f2b95bd2384efe6008000c0925c8e28bed4d1ba 100644 (file)
@@ -83,6 +83,26 @@ var codeRepoTests = []codeRepoTest{
                        "pkg/p.go",
                },
        },
+       {
+               vcs:     "git",
+               path:    "github.com/rsc/vgotest1",
+               rev:     "v0.0.0-20180219231006-80d85c5d4d17",
+               version: "v0.0.0-20180219231006-80d85c5d4d17",
+               name:    "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+               short:   "80d85c5d4d17",
+               time:    time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+               zip: []string{
+                       "LICENSE",
+                       "README.md",
+                       "pkg/p.go",
+               },
+       },
+       {
+               vcs:  "git",
+               path: "github.com/rsc/vgotest1",
+               rev:  "v0.0.1-0.20180219231006-80d85c5d4d17",
+               err:  `github.com/rsc/vgotest1@v0.0.1-0.20180219231006-80d85c5d4d17: invalid pseudo-version: tag (v0.0.0) found on revision 80d85c5d4d17 is already canonical, so should not be replaced with a pseudo-version derived from that tag`,
+       },
        {
                vcs:     "git",
                path:    "github.com/rsc/vgotest1",
@@ -105,7 +125,7 @@ var codeRepoTests = []codeRepoTest{
                name:    "45f53230a74ad275c7127e117ac46914c8126160",
                short:   "45f53230a74a",
                time:    time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC),
-               ziperr:  "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
+               err:     "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
        },
        {
                vcs:     "git",
@@ -136,15 +156,14 @@ var codeRepoTests = []codeRepoTest{
                },
        },
        {
-               vcs:      "git",
-               path:     "github.com/rsc/vgotest1/v2",
-               rev:      "45f53230a",
-               version:  "v2.0.0",
-               name:     "45f53230a74ad275c7127e117ac46914c8126160",
-               short:    "45f53230a74a",
-               time:     time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC),
-               gomoderr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
-               ziperr:   "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
+               vcs:     "git",
+               path:    "github.com/rsc/vgotest1/v2",
+               rev:     "45f53230a",
+               version: "v2.0.0",
+               name:    "45f53230a74ad275c7127e117ac46914c8126160",
+               short:   "45f53230a74a",
+               time:    time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC),
+               err:     "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
        },
        {
                vcs:     "git",
@@ -154,7 +173,7 @@ var codeRepoTests = []codeRepoTest{
                name:    "80d85c5d4d17598a0e9055e7c175a32b415d6128",
                short:   "80d85c5d4d17",
                time:    time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
-               ziperr:  "missing github.com/rsc/vgotest1/go.mod and .../v54321/go.mod at revision 80d85c5d4d17",
+               err:     "missing github.com/rsc/vgotest1/go.mod and .../v54321/go.mod at revision 80d85c5d4d17",
        },
        {
                vcs:  "git",
@@ -210,24 +229,24 @@ var codeRepoTests = []codeRepoTest{
                gomod:   "module \"github.com/rsc/vgotest1/v2\" // root go.mod\n",
        },
        {
-               vcs:      "git",
-               path:     "github.com/rsc/vgotest1/v2",
-               rev:      "v2.0.3",
-               version:  "v2.0.3",
-               name:     "f18795870fb14388a21ef3ebc1d75911c8694f31",
-               short:    "f18795870fb1",
-               time:     time.Date(2018, 2, 19, 23, 16, 4, 0, time.UTC),
-               gomoderr: "github.com/rsc/vgotest1/v2/go.mod has non-.../v2 module path \"github.com/rsc/vgotest\" at revision v2.0.3",
+               vcs:     "git",
+               path:    "github.com/rsc/vgotest1/v2",
+               rev:     "v2.0.3",
+               version: "v2.0.3",
+               name:    "f18795870fb14388a21ef3ebc1d75911c8694f31",
+               short:   "f18795870fb1",
+               time:    time.Date(2018, 2, 19, 23, 16, 4, 0, time.UTC),
+               err:     "github.com/rsc/vgotest1/v2/go.mod has non-.../v2 module path \"github.com/rsc/vgotest\" at revision v2.0.3",
        },
        {
-               vcs:      "git",
-               path:     "github.com/rsc/vgotest1/v2",
-               rev:      "v2.0.4",
-               version:  "v2.0.4",
-               name:     "1f863feb76bc7029b78b21c5375644838962f88d",
-               short:    "1f863feb76bc",
-               time:     time.Date(2018, 2, 20, 0, 3, 38, 0, time.UTC),
-               gomoderr: "github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision v2.0.4",
+               vcs:     "git",
+               path:    "github.com/rsc/vgotest1/v2",
+               rev:     "v2.0.4",
+               version: "v2.0.4",
+               name:    "1f863feb76bc7029b78b21c5375644838962f88d",
+               short:   "1f863feb76bc",
+               time:    time.Date(2018, 2, 20, 0, 3, 38, 0, time.UTC),
+               err:     "github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision v2.0.4",
        },
        {
                vcs:     "git",
@@ -504,6 +523,7 @@ func TestCodeRepo(t *testing.T) {
                                        tt.name = remap(tt.name, m)
                                        tt.short = remap(tt.short, m)
                                        tt.rev = remap(tt.rev, m)
+                                       tt.err = remap(tt.err, m)
                                        tt.gomoderr = remap(tt.gomoderr, m)
                                        tt.ziperr = remap(tt.ziperr, m)
                                        t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
@@ -515,7 +535,7 @@ func TestCodeRepo(t *testing.T) {
 }
 
 var hgmap = map[string]string{
-       "github.com/rsc/vgotest1/":                 "vcs-test.golang.org/hg/vgotest1.hg/",
+       "github.com/rsc/vgotest1":                  "vcs-test.golang.org/hg/vgotest1.hg",
        "f18795870fb14388a21ef3ebc1d75911c8694f31": "a9ad6d1d14eb544f459f446210c7eb3b009807c6",
        "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9": "f1fc0f22021b638d073d31c752847e7bf385def7",
        "b769f2de407a4db81af9c5de0a06016d60d2ea09": "92c7eb888b4fac17f1c6bd2e1060a1b881a3b832",
@@ -631,15 +651,30 @@ var latestTests = []struct {
                err:  "no commits",
        },
        {
-               vcs:     "git",
-               path:    "github.com/rsc/vgotest1",
-               version: "v0.0.0-20180219223237-a08abb797a67",
+               vcs:  "git",
+               path: "github.com/rsc/vgotest1",
+               err:  `github.com/rsc/vgotest1@v0.0.0-20180219223237-a08abb797a67: invalid version: go.mod has post-v0 module path "github.com/vgotest1/v2" at revision a08abb797a67`,
+       },
+       {
+               vcs:  "git",
+               path: "github.com/rsc/vgotest1/v2",
+               err:  `github.com/rsc/vgotest1/v2@v2.0.0-20180219223237-a08abb797a67: invalid version: github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision a08abb797a67`,
        },
        {
                vcs:  "git",
                path: "github.com/rsc/vgotest1/subdir",
                err:  "github.com/rsc/vgotest1/subdir@v0.0.0-20180219223237-a08abb797a67: invalid version: missing github.com/rsc/vgotest1/subdir/go.mod at revision a08abb797a67",
        },
+       {
+               vcs:     "git",
+               path:    "vcs-test.golang.org/git/commit-after-tag.git",
+               version: "v1.0.1-0.20190715211727-b325d8217783",
+       },
+       {
+               vcs:     "git",
+               path:    "vcs-test.golang.org/git/no-tags.git",
+               version: "v0.0.0-20190715212047-e706ba1d9f6d",
+       },
        {
                vcs:     "mod",
                path:    "swtch.com/testmod",
index 74e36cc6fc1579cb2d3f2cf49a81abd0eedef72c..51a56028c4acbeab3d3c8b2130916b408a3e6921 100644 (file)
@@ -701,9 +701,11 @@ to use and optionally its public key and URL, as in:
        GOSUMDB="sum.golang.org+<publickey>"
        GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"
 
-The go command knows the public key of sum.golang.org; use of any other
-database requires giving the public key explicitly. The URL defaults to
-"https://" followed by the database name.
+The go command knows the public key of sum.golang.org, and also that the name
+sum.golang.google.cn (available inside mainland China) connects to the
+sum.golang.org checksum database; use of any other database requires giving
+the public key explicitly.
+The URL defaults to "https://" followed by the database name.
 
 GOSUMDB defaults to "sum.golang.org", the Go checksum database run by Google.
 See https://sum.golang.org/privacy for the service's privacy policy.
index 6049ccfd30a5bc26abf6140173e71aabbeb84d09..569ef3a57a60a39682d00c8a38b0c54113307cca 100644 (file)
@@ -345,7 +345,9 @@ func (p *proxyRepo) Stat(rev string) (*RevInfo, error) {
 func (p *proxyRepo) Latest() (*RevInfo, error) {
        data, err := p.getBytes("@latest")
        if err != nil {
-               // TODO return err if not 404
+               if !errors.Is(err, os.ErrNotExist) {
+                       return nil, p.versionError("", err)
+               }
                return p.latest()
        }
        info := new(RevInfo)
index 95351269dbec8c79b82e8e0c12a7249740b5f01a..be52a8dc11f977fe357b04bfe4cb2b3a84aadb8c 100644 (file)
@@ -240,7 +240,7 @@ func lookup(proxy, path string) (r Repo, err error) {
 
 var (
        errModVendor       = errors.New("module lookup disabled by -mod=vendor")
-       errProxyOff        = errors.New("module lookup disabled by GOPROXY=off")
+       errProxyOff        = notExistError("module lookup disabled by GOPROXY=off")
        errNoproxy   error = notExistError("disabled by GOPRIVATE/GONOPROXY")
        errUseProxy  error = notExistError("path does not match GOPRIVATE/GONOPROXY")
 )
index 66a09d32c273dba6952ce2d3ec2e61df9abc377e..1c24ec273b57b4391e213f1199a04964144316d5 100644 (file)
@@ -60,7 +60,17 @@ func dbDial() (dbName string, db *sumweb.Conn, err error) {
        // $GOSUMDB can be "key" or "key url",
        // and the key can be a full verifier key
        // or a host on our list of known keys.
-       key := strings.Fields(cfg.GOSUMDB)
+
+       // Special case: sum.golang.google.cn
+       // is an alias, reachable inside mainland China,
+       // for sum.golang.org. If there are more
+       // of these we should add a map like knownGOSUMDB.
+       gosumdb := cfg.GOSUMDB
+       if gosumdb == "sum.golang.google.cn" {
+               gosumdb = "sum.golang.org https://sum.golang.google.cn"
+       }
+
+       key := strings.Fields(gosumdb)
        if len(key) >= 1 {
                if k := knownGOSUMDB[key[0]]; k != "" {
                        key[0] = k
@@ -232,10 +242,10 @@ func (*dbClient) WriteConfig(file string, old, new []byte) error {
 }
 
 // ReadCache reads cached lookups or tiles from
-// GOPATH/pkg/mod/download/cache/sumdb,
+// GOPATH/pkg/mod/cache/download/sumdb,
 // which will be deleted by "go clean -modcache".
 func (*dbClient) ReadCache(file string) ([]byte, error) {
-       targ := filepath.Join(PkgMod, "download/cache/sumdb", file)
+       targ := filepath.Join(PkgMod, "cache/download/sumdb", file)
        data, err := lockedfile.Read(targ)
        // lockedfile.Write does not atomically create the file with contents.
        // There is a moment between file creation and locking the file for writing,
@@ -249,7 +259,7 @@ func (*dbClient) ReadCache(file string) ([]byte, error) {
 
 // WriteCache updates cached lookups or tiles.
 func (*dbClient) WriteCache(file string, data []byte) {
-       targ := filepath.Join(PkgMod, "download/cache/sumdb", file)
+       targ := filepath.Join(PkgMod, "cache/download/sumdb", file)
        os.MkdirAll(filepath.Dir(targ), 0777)
        lockedfile.Write(targ, bytes.NewReader(data), 0666)
 }
index 491d2891c7ea0fb8eb5846e74e766f12da03bbce..1cae311c4c157b825164f2fe36fbd559fe2ebeeb 100644 (file)
@@ -39,17 +39,27 @@ and then builds and installs them.
 The first step is to resolve which dependencies to add.
 
 For each named package or package pattern, get must decide which version of
-the corresponding module to use. By default, get chooses the latest tagged
+the corresponding module to use. By default, get looks up the latest tagged
 release version, such as v0.4.5 or v1.2.3. If there are no tagged release
-versions, get chooses the latest tagged pre-release version, such as
-v0.0.1-pre1. If there are no tagged versions at all, get chooses the latest
-known commit.
+versions, get looks up the latest tagged pre-release version, such as
+v0.0.1-pre1. If there are no tagged versions at all, get looks up the latest
+known commit. If the module is not already required at a later version
+(for example, a pre-release newer than the latest release), get will use
+the version it looked up. Otherwise, get will use the currently
+required version.
 
 This default version selection can be overridden by adding an @version
 suffix to the package argument, as in 'go get golang.org/x/text@v0.3.0'.
+The version may be a prefix: @v1 denotes the latest available version starting
+with v1. See 'go help modules' under the heading 'Module queries' for the
+full query syntax.
+
 For modules stored in source control repositories, the version suffix can
 also be a commit hash, branch identifier, or other syntax known to the
-source control system, as in 'go get golang.org/x/text@master'.
+source control system, as in 'go get golang.org/x/text@master'. Note that
+branches with names that overlap with other module query syntax cannot be
+selected explicitly. For example, the suffix @v2 means the latest version
+starting with v2, not the branch named v2.
 
 If a module under consideration is already a dependency of the current
 development module, then get will update the required version.
@@ -59,12 +69,14 @@ dependency should be removed entirely, downgrading or removing modules
 depending on it as needed.
 
 The version suffix @latest explicitly requests the latest minor release of the
-given path. The suffix @patch requests the latest patch release: if the path
-is already in the build list, the selected version will have the same minor
-version. If the path is not already in the build list, @patch is equivalent
-to @latest. Neither @latest nor @patch will cause 'go get' to downgrade a module
-in the build list if it is required at a newer pre-release version that is
-newer than the latest released version.
+module named by the given path. The suffix @upgrade is like @latest but
+will not downgrade a module if it is already required at a revision or
+pre-release version newer than the latest released version. The suffix
+@patch requests the latest patch release: the latest released version
+with the same major and minor version numbers as the currently required
+version. Like @upgrade, @patch will not downgrade a module already required
+at a newer version. If the path is not already required, @upgrade and @patch
+are equivalent to @latest.
 
 Although get defaults to using the latest version of the module containing
 a named package, it does not use the latest version of that module's
@@ -178,7 +190,7 @@ func (v *upgradeFlag) Set(s string) error {
                s = ""
        }
        if s == "true" {
-               s = "latest"
+               s = "upgrade"
        }
        *v = upgradeFlag(s)
        return nil
@@ -202,8 +214,9 @@ type getArg struct {
        // if there is no "@"). path specifies the modules or packages to get.
        path string
 
-       // vers is the part of the argument after "@" (or "" if there is no "@").
-       // vers specifies the module version to get.
+       // vers is the part of the argument after "@" or an implied
+       // "upgrade" or "patch" if there is no "@". vers specifies the
+       // module version to get.
        vers string
 }
 
@@ -249,7 +262,7 @@ func runGet(cmd *base.Command, args []string) {
        }
 
        switch getU {
-       case "", "latest", "patch":
+       case "", "upgrade", "patch":
                // ok
        default:
                base.Fatalf("go get: unknown upgrade flag -u=%s", getU)
@@ -283,11 +296,11 @@ func runGet(cmd *base.Command, args []string) {
 
        // Parse command-line arguments and report errors. The command-line
        // arguments are of the form path@version or simply path, with implicit
-       // @latest. path@none is "downgrade away".
+       // @upgrade. path@none is "downgrade away".
        var gets []getArg
        var queries []*query
        for _, arg := range search.CleanPatterns(args) {
-               // Argument is module query path@vers, or else path with implicit @latest.
+               // Argument is path or path@vers.
                path := arg
                vers := ""
                if i := strings.Index(arg, "@"); i >= 0 {
@@ -298,10 +311,14 @@ func runGet(cmd *base.Command, args []string) {
                        continue
                }
 
-               // If the user runs 'go get -u=patch some/module', update some/module to a
-               // patch release, not a minor version.
-               if vers == "" && getU != "" {
-                       vers = string(getU)
+               // If no version suffix is specified, assume @upgrade.
+               // If -u=patch was specified, assume @patch instead.
+               if vers == "" {
+                       if getU != "" {
+                               vers = string(getU)
+                       } else {
+                               vers = "upgrade"
+                       }
                }
 
                gets = append(gets, getArg{raw: arg, path: path, vers: vers})
@@ -358,7 +375,7 @@ func runGet(cmd *base.Command, args []string) {
                        // The argument is a package path.
                        if pkgs := modload.TargetPackages(path); len(pkgs) != 0 {
                                // The path is in the main module. Nothing to query.
-                               if vers != "" && vers != "latest" && vers != "patch" {
+                               if vers != "upgrade" && vers != "patch" {
                                        base.Errorf("go get %s: can't request explicit version of path in main module", arg)
                                }
                                continue
@@ -376,8 +393,8 @@ func runGet(cmd *base.Command, args []string) {
                                continue
                        }
 
-                       // If we're querying "latest" or "patch", we need to know the current
-                       // version of the module. For "latest", we want to avoid accidentally
+                       // If we're querying "upgrade" or "patch", we need to know the current
+                       // version of the module. For "upgrade", we want to avoid accidentally
                        // downgrading from a newer prerelease. For "patch", we need to query
                        // the correct minor version.
                        // Here, we check if "path" is the name of a module in the build list
@@ -718,7 +735,7 @@ func runQueries(cache map[querySpec]*query, queries []*query, modOnly map[string
        return byPath
 }
 
-// getQuery evaluates the given package path, version pair
+// getQuery evaluates the given (package or module) path and version
 // to determine the underlying module version being requested.
 // If forceModulePath is set, getQuery must interpret path
 // as a module path.
@@ -736,34 +753,51 @@ func getQuery(path, vers string, prevM module.Version, forceModulePath bool) (mo
                base.Fatalf("go get: internal error: prevM may be set if and only if forceModulePath is set")
        }
 
-       if vers == "" || vers == "patch" && prevM.Version == "" {
-               vers = "latest"
-       }
-
-       if forceModulePath || !strings.Contains(path, "...") {
+       // If the query must be a module path, try only that module path.
+       if forceModulePath {
                if path == modload.Target.Path {
                        if vers != "latest" {
                                return module.Version{}, fmt.Errorf("can't get a specific version of the main module")
                        }
                }
 
-               // If the path doesn't contain a wildcard, try interpreting it as a module path.
                info, err := modload.Query(path, vers, prevM.Version, modload.Allowed)
                if err == nil {
                        return module.Version{Path: path, Version: info.Version}, nil
                }
 
-               // If the query fails, and the path must be a real module, report the query error.
-               if forceModulePath {
-                       return module.Version{}, err
+               // If the query was "upgrade" or "patch" and the current version has been
+               // replaced, check to see whether the error was for that same version:
+               // if so, the version was probably replaced because it is invalid,
+               // and we should keep that replacement without complaining.
+               if vers == "upgrade" || vers == "patch" {
+                       var vErr *module.InvalidVersionError
+                       if errors.As(err, &vErr) && vErr.Version == prevM.Version && modload.Replacement(prevM).Path != "" {
+                               return prevM, nil
+                       }
                }
+
+               return module.Version{}, err
        }
 
-       // Otherwise, try a package path or pattern.
+       // If the query may be either a package or a module, try it as a package path.
+       // If it turns out to only exist as a module, we can detect the resulting
+       // PackageNotInModuleError and avoid a second round-trip through (potentially)
+       // all of the configured proxies.
        results, err := modload.QueryPattern(path, vers, modload.Allowed)
        if err != nil {
+               // If the path doesn't contain a wildcard, check whether it was actually a
+               // module path instead. If so, return that.
+               if !strings.Contains(path, "...") {
+                       var modErr *modload.PackageNotInModuleError
+                       if errors.As(err, &modErr) && modErr.Mod.Path == path {
+                               return modErr.Mod, nil
+                       }
+               }
+
                return module.Version{}, err
        }
+
        return results[0].Mod, nil
 }
 
@@ -893,13 +927,23 @@ func (u *upgrader) Upgrade(m module.Version) (module.Version, error) {
        // which may return a pseudoversion for the latest commit.
        // Query "latest" returns the newest tagged version or the newest
        // prerelease version if there are no non-prereleases, or repo.Latest
-       // if there aren't any tagged versions. Since we're providing the previous
-       // version, Query will confirm the latest version is actually newer
-       // and will return the current version if not.
+       // if there aren't any tagged versions.
+       // If we're querying "upgrade" or "patch", Query will compare the current
+       // version against the chosen version and will return the current version
+       // if it is newer.
        info, err := modload.Query(m.Path, string(getU), m.Version, modload.Allowed)
        if err != nil {
                // Report error but return m, to let version selection continue.
                // (Reporting the error will fail the command at the next base.ExitIfErrors.)
+
+               // Special case: if the error is for m.Version itself and m.Version has a
+               // replacement, then keep it and don't report the error: the fact that the
+               // version is invalid is likely the reason it was replaced to begin with.
+               var vErr *module.InvalidVersionError
+               if errors.As(err, &vErr) && vErr.Version == m.Version && modload.Replacement(m).Path != "" {
+                       return m, nil
+               }
+
                // Special case: if the error is "no matching versions" then don't
                // even report the error. Because Query does not consider pseudo-versions,
                // it may happen that we have a pseudo-version but during -u=patch
index 17a65216c2a21c9302a090c06cf3888697ea2e80..7cbdef1c36c721c4a714765d0ec60fc4632b0518 100644 (file)
@@ -79,7 +79,7 @@ func addUpdate(m *modinfo.ModulePublic) {
                return
        }
 
-       if info, err := Query(m.Path, "latest", m.Version, Allowed); err == nil && semver.Compare(info.Version, m.Version) > 0 {
+       if info, err := Query(m.Path, "upgrade", m.Version, Allowed); err == nil && semver.Compare(info.Version, m.Version) > 0 {
                m.Update = &modinfo.ModulePublic{
                        Path:    m.Path,
                        Version: info.Version,
index 788544c2c85177ca10ff36240c1da424e22323ae..1927c1cff7363b639ca1bb9f68dbf39c67e67ecc 100644 (file)
@@ -231,12 +231,25 @@ evaluates to the available tagged version nearest to the comparison target
 The string "latest" matches the latest available tagged version,
 or else the underlying source repository's latest untagged revision.
 
-A revision identifier for the underlying source repository,
-such as a commit hash prefix, revision tag, or branch name,
-selects that specific code revision. If the revision is
-also tagged with a semantic version, the query evaluates to
-that semantic version. Otherwise the query evaluates to a
-pseudo-version for the commit.
+The string "upgrade" is like "latest", but if the module is
+currently required at a later version than the version "latest"
+would select (for example, a newer pre-release version), "upgrade"
+will select the later version instead.
+
+The string "patch" matches the latest available tagged version
+of a module with the same major and minor version numbers as the
+currently required version. If no version is currently required,
+"patch" is equivalent to "latest".
+
+A revision identifier for the underlying source repository, such as
+a commit hash prefix, revision tag, or branch name, selects that
+specific code revision. If the revision is also tagged with a
+semantic version, the query evaluates to that semantic version.
+Otherwise the query evaluates to a pseudo-version for the commit.
+Note that branches and tags with names that are matched by other
+query syntax cannot be selected this way. For example, the query
+"v2" means the latest version starting with "v2", not the branch
+named "v2".
 
 All queries prefer release versions to pre-release versions.
 For example, "<v1.2.3" will prefer to return "v1.2.2"
index dacc876701a0cad75c44d5ce386f63c9add98e99..70add3507a20b08e478140e8b11b607a9b3ab416 100644 (file)
@@ -22,6 +22,7 @@ import (
        "cmd/go/internal/par"
        "cmd/go/internal/search"
        "cmd/go/internal/semver"
+       "cmd/go/internal/str"
 )
 
 type ImportMissingError struct {
@@ -35,6 +36,9 @@ type ImportMissingError struct {
 
 func (e *ImportMissingError) Error() string {
        if e.Module.Path == "" {
+               if str.HasPathPrefix(e.ImportPath, "cmd") {
+                       return fmt.Sprintf("package %s is not in GOROOT (%s)", e.ImportPath, filepath.Join(cfg.GOROOT, "src", e.ImportPath))
+               }
                return "cannot find module providing package " + e.ImportPath
        }
        return "missing module for import: " + e.Module.Path + "@" + e.Module.Version + " provides " + e.ImportPath
@@ -74,6 +78,9 @@ func Import(path string) (m module.Version, dir string, err error) {
                dir := filepath.Join(cfg.GOROOT, "src", path)
                return module.Version{}, dir, nil
        }
+       if str.HasPathPrefix(path, "cmd") {
+               return module.Version{}, "", &ImportMissingError{ImportPath: path}
+       }
 
        // -mod=vendor is special.
        // Everything must be in the main module or the main module's vendor directory.
index c571ddc5f5423cc40b2308d396b8b6e1de7291a1..35d0c28cde10b943f880d449531783c58cf0f27f 100644 (file)
@@ -5,6 +5,7 @@
 package modload
 
 import (
+       "errors"
        "fmt"
        "os"
        "strings"
@@ -70,9 +71,7 @@ func listModules(args []string, listVersions bool) []*modinfo.ModulePublic {
                                mods = append(mods, &modinfo.ModulePublic{
                                        Path:    path,
                                        Version: vers,
-                                       Error: &modinfo.ModuleError{
-                                               Err: err.Error(),
-                                       },
+                                       Error:   modinfoError(path, vers, err),
                                })
                                continue
                        }
@@ -116,19 +115,15 @@ func listModules(args []string, listVersions bool) []*modinfo.ModulePublic {
                                                mods = append(mods, moduleInfo(module.Version{Path: arg, Version: info.Version}, false))
                                        } else {
                                                mods = append(mods, &modinfo.ModulePublic{
-                                                       Path: arg,
-                                                       Error: &modinfo.ModuleError{
-                                                               Err: err.Error(),
-                                                       },
+                                                       Path:  arg,
+                                                       Error: modinfoError(arg, "", err),
                                                })
                                        }
                                        continue
                                }
                                mods = append(mods, &modinfo.ModulePublic{
-                                       Path: arg,
-                                       Error: &modinfo.ModuleError{
-                                               Err: fmt.Sprintf("module %q is not a known dependency", arg),
-                                       },
+                                       Path:  arg,
+                                       Error: modinfoError(arg, "", errors.New("not a known dependency")),
                                })
                        } else {
                                fmt.Fprintf(os.Stderr, "warning: pattern %q matched no module dependencies\n", arg)
@@ -138,3 +133,21 @@ func listModules(args []string, listVersions bool) []*modinfo.ModulePublic {
 
        return mods
 }
+
+// modinfoError wraps an error to create an error message in
+// modinfo.ModuleError with minimal redundancy.
+func modinfoError(path, vers string, err error) *modinfo.ModuleError {
+       var nerr *NoMatchingVersionError
+       var merr *module.ModuleError
+       if errors.As(err, &nerr) {
+               // NoMatchingVersionError contains the query, so we don't mention the
+               // query again in ModuleError.
+               err = &module.ModuleError{Path: path, Err: err}
+       } else if !errors.As(err, &merr) {
+               // If the error does not contain path and version, wrap it in a
+               // module.ModuleError.
+               err = &module.ModuleError{Path: path, Version: vers, Err: err}
+       }
+
+       return &modinfo.ModuleError{Err: err.Error()}
+}
index a9d6c21b0e3d63bd36506b0eaf626a932f1e0dca..d18723e7dcd339a39e259be9e892b58e0d9af867 100644 (file)
@@ -100,11 +100,31 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
                                                dir = filepath.Clean(dir)
                                        }
 
+                                       // golang.org/issue/32917: We should resolve a relative path to a
+                                       // package path only if the relative path actually contains the code
+                                       // for that package.
+                                       if !dirContainsPackage(dir) {
+                                               // If we're outside of a module, ensure that the failure mode
+                                               // indicates that.
+                                               ModRoot()
+
+                                               // If the directory is local but does not exist, don't return it
+                                               // while loader is iterating, since this might trigger a fetch.
+                                               // After loader is done iterating, we still need to return the
+                                               // path, so that "go list -e" produces valid output.
+                                               if !iterating {
+                                                       // We don't have a valid path to resolve to, so report the
+                                                       // unresolved path.
+                                                       m.Pkgs = append(m.Pkgs, pkg)
+                                               }
+                                               continue
+                                       }
+
                                        // Note: The checks for @ here are just to avoid misinterpreting
                                        // the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
                                        // It's not strictly necessary but helpful to keep the checks.
                                        if modRoot != "" && dir == modRoot {
-                                               pkg = Target.Path
+                                               pkg = targetPrefix
                                        } else if modRoot != "" && strings.HasPrefix(dir, modRoot+string(filepath.Separator)) && !strings.Contains(dir[len(modRoot):], "@") {
                                                suffix := filepath.ToSlash(dir[len(modRoot):])
                                                if strings.HasPrefix(suffix, "/vendor/") {
@@ -121,7 +141,13 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
                                                                continue
                                                        }
                                                } else {
-                                                       pkg = Target.Path + suffix
+                                                       modPkg := targetPrefix + suffix
+                                                       if _, ok := dirInModule(modPkg, targetPrefix, modRoot, true); ok {
+                                                               pkg = modPkg
+                                                       } else if !iterating {
+                                                               ModRoot()
+                                                               base.Errorf("go: directory %s is outside main module", base.ShortPath(dir))
+                                                       }
                                                }
                                        } else if sub := search.InDir(dir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
                                                pkg = filepath.ToSlash(sub)
@@ -134,16 +160,6 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
                                                        base.Errorf("go: directory %s outside available modules", base.ShortPath(dir))
                                                }
                                        }
-                                       info, err := os.Stat(dir)
-                                       if err != nil || !info.IsDir() {
-                                               // If the directory is local but does not exist, don't return it
-                                               // while loader is iterating, since this would trigger a fetch.
-                                               // After loader is done iterating, we still need to return the
-                                               // path, so that "go list -e" produces valid output.
-                                               if iterating {
-                                                       continue
-                                               }
-                                       }
                                        m.Pkgs = append(m.Pkgs, pkg)
                                }
 
@@ -247,14 +263,30 @@ func pathInModuleCache(dir string) string {
        return ""
 }
 
-// warnPattern returns list, the result of matching pattern,
-// but if list is empty then first it prints a warning about
-// the pattern not matching any packages.
-func warnPattern(pattern string, list []string) []string {
-       if len(list) == 0 {
-               fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+var dirContainsPackageCache sync.Map // absolute dir → bool
+
+func dirContainsPackage(dir string) bool {
+       isPkg, ok := dirContainsPackageCache.Load(dir)
+       if !ok {
+               _, err := cfg.BuildContext.ImportDir(dir, 0)
+               if err == nil {
+                       isPkg = true
+               } else {
+                       if fi, statErr := os.Stat(dir); statErr != nil || !fi.IsDir() {
+                               // A non-directory or inaccessible directory is not a Go package.
+                               isPkg = false
+                       } else if _, noGo := err.(*build.NoGoError); noGo {
+                               // A directory containing no Go source files is not a Go package.
+                               isPkg = false
+                       } else {
+                               // An error other than *build.NoGoError indicates that the package exists
+                               // but has some other problem (such as a syntax error).
+                               isPkg = true
+                       }
+               }
+               isPkg, _ = dirContainsPackageCache.LoadOrStore(dir, isPkg)
        }
-       return list
+       return isPkg.(bool)
 }
 
 // ImportFromFiles adds modules to the build list as needed
@@ -355,11 +387,13 @@ func loadAll(testAll bool) []string {
 
        var paths []string
        for _, pkg := range loaded.pkgs {
-               if e, ok := pkg.err.(*ImportMissingError); ok && e.Module.Path == "" {
-                       continue // Package doesn't actually exist.
+               if pkg.err != nil {
+                       base.Errorf("%s: %v", pkg.stackText(), pkg.err)
+                       continue
                }
                paths = append(paths, pkg.path)
        }
+       base.ExitIfErrors()
        return paths
 }
 
@@ -1108,7 +1142,9 @@ func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
                return nil, module.VersionError(mod, errors.New("parsing go.mod: missing module line"))
        }
        if mpath := f.Module.Mod.Path; mpath != origPath && mpath != mod.Path {
-               return nil, module.VersionError(mod, fmt.Errorf("parsing go.mod: unexpected module path %q", mpath))
+               return nil, module.VersionError(mod, fmt.Errorf(`parsing go.mod:
+       module declares its path as: %s
+               but was required as: %s`, mpath, mod.Path))
        }
        if f.Go != nil {
                r.versions.LoadOrStore(mod, f.Go.Version)
index 8ce61c0a1d6657e525e2989a5160cd2dfda4ffb2..602bf47275db8bb7af45f682ef20c601d60888a8 100644 (file)
@@ -28,9 +28,10 @@ import (
 //   tagged version, with non-prereleases preferred over prereleases.
 //   If there are no tagged versions in the repo, latest returns the most
 //   recent commit.
+// - the literal string "upgrade", equivalent to "latest" except that if
+//   current is a newer version, current will be returned (see below).
 // - the literal string "patch", denoting the latest available tagged version
-//   with the same major and minor number as current. If current is "",
-//   "patch" is equivalent to "latest".
+//   with the same major and minor number as current (see below).
 // - v1, denoting the latest available tagged version v1.x.x.
 // - v1.2, denoting the latest available tagged version v1.2.x.
 // - v1.2.3, a semantic version string denoting that tagged version.
@@ -39,11 +40,12 @@ import (
 //   with non-prereleases preferred over prereleases.
 // - a repository commit identifier or tag, denoting that commit.
 //
-// current is optional, denoting the current version of the module.
-// If query is "latest" or "patch", current will be returned if it is a newer
-// semantic version or if it is a chronologically later pseudoversion. This
-// prevents accidental downgrades from newer prerelease or development
-// versions.
+// current denotes the current version of the module; it may be "" if the
+// current version is unknown or should not be considered. If query is
+// "upgrade" or "patch", current will be returned if it is a newer
+// semantic version or a chronologically later pseudo-version than the
+// version that would otherwise be chosen. This prevents accidental downgrades
+// from newer pre-release or development versions.
 //
 // If the allowed function is non-nil, Query excludes any versions for which
 // allowed returns false.
@@ -81,6 +83,10 @@ func queryProxy(proxy, path, query, current string, allowed func(module.Version)
                ok = allowed
                mayUseLatest = true
 
+       case query == "upgrade":
+               ok = allowed
+               mayUseLatest = true
+
        case query == "patch":
                if current == "" {
                        ok = allowed
@@ -202,9 +208,9 @@ func queryProxy(proxy, path, query, current string, allowed func(module.Version)
                        return nil, err
                }
 
-               // For "latest" and "patch", make sure we don't accidentally downgrade
+               // For "upgrade" and "patch", make sure we don't accidentally downgrade
                // from a newer prerelease or from a chronologically newer pseudoversion.
-               if current != "" && (query == "latest" || query == "patch") {
+               if current != "" && (query == "upgrade" || query == "patch") {
                        currentTime, err := modfetch.PseudoVersionTime(current)
                        if semver.Compare(rev.Version, current) < 0 || (err == nil && rev.Time.Before(currentTime)) {
                                return repo.Stat(current)
@@ -374,10 +380,10 @@ func QueryPattern(pattern, query string, allowed func(module.Version) bool) ([]Q
                        }
                        r.Packages = match(r.Mod, root, isLocal)
                        if len(r.Packages) == 0 {
-                               return r, &packageNotInModuleError{
-                                       mod:     r.Mod,
-                                       query:   query,
-                                       pattern: pattern,
+                               return r, &PackageNotInModuleError{
+                                       Mod:     r.Mod,
+                                       Query:   query,
+                                       Pattern: pattern,
                                }
                        }
                        return r, nil
@@ -440,30 +446,31 @@ func queryPrefixModules(candidateModules []string, queryModule func(path string)
        wg.Wait()
 
        // Classify the results. In case of failure, identify the error that the user
-       // is most likely to find helpful.
+       // is most likely to find helpful: the most useful class of error at the
+       // longest matching path.
        var (
+               noPackage   *PackageNotInModuleError
                noVersion   *NoMatchingVersionError
-               noPackage   *packageNotInModuleError
                notExistErr error
        )
        for _, r := range results {
                switch rErr := r.err.(type) {
                case nil:
                        found = append(found, r.QueryResult)
+               case *PackageNotInModuleError:
+                       if noPackage == nil {
+                               noPackage = rErr
+                       }
                case *NoMatchingVersionError:
                        if noVersion == nil {
                                noVersion = rErr
                        }
-               case *packageNotInModuleError:
-                       if noPackage == nil {
-                               noPackage = rErr
-                       }
                default:
                        if errors.Is(rErr, os.ErrNotExist) {
                                if notExistErr == nil {
                                        notExistErr = rErr
                                }
-                       } else {
+                       } else if err == nil {
                                err = r.err
                        }
                }
@@ -503,37 +510,37 @@ type NoMatchingVersionError struct {
 
 func (e *NoMatchingVersionError) Error() string {
        currentSuffix := ""
-       if (e.query == "latest" || e.query == "patch") && e.current != "" {
+       if (e.query == "upgrade" || e.query == "patch") && e.current != "" {
                currentSuffix = fmt.Sprintf(" (current version is %s)", e.current)
        }
        return fmt.Sprintf("no matching versions for query %q", e.query) + currentSuffix
 }
 
-// A packageNotInModuleError indicates that QueryPattern found a candidate
+// A PackageNotInModuleError indicates that QueryPattern found a candidate
 // module at the requested version, but that module did not contain any packages
 // matching the requested pattern.
 //
-// NOTE: packageNotInModuleError MUST NOT implement Is(os.ErrNotExist).
+// NOTE: PackageNotInModuleError MUST NOT implement Is(os.ErrNotExist).
 //
 // If the module came from a proxy, that proxy had to return a successful status
 // code for the versions it knows about, and thus did not have the opportunity
 // to return a non-400 status code to suppress fallback.
-type packageNotInModuleError struct {
-       mod     module.Version
-       query   string
-       pattern string
+type PackageNotInModuleError struct {
+       Mod     module.Version
+       Query   string
+       Pattern string
 }
 
-func (e *packageNotInModuleError) Error() string {
+func (e *PackageNotInModuleError) Error() string {
        found := ""
-       if e.query != e.mod.Version {
-               found = fmt.Sprintf(" (%s)", e.mod.Version)
+       if e.Query != e.Mod.Version {
+               found = fmt.Sprintf(" (%s)", e.Mod.Version)
        }
 
-       if strings.Contains(e.pattern, "...") {
-               return fmt.Sprintf("module %s@%s%s found, but does not contain packages matching %s", e.mod.Path, e.query, found, e.pattern)
+       if strings.Contains(e.Pattern, "...") {
+               return fmt.Sprintf("module %s@%s%s found, but does not contain packages matching %s", e.Mod.Path, e.Query, found, e.Pattern)
        }
-       return fmt.Sprintf("module %s@%s%s found, but does not contain package %s", e.mod.Path, e.query, found, e.pattern)
+       return fmt.Sprintf("module %s@%s%s found, but does not contain package %s", e.Mod.Path, e.Query, found, e.Pattern)
 }
 
 // ModuleHasRootPackage returns whether module m contains a package m.Path.
index 5c0527d40c947bef096c2ea7c373e0d25eda3cde..b91cbb5a700df8eb62e18f425630530726f03695 100644 (file)
@@ -100,7 +100,7 @@ var queryTests = []struct {
        {path: queryRepo, query: ">=v0.0.0", vers: "v0.0.0"},
        {path: queryRepo, query: "v0.0.1", vers: "v0.0.1"},
        {path: queryRepo, query: "v0.0.1+foo", vers: "v0.0.1"},
-       {path: queryRepo, query: "v0.0.99", err: `unknown revision v0.0.99`},
+       {path: queryRepo, query: "v0.0.99", err: `vcs-test.golang.org/git/querytest.git@v0.0.99: invalid version: unknown revision v0.0.99`},
        {path: queryRepo, query: "v0", vers: "v0.3.0"},
        {path: queryRepo, query: "v0.1", vers: "v0.1.2"},
        {path: queryRepo, query: "v0.2", err: `no matching versions for query "v0.2"`},
@@ -112,15 +112,17 @@ var queryTests = []struct {
        // unconditionally).
        {path: queryRepo, query: "42abcb6df8ee", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},
 
-       {path: queryRepo, query: "v1.9.10-pre2+wrongmetadata", err: `unknown revision v1.9.10-pre2+wrongmetadata`},
-       {path: queryRepo, query: "v1.9.10-pre2", err: `unknown revision v1.9.10-pre2`},
+       {path: queryRepo, query: "v1.9.10-pre2+wrongmetadata", err: `vcs-test.golang.org/git/querytest.git@v1.9.10-pre2+wrongmetadata: invalid version: unknown revision v1.9.10-pre2+wrongmetadata`},
+       {path: queryRepo, query: "v1.9.10-pre2", err: `vcs-test.golang.org/git/querytest.git@v1.9.10-pre2: invalid version: unknown revision v1.9.10-pre2`},
        {path: queryRepo, query: "latest", vers: "v1.9.9"},
-       {path: queryRepo, query: "latest", current: "v1.9.10-pre1", vers: "v1.9.10-pre1"},
-       {path: queryRepo, query: "latest", current: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},
-       {path: queryRepo, query: "latest", current: "v0.0.0-20190513201126-42abcb6df8ee", vers: "v0.0.0-20190513201126-42abcb6df8ee"},
-       {path: queryRepo, query: "latest", allow: "NOMATCH", err: `no matching versions for query "latest"`},
-       {path: queryRepo, query: "latest", current: "v1.9.9", allow: "NOMATCH", err: `no matching versions for query "latest" (current version is v1.9.9)`},
-       {path: queryRepo, query: "latest", current: "v1.99.99", err: `unknown revision v1.99.99`},
+       {path: queryRepo, query: "latest", current: "v1.9.10-pre1", vers: "v1.9.9"},
+       {path: queryRepo, query: "upgrade", vers: "v1.9.9"},
+       {path: queryRepo, query: "upgrade", current: "v1.9.10-pre1", vers: "v1.9.10-pre1"},
+       {path: queryRepo, query: "upgrade", current: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},
+       {path: queryRepo, query: "upgrade", current: "v0.0.0-20190513201126-42abcb6df8ee", vers: "v0.0.0-20190513201126-42abcb6df8ee"},
+       {path: queryRepo, query: "upgrade", allow: "NOMATCH", err: `no matching versions for query "upgrade"`},
+       {path: queryRepo, query: "upgrade", current: "v1.9.9", allow: "NOMATCH", err: `no matching versions for query "upgrade" (current version is v1.9.9)`},
+       {path: queryRepo, query: "upgrade", current: "v1.99.99", err: `vcs-test.golang.org/git/querytest.git@v1.99.99: invalid version: unknown revision v1.99.99`},
        {path: queryRepo, query: "patch", current: "", vers: "v1.9.9"},
        {path: queryRepo, query: "patch", current: "v0.1.0", vers: "v0.1.2"},
        {path: queryRepo, query: "patch", current: "v1.9.0", vers: "v1.9.9"},
@@ -159,8 +161,11 @@ var queryTests = []struct {
        {path: queryRepoV2, query: "v2.6.0-pre1", vers: "v2.6.0-pre1"},
        {path: queryRepoV2, query: "latest", vers: "v2.5.5"},
 
-       {path: queryRepoV3, query: "e0cf3de987e6", vers: "v3.0.0-20180704024501-e0cf3de987e6"},
-       {path: queryRepoV3, query: "latest", vers: "v3.0.0-20180704024501-e0cf3de987e6"},
+       // e0cf3de987e6 is the latest commit on the master branch, and it's actually
+       // v1.19.10-pre1, not anything resembling v3: attempting to query it as such
+       // should fail.
+       {path: queryRepoV3, query: "e0cf3de987e6", err: `vcs-test.golang.org/git/querytest.git/v3@v3.0.0-20180704024501-e0cf3de987e6: invalid version: go.mod has non-.../v3 module path "vcs-test.golang.org/git/querytest.git" (and .../v3/go.mod does not exist) at revision e0cf3de987e6`},
+       {path: queryRepoV3, query: "latest", err: `no matching versions for query "latest"`},
 
        {path: emptyRepo, query: "latest", vers: "v0.0.0-20180704023549-7bb914627242"},
        {path: emptyRepo, query: ">v0.0.0", err: `no matching versions for query ">v0.0.0"`},
@@ -180,7 +185,10 @@ func TestQuery(t *testing.T) {
                        ok, _ := path.Match(allow, m.Version)
                        return ok
                }
+               tt := tt
                t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.query+"/"+tt.current+"/"+allow, func(t *testing.T) {
+                       t.Parallel()
+
                        info, err := Query(tt.path, tt.query, tt.current, allowed)
                        if tt.err != "" {
                                if err == nil {
index 568efbd8b2663a5c0ea0893c546882c8d05befa6..4e7a828c24f10515b9503325f8c80ab0f9ec5ff7 100644 (file)
@@ -216,8 +216,8 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
                }
        }
 
-       // Construct the list by traversing the graph again, replacing older
-       // modules with required minimum versions.
+       // The final list is the minimum version of each module found in the graph.
+
        if v := min[target.Path]; v != target.Version {
                // TODO(jayconrod): there is a special case in modload.mvsReqs.Max
                // that prevents us from selecting a newer version of a module
@@ -228,19 +228,18 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
        }
 
        list := []module.Version{target}
-       listed := map[string]bool{target.Path: true}
-       for i := 0; i < len(list); i++ {
-               n := modGraph[list[i]]
+       for path, vers := range min {
+               if path != target.Path {
+                       list = append(list, module.Version{Path: path, Version: vers})
+               }
+
+               n := modGraph[module.Version{Path: path, Version: vers}]
                required := n.required
                for _, r := range required {
                        v := min[r.Path]
                        if r.Path != target.Path && reqs.Max(v, r.Version) != v {
                                panic(fmt.Sprintf("mistake: version %q does not satisfy requirement %+v", v, r)) // TODO: Don't panic.
                        }
-                       if !listed[r.Path] {
-                               list = append(list, module.Version{Path: r.Path, Version: v})
-                               listed[r.Path] = true
-                       }
                }
        }
 
@@ -289,12 +288,12 @@ func Req(target module.Version, list []module.Version, base []string, reqs Reqs)
        }
 
        // Walk modules in reverse post-order, only adding those not implied already.
-       have := map[string]string{}
+       have := map[module.Version]bool{}
        walk = func(m module.Version) error {
-               if v, ok := have[m.Path]; ok && reqs.Max(m.Version, v) == v {
+               if have[m] {
                        return nil
                }
-               have[m.Path] = m.Version
+               have[m] = true
                for _, m1 := range reqCache[m] {
                        walk(m1)
                }
@@ -322,7 +321,7 @@ func Req(target module.Version, list []module.Version, base []string, reqs Reqs)
                        // Older version.
                        continue
                }
-               if have[m.Path] != m.Version {
+               if !have[m] {
                        min = append(min, m)
                        walk(m)
                }
index cab4bb241bc701fcee70af4712e4285db2eef1e8..72d3ea95b7964f12e1a0eb45e99bf84b835fe111 100644 (file)
@@ -29,7 +29,7 @@ D5: E2
 G1: C4
 A2: B1 C4 D4
 build A: A B1 C2 D4 E2 F1
-upgrade* A: A B1 C4 D5 E2 G1
+upgrade* A: A B1 C4 D5 E2 F1 G1
 upgrade A C4: A B1 C4 D4 E2 F1 G1
 downgrade A2 D2: A2 C4 D2
 
@@ -38,7 +38,7 @@ A: B1 C2
 B1: D3
 C2: B2
 B2:
-build A: A B2 C2
+build A: A B2 C2 D3
 
 # Cross-dependency between D and E.
 # No matter how it arises, should get result of merging all build lists via max,
@@ -157,7 +157,18 @@ D1: E2
 E1: D2
 build A: A B C D2 E2
 
-# Upgrade from B1 to B2 should drop the transitive dep on D.
+# golang.org/issue/31248:
+# Even though we select X2, the requirement on I1
+# via X1 should be preserved.
+name: cross8
+M: A1 B1
+A1: X1
+B1: X2
+X1: I1
+X2: 
+build M: M A1 B1 I1 X2
+
+# Upgrade from B1 to B2 should not drop the transitive dep on D.
 name: drop
 A: B1 C1
 B1: D1
@@ -165,14 +176,14 @@ B2:
 C2:
 D2:
 build A: A B1 C1 D1
-upgrade* A: A B2 C2
+upgrade* A: A B2 C2 D2
 
 name: simplify
 A: B1 C1
 B1: C2
 C1: D1
 C2:
-build A: A B1 C2
+build A: A B1 C2 D1
 
 name: up1
 A: B1 C1
@@ -254,8 +265,9 @@ build A: A B1
 upgrade A B2: A B2
 upgrade* A: A B3
 
+# golang.org/issue/29773:
 # Requirements of older versions of the target
-# must not be carried over.
+# must be carried over.
 name: cycle2
 A: B1
 A1: C1
@@ -265,8 +277,8 @@ B2: A2
 C1: A2
 C2:
 D2:
-build A: A B1
-upgrade* A: A B2
+build A: A B1 C1 D1
+upgrade* A: A B2 C2 D2
 
 # Requirement minimization.
 
@@ -283,6 +295,14 @@ H1: G1
 req A: G1
 req A G: G1
 req A H: H1
+
+name: req3
+M: A1 B1
+A1: X1
+B1: X2
+X1: I1
+X2: 
+req M: A1 B1
 `
 
 func Test(t *testing.T) {
index eed2d437c99efd15b0396ce17151dcf920d6e097..95000011d83b48791350bd7316c782841576f6ca 100644 (file)
@@ -843,7 +843,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
        if !cfg.BuildN {
                // writeTestmain writes _testmain.go,
                // using the test description gathered in t.
-               if err := ioutil.WriteFile(testDir+"_testmain.go", pmain.Internal.TestmainGo, 0666); err != nil {
+               if err := ioutil.WriteFile(testDir+"_testmain.go", *pmain.Internal.TestmainGo, 0666); err != nil {
                        return nil, nil, nil, err
                }
        }
@@ -1250,6 +1250,15 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo
                return false
        }
 
+       if a.Package.Root == "" {
+               // Caching does not apply to tests outside of any module, GOPATH, or GOROOT.
+               if cache.DebugTest {
+                       fmt.Fprintf(os.Stderr, "testcache: caching disabled for package outside of module root, GOPATH, or GOROOT: %s\n", a.Package.ImportPath)
+               }
+               c.disableCache = true
+               return false
+       }
+
        var cacheArgs []string
        for _, arg := range testArgs {
                i := strings.Index(arg, "=")
@@ -1437,8 +1446,8 @@ func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error)
                        if !filepath.IsAbs(name) {
                                name = filepath.Join(pwd, name)
                        }
-                       if !inDir(name, a.Package.Root) {
-                               // Do not recheck files outside the GOPATH or GOROOT root.
+                       if a.Package.Root == "" || !inDir(name, a.Package.Root) {
+                               // Do not recheck files outside the module, GOPATH, or GOROOT root.
                                break
                        }
                        fmt.Fprintf(h, "stat %s %x\n", name, hashStat(name))
@@ -1446,8 +1455,8 @@ func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error)
                        if !filepath.IsAbs(name) {
                                name = filepath.Join(pwd, name)
                        }
-                       if !inDir(name, a.Package.Root) {
-                               // Do not recheck files outside the GOPATH or GOROOT root.
+                       if a.Package.Root == "" || !inDir(name, a.Package.Root) {
+                               // Do not recheck files outside the module, GOPATH, or GOROOT root.
                                break
                        }
                        fh, err := hashOpen(name)
index 55da960c025e6168af111c44c09444ce2fbec413..0e7deef1491a9c4d022ff0ff6b86341d4a7b0cb4 100644 (file)
@@ -103,6 +103,11 @@ func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) {
 }
 
 func (x *elfExe) DataStart() uint64 {
+       for _, s := range x.f.Sections {
+               if s.Name == ".go.buildinfo" {
+                       return s.Addr
+               }
+       }
        for _, p := range x.f.Progs {
                if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_X|elf.PF_W) == elf.PF_W {
                        return p.Vaddr
@@ -208,7 +213,13 @@ func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) {
 }
 
 func (x *machoExe) DataStart() uint64 {
-       // Assume data is first non-empty writable segment.
+       // Look for section named "__go_buildinfo".
+       for _, sec := range x.f.Sections {
+               if sec.Name == "__go_buildinfo" {
+                       return sec.Addr
+               }
+       }
+       // Try the first non-empty writable segment.
        const RW = 3
        for _, load := range x.f.Loads {
                seg, ok := load.(*macho.Segment)
index ed5a149da355f82fb4e0d6219b8b3c11f19ca255..9305b2d859c549356f1e0739aeb2d9e7e29bc4e3 100644 (file)
@@ -30,6 +30,8 @@ along with their dependencies, but it does not install the results.
 If the arguments to build are a list of .go files from a single directory,
 build treats them as a list of source files specifying a single package.
 
+When compiling packages, build ignores files that end in '_test.go'.
+
 When compiling a single main package, build writes
 the resulting executable to an output file named after
 the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
@@ -40,8 +42,6 @@ When compiling multiple packages or a single non-main package,
 build compiles the packages but discards the resulting object,
 serving only as a check that the packages can be built.
 
-When compiling packages, build ignores files that end in '_test.go'.
-
 The -o flag forces build to write the resulting executable or object
 to the named output file or directory, instead of the default behavior described
 in the last two paragraphs. If the named output is a directory that exists,
index 5ff9337afec0ab4bc3aa1a8b9d3d3312abff9693..27bde8c6151e4a8df31173563ccfe1d2c8d42a53 100644 (file)
@@ -203,8 +203,9 @@ func (b *Builder) toolID(name string) string {
                // On the development branch, use the content ID part of the build ID.
                id = contentID(f[len(f)-1])
        } else {
-               // For a release, the output is like: "compile version go1.9.1". Use the whole line.
-               id = f[2]
+               // For a release, the output is like: "compile version go1.9.1 X:framepointer".
+               // Use the whole line.
+               id = strings.TrimSpace(line)
        }
 
        b.id.Lock()
index 8e92f9461cf19d84f03b3a8034a7d6bfefdeb3b7..c666026213bf1a1a119655e9507783f70c870316 100644 (file)
@@ -542,15 +542,6 @@ func (b *Builder) build(a *Action) (err error) {
                }
        }
 
-       // Write out the _testinginit.go file for any test packages that import "testing".
-       if a.Package.Internal.TestinginitGo != nil {
-               initfile := objdir + "_testinginit.go"
-               if err := b.writeFile(initfile, a.Package.Internal.TestinginitGo); err != nil {
-                       return err
-               }
-               gofiles = append([]string{initfile}, gofiles...)
-       }
-
        // Run cgo.
        if a.Package.UsesCgo() || a.Package.UsesSwig() {
                // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
index a4e5507f2cd92ca6aba8cb9cde5769654f068665..ddf613d870126ca62b6402718b2f1e466c77e4af 100644 (file)
@@ -1,19 +1,16 @@
-// Copyright 2019 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 flag_test
 
 import (
        "flag"
+       "log"
        "testing"
 )
 
 var v = flag.Int("v", 0, "v flag")
 
-// Run this as go test pkg -args -v=7
+// Run this as go test pkg -v=7
 func TestVFlagIsSet(t *testing.T) {
        if *v != 7 {
-               t.Fatal("v flag not set")
+               log.Fatal("v flag not set")
        }
 }
index da19ebd9ec9060cb16d1062699232979b7dd9ed1..36bc2c67266e0c7906e9fd4e7ba5964b3b1a328b 100644 (file)
@@ -1,7 +1,7 @@
 example.com/badchain/c v1.1.0
 
 -- .mod --
-module example.com/badchain/wrong
+module badchain.example.com/c
 -- .info --
 {"Version":"v1.1.0"}
 -- c.go --
index 89e3ff0f1ec377116f1b1010783587a9240d1fbe..0d94bf61a9a3a772c27553de2cfa22bb16def539 100644 (file)
@@ -1,4 +1,5 @@
 env GO111MODULE=off
+env GODEBUG=gocachetest=1
 
 [!gc] skip
 [short] skip # clears cache, rebuilds too much
@@ -32,7 +33,7 @@ stderr 'main.go:2.* can inline main' # from compiler
 stderr '\d+ symbols' # from linker
 
 # Running a test should run the compiler, linker, and the test the first time.
-go test -v -x -gcflags=-m -ldflags=-v p_test.go
+go test -v -x -gcflags=-m -ldflags=-v p
 stderr 'compile( |\.exe"?)'
 stderr 'p_test.go:.*can inline Test' # from compile of p_test
 stderr 'testmain\.go:.*inlin' # from compile of testmain
@@ -42,7 +43,7 @@ stderr 'p\.test( |\.exe"?)'
 stdout 'TEST' # from test
 
 # ... but not the second, even though it still prints the compiler, linker, and test output.
-go test -v -x -gcflags=-m -ldflags=-v p_test.go
+go test -v -x -gcflags=-m -ldflags=-v p
 ! stderr 'compile( |\.exe"?)'
 stderr 'p_test.go:.*can inline Test' # from compile of p_test
 stderr 'testmain\.go:.*inlin' # from compile of testmain
@@ -60,7 +61,7 @@ func f(x *int) *int { return x }
 package main
 func main() {}
 
--- p_test.go --
+-- p/p_test.go --
 package p
 import "testing"
 func Test(t *testing.T) {println("TEST")}
diff --git a/libgo/go/cmd/go/testdata/script/cmd_import_error.txt b/libgo/go/cmd/go/testdata/script/cmd_import_error.txt
new file mode 100644 (file)
index 0000000..ba94f9b
--- /dev/null
@@ -0,0 +1,16 @@
+env GO111MODULE=on
+
+# Regression test for golang.org/issue/31031:
+# Importing or loading a non-existent package in cmd/ should print
+# a clear error in module mode.
+
+! go list cmd/unknown
+stderr '^can''t load package: package cmd/unknown: package cmd/unknown is not in GOROOT \('$GOROOT'[/\\]src[/\\]cmd[/\\]unknown\)$'
+
+go list -f '{{range .DepsErrors}}{{.Err}}{{end}}' x.go
+stdout '^package cmd/unknown is not in GOROOT \('$GOROOT'[/\\]src[/\\]cmd[/\\]unknown\)$'
+
+-- x.go --
+package x
+
+import _ "cmd/unknown"
index 40acbc5ac083b48b0e60825bc1e0eb4718c7f48e..d7aa553c1d3ba16428c0190d8f5d8251142573bf 100644 (file)
@@ -3,6 +3,7 @@
 env GO111MODULE=on
 [short] skip
 
+# Check when module x is inside GOPATH/src.
 go doc y
 stdout 'Package y is.*alphabet'
 stdout 'import "x/y"'
@@ -16,13 +17,25 @@ stdout 'Hello returns a greeting'
 go doc quote
 stdout 'Package quote collects pithy sayings.'
 
-# Double-check go doc y when y is not in GOPATH/src.
-env GOPATH=$WORK/altgopath
+# Double-check when module x is outside GOPATH/src.
+env GOPATH=$WORK/emptygopath
 go doc x/y
 stdout 'Package y is.*alphabet'
 go doc y
 stdout 'Package y is.*alphabet'
 
+# Triple-check when module x is outside GOPATH/src,
+# but other packages with same import paths are in GOPATH/src.
+# Since go doc is running in module mode here, packages in active module
+# should be preferred over packages in GOPATH. See golang.org/issue/28992.
+env GOPATH=$WORK/gopath2
+go doc x/y
+! stdout 'Package y is.*GOPATH'
+stdout 'Package y is.*alphabet'
+go doc rsc.io/quote
+! stdout 'Package quote is located in a GOPATH workspace.'
+stdout 'Package quote collects pithy sayings.'
+
 -- go.mod --
 module x
 require rsc.io/quote v1.5.2
@@ -33,3 +46,13 @@ package y
 
 -- x.go --
 package x
+
+-- $WORK/gopath2/src/x/y/y.go --
+// Package y is located in a GOPATH workspace.
+package y
+-- $WORK/gopath2/src/rsc.io/quote/quote.go --
+// Package quote is located in a GOPATH workspace.
+package quote
+
+// Hello is located in a GOPATH workspace.
+func Hello() string { return "" }
diff --git a/libgo/go/cmd/go/testdata/script/mod_dot.txt b/libgo/go/cmd/go/testdata/script/mod_dot.txt
new file mode 100644 (file)
index 0000000..c90074d
--- /dev/null
@@ -0,0 +1,36 @@
+env GO111MODULE=on
+
+# golang.org/issue/32917 and golang.org/issue/28459: 'go build' and 'go test'
+# in an empty directory should refer to the path '.' and should not attempt
+# to resolve an external module.
+cd dir
+! go get .
+stderr 'go get \.: path .* is not a package in module rooted at .*[/\\]dir$'
+! go list
+! stderr 'cannot find module providing package'
+stderr '^can.t load package: package \.: no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir$'
+
+cd subdir
+! go list
+! stderr 'cannot find module providing package'
+stderr '^can.t load package: package \.: no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]subdir$'
+cd ..
+
+# golang.org/issue/30590: if a package is found in the filesystem
+# but is not in the main module, the error message should not say
+# "cannot find module providing package", and we shouldn't try
+# to find a module providing the package.
+! go list ./othermodule
+! stderr 'cannot find module providing package'
+stderr 'go: directory othermodule is outside main module'
+
+-- dir/go.mod --
+module example.com
+go 1.13
+-- dir/subdir/README --
+There are no Go source files in this directory.
+-- dir/othermodule/go.mod --
+module example.com/othermodule
+go 1.13
+-- dir/othermodule/om.go --
+package othermodule
index c6729c71a299db0af28439283f04bc724b9ceb6a..9eb3140c3328a00b0ac87732ad264059044fd6c3 100644 (file)
@@ -17,6 +17,7 @@ stderr 'this.domain.is.invalid'
 stdout '"Error": ".*this.domain.is.invalid.*"'
 
 # download -json with version should print JSON
+# and download the .info file for the 'latest' version.
 go mod download -json 'rsc.io/quote@<=v1.5.0'
 stdout '^\t"Path": "rsc.io/quote"'
 stdout '^\t"Version": "v1.5.0"'
@@ -27,13 +28,14 @@ stdout '^\t"Sum": "h1:6fJa6E\+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE="'  # hash of
 stdout '^\t"GoModSum": "h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe\+TKr0="'
 ! stdout '"Error"'
 
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info
+
 # download queries above should not have added to go.mod.
 go list -m all
 ! stdout rsc.io
 
 # add to go.mod so we can test non-query downloads
 go mod edit -require rsc.io/quote@v1.5.2
-! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info
 ! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
 ! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
 
@@ -83,6 +85,16 @@ exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip
 go mod download -json rsc.io/quote@v1.5.1
 exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.zip
 
+# download reports errors encountered when locating modules
+! go mod download bad/path
+stderr '^module bad/path: not a known dependency$'
+! go mod download bad/path@latest
+stderr '^bad/path@latest: malformed module path "bad/path": missing dot in first path element$'
+! go mod download rsc.io/quote@v1.999.999
+stderr '^rsc.io/quote@v1.999.999: reading .*/v1.999.999.info: 404 Not Found$'
+! go mod download -json bad/path
+stdout '^\t"Error": "module bad/path: not a known dependency"'
+
 # allow go mod download without go.mod
 env GO111MODULE=auto
 rm go.mod
diff --git a/libgo/go/cmd/go/testdata/script/mod_download_latest.txt b/libgo/go/cmd/go/testdata/script/mod_download_latest.txt
new file mode 100644 (file)
index 0000000..60d860e
--- /dev/null
@@ -0,0 +1,20 @@
+env GO111MODULE=on
+
+# If the module is the latest version of itself,
+# the Latest field should be set.
+go mod download -json rsc.io/quote@v1.5.2
+stdout '"Latest":\s*true'
+
+# If the module is older than latest, the field should be unset.
+go mod download -json rsc.io/quote@v1.5.1
+! stdout '"Latest":'
+
+# If the module is newer than "latest", the field should be unset...
+go mod download -json rsc.io/quote@v1.5.3-pre1
+! stdout '"Latest":'
+
+# ...even if that version is also what is required by the main module.
+go mod init example.com
+go mod edit -require rsc.io/quote@v1.5.3-pre1
+go mod download -json rsc.io/quote@v1.5.3-pre1
+! stdout '"Latest":'
index 9341a1d08305f83d95a6a89064f5106a59f559b0..fd7de13002410325e21975c4cc3e32051309709b 100644 (file)
@@ -34,11 +34,11 @@ stderr 'import lookup disabled'
 
 ! go build -mod=readonly ./nonexist
 ! stderr 'import lookup disabled'
-stderr 'unknown import path "m/nonexist": cannot find package'
+stderr '^can.t load package: package ./nonexist: cannot find package "." in:\n\t'$WORK'[/\\]gopath[/\\]src[/\\]x[/\\]nonexist$'
 
 ! go build -mod=readonly ./go.mod
 ! stderr 'import lookup disabled'
-stderr 'unknown import path "m/go.mod": cannot find package'
+stderr 'can.t load package: package ./go.mod: cannot find package'
 
 -- x/go.mod --
 module m
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_fallback.txt b/libgo/go/cmd/go/testdata/script/mod_get_fallback.txt
new file mode 100644 (file)
index 0000000..a9834a3
--- /dev/null
@@ -0,0 +1,10 @@
+env GO111MODULE=on
+
+[!net] skip
+
+env GOPROXY=https://proxy.golang.org,direct
+env GOSUMDB=off
+
+go get -x -v -d golang.org/x/tools/cmd/goimports
+stderr '# get https://proxy.golang.org/golang.org/x/tools/@latest'
+! stderr '# get https://golang.org'
index 8e06220f9e6e80fdbd88c9745db2f4c989094bb1..403abcd28ba454cd03658f9572c95562fad87629 100644 (file)
@@ -4,13 +4,19 @@ env GO111MODULE=on
 # @patch and @latest within the main module refer to the current version.
 # The main module won't be upgraded, but missing dependencies will be added.
 cp go.mod.orig go.mod
-go get -d rsc.io/x@latest
+go get -d rsc.io/x
+grep 'rsc.io/quote v1.5.2' go.mod
+go get -d rsc.io/x@upgrade
 grep 'rsc.io/quote v1.5.2' go.mod
 cp go.mod.orig go.mod
 go get -d rsc.io/x@patch
 grep 'rsc.io/quote v1.5.2' go.mod
 cp go.mod.orig go.mod
 
+# The main module cannot be updated to @latest, which is a specific version.
+! go get -d rsc.io/x@latest
+stderr '^go get rsc.io/x@latest: can.t request explicit version of path in main module$'
+
 # The main module cannot be updated to a specific version.
 ! go get rsc.io/x@v0.1.0
 stderr '^go get rsc.io/x@v0.1.0: can.t request explicit version of path in main module$'
index 9616863383dae74cedc7f4a230a9d5066dffa7bd..b1838f824a6353aa3e6f0c89cd2c614bf8a71c5c 100644 (file)
@@ -1,6 +1,7 @@
 env GO111MODULE=on
 
 # Download modules to avoid stderr chatter
+go mod download example.com@v1.0.0
 go mod download example.com/newcycle/a@v1.0.0
 go mod download example.com/newcycle/a@v1.0.1
 go mod download example.com/newcycle/b@v1.0.0
@@ -10,5 +11,6 @@ go mod init m
 cmp stderr stderr-expected
 
 -- stderr-expected --
+go: finding example.com/newcycle v1.0.0
 go get: inconsistent versions:
        example.com/newcycle/a@v1.0.0 requires example.com/newcycle/a@v1.0.1 (not example.com/newcycle/a@v1.0.0)
index b9931970e0d9f232d2edee8cac6ee4b7a8d823fa..bfab70090cfaaa661bbb29f9f4535ff58d6d7997 100644 (file)
@@ -10,11 +10,11 @@ grep 'require rsc.io/quote' go.mod
 
 cp go.mod.orig go.mod
 ! go get -d rsc.io/quote/x...
-stderr 'go get rsc.io/quote/x...: module rsc.io/quote@latest \(v1.5.2\) found, but does not contain packages matching rsc.io/quote/x...'
+stderr 'go get rsc.io/quote/x...: module rsc.io/quote@upgrade \(v1.5.2\) found, but does not contain packages matching rsc.io/quote/x...'
 ! grep 'require rsc.io/quote' go.mod
 
 ! go get -d rsc.io/quote/x/...
-stderr 'go get rsc.io/quote/x/...: module rsc.io/quote@latest \(v1.5.2\) found, but does not contain packages matching rsc.io/quote/x/...'
+stderr 'go get rsc.io/quote/x/...: module rsc.io/quote@upgrade \(v1.5.2\) found, but does not contain packages matching rsc.io/quote/x/...'
 ! grep 'require rsc.io/quote' go.mod
 
 # If a pattern matches no packages within a module, the module should not
index b3436284aff02712180feb861377f41d40d24a12..cd19d99dbccbbf27076af73c02b417118291ebc2 100644 (file)
@@ -2,19 +2,26 @@
 [!exec:svn] skip
 
 env GO111MODULE=on
-env GOPROXY=direct # obtain llvm.org directory, not via svn.
+env GOPROXY=direct
+env GOSUMDB=off
 
 # Attempting to get a module zip using svn should fail with a reasonable
 # message instead of a panic.
 # TODO(golang.org/issue/26092): Really, it shouldn't fail at all.
-! go get -d llvm.org/llvm/bindings/go/llvm
+! go get -d vcs-test.golang.org/svn/hello.svn
 stderr 'ReadZip not implemented for svn'
 ! go install .
 stderr 'ReadZip not implemented for svn'
 
+# Attempting to get a nonexistent module using svn should fail with a
+# reasonable message instead of a panic.
+! go get -d vcs-test.golang.org/svn/nonexistent.svn
+! stderr panic
+stderr 'go get vcs-test.golang.org/svn/nonexistent.svn: no matching versions for query "upgrade"'
+
 -- go.mod --
 module golang/go/issues/28943/main
 -- main.go --
 package main
-import _ "llvm.org/llvm/bindings/go/llvm"
+import _ "vcs-test.golang.org/svn/hello.svn"
 func main() {}
index 9184d85f7f3ec1ecfe6bb76a8813cfeccee295b5..f5f415aa3fae25e66ec10e62a04469c14c115157 100644 (file)
@@ -9,18 +9,33 @@ env GO111MODULE=on
 # The v0.1.1 pseudo-version is semantically higher than the latest tag.
 # The v0.0.0 pseudo-version is chronologically newer.
 
-# 'get -u' should not downgrade to the (lower) tagged version.
+# Start at v0.1.1-0.20190429073117-b5426c86b553
 go get -d example.com/pseudoupgrade@b5426c8
+go list -m -u all
+stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$'
+
+# 'get -u' should not downgrade to the (lower) tagged version.
 go get -d -u
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$'
 
-# 'get example.com/pseudoupgrade@latest' should not downgrade to
-# the (lower) tagged version.
-go get -d example.com/pseudoupgrade@latest
+# 'get example.com/pseudoupgrade@upgrade' should not downgrade.
+go get -d example.com/pseudoupgrade@upgrade
 go list -m all
 stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$'
 
+# 'get example.com/pseudoupgrade' should not downgrade.
+# This is equivalent to 'get example.com/pseudoupgrade@upgrade'.
+go get -d example.com/pseudoupgrade
+go list -m all
+stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$'
+
+# 'get example.com/pseudoupgrade@latest' should downgrade.
+# @latest should not consider the current version.
+go get -d example.com/pseudoupgrade@latest
+go list -m all
+stdout '^example.com/pseudoupgrade v0.1.0$'
+
 # We should observe the same behavior with the newer pseudo-version.
 go get -d example.com/pseudoupgrade@v0.0.0-20190430073000-30950c05d534
 
@@ -29,12 +44,21 @@ go get -d -u
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$'
 
-# 'get example.com/pseudoupgrade@latest' should not downgrade to the
-# chronologically older tagged version.
-go get -d example.com/pseudoupgrade@latest
+# 'get example.com/pseudoupgrade@upgrade should not downgrade.
+go get -d example.com/pseudoupgrade@upgrade
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$'
 
+# 'get example.com/pseudoupgrade' should not downgrade.
+go get -d example.com/pseudoupgrade
+go list -m -u all
+stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$'
+
+# 'get example.com/pseudoupgrade@latest' should downgrade.
+go get -d example.com/pseudoupgrade@latest
+go list -m -u all
+stdout '^example.com/pseudoupgrade v0.1.0$'
+
 -- go.mod --
 module x
 
index a4eb5d6596f49f50a5f87dbd949d68bfc05bae84..ae05250c5f695bfe80e914d0994cf319ad6dacc4 100644 (file)
@@ -62,15 +62,31 @@ import (
        "go/build"
        "log"
        "os"
+       "path/filepath"
        "strings"
 )
 
 func main() {
-       p, err := build.Import(os.Args[1], os.Args[2], 0)
+       // build.Import should support relative and absolute source dir paths.
+       path := os.Args[1]
+       srcDir := os.Args[2]
+       p1, err := build.Import(path, srcDir, 0)
        if err != nil {
                log.Fatal(err)
        }
-       fmt.Printf("%s\n%s\n", p.Dir, strings.Join(p.GoFiles, " "))
+       absSrcDir, err := filepath.Abs(srcDir)
+       if err != nil {
+               log.Fatal(err)
+       }
+       p2, err := build.Import(path, absSrcDir, 0)
+       if err != nil {
+               log.Fatal(err)
+       }
+       if p1.Dir != p2.Dir {
+               log.Fatalf("different packages loaded with relative and absolute paths:\n\t%s\n\t%s", p1.Dir, p2.Dir)
+       }
+
+       fmt.Printf("%s\n%s\n", p1.Dir, strings.Join(p1.GoFiles, " "))
 }
 
 -- $GOPATH/other/go.mod --
diff --git a/libgo/go/cmd/go/testdata/script/mod_indirect.txt b/libgo/go/cmd/go/testdata/script/mod_indirect.txt
new file mode 100644 (file)
index 0000000..87a3f0b
--- /dev/null
@@ -0,0 +1,81 @@
+env GO111MODULE=on
+
+# golang.org/issue/31248: module requirements imposed by dependency versions
+# older than the selected version must still be taken into account.
+
+env GOFLAGS=-mod=readonly
+
+# Indirect dependencies required via older-than-selected versions must exist in
+# the module graph, but do not need to be listed explicitly in the go.mod file
+# (since they are implied).
+go mod graph
+stdout i@v0.1.0
+
+# The modules must also appear in the build list, not just the graph.
+go list -m all
+stdout '^i v0.1.0'
+
+# The packages provided by those dependencies must resolve.
+go list all
+stdout '^i$'
+
+-- go.mod --
+module main
+
+go 1.13
+
+require (
+       a v0.0.0
+       b v0.0.0
+       c v0.0.0
+)
+
+// Apply replacements so that the test can be self-contained.
+// (It's easier to see all of the modules here than to go
+// rooting around in testdata/mod.)
+replace (
+       a => ./a
+       b => ./b
+       c => ./c
+       x v0.1.0 => ./x1
+       x v0.2.0 => ./x2
+       i => ./i
+)
+-- main.go --
+package main
+
+import (
+       _ "a"
+       _ "b"
+       _ "c"
+)
+
+func main() {}
+-- a/go.mod --
+module a
+go 1.13
+require x v0.1.0
+-- a/a.go --
+package a
+-- b/go.mod --
+module b
+go 1.13
+require x v0.2.0
+-- b/b.go --
+package b
+-- c/go.mod --
+module c
+go 1.13
+-- c/c.go --
+package c
+import _ "i"
+-- x1/go.mod --
+module x
+go1.13
+require i v0.1.0
+-- x2/go.mod --
+module x
+go1.13
+-- i/go.mod --
+-- i/i.go --
+package i
diff --git a/libgo/go/cmd/go/testdata/script/mod_indirect_main.txt b/libgo/go/cmd/go/testdata/script/mod_indirect_main.txt
new file mode 100644 (file)
index 0000000..eeb93f1
--- /dev/null
@@ -0,0 +1,65 @@
+env GO111MODULE=on
+
+# Regression test for golang.org/issue/29773: 'go list -m' was not following
+# dependencies through older versions of the main module.
+
+go list -f '{{with .Module}}{{.Path}}{{with .Version}} {{.}}{{end}}{{end}}' all
+cmp stdout pkgmods.txt
+
+go list -m all
+cmp stdout mods.txt
+
+go mod graph
+cmp stdout graph.txt
+
+-- go.mod --
+module golang.org/issue/root
+
+go 1.12
+
+replace (
+       golang.org/issue/mirror v0.1.0 => ./mirror-v0.1.0
+       golang.org/issue/pkg v0.1.0 => ./pkg-v0.1.0
+       golang.org/issue/root v0.1.0 => ./root-v0.1.0
+)
+
+require golang.org/issue/mirror v0.1.0
+
+-- root.go --
+package root
+
+import _ "golang.org/issue/mirror"
+
+-- mirror-v0.1.0/go.mod --
+module golang.org/issue/mirror
+
+require golang.org/issue/root v0.1.0
+
+-- mirror-v0.1.0/mirror.go --
+package mirror
+
+import _ "golang.org/issue/pkg"
+
+-- pkg-v0.1.0/go.mod --
+module golang.org/issue/pkg
+
+-- pkg-v0.1.0/pkg.go --
+package pkg
+
+-- root-v0.1.0/go.mod --
+module golang.org/issue/root
+
+require golang.org/issue/pkg v0.1.0
+
+-- pkgmods.txt --
+golang.org/issue/mirror v0.1.0
+golang.org/issue/pkg v0.1.0
+golang.org/issue/root
+-- mods.txt --
+golang.org/issue/root
+golang.org/issue/mirror v0.1.0 => ./mirror-v0.1.0
+golang.org/issue/pkg v0.1.0 => ./pkg-v0.1.0
+-- graph.txt --
+golang.org/issue/root golang.org/issue/mirror@v0.1.0
+golang.org/issue/mirror@v0.1.0 golang.org/issue/root@v0.1.0
+golang.org/issue/root@v0.1.0 golang.org/issue/pkg@v0.1.0
diff --git a/libgo/go/cmd/go/testdata/script/mod_indirect_tidy.txt b/libgo/go/cmd/go/testdata/script/mod_indirect_tidy.txt
new file mode 100644 (file)
index 0000000..a12b35c
--- /dev/null
@@ -0,0 +1,60 @@
+env GO111MODULE=on
+
+# golang.org/issue/31248: loading the build list must not add explicit entries
+# for indirect dependencies already implied by older-than-selected versions
+# already in the build list.
+
+cp go.mod.orig go.mod
+go mod tidy
+cmp go.mod go.mod.orig
+
+cp go.mod.orig go.mod
+go list -m all
+cmp go.mod go.mod.orig
+
+-- go.mod.orig --
+module main
+
+go 1.13
+
+require a v0.0.0
+
+replace (
+       a v0.0.0 => ./a
+       b v0.0.0 => ./b
+       i v0.0.0 => ./i
+       x v0.1.0 => ./x1
+       x v0.2.0 => ./x2
+)
+-- main.go --
+package main
+
+import _ "a"
+
+func main() {}
+-- a/go.mod --
+module a
+go 1.13
+require (
+       x v0.2.0
+       b v0.0.0
+)
+-- a/a.go --
+package a
+-- b/go.mod --
+module b
+go 1.13
+require x v0.1.0
+-- x1/go.mod --
+module x
+go 1.13
+require (
+       b v0.0.0
+       i v0.0.0
+)
+-- x2/go.mod --
+module x
+go 1.13
+-- i/go.mod --
+module i
+go 1.13
index 2be0d01cce95d124a5077e9f8b83e90a8b1c3026..76e0b43a735e47ffd6411771660c2fd6841538ae 100644 (file)
@@ -134,6 +134,19 @@ cd ..
 go list -m golang.org/x/text
 stdout 'golang.org/x/text v0.0.0-0.20170915032832-14c0d48ead0c => golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c'
 
+# A 'replace' directive can replace an invalid 'latest' version, and
+# should suppress errors for that version in 'go get -u'
+cp go.mod.orig go.mod
+go mod edit -require golang.org/x/text@v1.999999.0
+go mod edit -replace golang.org/x/text@v1.999999.0=golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c
+cd outside
+! go get -d golang.org/x/text@upgrade
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.999999.0: reading golang.org/x/text/go.mod at revision v1.999999.0: unknown revision v1.999999.0'
+cd ..
+go get -d golang.org/x/text@upgrade
+go list -m golang.org/x/text
+stdout 'golang.org/x/text v1.999999.0 => golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c'
+
 # A pseudo-version derived from a non-ancestor tag is invalid.
 cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c
@@ -144,6 +157,16 @@ cd ..
 ! go list -m golang.org/x/text
 stderr 'golang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c: invalid pseudo-version: revision 14c0d48ead0c is not a descendent of preceding tag \(v0.2.0\)'
 
+# A pseudo-version derived from a canonical tag on the same revision is invalid.
+cp go.mod.orig go.mod
+go mod edit -require golang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac
+cd outside
+! go list -m golang.org/x/text
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac: invalid pseudo-version: tag \(v0.2.0\) found on revision c4d099d611ac is already canonical, so should not be replaced with a pseudo-version derived from that tag'
+cd ..
+! go list -m golang.org/x/text
+stderr 'golang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac: invalid pseudo-version: tag \(v0.2.0\) found on revision c4d099d611ac is already canonical, so should not be replaced with a pseudo-version derived from that tag'
+
 # A +incompatible suffix is not allowed on a version that is actually compatible.
 cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c+incompatible
@@ -165,15 +188,15 @@ go list -m github.com/pierrec/lz4
 stdout 'github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1'
 cd ..
 
-# A +incompatible version for a module that has an explicit go.mod file is invalid.
+# A +incompatible pseudo-version for a module that has an explicit go.mod file is invalid.
 cp go.mod.orig go.mod
-go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190131084431-473cd7ce01a1+incompatible
+go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible
 cd outside
 ! go list -m github.com/pierrec/lz4
-stderr 'go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190131084431-473cd7ce01a1\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr 'go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
 cd ..
 ! go list -m github.com/pierrec/lz4
-stderr 'github.com/pierrec/lz4@v2.0.9-0.20190131084431-473cd7ce01a1\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr 'github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
 
 # A +incompatible pseudo-version is valid for a revision of the module
 # that lacks a go.mod file.
index a15f5bca63540cc40cff161431e6df844f3a7cea..17b33fcc7bf36d22c2cb0ce40868269a9a1675eb 100644 (file)
@@ -34,12 +34,12 @@ go list rsc.io/quote/buggy
 
 # rsc.io/quote/buggy should not be listable as a module
 go list -m -e -f '{{.Error.Err}}' nonexist rsc.io/quote/buggy
-stdout '^module "nonexist" is not a known dependency'
-stdout '^module "rsc.io/quote/buggy" is not a known dependency'
+stdout '^module nonexist: not a known dependency$'
+stdout '^module rsc.io/quote/buggy: not a known dependency$'
 
 ! go list -m nonexist rsc.io/quote/buggy
-stderr '^go list -m nonexist: module "nonexist" is not a known dependency'
-stderr '^go list -m rsc.io/quote/buggy: module "rsc.io/quote/buggy" is not a known dependency'
+stderr '^go list -m: module nonexist: not a known dependency'
+stderr '^go list -m: module rsc.io/quote/buggy: not a known dependency'
 
 # Module loader does not interfere with list -e (golang.org/issue/24149).
 go list -e -f '{{.Error.Err}}' database
diff --git a/libgo/go/cmd/go/testdata/script/mod_list_compiled_concurrent.txt b/libgo/go/cmd/go/testdata/script/mod_list_compiled_concurrent.txt
new file mode 100644 (file)
index 0000000..b08713d
--- /dev/null
@@ -0,0 +1,41 @@
+env GO111MODULE=on
+
+[short] skip
+
+# Regression test for golang.org/issue/29667:
+# spurious 'failed to cache compiled Go files' errors.
+# This test failed reliably when run with -count=10
+# on a Linux workstation.
+
+env GOCACHE=$WORK/gocache
+mkdir $GOCACHE
+
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+go list -json -compiled -test=false -export=false -deps=true -- . &
+
+wait
+
+-- go.mod --
+module sandbox/bar
+-- bar.go --
+package bar
+
+import "C"
index c4db045631155b106f4cd2573aeaf5c602699c14..a8023cce9c5b787c20e5e3b6501c82c3d09f52bb 100644 (file)
@@ -12,9 +12,10 @@ stdout ^math$
 go list -f '{{.ImportPath}}' .
 stdout ^x$
 ! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
-stderr 'unknown import path "rsc.io/quote": cannot find package'
+stderr '^can.t load package: package '$WORK'[/\\]gopath/pkg/mod/rsc.io/quote@v1.5.2: can only use path@version syntax with .go get.'
+
 go list -e -f '{{with .Error}}{{.}}{{end}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
-stdout 'unknown import path "rsc.io/quote": cannot find package'
+stdout '^package '$WORK'[/\\]gopath/pkg/mod/rsc.io/quote@v1.5.2: can only use path@version syntax with .go get.'
 go mod download rsc.io/quote@v1.5.2
 go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
 stdout '^rsc.io/quote$'
diff --git a/libgo/go/cmd/go/testdata/script/mod_list_direct.txt b/libgo/go/cmd/go/testdata/script/mod_list_direct.txt
new file mode 100644 (file)
index 0000000..8f85871
--- /dev/null
@@ -0,0 +1,24 @@
+env GO111MODULE=on
+env GOPROXY=direct
+env GOSUMDB=off
+
+[!net] skip
+[!exec:git] skip
+
+# golang.org/issue/33099: if an import path ends in a major-version suffix,
+# ensure that 'direct' mode can resolve the package to the module.
+# For a while, (*modfetch.codeRepo).Stat was not checking for a go.mod file,
+# which would produce a hard error at the subsequent call to GoMod.
+
+go list all
+
+-- go.mod --
+module example.com
+go 1.13
+
+-- main.go --
+package main
+
+import _ "vcs-test.golang.org/git/v3pkg.git/v3"
+
+func main() {}
index 37de8825e06b460070c2bdd5f7c12eab7be1caf0..d43bbe7f2bcf19abb8dfce2fd3651ba7792e9a1c 100644 (file)
@@ -6,7 +6,7 @@ env GO111MODULE=on
 go mod download
 
 ! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
-stderr 'outside available modules'
+stderr 'can only use path@version syntax with .go get.'
 
 go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.1
 stdout 'rsc.io/quote'
index 474df0dc269e4401bc99875f019fa01c0c080985..f2d06490920151e090821eae5ca8e267ba834ccb 100644 (file)
@@ -1,8 +1,28 @@
 env GO111MODULE=on
 
+# If the current version is not latest, 'go list -u' should include its upgrade.
 go list -m -u all
 stdout 'rsc.io/quote v1.2.0 \[v1\.5\.2\]'
 
+# If the current version is latest, 'go list -u' should omit the upgrade.
+go get -d rsc.io/quote@v1.5.2
+go list -m -u all
+stdout 'rsc.io/quote v1.5.2$'
+
+# If the current version is newer than latest, 'go list -u' should
+# omit the upgrade.
+go get -d rsc.io/quote@v1.5.3-pre1
+go list -m -u all
+stdout 'rsc.io/quote v1.5.3-pre1$'
+
+# If the current build list has a higher version and the user asks about
+# a lower one, -u should report the upgrade for the lower one
+# but leave the build list unchanged.
+go list -m -u rsc.io/quote@v1.5.1
+stdout 'rsc.io/quote v1.5.1 \[v1.5.2\]$'
+go list -m -u rsc.io/quote
+stdout 'rsc.io/quote v1.5.3-pre1$'
+
 -- go.mod --
 module x
 require rsc.io/quote v1.2.0
index 6fdf2c7b6beb4406afddc90a924b51ac5f50f280..b97a2e6eaba2c5bad0202919d5948c9b8b9a5256 100644 (file)
@@ -57,19 +57,29 @@ import (
 func Test(t *testing.T) {}
 -- update-main-expected --
 go get: example.com/badchain/c@v1.0.0 updating to
-       example.com/badchain/c@v1.1.0: parsing go.mod: unexpected module path "example.com/badchain/wrong"
+       example.com/badchain/c@v1.1.0: parsing go.mod:
+       module declares its path as: badchain.example.com/c
+               but was required as: example.com/badchain/c
 -- update-a-expected --
 go get: example.com/badchain/a@v1.1.0 requires
        example.com/badchain/b@v1.1.0 requires
-       example.com/badchain/c@v1.1.0: parsing go.mod: unexpected module path "example.com/badchain/wrong"
+       example.com/badchain/c@v1.1.0: parsing go.mod:
+       module declares its path as: badchain.example.com/c
+               but was required as: example.com/badchain/c
 -- list-expected --
 go: example.com/badchain/a@v1.1.0 requires
        example.com/badchain/b@v1.1.0 requires
-       example.com/badchain/c@v1.1.0: parsing go.mod: unexpected module path "example.com/badchain/wrong"
+       example.com/badchain/c@v1.1.0: parsing go.mod:
+       module declares its path as: badchain.example.com/c
+               but was required as: example.com/badchain/c
 -- list-missing-expected --
 go: m/use imports
-       example.com/badchain/c: example.com/badchain/c@v1.1.0: parsing go.mod: unexpected module path "example.com/badchain/wrong"
+       example.com/badchain/c: example.com/badchain/c@v1.1.0: parsing go.mod:
+       module declares its path as: badchain.example.com/c
+               but was required as: example.com/badchain/c
 -- list-missing-test-expected --
 go: m/testuse tested by
        m/testuse.test imports
-       example.com/badchain/c: example.com/badchain/c@v1.1.0: parsing go.mod: unexpected module path "example.com/badchain/wrong"
+       example.com/badchain/c: example.com/badchain/c@v1.1.0: parsing go.mod:
+       module declares its path as: badchain.example.com/c
+               but was required as: example.com/badchain/c
index c41f83d264c1bfc46510c10d41b3e2d191e5d905..e87ca302f0ca9fb9eed00d8c030f300cc6202355 100644 (file)
@@ -22,7 +22,7 @@ go list -m rsc.io/quote@<v1.5.4
 stdout 'rsc.io/quote v1.5.2$'
 
 ! go list -m rsc.io/quote@>v1.5.3
-stderr 'go list -m rsc.io/quote: no matching versions for query ">v1.5.3"'
+stderr 'go list -m: module rsc.io/quote: no matching versions for query ">v1.5.3"'
 
 go list -m -e -f '{{.Error.Err}}' rsc.io/quote@>v1.5.3
 stdout 'no matching versions for query ">v1.5.3"'
index 4e27c1ee5c8d8db6170c0f5df6b35656d9ac1780..4d8259b40f1a4be6efe05ab0fca35008be71b77d 100644 (file)
@@ -28,6 +28,20 @@ go list -m example.com/join/...
 ! stdout 'example.com/join/subpkg'
 stdout 'example.com/join v1.1.0'
 
+# If the proxy provides an empty @v/list but rejects @latest with
+# some other explicit error (for example, a "permission denied" error),
+# that error should be reported to the user (and override a successful
+# result for other possible module paths).
+#
+# Depending on how the specific platform enforces permissions, the 'go get' may
+# fail either due to the intended permission error or due to a parse error.
+# We accept either failure message.
+env GOPROXY=file:///$WORK/gatekeeper
+chmod 0000 $WORK/gatekeeper/example.com/join/subpkg/@latest
+cp go.mod.orig go.mod
+! go get -d example.com/join/subpkg
+stderr 'go get example.com/join/subpkg: module example.com/join/subpkg: (invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)'
+
 -- go.mod.orig --
 module example.com/othermodule
 go 1.13
@@ -50,3 +64,10 @@ v1.0.0-does-not-exist
 v1.1.0
 -- $WORK/notfound/example.com/join/@v/v1.1.0.info --
 {"Version": "v1.1.0"}
+-- $WORK/gatekeeper/example.com/join/subpkg/@v/list --
+-- $WORK/gatekeeper/example.com/join/subpkg/@latest --
+ERROR: Latest version is forbidden.
+-- $WORK/gatekeeper/example.com/join/@v/list --
+v1.1.0
+-- $WORK/gatekeeper/example.com/join/@v/v1.1.0.info --
+{"Version": "v1.1.0"}
index 8e1f3d7a7b364db6c8897cd39fb3ae23ee8be2ca..641b9e73bcc67f565c9945f5d0359bc6a9ceae9e 100644 (file)
@@ -9,8 +9,8 @@ env dbname=localhost.localdev/sumdb
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb' '$proxy/sumdb-wrong
 ! go get -d rsc.io/quote
-stderr 'verifying rsc.io/quote@v1.5.2/go.mod: checksum mismatch'
-stderr 'downloaded: h1:LzX7'
+stderr 'verifying rsc.io/quote@v1.5.2: checksum mismatch'
+stderr 'downloaded: h1:3fEy'
 stderr 'localhost.localdev/sumdb: h1:wrong'
 stderr 'SECURITY ERROR\nThis download does NOT match the one reported by the checksum server.'
 ! go get -d rsc.io/sampler
index a44a87499a37442a399ee2aeaa203f7059383e3d..486bdf5ecf6c6da4453cf8fa7014104abbe64f29 100644 (file)
@@ -28,7 +28,7 @@ cp go.mod.orig go.mod
 rm go.sum
 env GOPROXY=off
 go get -d rsc.io/quote@v1.5.2 # using cache
-rm $GOPATH/pkg/mod/download/cache/sumdb/localhost.localdev/sumdb/lookup/rsc.io/quote@v1.5.2
+rm $GOPATH/pkg/mod/cache/download/sumdb/localhost.localdev/sumdb/lookup/rsc.io/quote@v1.5.2
 go get -d rsc.io/quote@v1.5.2 # using go.sum
 
 # fetch fails once we lose access to both cache and go.sum
index 744632ec904b0d89329a78c2982edd6e5d0740ca..47c8a3a0f3cf654ee63375c8a88b1565a3ae073e 100644 (file)
@@ -2,6 +2,7 @@
 
 env GO111MODULE=on
 env GOSUMDB=
+env GOPATH=$WORK/gopath1
 
 # With a file-based proxy with an empty checksum directory,
 # downloading a new module should fail, even if a subsequent
@@ -18,11 +19,20 @@ stderr '^verifying golang.org/x/text.*: Not Found'
 [!windows] env GOPROXY=file://$WORK/emptyproxy,https://proxy.golang.org
 go get -d golang.org/x/text@v0.3.2
 
+# After a successful sumdb lookup, the lookup can be repeated
+# using the download cache as a proxy.
+cp supported $GOPATH/pkg/mod/cache/download/sumdb/sum.golang.org/supported
+[windows] env GOPROXY=file:///$WORK/gopath1/pkg/mod/cache/download,file:///$WORK/sumproxy
+[!windows] env GOPROXY=file://$WORK/gopath1/pkg/mod/cache/download,file://$WORK/sumproxy
+env GOPATH=$WORK/gopath2
+rm go.sum
+go get -d -x -v golang.org/x/text@v0.3.2
+
 # Once the checksum is present in the go.sum file,
 # an empty file-based sumdb can be used in conjunction with
 # a fallback module mirror.
 grep golang.org/x/text go.sum
-go clean -modcache
+env GOPATH=$WORK/gopath3
 [windows] env GOPROXY=file:///$WORK/sumproxy
 [!windows] env GOPROXY=file://$WORK/sumproxy
 ! go get -d golang.org/x/text@v0.3.2
@@ -30,6 +40,8 @@ go clean -modcache
 [!windows] env GOPROXY=file://$WORK/sumproxy,https://proxy.golang.org
 go get -d golang.org/x/text@v0.3.2
 
+-- supported --
+
 -- go.mod --
 module example.com
 go 1.13
index 964501f2ee34c21f3455e3b370d7c91e6ec88151..40a07fc7e9fe702094f0d3a46cb2e7595b22d6d3 100644 (file)
@@ -14,31 +14,39 @@ stdout '^sum.golang.org$'
 [!exec:git] skip
 env GOSUMDB=sum.golang.org
 env GOPROXY=direct
-go get -d rsc.io/quote
+go get -d rsc.io/quote@v1.5.2
+cp go.sum saved.sum
 
 # download from proxy.golang.org with go.sum entry already
 go clean -modcache
 env GOSUMDB=
 env GOPROXY=
-go get -x -d rsc.io/quote
+go get -x -d rsc.io/quote@v1.5.2
 ! stderr github
 stderr proxy.golang.org/rsc.io/quote
 ! stderr sum.golang.org/tile
 ! stderr sum.golang.org/lookup/rsc.io/quote
+cmp go.sum saved.sum
 
-# download again, using checksum database to validate new go.sum lines
+# Download again.
+# Should use the checksum database to validate new go.sum lines,
+# but not need to fetch any new data from the proxy.
 rm go.sum
-go get -x -d rsc.io/quote
+go get -x -d rsc.io/quote@v1.5.2
 ! stderr github
-stderr proxy.golang.org/rsc.io/quote
+stderr proxy.golang.org/rsc.io/quote
 stderr sum.golang.org/tile
 stderr sum.golang.org/lookup/rsc.io/quote
+cmp go.sum saved.sum
 
 # test fallback to direct
 env TESTGOPROXY404=1
-go get -x -d rsc.io/quote
+go clean -modcache
+rm go.sum
+go get -x -d rsc.io/quote@v1.5.2
 stderr 'proxy.golang.org.*404 testing'
 stderr github.com/rsc
+cmp go.sum saved.sum
 
 -- go.mod --
 module m
index 6fbf7aeb8a92607e2f9f8ba5e766e28df67ee6aa..28166913fd57189a6f0c16e4d74370ba916a1483 100644 (file)
@@ -6,14 +6,14 @@ env GOPROXY GONOPROXY GOSUMDB GONOSUMDB
 # basic fetch (through proxy) works
 cp go.mod.orig go.mod
 go get -d rsc.io/fortune@v1.0.0 # note: must use test proxy, does not exist in real world
-rm $GOPATH/pkg/mod/download/cache/sumdb # rm sumdb cache but NOT package download cache
+rm $GOPATH/pkg/mod/cache/download/sumdb # rm sumdb cache but NOT package download cache
 rm go.sum
 
 # can fetch by explicit URL
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb' '$proxy/sumdb-direct
 go get -d rsc.io/fortune@v1.0.0
-rm $GOPATH/pkg/mod/download/cache/sumdb
+rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
 
 # direct access fails (because localhost.localdev does not exist)
@@ -25,7 +25,7 @@ env GOSUMDB=$sumdb
 env GOPROXY=direct
 ! go get -d rsc.io/fortune@v1.0.0
 stderr 'verifying.*localhost.localdev'
-rm $GOPATH/pkg/mod/download/cache/sumdb
+rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
 
 # proxy 404 falls back to direct access (which fails)
@@ -34,7 +34,7 @@ env GOSUMDB=$sumdb
 env GOPROXY=$proxy/sumdb-404
 ! go get -d rsc.io/fortune@v1.0.0
 stderr 'verifying.*localhost.localdev'
-rm $GOPATH/pkg/mod/download/cache/sumdb
+rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
 
 # proxy non-200/404/410 stops direct access
@@ -43,7 +43,7 @@ env GOSUMDB=$sumdb
 env GOPROXY=$proxy/sumdb-503
 ! go get -d rsc.io/fortune@v1.0.0
 stderr '503 Service Unavailable'
-rm $GOPATH/pkg/mod/download/cache/sumdb
+rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
 
 -- go.mod.orig --
diff --git a/libgo/go/cmd/go/testdata/script/mod_test_cached.txt b/libgo/go/cmd/go/testdata/script/mod_test_cached.txt
new file mode 100644 (file)
index 0000000..ffd573c
--- /dev/null
@@ -0,0 +1,77 @@
+[short] skip
+
+env GO111MODULE=on
+env GOCACHE=$WORK/gocache
+env GODEBUG=gocachetest=1
+
+# The first run of a test should not be cached.
+# The second run should be.
+go test -run=WriteTmp .
+! stdout '(cached)'
+go test -run=WriteTmp .
+stdout '(cached)'
+
+# 'go test' without arguments should never be cached.
+go test -run=WriteTmp
+! stdout '(cached)'
+go test -run=WriteTmp
+! stdout '(cached)'
+
+# We should never cache a test run from command-line files.
+go test -run=WriteTmp ./foo_test.go
+! stdout '(cached)'
+go test -run=WriteTmp ./foo_test.go
+! stdout '(cached)'
+
+[!exec:sleep] stop
+# The go command refuses to cache access to files younger than 2s, so sleep that long.
+exec sleep 2
+
+# Touching a file that the test reads from within its testdata should invalidate the cache.
+go test -run=ReadTestdata .
+! stdout '(cached)'
+go test -run=ReadTestdata .
+stdout '(cached)'
+cp testdata/bar.txt testdata/foo.txt
+go test -run=ReadTestdata .
+! stdout '(cached)'
+
+-- go.mod --
+module golang.org/issue/29111/foo
+
+-- foo.go --
+package foo
+
+-- testdata/foo.txt --
+foo
+-- testdata/bar.txt --
+bar
+
+-- foo_test.go --
+package foo_test
+
+import (
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "testing"
+)
+
+func TestWriteTmp(t *testing.T) {
+       dir, err := ioutil.TempDir("", "")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer os.RemoveAll(dir)
+       err = ioutil.WriteFile(filepath.Join(dir, "x"), nil, 0666)
+       if err != nil {
+               t.Fatal(err)
+       }
+}
+
+func TestReadTestdata(t *testing.T) {
+       _, err := ioutil.ReadFile("testdata/foo.txt")
+       if err != nil {
+               t.Fatal(err)
+       }
+}
diff --git a/libgo/go/cmd/go/testdata/script/mod_tidy_error.txt b/libgo/go/cmd/go/testdata/script/mod_tidy_error.txt
new file mode 100644 (file)
index 0000000..9bb8528
--- /dev/null
@@ -0,0 +1,39 @@
+env GO111MODULE=on
+
+# Regression test for golang.org/issue/27063:
+# 'go mod tidy' and 'go mod vendor' should not hide loading errors.
+
+! go mod tidy
+stderr '^issue27063 imports\n\tnonexist: malformed module path "nonexist": missing dot in first path element'
+stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com'
+stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist'
+
+! go mod vendor
+stderr '^issue27063 imports\n\tnonexist: malformed module path "nonexist": missing dot in first path element'
+stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com'
+stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist'
+
+-- go.mod --
+module issue27063
+
+go 1.13
+
+require issue27063/other v0.0.0
+replace issue27063/other => ./other
+-- x.go --
+package main
+
+import (
+       "nonexist"
+
+       "nonexist.example.com"
+       "issue27063/other"
+)
+
+func main() {}
+-- other/go.mod --
+module issue27063/other
+-- other/other.go --
+package other
+
+import "other.example.com/nonexist"
index eae4f2946ce5318214f581fa0d57939964e04d3a..5d872c3c80ef73956146ca95a67c22850f254e79 100644 (file)
@@ -171,12 +171,6 @@ package m
 
 import _ "appengine"
 import _ "appengine/datastore"
--- nonexistent.go --
-// +build alternatereality
-
-package m
-
-import _ "nonexistent.rsc.io"
 -- mypkg/go.mod --
 module me
 -- mypkg/mydir/d.go --
diff --git a/libgo/go/cmd/go/testdata/script/test_go111module_cache.txt b/libgo/go/cmd/go/testdata/script/test_go111module_cache.txt
new file mode 100644 (file)
index 0000000..ca1de43
--- /dev/null
@@ -0,0 +1,15 @@
+env GO111MODULE=on
+go mod init foo
+go test
+stdout ^ok\s+foo
+env GO111MODULE=off
+go test
+stdout ^ok\s+
+! stdout ^ok\s+(cache)$
+
+-- main_test.go --
+package main
+
+import "testing"
+
+func TestF(t *testing.T) {}
diff --git a/libgo/go/cmd/go/testdata/script/test_init.txt b/libgo/go/cmd/go/testdata/script/test_init.txt
deleted file mode 100644 (file)
index 73b4f3c..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-# Tests for automatic testing.Init calls when using 'go test'.
-
-env GO111MODULE=on
-
-# A TestMain should be able to access testing flags if it calls flag.Parse
-# without needing to use testing.Init.
-# Test code can use the name 'testing' without colliding with generated
-# testinginit code.
-# Tests running under 'go test' should observe that testing.Init is called
-# before any user package initialization code runs.
-go test
-stdout TestMain
-stdout TestInit
-stdout TestExt
-
--- go.mod --
-module m
-
--- init_test.go --
-package testinitflag
-
-import (
-       "flag"
-       "fmt"
-       "os"
-       Testing "testing"
-)
-
-func testFlagsInitialized() bool {
-       found := false
-       flag.VisitAll(func(f *flag.Flag) {
-               if f.Name == "test.count" {
-                       found = true
-               }
-       })
-       return found
-}
-
-var testing int
-var testingInitAtInitialization = testFlagsInitialized()
-
-func TestInit(t *Testing.T) {
-       if !testingInitAtInitialization {
-               t.Fatal("testing.Init not called before package initialization")
-       }
-       fmt.Printf("TestInit\n")
-}
-
-func TestMain(m *Testing.M) {
-       fmt.Printf("TestMain\n")
-       flag.Parse()
-       if !testFlagsInitialized() {
-               fmt.Println("testing flags not registered")
-               os.Exit(1)
-       }
-       os.Exit(m.Run())
-}
-
--- external_test.go --
-package testinitflag_test
-
-import (
-       "flag"
-       "fmt"
-       Testing "testing"
-)
-
-func testFlagsInitialized() bool {
-       found := false
-       flag.VisitAll(func(f *flag.Flag) {
-               if f.Name == "test.count" {
-                       found = true
-               }
-       })
-       return found
-}
-
-var testing int
-var testingInitAtInitialization = testFlagsInitialized()
-
-func TestExt(t *Testing.T) {
-       fmt.Printf("TestExt\n")
-       if !testingInitAtInitialization {
-               t.Fatal("testing.Init not called before package initialization")
-       }
-}
index cb4881f7a72ac3f1538bd049b7a99544f5a77c26..9086f047e4bbfbb9eae239df9f298348127edeb7 100644 (file)
@@ -8,5 +8,12 @@ go version -m fortune.exe
 stdout '^\tpath\trsc.io/fortune'
 stdout '^\tmod\trsc.io/fortune\tv1.0.0'
 
+go build -buildmode=pie -o external.exe rsc.io/fortune
+go version external.exe
+stdout '^external.exe: .+'
+go version -m external.exe
+stdout '^\tpath\trsc.io/fortune'
+stdout '^\tmod\trsc.io/fortune\tv1.0.0'
+
 -- go.mod --
 module m
diff --git a/libgo/go/cmd/go/testdata/standalone_testmain_flag_test.go b/libgo/go/cmd/go/testdata/standalone_testmain_flag_test.go
new file mode 100644 (file)
index 0000000..a59555b
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2019 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 standalone_testmain_flag_test
+
+import (
+       "flag"
+       "fmt"
+       "os"
+       "testing"
+)
+
+func TestMain(m *testing.M) {
+       // A TestMain should be able to access testing flags if it calls
+       // flag.Parse without needing to use testing.Init.
+       flag.Parse()
+       found := false
+       flag.VisitAll(func(f *flag.Flag) {
+               if f.Name == "test.count" {
+                       found = true
+               }
+       })
+       if !found {
+               fmt.Println("testing flags not registered")
+               os.Exit(1)
+       }
+       os.Exit(m.Run())
+}
diff --git a/libgo/go/cmd/gofmt/testdata/go2numbers.golden b/libgo/go/cmd/gofmt/testdata/go2numbers.golden
new file mode 100644 (file)
index 0000000..0184aaa
--- /dev/null
@@ -0,0 +1,186 @@
+package p
+
+const (
+       // 0-octals
+       _ = 0
+       _ = 0123
+       _ = 0123456
+
+       _ = 0_123
+       _ = 0123_456
+
+       // decimals
+       _ = 1
+       _ = 1234
+       _ = 1234567
+
+       _ = 1_234
+       _ = 1_234_567
+
+       // hexadecimals
+       _ = 0x0
+       _ = 0x1234
+       _ = 0xcafef00d
+
+       _ = 0x0
+       _ = 0x1234
+       _ = 0xCAFEf00d
+
+       _ = 0x_0
+       _ = 0x_1234
+       _ = 0x_CAFE_f00d
+
+       // octals
+       _ = 0o0
+       _ = 0o1234
+       _ = 0o01234567
+
+       _ = 0o0
+       _ = 0o1234
+       _ = 0o01234567
+
+       _ = 0o_0
+       _ = 0o_1234
+       _ = 0o0123_4567
+
+       _ = 0o_0
+       _ = 0o_1234
+       _ = 0o0123_4567
+
+       // binaries
+       _ = 0b0
+       _ = 0b1011
+       _ = 0b00101101
+
+       _ = 0b0
+       _ = 0b1011
+       _ = 0b00101101
+
+       _ = 0b_0
+       _ = 0b10_11
+       _ = 0b_0010_1101
+
+       // decimal floats
+       _ = 0.
+       _ = 123.
+       _ = 0123.
+
+       _ = .0
+       _ = .123
+       _ = .0123
+
+       _ = 0e0
+       _ = 123e+0
+       _ = 0123e-1
+
+       _ = 0e-0
+       _ = 123e+0
+       _ = 0123e123
+
+       _ = 0.e+1
+       _ = 123.e-10
+       _ = 0123.e123
+
+       _ = .0e-1
+       _ = .123e+10
+       _ = .0123e123
+
+       _ = 0.0
+       _ = 123.123
+       _ = 0123.0123
+
+       _ = 0.0e1
+       _ = 123.123e-10
+       _ = 0123.0123e+456
+
+       _ = 1_2_3.
+       _ = 0_123.
+
+       _ = 0_0e0
+       _ = 1_2_3e0
+       _ = 0_123e0
+
+       _ = 0e-0_0
+       _ = 1_2_3e+0
+       _ = 0123e1_2_3
+
+       _ = 0.e+1
+       _ = 123.e-1_0
+       _ = 01_23.e123
+
+       _ = .0e-1
+       _ = .123e+10
+       _ = .0123e123
+
+       _ = 1_2_3.123
+       _ = 0123.01_23
+
+       // hexadecimal floats
+       _ = 0x0.p+0
+       _ = 0xdeadcafe.p-10
+       _ = 0x1234.p123
+
+       _ = 0x.1p-0
+       _ = 0x.deadcafep2
+       _ = 0x.1234p+10
+
+       _ = 0x0p0
+       _ = 0xdeadcafep+1
+       _ = 0x1234p-10
+
+       _ = 0x0.0p0
+       _ = 0xdead.cafep+1
+       _ = 0x12.34p-10
+
+       _ = 0xdead_cafep+1
+       _ = 0x_1234p-10
+
+       _ = 0x_dead_cafe.p-10
+       _ = 0x12_34.p1_2_3
+       _ = 0x1_2_3_4.p-1_2_3
+
+       // imaginaries
+       _ = 0i
+       _ = 0i
+       _ = 8i
+       _ = 0i
+       _ = 123i
+       _ = 123i
+       _ = 56789i
+       _ = 1234i
+       _ = 1234567i
+
+       _ = 0i
+       _ = 0i
+       _ = 8i
+       _ = 0i
+       _ = 123i
+       _ = 123i
+       _ = 56_789i
+       _ = 1_234i
+       _ = 1_234_567i
+
+       _ = 0.i
+       _ = 123.i
+       _ = 0123.i
+       _ = 000123.i
+
+       _ = 0e0i
+       _ = 123e0i
+       _ = 0123e0i
+       _ = 000123e0i
+
+       _ = 0.e+1i
+       _ = 123.e-1_0i
+       _ = 01_23.e123i
+       _ = 00_01_23.e123i
+
+       _ = 0b1010i
+       _ = 0b1010i
+       _ = 0o660i
+       _ = 0o660i
+       _ = 0xabcDEFi
+       _ = 0xabcDEFi
+       _ = 0xabcDEFp0i
+       _ = 0xabcDEFp0i
+)
diff --git a/libgo/go/cmd/gofmt/testdata/go2numbers.input b/libgo/go/cmd/gofmt/testdata/go2numbers.input
new file mode 100644 (file)
index 0000000..f3e7828
--- /dev/null
@@ -0,0 +1,186 @@
+package p
+
+const (
+       // 0-octals
+       _ = 0
+       _ = 0123
+       _ = 0123456
+
+       _ = 0_123
+       _ = 0123_456
+
+       // decimals
+       _ = 1
+       _ = 1234
+       _ = 1234567
+
+       _ = 1_234
+       _ = 1_234_567
+
+       // hexadecimals
+       _ = 0x0
+       _ = 0x1234
+       _ = 0xcafef00d
+
+       _ = 0X0
+       _ = 0X1234
+       _ = 0XCAFEf00d
+
+       _ = 0X_0
+       _ = 0X_1234
+       _ = 0X_CAFE_f00d
+
+       // octals
+       _ = 0o0
+       _ = 0o1234
+       _ = 0o01234567
+
+       _ = 0O0
+       _ = 0O1234
+       _ = 0O01234567
+
+       _ = 0o_0
+       _ = 0o_1234
+       _ = 0o0123_4567
+
+       _ = 0O_0
+       _ = 0O_1234
+       _ = 0O0123_4567
+
+       // binaries
+       _ = 0b0
+       _ = 0b1011
+       _ = 0b00101101
+
+       _ = 0B0
+       _ = 0B1011
+       _ = 0B00101101
+
+       _ = 0b_0
+       _ = 0b10_11
+       _ = 0b_0010_1101
+
+       // decimal floats
+       _ = 0.
+       _ = 123.
+       _ = 0123.
+
+       _ = .0
+       _ = .123
+       _ = .0123
+
+       _ = 0e0
+       _ = 123e+0
+       _ = 0123E-1
+
+       _ = 0e-0
+       _ = 123E+0
+       _ = 0123E123
+
+       _ = 0.e+1
+       _ = 123.E-10
+       _ = 0123.e123
+
+       _ = .0e-1
+       _ = .123E+10
+       _ = .0123E123
+
+       _ = 0.0
+       _ = 123.123
+       _ = 0123.0123
+
+       _ = 0.0e1
+       _ = 123.123E-10
+       _ = 0123.0123e+456
+
+       _ = 1_2_3.
+       _ = 0_123.
+
+       _ = 0_0e0
+       _ = 1_2_3e0
+       _ = 0_123e0
+
+       _ = 0e-0_0
+       _ = 1_2_3E+0
+       _ = 0123E1_2_3
+
+       _ = 0.e+1
+       _ = 123.E-1_0
+       _ = 01_23.e123
+
+       _ = .0e-1
+       _ = .123E+10
+       _ = .0123E123
+
+       _ = 1_2_3.123
+       _ = 0123.01_23
+
+       // hexadecimal floats
+       _ = 0x0.p+0
+       _ = 0Xdeadcafe.p-10
+       _ = 0x1234.P123
+
+       _ = 0x.1p-0
+       _ = 0X.deadcafep2
+       _ = 0x.1234P+10
+
+       _ = 0x0p0
+       _ = 0Xdeadcafep+1
+       _ = 0x1234P-10
+
+       _ = 0x0.0p0
+       _ = 0Xdead.cafep+1
+       _ = 0x12.34P-10
+
+       _ = 0Xdead_cafep+1
+       _ = 0x_1234P-10
+
+       _ = 0X_dead_cafe.p-10
+       _ = 0x12_34.P1_2_3
+       _ = 0X1_2_3_4.P-1_2_3
+
+       // imaginaries
+       _ = 0i
+       _ = 00i
+       _ = 08i
+       _ = 0000000000i
+       _ = 0123i
+       _ = 0000000123i
+       _ = 0000056789i
+       _ = 1234i
+       _ = 1234567i
+
+       _ = 0i
+       _ = 0_0i
+       _ = 0_8i
+       _ = 0_000_000_000i
+       _ = 0_123i
+       _ = 0_000_000_123i
+       _ = 0_000_056_789i
+       _ = 1_234i
+       _ = 1_234_567i
+
+       _ = 0.i
+       _ = 123.i
+       _ = 0123.i
+       _ = 000123.i
+
+       _ = 0e0i
+       _ = 123e0i
+       _ = 0123E0i
+       _ = 000123E0i
+
+       _ = 0.e+1i
+       _ = 123.E-1_0i
+       _ = 01_23.e123i
+       _ = 00_01_23.e123i
+
+       _ = 0b1010i
+       _ = 0B1010i
+       _ = 0o660i
+       _ = 0O660i
+       _ = 0xabcDEFi
+       _ = 0XabcDEFi
+       _ = 0xabcDEFP0i
+       _ = 0XabcDEFp0i
+)
index 51d7be79dfab7aea7bec5c32fd02b6fdefebafec..29bdc9baf4a637763fc75e30086dca99acd500f2 100644 (file)
@@ -8,6 +8,11 @@ import (
        "math"
 )
 
+import (
+       "fmt"
+       "math"
+)
+
 import (
        "fmt"
 
index 9a4b09dbf9108ca8cd642e122a340887dee79b46..78ab4f654434a7e6e5d74eb958e647dce5e506fb 100644 (file)
@@ -8,6 +8,9 @@ import (
        "io"
 )
 
+import("fmt"
+"math")
+
 import (
        "fmt"
 
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite9.golden b/libgo/go/cmd/gofmt/testdata/rewrite9.golden
new file mode 100644 (file)
index 0000000..fffbd3d
--- /dev/null
@@ -0,0 +1,11 @@
+//gofmt -r=a&&b!=2->a
+
+// Copyright 2017 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 18987.
+
+package p
+
+const _ = x != 1
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite9.input b/libgo/go/cmd/gofmt/testdata/rewrite9.input
new file mode 100644 (file)
index 0000000..106ad94
--- /dev/null
@@ -0,0 +1,11 @@
+//gofmt -r=a&&b!=2->a
+
+// Copyright 2017 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 18987.
+
+package p
+
+const _ = x != 1 && x != 2
diff --git a/libgo/go/cmd/gofmt/testdata/typealias.golden b/libgo/go/cmd/gofmt/testdata/typealias.golden
new file mode 100644 (file)
index 0000000..bbbbf32
--- /dev/null
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+       _  = chan<- int
+       aa = interface{}
+       bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+       _   chan<- int
+       _   = chan<- int
+       aa0 interface{}
+       aaa = interface{}
+       bb0 p.BB
+       bbb = p.BB
+)
diff --git a/libgo/go/cmd/gofmt/testdata/typealias.input b/libgo/go/cmd/gofmt/testdata/typealias.input
new file mode 100644 (file)
index 0000000..6e49328
--- /dev/null
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+       _ = chan<- int
+       aa = interface{}
+       bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+       _ chan<- int
+       _ = chan<- int
+       aa0 interface{}
+       aaa = interface{}
+       bb0 p.BB
+       bbb = p.BB
+)
index 90e944656bb8a2ebeca5dd2d593ac0a124a222f6..79ad2ccf748036af2ee04473f66d687133bb43f0 100644 (file)
@@ -86,6 +86,10 @@ func (versionFlag) Set(s string) error {
        name = name[strings.LastIndex(name, `/`)+1:]
        name = name[strings.LastIndex(name, `\`)+1:]
        name = strings.TrimSuffix(name, ".exe")
+
+       // If there's an active experiment, include that,
+       // to distinguish go1.10.2 with an experiment
+       // from go1.10.2 without an experiment.
        p := Expstring()
        if p == DefaultExpstring() {
                p = ""
@@ -101,12 +105,6 @@ func (versionFlag) Set(s string) error {
        // build ID of the binary, so that if the compiler is changed and
        // rebuilt, we notice and rebuild all packages.
        if s == "full" {
-               // If there's an active experiment, include that,
-               // to distinguish go1.10.2 with an experiment
-               // from go1.10.2 without an experiment.
-               if x := Expstring(); x != "" {
-                       p += " " + x
-               }
                if strings.HasPrefix(Version, "devel") {
                        p += " buildID=" + buildID
                }
index 05d01d0294adaf9c99d0cd520e621427213821e4..62590850a66220027342acbfdcd64218aa11f6b8 100644 (file)
@@ -49,7 +49,6 @@ package context
 
 import (
        "errors"
-       "internal/oserror"
        "internal/reflectlite"
        "sync"
        "time"
@@ -163,9 +162,6 @@ type deadlineExceededError struct{}
 func (deadlineExceededError) Error() string   { return "context deadline exceeded" }
 func (deadlineExceededError) Timeout() bool   { return true }
 func (deadlineExceededError) Temporary() bool { return true }
-func (deadlineExceededError) Is(target error) bool {
-       return target == oserror.ErrTimeout || target == oserror.ErrTemporary
-}
 
 // An emptyCtx is never canceled, has no values, and has no deadline. It is not
 // struct{}, since vars of this type must have distinct addresses.
index 96ad14627c34ea1844952a2f091b9227f4052f87..b07a5cfce6422d2c71db2567d97e03f9731ccc12 100644 (file)
@@ -5,10 +5,8 @@
 package context
 
 import (
-       "errors"
        "fmt"
        "math/rand"
-       "os"
        "runtime"
        "strings"
        "sync"
@@ -649,7 +647,4 @@ func XTestDeadlineExceededSupportsTimeout(t testingT) {
        if !i.Timeout() {
                t.Fatal("wrong value for timeout")
        }
-       if !errors.Is(DeadlineExceeded, os.ErrTimeout) {
-               t.Fatal("errors.Is(DeadlineExceeded, os.ErrTimeout) = false, want true")
-       }
 }
index ad32d3e3add0fc44cfbac9921a708030c041e6a4..d058949242d034fb89db0ed833ec479eb8c5c1a8 100644 (file)
@@ -555,7 +555,7 @@ func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int
 }
 
 // DecryptOAEP decrypts ciphertext using RSA-OAEP.
-
+//
 // OAEP is parameterised by a hash function that is used as a random oracle.
 // Encryption and decryption of a given message must use the same hash function
 // and sha256.New() is a reasonable choice.
index d135b1fc994cf4bc1c653cc08eb0896d3acad33b..ef0b38584876c6b91ce445296959e893a8406268 100644 (file)
@@ -23,11 +23,14 @@ import (
 )
 
 const (
-       VersionSSL30 = 0x0300
        VersionTLS10 = 0x0301
        VersionTLS11 = 0x0302
        VersionTLS12 = 0x0303
        VersionTLS13 = 0x0304
+
+       // Deprecated: SSLv3 is cryptographically broken, and will be
+       // removed in Go 1.14. See golang.org/issue/32716.
+       VersionSSL30 = 0x0300
 )
 
 const (
@@ -791,6 +794,10 @@ var supportedVersions = []uint16{
 func (c *Config) supportedVersions(isClient bool) []uint16 {
        versions := make([]uint16, 0, len(supportedVersions))
        for _, v := range supportedVersions {
+               // TLS 1.0 is the default minimum version.
+               if (c == nil || c.MinVersion == 0) && v < VersionTLS10 {
+                       continue
+               }
                if c != nil && c.MinVersion != 0 && v < c.MinVersion {
                        continue
                }
index 22b126fa22dc5ce8c62be8000041b7961fd11132..a9c1c08cbc429ed3eba18a4e9d14d4222293265a 100644 (file)
@@ -77,6 +77,20 @@ func TestRejectBadProtocolVersion(t *testing.T) {
        }, "unsupported versions")
 }
 
+func TestSSLv3OptIn(t *testing.T) {
+       config := testConfig.Clone()
+       config.MinVersion = 0
+       testClientHelloFailure(t, config, &clientHelloMsg{
+               vers:   VersionSSL30,
+               random: make([]byte, 32),
+       }, "unsupported versions")
+       testClientHelloFailure(t, config, &clientHelloMsg{
+               vers:              VersionTLS12,
+               supportedVersions: []uint16{VersionSSL30},
+               random:            make([]byte, 32),
+       }, "unsupported versions")
+}
+
 func TestNoSuiteOverlap(t *testing.T) {
        clientHello := &clientHelloMsg{
                vers:               VersionTLS10,
index 35c1fe8bf5848abab468197b0b31d59006174827..cfd92908a962dabd12cb3918b70ca579d03eca11 100644 (file)
@@ -222,28 +222,65 @@ func tempFile(contents string) string {
 // localListener is set up by TestMain and used by localPipe to create Conn
 // pairs like net.Pipe, but connected by an actual buffered TCP connection.
 var localListener struct {
-       sync.Mutex
-       net.Listener
+       mu   sync.Mutex
+       addr net.Addr
+       ch   chan net.Conn
+}
+
+const localFlakes = 0 // change to 1 or 2 to exercise localServer/localPipe handling of mismatches
+
+func localServer(l net.Listener) {
+       for n := 0; ; n++ {
+               c, err := l.Accept()
+               if err != nil {
+                       return
+               }
+               if localFlakes == 1 && n%2 == 0 {
+                       c.Close()
+                       continue
+               }
+               localListener.ch <- c
+       }
 }
 
 func localPipe(t testing.TB) (net.Conn, net.Conn) {
-       localListener.Lock()
-       defer localListener.Unlock()
-       c := make(chan net.Conn)
-       go func() {
-               conn, err := localListener.Accept()
+       localListener.mu.Lock()
+       defer localListener.mu.Unlock()
+
+       addr := localListener.addr
+
+Dialing:
+       // We expect a rare mismatch, but probably not 5 in a row.
+       for i := 0; i < 5; i++ {
+               tooSlow := time.NewTimer(1 * time.Second)
+               defer tooSlow.Stop()
+               c1, err := net.Dial(addr.Network(), addr.String())
                if err != nil {
-                       t.Errorf("Failed to accept local connection: %v", err)
+                       t.Fatalf("localPipe: %v", err)
+               }
+               if localFlakes == 2 && i == 0 {
+                       c1.Close()
+                       continue
+               }
+               for {
+                       select {
+                       case <-tooSlow.C:
+                               t.Logf("localPipe: timeout waiting for %v", c1.LocalAddr())
+                               c1.Close()
+                               continue Dialing
+
+                       case c2 := <-localListener.ch:
+                               if c2.RemoteAddr().String() == c1.LocalAddr().String() {
+                                       return c1, c2
+                               }
+                               t.Logf("localPipe: unexpected connection: %v != %v", c2.RemoteAddr(), c1.LocalAddr())
+                               c2.Close()
+                       }
                }
-               c <- conn
-       }()
-       addr := localListener.Addr()
-       c1, err := net.Dial(addr.Network(), addr.String())
-       if err != nil {
-               t.Fatalf("Failed to dial local connection: %v", err)
        }
-       c2 := <-c
-       return c1, c2
+
+       t.Fatalf("localPipe: failed to connect")
+       panic("unreachable")
 }
 
 // zeroSource is an io.Reader that returns an unlimited number of zero bytes.
@@ -293,8 +330,10 @@ func runMain(m *testing.M) int {
                fmt.Fprintf(os.Stderr, "Failed to open local listener: %v", err)
                os.Exit(1)
        }
-       localListener.Listener = l
-       defer localListener.Close()
+       localListener.ch = make(chan net.Conn)
+       localListener.addr = l.Addr()
+       defer l.Close()
+       go localServer(l)
 
        if err := checkOpenSSLVersion(); err != nil {
                fmt.Fprintf(os.Stderr, "Error: %v", err)
index a07727c92bf2c4f18e7de13c4ed69b3f6d83df84..b68c074855f81ef448f4bc9f0b2077742ed07861 100644 (file)
@@ -359,50 +359,6 @@ func TestVerifyHostname(t *testing.T) {
        }
 }
 
-func TestVerifyHostnameResumed(t *testing.T) {
-       t.Run("TLSv12", func(t *testing.T) { testVerifyHostnameResumed(t, VersionTLS12) })
-       t.Run("TLSv13", func(t *testing.T) { testVerifyHostnameResumed(t, VersionTLS13) })
-}
-
-func testVerifyHostnameResumed(t *testing.T, version uint16) {
-       testenv.MustHaveExternalNetwork(t)
-
-       config := &Config{
-               MaxVersion:         version,
-               ClientSessionCache: NewLRUClientSessionCache(32),
-       }
-       for i := 0; i < 2; i++ {
-               c, err := DialWithDialer(&net.Dialer{
-                       Timeout: 10 * time.Second,
-               }, "tcp", "mail.google.com:https", config)
-               if err != nil {
-                       t.Fatalf("Dial #%d: %v", i, err)
-               }
-               cs := c.ConnectionState()
-               if i > 0 && !cs.DidResume {
-                       t.Fatalf("Subsequent connection unexpectedly didn't resume")
-               }
-               if cs.Version != version {
-                       t.Fatalf("Unexpectedly negotiated version %x", cs.Version)
-               }
-               if cs.VerifiedChains == nil {
-                       t.Fatalf("Dial #%d: cs.VerifiedChains == nil", i)
-               }
-               if err := c.VerifyHostname("mail.google.com"); err != nil {
-                       t.Fatalf("verify mail.google.com #%d: %v", i, err)
-               }
-               // Have the server send some data so session tickets are delivered.
-               c.SetDeadline(time.Now().Add(5 * time.Second))
-               if _, err := io.WriteString(c, "HEAD / HTTP/1.0\n\n"); err != nil {
-                       t.Fatal(err)
-               }
-               if _, err := c.Read(make([]byte, 1)); err != nil {
-                       t.Fatal(err)
-               }
-               c.Close()
-       }
-}
-
 func TestConnCloseBreakingWrite(t *testing.T) {
        ln := newLocalListener(t)
        defer ln.Close()
index 1a5424f54e82a3557d84b7ed142fc82ce08d59ee..e2a58203d9d9e805257179a80321bc23baeeae4e 100644 (file)
@@ -171,6 +171,11 @@ type Symbol struct {
        Info, Other byte
        Section     SectionIndex
        Value, Size uint64
+
+       // Version and Library are present only for the dynamic symbol
+       // table.
+       Version string
+       Library string
 }
 
 /*
@@ -1321,12 +1326,23 @@ func (f *File) Symbols() ([]Symbol, error) {
 // DynamicSymbols returns the dynamic symbol table for f. The symbols
 // will be listed in the order they appear in f.
 //
+// If f has a symbol version table, the returned Symbols will have
+// initialized Version and Library fields.
+//
 // For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
 // After retrieving the symbols as symtab, an externally supplied index x
 // corresponds to symtab[x-1], not symtab[x].
 func (f *File) DynamicSymbols() ([]Symbol, error) {
-       sym, _, err := f.getSymbols(SHT_DYNSYM)
-       return sym, err
+       sym, str, err := f.getSymbols(SHT_DYNSYM)
+       if err != nil {
+               return nil, err
+       }
+       if f.gnuVersionInit(str) {
+               for i := range sym {
+                       sym[i].Library, sym[i].Version = f.gnuVersion(i)
+               }
+       }
+       return sym, nil
 }
 
 type ImportedSymbol struct {
@@ -1349,7 +1365,8 @@ func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
        for i, s := range sym {
                if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
                        all = append(all, ImportedSymbol{Name: s.Name})
-                       f.gnuVersion(i, &all[len(all)-1])
+                       sym := &all[len(all)-1]
+                       sym.Library, sym.Version = f.gnuVersion(i)
                }
        }
        return all, nil
@@ -1362,11 +1379,16 @@ type verneed struct {
 
 // gnuVersionInit parses the GNU version tables
 // for use by calls to gnuVersion.
-func (f *File) gnuVersionInit(str []byte) {
+func (f *File) gnuVersionInit(str []byte) bool {
+       if f.gnuNeed != nil {
+               // Already initialized
+               return true
+       }
+
        // Accumulate verneed information.
        vn := f.SectionByType(SHT_GNU_VERNEED)
        if vn == nil {
-               return
+               return false
        }
        d, _ := vn.Data()
 
@@ -1421,17 +1443,18 @@ func (f *File) gnuVersionInit(str []byte) {
        // Versym parallels symbol table, indexing into verneed.
        vs := f.SectionByType(SHT_GNU_VERSYM)
        if vs == nil {
-               return
+               return false
        }
        d, _ = vs.Data()
 
        f.gnuNeed = need
        f.gnuVersym = d
+       return true
 }
 
 // gnuVersion adds Library and Version information to sym,
 // which came from offset i of the symbol table.
-func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
+func (f *File) gnuVersion(i int) (library string, version string) {
        // Each entry is two bytes.
        i = (i + 1) * 2
        if i >= len(f.gnuVersym) {
@@ -1442,8 +1465,7 @@ func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
                return
        }
        n := &f.gnuNeed[j]
-       sym.Library = n.File
-       sym.Version = n.Name
+       return n.File, n.Name
 }
 
 // ImportedLibraries returns the names of all libraries
index 1b79520e3ccb56c39bc61ebb3b8a575293a0498d..42f02312e871dda91417d861480631f5ef2e22e5 100644 (file)
@@ -819,6 +819,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{
                        Section: 0x0,
                        Value:   0x0,
                        Size:    0x18C,
+                       Version: "GLIBC_2.2.5",
+                       Library: "libc.so.6",
                },
                Symbol{
                        Name:    "__libc_start_main",
@@ -827,6 +829,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{
                        Section: 0x0,
                        Value:   0x0,
                        Size:    0x1C2,
+                       Version: "GLIBC_2.2.5",
+                       Library: "libc.so.6",
                },
        },
        "testdata/go-relocation-test-clang-x86.obj": {},
index b18996a930d307eb3c7f6bbdce0faadfa7a532df..3f34bc51dbfc0ddb705771b75436a17203175337 100644 (file)
@@ -41,7 +41,7 @@ func NewWriter(w io.Writer) *Writer {
        }
 }
 
-// Writer writes a single CSV record to w along with any necessary quoting.
+// Write writes a single CSV record to w along with any necessary quoting.
 // A record is a slice of strings with each string being one field.
 // Writes are buffered, so Flush must eventually be called to ensure
 // that the record is written to the underlying io.Writer.
index bdd94e34ce649f5fb5669ae3925fc4293b6a7565..cbd71acfc6c38f7827dd4290fcf6ca7bfbb68d47 100644 (file)
@@ -272,9 +272,6 @@ type decodeState struct {
        savedError            error
        useNumber             bool
        disallowUnknownFields bool
-       // safeUnquote is the number of current string literal bytes that don't
-       // need to be unquoted. When negative, no bytes need unquoting.
-       safeUnquote int
 }
 
 // readIndex returns the position of the last byte read.
@@ -376,27 +373,13 @@ func (d *decodeState) rescanLiteral() {
 Switch:
        switch data[i-1] {
        case '"': // string
-               // safeUnquote is initialized at -1, which means that all bytes
-               // checked so far can be unquoted at a later time with no work
-               // at all. When reaching the closing '"', if safeUnquote is
-               // still -1, all bytes can be unquoted with no work. Otherwise,
-               // only those bytes up until the first '\\' or non-ascii rune
-               // can be safely unquoted.
-               safeUnquote := -1
                for ; i < len(data); i++ {
-                       if c := data[i]; c == '\\' {
-                               if safeUnquote < 0 { // first unsafe byte
-                                       safeUnquote = int(i - d.off)
-                               }
+                       switch data[i] {
+                       case '\\':
                                i++ // escaped char
-                       } else if c == '"' {
-                               d.safeUnquote = safeUnquote
+                       case '"':
                                i++ // tokenize the closing quote too
                                break Switch
-                       } else if c >= utf8.RuneSelf {
-                               if safeUnquote < 0 { // first unsafe byte
-                                       safeUnquote = int(i - d.off)
-                               }
                        }
                }
        case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number
@@ -749,7 +732,7 @@ func (d *decodeState) object(v reflect.Value) error {
                start := d.readIndex()
                d.rescanLiteral()
                item := d.data[start:d.readIndex()]
-               key, ok := d.unquoteBytes(item)
+               key, ok := unquoteBytes(item)
                if !ok {
                        panic(phasePanicMsg)
                }
@@ -950,7 +933,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                        d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())})
                        return nil
                }
-               s, ok := d.unquoteBytes(item)
+               s, ok := unquoteBytes(item)
                if !ok {
                        if fromQuoted {
                                return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())
@@ -1001,7 +984,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                }
 
        case '"': // string
-               s, ok := d.unquoteBytes(item)
+               s, ok := unquoteBytes(item)
                if !ok {
                        if fromQuoted {
                                return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())
@@ -1159,7 +1142,7 @@ func (d *decodeState) objectInterface() map[string]interface{} {
                start := d.readIndex()
                d.rescanLiteral()
                item := d.data[start:d.readIndex()]
-               key, ok := d.unquote(item)
+               key, ok := unquote(item)
                if !ok {
                        panic(phasePanicMsg)
                }
@@ -1208,7 +1191,7 @@ func (d *decodeState) literalInterface() interface{} {
                return c == 't'
 
        case '"': // string
-               s, ok := d.unquote(item)
+               s, ok := unquote(item)
                if !ok {
                        panic(phasePanicMsg)
                }
@@ -1251,21 +1234,38 @@ func getu4(s []byte) rune {
 
 // unquote converts a quoted JSON string literal s into an actual string t.
 // The rules are different than for Go, so cannot use strconv.Unquote.
-func (d *decodeState) unquote(s []byte) (t string, ok bool) {
-       s, ok = d.unquoteBytes(s)
+func unquote(s []byte) (t string, ok bool) {
+       s, ok = unquoteBytes(s)
        t = string(s)
        return
 }
 
-func (d *decodeState) unquoteBytes(s []byte) (t []byte, ok bool) {
-       r := d.safeUnquote
-       // The bytes have been scanned, so we know that the first and last bytes
-       // are double quotes.
+func unquoteBytes(s []byte) (t []byte, ok bool) {
+       if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
+               return
+       }
        s = s[1 : len(s)-1]
 
-       // If there are no unusual characters, no unquoting is needed, so return
-       // a slice of the original bytes.
-       if r == -1 {
+       // Check for unusual characters. If there are none,
+       // then no unquoting is needed, so return a slice of the
+       // original bytes.
+       r := 0
+       for r < len(s) {
+               c := s[r]
+               if c == '\\' || c == '"' || c < ' ' {
+                       break
+               }
+               if c < utf8.RuneSelf {
+                       r++
+                       continue
+               }
+               rr, size := utf8.DecodeRune(s[r:])
+               if rr == utf8.RuneError && size == 1 {
+                       break
+               }
+               r += size
+       }
+       if r == len(s) {
                return s, true
        }
 
index 719a9fa290c77909555c78792503f5b98fde4964..3f25893b419a43f00149cd56965589f4ce8cd648 100644 (file)
@@ -1250,6 +1250,8 @@ var wrongStringTests = []wrongStringTest{
        {`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
        {`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
        {`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`},
+       {`{"result":"\""}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"" into string`},
+       {`{"result":"\"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"foo" into string`},
 }
 
 // If people misuse the ,string modifier, the error message should be
index 464ee3ece4f62cb6ec8cc13f12c4b15beedf75fb..67412763d64009d47ba3b51b110819b1474f3317 100644 (file)
@@ -137,7 +137,7 @@ import (
 // string, an integer type, or implement encoding.TextMarshaler. The map keys
 // are sorted and used as JSON object keys by applying the following rules,
 // subject to the UTF-8 coercion described for string values above:
-//   - string keys are used directly
+//   - keys of any string type are used directly
 //   - encoding.TextMarshalers are marshaled
 //   - integer keys are converted to strings
 //
@@ -460,7 +460,7 @@ func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
        }
 }
 
-func addrMarshalerEncoder(e *encodeState, v reflect.Value, _ encOpts) {
+func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
        va := v.Addr()
        if va.IsNil() {
                e.WriteString("null")
@@ -470,7 +470,7 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, _ encOpts) {
        b, err := m.MarshalJSON()
        if err == nil {
                // copy JSON into buffer, checking validity.
-               err = compact(&e.Buffer, b, true)
+               err = compact(&e.Buffer, b, opts.escapeHTML)
        }
        if err != nil {
                e.error(&MarshalerError{v.Type(), err})
index 4872b6f7ee1b0e55e457b828e373728a603d1648..be03f0d7ffc55510da9dcb41937709c959b6d9f9 100644 (file)
@@ -33,7 +33,7 @@ func Fuzz(data []byte) (score int) {
                err = Unmarshal(m, u)
                if err != nil {
                        fmt.Printf("v=%#v\n", v)
-                       fmt.Println("m=%s\n", string(m))
+                       fmt.Printf("m=%s\n", m)
                        panic(err)
                }
        }
index 1b49a369e3337def391dedd4df1e6a437e8bfee0..fba19548c92721d2f2fb0c63dd3accaa8a3077d3 100644 (file)
@@ -8,9 +8,6 @@ import "bytes"
 
 // Compact appends to dst the JSON-encoded src with
 // insignificant space characters elided.
-// Like Marshal, Compact applies HTMLEscape to any
-// string literals so that the JSON will be safe to embed
-// inside HTML <script> tags.
 func Compact(dst *bytes.Buffer, src []byte) error {
        return compact(dst, src, false)
 }
index 1d1999da251c43c34a809767285857cffa9092fe..e3317ddeb0b5d38eb41ab451a9bbe8af3ea7a896 100644 (file)
@@ -90,6 +90,18 @@ func TestEncoderIndent(t *testing.T) {
        }
 }
 
+type strMarshaler string
+
+func (s strMarshaler) MarshalJSON() ([]byte, error) {
+       return []byte(s), nil
+}
+
+type strPtrMarshaler string
+
+func (s *strPtrMarshaler) MarshalJSON() ([]byte, error) {
+       return []byte(*s), nil
+}
+
 func TestEncoderSetEscapeHTML(t *testing.T) {
        var c C
        var ct CText
@@ -97,6 +109,15 @@ func TestEncoderSetEscapeHTML(t *testing.T) {
                Valid   int `json:"<>&#! "`
                Invalid int `json:"\\"`
        }
+
+       // This case is particularly interesting, as we force the encoder to
+       // take the address of the Ptr field to use its MarshalJSON method. This
+       // is why the '&' is important.
+       marshalerStruct := &struct {
+               NonPtr strMarshaler
+               Ptr    strPtrMarshaler
+       }{`"<str>"`, `"<str>"`}
+
        for _, tt := range []struct {
                name       string
                v          interface{}
@@ -111,6 +132,11 @@ func TestEncoderSetEscapeHTML(t *testing.T) {
                        `{"\u003c\u003e\u0026#! ":0,"Invalid":0}`,
                        `{"<>&#! ":0,"Invalid":0}`,
                },
+               {
+                       `"<str>"`, marshalerStruct,
+                       `{"NonPtr":"\u003cstr\u003e","Ptr":"\u003cstr\u003e"}`,
+                       `{"NonPtr":"<str>","Ptr":"<str>"}`,
+               },
        } {
                var buf bytes.Buffer
                enc := NewEncoder(&buf)
index b8a46921be00e8d872ceccd036e6a2aff4b04acf..85d4260762e275ec56fd858f9bd676480f6b65eb 100644 (file)
@@ -3,9 +3,58 @@
 // license that can be found in the LICENSE file.
 
 // Package errors implements functions to manipulate errors.
+//
+// The New function creates errors whose only content is a text message.
+//
+// The Unwrap, Is and As functions work on errors that may wrap other errors.
+// An error wraps another error if its type has the method
+//
+//     Unwrap() error
+//
+// If e.Unwrap() returns a non-nil error w, then we say that e wraps w.
+//
+// A simple way to create wrapped errors is to call fmt.Errorf and apply the %w verb
+// to the error argument:
+//
+//     fmt.Errorf("... %w ...", ..., err, ...).Unwrap()
+//
+// returns err.
+//
+// Unwrap unpacks wrapped errors. If its argument's type has an
+// Unwrap method, it calls the method once. Otherwise, it returns nil.
+//
+// Is unwraps its first argument sequentially looking for an error that matches the
+// second. It reports whether it finds a match. It should be used in preference to
+// simple equality checks:
+//
+//     if errors.Is(err, os.ErrExist)
+//
+// is preferable to
+//
+//     if err == os.ErrExist
+//
+// because the former will succeed if err wraps os.ErrExist.
+//
+// As unwraps its first argument sequentially looking for an error that can be
+// assigned to its second argument, which must be a pointer. If it succeeds, it
+// performs the assignment and returns true. Otherwise, it returns false. The form
+//
+//     var perr *os.PathError
+//     if errors.As(err, &perr) {
+//             fmt.Println(perr.Path)
+//     }
+//
+// is preferable to
+//
+//     if perr, ok := err.(*os.PathError); ok {
+//             fmt.Println(perr.Path)
+//     }
+//
+// because the former will succeed if err wraps an *os.PathError.
 package errors
 
 // New returns an error that formats as the given text.
+// Each call to New returns a distinct error value even if the text is identical.
 func New(text string) error {
        return &errorString{text}
 }
index 666d1ff207a9baf4b232d4e15580e58df564311c..240da37c2952eb6589b6d4156c022b918497e4ed 100644 (file)
@@ -23,6 +23,9 @@ func Unwrap(err error) error {
 
 // Is reports whether any error in err's chain matches target.
 //
+// The chain consists of err itself followed by the sequence of errors obtained by
+// repeatedly calling Unwrap.
+//
 // An error is considered to match a target if it is equal to that target or if
 // it implements a method Is(error) bool such that Is(target) returns true.
 func Is(err, target error) bool {
@@ -50,6 +53,9 @@ func Is(err, target error) bool {
 // As finds the first error in err's chain that matches target, and if so, sets
 // target to that error value and returns true.
 //
+// The chain consists of err itself followed by the sequence of errors obtained by
+// repeatedly calling Unwrap.
+//
 // An error matches target if the error's concrete value is assignable to the value
 // pointed to by target, or if the error has a method As(interface{}) bool such that
 // As(target) returns true. In the latter case, the As method is responsible for
index c0dc0532b1ca4bb2f9e809c87d4afcfdfadc96d4..13b5c99b6e536fef7c6c978e5322519243e85c44 100644 (file)
@@ -205,7 +205,7 @@ func (v *Map) AddFloat(key string, delta float64) {
        }
 }
 
-// Deletes the given key from the map.
+// Delete deletes the given key from the map.
 func (v *Map) Delete(key string) {
        v.keysMu.Lock()
        defer v.keysMu.Unlock()
index 6ae6c47fd9d1d6c2e1c9212b80ed6670bb9ddc98..466a620353310b6d6322c60783aae143f5727a59 100644 (file)
@@ -12,7 +12,7 @@ import "errors"
 // If the format specifier includes a %w verb with an error operand,
 // the returned error will implement an Unwrap method returning the operand. It is
 // invalid to include more than one %w verb or to supply it with an operand
-// that does not implement the error innterface. The %w verb is otherwise
+// that does not implement the error interface. The %w verb is otherwise
 // a synonym for %v.
 func Errorf(format string, a ...interface{}) error {
        p := newPrinter()
index 74ada20de7a7cf66b91996cbf0318b9aaf703853..0dab2c98f75ee72666bd829ac2f4d07d5ff923bd 100644 (file)
@@ -609,7 +609,7 @@ func (s *ss) scanRune(bitSize int) int64 {
        return r
 }
 
-// scanBasePrefix reports whether the integer begins with a bas prefix
+// scanBasePrefix reports whether the integer begins with a base prefix
 // and returns the base, digit string, and whether a zero was found.
 // It is called only if the verb is %v.
 func (s *ss) scanBasePrefix() (base int, digits string, zeroFound bool) {
index 7102884c8596444653bd35972c6e6fa737eaba1f..be23c7fc43207f87af33626b9b676a6450736a66 100644 (file)
@@ -30,7 +30,7 @@ func SortImports(fset *token.FileSet, f *File) {
                i := 0
                specs := d.Specs[:0]
                for j, s := range d.Specs {
-                       if j > i && lineAt(fset, s.Pos()) > 1+lineAt(fset, d.Specs[j-1].End()) {
+                       if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line {
                                // j begins a new run. End this one.
                                specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...)
                                i = j
@@ -42,8 +42,8 @@ func SortImports(fset *token.FileSet, f *File) {
                // Deduping can leave a blank line before the rparen; clean that up.
                if len(d.Specs) > 0 {
                        lastSpec := d.Specs[len(d.Specs)-1]
-                       lastLine := lineAt(fset, lastSpec.Pos())
-                       rParenLine := lineAt(fset, d.Rparen)
+                       lastLine := fset.Position(lastSpec.Pos()).Line
+                       rParenLine := fset.Position(d.Rparen).Line
                        for rParenLine > lastLine+1 {
                                rParenLine--
                                fset.File(d.Rparen).MergeLine(rParenLine)
@@ -52,10 +52,6 @@ func SortImports(fset *token.FileSet, f *File) {
        }
 }
 
-func lineAt(fset *token.FileSet, pos token.Pos) int {
-       return fset.PositionFor(pos, false).Line
-}
-
 func importPath(s Spec) string {
        t, err := strconv.Unquote(s.(*ImportSpec).Path.Value)
        if err == nil {
@@ -93,11 +89,6 @@ type posSpan struct {
        End   token.Pos
 }
 
-type cgPos struct {
-       left bool // true if comment is to the left of the spec, false otherwise.
-       cg   *CommentGroup
-}
-
 func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
        // Can't short-circuit here even if specs are already sorted,
        // since they might yet need deduplication.
@@ -113,57 +104,39 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
        }
 
        // Identify comments in this range.
-       begSpecs := pos[0].Start
-       endSpecs := pos[len(pos)-1].End
-       beg := fset.File(begSpecs).LineStart(lineAt(fset, begSpecs))
-       end := fset.File(endSpecs).LineStart(lineAt(fset, endSpecs) + 1) // beginning of next line
-       first := len(f.Comments)
-       last := -1
+       // Any comment from pos[0].Start to the final line counts.
+       lastLine := fset.Position(pos[len(pos)-1].End).Line
+       cstart := len(f.Comments)
+       cend := len(f.Comments)
        for i, g := range f.Comments {
-               if g.End() >= end {
-                       break
+               if g.Pos() < pos[0].Start {
+                       continue
                }
-               // g.End() < end
-               if beg <= g.Pos() {
-                       // comment is within the range [beg, end[ of import declarations
-                       if i < first {
-                               first = i
-                       }
-                       if i > last {
-                               last = i
-                       }
+               if i < cstart {
+                       cstart = i
+               }
+               if fset.Position(g.End()).Line > lastLine {
+                       cend = i
+                       break
                }
        }
+       comments := f.Comments[cstart:cend]
 
-       var comments []*CommentGroup
-       if last >= 0 {
-               comments = f.Comments[first : last+1]
-       }
-
-       // Assign each comment to the import spec on the same line.
-       importComments := map[*ImportSpec][]cgPos{}
+       // Assign each comment to the import spec preceding it.
+       importComments := map[*ImportSpec][]*CommentGroup{}
        specIndex := 0
        for _, g := range comments {
                for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() {
                        specIndex++
                }
-               var left bool
-               // A block comment can appear before the first import spec.
-               if specIndex == 0 && pos[specIndex].Start > g.Pos() {
-                       left = true
-               } else if specIndex+1 < len(specs) && // Or it can appear on the left of an import spec.
-                       lineAt(fset, pos[specIndex].Start)+1 == lineAt(fset, g.Pos()) {
-                       specIndex++
-                       left = true
-               }
                s := specs[specIndex].(*ImportSpec)
-               importComments[s] = append(importComments[s], cgPos{left: left, cg: g})
+               importComments[s] = append(importComments[s], g)
        }
 
        // Sort the import specs by import path.
        // Remove duplicates, when possible without data loss.
        // Reassign the import paths to have the same position sequence.
-       // Reassign each comment to the spec on the same line.
+       // Reassign each comment to abut the end of its spec.
        // Sort the comments by new position.
        sort.Slice(specs, func(i, j int) bool {
                ipath := importPath(specs[i])
@@ -187,7 +160,7 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
                        deduped = append(deduped, s)
                } else {
                        p := s.Pos()
-                       fset.File(p).MergeLine(lineAt(fset, p))
+                       fset.File(p).MergeLine(fset.Position(p).Line)
                }
        }
        specs = deduped
@@ -201,16 +174,8 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
                s.Path.ValuePos = pos[i].Start
                s.EndPos = pos[i].End
                for _, g := range importComments[s] {
-                       for _, c := range g.cg.List {
-                               if g.left {
-                                       c.Slash = pos[i].Start - 1
-                               } else {
-                                       // An import spec can have both block comment and a line comment
-                                       // to its right. In that case, both of them will have the same pos.
-                                       // But while formatting the AST, the line comment gets moved to
-                                       // after the block comment.
-                                       c.Slash = pos[i].End
-                               }
+                       for _, c := range g.List {
+                               c.Slash = pos[i].End
                        }
                }
        }
index f108540233f973f2b208c54beced02f3406a72a7..021c6eca22f558f244b3ca4d9176c5d405b4dd5d 100644 (file)
@@ -1003,27 +1003,25 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode,
                return errNoModules
        }
 
+       // Find the absolute source directory. hasSubdir does not handle
+       // relative paths (and can't because the callbacks don't support this).
+       absSrcDir, err := filepath.Abs(srcDir)
+       if err != nil {
+               return errNoModules
+       }
+
        // If modules are not enabled, then the in-process code works fine and we should keep using it.
-       // TODO(bcmills): This assumes that the default is "auto" instead of "on".
        switch os.Getenv("GO111MODULE") {
        case "off":
                return errNoModules
-       case "on":
-               // ok
-       default: // "", "auto", anything else
-               // Automatic mode: no module use in $GOPATH/src.
-               for _, root := range gopath {
-                       sub, ok := ctxt.hasSubdir(root, srcDir)
-                       if ok && strings.HasPrefix(sub, "src/") {
-                               return errNoModules
-                       }
-               }
+       default: // "", "on", "auto", anything else
+               // Maybe use modules.
        }
 
        // If the source directory is in GOROOT, then the in-process code works fine
        // and we should keep using it. Moreover, the 'go list' approach below doesn't
        // take standard-library vendoring into account and will fail.
-       if _, ok := ctxt.hasSubdir(filepath.Join(ctxt.GOROOT, "src"), srcDir); ok {
+       if _, ok := ctxt.hasSubdir(filepath.Join(ctxt.GOROOT, "src"), absSrcDir); ok {
                return errNoModules
        }
 
@@ -1036,20 +1034,18 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode,
        }
 
        // Look to see if there is a go.mod.
-       abs, err := filepath.Abs(srcDir)
-       if err != nil {
-               return errNoModules
-       }
+       // Since go1.13, it doesn't matter if we're inside GOPATH.
+       parent := absSrcDir
        for {
-               info, err := os.Stat(filepath.Join(abs, "go.mod"))
+               info, err := os.Stat(filepath.Join(parent, "go.mod"))
                if err == nil && !info.IsDir() {
                        break
                }
-               d := filepath.Dir(abs)
-               if len(d) >= len(abs) {
+               d := filepath.Dir(parent)
+               if len(d) >= len(parent) {
                        return errNoModules // reached top of file system, no go.mod
                }
-               abs = d
+               parent = d
        }
 
        cmd := exec.Command("go", "list", "-compiler="+ctxt.Compiler, "-tags="+strings.Join(ctxt.BuildTags, ","), "-installsuffix="+ctxt.InstallSuffix, "-f={{.Dir}}\n{{.ImportPath}}\n{{.Root}}\n{{.Goroot}}\n", path)
index 709c43a52a611ce4c1d7478521e2fd4bc356dd64..fb862459c8a3eab4c39a7d60e774dd7dc6885f7c 100644 (file)
@@ -166,6 +166,7 @@ var pkgDeps = map[string][]string{
                "syscall/js",
        },
 
+       "internal/cfg":     {"L0"},
        "internal/poll":    {"L0", "internal/oserror", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8", "internal/syscall/windows"},
        "internal/testlog": {"L0"},
        "os":               {"L1", "os", "syscall", "time", "internal/oserror", "internal/poll", "internal/syscall/windows", "internal/syscall/unix", "internal/testlog"},
@@ -199,7 +200,7 @@ var pkgDeps = map[string][]string{
        "testing":               {"L2", "flag", "fmt", "internal/race", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
        "testing/iotest":        {"L2", "log"},
        "testing/quick":         {"L2", "flag", "fmt", "reflect", "time"},
-       "internal/testenv":      {"L2", "OS", "flag", "testing", "syscall"},
+       "internal/testenv":      {"L2", "OS", "flag", "testing", "syscall", "internal/cfg"},
        "internal/lazyregexp":   {"L2", "OS", "regexp"},
        "internal/lazytemplate": {"L2", "OS", "text/template"},
 
@@ -249,7 +250,7 @@ var pkgDeps = map[string][]string{
        "compress/gzip":                  {"L4", "compress/flate"},
        "compress/lzw":                   {"L4"},
        "compress/zlib":                  {"L4", "compress/flate"},
-       "context":                        {"errors", "internal/oserror", "internal/reflectlite", "sync", "time"},
+       "context":                        {"errors", "internal/reflectlite", "sync", "time"},
        "database/sql":                   {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"},
        "database/sql/driver":            {"L4", "context", "time", "database/sql/internal"},
        "debug/dwarf":                    {"L4"},
index 703825a45d7469f05d9c2e5b68bd12e8348e5961..de793efa873f7a16f954f23886983c645c978956 100644 (file)
 // To distinguish build constraints from package documentation, a series of
 // build constraints must be followed by a blank line.
 //
-// A build constraint is evaluated as the OR of space-separated options;
-// each option evaluates as the AND of its comma-separated terms;
-// and each term is an alphanumeric word or, preceded by !, its negation.
-// That is, the build constraint:
+// A build constraint is evaluated as the OR of space-separated options.
+// Each option evaluates as the AND of its comma-separated terms.
+// Each term consists of letters, digits, underscores, and dots.
+// A term may be negated with a preceding !.
+// For example, the build constraint:
 //
 //     // +build linux,386 darwin,!cgo
 //
diff --git a/libgo/go/go/doc/testdata/issue10858.go b/libgo/go/go/doc/testdata/issue10858.go
deleted file mode 100644 (file)
index aebea50..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-package issue10858
-
-import "unsafe"
-
-// Should be ignored
-
-// First line
-//
-// Second line
-type Type interface {
-       // Should be present
-
-       // Align returns the alignment in bytes of a value of
-       // this type when allocated in memory.
-       Align() int
-
-       // FieldAlign returns the alignment in bytes of a value of
-       // this type when used as a field in a struct.
-       FieldAlign() int // adjacent comment
-
-       //      Ptr: Elem
-       //      Slice: Elem
-
-       // Bits returns the size of the type in bits.
-
-       //
-       // It panics if the type's Kind is not one of the
-       // sized or unsized Int, Uint, Float, or Complex kinds.
-       Bits() int
-
-       // Should be ignored
-}
-
-// Should be ignored
-
-// NewType is a comment
-//
-// ending with this line.
-func NewType() Type {}
-
-// Ignore
-
-// First line
-//
-// Second line
-const (
-       // Should be ignored
-
-       // C1 comment
-       C1 int = 1 << 0
-
-       // Should
-       //
-       // be ignored
-
-       C2 int = 1 << 1
-
-       // C3 comment
-       //
-       // with a line gap
-       C3 int = 1 << 2
-
-       // Should be ignored
-)
-
-// Should be ignored
-
-// Should be ignored
-
-// TypeAlg is a
-// copy of runtime.typeAlg
-type TypeAlg struct {
-       // function for hashing objects of this type
-       //
-       //
-       // (ptr to object, seed) -> hash
-       Hash func(unsafe.Pointer, uintptr) uintptr
-
-       // include
-       // include
-
-       // include
-
-       // function for comparing objects of this type
-       // (ptr to object A, ptr to object B) -> ==?
-       Equal func(unsafe.Pointer, unsafe.Pointer) bool
-       // Should be ignored
-}
-
-// Should be ignored
-
-// StructTag is a comment
-//
-//
-// with 2 connecting lines
-type StructTag string // adjacent comment
-
-// Should be ignored
-
-// Get returns the value associated with key in the tag string.
-func (tag StructTag) Get(key string) string {
-}
index 703090b7b6bf8fdaaba04d9419e4db4db66cd85f..fa7d8484f12e528f19ea92c1ac8ea13b6ffe4f6e 100644 (file)
@@ -29,17 +29,15 @@ type Lookup func(path string) (io.ReadCloser, error)
 // (if the package API depends on cgo-defined entities, the type
 // checker won't have access to those).
 //
-// If lookup is nil, the default package lookup mechanism for the
-// given compiler is used, and the resulting importer attempts
-// to resolve relative and absolute import paths to canonical
-// import path IDs before finding the imported file.
+// The lookup function is called each time the resulting importer needs
+// to resolve an import path. In this mode the importer can only be
+// invoked with canonical import paths (not relative or absolute ones);
+// it is assumed that the translation to canonical import paths is being
+// done by the client of the importer.
 //
-// If lookup is non-nil, then the returned importer calls lookup
-// each time it needs to resolve an import path. In this mode
-// the importer can only be invoked with canonical import paths
-// (not relative or absolute ones); it is assumed that the translation
-// to canonical import paths is being done by the client of the
-// importer.
+// A lookup function must be provided for correct module-aware operation.
+// Deprecated: If lookup is nil, for backwards-compatibility, the importer
+// will attempt to resolve imports in the $GOPATH workspace.
 func ForCompiler(fset *token.FileSet, compiler string, lookup Lookup) types.Importer {
        switch compiler {
        case "gc":
index 9294bb6b3ef690f78b60f681dfd781c6d2448097..ba16b652246f11bcae4c99e21ca29420fb830f53 100644 (file)
@@ -63,7 +63,6 @@ type parser struct {
        topScope   *ast.Scope        // top-most scope; may be pkgScope
        unresolved []*ast.Ident      // unresolved identifiers
        imports    []*ast.ImportSpec // list of imports
-       inStruct   bool              // if set, parser is parsing a struct or interface (for comment collection)
 
        // Label scopes
        // (maintained by open/close LabelScope)
@@ -338,15 +337,7 @@ func (p *parser) next() {
                // consume successor comments, if any
                endline = -1
                for p.tok == token.COMMENT {
-                       n := 1
-                       // When inside a struct (or interface), we don't want to lose comments
-                       // separated from individual field (or method) documentation by empty
-                       // lines. Allow for some white space in this case and collect those
-                       // comments as a group. See issue #10858 for details.
-                       if p.inStruct {
-                               n = 2
-                       }
-                       comment, endline = p.consumeCommentGroup(n)
+                       comment, endline = p.consumeCommentGroup(1)
                }
 
                if endline+1 == p.file.Line(p.pos) {
@@ -757,7 +748,6 @@ func (p *parser) parseStructType() *ast.StructType {
        }
 
        pos := p.expect(token.STRUCT)
-       p.inStruct = true
        lbrace := p.expect(token.LBRACE)
        scope := ast.NewScope(nil) // struct scope
        var list []*ast.Field
@@ -768,7 +758,6 @@ func (p *parser) parseStructType() *ast.StructType {
                list = append(list, p.parseFieldDecl(scope))
        }
        rbrace := p.expect(token.RBRACE)
-       p.inStruct = false
 
        return &ast.StructType{
                Struct: pos,
@@ -970,7 +959,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
        }
 
        pos := p.expect(token.INTERFACE)
-       p.inStruct = true
        lbrace := p.expect(token.LBRACE)
        scope := ast.NewScope(nil) // interface scope
        var list []*ast.Field
@@ -978,7 +966,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
                list = append(list, p.parseMethodSpec(scope))
        }
        rbrace := p.expect(token.RBRACE)
-       p.inStruct = false
 
        return &ast.InterfaceType{
                Interface: pos,
index b50ee2fd5f38d89c4cecc83d7913a8b2aecb5ff5..409b468f20a311c43e0e5db5a12e5f518d3399a7 100644 (file)
@@ -42,7 +42,7 @@ func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope {
 // Parent returns the scope's containing (parent) scope.
 func (s *Scope) Parent() *Scope { return s.parent }
 
-// Len() returns the number of scope elements.
+// Len returns the number of scope elements.
 func (s *Scope) Len() int { return len(s.elems) }
 
 // Names returns the scope's element names in sorted order.
@@ -57,7 +57,7 @@ func (s *Scope) Names() []string {
        return names
 }
 
-// NumChildren() returns the number of scopes nested in s.
+// NumChildren returns the number of scopes nested in s.
 func (s *Scope) NumChildren() int { return len(s.children) }
 
 // Child returns the i'th child scope for 0 <= i < NumChildren().
index 0c007f6cd0155157af9d018004ee84d3968a2038..31c572f83b1234f8c48ad83a8d26513bce8343f0 100644 (file)
@@ -24,7 +24,7 @@ import (
 //
 type Qualifier func(*Package) string
 
-// RelativeTo(pkg) returns a Qualifier that fully qualifies members of
+// RelativeTo returns a Qualifier that fully qualifies members of
 // all packages other than pkg.
 func RelativeTo(pkg *Package) Qualifier {
        if pkg == nil {
index 4e2e1ab090ca461536ea29b23268fd08d5d31579..19e4133f7d1911378f281412a3046e32d4be9da0 100644 (file)
@@ -1,4 +1,4 @@
-// Created by cgo -godefs - DO NOT EDIT
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
 // cgo -godefs defs_darwin.go
 
 package route
index 719c88d11f89eb385bdae8185837e33c6d3a6c4b..8ed2d4d550c15b58210eed0e4c301a9712d591e4 100644 (file)
@@ -1,4 +1,4 @@
-// Created by cgo -godefs - DO NOT EDIT
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
 // cgo -godefs defs_dragonfly.go
 
 package route
index b03bc01f6543e67f4068d9d0490195408dae075c..f36aaadb59f71a310c904993991911373ab05b03 100644 (file)
@@ -1,4 +1,4 @@
-// Created by cgo -godefs - DO NOT EDIT
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
 // cgo -godefs defs_freebsd.go
 
 package route
index 0b675b3d3f9d6781d0b88fca32725e4660576e7e..4c639b82e4b3a3ed514648006fd5e001651c335e 100644 (file)
@@ -1,4 +1,4 @@
-// Created by cgo -godefs - DO NOT EDIT
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
 // cgo -godefs defs_freebsd.go
 
 package route
index 58f8ea16f251197db3c44d07fcf0eb24c21730b8..710c1472b64397610228c94363315a20e799e60b 100644 (file)
@@ -1,4 +1,4 @@
-// Created by cgo -godefs - DO NOT EDIT
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
 // cgo -godefs defs_freebsd.go
 
 package route
index e0df45e8b55382fe7a2f4b5f885ef4f99208b049..b4f66ca6cbc818ebfc1637e90afea30988e523ea 100644 (file)
@@ -1,4 +1,4 @@
-// Created by cgo -godefs - DO NOT EDIT
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
 // cgo -godefs defs_netbsd.go
 
 package route
index db8c8efb49b291a5b09f513a5db4543a876a7b79..1021b4cea4f3dd1751fa772b14767b77ec7db157 100644 (file)
@@ -1,4 +1,4 @@
-// Created by cgo -godefs - DO NOT EDIT
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
 // cgo -godefs defs_openbsd.go
 
 package route
diff --git a/libgo/go/internal/cfg/cfg.go b/libgo/go/internal/cfg/cfg.go
new file mode 100644 (file)
index 0000000..4c2cf8e
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2019 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 cfg holds configuration shared by the Go command and internal/testenv.
+// Definitions that don't need to be exposed outside of cmd/go should be in
+// cmd/go/internal/cfg instead of this package.
+package cfg
+
+// KnownEnv is a list of environment variables that affect the operation
+// of the Go command.
+const KnownEnv = `
+       AR
+       CC
+       CGO_CFLAGS
+       CGO_CFLAGS_ALLOW
+       CGO_CFLAGS_DISALLOW
+       CGO_CPPFLAGS
+       CGO_CPPFLAGS_ALLOW
+       CGO_CPPFLAGS_DISALLOW
+       CGO_CXXFLAGS
+       CGO_CXXFLAGS_ALLOW
+       CGO_CXXFLAGS_DISALLOW
+       CGO_ENABLED
+       CGO_FFLAGS
+       CGO_FFLAGS_ALLOW
+       CGO_FFLAGS_DISALLOW
+       CGO_LDFLAGS
+       CGO_LDFLAGS_ALLOW
+       CGO_LDFLAGS_DISALLOW
+       CXX
+       FC
+       GCCGO
+       GO111MODULE
+       GO386
+       GOARCH
+       GOARM
+       GOBIN
+       GOCACHE
+       GOENV
+       GOEXE
+       GOFLAGS
+       GOGCCFLAGS
+       GOHOSTARCH
+       GOHOSTOS
+       GOMIPS
+       GOMIPS64
+       GONOPROXY
+       GONOSUMDB
+       GOOS
+       GOPATH
+       GOPPC64
+       GOPRIVATE
+       GOPROXY
+       GOROOT
+       GOSUMDB
+       GOTMPDIR
+       GOTOOLDIR
+       GOWASM
+       GO_EXTLINK_ENABLED
+       PKG_CONFIG
+`
index 8bd17c8b562ff98a03ff6665af5ca0de78f69193..28a1ab32d32c5fc03b9dfaf8587f77e9090ab4a0 100644 (file)
@@ -15,50 +15,4 @@ var (
        ErrExist      = errors.New("file already exists")
        ErrNotExist   = errors.New("file does not exist")
        ErrClosed     = errors.New("file already closed")
-       ErrTemporary  = temporaryError{}
-       ErrTimeout    = timeoutError{}
 )
-
-type timeoutError struct{}
-
-func (timeoutError) Error() string { return "deadline exceeded" }
-func (timeoutError) Timeout() bool { return true }
-
-type temporaryError struct{}
-
-func (temporaryError) Error() string   { return "temporary error" }
-func (temporaryError) Temporary() bool { return true }
-
-// IsTimeout reports whether err indicates a timeout.
-func IsTimeout(err error) bool {
-       for err != nil {
-               if err == ErrTimeout {
-                       return true
-               }
-               if x, ok := err.(interface{ Timeout() bool }); ok {
-                       return x.Timeout()
-               }
-               if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(ErrTimeout) {
-                       return true
-               }
-               err = errors.Unwrap(err)
-       }
-       return false
-}
-
-// IsTemporary reports whether err indicates a temporary condition.
-func IsTemporary(err error) bool {
-       for err != nil {
-               if err == ErrTemporary {
-                       return true
-               }
-               if x, ok := err.(interface{ Temporary() bool }); ok {
-                       return x.Temporary()
-               }
-               if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(ErrTemporary) {
-                       return true
-               }
-               err = errors.Unwrap(err)
-       }
-       return false
-}
diff --git a/libgo/go/internal/oserror/errors_test.go b/libgo/go/internal/oserror/errors_test.go
deleted file mode 100644 (file)
index 6d6a56a..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-package oserror_test
-
-import (
-       "errors"
-       "fmt"
-       "internal/oserror"
-       "os"
-       "testing"
-)
-
-type ttError struct {
-       timeout   bool
-       temporary bool
-}
-
-func (e ttError) Error() string {
-       return fmt.Sprintf("ttError{timeout:%v temporary:%v}", e.timeout, e.temporary)
-}
-func (e ttError) Timeout() bool   { return e.timeout }
-func (e ttError) Temporary() bool { return e.temporary }
-
-type isError struct {
-       err error
-}
-
-func (e isError) Error() string        { return fmt.Sprintf("isError(%v)", e.err) }
-func (e isError) Is(target error) bool { return e.err == target }
-
-func TestIsTimeout(t *testing.T) {
-       for _, test := range []struct {
-               want bool
-               err  error
-       }{
-               {true, ttError{timeout: true}},
-               {true, isError{os.ErrTimeout}},
-               {true, os.ErrTimeout},
-               {true, fmt.Errorf("wrap: %w", os.ErrTimeout)},
-               {false, ttError{timeout: false}},
-               {false, errors.New("error")},
-       } {
-               if got, want := oserror.IsTimeout(test.err), test.want; got != want {
-                       t.Errorf("IsTimeout(err) = %v, want %v\n%+v", got, want, test.err)
-               }
-       }
-}
-
-func TestIsTemporary(t *testing.T) {
-       for _, test := range []struct {
-               want bool
-               err  error
-       }{
-               {true, ttError{temporary: true}},
-               {true, isError{os.ErrTemporary}},
-               {true, os.ErrTemporary},
-               {true, fmt.Errorf("wrap: %w", os.ErrTemporary)},
-               {false, ttError{temporary: false}},
-               {false, errors.New("error")},
-       } {
-               if got, want := oserror.IsTemporary(test.err), test.want; got != want {
-                       t.Errorf("IsTemporary(err) = %v, want %v\n%+v", got, want, test.err)
-               }
-       }
-}
index 784bea4b5a260924402cebcd2a872c684b419ade..c0de50c1b46e55ba6c658dfa352ac1a2b67d17fb 100644 (file)
@@ -11,7 +11,6 @@ package poll
 
 import (
        "errors"
-       "internal/oserror"
 )
 
 // ErrNetClosing is returned when a network descriptor is used after
@@ -47,10 +46,6 @@ func (e *TimeoutError) Error() string   { return "i/o timeout" }
 func (e *TimeoutError) Timeout() bool   { return true }
 func (e *TimeoutError) Temporary() bool { return true }
 
-func (e *TimeoutError) Is(target error) bool {
-       return target == oserror.ErrTimeout || target == oserror.ErrTemporary
-}
-
 // ErrNotPollable is returned when the file or socket is not suitable
 // for event notification.
 var ErrNotPollable = errors.New("not pollable")
index 4e2c62c741a74bee3c51b2f597c0aad7cb77c31b..3460054a676420547a7d63a00e4e3b6b30099ef7 100644 (file)
@@ -13,6 +13,7 @@ package testenv
 import (
        "errors"
        "flag"
+       "internal/cfg"
        "os"
        "os/exec"
        "path/filepath"
@@ -102,6 +103,12 @@ func GoToolPath(t testing.TB) string {
        if err != nil {
                t.Fatal(err)
        }
+       // Add all environment variables that affect the Go command to test metadata.
+       // Cached test results will be invalidate when these variables change.
+       // See golang.org/issue/32285.
+       for _, envVar := range strings.Fields(cfg.KnownEnv) {
+               os.Getenv(envVar)
+       }
        return path
 }
 
index b887165096613729c29b3a5c77d4be1f72a7e1c1..0c9a488811b47531d29ecc9b86f38c3c2e25c0ba 100644 (file)
@@ -23,7 +23,6 @@ package net
 
 import (
        "context"
-       "os"
        "syscall"
        "unsafe"
 )
@@ -57,16 +56,6 @@ func (eai addrinfoErrno) Error() string   { return bytePtrToString(libc_gai_stre
 func (eai addrinfoErrno) Temporary() bool { return eai == syscall.EAI_AGAIN }
 func (eai addrinfoErrno) Timeout() bool   { return false }
 
-func (eai addrinfoErrno) Is(target error) bool {
-       switch target {
-       case os.ErrTemporary:
-               return eai.Temporary()
-       case os.ErrTimeout:
-               return eai.Timeout()
-       }
-       return false
-}
-
 type portLookupResult struct {
        port int
        err  error
index 2a09f5f6c6965323a5e642cf5f26f6ea07df792c..a783b4661856287f9e7f606b5d99cc71b86bb9a2 100644 (file)
@@ -132,7 +132,7 @@ func ExampleServer_Shutdown() {
 
        if err := srv.ListenAndServe(); err != http.ErrServerClosed {
                // Error starting or closing listener:
-               log.Printf("HTTP server ListenAndServe: %v", err)
+               log.Fatalf("HTTP server ListenAndServe: %v", err)
        }
 
        <-idleConnsClosed
index f0dfa8cd336c7a4efdf745bc625f984a4db9b3ff..d265cd3f726f1675b2816016a64e295ff9951e91 100644 (file)
@@ -166,30 +166,40 @@ func (t *Transport) IdleConnCountForTesting(scheme, addr string) int {
        return 0
 }
 
-func (t *Transport) IdleConnChMapSizeForTesting() int {
+func (t *Transport) IdleConnWaitMapSizeForTesting() int {
        t.idleMu.Lock()
        defer t.idleMu.Unlock()
-       return len(t.idleConnCh)
+       return len(t.idleConnWait)
 }
 
 func (t *Transport) IsIdleForTesting() bool {
        t.idleMu.Lock()
        defer t.idleMu.Unlock()
-       return t.wantIdle
+       return t.closeIdle
 }
 
-func (t *Transport) RequestIdleConnChForTesting() {
-       t.getIdleConnCh(connectMethod{nil, "http", "example.com", false})
+func (t *Transport) QueueForIdleConnForTesting() {
+       t.queueForIdleConn(nil)
 }
 
+// PutIdleTestConn reports whether it was able to insert a fresh
+// persistConn for scheme, addr into the idle connection pool.
 func (t *Transport) PutIdleTestConn(scheme, addr string) bool {
        c, _ := net.Pipe()
        key := connectMethodKey{"", scheme, addr, false}
-       select {
-       case <-t.incHostConnCount(key):
-       default:
-               return false
+
+       if t.MaxConnsPerHost > 0 {
+               // Transport is tracking conns-per-host.
+               // Increment connection count to account
+               // for new persistConn created below.
+               t.connsPerHostMu.Lock()
+               if t.connsPerHost == nil {
+                       t.connsPerHost = make(map[connectMethodKey]int)
+               }
+               t.connsPerHost[key]++
+               t.connsPerHostMu.Unlock()
        }
+
        return t.tryPutIdleConn(&persistConn{
                t:        t,
                conn:     c,                   // dummy
index 2efa0ef125b5599184122b7facd42399d1784f2a..21921aba5fdd01e92e7aa6a1b5b299015034dcec 100644 (file)
@@ -3611,10 +3611,11 @@ func (p *http2pipe) Done() <-chan struct{} {
 }
 
 const (
-       http2prefaceTimeout        = 10 * time.Second
-       http2firstSettingsTimeout  = 2 * time.Second // should be in-flight with preface anyway
-       http2handlerChunkWriteSize = 4 << 10
-       http2defaultMaxStreams     = 250 // TODO: make this 100 as the GFE seems to?
+       http2prefaceTimeout         = 10 * time.Second
+       http2firstSettingsTimeout   = 2 * time.Second // should be in-flight with preface anyway
+       http2handlerChunkWriteSize  = 4 << 10
+       http2defaultMaxStreams      = 250 // TODO: make this 100 as the GFE seems to?
+       http2maxQueuedControlFrames = 10000
 )
 
 var (
@@ -3722,6 +3723,15 @@ func (s *http2Server) maxConcurrentStreams() uint32 {
        return http2defaultMaxStreams
 }
 
+// maxQueuedControlFrames is the maximum number of control frames like
+// SETTINGS, PING and RST_STREAM that will be queued for writing before
+// the connection is closed to prevent memory exhaustion attacks.
+func (s *http2Server) maxQueuedControlFrames() int {
+       // TODO: if anybody asks, add a Server field, and remember to define the
+       // behavior of negative values.
+       return http2maxQueuedControlFrames
+}
+
 type http2serverInternalState struct {
        mu          sync.Mutex
        activeConns map[*http2serverConn]struct{}
@@ -4065,6 +4075,7 @@ type http2serverConn struct {
        sawFirstSettings            bool // got the initial SETTINGS frame after the preface
        needToSendSettingsAck       bool
        unackedSettings             int    // how many SETTINGS have we sent without ACKs?
+       queuedControlFrames         int    // control frames in the writeSched queue
        clientMaxStreams            uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
        advMaxStreams               uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
        curClientStreams            uint32 // number of open streams initiated by the client
@@ -4456,6 +4467,14 @@ func (sc *http2serverConn) serve() {
                        }
                }
 
+               // If the peer is causing us to generate a lot of control frames,
+               // but not reading them from us, assume they are trying to make us
+               // run out of memory.
+               if sc.queuedControlFrames > sc.srv.maxQueuedControlFrames() {
+                       sc.vlogf("http2: too many control frames in send queue, closing connection")
+                       return
+               }
+
                // Start the shutdown timer after sending a GOAWAY. When sending GOAWAY
                // with no error code (graceful shutdown), don't start the timer until
                // all open streams have been completed.
@@ -4657,6 +4676,14 @@ func (sc *http2serverConn) writeFrame(wr http2FrameWriteRequest) {
        }
 
        if !ignoreWrite {
+               if wr.isControl() {
+                       sc.queuedControlFrames++
+                       // For extra safety, detect wraparounds, which should not happen,
+                       // and pull the plug.
+                       if sc.queuedControlFrames < 0 {
+                               sc.conn.Close()
+                       }
+               }
                sc.writeSched.Push(wr)
        }
        sc.scheduleFrameWrite()
@@ -4774,10 +4801,8 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
 // If a frame is already being written, nothing happens. This will be called again
 // when the frame is done being written.
 //
-// If a frame isn't being written we need to send one, the best frame
-// to send is selected, preferring first things that aren't
-// stream-specific (e.g. ACKing settings), and then finding the
-// highest priority stream.
+// If a frame isn't being written and we need to send one, the best frame
+// to send is selected by writeSched.
 //
 // If a frame isn't being written and there's nothing else to send, we
 // flush the write buffer.
@@ -4805,6 +4830,9 @@ func (sc *http2serverConn) scheduleFrameWrite() {
                }
                if !sc.inGoAway || sc.goAwayCode == http2ErrCodeNo {
                        if wr, ok := sc.writeSched.Pop(); ok {
+                               if wr.isControl() {
+                                       sc.queuedControlFrames--
+                               }
                                sc.startFrameWrite(wr)
                                continue
                        }
@@ -5097,6 +5125,8 @@ func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
        if err := f.ForeachSetting(sc.processSetting); err != nil {
                return err
        }
+       // TODO: judging by RFC 7540, Section 6.5.3 each SETTINGS frame should be
+       // acknowledged individually, even if multiple are received before the ACK.
        sc.needToSendSettingsAck = true
        sc.scheduleFrameWrite()
        return nil
@@ -7451,7 +7481,7 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
                req.Method != "HEAD" {
                // Request gzip only, not deflate. Deflate is ambiguous and
                // not as universally supported anyway.
-               // See: http://www.gzip.org/zlib/zlib_faq.html#faq38
+               // See: https://zlib.net/zlib_faq.html#faq39
                //
                // Note that we don't request this for HEAD requests,
                // due to a bug in nginx:
@@ -9460,7 +9490,7 @@ type http2WriteScheduler interface {
 
        // Pop dequeues the next frame to write. Returns false if no frames can
        // be written. Frames with a given wr.StreamID() are Pop'd in the same
-       // order they are Push'd.
+       // order they are Push'd. No frames should be discarded except by CloseStream.
        Pop() (wr http2FrameWriteRequest, ok bool)
 }
 
@@ -9504,6 +9534,12 @@ func (wr http2FrameWriteRequest) StreamID() uint32 {
        return wr.stream.id
 }
 
+// isControl reports whether wr is a control frame for MaxQueuedControlFrames
+// purposes. That includes non-stream frames and RST_STREAM frames.
+func (wr http2FrameWriteRequest) isControl() bool {
+       return wr.stream == nil
+}
+
 // DataSize returns the number of flow control bytes that must be consumed
 // to write this entire frame. This is 0 for non-DATA frames.
 func (wr http2FrameWriteRequest) DataSize() int {
index 1e1ed981ecc1961b626e2c0441f38ebbfdde07ca..230ca03d4f052d0f60d7c543c086171513fb947a 100644 (file)
@@ -78,8 +78,12 @@ func (h Header) write(w io.Writer, trace *httptrace.ClientTrace) error {
        return h.writeSubset(w, nil, trace)
 }
 
-// Clone returns a copy of h.
+// Clone returns a copy of h or nil if h is nil.
 func (h Header) Clone() Header {
+       if h == nil {
+               return nil
+       }
+
        // Find total number of values.
        nv := 0
        for _, vv := range h {
index 7595fb7f0ead4b745ca91f3ab2566e20836962b0..a82504afe329e82a5a773ccab9d41b2d27201e4a 100644 (file)
@@ -176,6 +176,14 @@ func TestHasToken(t *testing.T) {
        }
 }
 
+func TestNilHeaderClone(t *testing.T) {
+       t1 := Header(nil)
+       t2 := t1.Clone()
+       if t2 != nil {
+               t.Errorf("cloned header does not match original: got: %+v; want: %+v", t2, nil)
+       }
+}
+
 var testHeader = Header{
        "Content-Length": {"123"},
        "Content-Type":   {"text/plain"},
index 1d7b0efa11b91ff7cc463497dc3270c33534569e..e8f7df29a14d41da098361f71105ae66a56c063c 100644 (file)
@@ -199,6 +199,9 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
        if req.ContentLength == 0 {
                outreq.Body = nil // Issue 16036: nil Body for http.Transport retries
        }
+       if outreq.Header == nil {
+               outreq.Header = make(http.Header) // Issue 33142: historical behavior was to always allocate
+       }
 
        p.Director(outreq)
        outreq.Close = false
index e8cb8149387a453cdff5626be3753d4b20daec10..7f9dc0800f8d91e62be983ae45ee5bfbf5c134e7 100644 (file)
@@ -659,6 +659,26 @@ func TestReverseProxy_NilBody(t *testing.T) {
        }
 }
 
+// Issue 33142: always allocate the request headers
+func TestReverseProxy_AllocatedHeader(t *testing.T) {
+       proxyHandler := new(ReverseProxy)
+       proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
+       proxyHandler.Director = func(*http.Request) {}         // noop
+       proxyHandler.Transport = RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
+               if req.Header == nil {
+                       t.Error("Header == nil; want a non-nil Header")
+               }
+               return nil, errors.New("done testing the interesting part; so force a 502 Gateway error")
+       })
+
+       proxyHandler.ServeHTTP(httptest.NewRecorder(), &http.Request{
+               Method:     "GET",
+               URL:        &url.URL{Scheme: "http", Host: "fake.tld", Path: "/"},
+               Proto:      "HTTP/1.0",
+               ProtoMajor: 1,
+       })
+}
+
 // Issue 14237. Test ModifyResponse and that an error from it
 // causes the proxy to return StatusBadGateway, or StatusOK otherwise.
 func TestReverseProxyModifyResponse(t *testing.T) {
index fa63175c20c7a91541395b1eacb3ea12ade3566e..31d62083cb0ee3287a2f968735a325163d477693 100644 (file)
@@ -237,12 +237,12 @@ type Request struct {
        Host string
 
        // Form contains the parsed form data, including both the URL
-       // field's query parameters and the POST or PUT form data.
+       // field's query parameters and the PATCH, POST, or PUT form data.
        // This field is only available after ParseForm is called.
        // The HTTP client ignores Form and uses Body instead.
        Form url.Values
 
-       // PostForm contains the parsed form data from POST, PATCH,
+       // PostForm contains the parsed form data from PATCH, POST
        // or PUT body parameters.
        //
        // This field is only available after ParseForm is called.
@@ -450,7 +450,7 @@ func (r *Request) Referer() string {
 
 // multipartByReader is a sentinel value.
 // Its presence in Request.MultipartForm indicates that parsing of the request
-// body has been handed off to a MultipartReader instead of ParseMultipartFrom.
+// body has been handed off to a MultipartReader instead of ParseMultipartForm.
 var multipartByReader = &multipart.Form{
        Value: make(map[string][]string),
        File:  make(map[string][]*multipart.FileHeader),
index 2065a250156ba270a8d659d629105473d8a90a02..cd9d796c2641494041cb0273700b973e49e8a609 100644 (file)
@@ -66,7 +66,7 @@ type Response struct {
        // The Body is automatically dechunked if the server replied
        // with a "chunked" Transfer-Encoding.
        //
-       // As of Go 1.12, the Body will be also implement io.Writer
+       // As of Go 1.12, the Body will also implement io.Writer
        // on a successful "101 Switching Protocols" response,
        // as used by WebSockets and HTTP/2's "h2c" mode.
        Body io.ReadCloser
index e7ed15c3aa49613682cf6762249b31bba335818d..61adda2604c89979c4e170912ab5abf615be6808 100644 (file)
@@ -2407,6 +2407,7 @@ func TestTimeoutHandlerRace(t *testing.T) {
 }
 
 // See issues 8209 and 8414.
+// Both issues involved panics in the implementation of TimeoutHandler.
 func TestTimeoutHandlerRaceHeader(t *testing.T) {
        setParallel(t)
        defer afterTest(t)
@@ -2434,7 +2435,9 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) {
                        defer func() { <-gate }()
                        res, err := c.Get(ts.URL)
                        if err != nil {
-                               t.Error(err)
+                               // We see ECONNRESET from the connection occasionally,
+                               // and that's OK: this test is checking that the server does not panic.
+                               t.Log(err)
                                return
                        }
                        defer res.Body.Close()
@@ -5507,19 +5510,23 @@ func TestServerSetKeepAlivesEnabledClosesConns(t *testing.T) {
        if a1 != a2 {
                t.Fatal("expected first two requests on same connection")
        }
-       var idle0 int
-       if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool {
-               idle0 = tr.IdleConnKeyCountForTesting()
-               return idle0 == 1
-       }) {
-               t.Fatalf("idle count before SetKeepAlivesEnabled called = %v; want 1", idle0)
+       addr := strings.TrimPrefix(ts.URL, "http://")
+
+       // The two requests should have used the same connection,
+       // and there should not have been a second connection that
+       // was created by racing dial against reuse.
+       // (The first get was completed when the second get started.)
+       n := tr.IdleConnCountForTesting("http", addr)
+       if n != 1 {
+               t.Fatalf("idle count for %q after 2 gets = %d, want 1", addr, n)
        }
 
+       // SetKeepAlivesEnabled should discard idle conns.
        ts.Config.SetKeepAlivesEnabled(false)
 
        var idle1 int
        if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool {
-               idle1 = tr.IdleConnKeyCountForTesting()
+               idle1 = tr.IdleConnCountForTesting("http", addr)
                return idle1 == 0
        }) {
                t.Fatalf("idle count after SetKeepAlivesEnabled called = %v; want 0", idle1)
index 74569bf7b0760e69d051e3cfd51872366ad0e18a..aaf7b68eaff9404cde65a3b36f8531f335a3eef5 100644 (file)
@@ -231,13 +231,13 @@ type CloseNotifier interface {
 
 var (
        // ServerContextKey is a context key. It can be used in HTTP
-       // handlers with context.WithValue to access the server that
+       // handlers with Context.Value to access the server that
        // started the handler. The associated value will be of
        // type *Server.
        ServerContextKey = &contextKey{"http-server"}
 
        // LocalAddrContextKey is a context key. It can be used in
-       // HTTP handlers with context.WithValue to access the local
+       // HTTP handlers with Context.Value to access the local
        // address the connection arrived on.
        // The associated value will be of type net.Addr.
        LocalAddrContextKey = &contextKey{"local-addr"}
@@ -3182,8 +3182,8 @@ func (srv *Server) onceSetNextProtoDefaults() {
 // After such a timeout, writes by h to its ResponseWriter will return
 // ErrHandlerTimeout.
 //
-// TimeoutHandler buffers all Handler writes to memory and does not
-// support the Hijacker or Flusher interfaces.
+// TimeoutHandler supports the Flusher and Pusher interfaces but does not
+// support the Hijacker interface.
 func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
        return &timeoutHandler{
                handler: h,
index e6640dd404df285712b7294f6abdf74d9aece36a..d22d6363815fbc050aee9d0ea917ee5c1b44871c 100644 (file)
@@ -1,5 +1,5 @@
 // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
-//go:generate bundle -o socks_bundle.go -dst net/http -prefix socks -underscore golang.org/x/net/internal/socks
+//go:generate bundle -o socks_bundle.go -prefix socks golang.org/x/net/internal/socks
 
 // Package socks provides a SOCKS version 5 client implementation.
 //
index 26f642aa7a02b9f40c1dc2afa6feca0368ee8ec8..ee279877e02e2cede7ed3e2016ce518642f89966 100644 (file)
@@ -57,15 +57,6 @@ var DefaultTransport RoundTripper = &Transport{
 // MaxIdleConnsPerHost.
 const DefaultMaxIdleConnsPerHost = 2
 
-// connsPerHostClosedCh is a closed channel used by MaxConnsPerHost
-// for the property that receives from a closed channel return the
-// zero value.
-var connsPerHostClosedCh = make(chan struct{})
-
-func init() {
-       close(connsPerHostClosedCh)
-}
-
 // Transport is an implementation of RoundTripper that supports HTTP,
 // HTTPS, and HTTP proxies (for either HTTP or HTTPS with CONNECT).
 //
@@ -102,11 +93,11 @@ func init() {
 // request is treated as idempotent but the header is not sent on the
 // wire.
 type Transport struct {
-       idleMu     sync.Mutex
-       wantIdle   bool                                // user has requested to close all idle conns
-       idleConn   map[connectMethodKey][]*persistConn // most recently used at end
-       idleConnCh map[connectMethodKey]chan *persistConn
-       idleLRU    connLRU
+       idleMu       sync.Mutex
+       closeIdle    bool                                // user has requested to close all idle conns
+       idleConn     map[connectMethodKey][]*persistConn // most recently used at end
+       idleConnWait map[connectMethodKey]wantConnQueue  // waiting getConns
+       idleLRU      connLRU
 
        reqMu       sync.Mutex
        reqCanceler map[*Request]func(error)
@@ -114,9 +105,9 @@ type Transport struct {
        altMu    sync.Mutex   // guards changing altProto only
        altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme
 
-       connCountMu          sync.Mutex
-       connPerHostCount     map[connectMethodKey]int
-       connPerHostAvailable map[connectMethodKey]chan struct{}
+       connsPerHostMu   sync.Mutex
+       connsPerHost     map[connectMethodKey]int
+       connsPerHostWait map[connectMethodKey]wantConnQueue // waiting getConns
 
        // Proxy specifies a function to return a proxy for a given
        // Request. If the function returns a non-nil error, the
@@ -203,11 +194,6 @@ type Transport struct {
        // active, and idle states. On limit violation, dials will block.
        //
        // Zero means no limit.
-       //
-       // For HTTP/2, this currently only controls the number of new
-       // connections being created at a time, instead of the total
-       // number. In practice, hosts using HTTP/2 only have about one
-       // idle connection, though.
        MaxConnsPerHost int
 
        // IdleConnTimeout is the maximum amount of time an idle
@@ -543,7 +529,6 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
                var resp *Response
                if pconn.alt != nil {
                        // HTTP/2 path.
-                       t.putOrCloseIdleConn(pconn)
                        t.setReqCanceler(req, nil) // not cancelable with CancelRequest
                        resp, err = pconn.alt.RoundTrip(req)
                } else {
@@ -554,7 +539,6 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
                }
                if http2isNoCachedConnError(err) {
                        t.removeIdleConn(pconn)
-                       t.decHostConnCount(cm.key()) // clean up the persistent connection
                } else if !pconn.shouldRetryRequest(req, err) {
                        // Issue 16465: return underlying net.Conn.Read error from peek,
                        // as we've historically done.
@@ -665,8 +649,7 @@ func (t *Transport) CloseIdleConnections() {
        t.idleMu.Lock()
        m := t.idleConn
        t.idleConn = nil
-       t.idleConnCh = nil
-       t.wantIdle = true
+       t.closeIdle = true // close newly idle connections
        t.idleLRU = connLRU{}
        t.idleMu.Unlock()
        for _, conns := range m {
@@ -727,6 +710,8 @@ func resetProxyConfig() {
 }
 
 func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectMethod, err error) {
+       // TODO: the validPort check is redundant after CL 189258, as url.URL.Port
+       // only returns valid ports now. golang.org/issue/33600
        if port := treq.URL.Port(); !validPort(port) {
                return cm, fmt.Errorf("invalid URL port %q", port)
        }
@@ -762,7 +747,7 @@ func (cm *connectMethod) proxyAuth() string {
 var (
        errKeepAlivesDisabled = errors.New("http: putIdleConn: keep alives disabled")
        errConnBroken         = errors.New("http: putIdleConn: connection is in bad state")
-       errWantIdle           = errors.New("http: putIdleConn: CloseIdleConnections was called")
+       errCloseIdle          = errors.New("http: putIdleConn: CloseIdleConnections was called")
        errTooManyIdle        = errors.New("http: putIdleConn: too many idle connections")
        errTooManyIdleHost    = errors.New("http: putIdleConn: too many idle connections for host")
        errCloseIdleConns     = errors.New("http: CloseIdleConnections called")
@@ -821,29 +806,56 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
                return errConnBroken
        }
        pconn.markReused()
-       key := pconn.cacheKey
 
        t.idleMu.Lock()
        defer t.idleMu.Unlock()
 
-       waitingDialer := t.idleConnCh[key]
-       select {
-       case waitingDialer <- pconn:
-               // We're done with this pconn and somebody else is
-               // currently waiting for a conn of this type (they're
-               // actively dialing, but this conn is ready
-               // first). Chrome calls this socket late binding. See
-               // https://insouciant.org/tech/connection-management-in-chromium/
+       // HTTP/2 (pconn.alt != nil) connections do not come out of the idle list,
+       // because multiple goroutines can use them simultaneously.
+       // If this is an HTTP/2 connection being “returned,” we're done.
+       if pconn.alt != nil && t.idleLRU.m[pconn] != nil {
                return nil
-       default:
-               if waitingDialer != nil {
-                       // They had populated this, but their dial won
-                       // first, so we can clean up this map entry.
-                       delete(t.idleConnCh, key)
+       }
+
+       // Deliver pconn to goroutine waiting for idle connection, if any.
+       // (They may be actively dialing, but this conn is ready first.
+       // Chrome calls this socket late binding.
+       // See https://insouciant.org/tech/connection-management-in-chromium/.)
+       key := pconn.cacheKey
+       if q, ok := t.idleConnWait[key]; ok {
+               done := false
+               if pconn.alt == nil {
+                       // HTTP/1.
+                       // Loop over the waiting list until we find a w that isn't done already, and hand it pconn.
+                       for q.len() > 0 {
+                               w := q.popFront()
+                               if w.tryDeliver(pconn, nil) {
+                                       done = true
+                                       break
+                               }
+                       }
+               } else {
+                       // HTTP/2.
+                       // Can hand the same pconn to everyone in the waiting list,
+                       // and we still won't be done: we want to put it in the idle
+                       // list unconditionally, for any future clients too.
+                       for q.len() > 0 {
+                               w := q.popFront()
+                               w.tryDeliver(pconn, nil)
+                       }
+               }
+               if q.len() == 0 {
+                       delete(t.idleConnWait, key)
+               } else {
+                       t.idleConnWait[key] = q
+               }
+               if done {
+                       return nil
                }
        }
-       if t.wantIdle {
-               return errWantIdle
+
+       if t.closeIdle {
+               return errCloseIdle
        }
        if t.idleConn == nil {
                t.idleConn = make(map[connectMethodKey][]*persistConn)
@@ -864,71 +876,87 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
                oldest.close(errTooManyIdle)
                t.removeIdleConnLocked(oldest)
        }
-       if t.IdleConnTimeout > 0 {
+
+       // Set idle timer, but only for HTTP/1 (pconn.alt == nil).
+       // The HTTP/2 implementation manages the idle timer itself
+       // (see idleConnTimeout in h2_bundle.go).
+       if t.IdleConnTimeout > 0 && pconn.alt == nil {
                if pconn.idleTimer != nil {
                        pconn.idleTimer.Reset(t.IdleConnTimeout)
                } else {
-                       // idleTimer does not apply to HTTP/2
-                       if pconn.alt == nil {
-                               pconn.idleTimer = time.AfterFunc(t.IdleConnTimeout, pconn.closeConnIfStillIdle)
-                       }
+                       pconn.idleTimer = time.AfterFunc(t.IdleConnTimeout, pconn.closeConnIfStillIdle)
                }
        }
        pconn.idleAt = time.Now()
        return nil
 }
 
-// getIdleConnCh returns a channel to receive and return idle
-// persistent connection for the given connectMethod.
-// It may return nil, if persistent connections are not being used.
-func (t *Transport) getIdleConnCh(cm connectMethod) chan *persistConn {
+// queueForIdleConn queues w to receive the next idle connection for w.cm.
+// As an optimization hint to the caller, queueForIdleConn reports whether
+// it successfully delivered an already-idle connection.
+func (t *Transport) queueForIdleConn(w *wantConn) (delivered bool) {
        if t.DisableKeepAlives {
-               return nil
+               return false
        }
-       key := cm.key()
+
        t.idleMu.Lock()
        defer t.idleMu.Unlock()
-       t.wantIdle = false
-       if t.idleConnCh == nil {
-               t.idleConnCh = make(map[connectMethodKey]chan *persistConn)
-       }
-       ch, ok := t.idleConnCh[key]
-       if !ok {
-               ch = make(chan *persistConn)
-               t.idleConnCh[key] = ch
+
+       // Stop closing connections that become idle - we might want one.
+       // (That is, undo the effect of t.CloseIdleConnections.)
+       t.closeIdle = false
+
+       if w == nil {
+               // Happens in test hook.
+               return false
        }
-       return ch
-}
 
-func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn, idleSince time.Time) {
-       key := cm.key()
-       t.idleMu.Lock()
-       defer t.idleMu.Unlock()
-       for {
-               pconns, ok := t.idleConn[key]
-               if !ok {
-                       return nil, time.Time{}
+       // Look for most recently-used idle connection.
+       if list, ok := t.idleConn[w.key]; ok {
+               stop := false
+               delivered := false
+               for len(list) > 0 && !stop {
+                       pconn := list[len(list)-1]
+                       if pconn.isBroken() {
+                               // persistConn.readLoop has marked the connection broken,
+                               // but Transport.removeIdleConn has not yet removed it from the idle list.
+                               // Drop on floor on behalf of Transport.removeIdleConn.
+                               list = list[:len(list)-1]
+                               continue
+                       }
+                       delivered = w.tryDeliver(pconn, nil)
+                       if delivered {
+                               if pconn.alt != nil {
+                                       // HTTP/2: multiple clients can share pconn.
+                                       // Leave it in the list.
+                               } else {
+                                       // HTTP/1: only one client can use pconn.
+                                       // Remove it from the list.
+                                       t.idleLRU.remove(pconn)
+                                       list = list[:len(list)-1]
+                               }
+                       }
+                       stop = true
                }
-               if len(pconns) == 1 {
-                       pconn = pconns[0]
-                       delete(t.idleConn, key)
+               if len(list) > 0 {
+                       t.idleConn[w.key] = list
                } else {
-                       // 2 or more cached connections; use the most
-                       // recently used one at the end.
-                       pconn = pconns[len(pconns)-1]
-                       t.idleConn[key] = pconns[:len(pconns)-1]
+                       delete(t.idleConn, w.key)
                }
-               t.idleLRU.remove(pconn)
-               if pconn.isBroken() {
-                       // There is a tiny window where this is
-                       // possible, between the connecting dying and
-                       // the persistConn readLoop calling
-                       // Transport.removeIdleConn. Just skip it and
-                       // carry on.
-                       continue
+               if stop {
+                       return delivered
                }
-               return pconn, pconn.idleAt
        }
+
+       // Register to receive next connection that becomes idle.
+       if t.idleConnWait == nil {
+               t.idleConnWait = make(map[connectMethodKey]wantConnQueue)
+       }
+       q := t.idleConnWait[w.key]
+       q.cleanFront()
+       q.pushBack(w)
+       t.idleConnWait[w.key] = q
+       return false
 }
 
 // removeIdleConn marks pconn as dead.
@@ -1015,20 +1043,171 @@ func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, e
        return zeroDialer.DialContext(ctx, network, addr)
 }
 
+// A wantConn records state about a wanted connection
+// (that is, an active call to getConn).
+// The conn may be gotten by dialing or by finding an idle connection,
+// or a cancellation may make the conn no longer wanted.
+// These three options are racing against each other and use
+// wantConn to coordinate and agree about the winning outcome.
+type wantConn struct {
+       cm    connectMethod
+       key   connectMethodKey // cm.key()
+       ctx   context.Context  // context for dial
+       ready chan struct{}    // closed when pc, err pair is delivered
+
+       // hooks for testing to know when dials are done
+       // beforeDial is called in the getConn goroutine when the dial is queued.
+       // afterDial is called when the dial is completed or cancelled.
+       beforeDial func()
+       afterDial  func()
+
+       mu  sync.Mutex // protects pc, err, close(ready)
+       pc  *persistConn
+       err error
+}
+
+// waiting reports whether w is still waiting for an answer (connection or error).
+func (w *wantConn) waiting() bool {
+       select {
+       case <-w.ready:
+               return false
+       default:
+               return true
+       }
+}
+
+// tryDeliver attempts to deliver pc, err to w and reports whether it succeeded.
+func (w *wantConn) tryDeliver(pc *persistConn, err error) bool {
+       w.mu.Lock()
+       defer w.mu.Unlock()
+
+       if w.pc != nil || w.err != nil {
+               return false
+       }
+
+       w.pc = pc
+       w.err = err
+       if w.pc == nil && w.err == nil {
+               panic("net/http: internal error: misuse of tryDeliver")
+       }
+       close(w.ready)
+       return true
+}
+
+// cancel marks w as no longer wanting a result (for example, due to cancellation).
+// If a connection has been delivered already, cancel returns it with t.putOrCloseIdleConn.
+func (w *wantConn) cancel(t *Transport, err error) {
+       w.mu.Lock()
+       if w.pc == nil && w.err == nil {
+               close(w.ready) // catch misbehavior in future delivery
+       }
+       pc := w.pc
+       w.pc = nil
+       w.err = err
+       w.mu.Unlock()
+
+       if pc != nil {
+               t.putOrCloseIdleConn(pc)
+       }
+}
+
+// A wantConnQueue is a queue of wantConns.
+type wantConnQueue struct {
+       // This is a queue, not a deque.
+       // It is split into two stages - head[headPos:] and tail.
+       // popFront is trivial (headPos++) on the first stage, and
+       // pushBack is trivial (append) on the second stage.
+       // If the first stage is empty, popFront can swap the
+       // first and second stages to remedy the situation.
+       //
+       // This two-stage split is analogous to the use of two lists
+       // in Okasaki's purely functional queue but without the
+       // overhead of reversing the list when swapping stages.
+       head    []*wantConn
+       headPos int
+       tail    []*wantConn
+}
+
+// len returns the number of items in the queue.
+func (q *wantConnQueue) len() int {
+       return len(q.head) - q.headPos + len(q.tail)
+}
+
+// pushBack adds w to the back of the queue.
+func (q *wantConnQueue) pushBack(w *wantConn) {
+       q.tail = append(q.tail, w)
+}
+
+// popFront removes and returns the wantConn at the front of the queue.
+func (q *wantConnQueue) popFront() *wantConn {
+       if q.headPos >= len(q.head) {
+               if len(q.tail) == 0 {
+                       return nil
+               }
+               // Pick up tail as new head, clear tail.
+               q.head, q.headPos, q.tail = q.tail, 0, q.head[:0]
+       }
+       w := q.head[q.headPos]
+       q.head[q.headPos] = nil
+       q.headPos++
+       return w
+}
+
+// peekFront returns the wantConn at the front of the queue without removing it.
+func (q *wantConnQueue) peekFront() *wantConn {
+       if q.headPos < len(q.head) {
+               return q.head[q.headPos]
+       }
+       if len(q.tail) > 0 {
+               return q.tail[0]
+       }
+       return nil
+}
+
+// cleanFront pops any wantConns that are no longer waiting from the head of the
+// queue, reporting whether any were popped.
+func (q *wantConnQueue) cleanFront() (cleaned bool) {
+       for {
+               w := q.peekFront()
+               if w == nil || w.waiting() {
+                       return cleaned
+               }
+               q.popFront()
+               cleaned = true
+       }
+}
+
 // getConn dials and creates a new persistConn to the target as
 // specified in the connectMethod. This includes doing a proxy CONNECT
 // and/or setting up TLS.  If this doesn't return an error, the persistConn
 // is ready to write requests to.
-func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistConn, error) {
+func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persistConn, err error) {
        req := treq.Request
        trace := treq.trace
        ctx := req.Context()
        if trace != nil && trace.GetConn != nil {
                trace.GetConn(cm.addr())
        }
-       if pc, idleSince := t.getIdleConn(cm); pc != nil {
+
+       w := &wantConn{
+               cm:         cm,
+               key:        cm.key(),
+               ctx:        ctx,
+               ready:      make(chan struct{}, 1),
+               beforeDial: testHookPrePendingDial,
+               afterDial:  testHookPostPendingDial,
+       }
+       defer func() {
+               if err != nil {
+                       w.cancel(t, err)
+               }
+       }()
+
+       // Queue for idle connection.
+       if delivered := t.queueForIdleConn(w); delivered {
+               pc := w.pc
                if trace != nil && trace.GotConn != nil {
-                       trace.GotConn(pc.gotIdleConnTrace(idleSince))
+                       trace.GotConn(pc.gotIdleConnTrace(pc.idleAt))
                }
                // set request canceler to some non-nil function so we
                // can detect whether it was cleared between now and when
@@ -1037,108 +1216,44 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
                return pc, nil
        }
 
-       type dialRes struct {
-               pc  *persistConn
-               err error
-       }
-       dialc := make(chan dialRes)
-       cmKey := cm.key()
-
-       // Copy these hooks so we don't race on the postPendingDial in
-       // the goroutine we launch. Issue 11136.
-       testHookPrePendingDial := testHookPrePendingDial
-       testHookPostPendingDial := testHookPostPendingDial
-
-       handlePendingDial := func() {
-               testHookPrePendingDial()
-               go func() {
-                       if v := <-dialc; v.err == nil {
-                               t.putOrCloseIdleConn(v.pc)
-                       } else {
-                               t.decHostConnCount(cmKey)
-                       }
-                       testHookPostPendingDial()
-               }()
-       }
-
        cancelc := make(chan error, 1)
        t.setReqCanceler(req, func(err error) { cancelc <- err })
 
-       if t.MaxConnsPerHost > 0 {
-               select {
-               case <-t.incHostConnCount(cmKey):
-                       // count below conn per host limit; proceed
-               case pc := <-t.getIdleConnCh(cm):
-                       if trace != nil && trace.GotConn != nil {
-                               trace.GotConn(httptrace.GotConnInfo{Conn: pc.conn, Reused: pc.isReused()})
-                       }
-                       return pc, nil
-               case <-req.Cancel:
-                       return nil, errRequestCanceledConn
-               case <-req.Context().Done():
-                       return nil, req.Context().Err()
-               case err := <-cancelc:
-                       if err == errRequestCanceled {
-                               err = errRequestCanceledConn
-                       }
-                       return nil, err
-               }
-       }
+       // Queue for permission to dial.
+       t.queueForDial(w)
 
-       go func() {
-               pc, err := t.dialConn(ctx, cm)
-               dialc <- dialRes{pc, err}
-       }()
-
-       idleConnCh := t.getIdleConnCh(cm)
+       // Wait for completion or cancellation.
        select {
-       case v := <-dialc:
-               // Our dial finished.
-               if v.pc != nil {
-                       if trace != nil && trace.GotConn != nil && v.pc.alt == nil {
-                               trace.GotConn(httptrace.GotConnInfo{Conn: v.pc.conn})
+       case <-w.ready:
+               // Trace success but only for HTTP/1.
+               // HTTP/2 calls trace.GotConn itself.
+               if w.pc != nil && w.pc.alt == nil && trace != nil && trace.GotConn != nil {
+                       trace.GotConn(httptrace.GotConnInfo{Conn: w.pc.conn, Reused: w.pc.isReused()})
+               }
+               if w.err != nil {
+                       // If the request has been cancelled, that's probably
+                       // what caused w.err; if so, prefer to return the
+                       // cancellation error (see golang.org/issue/16049).
+                       select {
+                       case <-req.Cancel:
+                               return nil, errRequestCanceledConn
+                       case <-req.Context().Done():
+                               return nil, req.Context().Err()
+                       case err := <-cancelc:
+                               if err == errRequestCanceled {
+                                       err = errRequestCanceledConn
+                               }
+                               return nil, err
+                       default:
+                               // return below
                        }
-                       return v.pc, nil
                }
-               // Our dial failed. See why to return a nicer error
-               // value.
-               t.decHostConnCount(cmKey)
-               select {
-               case <-req.Cancel:
-                       // It was an error due to cancellation, so prioritize that
-                       // error value. (Issue 16049)
-                       return nil, errRequestCanceledConn
-               case <-req.Context().Done():
-                       return nil, req.Context().Err()
-               case err := <-cancelc:
-                       if err == errRequestCanceled {
-                               err = errRequestCanceledConn
-                       }
-                       return nil, err
-               default:
-                       // It wasn't an error due to cancellation, so
-                       // return the original error message:
-                       return nil, v.err
-               }
-       case pc := <-idleConnCh:
-               // Another request finished first and its net.Conn
-               // became available before our dial. Or somebody
-               // else's dial that they didn't use.
-               // But our dial is still going, so give it away
-               // when it finishes:
-               handlePendingDial()
-               if trace != nil && trace.GotConn != nil {
-                       trace.GotConn(httptrace.GotConnInfo{Conn: pc.conn, Reused: pc.isReused()})
-               }
-               return pc, nil
+               return w.pc, w.err
        case <-req.Cancel:
-               handlePendingDial()
                return nil, errRequestCanceledConn
        case <-req.Context().Done():
-               handlePendingDial()
                return nil, req.Context().Err()
        case err := <-cancelc:
-               handlePendingDial()
                if err == errRequestCanceled {
                        err = errRequestCanceledConn
                }
@@ -1146,81 +1261,103 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
        }
 }
 
-// incHostConnCount increments the count of connections for a
-// given host. It returns an already-closed channel if the count
-// is not at its limit; otherwise it returns a channel which is
-// notified when the count is below the limit.
-func (t *Transport) incHostConnCount(cmKey connectMethodKey) <-chan struct{} {
+// queueForDial queues w to wait for permission to begin dialing.
+// Once w receives permission to dial, it will do so in a separate goroutine.
+func (t *Transport) queueForDial(w *wantConn) {
+       w.beforeDial()
        if t.MaxConnsPerHost <= 0 {
-               return connsPerHostClosedCh
+               go t.dialConnFor(w)
+               return
        }
-       t.connCountMu.Lock()
-       defer t.connCountMu.Unlock()
-       if t.connPerHostCount[cmKey] == t.MaxConnsPerHost {
-               if t.connPerHostAvailable == nil {
-                       t.connPerHostAvailable = make(map[connectMethodKey]chan struct{})
-               }
-               ch, ok := t.connPerHostAvailable[cmKey]
-               if !ok {
-                       ch = make(chan struct{})
-                       t.connPerHostAvailable[cmKey] = ch
+
+       t.connsPerHostMu.Lock()
+       defer t.connsPerHostMu.Unlock()
+
+       if n := t.connsPerHost[w.key]; n < t.MaxConnsPerHost {
+               if t.connsPerHost == nil {
+                       t.connsPerHost = make(map[connectMethodKey]int)
                }
-               return ch
+               t.connsPerHost[w.key] = n + 1
+               go t.dialConnFor(w)
+               return
        }
-       if t.connPerHostCount == nil {
-               t.connPerHostCount = make(map[connectMethodKey]int)
+
+       if t.connsPerHostWait == nil {
+               t.connsPerHostWait = make(map[connectMethodKey]wantConnQueue)
        }
-       t.connPerHostCount[cmKey]++
-       // return a closed channel to avoid race: if decHostConnCount is called
-       // after incHostConnCount and during the nil check, decHostConnCount
-       // will delete the channel since it's not being listened on yet.
-       return connsPerHostClosedCh
+       q := t.connsPerHostWait[w.key]
+       q.cleanFront()
+       q.pushBack(w)
+       t.connsPerHostWait[w.key] = q
 }
 
-// decHostConnCount decrements the count of connections
-// for a given host.
-// See Transport.MaxConnsPerHost.
-func (t *Transport) decHostConnCount(cmKey connectMethodKey) {
+// dialConnFor dials on behalf of w and delivers the result to w.
+// dialConnFor has received permission to dial w.cm and is counted in t.connCount[w.cm.key()].
+// If the dial is cancelled or unsuccessful, dialConnFor decrements t.connCount[w.cm.key()].
+func (t *Transport) dialConnFor(w *wantConn) {
+       defer w.afterDial()
+
+       pc, err := t.dialConn(w.ctx, w.cm)
+       delivered := w.tryDeliver(pc, err)
+       if err == nil && (!delivered || pc.alt != nil) {
+               // pconn was not passed to w,
+               // or it is HTTP/2 and can be shared.
+               // Add to the idle connection pool.
+               t.putOrCloseIdleConn(pc)
+       }
+       if err != nil {
+               t.decConnsPerHost(w.key)
+       }
+}
+
+// decConnsPerHost decrements the per-host connection count for key,
+// which may in turn give a different waiting goroutine permission to dial.
+func (t *Transport) decConnsPerHost(key connectMethodKey) {
        if t.MaxConnsPerHost <= 0 {
                return
        }
-       t.connCountMu.Lock()
-       defer t.connCountMu.Unlock()
-       t.connPerHostCount[cmKey]--
-       select {
-       case t.connPerHostAvailable[cmKey] <- struct{}{}:
-       default:
-               // close channel before deleting avoids getConn waiting forever in
-               // case getConn has reference to channel but hasn't started waiting.
-               // This could lead to more than MaxConnsPerHost in the unlikely case
-               // that > 1 go routine has fetched the channel but none started waiting.
-               if t.connPerHostAvailable[cmKey] != nil {
-                       close(t.connPerHostAvailable[cmKey])
+
+       t.connsPerHostMu.Lock()
+       defer t.connsPerHostMu.Unlock()
+       n := t.connsPerHost[key]
+       if n == 0 {
+               // Shouldn't happen, but if it does, the counting is buggy and could
+               // easily lead to a silent deadlock, so report the problem loudly.
+               panic("net/http: internal error: connCount underflow")
+       }
+
+       // Can we hand this count to a goroutine still waiting to dial?
+       // (Some goroutines on the wait list may have timed out or
+       // gotten a connection another way. If they're all gone,
+       // we don't want to kick off any spurious dial operations.)
+       if q := t.connsPerHostWait[key]; q.len() > 0 {
+               done := false
+               for q.len() > 0 {
+                       w := q.popFront()
+                       if w.waiting() {
+                               go t.dialConnFor(w)
+                               done = true
+                               break
+                       }
+               }
+               if q.len() == 0 {
+                       delete(t.connsPerHostWait, key)
+               } else {
+                       // q is a value (like a slice), so we have to store
+                       // the updated q back into the map.
+                       t.connsPerHostWait[key] = q
+               }
+               if done {
+                       return
                }
-               delete(t.connPerHostAvailable, cmKey)
-       }
-       if t.connPerHostCount[cmKey] == 0 {
-               delete(t.connPerHostCount, cmKey)
        }
-}
 
-// connCloseListener wraps a connection, the transport that dialed it
-// and the connected-to host key so the host connection count can be
-// transparently decremented by whatever closes the embedded connection.
-type connCloseListener struct {
-       net.Conn
-       t        *Transport
-       cmKey    connectMethodKey
-       didClose int32
-}
-
-func (c *connCloseListener) Close() error {
-       if atomic.AddInt32(&c.didClose, 1) != 1 {
-               return nil
+       // Otherwise, decrement the recorded count.
+       if n--; n == 0 {
+               delete(t.connsPerHost, key)
+       } else {
+               t.connsPerHost[key] = n
        }
-       err := c.Conn.Close()
-       c.t.decHostConnCount(c.cmKey)
-       return err
 }
 
 // The connect method and the transport can both specify a TLS
@@ -1283,8 +1420,8 @@ func (pconn *persistConn) addTLS(name string, trace *httptrace.ClientTrace) erro
        return nil
 }
 
-func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistConn, error) {
-       pconn := &persistConn{
+func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *persistConn, err error) {
+       pconn = &persistConn{
                t:             t,
                cacheKey:      cm.key(),
                reqch:         make(chan requestAndChan, 1),
@@ -1423,9 +1560,6 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
                }
        }
 
-       if t.MaxConnsPerHost > 0 {
-               pconn.conn = &connCloseListener{Conn: pconn.conn, t: t, cmKey: pconn.cacheKey}
-       }
        pconn.br = bufio.NewReaderSize(pconn, t.readBufferSize())
        pconn.bw = bufio.NewWriterSize(persistConnWriter{pconn}, t.writeBufferSize())
 
@@ -1631,7 +1765,7 @@ func (pc *persistConn) canceled() error {
        return pc.canceledErr
 }
 
-// isReused reports whether this connection is in a known broken state.
+// isReused reports whether this connection has been used before.
 func (pc *persistConn) isReused() bool {
        pc.mu.Lock()
        r := pc.reused
@@ -2119,10 +2253,12 @@ func (pc *persistConn) wroteRequest() bool {
                // but the server has already replied. In this case, we don't
                // want to wait too long, and we want to return false so this
                // connection isn't re-used.
+               t := time.NewTimer(maxWriteWaitBeforeConnReuse)
+               defer t.Stop()
                select {
                case err := <-pc.writeErrCh:
                        return err == nil
-               case <-time.After(maxWriteWaitBeforeConnReuse):
+               case <-t.C:
                        return false
                }
        }
@@ -2176,16 +2312,6 @@ func (e *httpError) Error() string   { return e.err }
 func (e *httpError) Timeout() bool   { return e.timeout }
 func (e *httpError) Temporary() bool { return true }
 
-func (e *httpError) Is(target error) bool {
-       switch target {
-       case os.ErrTimeout:
-               return e.timeout
-       case os.ErrTemporary:
-               return true
-       }
-       return false
-}
-
 var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
 
 // errRequestCanceled is set to be identical to the one from h2 to facilitate
@@ -2374,10 +2500,10 @@ func (pc *persistConn) closeLocked(err error) {
        pc.broken = true
        if pc.closed == nil {
                pc.closed = err
-               if pc.alt != nil {
-                       // Clean up any host connection counting.
-                       pc.t.decHostConnCount(pc.cacheKey)
-               } else {
+               pc.t.decConnsPerHost(pc.cacheKey)
+               // Close HTTP/1 (pc.alt == nil) connection.
+               // HTTP/2 closes its connection itself.
+               if pc.alt == nil {
                        if err != errCallerOwnsConn {
                                pc.conn.Close()
                        }
@@ -2520,10 +2646,6 @@ func (tlsHandshakeTimeoutError) Timeout() bool   { return true }
 func (tlsHandshakeTimeoutError) Temporary() bool { return true }
 func (tlsHandshakeTimeoutError) Error() string   { return "net/http: TLS handshake timeout" }
 
-func (tlsHandshakeTimeoutError) Is(target error) bool {
-       return target == os.ErrTimeout || target == os.ErrTemporary
-}
-
 // fakeLocker is a sync.Locker which does nothing. It's used to guard
 // test-only fields when not under test, to avoid runtime atomic
 // overhead.
index 2b58e1daecb844691bcef42185118ee8bbf3e5a2..f304a7bc0e4d0d93629f62c916ceea51613c443d 100644 (file)
@@ -655,13 +655,17 @@ func TestTransportMaxConnsPerHost(t *testing.T) {
 
                expected := int32(tr.MaxConnsPerHost)
                if dialCnt != expected {
-                       t.Errorf("Too many dials (%s): %d", scheme, dialCnt)
+                       t.Errorf("round 1: too many dials (%s): %d != %d", scheme, dialCnt, expected)
                }
                if gotConnCnt != expected {
-                       t.Errorf("Too many get connections (%s): %d", scheme, gotConnCnt)
+                       t.Errorf("round 1: too many get connections (%s): %d != %d", scheme, gotConnCnt, expected)
                }
                if ts.TLS != nil && tlsHandshakeCnt != expected {
-                       t.Errorf("Too many tls handshakes (%s): %d", scheme, tlsHandshakeCnt)
+                       t.Errorf("round 1: too many tls handshakes (%s): %d != %d", scheme, tlsHandshakeCnt, expected)
+               }
+
+               if t.Failed() {
+                       t.FailNow()
                }
 
                (<-connCh).Close()
@@ -670,13 +674,13 @@ func TestTransportMaxConnsPerHost(t *testing.T) {
                doReq()
                expected++
                if dialCnt != expected {
-                       t.Errorf("Too many dials (%s): %d", scheme, dialCnt)
+                       t.Errorf("round 2: too many dials (%s): %d", scheme, dialCnt)
                }
                if gotConnCnt != expected {
-                       t.Errorf("Too many get connections (%s): %d", scheme, gotConnCnt)
+                       t.Errorf("round 2: too many get connections (%s): %d != %d", scheme, gotConnCnt, expected)
                }
                if ts.TLS != nil && tlsHandshakeCnt != expected {
-                       t.Errorf("Too many tls handshakes (%s): %d", scheme, tlsHandshakeCnt)
+                       t.Errorf("round 2: too many tls handshakes (%s): %d != %d", scheme, tlsHandshakeCnt, expected)
                }
        }
 
@@ -1654,6 +1658,180 @@ func TestTransportPersistConnLeakShortBody(t *testing.T) {
        }
 }
 
+// A countedConn is a net.Conn that decrements an atomic counter when finalized.
+type countedConn struct {
+       net.Conn
+}
+
+// A countingDialer dials connections and counts the number that remain reachable.
+type countingDialer struct {
+       dialer      net.Dialer
+       mu          sync.Mutex
+       total, live int64
+}
+
+func (d *countingDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
+       conn, err := d.dialer.DialContext(ctx, network, address)
+       if err != nil {
+               return nil, err
+       }
+
+       counted := new(countedConn)
+       counted.Conn = conn
+
+       d.mu.Lock()
+       defer d.mu.Unlock()
+       d.total++
+       d.live++
+
+       runtime.SetFinalizer(counted, d.decrement)
+       return counted, nil
+}
+
+func (d *countingDialer) decrement(*countedConn) {
+       d.mu.Lock()
+       defer d.mu.Unlock()
+       d.live--
+}
+
+func (d *countingDialer) Read() (total, live int64) {
+       d.mu.Lock()
+       defer d.mu.Unlock()
+       return d.total, d.live
+}
+
+func TestTransportPersistConnLeakNeverIdle(t *testing.T) {
+       defer afterTest(t)
+
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               // Close every connection so that it cannot be kept alive.
+               conn, _, err := w.(Hijacker).Hijack()
+               if err != nil {
+                       t.Errorf("Hijack failed unexpectedly: %v", err)
+                       return
+               }
+               conn.Close()
+       }))
+       defer ts.Close()
+
+       var d countingDialer
+       c := ts.Client()
+       c.Transport.(*Transport).DialContext = d.DialContext
+
+       body := []byte("Hello")
+       for i := 0; ; i++ {
+               total, live := d.Read()
+               if live < total {
+                       break
+               }
+               if i >= 1<<12 {
+                       t.Fatalf("Count of live client net.Conns (%d) not lower than total (%d) after %d Do / GC iterations.", live, total, i)
+               }
+
+               req, err := NewRequest("POST", ts.URL, bytes.NewReader(body))
+               if err != nil {
+                       t.Fatal(err)
+               }
+               _, err = c.Do(req)
+               if err == nil {
+                       t.Fatal("expected broken connection")
+               }
+
+               runtime.GC()
+       }
+}
+
+type countedContext struct {
+       context.Context
+}
+
+type contextCounter struct {
+       mu   sync.Mutex
+       live int64
+}
+
+func (cc *contextCounter) Track(ctx context.Context) context.Context {
+       counted := new(countedContext)
+       counted.Context = ctx
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       cc.live++
+       runtime.SetFinalizer(counted, cc.decrement)
+       return counted
+}
+
+func (cc *contextCounter) decrement(*countedContext) {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       cc.live--
+}
+
+func (cc *contextCounter) Read() (live int64) {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       return cc.live
+}
+
+func TestTransportPersistConnContextLeakMaxConnsPerHost(t *testing.T) {
+       if runtime.Compiler == "gccgo" {
+               t.Skip("fails with conservative stack GC")
+       }
+
+       defer afterTest(t)
+
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               runtime.Gosched()
+               w.WriteHeader(StatusOK)
+       }))
+       defer ts.Close()
+
+       c := ts.Client()
+       c.Transport.(*Transport).MaxConnsPerHost = 1
+
+       ctx := context.Background()
+       body := []byte("Hello")
+       doPosts := func(cc *contextCounter) {
+               var wg sync.WaitGroup
+               for n := 64; n > 0; n-- {
+                       wg.Add(1)
+                       go func() {
+                               defer wg.Done()
+
+                               ctx := cc.Track(ctx)
+                               req, err := NewRequest("POST", ts.URL, bytes.NewReader(body))
+                               if err != nil {
+                                       t.Error(err)
+                               }
+
+                               _, err = c.Do(req.WithContext(ctx))
+                               if err != nil {
+                                       t.Errorf("Do failed with error: %v", err)
+                               }
+                       }()
+               }
+               wg.Wait()
+       }
+
+       var initialCC contextCounter
+       doPosts(&initialCC)
+
+       // flushCC exists only to put pressure on the GC to finalize the initialCC
+       // contexts: the flushCC allocations should eventually displace the initialCC
+       // allocations.
+       var flushCC contextCounter
+       for i := 0; ; i++ {
+               live := initialCC.Read()
+               if live == 0 {
+                       break
+               }
+               if i >= 100 {
+                       t.Fatalf("%d Contexts still not finalized after %d GC cycles.", live, i)
+               }
+               doPosts(&flushCC)
+               runtime.GC()
+       }
+}
+
 // This used to crash; https://golang.org/issue/3266
 func TestTransportIdleConnCrash(t *testing.T) {
        defer afterTest(t)
@@ -2795,8 +2973,8 @@ func TestIdleConnChannelLeak(t *testing.T) {
                        <-didRead
                }
 
-               if got := tr.IdleConnChMapSizeForTesting(); got != 0 {
-                       t.Fatalf("ForDisableKeepAlives = %v, map size = %d; want 0", disableKeep, got)
+               if got := tr.IdleConnWaitMapSizeForTesting(); got != 0 {
+                       t.Fatalf("for DisableKeepAlives = %v, map size = %d; want 0", disableKeep, got)
                }
        }
 }
@@ -3378,9 +3556,9 @@ func TestTransportCloseIdleConnsThenReturn(t *testing.T) {
        }
        wantIdle("after second put", 0)
 
-       tr.RequestIdleConnChForTesting() // should toggle the transport out of idle mode
+       tr.QueueForIdleConnForTesting() // should toggle the transport out of idle mode
        if tr.IsIdleForTesting() {
-               t.Error("shouldn't be idle after RequestIdleConnChForTesting")
+               t.Error("shouldn't be idle after QueueForIdleConnForTesting")
        }
        if !tr.PutIdleTestConn("http", "example.com") {
                t.Fatal("after re-activation")
@@ -3802,8 +3980,8 @@ func TestNoCrashReturningTransportAltConn(t *testing.T) {
        ln := newLocalListener(t)
        defer ln.Close()
 
-       handledPendingDial := make(chan bool, 1)
-       SetPendingDialHooks(nil, func() { handledPendingDial <- true })
+       var wg sync.WaitGroup
+       SetPendingDialHooks(func() { wg.Add(1) }, wg.Done)
        defer SetPendingDialHooks(nil, nil)
 
        testDone := make(chan struct{})
@@ -3873,7 +4051,7 @@ func TestNoCrashReturningTransportAltConn(t *testing.T) {
 
        doReturned <- true
        <-madeRoundTripper
-       <-handledPendingDial
+       wg.Wait()
 }
 
 func TestTransportReuseConnection_Gzip_Chunked(t *testing.T) {
@@ -4285,7 +4463,7 @@ func TestTransportRejectsAlphaPort(t *testing.T) {
                t.Fatalf("got %#v; want *url.Error", err)
        }
        got := ue.Err.Error()
-       want := `invalid URL port "123foo"`
+       want := `invalid port ":123foo" after host`
        if got != want {
                t.Errorf("got error %q; want %q", got, want)
        }
index cf90c0cd546c513b2fe52820e87955180d9dcea5..1a1d0e7dba471e528e15da67158474e54d8f6b7a 100644 (file)
@@ -513,12 +513,12 @@ func (n *IPNet) Contains(ip IP) bool {
 // Network returns the address's network name, "ip+net".
 func (n *IPNet) Network() string { return "ip+net" }
 
-// String returns the CIDR notation of n like "192.0.2.1/24"
+// String returns the CIDR notation of n like "192.0.2.0/24"
 // or "2001:db8::/48" as defined in RFC 4632 and RFC 4291.
 // If the mask is not in the canonical form, it returns the
 // string which consists of an IP address, followed by a slash
 // character and a mask expressed as hexadecimal form with no
-// punctuation like "198.51.100.1/c000ff00".
+// punctuation like "198.51.100.0/c000ff00".
 func (n *IPNet) String() string {
        nn, m := networkNumberAndMask(n)
        if nn == nil || m == nil {
index e0907806ca6e337465753e38cb33d4c7f4ca36c5..75207db4342cbe64a2a43b66ba1717695da8c337 100644 (file)
@@ -148,7 +148,7 @@ type Address struct {
        Address string // user@domain
 }
 
-// Parses a single RFC 5322 address, e.g. "Barry Gibbs <bg@example.com>"
+// ParseAddress parses a single RFC 5322 address, e.g. "Barry Gibbs <bg@example.com>"
 func ParseAddress(address string) (*Address, error) {
        return (&addrParser{s: address}).parseSingleAddress()
 }
index b3f9b8ba07f04bd3c098af33a1ae70047c967d8b..38c6b9963747a5bb81293252d11b70643824a542 100644 (file)
@@ -146,6 +146,13 @@ type Conn interface {
        // the deadline after successful Read or Write calls.
        //
        // A zero value for t means I/O operations will not time out.
+       //
+       // Note that if a TCP connection has keep-alive turned on,
+       // which is the default unless overridden by Dialer.KeepAlive
+       // or ListenConfig.KeepAlive, then a keep-alive failure may
+       // also return a timeout error. On Unix systems a keep-alive
+       // failure on I/O can be detected using
+       // errors.Is(err, syscall.ETIMEDOUT).
        SetDeadline(t time.Time) error
 
        // SetReadDeadline sets the deadline for future Read calls
@@ -516,16 +523,6 @@ func (e *OpError) Temporary() bool {
        return ok && t.Temporary()
 }
 
-func (e *OpError) Is(target error) bool {
-       switch target {
-       case os.ErrTemporary:
-               return e.Temporary()
-       case os.ErrTimeout:
-               return e.Timeout()
-       }
-       return false
-}
-
 // A ParseError is the error type of literal network address parsers.
 type ParseError struct {
        // Type is the type of string that was expected, such as
@@ -617,16 +614,6 @@ func (e *DNSError) Timeout() bool { return e.IsTimeout }
 // error and return a DNSError for which Temporary returns false.
 func (e *DNSError) Temporary() bool { return e.IsTimeout || e.IsTemporary }
 
-func (e *DNSError) Is(target error) bool {
-       switch target {
-       case os.ErrTemporary:
-               return e.Temporary()
-       case os.ErrTimeout:
-               return e.Timeout()
-       }
-       return false
-}
-
 type writerOnly struct {
        io.Writer
 }
index 2b5845bb1580f3f5f4fdef7d24ef45dc4c8bba5f..463ae8856d2c57b274fb390a99de4ebb425518d6 100644 (file)
@@ -525,6 +525,9 @@ func TestNotTemporaryRead(t *testing.T) {
        if runtime.GOOS == "freebsd" {
                testenv.SkipFlaky(t, 25289)
        }
+       if runtime.GOOS == "aix" {
+               testenv.SkipFlaky(t, 29685)
+       }
        t.Parallel()
        server := func(cs *TCPConn) error {
                cs.SetLinger(0)
index 8cc127464b1e8ef7cdd31b3b5a3df1a21d9b0e95..9177fc403643e3b9de936811a9c1873efa5a34cf 100644 (file)
@@ -6,7 +6,6 @@ package net
 
 import (
        "io"
-       "os"
        "sync"
        "time"
 )
@@ -85,10 +84,6 @@ func (timeoutError) Error() string   { return "deadline exceeded" }
 func (timeoutError) Timeout() bool   { return true }
 func (timeoutError) Temporary() bool { return true }
 
-func (timeoutError) Is(target error) bool {
-       return target == os.ErrTemporary || target == os.ErrTimeout
-}
-
 type pipeAddr struct{}
 
 func (pipeAddr) Network() string { return "pipe" }
index 4b9fe7eba97c267f98c0c3a5e77d0be429dec5ad..b4fc2c0198169e58bf0d55ff5a387416f804fe44 100644 (file)
@@ -7,9 +7,7 @@
 package net
 
 import (
-       "errors"
        "fmt"
-       "internal/oserror"
        "internal/poll"
        "internal/testenv"
        "io"
@@ -90,9 +88,6 @@ func TestDialTimeout(t *testing.T) {
                        if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
                                t.Fatalf("#%d: %v", i, err)
                        }
-                       if !errors.Is(err, oserror.ErrTimeout) {
-                               t.Fatalf("#%d: Dial error is not os.ErrTimeout: %v", i, err)
-                       }
                }
        }
 }
@@ -826,24 +821,14 @@ func testVariousDeadlines(t *testing.T) {
                d   time.Duration
        }
 
-       ch := make(chan error, 1)
-       pasvch := make(chan result)
        handler := func(ls *localServer, ln Listener) {
                for {
                        c, err := ln.Accept()
                        if err != nil {
-                               ch <- err
-                               return
+                               break
                        }
-                       // The server, with no timeouts of its own,
-                       // sending bytes to clients as fast as it can.
-                       go func() {
-                               t0 := time.Now()
-                               n, err := io.Copy(c, neverEnding('a'))
-                               dt := time.Since(t0)
-                               c.Close()
-                               pasvch <- result{n, err, dt}
-                       }()
+                       c.Read(make([]byte, 1)) // wait for client to close connection
+                       c.Close()
                }
        }
        ls, err := newLocalServer("tcp")
@@ -884,18 +869,18 @@ func testVariousDeadlines(t *testing.T) {
                        }
                }
                for run := 0; run < numRuns; run++ {
-                       name := fmt.Sprintf("%v run %d/%d", timeout, run+1, numRuns)
+                       name := fmt.Sprintf("%v %d/%d", timeout, run, numRuns)
                        t.Log(name)
 
+                       tooSlow := time.NewTimer(5 * time.Second)
+                       defer tooSlow.Stop()
+
                        c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
                        if err != nil {
                                t.Fatal(err)
                        }
 
-                       tooLong := 5 * time.Second
-                       max := time.NewTimer(tooLong)
-                       defer max.Stop()
-                       actvch := make(chan result)
+                       ch := make(chan result, 1)
                        go func() {
                                t0 := time.Now()
                                if err := c.SetDeadline(t0.Add(timeout)); err != nil {
@@ -904,27 +889,18 @@ func testVariousDeadlines(t *testing.T) {
                                n, err := io.Copy(ioutil.Discard, c)
                                dt := time.Since(t0)
                                c.Close()
-                               actvch <- result{n, err, dt}
+                               ch <- result{n, err, dt}
                        }()
 
                        select {
-                       case res := <-actvch:
+                       case res := <-ch:
                                if nerr, ok := res.err.(Error); ok && nerr.Timeout() {
-                                       t.Logf("for %v, good client timeout after %v, reading %d bytes", name, res.d, res.n)
+                                       t.Logf("%v: good timeout after %v; %d bytes", name, res.d, res.n)
                                } else {
-                                       t.Fatalf("for %v, client Copy = %d, %v; want timeout", name, res.n, res.err)
+                                       t.Fatalf("%v: Copy = %d, %v; want timeout", name, res.n, res.err)
                                }
-                       case <-max.C:
-                               t.Fatalf("for %v, timeout (%v) waiting for client to timeout (%v) reading", name, tooLong, timeout)
-                       }
-
-                       select {
-                       case res := <-pasvch:
-                               t.Logf("for %v, server in %v wrote %d: %v", name, res.d, res.n, res.err)
-                       case err := <-ch:
-                               t.Fatalf("for %v, Accept = %v", name, err)
-                       case <-max.C:
-                               t.Fatalf("for %v, timeout waiting for server to finish writing", name)
+                       case <-tooSlow.C:
+                               t.Fatalf("%v: client stuck in Dial+Copy", name)
                        }
                }
        }
index 7f6ff93ce4657a18a7ac6cf8332f80c458809c6c..12ea35f0f9e02c96689084b58a0c695e208f7e9c 100644 (file)
@@ -13,7 +13,6 @@ package url
 import (
        "errors"
        "fmt"
-       "internal/oserror"
        "sort"
        "strconv"
        "strings"
@@ -26,10 +25,22 @@ type Error struct {
        Err error
 }
 
-func (e *Error) Unwrap() error   { return e.Err }
-func (e *Error) Error() string   { return e.Op + " " + e.URL + ": " + e.Err.Error() }
-func (e *Error) Timeout() bool   { return oserror.IsTimeout(e.Err) }
-func (e *Error) Temporary() bool { return oserror.IsTemporary(e.Err) }
+func (e *Error) Unwrap() error { return e.Err }
+func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() }
+
+func (e *Error) Timeout() bool {
+       t, ok := e.Err.(interface {
+               Timeout() bool
+       })
+       return ok && t.Timeout()
+}
+
+func (e *Error) Temporary() bool {
+       t, ok := e.Err.(interface {
+               Temporary() bool
+       })
+       return ok && t.Temporary()
+}
 
 func ishex(c byte) bool {
        switch {
@@ -637,6 +648,11 @@ func parseHost(host string) (string, error) {
                        }
                        return host1 + host2 + host3, nil
                }
+       } else if i := strings.LastIndex(host, ":"); i != -1 {
+               colonPort := host[i:]
+               if !validOptionalPort(colonPort) {
+                       return "", fmt.Errorf("invalid port %q after host", colonPort)
+               }
        }
 
        var err error
@@ -1035,44 +1051,39 @@ func (u *URL) RequestURI() string {
        return result
 }
 
-// Hostname returns u.Host, without any port number.
+// Hostname returns u.Host, stripping any valid port number if present.
 //
-// If Host is an IPv6 literal with a port number, Hostname returns the
-// IPv6 literal without the square brackets. IPv6 literals may include
-// a zone identifier.
+// If the result is enclosed in square brackets, as literal IPv6 addresses are,
+// the square brackets are removed from the result.
 func (u *URL) Hostname() string {
-       return stripPort(u.Host)
+       host, _ := splitHostPort(u.Host)
+       return host
 }
 
 // Port returns the port part of u.Host, without the leading colon.
-// If u.Host doesn't contain a port, Port returns an empty string.
+//
+// If u.Host doesn't contain a valid numeric port, Port returns an empty string.
 func (u *URL) Port() string {
-       return portOnly(u.Host)
+       _, port := splitHostPort(u.Host)
+       return port
 }
 
-func stripPort(hostport string) string {
-       colon := strings.IndexByte(hostport, ':')
-       if colon == -1 {
-               return hostport
-       }
-       if i := strings.IndexByte(hostport, ']'); i != -1 {
-               return strings.TrimPrefix(hostport[:i], "[")
-       }
-       return hostport[:colon]
-}
+// splitHostPort separates host and port. If the port is not valid, it returns
+// the entire input as host, and it doesn't check the validity of the host.
+// Unlike net.SplitHostPort, but per RFC 3986, it requires ports to be numeric.
+func splitHostPort(hostport string) (host, port string) {
+       host = hostport
 
-func portOnly(hostport string) string {
-       colon := strings.IndexByte(hostport, ':')
-       if colon == -1 {
-               return ""
+       colon := strings.LastIndexByte(host, ':')
+       if colon != -1 && validOptionalPort(host[colon:]) {
+               host, port = host[:colon], host[colon+1:]
        }
-       if i := strings.Index(hostport, "]:"); i != -1 {
-               return hostport[i+len("]:"):]
-       }
-       if strings.Contains(hostport, "]") {
-               return ""
+
+       if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
+               host = host[1 : len(host)-1]
        }
-       return hostport[colon+len(":"):]
+
+       return
 }
 
 // Marshaling interface implementations.
index e6d6ef8a838afcb55b6a42b688cceabd74b6b1e7..e83c86c424324e7b77b9598cc9bc6ff0709ba527 100644 (file)
@@ -422,10 +422,10 @@ var urltests = []URLTest{
        },
        // worst case host, still round trips
        {
-               "scheme://!$&'()*+,;=hello!:port/path",
+               "scheme://!$&'()*+,;=hello!:1/path",
                &URL{
                        Scheme: "scheme",
-                       Host:   "!$&'()*+,;=hello!:port",
+                       Host:   "!$&'()*+,;=hello!:1",
                        Path:   "/path",
                },
                "",
@@ -1425,11 +1425,13 @@ func TestParseErrors(t *testing.T) {
                {"http://[::1]", false},
                {"http://[::1]:80", false},
                {"http://[::1]:namedport", true}, // rfc3986 3.2.3
+               {"http://x:namedport", true},     // rfc3986 3.2.3
                {"http://[::1]/", false},
                {"http://[::1]a", true},
                {"http://[::1]%23", true},
                {"http://[::1%25en0]", false},     // valid zone id
                {"http://[::1]:", false},          // colon, but no port OK
+               {"http://x:", false},              // colon, but no port OK
                {"http://[::1]:%38%30", true},     // not allowed: % encoding only for non-ASCII
                {"http://[::1%25%41]", false},     // RFC 6874 allows over-escaping in zone
                {"http://[%10::1]", true},         // no %xx escapes in IP address
@@ -1621,52 +1623,46 @@ func TestURLErrorImplementsNetError(t *testing.T) {
        }
 }
 
-func TestURLHostname(t *testing.T) {
+func TestURLHostnameAndPort(t *testing.T) {
        tests := []struct {
-               host string // URL.Host field
-               want string
+               in   string // URL.Host field
+               host string
+               port string
        }{
-               {"foo.com:80", "foo.com"},
-               {"foo.com", "foo.com"},
-               {"FOO.COM", "FOO.COM"}, // no canonicalization (yet?)
-               {"1.2.3.4", "1.2.3.4"},
-               {"1.2.3.4:80", "1.2.3.4"},
-               {"[1:2:3:4]", "1:2:3:4"},
-               {"[1:2:3:4]:80", "1:2:3:4"},
-               {"[::1]:80", "::1"},
-               {"[::1]", "::1"},
-               {"localhost", "localhost"},
-               {"localhost:443", "localhost"},
-               {"some.super.long.domain.example.org:8080", "some.super.long.domain.example.org"},
-               {"[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:17000", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"},
-               {"[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"},
+               {"foo.com:80", "foo.com", "80"},
+               {"foo.com", "foo.com", ""},
+               {"foo.com:", "foo.com", ""},
+               {"FOO.COM", "FOO.COM", ""}, // no canonicalization
+               {"1.2.3.4", "1.2.3.4", ""},
+               {"1.2.3.4:80", "1.2.3.4", "80"},
+               {"[1:2:3:4]", "1:2:3:4", ""},
+               {"[1:2:3:4]:80", "1:2:3:4", "80"},
+               {"[::1]:80", "::1", "80"},
+               {"[::1]", "::1", ""},
+               {"[::1]:", "::1", ""},
+               {"localhost", "localhost", ""},
+               {"localhost:443", "localhost", "443"},
+               {"some.super.long.domain.example.org:8080", "some.super.long.domain.example.org", "8080"},
+               {"[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:17000", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "17000"},
+               {"[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", ""},
+
+               // Ensure that even when not valid, Host is one of "Hostname",
+               // "Hostname:Port", "[Hostname]" or "[Hostname]:Port".
+               // See https://golang.org/issue/29098.
+               {"[google.com]:80", "google.com", "80"},
+               {"google.com]:80", "google.com]", "80"},
+               {"google.com:80_invalid_port", "google.com:80_invalid_port", ""},
+               {"[::1]extra]:80", "::1]extra", "80"},
+               {"google.com]extra:extra", "google.com]extra:extra", ""},
        }
        for _, tt := range tests {
-               u := &URL{Host: tt.host}
-               got := u.Hostname()
-               if got != tt.want {
-                       t.Errorf("Hostname for Host %q = %q; want %q", tt.host, got, tt.want)
+               u := &URL{Host: tt.in}
+               host, port := u.Hostname(), u.Port()
+               if host != tt.host {
+                       t.Errorf("Hostname for Host %q = %q; want %q", tt.in, host, tt.host)
                }
-       }
-}
-
-func TestURLPort(t *testing.T) {
-       tests := []struct {
-               host string // URL.Host field
-               want string
-       }{
-               {"foo.com", ""},
-               {"foo.com:80", "80"},
-               {"1.2.3.4", ""},
-               {"1.2.3.4:80", "80"},
-               {"[1:2:3:4]", ""},
-               {"[1:2:3:4]:80", "80"},
-       }
-       for _, tt := range tests {
-               u := &URL{Host: tt.host}
-               got := u.Port()
-               if got != tt.want {
-                       t.Errorf("Port for Host %q = %q; want %q", tt.host, got, tt.want)
+               if port != tt.port {
+                       t.Errorf("Port for Host %q = %q; want %q", tt.in, port, tt.port)
                }
        }
 }
index 6c54456a21576bd633fdf4e88f490a673e263b0c..1d7ced8061c5d76223076c85f757284a7dd94728 100644 (file)
@@ -26,7 +26,10 @@ func (f *File) Readdir(n int) ([]FileInfo, error) {
        return f.readdir(n)
 }
 
-// Readdirnames reads and returns a slice of names from the directory f.
+// Readdirnames reads the contents of the directory associated with file
+// and returns a slice of up to n names of files in the directory,
+// in directory order. Subsequent calls on the same file will yield
+// further names.
 //
 // If n > 0, Readdirnames returns at most n names. In this case, if
 // Readdirnames returns an empty slice, it will return a non-nil error
index 0c2e6a73220a729dd10da1b17efe3b70281f64b0..0e8e2d47f8fa380dbcddfa43564fcd3748c9ac4a 100644 (file)
@@ -22,8 +22,6 @@ var (
        ErrExist      = errExist()      // "file already exists"
        ErrNotExist   = errNotExist()   // "file does not exist"
        ErrClosed     = errClosed()     // "file already closed"
-       ErrTimeout    = errTimeout()    // "deadline exceeded"
-       ErrTemporary  = errTemporary()  // "temporary error"
        ErrNoDeadline = errNoDeadline() // "file type does not support deadline"
 )
 
@@ -32,8 +30,6 @@ func errPermission() error { return oserror.ErrPermission }
 func errExist() error      { return oserror.ErrExist }
 func errNotExist() error   { return oserror.ErrNotExist }
 func errClosed() error     { return oserror.ErrClosed }
-func errTimeout() error    { return oserror.ErrTimeout }
-func errTemporary() error  { return oserror.ErrTemporary }
 func errNoDeadline() error { return poll.ErrNoDeadline }
 
 type timeout interface {
@@ -119,7 +115,8 @@ func underlyingErrorIs(err, target error) bool {
        if err == target {
                return true
        }
-       e, ok := err.(interface{ Is(error) bool })
+       // To preserve prior behavior, only examine syscall errors.
+       e, ok := err.(syscallErrorType)
        return ok && e.Is(target)
 }
 
diff --git a/libgo/go/os/error_errno.go b/libgo/go/os/error_errno.go
new file mode 100644 (file)
index 0000000..31ae05a
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2019 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.
+
+// +build !plan9
+
+package os
+
+import "syscall"
+
+type syscallErrorType = syscall.Errno
diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go
new file mode 100644 (file)
index 0000000..af6065d
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2019 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 os
+
+import "syscall"
+
+type syscallErrorType = syscall.ErrorString
index a03bd28b9ae908277bd88e50deb6e890fc6a8e6b..3d921578fd294fb3db45821687d921620591c624 100644 (file)
@@ -175,3 +175,13 @@ func TestPathErrorUnwrap(t *testing.T) {
                t.Error("errors.Is failed, wanted success")
        }
 }
+
+type myErrorIs struct{ error }
+
+func (e myErrorIs) Is(target error) bool { return target == e.error }
+
+func TestErrorIsMethods(t *testing.T) {
+       if os.IsPermission(myErrorIs{os.ErrPermission}) {
+               t.Error("os.IsPermission(err) = true when err.Is(os.ErrPermission), wanted false")
+       }
+}
index 96df3fb5e90fb24a3db90659fb3d585f29834a5a..c13babe5f7fad8ee418dc1783fc8e7e7413aea4e 100644 (file)
 //     }
 //     fmt.Printf("read %d bytes: %q\n", count, data[:count])
 //
+// Note: The maximum number of concurrent operations on a File may be limited by
+// the OS or the system. The number should be high, but exceeding it may degrade
+// performance or cause other issues.
+//
 package os
 
 import (
index b6430d36aebfbfff49f803db6a2b02b71bfe27fe..c27432f9ab4d2f09ece5ead8709ae039578c4a1d 100644 (file)
@@ -2253,6 +2253,8 @@ func TestPipeThreads(t *testing.T) {
                t.Skip("skipping on Plan 9; does not support runtime poller")
        case "js":
                t.Skip("skipping on js; no support for os.Pipe")
+       case "darwin":
+               t.Skip("skipping on Darwin; issue 33953")
        }
 
        threads := 100
index f3ecf57cb7c2e5988abc818b6d60d399055a9932..377aa49c91e366973aa51eb2e18781a2283905d1 100644 (file)
@@ -173,7 +173,7 @@ func openFdAt(dirfd int, name string) (*File, error) {
        var r int
        for {
                var e error
-               r, e = unix.Openat(dirfd, name, O_RDONLY, 0)
+               r, e = unix.Openat(dirfd, name, O_RDONLY|syscall.O_CLOEXEC, 0)
                if e == nil {
                        break
                }
index 075e8c11cb3f664f8e2e4f16512c0cedea26a71d..3c23090489f953dd89260208eccf12a864a1e9cc 100644 (file)
@@ -101,17 +101,6 @@ func TestTerminalSignal(t *testing.T) {
                Ctty:    int(slave.Fd()),
        }
 
-       // Test ctty management by sending enough child fd to overlap the
-       // parent's fd intended for child's ctty.
-       for 2+len(cmd.ExtraFiles) < cmd.SysProcAttr.Ctty {
-               dummy, err := os.Open(os.DevNull)
-               if err != nil {
-                       t.Fatal(err)
-               }
-               defer dummy.Close()
-               cmd.ExtraFiles = append(cmd.ExtraFiles, dummy)
-       }
-
        if err := cmd.Start(); err != nil {
                t.Fatal(err)
        }
index 600ff08797cc93a4b35ddccbc30e96ae31881b88..0c570f141351a3874805bf1df714990894d9fb93 100644 (file)
@@ -141,7 +141,7 @@ var jointests = []JoinTest{
 func TestJoin(t *testing.T) {
        for _, test := range jointests {
                if p := Join(test.elem...); p != test.path {
-                       t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
+                       t.Errorf("Join(%q) = %q, want %q", test.elem, p, test.path)
                }
        }
 }
index 823d43c6e88184396a31d8c2a186bb806d959353..6e06485f0180b1b84f5f2b5d52d82064c233e2c1 100644 (file)
@@ -2060,6 +2060,16 @@ func (p Point) TotalDist(points ...Point) int {
        return tot
 }
 
+// This will be index 5.
+func (p *Point) Int64Method(x int64) int64 {
+       return x
+}
+
+// This will be index 6.
+func (p *Point) Int32Method(x int32) int32 {
+       return x
+}
+
 func TestMethod(t *testing.T) {
        // Non-curried method of type.
        p := Point{3, 4}
@@ -2268,6 +2278,17 @@ func TestMethodValue(t *testing.T) {
        if i != 425 {
                t.Errorf("Interface MethodByName returned %d; want 425", i)
        }
+
+       // For issue #33628: method args are not stored at the right offset
+       // on amd64p32.
+       m64 := ValueOf(&p).MethodByName("Int64Method").Interface().(func(int64) int64)
+       if x := m64(123); x != 123 {
+               t.Errorf("Int64Method returned %d; want 123", x)
+       }
+       m32 := ValueOf(&p).MethodByName("Int32Method").Interface().(func(int32) int32)
+       if x := m32(456); x != 456 {
+               t.Errorf("Int32Method returned %d; want 456", x)
+       }
 }
 
 func TestVariadicMethodValue(t *testing.T) {
index e49625b46e669682c845e5a821a8a4c011952679..d39521094ec608e4bea43facc0303b64b9811a61 100644 (file)
@@ -36,9 +36,10 @@ type cpuProfile struct {
        // 300 words per second.
        // Hopefully a normal Go thread will get the profiling
        // signal at least once every few seconds.
-       extra     [1000]uintptr
-       numExtra  int
-       lostExtra uint64 // count of frames lost because extra is full
+       extra      [1000]uintptr
+       numExtra   int
+       lostExtra  uint64 // count of frames lost because extra is full
+       lostAtomic uint64 // count of frames lost because of being in atomic64 on mips/arm; updated racily
 }
 
 var cpuprof cpuProfile
@@ -94,7 +95,7 @@ func (p *cpuProfile) add(gp *g, stk []uintptr) {
        }
 
        if prof.hz != 0 { // implies cpuprof.log != nil
-               if p.numExtra > 0 || p.lostExtra > 0 {
+               if p.numExtra > 0 || p.lostExtra > 0 || p.lostAtomic > 0 {
                        p.addExtra()
                }
                hdr := [1]uint64{1}
@@ -159,18 +160,20 @@ func (p *cpuProfile) addExtra() {
                        _LostExternalCodePC + sys.PCQuantum,
                        _ExternalCodePC + sys.PCQuantum,
                }
-               cpuprof.log.write(nil, 0, hdr[:], lostStk[:])
+               p.log.write(nil, 0, hdr[:], lostStk[:])
                p.lostExtra = 0
        }
-}
 
-func (p *cpuProfile) addLostAtomic64(count uint64) {
-       hdr := [1]uint64{count}
-       lostStk := [2]uintptr{
-               _LostSIGPROFDuringAtomic64PC + sys.PCQuantum,
-               _SystemPC + sys.PCQuantum,
+       if p.lostAtomic > 0 {
+               hdr := [1]uint64{p.lostAtomic}
+               lostStk := [2]uintptr{
+                       _LostSIGPROFDuringAtomic64PC + sys.PCQuantum,
+                       _SystemPC + sys.PCQuantum,
+               }
+               p.log.write(nil, 0, hdr[:], lostStk[:])
+               p.lostAtomic = 0
        }
-       cpuprof.log.write(nil, 0, hdr[:], lostStk[:])
+
 }
 
 // CPUProfile panics.
index 0db23937926f054de768bccbda19bb68bd0b556c..10890d35a6583211de8f7f375b1076f0cca041e7 100644 (file)
@@ -675,3 +675,37 @@ func (t *Treap) CheckInvariants() {
        t.mTreap.treap.walkTreap(checkTreapNode)
        t.mTreap.treap.validateInvariants()
 }
+
+func RunGetgThreadSwitchTest() {
+       // Test that getg works correctly with thread switch.
+       // With gccgo, if we generate getg inlined, the backend
+       // may cache the address of the TLS variable, which
+       // will become invalid after a thread switch. This test
+       // checks that the bad caching doesn't happen.
+
+       ch := make(chan int)
+       go func(ch chan int) {
+               ch <- 5
+               LockOSThread()
+       }(ch)
+
+       g1 := getg()
+
+       // Block on a receive. This is likely to get us a thread
+       // switch. If we yield to the sender goroutine, it will
+       // lock the thread, forcing us to resume on a different
+       // thread.
+       <-ch
+
+       g2 := getg()
+       if g1 != g2 {
+               panic("g1 != g2")
+       }
+
+       // Also test getg after some control flow, as the
+       // backend is sensitive to control flow.
+       g3 := getg()
+       if g1 != g3 {
+               panic("g1 != g3")
+       }
+}
index cee5f6bc4de0dbfe8cca26637a0d8f2b707138f1..0eee55ef97ecfda4df88829b66b8c06386c2b2a3 100644 (file)
@@ -335,12 +335,21 @@ const (
 var physPageSize uintptr
 
 // physHugePageSize is the size in bytes of the OS's default physical huge
-// page size whose allocation is opaque to the application.
+// page size whose allocation is opaque to the application. It is assumed
+// and verified to be a power of two.
 //
 // If set, this must be set by the OS init code (typically in osinit) before
 // mallocinit. However, setting it at all is optional, and leaving the default
 // value is always safe (though potentially less efficient).
-var physHugePageSize uintptr
+//
+// Since physHugePageSize is always assumed to be a power of two,
+// physHugePageShift is defined as physHugePageSize == 1 << physHugePageShift.
+// The purpose of physHugePageShift is to avoid doing divisions in
+// performance critical functions.
+var (
+       physHugePageSize  uintptr
+       physHugePageShift uint
+)
 
 // OS memory management abstraction layer
 //
@@ -443,6 +452,17 @@ func mallocinit() {
                print("system page size (", physPageSize, ") must be a power of 2\n")
                throw("bad system page size")
        }
+       if physHugePageSize&(physHugePageSize-1) != 0 {
+               print("system huge page size (", physHugePageSize, ") must be a power of 2\n")
+               throw("bad system huge page size")
+       }
+       if physHugePageSize != 0 {
+               // Since physHugePageSize is a power of 2, it suffices to increase
+               // physHugePageShift until 1<<physHugePageShift == physHugePageSize.
+               for 1<<physHugePageShift != physHugePageSize {
+                       physHugePageShift++
+               }
+       }
 
        // Initialize the heap.
        mheap_.init()
@@ -877,7 +897,22 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
        if debug.sbrk != 0 {
                align := uintptr(16)
                if typ != nil {
-                       align = uintptr(typ.align)
+                       // TODO(austin): This should be just
+                       //   align = uintptr(typ.align)
+                       // but that's only 4 on 32-bit platforms,
+                       // even if there's a uint64 field in typ (see #599).
+                       // This causes 64-bit atomic accesses to panic.
+                       // Hence, we use stricter alignment that matches
+                       // the normal allocator better.
+                       if size&7 == 0 {
+                               align = 8
+                       } else if size&3 == 0 {
+                               align = 4
+                       } else if size&1 == 0 {
+                               align = 2
+                       } else {
+                               align = 1
+                       }
                }
                return persistentalloc(size, align, &memstats.other_sys)
        }
@@ -1076,8 +1111,8 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
        }
 
        if rate := MemProfileRate; rate > 0 {
-               if rate != 1 && int32(size) < c.next_sample {
-                       c.next_sample -= int32(size)
+               if rate != 1 && size < c.next_sample {
+                       c.next_sample -= size
                } else {
                        mp := acquirem()
                        profilealloc(mp, x, size)
@@ -1180,7 +1215,7 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
 // processes, the distance between two samples follows the exponential
 // distribution (exp(MemProfileRate)), so the best return value is a random
 // number taken from an exponential distribution whose mean is MemProfileRate.
-func nextSample() int32 {
+func nextSample() uintptr {
        if GOOS == "plan9" {
                // Plan 9 doesn't support floating point in note handler.
                if g := getg(); g == g.m.gsignal {
@@ -1188,7 +1223,7 @@ func nextSample() int32 {
                }
        }
 
-       return fastexprand(MemProfileRate)
+       return uintptr(fastexprand(MemProfileRate))
 }
 
 // fastexprand returns a random number from an exponential distribution with
@@ -1223,14 +1258,14 @@ func fastexprand(mean int) int32 {
 
 // nextSampleNoFP is similar to nextSample, but uses older,
 // simpler code to avoid floating point.
-func nextSampleNoFP() int32 {
+func nextSampleNoFP() uintptr {
        // Set first allocation sample size.
        rate := MemProfileRate
        if rate > 0x3fffffff { // make 2*rate not overflow
                rate = 0x3fffffff
        }
        if rate != 0 {
-               return int32(fastrand() % uint32(2*rate))
+               return uintptr(fastrand() % uint32(2*rate))
        }
        return 0
 }
index ca926827e1152f10710dacbdc4613a5e3e397b94..27328e1e31e5db955e0a601b1d54bceada113f4d 100644 (file)
@@ -19,7 +19,7 @@ import (
 type mcache struct {
        // The following members are accessed on every malloc,
        // so they are grouped here for better caching.
-       next_sample int32   // trigger heap sample after allocating this many bytes
+       next_sample uintptr // trigger heap sample after allocating this many bytes
        local_scan  uintptr // bytes of scannable heap allocated
 
        // Allocator cache for tiny objects w/o pointers.
index 910c1231278baa054eefa75476bfed3a5f15649a..9f8c4725f0881aaf6edb446304d0832997089b10 100644 (file)
@@ -130,7 +130,7 @@ func gcPaceScavenger() {
        if physHugePageSize != 0 {
                // Start by computing the amount of free memory we have in huge pages
                // in total. Trivially, this is all the huge page work we need to do.
-               hugeWork := uint64(mheap_.free.unscavHugePages * physHugePageSize)
+               hugeWork := uint64(mheap_.free.unscavHugePages) << physHugePageShift
 
                // ...but it could turn out that there's more huge work to do than
                // total work, so cap it at total work. This might happen for very large
@@ -138,14 +138,14 @@ func gcPaceScavenger() {
                // that there are free chunks of memory larger than a huge page that we don't want
                // to scavenge.
                if hugeWork >= totalWork {
-                       hugePages := totalWork / uint64(physHugePageSize)
-                       hugeWork = hugePages * uint64(physHugePageSize)
+                       hugePages := totalWork >> physHugePageShift
+                       hugeWork = hugePages << physHugePageShift
                }
                // Everything that's not huge work is regular work. At this point we
                // know huge work so we can calculate how much time that will take
                // based on scavengePageRate (which applies to pages of any size).
                regularWork = totalWork - hugeWork
-               hugeTime = hugeWork / uint64(physHugePageSize) * scavengeHugePagePeriod
+               hugeTime = (hugeWork >> physHugePageShift) * scavengeHugePagePeriod
        }
        // Finally, we can compute how much time it'll take to do the regular work
        // and the total time to do all the work.
index f18bf9beea366aef6ea58fbdef2ab31167a46f1e..cd01b3f757014ee7ff4bc49f58d585690aa5e171 100644 (file)
@@ -514,11 +514,13 @@ func (h *mheap) coalesce(s *mspan) {
                h.free.insert(other)
        }
 
-       hpBefore := s.hugePages()
+       hpMiddle := s.hugePages()
 
        // Coalesce with earlier, later spans.
+       var hpBefore uintptr
        if before := spanOf(s.base() - 1); before != nil && before.state == mSpanFree {
                if s.scavenged == before.scavenged {
+                       hpBefore = before.hugePages()
                        merge(before, s, before)
                } else {
                        realign(before, s, before)
@@ -526,23 +528,29 @@ func (h *mheap) coalesce(s *mspan) {
        }
 
        // Now check to see if next (greater addresses) span is free and can be coalesced.
+       var hpAfter uintptr
        if after := spanOf(s.base() + s.npages*pageSize); after != nil && after.state == mSpanFree {
                if s.scavenged == after.scavenged {
+                       hpAfter = after.hugePages()
                        merge(s, after, after)
                } else {
                        realign(s, after, after)
                }
        }
-
-       if !s.scavenged && s.hugePages() > hpBefore {
+       if !s.scavenged && s.hugePages() > hpBefore+hpMiddle+hpAfter {
                // If s has grown such that it now may contain more huge pages than it
-               // did before, then mark the whole region as huge-page-backable.
+               // and its now-coalesced neighbors did before, then mark the whole region
+               // as huge-page-backable.
                //
                // Otherwise, on systems where we break up huge pages (like Linux)
                // s may not be backed by huge pages because it could be made up of
                // pieces which are broken up in the underlying VMA. The primary issue
                // with this is that it can lead to a poor estimate of the amount of
                // free memory backed by huge pages for determining the scavenging rate.
+               //
+               // TODO(mknyszek): Measure the performance characteristics of sysHugePage
+               // and determine whether it makes sense to only sysHugePage on the pages
+               // that matter, or if it's better to just mark the whole region.
                sysHugePage(unsafe.Pointer(s.base()), s.npages*pageSize)
        }
 }
@@ -561,7 +569,7 @@ func (s *mspan) hugePages() uintptr {
                end &^= physHugePageSize - 1
        }
        if start < end {
-               return (end - start) / physHugePageSize
+               return (end - start) >> physHugePageShift
        }
        return 0
 }
index 21ffb5c2d0de1a47ba9a7bb3393bb91f179cad95..2a11f9329bcff41c2e2bb57d1c82887432f5718c 100644 (file)
@@ -61,13 +61,24 @@ func panicCheck1(pc uintptr, msg string) {
 }
 
 // Same as above, but calling from the runtime is allowed.
+//
+// Using this function is necessary for any panic that may be
+// generated by runtime.sigpanic, since those are always called by the
+// runtime.
 func panicCheck2(err string) {
+       // panic allocates, so to avoid recursive malloc, turn panics
+       // during malloc into throws.
        gp := getg()
        if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
                throw(err)
        }
 }
 
+// Many of the following panic entry-points turn into throws when they
+// happen in various runtime contexts. These should never happen in
+// the runtime, and if they do, they indicate a serious issue and
+// should not be caught by user code.
+//
 // The panic{Index,Slice,divide,shift} functions are called by
 // code generated by the compiler for out of bounds index expressions,
 // out of bounds slice expressions, division by zero, and shift by negative.
index e6aace83e26cfe49ef386ea161b829a9fd0630ed..b71bbad9a69d176f3f721c6a26367759104caf9f 100644 (file)
@@ -16,6 +16,7 @@ func runtime_setProfLabel(labels unsafe.Pointer)
 func runtime_getProfLabel() unsafe.Pointer
 
 // SetGoroutineLabels sets the current goroutine's labels to match ctx.
+// A new goroutine inherits the labels of the goroutine that created it.
 // This is a lower-level API than Do, which should be used instead when possible.
 func SetGoroutineLabels(ctx context.Context) {
        ctxLabels, _ := ctx.Value(labelContextKey{}).(*labelMap)
@@ -24,6 +25,7 @@ func SetGoroutineLabels(ctx context.Context) {
 
 // Do calls f with a copy of the parent context with the
 // given labels added to the parent's label map.
+// Goroutines spawned while executing f will inherit the augmented label-set.
 // Each key/value pair in labels is inserted into the label map in the
 // order provided, overriding any previous value for the same key.
 // The augmented label map will be set for the duration of the call to f
index afedad50b215fb03aed2f6dd4578fd88346b99bd..a0147cf954de97c10a4ef3dd1e26fcfc32033b83 100644 (file)
@@ -3505,9 +3505,6 @@ func _GC()                        { _GC() }
 func _LostSIGPROFDuringAtomic64() { _LostSIGPROFDuringAtomic64() }
 func _VDSO()                      { _VDSO() }
 
-// Counts SIGPROFs received while in atomic64 critical section, on mips{,le}
-var lostAtomic64Count uint64
-
 var _SystemPC = funcPC(_System)
 var _ExternalCodePC = funcPC(_ExternalCode)
 var _LostExternalCodePC = funcPC(_LostExternalCode)
@@ -3598,10 +3595,6 @@ func sigprof(pc uintptr, gp *g, mp *m) {
        }
 
        if prof.hz != 0 {
-               if (GOARCH == "mips" || GOARCH == "mipsle" || GOARCH == "arm") && lostAtomic64Count > 0 {
-                       cpuprof.addLostAtomic64(lostAtomic64Count)
-                       lostAtomic64Count = 0
-               }
                cpuprof.add(gp, stk[:n])
        }
        getg().m.mallocing--
index b9be3387dbdf43e8a4ecde3233015df24df32a69..fee03be6e58cf7bcaf10d5980196820e69045529 100644 (file)
@@ -984,3 +984,7 @@ func TestPreemptionAfterSyscall(t *testing.T) {
                })
        }
 }
+
+func TestGetgThreadSwitch(t *testing.T) {
+       runtime.RunGetgThreadSwitchTest()
+}
index 1a29b207f818bc246ba85724ed46d3537123db30..20704642f8ddcb9f47a1f3878cc17eb645da6fc0 100644 (file)
@@ -105,6 +105,10 @@ Send:
                        break Send
                case sigReceiving:
                        if atomic.Cas(&sig.state, sigReceiving, sigIdle) {
+                               if GOOS == "darwin" {
+                                       sigNoteWakeup(&sig.note)
+                                       break Send
+                               }
                                notewakeup(&sig.note)
                                break Send
                        }
@@ -136,6 +140,10 @@ func signal_recv() uint32 {
                                throw("signal_recv: inconsistent state")
                        case sigIdle:
                                if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
+                                       if GOOS == "darwin" {
+                                               sigNoteSleep(&sig.note)
+                                               break Receive
+                                       }
                                        notetsleepg(&sig.note, -1)
                                        noteclear(&sig.note)
                                        break Receive
@@ -188,6 +196,10 @@ func signal_enable(s uint32) {
                // to use for initialization. It does not pass
                // signal information in m.
                sig.inuse = true // enable reception of signals; cannot disable
+               if GOOS == "darwin" {
+                       sigNoteSetup(&sig.note)
+                       return
+               }
                noteclear(&sig.note)
                return
        }
diff --git a/libgo/go/runtime/sigqueue_note.go b/libgo/go/runtime/sigqueue_note.go
new file mode 100644 (file)
index 0000000..16aeeb2
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2019 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.
+
+// The current implementation of notes on Darwin is not async-signal-safe,
+// so on Darwin the sigqueue code uses different functions to wake up the
+// signal_recv thread. This file holds the non-Darwin implementations of
+// those functions. These functions will never be called.
+
+// +build !darwin
+// +build !plan9
+
+package runtime
+
+func sigNoteSetup(*note) {
+       throw("sigNoteSetup")
+}
+
+func sigNoteSleep(*note) {
+       throw("sigNoteSleep")
+}
+
+func sigNoteWakeup(*note) {
+       throw("sigNoteWakeup")
+}
index eff1379b97eccf21bd0b10f3793bd47305a0eca2..d531bda33febda1d102a46e108d076f0b9ef79af 100644 (file)
@@ -649,7 +649,7 @@ func atof64(s string) (f float64, err error) {
 // ParseFloat returns the nearest floating-point number rounded
 // using IEEE754 unbiased rounding.
 // (Parsing a hexadecimal floating-point value only rounds when
-// there are more bits in the hexadecimal representatiton than
+// there are more bits in the hexadecimal representation than
 // will fit in the mantissa.)
 //
 // The errors that ParseFloat returns have concrete type *NumError
index 31774d0c9a383dd05499a039924ba31a6670df8e..0233f14b406e4fc56dd40d8d334f81ca091dd398 100644 (file)
@@ -154,7 +154,8 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) {
 //
 // If base == 0, the base is implied by the string's prefix:
 // base 2 for "0b", base 8 for "0" or "0o", base 16 for "0x",
-// and base 10 otherwise.
+// and base 10 otherwise. Also, for base == 0 only, underscore
+// characters are permitted per the Go integer literal syntax.
 // If base is below 0, is 1, or is above 36, an error is returned.
 //
 // The bitSize argument specifies the integer type
index 4f3a1ce8c6fdf869eb20b383d6a8ab98102a62b4..375f9cac6502e89a0124315a04c1700b8cbd13ae 100644 (file)
@@ -247,14 +247,23 @@ func ExampleSplitAfterN() {
 }
 
 func ExampleTitle() {
+       // Compare this example to the ToTitle example.
        fmt.Println(strings.Title("her royal highness"))
-       // Output: Her Royal Highness
+       fmt.Println(strings.Title("loud noises"))
+       fmt.Println(strings.Title("хлеб"))
+       // Output:
+       // Her Royal Highness
+       // Loud Noises
+       // Хлеб
 }
 
 func ExampleToTitle() {
+       // Compare this example to the Title example.
+       fmt.Println(strings.ToTitle("her royal highness"))
        fmt.Println(strings.ToTitle("loud noises"))
        fmt.Println(strings.ToTitle("хлеб"))
        // Output:
+       // HER ROYAL HIGHNESS
        // LOUD NOISES
        // ХЛЕБ
 }
index ccab1fb861d3b3b07406b1f86a57931f5419f2ce..e28d42887930b9d852bdd2129c28f4ebf3bd8c8b 100644 (file)
@@ -25,7 +25,8 @@ type replacer interface {
 
 // NewReplacer returns a new Replacer from a list of old, new string
 // pairs. Replacements are performed in the order they appear in the
-// target string, without overlapping matches.
+// target string, without overlapping matches. The old string
+// comparisons are done in argument order.
 //
 // NewReplacer panics if given an odd number of arguments.
 func NewReplacer(oldnew ...string) *Replacer {
index 73374813809192d0a1f9df7e4b70cec4ed8e5a74..cee315ce9e4027b9647a0b1f550f91b3b92c277a 100644 (file)
@@ -610,7 +610,8 @@ func ToLower(s string) string {
        return Map(unicode.ToLower, s)
 }
 
-// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case.
+// ToTitle returns a copy of the string s with all Unicode letters mapped to
+// their Unicode title case.
 func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
 
 // ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
@@ -626,7 +627,7 @@ func ToLowerSpecial(c unicode.SpecialCase, s string) string {
 }
 
 // ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
-// title case, giving priority to the special casing rules.
+// Unicode title case, giving priority to the special casing rules.
 func ToTitleSpecial(c unicode.SpecialCase, s string) string {
        return Map(c.ToTitle, s)
 }
@@ -707,7 +708,7 @@ func isSeparator(r rune) bool {
 }
 
 // Title returns a copy of the string s with all Unicode letters that begin words
-// mapped to their title case.
+// mapped to their Unicode title case.
 //
 // BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
 func Title(s string) string {
index 10d3599f476550c7a7240a3f20036f87b09dd392..ffbe56746406288ae48cda2173346ed0b7f25d2d 100644 (file)
@@ -18,9 +18,13 @@ type PoolDequeue interface {
 }
 
 func NewPoolDequeue(n int) PoolDequeue {
-       return &poolDequeue{
+       d := &poolDequeue{
                vals: make([]eface, n),
        }
+       // For testing purposes, set the head and tail indexes close
+       // to wrapping around.
+       d.headTail = d.pack(1<<dequeueBits-500, 1<<dequeueBits-500)
+       return d
 }
 
 func (d *poolDequeue) PushHead(val interface{}) bool {
index 84761970dd87df766951e58f1915842c2f2c14b8..ca044082241232ec7ed7fe2a850a9e10d0978633 100644 (file)
@@ -38,6 +38,20 @@ type Once struct {
 // without calling f.
 //
 func (o *Once) Do(f func()) {
+       // Note: Here is an incorrect implementation of Do:
+       //
+       //      if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
+       //              f()
+       //      }
+       //
+       // Do guarantees that when it returns, f has finished.
+       // This implementation would not implement that guarantee:
+       // given two simultaneous calls, the winner of the cas would
+       // call f, and the second would return immediately, without
+       // waiting for the first's call to f to complete.
+       // This is why the slow path falls back to a mutex, and why
+       // the atomic.StoreUint32 must be delayed until after f returns.
+
        if atomic.LoadUint32(&o.done) == 0 {
                // Outlined slow-path to allow inlining of the fast-path.
                o.doSlow(f)
index 7e175a91cdd4279f4afb941c5c3487a5622be35d..c67bd8c4e8c314733507ffcfe598983abeff9aed 100644 (file)
@@ -174,15 +174,19 @@ func TestPoolChain(t *testing.T) {
 
 func testPoolDequeue(t *testing.T, d PoolDequeue) {
        const P = 10
-       // In long mode, do enough pushes to wrap around the 21-bit
-       // indexes.
-       N := 1<<21 + 1000
+       var N int = 2e6
        if testing.Short() {
                N = 1e3
        }
        have := make([]int32, N)
        var stop int32
        var wg WaitGroup
+       record := func(val int) {
+               atomic.AddInt32(&have[val], 1)
+               if val == N-1 {
+                       atomic.StoreInt32(&stop, 1)
+               }
+       }
 
        // Start P-1 consumers.
        for i := 1; i < P; i++ {
@@ -193,10 +197,7 @@ func testPoolDequeue(t *testing.T, d PoolDequeue) {
                                val, ok := d.PopTail()
                                if ok {
                                        fail = 0
-                                       atomic.AddInt32(&have[val.(int)], 1)
-                                       if val.(int) == N-1 {
-                                               atomic.StoreInt32(&stop, 1)
-                                       }
+                                       record(val.(int))
                                } else {
                                        // Speed up the test by
                                        // allowing the pusher to run.
@@ -222,7 +223,7 @@ func testPoolDequeue(t *testing.T, d PoolDequeue) {
                                val, ok := d.PopHead()
                                if ok {
                                        nPopHead++
-                                       atomic.AddInt32(&have[val.(int)], 1)
+                                       record(val.(int))
                                }
                        }
                }
@@ -236,10 +237,12 @@ func testPoolDequeue(t *testing.T, d PoolDequeue) {
                        t.Errorf("expected have[%d] = 1, got %d", i, count)
                }
        }
-       if nPopHead == 0 {
-               // In theory it's possible in a valid schedule for
-               // popHead to never succeed, but in practice it almost
-               // always succeeds, so this is unlikely to flake.
+       // Check that at least some PopHeads succeeded. We skip this
+       // check in short mode because it's common enough that the
+       // queue will stay nearly empty all the time and a PopTail
+       // will happen during the window between every PushHead and
+       // PopHead.
+       if !testing.Short() && nPopHead == 0 {
                t.Errorf("popHead never succeeded")
        }
 }
index 3a4db044e5ceef5b89d485f485dbff42da7fcb01..a241e2101f4521b932adc2e9647ff16ef54ea811 100644 (file)
@@ -168,26 +168,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
                }
        }
 
-       // Detach fd 0 from tty
-       if sys.Noctty {
-               _, err1 = raw_ioctl(0, TIOCNOTTY, 0)
-               if err1 != 0 {
-                       goto childerror
-               }
-       }
-
-       // Set the controlling TTY to Ctty
-       if sys.Setctty {
-               if TIOCSCTTY == 0 {
-                       err1 = ENOSYS
-                       goto childerror
-               }
-               _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 0)
-               if err1 != 0 {
-                       goto childerror
-               }
-       }
-
        // Pass 1: look for fd[i] < i and move those up above len(fd)
        // so that pass 2 won't stomp on an fd it needs later.
        if pipe < nextfd {
@@ -245,6 +225,26 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
                raw_close(i)
        }
 
+       // Detach fd 0 from tty
+       if sys.Noctty {
+               _, err1 = raw_ioctl(0, TIOCNOTTY, 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Set the controlling TTY to Ctty
+       if sys.Setctty {
+               if TIOCSCTTY == 0 {
+                       err1 = ENOSYS
+                       goto childerror
+               }
+               _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
        // Time to exec.
        err1 = raw_execve(argv0, &argv[0], &envv[0])
 
index 9f7bf67d2c3c541d2b237fcf3bdcf7a55976c509..ac1ead3a2b3339930e352341b183dd6ac7374ccf 100644 (file)
@@ -160,22 +160,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
                }
        }
 
-       // Detach fd 0 from tty
-       if sys.Noctty {
-               _, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), 0, uintptr(TIOCNOTTY), 0)
-               if err1 != 0 {
-                       goto childerror
-               }
-       }
-
-       // Set the controlling TTY to Ctty
-       if sys.Setctty {
-               _, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
-               if err1 != 0 {
-                       goto childerror
-               }
-       }
-
        // Pass 1: look for fd[i] < i and move those up above len(fd)
        // so that pass 2 won't stomp on an fd it needs later.
        if pipe < nextfd {
@@ -233,6 +217,22 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
                rawSyscall(funcPC(libc_close_trampoline), uintptr(i), 0, 0)
        }
 
+       // Detach fd 0 from tty
+       if sys.Noctty {
+               _, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), 0, uintptr(TIOCNOTTY), 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Set the controlling TTY to Ctty
+       if sys.Setctty {
+               _, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
        // Time to exec.
        _, _, err1 = rawSyscall(funcPC(libc_execve_trampoline),
                uintptr(unsafe.Pointer(argv0)),
index 215ecc23393ea4dc759777b12da4ae7af9c10db8..f842cdc85bf42218febac79e0822b47cb815bf09 100644 (file)
@@ -440,22 +440,6 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
                }
        }
 
-       // Detach fd 0 from tty
-       if sys.Noctty {
-               _, err1 = raw_ioctl(0, TIOCNOTTY, 0)
-               if err1 != 0 {
-                       goto childerror
-               }
-       }
-
-       // Set the controlling TTY to Ctty
-       if sys.Setctty {
-               _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 1)
-               if err1 != 0 {
-                       goto childerror
-               }
-       }
-
        // Pass 1: look for fd[i] < i and move those up above len(fd)
        // so that pass 2 won't stomp on an fd it needs later.
        if pipe < nextfd {
@@ -513,6 +497,22 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
                raw_close(i)
        }
 
+       // Detach fd 0 from tty
+       if sys.Noctty {
+               _, err1 = raw_ioctl(0, TIOCNOTTY, 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Set the controlling TTY to Ctty
+       if sys.Setctty {
+               _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 1)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
        // Enable tracing if requested.
        // Do this right before exec so that we don't unnecessarily trace the runtime
        // setting up after the fork. See issue #21428.
index b0f5c46bfc041e886a446721c3541b77a94c9243..a339ae82588ff72efdb6a94ee0a932b57a160d29 100644 (file)
@@ -21,10 +21,6 @@ func (e Errno) Error() string {
 
 func (e Errno) Is(target error) bool {
        switch target {
-       case oserror.ErrTemporary:
-               return e.Temporary()
-       case oserror.ErrTimeout:
-               return e.Timeout()
        case oserror.ErrPermission:
                return e == EACCES || e == EPERM
        case oserror.ErrExist:
index e48dc8f9844c8dd00502309b8c68bbdb7bba6a89..a9e4560e9666c720b6e7c6405ac5bfa2ecf42bb2 100644 (file)
@@ -11,12 +11,12 @@ import (
 
 const (
        _SYS_FSTAT_FREEBSD12         = 551 // { int fstat(int fd, _Out_ struct stat *sb); }
-       _SYS_FSTATAT_FREEBSD12       = 552 // { int fstatat(int fd, _In_z_ char *path, \
-       _SYS_GETDIRENTRIES_FREEBSD12 = 554 // { ssize_t getdirentries(int fd, \
-       _SYS_STATFS_FREEBSD12        = 555 // { int statfs(_In_z_ char *path, \
-       _SYS_FSTATFS_FREEBSD12       = 556 // { int fstatfs(int fd, \
-       _SYS_GETFSSTAT_FREEBSD12     = 557 // { int getfsstat( \
-       _SYS_MKNODAT_FREEBSD12       = 559 // { int mknodat(int fd, _In_z_ char *path, \
+       _SYS_FSTATAT_FREEBSD12       = 552 // { int fstatat(int fd, _In_z_ char *path, _Out_ struct stat *buf, int flag); }
+       _SYS_GETDIRENTRIES_FREEBSD12 = 554 // { ssize_t getdirentries(int fd, _Out_writes_bytes_(count) char *buf, size_t count, _Out_ off_t *basep); }
+       _SYS_STATFS_FREEBSD12        = 555 // { int statfs(_In_z_ char *path, _Out_ struct statfs *buf); }
+       _SYS_FSTATFS_FREEBSD12       = 556 // { int fstatfs(int fd, _Out_ struct statfs *buf); }
+       _SYS_GETFSSTAT_FREEBSD12     = 557 // { int getfsstat(_Out_writes_bytes_opt_(bufsize) struct statfs *buf, long bufsize, int mode); }
+       _SYS_MKNODAT_FREEBSD12       = 559 // { int mknodat(int fd, _In_z_ char *path, mode_t mode, dev_t dev); }
 )
 
 // See https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions.html.
index 99f9a935fe5ff9b1d782d956daad5b9ac0af19a5..175fe47fcaa0d3c76a545d4cfe61dda68d0bf865 100644 (file)
@@ -58,10 +58,6 @@ func (e Errno) Error() string {
 
 func (e Errno) Is(target error) bool {
        switch target {
-       case oserror.ErrTemporary:
-               return e.Temporary()
-       case oserror.ErrTimeout:
-               return e.Timeout()
        case oserror.ErrPermission:
                return e == EACCES || e == EPERM
        case oserror.ErrExist:
index 339df13f439ada9cae4df878f3e664607128626a..6ab9b7919615bb2621b2331f2cf6887a82a433b2 100644 (file)
@@ -1075,11 +1075,6 @@ type testDeps interface {
 // It is not meant to be called directly and is not subject to the Go 1 compatibility document.
 // It may change signature from release to release.
 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
-       // In most cases, Init has already been called by the testinginit code
-       // that 'go test' injects into test packages.
-       // Call it again here to handle cases such as:
-       // - test packages that don't import "testing" (such as example-only packages)
-       // - direct use of MainStart (though that isn't well-supported)
        Init()
        return &M{
                deps:       deps,
index fa5a0cd70de80ebd7978a064bdf21ad3a3381d38..e0847a7239680c286a4805834be680ff2104a754 100644 (file)
@@ -58,17 +58,19 @@ func (pos Position) String() string {
 // For instance, if the mode is ScanIdents (not ScanStrings), the string
 // "foo" is scanned as the token sequence '"' Ident '"'.
 //
+// Use GoTokens to configure the Scanner such that it accepts all Go
+// literal tokens including Go identifiers. Comments will be skipped.
+//
 const (
-       ScanIdents           = 1 << -Ident
-       ScanInts             = 1 << -Int
-       ScanFloats           = 1 << -Float // includes Ints and hexadecimal floats
-       ScanChars            = 1 << -Char
-       ScanStrings          = 1 << -String
-       ScanRawStrings       = 1 << -RawString
-       ScanComments         = 1 << -Comment
-       SkipComments         = 1 << -skipComment          // if set with ScanComments, comments become white space
-       AllowDigitSeparators = 1 << -allowDigitSeparators // if set, number literals may contain underscores as digit separators
-       GoTokens             = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments | AllowDigitSeparators
+       ScanIdents     = 1 << -Ident
+       ScanInts       = 1 << -Int
+       ScanFloats     = 1 << -Float // includes Ints and hexadecimal floats
+       ScanChars      = 1 << -Char
+       ScanStrings    = 1 << -String
+       ScanRawStrings = 1 << -RawString
+       ScanComments   = 1 << -Comment
+       SkipComments   = 1 << -skipComment // if set with ScanComments, comments become white space
+       GoTokens       = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments
 )
 
 // The result of Scan is one of these tokens or a Unicode character.
@@ -84,7 +86,6 @@ const (
 
        // internal use only
        skipComment
-       allowDigitSeparators
 )
 
 var tokenString = map[rune]string{
@@ -363,8 +364,7 @@ func lower(ch rune) rune     { return ('a' - 'A') | ch } // returns lower-case c
 func isDecimal(ch rune) bool { return '0' <= ch && ch <= '9' }
 func isHex(ch rune) bool     { return '0' <= ch && ch <= '9' || 'a' <= lower(ch) && lower(ch) <= 'f' }
 
-// digits accepts the sequence { digit } (if AllowDigitSeparators is not set)
-// or { digit | '_' } (if AllowDigitSeparators is set), starting with ch0.
+// digits accepts the sequence { digit | '_' } starting with ch0.
 // If base <= 10, digits accepts any decimal digit but records
 // the first invalid digit >= base in *invalid if *invalid == 0.
 // digits returns the first rune that is not part of the sequence
@@ -374,7 +374,7 @@ func (s *Scanner) digits(ch0 rune, base int, invalid *rune) (ch rune, digsep int
        ch = ch0
        if base <= 10 {
                max := rune('0' + base)
-               for isDecimal(ch) || ch == '_' && s.Mode&AllowDigitSeparators != 0 {
+               for isDecimal(ch) || ch == '_' {
                        ds := 1
                        if ch == '_' {
                                ds = 2
@@ -385,7 +385,7 @@ func (s *Scanner) digits(ch0 rune, base int, invalid *rune) (ch rune, digsep int
                        ch = s.next()
                }
        } else {
-               for isHex(ch) || ch == '_' && s.Mode&AllowDigitSeparators != 0 {
+               for isHex(ch) || ch == '_' {
                        ds := 1
                        if ch == '_' {
                                ds = 2
index fb68106c169cfd13c51e7c5a6d562a032d9d25ed..fe39d3060bf185a171aacc5ee527c7d4879582db 100644 (file)
@@ -886,8 +886,7 @@ func TestIssue30320(t *testing.T) {
                {"foo01.bar31.xx-0-1-1-0", "01 31 0 1 1 0", ScanInts},
                {"foo0/12/0/5.67", "0 12 0 5 67", ScanInts},
                {"xxx1e0yyy", "1 0", ScanInts},
-               {"1_2", "1 2", ScanInts}, // don't consume _ as part of a number if not explicitly enabled
-               {"1_2", "1_2", ScanInts | AllowDigitSeparators},
+               {"1_2", "1_2", ScanInts},
                {"xxx1.0yyy2e3ee", "1 0 2 3", ScanInts},
                {"xxx1.0yyy2e3ee", "1.0 2e3", ScanFloats},
        } {
index 10edf6fe0e0dd70ef866fe99e2f0bf98d3912ac1..2cc908da55e4fa767e37be542a857207ee4fcdbe 100644 (file)
@@ -54,8 +54,8 @@ type Timer struct {
 // Stop does not close the channel, to prevent a read from the channel succeeding
 // incorrectly.
 //
-// To prevent a timer created with NewTimer from firing after a call to Stop,
-// check the return value and drain the channel.
+// To ensure the channel is empty after a call to Stop, check the
+// return value and drain the channel.
 // For example, assuming the program has not received from t.C already:
 //
 //     if !t.Stop() {
@@ -97,10 +97,9 @@ func NewTimer(d Duration) *Timer {
 // It returns true if the timer had been active, false if the timer had
 // expired or been stopped.
 //
-// Resetting a timer must take care not to race with the send into t.C
-// that happens when the current timer expires.
+// Reset should be invoked only on stopped or expired timers with drained channels.
 // If a program has already received a value from t.C, the timer is known
-// to have expired, and t.Reset can be used directly.
+// to have expired and the channel drained, so t.Reset can be used directly.
 // If a program has not yet received a value from t.C, however,
 // the timer must be stopped and—if Stop reports that the timer expired
 // before being stopped—the channel explicitly drained:
index c8116a74f43b78ff51d9a8843d0656a2561b7d2c..0d1cb9e5a153cda1dd3e71ee0ae11736dbe185f9 100644 (file)
@@ -906,33 +906,16 @@ func (t Time) Sub(u Time) Duration {
                }
                return d
        }
-
-       ts, us := t.sec(), u.sec()
-
-       var sec, nsec, d int64
-
-       ssub := ts - us
-       if (ssub < ts) != (us > 0) {
-               goto overflow
-       }
-
-       if ssub < int64(minDuration/Second) || ssub > int64(maxDuration/Second) {
-               goto overflow
-       }
-       sec = ssub * int64(Second)
-
-       nsec = int64(t.nsec() - u.nsec())
-       d = sec + nsec
-       if (d > sec) != (nsec > 0) {
-               goto overflow
-       }
-       return Duration(d)
-
-overflow:
-       if t.Before(u) {
+       d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec())
+       // Check for overflow or underflow.
+       switch {
+       case u.Add(d).Equal(t):
+               return d // d is correct
+       case t.Before(u):
                return minDuration // t - u is negative out of range
+       default:
+               return maxDuration // t - u is positive out of range
        }
-       return maxDuration // t - u is positive out of range
 }
 
 // Since returns the time elapsed since t.
index dd3a8160cd86d7c706d9ad5d462c0db210c08f4c..95998c362f09f97ef0c34e0c3808cebedefb53a9 100644 (file)
@@ -995,6 +995,7 @@ var subTests = []struct {
        {Date(2300, 1, 1, 0, 0, 0, 0, UTC), Date(2000, 1, 1, 0, 0, 0, 0, UTC), Duration(maxDuration)},
        {Date(2000, 1, 1, 0, 0, 0, 0, UTC), Date(2290, 1, 1, 0, 0, 0, 0, UTC), -290*365*24*Hour - 71*24*Hour},
        {Date(2000, 1, 1, 0, 0, 0, 0, UTC), Date(2300, 1, 1, 0, 0, 0, 0, UTC), Duration(minDuration)},
+       {Date(2311, 11, 26, 02, 16, 47, 63535996, UTC), Date(2019, 8, 16, 2, 29, 30, 268436582, UTC), 9223372036795099414},
        {MinMonoTime, MaxMonoTime, minDuration},
        {MaxMonoTime, MinMonoTime, maxDuration},
 }
@@ -1008,14 +1009,6 @@ func TestSub(t *testing.T) {
        }
 }
 
-func BenchmarkSub(b *testing.B) {
-       for i := 0; i < b.N; i++ {
-               for _, st := range subTests {
-                       st.t.Sub(st.u)
-               }
-       }
-}
-
 var nsDurationTests = []struct {
        d    Duration
        want int64
index 28fdc17fce6daf5a1c8487d37a90d332434bafbb..b19747a05b96a96a4cfb22262fe2015d8d321aa2 100644 (file)
@@ -108,6 +108,7 @@ image/jpeg
 image/png
 index/suffixarray
 internal/bytealg
+internal/cfg
 internal/cpu
 internal/fmtsort
 internal/goroot
index e6bac0fff4572ac3f71ca1dd17c288c88bb860b1..1bdf843451d366b693857abe92a11d31ede08d6f 100644 (file)
@@ -112,6 +112,7 @@ func TestReportsTypeErrors(t *testing.T) {
                "issue18452.go",
                "issue18889.go",
                "issue28721.go",
+               "issue33061.go",
        } {
                check(t, file)
        }
index d1ef191bf545b43fa3ba120f7c1f4ffa440b45b4..4a46b6023bb510ab70e146c80358b7f56bee5f52 100644 (file)
@@ -156,8 +156,8 @@ var ptrTests = []ptrTest{
                // Storing a Go pointer into C memory should fail.
                name: "barrier",
                c: `#include <stdlib.h>
-                    char **f14a() { return malloc(sizeof(char*)); }
-                    void f14b(char **p) {}`,
+                   char **f14a() { return malloc(sizeof(char*)); }
+                   void f14b(char **p) {}`,
                body:      `p := C.f14a(); *p = new(C.char); C.f14b(p)`,
                fail:      true,
                expensive: true,
@@ -167,9 +167,9 @@ var ptrTests = []ptrTest{
                // large value should fail.
                name: "barrierstruct",
                c: `#include <stdlib.h>
-                    struct s15 { char *a[10]; };
-                    struct s15 *f15() { return malloc(sizeof(struct s15)); }
-                    void f15b(struct s15 *p) {}`,
+                   struct s15 { char *a[10]; };
+                   struct s15 *f15() { return malloc(sizeof(struct s15)); }
+                   void f15b(struct s15 *p) {}`,
                body:      `p := C.f15(); p.a = [10]*C.char{new(C.char)}; C.f15b(p)`,
                fail:      true,
                expensive: true,
@@ -179,9 +179,9 @@ var ptrTests = []ptrTest{
                // copy should fail.
                name: "barrierslice",
                c: `#include <stdlib.h>
-                    struct s16 { char *a[10]; };
-                    struct s16 *f16() { return malloc(sizeof(struct s16)); }
-                    void f16b(struct s16 *p) {}`,
+                   struct s16 { char *a[10]; };
+                   struct s16 *f16() { return malloc(sizeof(struct s16)); }
+                   void f16b(struct s16 *p) {}`,
                body:      `p := C.f16(); copy(p.a[:], []*C.char{new(C.char)}); C.f16b(p)`,
                fail:      true,
                expensive: true,
@@ -191,9 +191,9 @@ var ptrTests = []ptrTest{
                // different code path.
                name: "barriergcprogarray",
                c: `#include <stdlib.h>
-                    struct s17 { char *a[32769]; };
-                    struct s17 *f17() { return malloc(sizeof(struct s17)); }
-                    void f17b(struct s17 *p) {}`,
+                   struct s17 { char *a[32769]; };
+                   struct s17 *f17() { return malloc(sizeof(struct s17)); }
+                   void f17b(struct s17 *p) {}`,
                body:      `p := C.f17(); p.a = [32769]*C.char{new(C.char)}; C.f17b(p)`,
                fail:      true,
                expensive: true,
@@ -202,10 +202,10 @@ var ptrTests = []ptrTest{
                // Similar case, with a source on the heap.
                name: "barriergcprogarrayheap",
                c: `#include <stdlib.h>
-                    struct s18 { char *a[32769]; };
-                    struct s18 *f18() { return malloc(sizeof(struct s18)); }
-                    void f18b(struct s18 *p) {}
-                    void f18c(void *p) {}`,
+                   struct s18 { char *a[32769]; };
+                   struct s18 *f18() { return malloc(sizeof(struct s18)); }
+                   void f18b(struct s18 *p) {}
+                   void f18c(void *p) {}`,
                imports:   []string{"unsafe"},
                body:      `p := C.f18(); n := &[32769]*C.char{new(C.char)}; p.a = *n; C.f18b(p); n[0] = nil; C.f18c(unsafe.Pointer(n))`,
                fail:      true,
@@ -215,10 +215,10 @@ var ptrTests = []ptrTest{
                // A GC program with a struct.
                name: "barriergcprogstruct",
                c: `#include <stdlib.h>
-                    struct s19a { char *a[32769]; };
-                    struct s19b { struct s19a f; };
-                    struct s19b *f19() { return malloc(sizeof(struct s19b)); }
-                    void f19b(struct s19b *p) {}`,
+                   struct s19a { char *a[32769]; };
+                   struct s19b { struct s19a f; };
+                   struct s19b *f19() { return malloc(sizeof(struct s19b)); }
+                   void f19b(struct s19b *p) {}`,
                body:      `p := C.f19(); p.f = C.struct_s19a{[32769]*C.char{new(C.char)}}; C.f19b(p)`,
                fail:      true,
                expensive: true,
@@ -227,11 +227,11 @@ var ptrTests = []ptrTest{
                // Similar case, with a source on the heap.
                name: "barriergcprogstructheap",
                c: `#include <stdlib.h>
-                    struct s20a { char *a[32769]; };
-                    struct s20b { struct s20a f; };
-                    struct s20b *f20() { return malloc(sizeof(struct s20b)); }
-                    void f20b(struct s20b *p) {}
-                    void f20c(void *p) {}`,
+                   struct s20a { char *a[32769]; };
+                   struct s20b { struct s20a f; };
+                   struct s20b *f20() { return malloc(sizeof(struct s20b)); }
+                   void f20b(struct s20b *p) {}
+                   void f20c(void *p) {}`,
                imports:   []string{"unsafe"},
                body:      `p := C.f20(); n := &C.struct_s20a{[32769]*C.char{new(C.char)}}; p.f = *n; C.f20b(p); n.a[0] = nil; C.f20c(unsafe.Pointer(n))`,
                fail:      true,
@@ -242,7 +242,7 @@ var ptrTests = []ptrTest{
                name: "export1",
                c:    `extern unsigned char *GoFn21();`,
                support: `//export GoFn21
-                          func GoFn21() *byte { return new(byte) }`,
+                         func GoFn21() *byte { return new(byte) }`,
                body: `C.GoFn21()`,
                fail: true,
        },
@@ -250,17 +250,17 @@ var ptrTests = []ptrTest{
                // Returning a C pointer is fine.
                name: "exportok",
                c: `#include <stdlib.h>
-                    extern unsigned char *GoFn22();`,
+                   extern unsigned char *GoFn22();`,
                support: `//export GoFn22
-                          func GoFn22() *byte { return (*byte)(C.malloc(1)) }`,
+                         func GoFn22() *byte { return (*byte)(C.malloc(1)) }`,
                body: `C.GoFn22()`,
        },
        {
                // Passing a Go string is fine.
                name: "passstring",
                c: `#include <stddef.h>
-                    typedef struct { const char *p; ptrdiff_t n; } gostring23;
-                    gostring23 f23(gostring23 s) { return s; }`,
+                   typedef struct { const char *p; ptrdiff_t n; } gostring23;
+                   gostring23 f23(gostring23 s) { return s; }`,
                imports: []string{"unsafe"},
                body:    `s := "a"; r := C.f23(*(*C.gostring23)(unsafe.Pointer(&s))); if *(*string)(unsafe.Pointer(&r)) != s { panic(r) }`,
        },
@@ -279,12 +279,12 @@ var ptrTests = []ptrTest{
                c:       `extern void f25();`,
                imports: []string{"strings"},
                support: `//export GoStr25
-                          func GoStr25() string { return strings.Repeat("a", 2) }`,
+                         func GoStr25() string { return strings.Repeat("a", 2) }`,
                body: `C.f25()`,
                c1: `#include <stddef.h>
-                                 typedef struct { const char *p; ptrdiff_t n; } gostring25;
-                                 extern gostring25 GoStr25();
-                                 void f25() { GoStr25(); }`,
+                    typedef struct { const char *p; ptrdiff_t n; } gostring25;
+                    extern gostring25 GoStr25();
+                    void f25() { GoStr25(); }`,
                fail: true,
        },
        {
@@ -295,7 +295,7 @@ var ptrTests = []ptrTest{
                // that is, we are testing something that is not unsafe.
                name: "ptrdata1",
                c: `#include <stdlib.h>
-                    void f26(void* p) {}`,
+                   void f26(void* p) {}`,
                imports: []string{"unsafe"},
                support: `type S26 struct { p *int; a [8*8]byte; u uintptr }`,
                body:    `i := 0; p := &S26{u:uintptr(unsafe.Pointer(&i))}; q := (*S26)(C.malloc(C.size_t(unsafe.Sizeof(*p)))); *q = *p; C.f26(unsafe.Pointer(q))`,
@@ -305,7 +305,7 @@ var ptrTests = []ptrTest{
                // Like ptrdata1, but with a type that uses a GC program.
                name: "ptrdata2",
                c: `#include <stdlib.h>
-                    void f27(void* p) {}`,
+                   void f27(void* p) {}`,
                imports: []string{"unsafe"},
                support: `type S27 struct { p *int; a [32769*8]byte; q *int; u uintptr }`,
                body:    `i := 0; p := S27{u:uintptr(unsafe.Pointer(&i))}; q := (*S27)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f27(unsafe.Pointer(q))`,
@@ -423,6 +423,15 @@ var ptrTests = []ptrTest{
                body:    `t := reflect.StructOf([]reflect.StructField{{Name: "MyInt38", Type: reflect.TypeOf(MyInt38(0)), Anonymous: true}}); v := reflect.New(t).Elem(); v.Interface().(Getter38).Get()`,
                fail:    false,
        },
+       {
+               // Test that a converted address of a struct field results
+               // in a check for just that field and not the whole struct.
+               name:    "structfieldcast",
+               c:       `struct S40i { int i; int* p; }; void f40(struct S40i* p) {}`,
+               support: `type S40 struct { p *int; a C.struct_S40i }`,
+               body:    `s := &S40{p: new(int)}; C.f40((*C.struct_S40i)(&s.a))`,
+               fail:    false,
+       },
 }
 
 func TestPointerChecks(t *testing.T) {
@@ -466,6 +475,9 @@ func buildPtrTests(t *testing.T) (dir, exe string) {
        if err := os.MkdirAll(src, 0777); err != nil {
                t.Fatal(err)
        }
+       if err := ioutil.WriteFile(filepath.Join(src, "go.mod"), []byte("module ptrtest"), 0666); err != nil {
+               t.Fatal(err)
+       }
 
        // Prepare two cgo inputs: one for standard cgo and one for //export cgo.
        // (The latter cannot have C definitions, only declarations.)
diff --git a/libgo/misc/cgo/errors/testdata/issue33061.go b/libgo/misc/cgo/errors/testdata/issue33061.go
new file mode 100644 (file)
index 0000000..77d5f7a
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2019 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.
+
+// cgo shouldn't crash if there is an extra argument with a C reference.
+
+package main
+
+// void F(void* p) {};
+import "C"
+
+import "unsafe"
+
+func F() {
+       var i int
+       C.F(unsafe.Pointer(&i), C.int(0)) // ERROR HERE
+}
index ac1a1c7f1a8cca20da9448ad244eb529e1a8fce7..9d16338c0f6342fc4375f76ff04f556f799a5bac 100644 (file)
@@ -941,3 +941,10 @@ func TestTestInstalledShared(t *testing.T) {
 func TestGeneratedMethod(t *testing.T) {
        goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue25065")
 }
+
+// Test use of shared library struct with generated hash function.
+// Issue 30768.
+func TestGeneratedHash(t *testing.T) {
+       goCmd(nil, "install", "-buildmode=shared", "-linkshared", "./issue30768/issue30768lib")
+       goCmd(nil, "test", "-linkshared", "./issue30768")
+}
diff --git a/libgo/misc/cgo/testshared/testdata/issue30768/issue30768lib/lib.go b/libgo/misc/cgo/testshared/testdata/issue30768/issue30768lib/lib.go
new file mode 100644 (file)
index 0000000..9e45ebe
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2019 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 issue30768lib
+
+// S is a struct that requires a generated hash function.
+type S struct {
+       A string
+       B int
+}
diff --git a/libgo/misc/cgo/testshared/testdata/issue30768/x_test.go b/libgo/misc/cgo/testshared/testdata/issue30768/x_test.go
new file mode 100644 (file)
index 0000000..1bbd139
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2019 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 issue30768_test
+
+import (
+       "testing"
+
+       "testshared/issue30768/issue30768lib"
+)
+
+type s struct {
+       s issue30768lib.S
+}
+
+func Test30768(t *testing.T) {
+       // Calling t.Log will convert S to an empty interface,
+       // which will force a reference to the generated hash function,
+       // defined in the shared library.
+       t.Log(s{})
+}