DRAFT RELEASE NOTES — Introduction to Go 1.22

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

Changes to the language

Go 1.22 makes two changes to "for" loops.

Go 1.22 includes a preview of a language change we are considering for a future version of Go: range-over-function iterators. Building with GOEXPERIMENT=rangefunc enables this feature.

Tools

Go command

Commands in workspaces can now use a vendor directory containing the dependencies of the workspace. The directory is created by go work vendor, and used by build commands when the -mod flag is set to vendor, which is the default when a workspace vendor directory is present.

Note that the vendor directory's contents for a workspace are different from those of a single module: if the directory at the root of a workspace also contains one of the modules in the workspace, its vendor directory can contain the dependencies of either the workspace or of the module, but not both.

go test -cover now prints coverage summaries for covered packages that do not have their own test files. Prior to Go 1.22 a go test -cover run for such a package would report

? mymod/mypack [no test files]

and now with Go 1.22, functions in the package are treated as uncovered:

mymod/mypack coverage: 0.0% of statements

Trace

The trace tool's web UI has been gently refreshed as part of the work to support the new tracer, resolving several issues and improving the readability of various sub-pages. The web UI now supports exploring traces in a thread-oriented view. The trace viewer also now displays the full duration of all system calls.
These improvements only apply for viewing traces produced by programs built with Go 1.22 or newer. A future release will bring some of these improvements to traces produced by older version of Go.

Vet

TODO: https://go.dev/cl/539016: go/analysis/passes/loopclosure: disable checker after go1.22.; loopclosure was modified to only not report in files with GoVersion after 1.22.

New warnings for missing values after append

The vet tool now reports calls to append that pass no values to be appended to the slice, such as slice = append(slice). Such a statement has no effect, and experience has shown that is nearly always a mistake.

New warnings for deferring time.Since

The vet tool now reports a non-deferred call to time.Since(t) within a defer statement. This is equivalent to calling time.Now().Sub(t) before the defer statement, not when the deferred function is called. In nearly all cases, the correct code requires deferring the time.Since call. For example:

t := time.Now()
defer log.Println(time.Since(t)) // non-deferred call to time.Since
tmp := time.Since(t); defer log.Println(tmp) // equivalent to the previous defer

defer func() {
  log.Println(time.Since(t)) // a correctly deferred call to time.Since
}()

New warnings for mismatched key-value pairs in log/slog calls

The vet tool now reports invalid arguments in calls to functions and methods in the structured logging package, log/slog, that accept alternating key/value pairs. It reports calls where an argument in a key position is neither a string nor a slog.Attr, and where a final key is missing its value.

Runtime

The runtime now keeps type-based garbage collection metadata nearer to each heap object, improving the CPU performance (latency or throughput) of Go programs by 1–3%. This change also reduces the memory overhead of the majority Go programs by approximately 1% by deduplicating redundant metadata. Some programs may see a smaller improvement because this change adjusts the size class boundaries of the memory allocator, so some objects may be moved up a size class.

A consequence of this change is that some objects' addresses that were previously always aligned to a 16 byte (or higher) boundary will now only be aligned to an 8 byte boundary. Some programs that use assembly instructions that require memory addresses to be more than 8-byte aligned and rely on the memory allocator's previous alignment behavior may break, but we expect such programs to be rare. Such programs may be built with GOEXPERIMENT=noallocheaders to revert to the old metadata layout and restore the previous alignment behavior, but package owners should update their assembly code to avoid the alignment assumption, as this workaround will be removed in a future release.

On the windows/amd64 port, programs linking or loading Go libraries built with -buildmode=c-archive or -buildmode=c-shared can now use the SetUnhandledExceptionFilter Win32 function to catch exceptions not handled by the Go runtime. Note that this was already supported on the windows/386 port.

Compiler

Profile-guided Optimization (PGO) builds can now devirtualize a higher proportion of calls than previously possible. Most programs from a representative set of Go programs now see between 2 and 14% improvement from enabling PGO.

Linker

The linker's -s and -w flags are now behave more consistently across all platforms. The -w flag suppresses DWARF debug information generation. The -s flag suppresses symbol table generation. The -s flag also implies the -w flag, which can be negated with -w=0. That is, -s -w=0 will generate a binary with DWARF debug information generation but without the symbol table.

On ELF platforms, the -B linker flag now accepts a special form: with -B gobuildid, the linker will generate a GNU build ID (the ELF NT_GNU_BUILD_ID note) derived from the Go build ID.

On Windows, when building with -linkmode=internal, the linker now preserves SEH information from C object files by copying the .pdata and .xdata sections into the final binary. This helps with debugging and profiling binaries using native tools, such as WinDbg. Note that until now, C functions' SEH exception handlers were not being honored, so this change may cause some programs to behave differently. -linkmode=external is not affected by this change, as external linkers already preserve SEH information.

