DRAFT RELEASE NOTES — Introduction to Go 1.20

Go 1.20 is not yet released. These are work-in-progress release notes. Go 1.20 is expected to be released in February 2023.

Changes to the language

TODO: complete this section

TODO: https://go.dev/issue/8606: define that structs are compared field-by-field as listed in source code

TODO: https://go.dev/issue/46505: allow conversion from slice to array

Ports

TODO: complete this section, or delete if not needed

TODO: https://go.dev/issue/53466: add freebsd/riscv64 port

Tools

Go command

The directory $GOROOT/pkg no longer stores pre-compiled package archives for the standard library: go install no longer writes them, the go build no longer checks for them, and the Go distribution no longer ships them. Instead, packages in the standard library are built as needed and cached in the build cache, just like packages outside GOROOT. This change reduces the size of the Go distribution and also avoids C toolchain skew for packages that use cgo.

The implementation of go test -json has been improved to make it more robust. Programs that run go test -json do not need any updates. Programs that invoke go tool test2json directly should now run the test binary with -v=json (for example, go test -v=json or ./pkg.test -test.v=json) instead of plain -v.

A related change to go test -json is the addition of an event with Action set to start at the beginning of each test program's execution. When running multiple tests using the go command, these start events are guaranteed to be emitted in the same order as the packages named on the command line.

The go command now defines architecture feature build tags, such as amd64.v2, to allow selecting a package implementation file based on the presence or absence of a particular architecture feature. See go help buildconstraint for details.

The go subcommands now accept -C <dir> to change directory to <dir> before performing the command, which may be useful for scripts that need to execute commands in multiple different modules.

The go build and go test commands no longer accept the -i flag, which has been deprecated since Go 1.16.

The go generate command now accepts -skip <pattern> to skip //go:generate directives matching <pattern>.

The go test command now accepts -skip <pattern> to skip tests, subtests, or examples matching <pattern>.

When the main module is located within GOPATH/src, go install no longer installs libraries for non-main packages to GOPATH/pkg, and go list no longer reports a Target field for such packages. (In module mode, compiled packages are stored in the build cache only, but a bug had caused the GOPATH install targets to unexpectedly remain in effect.)

go version

The go version -m command now supports reading more types of Go binaries, most notably, Windows DLLs built with go build -buildmode=c-shared and Linux binaries without execute permission.

Cgo

The go command now disables cgo by default on systems without a C toolchain. More specifically, when the CGO_ENABLED environment variable is unset, the CC environment variable is unset, and the default C compiler (typically clang or gcc) is not found in the path, CGO_ENABLED defaults to 0. As always, you can override the default by setting CGO_ENABLED explicitly.

The most important effect of the default change is that when Go is installed on a system without a C compiler, it will now use pure Go builds for packages in the standard library that use cgo, instead of using pre-distributed package archives (which have been removed, as noted above) or attempting to use cgo and failing. This makes Go work better in some minimal container environments as well as on macOS, where pre-distributed package archives have not been used for cgo-based packages since Go 1.16.

The packages in the standard library that use cgo are net, os/user, and plugin. On macOS, the net and os/user packages have been rewritten not to use cgo: the same code is now used for cgo and non-cgo builds as well as cross-compiled builds. On Windows, the net and os/user packages have never used cgo. On other systems, builds with cgo disabled will use a pure Go version of these packages.

On macOS, the race detector has been rewritten not to use cgo: race-detector-enabled programs can be built and run without Xcode. On Linux and other Unix systems, and on Windows, a host C toolchain is required to use the race detector.

Cover

TODO coverage

Vet

Improved detection of loop variable capture by nested functions

The vet tool now reports references to loop variables following a call to T.Parallel() within subtest function bodies. Such references may observe the value of the variable from a different iteration (typically causing test cases to be skipped) or an invalid state due to unsynchronized concurrent access.

The tool also detects reference mistakes in more places. Previously it would only consider the last statement of the loop body, but now it recursively inspects the last statements within if, switch, and select statements.

New diagnostic for incorrect time formats

The vet tool now reports use of the time format 2006-02-01 (yyyy-dd-mm) with Time.Format and time.Parse. This format does not appear in common date standards, but is frequently used by mistake when attempting to use the ISO 8601 date format (yyyy-mm-dd).

Runtime

TODO: complete this section, or delete if not needed

Compiler

TODO: https://go.dev/issue/49390: clarify whether "-l" and "-N" compiler flags are actually supported

Linker

TODO: complete this section, or delete if not needed

Bootstrap

