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

TODO: https://go.dev/cl/421440: cmd/go: add go generate -skip flag

TODO: https://go.dev/issue/45454: provide build tags for architecture environment variables

TODO: CL 448357: cmd/go: print test2json start events

The Go distribution no longer ships with pre-compiled .a files for most of the packages in GOROOT, now only including .a files for the five packages in GOROOT that use cgo. Instead, those packages will be built as needed and cached in the build cache, as is already done for non-main packages outside GOROOT. Further, go install will also not install .a files for GOROOT packages except for those that use cgo. These changes are intended to reduce the size of the Go distribution, in some cases by up to two-thirds.

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.)

The -i flag is no longer accepted by go build and go test. The flag has been deprecated since Go 1.16.

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 test command now accepts -skip <pattern> to skip tests or subtests matching <pattern>.

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.

Cover

TODO coverage

Vet

TODO: https://go.dev/issue/48801: check for time formats with 2006-02-01

TODO: https://go.dev/issue/55972: extend the loopclosure analysis to parallel subtests

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

TODO: https://go.dev/issue/44505: adopt Go 1.17.13 as bootstrap toolchain for Go 1.20

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

(*Reader).Next will now 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 want to operate on archives containing insecure file names may ignore this error.

Insecure tar file name checks may be entirely disabled by setting the GODEBUG=tarinsecurepath=1 environment variable.

archive/zip

NewReader will now 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 want to operate on archives containing insecure file names may ignore this error.

Insecure zip file name checks may be entirely disabled by setting the GODEBUG=zipinsecurepath=1 environment variable.

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

TODO: https://go.dev/issue/54880: seed global generator randomly

TODO: https://go.dev/cl/436955: math/rand: deprecate Read

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