Bootstrap

As mentioned in the Go 1.20 release notes, Go 1.22 now requires the final point release of Go 1.20 or later for bootstrap. We expect that Go 1.24 will require the final point release of Go 1.22 or later for bootstrap.

Core library

New math/rand/v2 package

TODO: https://go.dev/cl/502495: math/rand/v2: start of new API; modified api/next/61716.txt

TODO: https://go.dev/cl/502497: math/rand/v2: remove Read; modified api/next/61716.txt

TODO: https://go.dev/cl/502498: math/rand/v2: remove Rand.Seed; modified api/next/61716.txt

TODO: https://go.dev/cl/502499: math/rand/v2: change Source to use uint64; modified api/next/61716.txt

TODO: https://go.dev/cl/502500: math/rand/v2: add, optimize N, UintN, Uint32N, Uint64N; modified api/next/61716.txt

TODO: https://go.dev/cl/502505: math/rand/v2: add PCG-DXSM; modified api/next/61716.txt

TODO: https://go.dev/cl/502506: math/rand/v2: delete Mitchell/Reeds source; modified api/next/61716.txt

TODO: https://go.dev/cl/516857: math/rand/v2: rename various functions; modified api/next/61716.txt

TODO: https://go.dev/cl/516859: math/rand/v2: add ChaCha8; modified api/next/61716.txt

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

The new method Writer.AddFS adds all of the files from an fs.FS to the archive.

If the argument to FileInfoHeader implements the new FileInfoNames interface, then the interface methods will be used to set the UID/GID of the file header. This allows applications to override the default UID/GID resolution.

archive/zip

The new method Writer.AddFS adds all of the files from an fs.FS to the archive.

bufio

When a SplitFunc returns ErrFinalToken with a nil token, Scanner will now stop immediately. Previously, it would report a final empty token before stopping, which was usually not desired. Callers that do want to report a final empty token can do so by returning []byte{} rather than nil.

cmp

The new function Or returns the first in a sequence of values that is not the zero value.

crypto/tls

TODO: https://go.dev/issue/43922: implement RFC7627

TODO: https://go.dev/issue/62459: make default minimum version for servers TLS 1.2

TODO: https://go.dev/issue/63413: disable RSA key exchange cipher suites by default

TODO: https://go.dev/cl/514997: crypto/tls: change SendSessionTicket to take an options struct; modified api/go1.21.txt

TODO: https://go.dev/cl/541516: crypto/tls: change default minimum version to 1.2

TODO: https://go.dev/cl/541517: crypto/tls: remove RSA KEX ciphers from the default list

TODO: https://go.dev/cl/544155: crypto/tls: disable ExportKeyingMaterial without EMS

crypto/x509

TODO: https://go.dev/issue/57178: support code-constrained roots

TODO: https://go.dev/issue/58922: add android user trusted CA folder as a possible source for certificate retrieval

TODO: https://go.dev/issue/60665: introduce new robust OID type & use it for certificate policies

TODO: https://go.dev/cl/519315: crypto/x509: implement AddCertWithConstraint; modified api/next/57178.txt

TODO: https://go.dev/cl/520535: crypto/x509: add new OID type and use it in Certificate; modified api/next/60665.txt

database/sql

The new Null[T] type provide a way to scan nullable columns for any column types.

debug/elf

Constant R_MIPS_PC32 is defined for use with MIPS64 systems.

Additional R_LARCH_* constants are defined for use with LoongArch systems.

encoding

The new methods AppendEncode and AppendDecode added to each of the Encoding types in the packages encoding/base32, encoding/base64, and encoding/hex simplify encoding and decoding from and to byte slices by taking care of byte slice buffer management.

The methods base32.Encoding.WithPadding and base64.Encoding.WithPadding now panic if the padding argument is a negative value other than NoPadding.

encoding/json

Marshaling and encoding functionality now escapes '\b' and '\f' characters as \b and \f instead of \u0008 and \u000c.

go/ast

The following declarations related to syntactic identifier resolution are now deprecated: Ident.Obj, Object, Scope, File.Scope, File.Unresolved, Importer, Package, NewPackage.

Identifiers cannot be accurately resolved without type information. Consider, for example, the identifier K in T{K: ""}: it could be the name of a local variable if T is a map type, or the name of a field if T is a struct type.

New programs should use the go/types package to resolve identifiers; see Object, Info.Uses, and Info.Defs for details.

The new ast.Unparen function removes any enclosing parentheses from an expression.

go/types