When building a Go release from source and GOROOT_BOOTSTRAP is not set, previous versions of Go looked for a Go 1.4 or later bootstrap toolchain in the directory $HOME/go1.4 (%HOMEDRIVE%%HOMEPATH%\go1.4 on Windows). Go 1.18 and Go 1.19 looked first for $HOME/go1.17 or $HOME/sdk/go1.17 before falling back to $HOME/go1.4, in ancitipation of requiring Go 1.17 for use when bootstrapping Go 1.20. Go 1.20 does require a Go 1.17 release for bootstrapping, but we realized that we should adopt the latest point release of the bootstrap toolchain, so it requires Go 1.17.13. Go 1.20 looks for $HOME/go1.17.13 or $HOME/sdk/go1.17.13 before falling back to $HOME/go1.4 (to support systems that hard-coded the path $HOME/go1.4 but have installed a newer Go toolchain there). In the future, we plan to move the bootstrap toolchain forward approximately once a year, and in particular we expect that Go 1.22 will require the final point release of Go 1.20 for bootstrap.

Core library

New crypto/ecdh package

TODO: complete this section

Wrapping multiple errors

Go 1.20 expands support for error wrapping to permit an error to wrap multiple other errors.

An error e can wrap more than one error by providing an Unwrap method that returns a []error.

The errors.Is and errors.As functions have been updated to inspect multiply wrapped errors.

The fmt.Errorf function now supports multiple occurrances of the %w format verb, which will cause it to return an error that wraps all of those error operands.

The new function errors.Join returns an error wrapping a list of errors.

HTTP ResponseController

The new "net/http".ResponseController type provides access to extended per-request functionality not handled by the "net/http".ResponseWriter interface.

Previously, we have added new per-request functionality by defining optional interfaces which a ResponseWriter can implement, such as Flusher. These interfaces are not discoverable and clumsy to use.

The ResponseController type provides a clearer, more discoverable way to add per-handler controls. Two such controls also added in Go 1.20 are SetReadDeadline and SetWriteDeadline, which allow setting per-request read and write deadlines. For example:

func RequestHandler(w ResponseWriter, r *Request) {
  rc := http.NewResponseController(w)
  rc.SetWriteDeadline(0) // disable Server.WriteTimeout when sending a large response
  io.Copy(w, bigData)
}

New ReverseProxy Rewrite hook

The httputil.ReverseProxy forwarding proxy includes a new Rewrite hook function, superseding the previous Director hook.

The Rewrite hook accepts a ProxyRequest parameter, which includes both the inbound request received by the proxy and the outbound request that it will send. Unlike Director hooks, which only operate on the outbound request, this permits Rewrite hooks to avoid certain scenarios where a malicious inbound request may cause headers added by the hook to be removed before forwarding. See issue #50580.

The ProxyRequest.SetURL method routes the outbound request to a provided destination and supersedes the NewSingleHostReverseProxy function. Unlike NewSingleHostReverseProxy, SetURL also sets the Host header of the outbound request.

The ProxyRequest.SetXForwarded method sets the X-Forwarded-For, X-Forwarded-Host, and X-Forwarded-Proto headers of the outbound request. When using a Rewrite, these headers are not added by default.

An example of a Rewrite hook using these features is:

proxyHandler := &httputil.ReverseProxy{
  Rewrite: func(r *httputil.ProxyRequest) {
    r.SetURL(outboundURL) // Forward request to outboundURL.
    r.SetXForwarded()     // Set X-Forwarded-* headers.
    r.Out.Header.Set("X-Additional-Header", "header set by the proxy")
  },
}

Minor changes to the library

As always, there are various minor changes and updates to the library, made with the Go 1 promise of compatibility in mind. There are also various performance improvements, not enumerated here.

TODO: complete this section

archive/tar

When the GODEBUG=tarinsecurepath=0 environment variable is set, (*Reader).Next will return the error ErrInsecurePath when opening an archive which contains file names that are absolute, refer to a location outside the current directory, contain invalid characters, or (on Windows) are reserved names such as NUL. Programs that perform their own name sanitization can ignore this error. This behavior will be made the default in a future version of Go.

archive/zip

When the GODEBUG=zipinsecurepath=0 environment variable is set, NewReader will return the error ErrInsecurePath when opening an archive which contains file names that are absolute, refer to a location outside the current irectory, contain invalid characters, or (on Windows) are reserved names such as NUL. Programs that perform their own name sanitization can ignore this error. This behavior will be made the default in a future version of Go.

Reading from a directory file that contains file data will now return an error. The zip specification does not permit directory files to contain file data, so this change only affects reading from invalid archives.

bytes

TODO: https://go.dev/cl/407176: strings, bytes: add CutPrefix and CutSuffix

TODO: https://go.dev/cl/359675: bytes: add Clone function

context

TODO: https://go.dev/cl/375977: context: add APIs for writing and reading cancelation cause; modified api/next/51365.txt

crypto/ed25519

TODO: https://go.dev/cl/373076: crypto/ed25519: implement Ed25519ph in Sign and VerifyWithOptions; modified api/next/31804.txt

