diff --git a/api/go1.17.txt b/api/go1.17.txt
index f054458715..c5eb381708 100644
--- a/api/go1.17.txt
+++ b/api/go1.17.txt
@@ -28,6 +28,38 @@ pkg encoding/csv, method (*Reader) FieldPos(int) (int, int)
pkg go/build, type Context struct, ToolTags []string
pkg go/parser, const SkipObjectResolution = 64
pkg go/parser, const SkipObjectResolution Mode
+pkg image, method (*Alpha) RGBA64At(int, int) color.RGBA64
+pkg image, method (*Alpha) SetRGBA64(int, int, color.RGBA64)
+pkg image, method (*Alpha16) RGBA64At(int, int) color.RGBA64
+pkg image, method (*Alpha16) SetRGBA64(int, int, color.RGBA64)
+pkg image, method (*CMYK) RGBA64At(int, int) color.RGBA64
+pkg image, method (*CMYK) SetRGBA64(int, int, color.RGBA64)
+pkg image, method (*Gray) RGBA64At(int, int) color.RGBA64
+pkg image, method (*Gray) SetRGBA64(int, int, color.RGBA64)
+pkg image, method (*Gray16) RGBA64At(int, int) color.RGBA64
+pkg image, method (*Gray16) SetRGBA64(int, int, color.RGBA64)
+pkg image, method (*NRGBA) RGBA64At(int, int) color.RGBA64
+pkg image, method (*NRGBA) SetRGBA64(int, int, color.RGBA64)
+pkg image, method (*NRGBA64) RGBA64At(int, int) color.RGBA64
+pkg image, method (*NRGBA64) SetRGBA64(int, int, color.RGBA64)
+pkg image, method (*NYCbCrA) RGBA64At(int, int) color.RGBA64
+pkg image, method (*Paletted) RGBA64At(int, int) color.RGBA64
+pkg image, method (*Paletted) SetRGBA64(int, int, color.RGBA64)
+pkg image, method (*RGBA) RGBA64At(int, int) color.RGBA64
+pkg image, method (*RGBA) SetRGBA64(int, int, color.RGBA64)
+pkg image, method (*YCbCr) RGBA64At(int, int) color.RGBA64
+pkg image, type RGBA64Image interface { At, Bounds, ColorModel, RGBA64At }
+pkg image, type RGBA64Image interface, At(int, int) color.Color
+pkg image, type RGBA64Image interface, Bounds() Rectangle
+pkg image, type RGBA64Image interface, ColorModel() color.Model
+pkg image, type RGBA64Image interface, RGBA64At(int, int) color.RGBA64
+pkg image/draw, type RGBA64Image interface { At, Bounds, ColorModel, RGBA64At, Set, SetRGBA64 }
+pkg image/draw, type RGBA64Image interface, At(int, int) color.Color
+pkg image/draw, type RGBA64Image interface, Bounds() image.Rectangle
+pkg image/draw, type RGBA64Image interface, ColorModel() color.Model
+pkg image/draw, type RGBA64Image interface, RGBA64At(int, int) color.RGBA64
+pkg image/draw, type RGBA64Image interface, Set(int, int, color.Color)
+pkg image/draw, type RGBA64Image interface, SetRGBA64(int, int, color.RGBA64)
pkg io/fs, func FileInfoToDirEntry(FileInfo) DirEntry
pkg math, const MaxFloat64 = 1.79769e+308 // 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368
pkg math, const MaxInt = 9223372036854775807
@@ -153,7 +185,7 @@ pkg time, const Layout = "01/02 03:04:05PM '06 -0700"
pkg time, const Layout ideal-string
pkg time, func UnixMicro(int64) Time
pkg time, func UnixMilli(int64) Time
-pkg time, method (*Time) IsDST() bool
pkg time, method (Time) GoString() string
+pkg time, method (Time) IsDST() bool
pkg time, method (Time) UnixMicro() int64
pkg time, method (Time) UnixMilli() int64
diff --git a/doc/go1.17.html b/doc/go1.17.html
index 75c05c9e25..02cd18d037 100644
--- a/doc/go1.17.html
+++ b/doc/go1.17.html
@@ -162,7 +162,7 @@ Do not send CLs removing the interior tags from such phrases.
By default, go mod tidy verifies that
the selected versions of dependencies relevant to the main module are the same
versions that would be used by the prior Go release (Go 1.16 for a module that
- spsecifies go 1.17), and preserves
+ specifies go 1.17), and preserves
the go.sum entries needed by that release even for dependencies
that are not normally needed by other commands.
@@ -214,6 +214,16 @@ Do not send CLs removing the interior tags from such phrases.
environment for details.
+
+ go get prints a deprecation warning when installing
+ commands outside the main module (without the -d flag).
+ go install cmd@version should be used
+ instead to install a command at a specific version, using a suffix like
+ @latest or @v1.2.3. In Go 1.18, the -d
+ flag will always be enabled, and go get will only
+ be used to change dependencies in go.mod.
+
+
go.mod files missing go directives
@@ -387,7 +397,7 @@ func Foo() bool {
registers instead of the stack. This work is enabled for Linux, MacOS, and
Windows on the 64-bit x86 architecture (the linux/amd64,
darwin/amd64, windows/amd64 ports). For a
- representative set of Go packages and programs, benchmarking has shown
+ representative set of Go packages and programs, benchmarking has shown
performance improvements of about 5%, and a typical reduction in binary size
of about 2%.
@@ -441,6 +451,67 @@ func Foo() bool {
runtime/cgo.Handle for more information.
+URL query parsing
+
+
+
+ The net/url and net/http packages used to accept
+ ";" (semicolon) as a setting separator in URL queries, in
+ addition to "&" (ampersand). Now, settings with non-percent-encoded
+ semicolons are rejected and net/http servers will log a warning to
+ Server.ErrorLog
+ when encountering one in a request URL.
+
+
+
+ For example, before Go 1.17 the Query
+ method of the URL example?a=1;b=2&c=3 would have returned
+ map[a:[1] b:[2] c:[3]], while now it returns map[c:[3]].
+
+
+
+ When encountering such a query string,
+ URL.Query
+ and
+ Request.FormValue
+ ignore any settings that contain a semicolon,
+ ParseQuery
+ returns the remaining settings and an error, and
+ Request.ParseForm
+ and
+ Request.ParseMultipartForm
+ return an error but still set Request fields based on the
+ remaining settings.
+
+
+
+ net/http users can restore the original behavior by using the new
+ AllowQuerySemicolons
+ handler wrapper. This will also suppress the ErrorLog warning.
+ Note that accepting semicolons as query separators can lead to security issues
+ if different systems interpret cache keys differently.
+ See issue 25192 for more information.
+
+
+TLS strict ALPN
+
+
+
+ When Config.NextProtos
+ is set, servers now enforce that there is an overlap between the configured
+ protocols and the ALPN protocols advertised by the client, if any. If there is
+ no mutually supported protocol, the connection is closed with the
+ no_application_protocol alert, as required by RFC 7301. This
+ helps mitigate the ALPACA cross-protocol attack.
+
+
+
+ As an exception, when the value "h2" is included in the server's
+ Config.NextProtos, HTTP/1.1 clients will be allowed to connect as
+ if they didn't support ALPN.
+ See issue 46310 for more information.
+
+
Minor changes to the library
@@ -549,14 +620,6 @@ func Foo() bool {
methods. Canceling the context after the handshake has finished has no effect.
-
- When Config.NextProtos
- is set, servers now enforce that there is an overlap between the
- configured protocols and the protocols advertised by the client, if any.
- If there is no overlap the connection is closed with the
- no_application_protocol alert, as required by RFC 7301.
-
-
Cipher suite ordering is now handled entirely by the
crypto/tls package. Currently, cipher suites are sorted based
@@ -576,6 +639,15 @@ func Foo() bool {
weakness. They are still enabled by default but only as a last resort,
thanks to the cipher suite ordering change above.
+
+
+ Beginning in the next release, Go 1.18, the
+ Config.MinVersion
+ for crypto/tls clients will default to TLS 1.2, disabling TLS 1.0
+ and TLS 1.1 by default. Applications will be able to override the change by
+ explicitly setting Config.MinVersion.
+ This will not affect crypto/tls servers.
+
@@ -603,6 +675,14 @@ func Foo() bool {
roots. This adds support for the new system trusted certificate store in
FreeBSD 12.2+.
+
+
+ Beginning in the next release, Go 1.18, crypto/x509 will
+ reject certificates signed with the SHA-1 hash function. This doesn't
+ apply to self-signed root certificates. Practical attacks against SHA-1
+ have been demonstrated in 2017 and publicly
+ trusted Certificate Authorities have not issued SHA-1 certificates since 2015.
+
@@ -658,6 +738,22 @@ func Foo() bool {
+- encoding/xml
+ -
+
+ When a comment appears within a
+ Directive, it is now replaced
+ with a single space instead of being completely elided.
+
+
+
+ Invalid element or attribute names with leading, trailing, or multiple
+ colons are now stored unmodified into the
+ Name.Local field.
+
+
+
+
- flag
-
@@ -693,6 +789,29 @@ func Foo() bool {
+- go/parser
+ -
+
+ The new SkipObjectResolution
+ Mode value instructs the parser not to resolve identifiers to
+ their declaration. This may improve parsing speed.
+
+
+
+
+- image
+ -
+
+ The concrete image types (RGBA, Gray16 and so on)
+ now implement a new RGBA64Image
+ interface. Those concrete types, other than the chroma-subsampling
+ related YCbCr and NYCbCrA, also now implement
+ draw.RGBA64Image, a
+ new interface in the image/draw package.
+
+
+
+
- io/fs
-
@@ -721,6 +840,20 @@ func Foo() bool {
+- mime/multipart
+ -
+
+ Part.FileName
+ now applies
+ filepath.Base to the
+ return value. This mitigates potential path traversal vulnerabilities in
+ applications that accept multipart messages, such as net/http
+ servers that call
+ Request.FormFile.
+
+
+
+
- net
-
@@ -740,7 +873,7 @@ func Foo() bool {
the net.Error interface.
-
+
The ParseIP and ParseCIDR
functions now reject IPv4 addresses which contain decimal components with leading zeros.
@@ -771,6 +904,29 @@ func Foo() bool {
The ReadRequest function
now returns an error when the request has multiple Host headers.
+
+
+ When producing a redirect to the cleaned version of a URL,
+ ServeMux now always
+ uses relative URLs in the Location header. Previously it
+ would echo the full URL of the request, which could lead to unintended
+ redirects if the client could be made to send an absolute request URL.
+
+
+
+ When interpreting certain HTTP headers handled by net/http,
+ non-ASCII characters are now ignored or rejected.
+
+
+
+ If
+ Request.ParseForm
+ returns an error when called by
+ Request.ParseMultipartForm,
+ the latter now continues populating
+ Request.MultipartForm
+ before returning it.
+
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index ab48632a44..4cddcf48a4 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -1003,7 +1003,8 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
p.errorf("unimplemented two-register form")
}
a.Index = r1
- if scale != 0 && p.arch.Family == sys.ARM64 {
+ if scale != 0 && scale != 1 && p.arch.Family == sys.ARM64 {
+ // Support (R1)(R2) (no scaling) and (R1)(R2*1).
p.errorf("arm64 doesn't support scaled register format")
} else {
a.Scale = int16(scale)
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index 1146c1a789..5f1e68545b 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -547,6 +547,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
// shifted or extended register offset.
MOVD (R2)(R6.SXTW), R4 // 44c866f8
MOVD (R3)(R6), R5 // 656866f8
+ MOVD (R3)(R6*1), R5 // 656866f8
MOVD (R2)(R6), R4 // 446866f8
MOVWU (R19)(R20<<2), R20 // 747a74b8
MOVD (R2)(R6<<3), R4 // 447866f8
@@ -579,6 +580,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
MOVB R4, (R2)(R6.SXTX) // 44e82638
MOVB R8, (R3)(R9.UXTW) // 68482938
MOVB R10, (R5)(R8) // aa682838
+ MOVB R10, (R5)(R8*1) // aa682838
MOVH R11, (R2)(R7.SXTW<<1) // 4bd82778
MOVH R5, (R1)(R2<<1) // 25782278
MOVH R7, (R2)(R5.SXTX<<1) // 47f82578
diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go
index f3b58a172a..b01b467413 100644
--- a/src/cmd/go/internal/modfetch/cache.go
+++ b/src/cmd/go/internal/modfetch/cache.go
@@ -152,7 +152,7 @@ func lockVersion(mod module.Version) (unlock func(), err error) {
// If err is nil, the caller MUST eventually call the unlock function.
func SideLock() (unlock func(), err error) {
if err := checkCacheDir(); err != nil {
- base.Fatalf("go: %v", err)
+ return nil, err
}
path := filepath.Join(cfg.GOMODCACHE, "cache", "lock")
diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go
index 8eee723f89..ea5c4e229a 100644
--- a/src/cmd/go/internal/modget/get.go
+++ b/src/cmd/go/internal/modget/get.go
@@ -1153,6 +1153,7 @@ func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPack
Tags: imports.AnyTags(),
VendorModulesInGOROOTSrc: true,
LoadTests: *getT,
+ AssumeRootsImported: true, // After 'go get foo', imports of foo should build.
SilencePackageErrors: true, // May be fixed by subsequent upgrades or downgrades.
}
diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go
index e5db41c748..64eaa16e8b 100644
--- a/src/cmd/go/internal/modload/buildlist.go
+++ b/src/cmd/go/internal/modload/buildlist.go
@@ -443,7 +443,7 @@ func expandGraph(ctx context.Context, rs *Requirements) (*Requirements, *ModuleG
// roots — but in a lazy module it may pull in previously-irrelevant
// transitive dependencies.
- newRS, rsErr := updateRoots(ctx, rs.direct, rs, nil, nil)
+ newRS, rsErr := updateRoots(ctx, rs.direct, rs, nil, nil, false)
if rsErr != nil {
// Failed to update roots, perhaps because of an error in a transitive
// dependency needed for the update. Return the original Requirements
@@ -517,11 +517,11 @@ func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Require
return tidyLazyRoots(ctx, rs.direct, pkgs)
}
-func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version) (*Requirements, error) {
+func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
if rs.depth == eager {
return updateEagerRoots(ctx, direct, rs, add)
}
- return updateLazyRoots(ctx, direct, rs, pkgs, add)
+ return updateLazyRoots(ctx, direct, rs, pkgs, add, rootsImported)
}
// tidyLazyRoots returns a minimal set of root requirements that maintains the
@@ -661,7 +661,7 @@ func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg)
//
// (See https://golang.org/design/36460-lazy-module-loading#invariants for more
// detail.)
-func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version) (*Requirements, error) {
+func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
roots := rs.rootModules
rootsUpgraded := false
@@ -688,6 +688,10 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
//
// (This is the “import invariant” that makes lazy loading possible.)
+ case rootsImported && pkg.flags.has(pkgFromRoot):
+ // pkg is a transitive dependency of some root, and we are treating the
+ // roots as if they are imported by the main module (as in 'go get').
+
case pkg.flags.has(pkgIsRoot):
// pkg is a root of the package-import graph. (Generally this means that
// it matches a command-line argument.) We want future invocations of the
diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go
index eb9cfe629b..cbc7289afa 100644
--- a/src/cmd/go/internal/modload/init.go
+++ b/src/cmd/go/internal/modload/init.go
@@ -661,7 +661,7 @@ func requirementsFromModFile(ctx context.Context) *Requirements {
for _, n := range mPathCount {
if n > 1 {
var err error
- rs, err = updateRoots(ctx, rs.direct, rs, nil, nil)
+ rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
if err != nil {
base.Fatalf("go: %v", err)
}
diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go
index a9d1777125..a3a8021c04 100644
--- a/src/cmd/go/internal/modload/load.go
+++ b/src/cmd/go/internal/modload/load.go
@@ -171,6 +171,11 @@ type PackageOpts struct {
// if the flag is set to "readonly" (the default) or "vendor".
ResolveMissingImports bool
+ // AssumeRootsImported indicates that the transitive dependencies of the root
+ // packages should be treated as if those roots will be imported by the main
+ // module.
+ AssumeRootsImported bool
+
// AllowPackage, if non-nil, is called after identifying the module providing
// each package. If AllowPackage returns a non-nil error, that error is set
// for the package, and the imports and test of that package will not be
@@ -875,6 +880,11 @@ const (
// are also roots (and must be marked pkgIsRoot).
pkgIsRoot
+ // pkgFromRoot indicates that the package is in the transitive closure of
+ // imports starting at the roots. (Note that every package marked as pkgIsRoot
+ // is also trivially marked pkgFromRoot.)
+ pkgFromRoot
+
// pkgImportsLoaded indicates that the imports and testImports fields of a
// loadPkg have been populated.
pkgImportsLoaded
@@ -1068,7 +1078,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
// iteration so we don't need to also update it here. (That would waste time
// computing a "direct" map that we'll have to recompute later anyway.)
direct := ld.requirements.direct
- rs, err := updateRoots(ctx, direct, ld.requirements, noPkgs, toAdd)
+ rs, err := updateRoots(ctx, direct, ld.requirements, noPkgs, toAdd, ld.AssumeRootsImported)
if err != nil {
// If an error was found in a newly added module, report the package
// import stack instead of the module requirement stack. Packages
@@ -1274,7 +1284,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
addRoots = tidy.rootModules
}
- rs, err = updateRoots(ctx, direct, rs, ld.pkgs, addRoots)
+ rs, err = updateRoots(ctx, direct, rs, ld.pkgs, addRoots, ld.AssumeRootsImported)
if err != nil {
// We don't actually know what even the root requirements are supposed to be,
// so we can't proceed with loading. Return the error to the caller
@@ -1433,6 +1443,9 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
// This package matches a root pattern by virtue of being in "all".
flags |= pkgIsRoot
}
+ if flags.has(pkgIsRoot) {
+ flags |= pkgFromRoot
+ }
old := pkg.flags.update(flags)
new := old | flags
@@ -1487,6 +1500,12 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
ld.applyPkgFlags(ctx, dep, pkgInAll)
}
}
+
+ if new.has(pkgFromRoot) && !old.has(pkgFromRoot|pkgImportsLoaded) {
+ for _, dep := range pkg.imports {
+ ld.applyPkgFlags(ctx, dep, pkgFromRoot)
+ }
+ }
}
// preloadRootModules loads the module requirements needed to identify the
@@ -1549,7 +1568,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
}
module.Sort(toAdd)
- rs, err := updateRoots(ctx, ld.requirements.direct, ld.requirements, nil, toAdd)
+ rs, err := updateRoots(ctx, ld.requirements.direct, ld.requirements, nil, toAdd, ld.AssumeRootsImported)
if err != nil {
// We are missing some root dependency, and for some reason we can't load
// enough of the module dependency graph to add the missing root. Package
diff --git a/src/cmd/go/testdata/script/mod_edit_no_modcache.txt b/src/cmd/go/testdata/script/mod_edit_no_modcache.txt
new file mode 100644
index 0000000000..ced15bb301
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_edit_no_modcache.txt
@@ -0,0 +1,15 @@
+# 'go mod edit' opportunistically locks the side-lock file in the module cache,
+# for compatibility with older versions of the 'go' command.
+# It does not otherwise depend on the module cache, so it should not
+# fail if the module cache directory cannot be created.
+
+[root] skip
+
+mkdir $WORK/readonly
+chmod 0555 $WORK/readonly
+env GOPATH=$WORK/readonly/nonexist
+
+go mod edit -go=1.17
+
+-- go.mod --
+module example.com/m
diff --git a/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt
new file mode 100644
index 0000000000..1cef9d1c0c
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt
@@ -0,0 +1,44 @@
+# https://golang.org/issue/45979: after 'go get' on a package,
+# that package should be importable without error.
+
+
+# We start out with an unresolved dependency.
+# 'go list' suggests that we run 'go get' on that dependency.
+
+! go list -deps .
+stderr '^m.go:3:8: no required module provides package rsc\.io/quote; to add it:\n\tgo get rsc.io/quote$'
+
+
+# When we run the suggested 'go get' command, the new dependency can be used
+# immediately.
+#
+# 'go get' marks the new dependency as 'indirect', because it doesn't scan
+# enough source code to know whether it is direct, and it is easier and less
+# invasive to remove an incorrect indirect mark (e.g. using 'go get') than to
+# add one that is missing ('go mod tidy' or 'go mod vendor').
+
+go get rsc.io/quote
+grep 'rsc.io/quote v\d+\.\d+\.\d+ // indirect$' go.mod
+! grep 'rsc.io/quote v\d+\.\d+\.\d+$' go.mod
+
+go list -deps .
+! stderr .
+[!short] go build .
+[!short] ! stderr .
+
+
+# 'go get .' (or 'go mod tidy') removes the indirect mark.
+
+go get .
+grep 'rsc.io/quote v\d+\.\d+\.\d+$' go.mod
+! grep 'rsc.io/quote v\d+\.\d+\.\d+ // indirect$' go.mod
+
+
+-- go.mod --
+module example.com/m
+
+go 1.17
+-- m.go --
+package m
+
+import _ "rsc.io/quote"
diff --git a/src/cmd/go/testdata/script/mod_sumdb_golang.txt b/src/cmd/go/testdata/script/mod_sumdb_golang.txt
index cc0b0da474..becd88b52e 100644
--- a/src/cmd/go/testdata/script/mod_sumdb_golang.txt
+++ b/src/cmd/go/testdata/script/mod_sumdb_golang.txt
@@ -10,45 +10,73 @@ go env GOSUMDB
stdout '^sum.golang.org$'
# Download direct from github.
+
[!net] skip
[!exec:git] skip
env GOSUMDB=sum.golang.org
env GOPROXY=direct
+
go get -d rsc.io/quote@v1.5.2
cp go.sum saved.sum
+
# Download from proxy.golang.org with go.sum entry already.
# Use 'go list' instead of 'go get' since the latter may download extra go.mod
# files not listed in go.sum.
+
go clean -modcache
env GOSUMDB=
env GOPROXY=
-go list -x -deps rsc.io/quote
+
+go list -x -m all # Download go.mod files.
! stderr github
stderr proxy.golang.org/rsc.io/quote
! stderr sum.golang.org/tile
! stderr sum.golang.org/lookup/rsc.io/quote
+
+go list -x -deps rsc.io/quote # Download module source.
+! 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.
# 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 list -mod=mod -x rsc.io/quote
+
+go list -mod=mod -x -m all # Add checksums for go.mod files.
+stderr sum.golang.org/tile
! stderr github
! stderr proxy.golang.org/rsc.io/quote
-stderr sum.golang.org/tile
stderr sum.golang.org/lookup/rsc.io/quote
+
+go list -mod=mod -x rsc.io/quote # Add checksums for module source.
+! stderr . # Adds checksums, but for entities already in the module cache.
+
cmp go.sum saved.sum
+
# test fallback to direct
+
env TESTGOPROXY404=1
go clean -modcache
rm go.sum
-go list -mod=mod -x rsc.io/quote
+
+go list -mod=mod -x -m all # Download go.mod files
stderr 'proxy.golang.org.*404 testing'
stderr github.com/rsc
+
+go list -mod=mod -x rsc.io/quote # Download module source.
+stderr 'proxy.golang.org.*404 testing'
+stderr github.com/rsc
+
cmp go.sum saved.sum
+
-- go.mod --
module m
diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go
index 1d10a7b41f..e72c765adc 100644
--- a/src/cmd/pprof/pprof.go
+++ b/src/cmd/pprof/pprof.go
@@ -233,8 +233,8 @@ func (f *file) Name() string {
}
func (f *file) ObjAddr(addr uint64) (uint64, error) {
- // No support for shared libraries.
- return 0, nil
+ // No support for shared libraries, so translation is a no-op.
+ return addr, nil
}
func (f *file) BuildID() string {
diff --git a/src/cmd/pprof/pprof_test.go b/src/cmd/pprof/pprof_test.go
new file mode 100644
index 0000000000..11e251bfde
--- /dev/null
+++ b/src/cmd/pprof/pprof_test.go
@@ -0,0 +1,127 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "internal/testenv"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+var tmp, pprofExe string // populated by buildPprof
+
+func TestMain(m *testing.M) {
+ if !testenv.HasGoBuild() {
+ return
+ }
+
+ var exitcode int
+ if err := buildPprof(); err == nil {
+ exitcode = m.Run()
+ } else {
+ fmt.Println(err)
+ exitcode = 1
+ }
+ os.RemoveAll(tmp)
+ os.Exit(exitcode)
+}
+
+func buildPprof() error {
+ var err error
+ tmp, err = os.MkdirTemp("", "TestPprof")
+ if err != nil {
+ return fmt.Errorf("TempDir failed: %v", err)
+ }
+
+ pprofExe = filepath.Join(tmp, "testpprof.exe")
+ gotool, err := testenv.GoTool()
+ if err != nil {
+ return err
+ }
+ out, err := exec.Command(gotool, "build", "-o", pprofExe, "cmd/pprof").CombinedOutput()
+ if err != nil {
+ os.RemoveAll(tmp)
+ return fmt.Errorf("go build -o %v cmd/pprof: %v\n%s", pprofExe, err, string(out))
+ }
+
+ return nil
+}
+
+// See also runtime/pprof.cpuProfilingBroken.
+func mustHaveCPUProfiling(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("skipping on %s, unimplemented", runtime.GOOS)
+ case "aix":
+ t.Skipf("skipping on %s, issue 45170", runtime.GOOS)
+ case "ios", "dragonfly", "netbsd", "illumos", "solaris":
+ t.Skipf("skipping on %s, issue 13841", runtime.GOOS)
+ case "openbsd":
+ if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
+ t.Skipf("skipping on %s/%s, issue 13841", runtime.GOOS, runtime.GOARCH)
+ }
+ }
+}
+
+func mustHaveDisasm(t *testing.T) {
+ switch runtime.GOARCH {
+ case "mips", "mipsle", "mips64", "mips64le":
+ t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
+ case "riscv64":
+ t.Skipf("skipping on %s, issue 36738", runtime.GOARCH)
+ case "s390x":
+ t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
+ }
+
+ // Skip PIE platforms, pprof can't disassemble PIE.
+ if runtime.GOOS == "windows" {
+ t.Skipf("skipping on %s, issue 46639", runtime.GOOS)
+ }
+ if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
+ t.Skipf("skipping on %s/%s, issue 46639", runtime.GOOS, runtime.GOARCH)
+ }
+}
+
+// TestDisasm verifies that cmd/pprof can successfully disassemble functions.
+//
+// This is a regression test for issue 46636.
+func TestDisasm(t *testing.T) {
+ mustHaveCPUProfiling(t)
+ mustHaveDisasm(t)
+ testenv.MustHaveGoBuild(t)
+
+ tmpdir := t.TempDir()
+ cpuExe := filepath.Join(tmpdir, "cpu.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", cpuExe, "cpu.go")
+ cmd.Dir = "testdata/"
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failed: %v\n%s", err, out)
+ }
+
+ profile := filepath.Join(tmpdir, "cpu.pprof")
+ cmd = exec.Command(cpuExe, "-output", profile)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("cpu failed: %v\n%s", err, out)
+ }
+
+ cmd = exec.Command(pprofExe, "-disasm", "main.main", cpuExe, profile)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("pprof failed: %v\n%s", err, out)
+ }
+
+ sout := string(out)
+ want := "ROUTINE ======================== main.main"
+ if !strings.Contains(sout, want) {
+ t.Errorf("pprof disasm got %s want contains %q", sout, want)
+ }
+}
diff --git a/src/cmd/pprof/testdata/cpu.go b/src/cmd/pprof/testdata/cpu.go
new file mode 100644
index 0000000000..5b682870db
--- /dev/null
+++ b/src/cmd/pprof/testdata/cpu.go
@@ -0,0 +1,41 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "runtime/pprof"
+ "time"
+)
+
+var output = flag.String("output", "", "pprof profile output file")
+
+func main() {
+ flag.Parse()
+ if *output == "" {
+ fmt.Fprintf(os.Stderr, "usage: %s -output file.pprof\n", os.Args[0])
+ os.Exit(2)
+ }
+
+ f, err := os.Create(*output)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+ defer f.Close()
+
+ if err := pprof.StartCPUProfile(f); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+ defer pprof.StopCPUProfile()
+
+ // Spin for long enough to collect some samples.
+ start := time.Now()
+ for time.Since(start) < time.Second {
+ }
+}
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index 80f63e877d..7d1cb9b85a 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -2838,9 +2838,10 @@ func TestTxStmtDeadlock(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond)
+ ctx, cancel := context.WithCancel(context.Background())
defer cancel()
tx, err := db.BeginTx(ctx, nil)
+ cancel()
if err != nil {
t.Fatal(err)
}
diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go
index 8f96aa2d18..13f6668293 100644
--- a/src/image/draw/draw.go
+++ b/src/image/draw/draw.go
@@ -23,6 +23,16 @@ type Image interface {
Set(x, y int, c color.Color)
}
+// RGBA64Image extends both the Image and image.RGBA64Image interfaces with a
+// SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to
+// calling Set, but it can avoid allocations from converting concrete color
+// types to the color.Color interface type.
+type RGBA64Image interface {
+ image.RGBA64Image
+ Set(x, y int, c color.Color)
+ SetRGBA64(x, y int, c color.RGBA64)
+}
+
// Quantizer produces a palette for an image.
type Quantizer interface {
// Quantize appends up to cap(p) - len(p) colors to p and returns the
diff --git a/src/image/image.go b/src/image/image.go
index 8adba96ab6..930d9ac6c7 100644
--- a/src/image/image.go
+++ b/src/image/image.go
@@ -45,6 +45,17 @@ type Image interface {
At(x, y int) color.Color
}
+// RGBA64Image is an Image whose pixels can be converted directly to a
+// color.RGBA64.
+type RGBA64Image interface {
+ // RGBA64At returns the RGBA64 color of the pixel at (x, y). It is
+ // equivalent to calling At(x, y).RGBA() and converting the resulting
+ // 32-bit return values to a color.RGBA64, but it can avoid allocations
+ // from converting concrete color types to the color.Color interface type.
+ RGBA64At(x, y int) color.RGBA64
+ Image
+}
+
// PalettedImage is an image whose colors may come from a limited palette.
// If m is a PalettedImage and m.ColorModel() returns a color.Palette p,
// then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
@@ -90,6 +101,24 @@ func (p *RGBA) At(x, y int) color.Color {
return p.RGBAAt(x, y)
}
+func (p *RGBA) RGBA64At(x, y int) color.RGBA64 {
+ if !(Point{x, y}.In(p.Rect)) {
+ return color.RGBA64{}
+ }
+ i := p.PixOffset(x, y)
+ s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+ r := uint16(s[0])
+ g := uint16(s[1])
+ b := uint16(s[2])
+ a := uint16(s[3])
+ return color.RGBA64{
+ (r << 8) | r,
+ (g << 8) | g,
+ (b << 8) | b,
+ (a << 8) | a,
+ }
+}
+
func (p *RGBA) RGBAAt(x, y int) color.RGBA {
if !(Point{x, y}.In(p.Rect)) {
return color.RGBA{}
@@ -118,6 +147,18 @@ func (p *RGBA) Set(x, y int, c color.Color) {
s[3] = c1.A
}
+func (p *RGBA) SetRGBA64(x, y int, c color.RGBA64) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := p.PixOffset(x, y)
+ s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+ s[0] = uint8(c.R >> 8)
+ s[1] = uint8(c.G >> 8)
+ s[2] = uint8(c.B >> 8)
+ s[3] = uint8(c.A >> 8)
+}
+
func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
if !(Point{x, y}.In(p.Rect)) {
return
@@ -311,6 +352,11 @@ func (p *NRGBA) At(x, y int) color.Color {
return p.NRGBAAt(x, y)
}
+func (p *NRGBA) RGBA64At(x, y int) color.RGBA64 {
+ r, g, b, a := p.NRGBAAt(x, y).RGBA()
+ return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA {
if !(Point{x, y}.In(p.Rect)) {
return color.NRGBA{}
@@ -339,6 +385,24 @@ func (p *NRGBA) Set(x, y int, c color.Color) {
s[3] = c1.A
}
+func (p *NRGBA) SetRGBA64(x, y int, c color.RGBA64) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
+ if (a != 0) && (a != 0xffff) {
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ }
+ i := p.PixOffset(x, y)
+ s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+ s[0] = uint8(r >> 8)
+ s[1] = uint8(g >> 8)
+ s[2] = uint8(b >> 8)
+ s[3] = uint8(a >> 8)
+}
+
func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
if !(Point{x, y}.In(p.Rect)) {
return
@@ -415,6 +479,11 @@ func (p *NRGBA64) At(x, y int) color.Color {
return p.NRGBA64At(x, y)
}
+func (p *NRGBA64) RGBA64At(x, y int) color.RGBA64 {
+ r, g, b, a := p.NRGBA64At(x, y).RGBA()
+ return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 {
if !(Point{x, y}.In(p.Rect)) {
return color.NRGBA64{}
@@ -452,6 +521,28 @@ func (p *NRGBA64) Set(x, y int, c color.Color) {
s[7] = uint8(c1.A)
}
+func (p *NRGBA64) SetRGBA64(x, y int, c color.RGBA64) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
+ if (a != 0) && (a != 0xffff) {
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ }
+ i := p.PixOffset(x, y)
+ s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
+ s[0] = uint8(r >> 8)
+ s[1] = uint8(r)
+ s[2] = uint8(g >> 8)
+ s[3] = uint8(g)
+ s[4] = uint8(b >> 8)
+ s[5] = uint8(b)
+ s[6] = uint8(a >> 8)
+ s[7] = uint8(a)
+}
+
func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
if !(Point{x, y}.In(p.Rect)) {
return
@@ -532,6 +623,12 @@ func (p *Alpha) At(x, y int) color.Color {
return p.AlphaAt(x, y)
}
+func (p *Alpha) RGBA64At(x, y int) color.RGBA64 {
+ a := uint16(p.AlphaAt(x, y).A)
+ a |= a << 8
+ return color.RGBA64{a, a, a, a}
+}
+
func (p *Alpha) AlphaAt(x, y int) color.Alpha {
if !(Point{x, y}.In(p.Rect)) {
return color.Alpha{}
@@ -554,6 +651,14 @@ func (p *Alpha) Set(x, y int, c color.Color) {
p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
}
+func (p *Alpha) SetRGBA64(x, y int, c color.RGBA64) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := p.PixOffset(x, y)
+ p.Pix[i] = uint8(c.A >> 8)
+}
+
func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
if !(Point{x, y}.In(p.Rect)) {
return
@@ -626,6 +731,11 @@ func (p *Alpha16) At(x, y int) color.Color {
return p.Alpha16At(x, y)
}
+func (p *Alpha16) RGBA64At(x, y int) color.RGBA64 {
+ a := p.Alpha16At(x, y).A
+ return color.RGBA64{a, a, a, a}
+}
+
func (p *Alpha16) Alpha16At(x, y int) color.Alpha16 {
if !(Point{x, y}.In(p.Rect)) {
return color.Alpha16{}
@@ -650,6 +760,15 @@ func (p *Alpha16) Set(x, y int, c color.Color) {
p.Pix[i+1] = uint8(c1.A)
}
+func (p *Alpha16) SetRGBA64(x, y int, c color.RGBA64) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := p.PixOffset(x, y)
+ p.Pix[i+0] = uint8(c.A >> 8)
+ p.Pix[i+1] = uint8(c.A)
+}
+
func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
if !(Point{x, y}.In(p.Rect)) {
return
@@ -723,6 +842,12 @@ func (p *Gray) At(x, y int) color.Color {
return p.GrayAt(x, y)
}
+func (p *Gray) RGBA64At(x, y int) color.RGBA64 {
+ gray := uint16(p.GrayAt(x, y).Y)
+ gray |= gray << 8
+ return color.RGBA64{gray, gray, gray, 0xffff}
+}
+
func (p *Gray) GrayAt(x, y int) color.Gray {
if !(Point{x, y}.In(p.Rect)) {
return color.Gray{}
@@ -745,6 +870,16 @@ func (p *Gray) Set(x, y int, c color.Color) {
p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
}
+func (p *Gray) SetRGBA64(x, y int, c color.RGBA64) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ // This formula is the same as in color.grayModel.
+ gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 24
+ i := p.PixOffset(x, y)
+ p.Pix[i] = uint8(gray)
+}
+
func (p *Gray) SetGray(x, y int, c color.Gray) {
if !(Point{x, y}.In(p.Rect)) {
return
@@ -804,6 +939,11 @@ func (p *Gray16) At(x, y int) color.Color {
return p.Gray16At(x, y)
}
+func (p *Gray16) RGBA64At(x, y int) color.RGBA64 {
+ gray := p.Gray16At(x, y).Y
+ return color.RGBA64{gray, gray, gray, 0xffff}
+}
+
func (p *Gray16) Gray16At(x, y int) color.Gray16 {
if !(Point{x, y}.In(p.Rect)) {
return color.Gray16{}
@@ -828,6 +968,17 @@ func (p *Gray16) Set(x, y int, c color.Color) {
p.Pix[i+1] = uint8(c1.Y)
}
+func (p *Gray16) SetRGBA64(x, y int, c color.RGBA64) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ // This formula is the same as in color.gray16Model.
+ gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 16
+ i := p.PixOffset(x, y)
+ p.Pix[i+0] = uint8(gray >> 8)
+ p.Pix[i+1] = uint8(gray)
+}
+
func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
if !(Point{x, y}.In(p.Rect)) {
return
@@ -888,6 +1039,11 @@ func (p *CMYK) At(x, y int) color.Color {
return p.CMYKAt(x, y)
}
+func (p *CMYK) RGBA64At(x, y int) color.RGBA64 {
+ r, g, b, a := p.CMYKAt(x, y).RGBA()
+ return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
func (p *CMYK) CMYKAt(x, y int) color.CMYK {
if !(Point{x, y}.In(p.Rect)) {
return color.CMYK{}
@@ -916,6 +1072,19 @@ func (p *CMYK) Set(x, y int, c color.Color) {
s[3] = c1.K
}
+func (p *CMYK) SetRGBA64(x, y int, c color.RGBA64) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ cc, mm, yy, kk := color.RGBToCMYK(uint8(c.R>>8), uint8(c.G>>8), uint8(c.B>>8))
+ i := p.PixOffset(x, y)
+ s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+ s[0] = cc
+ s[1] = mm
+ s[2] = yy
+ s[3] = kk
+}
+
func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
if !(Point{x, y}.In(p.Rect)) {
return
@@ -988,6 +1157,26 @@ func (p *Paletted) At(x, y int) color.Color {
return p.Palette[p.Pix[i]]
}
+func (p *Paletted) RGBA64At(x, y int) color.RGBA64 {
+ if len(p.Palette) == 0 {
+ return color.RGBA64{}
+ }
+ c := color.Color(nil)
+ if !(Point{x, y}.In(p.Rect)) {
+ c = p.Palette[0]
+ } else {
+ i := p.PixOffset(x, y)
+ c = p.Palette[p.Pix[i]]
+ }
+ r, g, b, a := c.RGBA()
+ return color.RGBA64{
+ uint16(r),
+ uint16(g),
+ uint16(b),
+ uint16(a),
+ }
+}
+
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *Paletted) PixOffset(x, y int) int {
@@ -1002,6 +1191,14 @@ func (p *Paletted) Set(x, y int, c color.Color) {
p.Pix[i] = uint8(p.Palette.Index(c))
}
+func (p *Paletted) SetRGBA64(x, y int, c color.RGBA64) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := p.PixOffset(x, y)
+ p.Pix[i] = uint8(p.Palette.Index(c))
+}
+
func (p *Paletted) ColorIndexAt(x, y int) uint8 {
if !(Point{x, y}.In(p.Rect)) {
return 0
diff --git a/src/image/image_test.go b/src/image/image_test.go
index b9b9bfaa28..c64b6107b7 100644
--- a/src/image/image_test.go
+++ b/src/image/image_test.go
@@ -6,6 +6,7 @@ package image
import (
"image/color"
+ "image/color/palette"
"testing"
)
@@ -191,6 +192,80 @@ func Test16BitsPerColorChannel(t *testing.T) {
}
}
+func TestRGBA64Image(t *testing.T) {
+ // memset sets every element of s to v.
+ memset := func(s []byte, v byte) {
+ for i := range s {
+ s[i] = v
+ }
+ }
+
+ r := Rect(0, 0, 3, 2)
+ testCases := []Image{
+ NewAlpha(r),
+ NewAlpha16(r),
+ NewCMYK(r),
+ NewGray(r),
+ NewGray16(r),
+ NewNRGBA(r),
+ NewNRGBA64(r),
+ NewNYCbCrA(r, YCbCrSubsampleRatio444),
+ NewPaletted(r, palette.Plan9),
+ NewRGBA(r),
+ NewRGBA64(r),
+ NewYCbCr(r, YCbCrSubsampleRatio444),
+ }
+ for _, tc := range testCases {
+ switch tc := tc.(type) {
+ // Most of the concrete image types in the testCases implement the
+ // draw.RGBA64Image interface: they have a SetRGBA64 method. We use an
+ // interface literal here, instead of importing "image/draw", to avoid
+ // an import cycle.
+ //
+ // The YCbCr and NYCbCrA types are special-cased. Chroma subsampling
+ // means that setting one pixel can modify neighboring pixels. They
+ // don't have Set or SetRGBA64 methods because that side effect could
+ // be surprising. Here, we just memset the channel buffers instead.
+ case interface {
+ SetRGBA64(x, y int, c color.RGBA64)
+ }:
+ tc.SetRGBA64(1, 1, color.RGBA64{0x7FFF, 0x3FFF, 0x0000, 0x7FFF})
+
+ case *NYCbCrA:
+ memset(tc.YCbCr.Y, 0x77)
+ memset(tc.YCbCr.Cb, 0x88)
+ memset(tc.YCbCr.Cr, 0x99)
+ memset(tc.A, 0xAA)
+
+ case *YCbCr:
+ memset(tc.Y, 0x77)
+ memset(tc.Cb, 0x88)
+ memset(tc.Cr, 0x99)
+
+ default:
+ t.Errorf("could not initialize pixels for %T", tc)
+ continue
+ }
+
+ // Check that RGBA64At(x, y) is equivalent to At(x, y).RGBA().
+ rgba64Image, ok := tc.(RGBA64Image)
+ if !ok {
+ t.Errorf("%T is not an RGBA64Image", tc)
+ continue
+ }
+ got := rgba64Image.RGBA64At(1, 1)
+ wantR, wantG, wantB, wantA := tc.At(1, 1).RGBA()
+ if (uint32(got.R) != wantR) || (uint32(got.G) != wantG) ||
+ (uint32(got.B) != wantB) || (uint32(got.A) != wantA) {
+ t.Errorf("%T:\ngot (0x%04X, 0x%04X, 0x%04X, 0x%04X)\n"+
+ "want (0x%04X, 0x%04X, 0x%04X, 0x%04X)", tc,
+ got.R, got.G, got.B, got.A,
+ wantR, wantG, wantB, wantA)
+ continue
+ }
+ }
+}
+
func BenchmarkAt(b *testing.B) {
for _, tc := range testImages {
b.Run(tc.name, func(b *testing.B) {
diff --git a/src/image/ycbcr.go b/src/image/ycbcr.go
index fbdffe1bd1..328b90d152 100644
--- a/src/image/ycbcr.go
+++ b/src/image/ycbcr.go
@@ -71,6 +71,11 @@ func (p *YCbCr) At(x, y int) color.Color {
return p.YCbCrAt(x, y)
}
+func (p *YCbCr) RGBA64At(x, y int) color.RGBA64 {
+ r, g, b, a := p.YCbCrAt(x, y).RGBA()
+ return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
if !(Point{x, y}.In(p.Rect)) {
return color.YCbCr{}
@@ -210,6 +215,11 @@ func (p *NYCbCrA) At(x, y int) color.Color {
return p.NYCbCrAAt(x, y)
}
+func (p *NYCbCrA) RGBA64At(x, y int) color.RGBA64 {
+ r, g, b, a := p.NYCbCrAAt(x, y).RGBA()
+ return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA {
if !(Point{X: x, Y: y}.In(p.Rect)) {
return color.NYCbCrA{}
diff --git a/src/math/rand/rand.go b/src/math/rand/rand.go
index 8179d9f464..13f20ca5ef 100644
--- a/src/math/rand/rand.go
+++ b/src/math/rand/rand.go
@@ -12,9 +12,6 @@
// The default Source is safe for concurrent use by multiple goroutines, but
// Sources created by NewSource are not.
//
-// Mathematical interval notation such as [0, n) is used throughout the
-// documentation for this package.
-//
// This package's outputs might be easily predictable regardless of how it's
// seeded. For random numbers suitable for security-sensitive work, see the
// crypto/rand package.
@@ -106,7 +103,7 @@ func (r *Rand) Int() int {
return int(u << 1 >> 1) // clear sign bit if int == int32
}
-// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
func (r *Rand) Int63n(n int64) int64 {
if n <= 0 {
@@ -123,7 +120,7 @@ func (r *Rand) Int63n(n int64) int64 {
return v % n
}
-// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
func (r *Rand) Int31n(n int32) int32 {
if n <= 0 {
@@ -140,7 +137,7 @@ func (r *Rand) Int31n(n int32) int32 {
return v % n
}
-// int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+// int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
// n must be > 0, but int31n does not check this; the caller must ensure it.
// int31n exists because Int31n is inefficient, but Go 1 compatibility
// requires that the stream of values produced by math/rand remain unchanged.
@@ -164,7 +161,7 @@ func (r *Rand) int31n(n int32) int32 {
return int32(prod >> 32)
}
-// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
func (r *Rand) Intn(n int) int {
if n <= 0 {
@@ -176,7 +173,7 @@ func (r *Rand) Intn(n int) int {
return int(r.Int63n(int64(n)))
}
-// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
+// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0).
func (r *Rand) Float64() float64 {
// A clearer, simpler implementation would be:
// return float64(r.Int63n(1<<53)) / (1<<53)
@@ -202,7 +199,7 @@ again:
return f
}
-// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
+// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0).
func (r *Rand) Float32() float32 {
// Same rationale as in Float64: we want to preserve the Go 1 value
// stream except we want to fix it not to return 1.0
@@ -215,7 +212,8 @@ again:
return f
}
-// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
+// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
+// in the half-open interval [0,n).
func (r *Rand) Perm(n int) []int {
m := make([]int, n)
// In the following loop, the iteration when i=0 always swaps m[0] with m[0].
@@ -323,31 +321,31 @@ func Int31() int32 { return globalRand.Int31() }
// Int returns a non-negative pseudo-random int from the default Source.
func Int() int { return globalRand.Int() }
-// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n)
+// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n)
// from the default Source.
// It panics if n <= 0.
func Int63n(n int64) int64 { return globalRand.Int63n(n) }
-// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n)
+// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n)
// from the default Source.
// It panics if n <= 0.
func Int31n(n int32) int32 { return globalRand.Int31n(n) }
-// Intn returns, as an int, a non-negative pseudo-random number in [0,n)
+// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n)
// from the default Source.
// It panics if n <= 0.
func Intn(n int) int { return globalRand.Intn(n) }
-// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0)
+// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0)
// from the default Source.
func Float64() float64 { return globalRand.Float64() }
-// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0)
+// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0)
// from the default Source.
func Float32() float32 { return globalRand.Float32() }
-// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n)
-// from the default Source.
+// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
+// in the half-open interval [0,n) from the default Source.
func Perm(n int) []int { return globalRand.Perm(n) }
// Shuffle pseudo-randomizes the order of elements using the default Source.
diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go
index cea68742d2..649854b746 100644
--- a/src/os/signal/signal_test.go
+++ b/src/os/signal/signal_test.go
@@ -32,6 +32,11 @@ import (
// The current value is set based on flakes observed in the Go builders.
var settleTime = 100 * time.Millisecond
+// fatalWaitingTime is an absurdly long time to wait for signals to be
+// delivered but, using it, we (hopefully) eliminate test flakes on the
+// build servers. See #46736 for discussion.
+var fatalWaitingTime = 30 * time.Second
+
func init() {
if testenv.Builder() == "solaris-amd64-oraclerel" {
// The solaris-amd64-oraclerel builder has been observed to time out in
@@ -84,7 +89,7 @@ func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) {
// General user code should filter out all unexpected signals instead of just
// SIGURG, but since os/signal is tightly coupled to the runtime it seems
// appropriate to be stricter here.
- for time.Since(start) < settleTime {
+ for time.Since(start) < fatalWaitingTime {
select {
case s := <-c:
if s == sig {
@@ -97,7 +102,7 @@ func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) {
timer.Reset(settleTime / 10)
}
}
- t.Fatalf("timeout after %v waiting for %v", settleTime, sig)
+ t.Fatalf("timeout after %v waiting for %v", fatalWaitingTime, sig)
}
// quiesce waits until we can be reasonably confident that all pending signals
diff --git a/src/runtime/example_test.go b/src/runtime/example_test.go
index e4912a5158..dcb8f7798e 100644
--- a/src/runtime/example_test.go
+++ b/src/runtime/example_test.go
@@ -12,12 +12,15 @@ import (
func ExampleFrames() {
c := func() {
- // Ask runtime.Callers for up to 10 pcs, including runtime.Callers itself.
+ // Ask runtime.Callers for up to 10 PCs, including runtime.Callers itself.
pc := make([]uintptr, 10)
n := runtime.Callers(0, pc)
if n == 0 {
- // No pcs available. Stop now.
- // This can happen if the first argument to runtime.Callers is large.
+ // No PCs available. This can happen if the first argument to
+ // runtime.Callers is large.
+ //
+ // Return now to avoid processing the zero Frame that would
+ // otherwise be returned by frames.Next below.
return
}
@@ -25,9 +28,12 @@ func ExampleFrames() {
frames := runtime.CallersFrames(pc)
// Loop to get frames.
- // A fixed number of pcs can expand to an indefinite number of Frames.
+ // A fixed number of PCs can expand to an indefinite number of Frames.
for {
frame, more := frames.Next()
+
+ // Process this frame.
+ //
// To keep this example's output stable
// even if there are changes in the testing package,
// stop unwinding when we leave package runtime.
@@ -35,6 +41,8 @@ func ExampleFrames() {
break
}
fmt.Printf("- more:%v | %s\n", more, frame.Function)
+
+ // Check whether there are more frames to process after this one.
if !more {
break
}
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index cfcf379d1f..e0d32a0f54 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -261,6 +261,27 @@ func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []*profile.Loca
return p
}
+func cpuProfilingBroken() bool {
+ switch runtime.GOOS {
+ case "plan9":
+ // Profiling unimplemented.
+ return true
+ case "aix":
+ // See https://golang.org/issue/45170.
+ return true
+ case "ios", "dragonfly", "netbsd", "illumos", "solaris":
+ // See https://golang.org/issue/13841.
+ return true
+ case "openbsd":
+ if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
+ // See https://golang.org/issue/13841.
+ return true
+ }
+ }
+
+ return false
+}
+
// testCPUProfile runs f under the CPU profiler, checking for some conditions specified by need,
// as interpreted by matches, and returns the parsed profile.
func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []string, f func(dur time.Duration)) *profile.Profile {
@@ -276,16 +297,7 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri
t.Skip("skipping on plan9")
}
- broken := false
- switch runtime.GOOS {
- // See https://golang.org/issue/45170 for AIX.
- case "ios", "dragonfly", "netbsd", "illumos", "solaris", "aix":
- broken = true
- case "openbsd":
- if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
- broken = true
- }
- }
+ broken := cpuProfilingBroken()
maxDuration := 5 * time.Second
if testing.Short() && broken {
@@ -612,7 +624,7 @@ func growstack1() {
//go:noinline
func growstack(n int) {
- var buf [8 << 16]byte
+ var buf [8 << 18]byte
use(buf)
if n > 0 {
growstack(n - 1)
@@ -620,7 +632,7 @@ func growstack(n int) {
}
//go:noinline
-func use(x [8 << 16]byte) {}
+func use(x [8 << 18]byte) {}
func TestBlockProfile(t *testing.T) {
type TestCase struct {
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index 0b3414d457..8117582855 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -281,6 +281,8 @@ func setProcessCPUProfiler(hz int32) {
it.it_value = it.it_interval
setitimer(_ITIMER_PROF, &it, nil)
} else {
+ setitimer(_ITIMER_PROF, &itimerval{}, nil)
+
// If the Go signal handler should be disabled by default,
// switch back to the signal handler that was installed
// when we enabled profiling. We don't try to handle the case
@@ -304,8 +306,6 @@ func setProcessCPUProfiler(hz int32) {
setsig(_SIGPROF, h)
}
}
-
- setitimer(_ITIMER_PROF, &itimerval{}, nil)
}
}
@@ -383,7 +383,7 @@ func preemptM(mp *m) {
//go:nosplit
func sigFetchG(c *sigctxt) *g {
switch GOARCH {
- case "arm", "arm64":
+ case "arm", "arm64", "ppc64", "ppc64le":
if !iscgo && inVDSOPage(c.sigpc()) {
// When using cgo, we save the g on TLS and load it from there
// in sigtramp. Just use that.
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 0167d51d60..44ea0710c6 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -69,8 +69,15 @@ func CallersFrames(callers []uintptr) *Frames {
return f
}
-// Next returns frame information for the next caller.
-// If more is false, there are no more callers (the Frame value is valid).
+// Next returns a Frame representing the next call frame in the slice
+// of PC values. If it has already returned all call frames, Next
+// returns a zero Frame.
+//
+// The more result indicates whether the next call to Next will return
+// a valid Frame. It does not necessarily indicate whether this call
+// returned one.
+//
+// See the Frames example for idiomatic usage.
func (ci *Frames) Next() (frame Frame, more bool) {
for len(ci.frames) < 2 {
// Find the next frame.
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 05b5916db4..005fa4d2b4 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -216,15 +216,45 @@ TEXT runtime·walltime(SB),NOSPLIT,$16-12
MOVD (g_sched+gobuf_sp)(R7), R1 // Set SP to g0 stack
noswitch:
- SUB $16, R1 // Space for results
- RLDICR $0, R1, $59, R1 // Align for C code
+ SUB $16, R1 // Space for results
+ RLDICR $0, R1, $59, R1 // Align for C code
MOVD R12, CTR
MOVD R1, R4
- BL (CTR) // Call from VDSO
- MOVD $0, R0 // Restore R0
- MOVD 0(R1), R3 // sec
- MOVD 8(R1), R5 // nsec
- MOVD R15, R1 // Restore SP
+
+ // Store g on gsignal's stack, so if we receive a signal
+ // during VDSO code we can find the g.
+ // If we don't have a signal stack, we won't receive signal,
+ // so don't bother saving g.
+ // When using cgo, we already saved g on TLS, also don't save
+ // g here.
+ // Also don't save g if we are already on the signal stack.
+ // We won't get a nested signal.
+ MOVBZ runtime·iscgo(SB), R22
+ CMP R22, $0
+ BNE nosaveg
+ MOVD m_gsignal(R21), R22 // g.m.gsignal
+ CMP R22, $0
+ BEQ nosaveg
+
+ CMP g, R22
+ BEQ nosaveg
+ MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
+ MOVD g, (R22)
+
+ BL (CTR) // Call from VDSO
+
+ MOVD $0, (R22) // clear g slot, R22 is unchanged by C code
+
+ JMP finish
+
+nosaveg:
+ BL (CTR) // Call from VDSO
+
+finish:
+ MOVD $0, R0 // Restore R0
+ MOVD 0(R1), R3 // sec
+ MOVD 8(R1), R5 // nsec
+ MOVD R15, R1 // Restore SP
// Restore vdsoPC, vdsoSP
// We don't worry about being signaled between the two stores.
@@ -236,7 +266,7 @@ noswitch:
MOVD 32(R1), R6
MOVD R6, m_vdsoPC(R21)
-finish:
+return:
MOVD R3, sec+0(FP)
MOVW R5, nsec+8(FP)
RET
@@ -247,7 +277,7 @@ fallback:
SYSCALL $SYS_clock_gettime
MOVD 32(R1), R3
MOVD 40(R1), R5
- JMP finish
+ JMP return
TEXT runtime·nanotime1(SB),NOSPLIT,$16-8
MOVD $1, R3 // CLOCK_MONOTONIC
@@ -283,7 +313,37 @@ noswitch:
RLDICR $0, R1, $59, R1 // Align for C code
MOVD R12, CTR
MOVD R1, R4
- BL (CTR) // Call from VDSO
+
+ // Store g on gsignal's stack, so if we receive a signal
+ // during VDSO code we can find the g.
+ // If we don't have a signal stack, we won't receive signal,
+ // so don't bother saving g.
+ // When using cgo, we already saved g on TLS, also don't save
+ // g here.
+ // Also don't save g if we are already on the signal stack.
+ // We won't get a nested signal.
+ MOVBZ runtime·iscgo(SB), R22
+ CMP R22, $0
+ BNE nosaveg
+ MOVD m_gsignal(R21), R22 // g.m.gsignal
+ CMP R22, $0
+ BEQ nosaveg
+
+ CMP g, R22
+ BEQ nosaveg
+ MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
+ MOVD g, (R22)
+
+ BL (CTR) // Call from VDSO
+
+ MOVD $0, (R22) // clear g slot, R22 is unchanged by C code
+
+ JMP finish
+
+nosaveg:
+ BL (CTR) // Call from VDSO
+
+finish:
MOVD $0, R0 // Restore R0
MOVD 0(R1), R3 // sec
MOVD 8(R1), R5 // nsec
@@ -299,7 +359,7 @@ noswitch:
MOVD 32(R1), R6
MOVD R6, m_vdsoPC(R21)
-finish:
+return:
// sec is in R3, nsec in R5
// return nsec in R3
MOVD $1000000000, R4
@@ -314,7 +374,7 @@ fallback:
SYSCALL $SYS_clock_gettime
MOVD 32(R1), R3
MOVD 40(R1), R5
- JMP finish
+ JMP return
TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
MOVW how+0(FP), R3
@@ -469,7 +529,7 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
// this might be called in external code context,
// where g is not set.
MOVBZ runtime·iscgo(SB), R6
- CMP R6, $0
+ CMP R6, $0
BEQ 2(PC)
BL runtime·load_g(SB)
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 85a7fec65f..fdf57a3953 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -252,6 +252,8 @@ import (
"sync"
"sync/atomic"
"time"
+ "unicode"
+ "unicode/utf8"
)
var initRan bool
@@ -908,11 +910,6 @@ func (c *common) Cleanup(f func()) {
c.cleanups = append(c.cleanups, fn)
}
-var tempDirReplacer struct {
- sync.Once
- r *strings.Replacer
-}
-
// TempDir returns a temporary directory for the test to use.
// The directory is automatically removed by Cleanup when the test and
// all its subtests complete.
@@ -936,13 +933,26 @@ func (c *common) TempDir() string {
if nonExistent {
c.Helper()
- // os.MkdirTemp doesn't like path separators in its pattern,
- // so mangle the name to accommodate subtests.
- tempDirReplacer.Do(func() {
- tempDirReplacer.r = strings.NewReplacer("/", "_", "\\", "_", ":", "_")
- })
- pattern := tempDirReplacer.r.Replace(c.Name())
-
+ // Drop unusual characters (such as path separators or
+ // characters interacting with globs) from the directory name to
+ // avoid surprising os.MkdirTemp behavior.
+ mapper := func(r rune) rune {
+ if r < utf8.RuneSelf {
+ const allowed = "!#$%&()+,-.=@^_{}~ "
+ if '0' <= r && r <= '9' ||
+ 'a' <= r && r <= 'z' ||
+ 'A' <= r && r <= 'Z' {
+ return r
+ }
+ if strings.ContainsRune(allowed, r) {
+ return r
+ }
+ } else if unicode.IsLetter(r) || unicode.IsNumber(r) {
+ return r
+ }
+ return -1
+ }
+ pattern := strings.Map(mapper, c.Name())
c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern)
if c.tempDirErr == nil {
c.Cleanup(func() {
diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go
index 55a4df4739..08ae23991f 100644
--- a/src/testing/testing_test.go
+++ b/src/testing/testing_test.go
@@ -58,6 +58,9 @@ func TestTempDir(t *testing.T) {
t.Run("test:subtest", testTempDir)
t.Run("test/..", testTempDir)
t.Run("../test", testTempDir)
+ t.Run("test[]", testTempDir)
+ t.Run("test*", testTempDir)
+ t.Run("äöüéè", testTempDir)
}
func testTempDir(t *testing.T) {
@@ -74,7 +77,7 @@ func testTempDir(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- t.Errorf("directory %q stil exists: %v, isDir=%v", dir, fi, fi.IsDir())
+ t.Errorf("directory %q still exists: %v, isDir=%v", dir, fi, fi.IsDir())
default:
if !t.Failed() {
t.Fatal("never received dir channel")
@@ -108,6 +111,11 @@ func testTempDir(t *testing.T) {
if len(files) > 0 {
t.Errorf("unexpected %d files in TempDir: %v", len(files), files)
}
+
+ glob := filepath.Join(dir, "*.txt")
+ if _, err := filepath.Glob(glob); err != nil {
+ t.Error(err)
+ }
}
func TestSetenv(t *testing.T) {
diff --git a/src/time/time.go b/src/time/time.go
index cd756bbf5f..1cf1e2bbf6 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -1340,7 +1340,7 @@ func UnixMicro(usec int64) Time {
}
// IsDST reports whether the time in the configured location is in Daylight Savings Time.
-func (t *Time) IsDST() bool {
+func (t Time) IsDST() bool {
_, _, _, _, isDST := t.loc.lookup(t.Unix())
return isDST
}