The new Alias type represents type aliases. Previously, type aliases were not represented explicitly, so a reference to a type alias was equivalent to spelling out the aliased type, and the name of the alias was lost. The new representation retains the intermediate Alias. This enables improved error reporting (the name of a type alias can be reported), and allows for better handling of cyclic type declarations involving type aliases. In a future release, Alias types will also carry type parameter information. The new function Unalias returns the actual type denoted by an Alias type (or any other Type for that matter).

Because Alias types may break existing type switches that do not know to check for them, this functionality is controlled by a GODEBUG field named gotypesalias. With gotypesalias=0, everything behaves as before, and Alias types are never created. With gotypesalias=1, Alias types are created and clients must expect them. The default is gotypesalias=0. In a future release, the default will be changed to gotypesalias=1. Clients of go/types are urged to adjust their code as soon as possible to work with gotypesalias=1 to eliminate problems early.

The Info struct now exports the FileVersions map which provides per-file Go version information.

The new helper method PkgNameOf returns the local package name for the given import declaration.

The implementation of SizesFor has been adjusted to compute the same type sizes as the compiler when the compiler argument for SizesFor is "gc". The default Sizes implementation used by the type checker is now types.SizesFor("gc", "amd64").

The start position (Pos) of the lexical environment block (Scope) that represents a function body has changed: it used to start at the opening curly brace of the function body, but now starts at the function's func token.

go/version

The new go/version package implements functions for validating and comparing Go version strings.

html/template

TODO: https://go.dev/issue/61619: allow actions in JS template literals

TODO: https://go.dev/cl/507995: html/template: support parsing complex JS template literals; modified api/next/61619.txt

io

The new SectionReader.Outer method returns the ReaderAt, offset, and size passed to NewSectionReader.

log/slog

TODO: https://go.dev/issue/62418: enable setting level on default log.Logger

TODO: https://go.dev/cl/525096: log/slog: add LogLoggerLevel to enable setting level on the default logger; modified api/next/62418.txt

math/big

The new method Rat.FloatPrec computes the number of fractional decimal digits required to represent a rational number accurately as a floating-point number, and whether accurate decimal representation is possible in the first place.

net

When io.Copy copies from a TCPConn to a UnixConn, it will now use Linux's sendfile(2) system call if possible, using the new method TCPConn.WriteTo.

The Go DNS Resolver, used when building the binary with "-tags=netgo", now searches a matching name in the Windows hosts file, located at %SystemRoot%\System32\drivers\etc\hosts, before making a DNS query.

net/http

TODO: https://go.dev/issue/51971: add ServeFileFS, FileServerFS, NewFileTransportFS

TODO: https://go.dev/issue/61410: enhanced ServeMux routing

TODO: https://go.dev/cl/513956: net/http: add ServeFileFS, FileServerFS, NewFileTransportFS; modified api/next/51971.txt

TODO: https://go.dev/cl/517336: net/http: disallow empty Content-Length header

TODO: https://go.dev/cl/528355: net/http: implement path value methods on Request; modified api/next/61410.txt

net/http/cgi

TODO: https://go.dev/cl/539615: net/http/cgi: the PATH_INFO should be empty or start with a slash

net/netip

TODO: https://go.dev/issue/61642: add Prefix.Compare and AddrPort.Compare

TODO: https://go.dev/cl/524616: net/netip: add AddrPort.Compare and Prefix.Compare; modified api/next/61642.txt

os

On Windows, the Stat function now follows all reparse points that link to another named entity in the system. It was previously only following IO_REPARSE_TAG_SYMLINK and IO_REPARSE_TAG_MOUNT_POINT reparse points.

On Windows, passing O_SYNC to OpenFile now causes write operations to go directly to disk, equivalent to O_SYNC on Unix platforms.

When io.Copy copies from a File to a net.UnixConn, it will now use Linux's sendfile(2) system call if possible, using the new method File.WriteTo.

os/exec

On Windows, LookPath now ignores empty entries in %PATH%, and returns ErrNotFound (instead of ErrNotExist) if no executable file extension is found to resolve an otherwise-unambiguous name.

On Windows, Command and Cmd.Start no longer call LookPath if the path to the executable is already absolute and has an executable file extension. In addition, Cmd.Start no longer writes the resolved extension back to the Path field, so it is now safe to call the String method concurrently with a call to Start.

reflect

The Value.IsZero method will now return true for a floating-point or complex negative zero, and will return true for a struct value if a blank field (a field named _) somehow has a non-zero value. These changes make IsZero consistent with comparing a value to zero using the language == operator.

The PtrTo function is deprecated, in favor of PointerTo.

TODO: https://go.dev/issue/60088: reflect: add TypeFor