crypto/elliptic

TODO: https://go.dev/issue/34648: automatically upgrade CurveParams for known curves and deprecate custom ones

crypto/rsa

TODO: https://go.dev/issue/19974: allow hash.Hash for OAEP and MGF1 to be specified independently

crypto/subtle

TODO: https://go.dev/issue/53021: add XORBytes

TODO: https://go.dev/cl/421435: crypto/subtle: add XORBytes; modified api/next/53021.txt

crypto/tls

TODO: https://go.dev/cl/426455: crypto/tls: use certificate cache in client

debug/elf

TODO: https://go.dev/cl/420982: debug/elf: add new-style LoongArch reloc types; modified api/next/54222.txt

TODO: https://go.dev/cl/411915: debug/elf: fix reloc number of R_PPC64_SECTOFF_LO_DS; modified api/except.txt, api/next/53356.txt

TODO: https://go.dev/cl/425555: debug/elf: define additional PPC64 ELFv2 relocations; modified api/next/54345.txt

TODO: https://go.dev/cl/429601: debug/elf: return error on reading from SHT_NOBITS sections

TODO: https://go.dev/cl/435415: debug/elf: fix typo in R_PPC64_TPREL34 and R_PPC64_DTPREL34; modified api/next/54345.txt

debug/pe

TODO: https://go.dev/cl/421357: debug/pe: add IMAGE_FILE_MACHINE_RISCV{32,64,128}; modified api/next/54251.txt

encoding/binary

The ReadVarint and ReadUvarint functions will now return io.ErrUnexpectedEOF after reading a partial value, rather than io.EOF.

encoding/xml

TODO: https://go.dev/issue/53346: Add (*Encoder).Close() to check for unclosed elements

TODO: https://go.dev/cl/424777: encoding/xml: add (*Encoder).Close

TODO: https://go.dev/cl/103875: encoding/xml: error when more than one colon in qualified names

TODO: https://go.dev/cl/107255: encoding/xml: error when closing tag does not match opening tag

errors

The new Join function returns an error wrapping a list of errors.

fmt

The Errorf function supports multiple occurrances of the %w format verb.

TODO: https://go.dev/issue/51668: add FormatString(State) string

TODO: https://go.dev/cl/400875: fmt: add a function to recover the original format string given a State; modified api/next/51668.txt

go/ast

TODO: https://go.dev/cl/426091: go/ast: add Range token.Pos to RangeStmt

TODO: https://go.dev/cl/427955: go/ast: record start and end of file in File.File{Start,End}; modified api/next/53202.txt

go/build

TODO: https://go.dev/cl/421434: go/build: add GO$GOARCH-based ToolTags

go/token

TODO: https://go.dev/cl/410114: go/token: add (*FileSet).RemoveFile(*File) method

io

TODO: https://go.dev/issue/45899: add OffsetWriter, NewOffsetWriter

TODO: https://go.dev/cl/406776: io: add OffsetWriter, NewOffsetWriter; modified api/next/45899.txt

io/fs

TODO: https://go.dev/cl/363814: path/filepath, io/fs: add SkipAll; modified api/next/47209.txt

math/rand

The math/rand package now automatically seeds the global random number generator (used by top-level functions like Float64 and Int) with a random value, and the top-level Seed function has been deprecated. Programs that need a reproducible sequence of random numbers should prefer to allocate their own random source, using rand.New(rand.NewSource(seed)).

Programs that need the earlier consistent global seeding behavior can set GODEBUG=randautoseed=0 in their environment.

mime

The ParseMediaType function now allows duplicate parameter names, so long as the values of the names are the same.

mime/multipart

Methods of the Reader type now wrap errors returned by the underlying io.Reader.

net

The LookupCNAME function now consistently returns the contents of a CNAME record when one exists. Previously on Unix systems and when using the pure Go resolver, LookupCNAME would return an error if a CNAME record referred to a name that with no A, AAAA, or CNAME record. This change modifies LookupCNAME to match the previous behavior on Windows, allowing allowing LookupCNAME to succeed whenever a CNAME exists.

Interface.Flags now includes the new flag FlagRunning, indicating an operationally active interface. An interface which is administratively configured but not active (for example, because the network cable is not connected) will have FlagUp set but not FlagRunning.

The new Dialer.ControlContext field contains a callback function similar to the existing Dialer.Control hook, that additionally accepts the dial context as a parameter. Control is ignored when ControlContext is not nil.

The Go DNS resolver recognizes the trust-ad resolver option. When options trust-ad is set in resolv.conf, the Go resolver will set the AD bit in DNS queries. The resolver does not make use of the AD bit in responses.

DNS resolution will detect changes to /etc/nsswitch.conf and reload the file when it changes. Checks are made at most once every five seconds, matching the previous handling of /etc/hosts and /etc/resolv.conf.

net/http

The new ResponseController type provides access to extended per-request functionality not handled by the ResponseWriter interface.

The new ResponseController.SetReadDeadline and ResponseController.SetWriteDeadline methods permit setting per-request read and write deadlines.

The ResponseWriter.WriteHeader function now supports sending 1xx status codes.

The new Server.DisableGeneralOptionsHandler configuration setting allows disabling the default OPTIONS * handler.

The new Transport.OnProxyConnectResponse hook is called when a Transport receives an HTTP response from a proxy for a CONNECT request.

The HTTP server now accepts HEAD requests containing a body, rather than rejecting them as invalid.

HTTP/2 stream errors returned by net/http functions may be converted to a "golang.org/x/net/http2".StreamError using errors.As.

Leading and trailing spaces are trimmed from cookie names, rather than being rejected as invalid. For example, a cookie setting of "name =value" is now accepted as setting the cookie "name".

net/http/httputil

The new ReverseProxy hook supersedes the existing Rewrite hook.

ReverseProxy now adds X-Forwarded-Proto and X-Forwarded-Host headers to forwarded requests. These headers are added to all requests forwarded by a Director hook, and to requests forwarded by a Rewrite hook which calls the ProxyRequest.SetXForwarded function.

ReverseProxy no longer adds a User-Agent header to forwarded requests when the incoming request does not have one.

net/netip

TODO: https://go.dev/issue/51766: add IPv6LinkLocalAllRouters

TODO: https://go.dev/issue/51777: add IPv6Loopback

TODO: https://go.dev/cl/412475: net/netip: add IPv6LinkLocalAllRouters and IPv6Loopback; modified api/next/51766.txt, api/next/51777.txt

os

TODO: https://go.dev/cl/448897: os: remove special casing of NUL in Windows file operations

os/exec

The new Cmd fields Cancel and WaitDelay specify the behavior of the Cmd when its associated Context is canceled or its process exits with I/O pipes still held open by a child process.

path/filepath

TODO: https://go.dev/cl/363814: path/filepath, io/fs: add SkipAll; modified api/next/47209.txt

The new IsLocal function reports whether a path is lexically local to a directory. For example, if IsLocal(p) is true, then Open(p) will refer to a file that is lexically within the subtree rooted at the current directory.

reflect

TODO: https://go.dev/issue/46746: add Value.Equal, Value.Comparable

TODO: https://go.dev/issue/48000: add reflect.Value.Grow

TODO: https://go.dev/issue/52376: add Value.SetZero

TODO: https://go.dev/cl/389635: reflect: add Value.Grow

TODO: https://go.dev/cl/411476: reflect: add Value.SetZero

TODO: https://go.dev/cl/423794: reflect: add Value.{Comparable,Equal}

TODO: https://go.dev/cl/425184: reflect: fix Value.SetIterXXX to check for the read-only bit

TODO: https://go.dev/cl/428757: reflect: deprecate SliceHeader and StringHeader

regexp

TODO: https://go.dev/cl/444817: regexp: add ErrLarge error; modified api/next/56041.txt

runtime/metrics

TODO: https://go.dev/issue/47216: add GOMAXPROCS, NumCgoCall, GC CPU time

strconv

TODO: https://go.dev/cl/345488: strconv: optimize Parse for []byte arguments

strings

TODO: https://go.dev/issue/42537: add CutPrefix and CutSuffix

TODO: https://go.dev/issue/45038: bytes, strings: add Clone

sync

The new methods Map.Swap, Map.CompareAndSwap, and Map.CompareAndDelete allow existing map entries to be updated atomically.

syscall

TODO: https://go.dev/cl/407574: syscall: add new CLONE_ flags for Linux

TODO: https://go.dev/cl/411596: syscall: remove FreeBSD 11 and below 64bit inode compatibility shims

TODO: https://go.dev/cl/417695: syscall: add CgroupFD support for ForkExec on Linux

testing

The new method B.Elapsed reports the current elapsed time of the benchmark, which may be useful for calculating rates to report with ReportMetric.

time

TODO: https://go.dev/issue/52746: add DateTime, DateOnly, TimeOnly format constants

TODO: https://go.dev/cl/412495: time: add DateTime, DateOnly, and TimeOnly

TODO: https://go.dev/cl/382734: time: implement Compare method

TODO: https://go.dev/cl/425037: time: fix Parse to ignore extra sub-nanosecond digits

TODO: https://go.dev/cl/444277: time: implement strict RFC 3339 during marshal and unmarshal

unicode/utf16

TODO: https://go.dev/issue/51896: add AppendRune

TODO: https://go.dev/cl/409054: unicode/utf16: add AppendRune; modified api/next/51896.txt