runtime/metrics

Four new histogram metrics /sched/pauses/stopping/gc:seconds, /sched/pauses/stopping/other:seconds, /sched/pauses/total/gc:seconds, and /sched/pauses/total/other:seconds provide additional details about stop-the-world pauses. The "stopping" metrics report the time taken from deciding to stop the world until all goroutines are stopped. The "total" metrics report the time taken from deciding to stop the world until it is started again.

The /gc/pauses:seconds metric is deprecated, as it is equivalent to the new /sched/pauses/total/gc:seconds metric.

/sync/mutex/wait/total:seconds now includes contention on runtime-internal locks in addition to sync.Mutex and sync.RWMutex.

runtime/pprof

Mutex profiles now scale contention by the number of goroutines blocked on the mutex. This provides a more accurate representation of the degree to which a mutex is a bottleneck in a Go program. For instance, if 100 goroutines are blocked on a mutex for 10 milliseconds, a mutex profile will now record 1 second of delay instead of 10 milliseconds of delay.

Mutex profiles also now include contention on runtime-internal locks in addition to sync.Mutex and sync.RWMutex. Contention on runtime-internal locks is always reported at runtime._LostContendedRuntimeLock. A future release will add complete stack traces in these cases.

CPU profiles on Darwin platforms now contain the process's memory map, enabling the disassembly view in the pprof tool.

runtime/trace

The execution tracer has been completely overhauled in this release, resolving several long-standing issues and paving the way for new use-cases for execution traces.

Execution traces now use the operating system's clock on most platforms (Windows excluded) so it is possible to correlate them with traces produced by lower-level components. Execution traces no longer depend on the reliability of the platform's clock to produce a correct trace. Execution traces are now partitioned regularly on-the-fly and as a result may be processed in a streamable way. Execution traces now contain complete durations for all system calls. Execution traces now contain information about the operating system threads that goroutines executed on. The latency impact of starting and stopping execution traces has been dramatically reduced. Execution traces may now begin or end during the garbage collection mark phase.

To allow Go developers to take advantage of these improvements, an experimental trace reading package is available at golang.org/x/exp/trace. Note that this package only works on traces produced by programs built with Go 1.22 at the moment. Please try out the package and provide feedback on the corresponding proposal issue.

If you experience any issues with the new execution tracer implementation, you may switch back to the old implementation by building your Go program with GOEXPERIMENT=noexectracer2. If you do, please file an issue, otherwise this option will be removed in a future release.

slices

The new function Concat concatenates multiple slices.

Functions that shrink the size of a slice (Delete, DeleteFunc, Compact, CompactFunc, and Replace) now zero the elements between the new length and the old length.

Insert now always panics if the argument i is out of range. Previously it did not panic in this situation if there were no elements to be inserted.

syscall

The syscall package has been frozen since Go 1.4 and was marked as deprecated in Go 1.11, causing many editors to warn about any use of the package. However, some non-deprecated functionality requires use of the syscall package, such as the os/exec.Cmd.SysProcAttr field. To avoid unnecesary complaints on such code, the syscall package is no longer marked as deprecated. The package remains frozen to most new functionality, and new code remains encouraged to use golang.org/x/sys/unix or golang.org/x/sys/windows where possible.

On Linux, the new SysProcAttr.PidFD field allows obtaining a PID FD when starting a child process via StartProcess or os/exec.

On Windows, passing O_SYNC to Open now causes write operations to go directly to disk, equivalent to O_SYNC on Unix platforms.

testing/slogtest

TODO: https://go.dev/issue/61758: support sub-tests

TODO: https://go.dev/cl/516076: testing/slogtest: add Run to run cases as subtests; modified api/next/61758.txt

Ports

Darwin

On macOS on 64-bit x86 architecture (the darwin/amd64 port), the Go toolchain now generates position-independent executables (PIE) by default. Non-PIE binaries can be generated by specifying the -buildmode=exe build flag. On 64-bit ARM-based macOS (the darwin/arm64 port), the Go toolchain already generates PIE by default.

Arm

The GOARM environment variable now allows you to select whether to use software or hardware floating point. Previously, valid GOARM values were 5, 6, or 7. Now those same values can be optionally followed by ,softfloat or ,hardfloat to select the floating-point implementation.

This new option defaults to softfloat for version 5 and hardfloat for versions 6 and 7.

Loong64

The loong64 port now supports passing function arguments and results using registers.

The linux/loong64 port now supports the memory sanitizer, new-style linker relocations, and the plugin build mode.

OpenBSD

Go 1.22 adds an experimental port to OpenBSD on big-endian 64-bit PowerPC (openbsd/ppc64).