[dev.boringcrypto.go1.17] all: merge go1.17rc2 into dev.boringcrypto.go1.17

Change-Id: I24c7d03fb140d1df8f33b950ee54f4ee51f345d6
diff --git a/AUTHORS b/AUTHORS
index 48ce71f..95d3158 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -41,7 +41,7 @@
 Afanasev Stanislav <phpprogger@gmail.com>
 Agis Anastasopoulos <agis.anast@gmail.com>
 Agniva De Sarker <agnivade@yahoo.co.in>
-Ahmed Wahed <oneofone@gmail.com>
+Ahmed W. Mones <oneofone@gmail.com>
 Ahmet Soormally <ahmet@mangomm.co.uk>
 Ahmy Yulrizka <yulrizka@gmail.com>
 Aiden Scandella <ai@uber.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 6c7262a..ee50a4c 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -67,7 +67,7 @@
 Afanasev Stanislav <phpprogger@gmail.com>
 Agis Anastasopoulos <agis.anast@gmail.com>
 Agniva De Sarker <agnivade@yahoo.co.in>
-Ahmed Wahed <oneofone@gmail.com>
+Ahmed W. Mones <oneofone@gmail.com>
 Ahmet Alp Balkan <ahmetb@google.com>
 Ahmet Soormally <ahmet@mangomm.co.uk>
 Ahmy Yulrizka <yulrizka@gmail.com>
diff --git a/api/go1.17.txt b/api/go1.17.txt
new file mode 100644
index 0000000..4850538
--- /dev/null
+++ b/api/go1.17.txt
@@ -0,0 +1,195 @@
+pkg archive/zip, method (*File) OpenRaw() (io.Reader, error)
+pkg archive/zip, method (*Writer) Copy(*File) error
+pkg archive/zip, method (*Writer) CreateRaw(*FileHeader) (io.Writer, error)
+pkg compress/lzw, method (*Reader) Close() error
+pkg compress/lzw, method (*Reader) Read([]uint8) (int, error)
+pkg compress/lzw, method (*Reader) Reset(io.Reader, Order, int)
+pkg compress/lzw, method (*Writer) Close() error
+pkg compress/lzw, method (*Writer) Reset(io.Writer, Order, int)
+pkg compress/lzw, method (*Writer) Write([]uint8) (int, error)
+pkg compress/lzw, type Reader struct
+pkg compress/lzw, type Writer struct
+pkg crypto/tls, method (*CertificateRequestInfo) Context() context.Context
+pkg crypto/tls, method (*ClientHelloInfo) Context() context.Context
+pkg crypto/tls, method (*Conn) HandshakeContext(context.Context) error
+pkg database/sql, method (*NullByte) Scan(interface{}) error
+pkg database/sql, method (*NullInt16) Scan(interface{}) error
+pkg database/sql, method (NullByte) Value() (driver.Value, error)
+pkg database/sql, method (NullInt16) Value() (driver.Value, error)
+pkg database/sql, type NullByte struct
+pkg database/sql, type NullByte struct, Byte uint8
+pkg database/sql, type NullByte struct, Valid bool
+pkg database/sql, type NullInt16 struct
+pkg database/sql, type NullInt16 struct, Int16 int16
+pkg database/sql, type NullInt16 struct, Valid bool
+pkg debug/elf, const SHT_MIPS_ABIFLAGS = 1879048234
+pkg debug/elf, const SHT_MIPS_ABIFLAGS SectionType
+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 (*Uniform) RGBA64At(int, int) color.RGBA64
+pkg image, method (*YCbCr) RGBA64At(int, int) color.RGBA64
+pkg image, method (Rectangle) 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
+pkg math, const MaxInt ideal-int
+pkg math, const MaxUint = 18446744073709551615
+pkg math, const MaxUint ideal-int
+pkg math, const MinInt = -9223372036854775808
+pkg math, const MinInt ideal-int
+pkg math, const SmallestNonzeroFloat32 = 1.4013e-45  // 1/713623846352979940529142984724747568191373312
+pkg math, const SmallestNonzeroFloat64 = 4.94066e-324  // 1/202402253307310618352495346718917307049556649764142118356901358027430339567995346891960383701437124495187077864316811911389808737385793476867013399940738509921517424276566361364466907742093216341239767678472745068562007483424692698618103355649159556340810056512358769552333414615230502532186327508646006263307707741093494784
+pkg net, method (*ParseError) Temporary() bool
+pkg net, method (*ParseError) Timeout() bool
+pkg net, method (IP) IsPrivate() bool
+pkg net/http, func AllowQuerySemicolons(Handler) Handler
+pkg net/url, method (Values) Has(string) bool
+pkg reflect, func VisibleFields(Type) []StructField
+pkg reflect, method (Method) IsExported() bool
+pkg reflect, method (StructField) IsExported() bool
+pkg reflect, method (Value) CanConvert(Type) bool
+pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete()
+pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (darwin-amd64-cgo), type Handle uintptr
+pkg runtime/cgo (freebsd-386-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (freebsd-386-cgo), method (Handle) Delete()
+pkg runtime/cgo (freebsd-386-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (freebsd-386-cgo), type Handle uintptr
+pkg runtime/cgo (freebsd-amd64-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Delete()
+pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (freebsd-amd64-cgo), type Handle uintptr
+pkg runtime/cgo (freebsd-arm-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Delete()
+pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (freebsd-arm-cgo), type Handle uintptr
+pkg runtime/cgo (linux-386-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (linux-386-cgo), method (Handle) Delete()
+pkg runtime/cgo (linux-386-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (linux-386-cgo), type Handle uintptr
+pkg runtime/cgo (linux-amd64-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (linux-amd64-cgo), method (Handle) Delete()
+pkg runtime/cgo (linux-amd64-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (linux-amd64-cgo), type Handle uintptr
+pkg runtime/cgo (linux-arm-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (linux-arm-cgo), method (Handle) Delete()
+pkg runtime/cgo (linux-arm-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (linux-arm-cgo), type Handle uintptr
+pkg runtime/cgo (netbsd-386-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (netbsd-386-cgo), method (Handle) Delete()
+pkg runtime/cgo (netbsd-386-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (netbsd-386-cgo), type Handle uintptr
+pkg runtime/cgo (netbsd-amd64-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Delete()
+pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (netbsd-amd64-cgo), type Handle uintptr
+pkg runtime/cgo (netbsd-arm-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Delete()
+pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (netbsd-arm-cgo), type Handle uintptr
+pkg runtime/cgo (netbsd-arm64-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Delete()
+pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (netbsd-arm64-cgo), type Handle uintptr
+pkg runtime/cgo (openbsd-386-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (openbsd-386-cgo), method (Handle) Delete()
+pkg runtime/cgo (openbsd-386-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (openbsd-386-cgo), type Handle uintptr
+pkg runtime/cgo (openbsd-amd64-cgo), func NewHandle(interface{}) Handle
+pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Delete()
+pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Value() interface{}
+pkg runtime/cgo (openbsd-amd64-cgo), type Handle uintptr
+pkg strconv, func QuotedPrefix(string) (string, error)
+pkg sync/atomic, method (*Value) CompareAndSwap(interface{}, interface{}) bool
+pkg sync/atomic, method (*Value) Swap(interface{}) interface{}
+pkg syscall (netbsd-386), const SYS_WAIT6 = 481
+pkg syscall (netbsd-386), const SYS_WAIT6 ideal-int
+pkg syscall (netbsd-386), const WEXITED = 32
+pkg syscall (netbsd-386), const WEXITED ideal-int
+pkg syscall (netbsd-386-cgo), const SYS_WAIT6 = 481
+pkg syscall (netbsd-386-cgo), const SYS_WAIT6 ideal-int
+pkg syscall (netbsd-386-cgo), const WEXITED = 32
+pkg syscall (netbsd-386-cgo), const WEXITED ideal-int
+pkg syscall (netbsd-amd64), const SYS_WAIT6 = 481
+pkg syscall (netbsd-amd64), const SYS_WAIT6 ideal-int
+pkg syscall (netbsd-amd64), const WEXITED = 32
+pkg syscall (netbsd-amd64), const WEXITED ideal-int
+pkg syscall (netbsd-amd64-cgo), const SYS_WAIT6 = 481
+pkg syscall (netbsd-amd64-cgo), const SYS_WAIT6 ideal-int
+pkg syscall (netbsd-amd64-cgo), const WEXITED = 32
+pkg syscall (netbsd-amd64-cgo), const WEXITED ideal-int
+pkg syscall (netbsd-arm), const SYS_WAIT6 = 481
+pkg syscall (netbsd-arm), const SYS_WAIT6 ideal-int
+pkg syscall (netbsd-arm), const WEXITED = 32
+pkg syscall (netbsd-arm), const WEXITED ideal-int
+pkg syscall (netbsd-arm-cgo), const SYS_WAIT6 = 481
+pkg syscall (netbsd-arm-cgo), const SYS_WAIT6 ideal-int
+pkg syscall (netbsd-arm-cgo), const WEXITED = 32
+pkg syscall (netbsd-arm-cgo), const WEXITED ideal-int
+pkg syscall (netbsd-arm64), const SYS_WAIT6 = 481
+pkg syscall (netbsd-arm64), const SYS_WAIT6 ideal-int
+pkg syscall (netbsd-arm64), const WEXITED = 32
+pkg syscall (netbsd-arm64), const WEXITED ideal-int
+pkg syscall (netbsd-arm64-cgo), const SYS_WAIT6 = 481
+pkg syscall (netbsd-arm64-cgo), const SYS_WAIT6 ideal-int
+pkg syscall (netbsd-arm64-cgo), const WEXITED = 32
+pkg syscall (netbsd-arm64-cgo), const WEXITED ideal-int
+pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC = 2048
+pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC = 2048
+pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC = 2048
+pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC = 2048
+pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (windows-386), type SysProcAttr struct, AdditionalInheritedHandles []Handle
+pkg syscall (windows-386), type SysProcAttr struct, ParentProcess Handle
+pkg syscall (windows-amd64), type SysProcAttr struct, AdditionalInheritedHandles []Handle
+pkg syscall (windows-amd64), type SysProcAttr struct, ParentProcess Handle
+pkg testing, method (*B) Setenv(string, string)
+pkg testing, method (*T) Setenv(string, string)
+pkg testing, type TB interface, Setenv(string, string)
+pkg text/template/parse, const SkipFuncCheck = 2
+pkg text/template/parse, const SkipFuncCheck Mode
+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) GoString() string
+pkg time, method (Time) IsDST() bool
+pkg time, method (Time) UnixMicro() int64
+pkg time, method (Time) UnixMilli() int64
diff --git a/api/next.txt b/api/next.txt
index 9e99600..e69de29 100644
--- a/api/next.txt
+++ b/api/next.txt
@@ -1,99 +0,0 @@
-pkg compress/lzw, method (*Reader) Close() error
-pkg compress/lzw, method (*Reader) Read([]uint8) (int, error)
-pkg compress/lzw, method (*Reader) Reset(io.Reader, Order, int)
-pkg compress/lzw, method (*Writer) Close() error
-pkg compress/lzw, method (*Writer) Reset(io.Writer, Order, int)
-pkg compress/lzw, method (*Writer) Write([]uint8) (int, error)
-pkg compress/lzw, type Reader struct
-pkg compress/lzw, type Writer struct
-pkg crypto/tls, method (*CertificateRequestInfo) Context() context.Context
-pkg crypto/tls, method (*ClientHelloInfo) Context() context.Context
-pkg crypto/tls, method (*Conn) HandshakeContext(context.Context) error
-pkg debug/elf, const SHT_MIPS_ABIFLAGS = 1879048234
-pkg debug/elf, const SHT_MIPS_ABIFLAGS SectionType
-pkg encoding/csv, method (*Reader) FieldPos(int) (int, int)
-pkg go/ast, method (*FuncDecl) IsMethod() bool
-pkg go/build, type Context struct, ToolTags []string
-pkg go/parser, const SkipObjectResolution = 64
-pkg go/parser, const SkipObjectResolution Mode
-pkg go/types, type Config struct, GoVersion string
-pkg io/fs, func FileInfoToDirEntry(FileInfo) DirEntry
-pkg net, method (*ParseError) Temporary() bool
-pkg net, method (*ParseError) Timeout() bool
-pkg net, method (IP) IsPrivate() bool
-pkg reflect, func VisibleFields(Type) []StructField
-pkg reflect, method (Method) IsExported() bool
-pkg reflect, method (StructField) IsExported() bool
-pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete()
-pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (darwin-amd64-cgo), type Handle uintptr
-pkg runtime/cgo (freebsd-386-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (freebsd-386-cgo), method (Handle) Delete()
-pkg runtime/cgo (freebsd-386-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (freebsd-386-cgo), type Handle uintptr
-pkg runtime/cgo (freebsd-amd64-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Delete()
-pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (freebsd-amd64-cgo), type Handle uintptr
-pkg runtime/cgo (freebsd-arm-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Delete()
-pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (freebsd-arm-cgo), type Handle uintptr
-pkg runtime/cgo (linux-386-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (linux-386-cgo), method (Handle) Delete()
-pkg runtime/cgo (linux-386-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (linux-386-cgo), type Handle uintptr
-pkg runtime/cgo (linux-amd64-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (linux-amd64-cgo), method (Handle) Delete()
-pkg runtime/cgo (linux-amd64-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (linux-amd64-cgo), type Handle uintptr
-pkg runtime/cgo (linux-arm-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (linux-arm-cgo), method (Handle) Delete()
-pkg runtime/cgo (linux-arm-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (linux-arm-cgo), type Handle uintptr
-pkg runtime/cgo (netbsd-386-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (netbsd-386-cgo), method (Handle) Delete()
-pkg runtime/cgo (netbsd-386-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (netbsd-386-cgo), type Handle uintptr
-pkg runtime/cgo (netbsd-amd64-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Delete()
-pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (netbsd-amd64-cgo), type Handle uintptr
-pkg runtime/cgo (netbsd-arm-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Delete()
-pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (netbsd-arm-cgo), type Handle uintptr
-pkg runtime/cgo (netbsd-arm64-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Delete()
-pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (netbsd-arm64-cgo), type Handle uintptr
-pkg runtime/cgo (openbsd-386-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (openbsd-386-cgo), method (Handle) Delete()
-pkg runtime/cgo (openbsd-386-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (openbsd-386-cgo), type Handle uintptr
-pkg runtime/cgo (openbsd-amd64-cgo), func NewHandle(interface{}) Handle
-pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Delete()
-pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Value() interface{}
-pkg runtime/cgo (openbsd-amd64-cgo), type Handle uintptr
-pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC = 2048
-pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC ideal-int
-pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC = 2048
-pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC ideal-int
-pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC = 2048
-pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC ideal-int
-pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC = 2048
-pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC ideal-int
-pkg syscall (windows-386), type SysProcAttr struct, AdditionalInheritedHandles []Handle
-pkg syscall (windows-386), type SysProcAttr struct, ParentProcess Handle
-pkg syscall (windows-amd64), type SysProcAttr struct, AdditionalInheritedHandles []Handle
-pkg syscall (windows-amd64), type SysProcAttr struct, ParentProcess Handle
-pkg testing, method (*B) Setenv(string, string)
-pkg testing, method (*T) Setenv(string, string)
-pkg text/template/parse, const SkipFuncCheck = 2
-pkg text/template/parse, const SkipFuncCheck Mode
-pkg time, func UnixMicro(int64) Time
-pkg time, func UnixMilli(int64) Time
-pkg time, method (*Time) IsDST() bool
-pkg time, method (Time) UnixMicro() int64
-pkg time, method (Time) UnixMilli() int64
diff --git a/codereview.cfg b/codereview.cfg
index 4157a72..b630148 100644
--- a/codereview.cfg
+++ b/codereview.cfg
@@ -1,2 +1 @@
-branch: dev.boringcrypto
-parent-branch: master
+branch: dev.boringcrypto.go1.17
diff --git a/doc/asm.html b/doc/asm.html
index 7173d9b..d578800 100644
--- a/doc/asm.html
+++ b/doc/asm.html
@@ -828,10 +828,6 @@
 <h3 id="arm64">ARM64</h3>
 
 <p>
-The ARM64 port is in an experimental state.
-</p>
-
-<p>
 <code>R18</code> is the "platform register", reserved on the Apple platform.
 To prevent accidental misuse, the register is named <code>R18_PLATFORM</code>.
 <code>R27</code> and <code>R28</code> are reserved by the compiler and linker.
diff --git a/doc/go1.17.html b/doc/go1.17.html
index cf856a1..48811e6 100644
--- a/doc/go1.17.html
+++ b/doc/go1.17.html
@@ -25,12 +25,54 @@
 
 <h2 id="language">Changes to the language</h2>
 
-<p><!-- CL 216424 -->
-  TODO: <a href="https://golang.org/cl/216424">https://golang.org/cl/216424</a>: allow conversion from slice to array ptr
+<p>
+  Go 1.17 includes three small enhancements to the language.
 </p>
 
-<p><!-- CL 312212 -->
-  TODO: <a href="https://golang.org/cl/312212">https://golang.org/cl/312212</a>: add unsafe.Add and unsafe.Slice
+<ul>
+  <li><!-- CL 216424; issue 395 -->
+    <a href="/ref/spec#Conversions_from_slice_to_array_pointer">Conversions
+    from slice to array pointer</a>: An expression <code>s</code> of
+    type <code>[]T</code> may now be converted to array pointer type
+    <code>*[N]T</code>. If <code>a</code> is the result of such a
+    conversion, then corresponding indices that are in range refer to
+    the same underlying elements: <code>&amp;a[i] == &amp;s[i]</code>
+    for <code>0 &lt;= i &lt; N</code>. The conversion panics if
+    <code>len(s)</code> is less than <code>N</code>.
+  </li>
+
+  <li><!-- CL 312212; issue 40481 -->
+    <a href="/pkg/unsafe#Add"><code>unsafe.Add</code></a>:
+    <code>unsafe.Add(ptr, len)</code> adds <code>len</code>
+    to <code>ptr</code> and returns the updated pointer
+    <code>unsafe.Pointer(uintptr(ptr) + uintptr(len))</code>.
+  </li>
+
+  <li><!-- CL 312212; issue 19367 -->
+    <a href="/pkg/unsafe#Slice"><code>unsafe.Slice</code></a>:
+    For expression <code>ptr</code> of type <code>*T</code>,
+    <code>unsafe.Slice(ptr, len)</code> returns a slice of
+    type <code>[]T</code> whose underlying array starts
+    at <code>ptr</code> and whose length and capacity
+    are <code>len</code>.
+  </li>
+</ul>
+
+<p>
+  The package unsafe enhancements were added to simplify writing code that conforms
+  to <code>unsafe.Pointer</code>'s <a href="/pkg/unsafe/#Pointer">safety
+  rules</a>, but the rules remain unchanged. In particular, existing
+  programs that correctly use <code>unsafe.Pointer</code> remain
+  valid, and new programs must still follow the rules when
+  using <code>unsafe.Add</code> or <code>unsafe.Slice</code>.
+</p>
+
+
+<p>
+  Note that the new conversion from slice to array pointer is the
+  first case in which a type conversion can panic at run time.
+  Analysis tools that assume type conversions can never panic
+  should be updated to consider this possibility.
 </p>
 
 <h2 id="ports">Ports</h2>
@@ -43,16 +85,53 @@
   for previous versions has been discontinued.
 </p>
 
-<p>
-  TODO: complete the Ports section
+<h3 id="windows">Windows</h3>
+
+<p><!-- golang.org/issue/36439 -->
+  Go 1.17 adds support of 64-bit ARM architecture on Windows (the
+  <code>windows/arm64</code> port). This port supports cgo.
+</p>
+
+<h3 id="openbsd">OpenBSD</h3>
+
+<p><!-- golang.org/issue/43005 -->
+  The 64-bit MIPS architecture on OpenBSD (the <code>openbsd/mips64</code>
+  port) now supports cgo.
+</p>
+
+<p><!-- golang.org/issue/36435 -->
+  In Go 1.16, on the 64-bit x86 and 64-bit ARM architectures on
+  OpenBSD (the <code>openbsd/amd64</code> and <code>openbsd/arm64</code>
+  ports) system calls are made through <code>libc</code>, instead
+  of directly using machine instructions. In Go 1.17, this is also
+  done on the 32-bit x86 and 32-bit ARM architectures on OpenBSD
+  (the <code>openbsd/386</code> and <code>openbsd/arm</code> ports).
+  This ensures compatibility with OpenBSD 6.9 onwards, which require
+  system calls to be made through <code>libc</code> for non-static
+  Go binaries.
+</p>
+
+<h3 id="arm64">ARM64</h3>
+
+<p><!-- CL 288814 -->
+  Go programs now maintain stack frame pointers on the 64-bit ARM
+  architecture on all operating systems. Previously it maintained
+  stack frame pointers only on Linux, macOS, and iOS.
+</p>
+
+<h3 id="loong64">loong64 GOARCH value reserved</h3>
+
+<p><!-- CL 333909 -->
+  The main Go compiler does not yet support the LoongArch
+  architecture, but we've reserved the <code>GOARCH</code> value
+  "<code>loong64</code>".
+  This means that Go files named <code>*_loong64.go</code> will now
+  be <a href="/pkg/go/build/#hdr-Build_Constraints">ignored by Go
+  tools</a> except when that GOARCH value is being used.
 </p>
 
 <h2 id="tools">Tools</h2>
 
-<p>
-  TODO: complete the Tools section
-</p>
-
 <h3 id="go-command">Go command</h3>
 
 <h4 id="lazy-loading">Lazy module loading</h4>
@@ -60,7 +139,7 @@
 <p><!-- golang.org/issue/36460 -->
   If a module specifies <code>go</code> <code>1.17</code> or higher in its
   <code>go.mod</code> file, its transitive requirements are now loaded lazily,
-  avoding the need to download or read <code>go.mod</code> files for
+  avoiding the need to download or read <code>go.mod</code> files for
   otherwise-irrelevant dependencies. To support lazy loading, in Go 1.17 modules
   the <code>go</code> command maintains <em>explicit</em> requirements in
   the <code>go.mod</code> file for every dependency that provides any package
@@ -70,8 +149,17 @@
   <!-- TODO(bcmills): replace the design-doc link with proper documentation. -->
 </p>
 
-<p><!-- golang.org/issue/45094 --> To facilitate the upgrade to lazy loading,
-  the <code>go</code> <code>mod</code> <code>tidy</code> subcommand now supports
+<p><!-- golang.org/issue/45965 -->
+  Because the number of additional explicit requirements in the go.mod file may
+  be substantial, in a Go 1.17 module the newly-added requirements
+  on <em>indirect</em> dependencies are maintained in a
+  separate <code>require</code> block from the block containing direct
+  dependencies.
+</p>
+
+<p><!-- golang.org/issue/45094 -->
+  To facilitate the upgrade to lazy loading, the
+  <code>go</code> <code>mod</code> <code>tidy</code> subcommand now supports
   a <code>-go</code> flag to set or change the <code>go</code> version in
   the <code>go.mod</code> file. To enable lazy loading for an existing module
   without changing the selected versions of its dependencies, run:
@@ -81,6 +169,42 @@
   go mod tidy -go=1.17
 </pre>
 
+<p><!-- golang.org/issue/46141 -->
+  By default, <code>go</code> <code>mod</code> <code>tidy</code> 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
+  specifies <code>go</code> <code>1.17</code>), and preserves
+  the <code>go.sum</code> entries needed by that release even for dependencies
+  that are not normally needed by other commands.
+</p>
+
+<p>
+  The <code>-compat</code> flag allows that version to be overridden to support
+  older (or only newer) versions, up to the version specified by
+  the <code>go</code> directive in the <code>go.mod</code> file. To tidy
+  a <code>go</code> <code>1.17</code> module for Go 1.17 only, without saving
+  checksums for (or checking for consistency with) Go 1.16:
+</p>
+
+<pre>
+  go mod tidy -compat=1.17
+</pre>
+
+<p>
+  Note that even if the main module is tidied with <code>-compat=1.17</code>,
+  users who <code>require</code> the module from a
+  <code>go</code> <code>1.16</code> or earlier module will still be able to
+  use it, provided that the packages use only compatible language and library
+  features.
+</p>
+
+<p><!-- golang.org/issue/46366 -->
+  The <code>go</code> <code>mod</code> <code>graph</code> subcommand also
+  supports the <code>-go</code> flag, which causes it to report the graph as
+  seen by the indicated Go version, showing dependencies that may otherwise be
+  pruned out by lazy loading.
+</p>
+
 <h4 id="module-deprecation-comments">Module deprecation comments</h4>
 
 <p><!-- golang.org/issue/40357 -->
@@ -108,6 +232,16 @@
   <code>environment</code> for details.
 </p>
 
+<p><!-- golang.org/issue/43684 -->
+  <code>go</code> <code>get</code> prints a deprecation warning when installing
+  commands outside the main module (without the <code>-d</code> flag).
+  <code>go</code> <code>install</code> <code>cmd@version</code> should be used
+  instead to install a command at a specific version, using a suffix like
+  <code>@latest</code> or <code>@v1.2.3</code>. In Go 1.18, the <code>-d</code>
+  flag will always be enabled, and <code>go</code> <code>get</code> will only
+  be used to change dependencies in <code>go.mod</code>.
+</p>
+
 <h4 id="missing-go-directive"><code>go.mod</code> files missing <code>go</code> directives</h4>
 
 <p><!-- golang.org/issue/44976 -->
@@ -161,72 +295,181 @@
   password-protected SSH keys.
 </p>
 
-<p><!-- CL 249759 -->
-  TODO: <a href="https://golang.org/cl/249759">https://golang.org/cl/249759</a>: cmd/cover: replace code using optimized golang.org/x/tools/cover
+<h4 id="go-mod-download"><code>go</code> <code>mod</code> <code>download</code></h4>
+
+<p><!-- golang.org/issue/45332 -->
+  When <code>go</code> <code>mod</code> <code>download</code> is invoked without
+  arguments, it will no longer save sums for downloaded module content to
+  <code>go.sum</code>. It may still make changes to <code>go.mod</code> and
+  <code>go.sum</code> needed to load the build list. This is the same as the
+  behavior in Go 1.15. To save sums for all modules, use <code>go</code>
+  <code>mod</code> <code>download</code> <code>all</code>.
+</p>
+
+<h4 id="build-lines"><code>//go:build</code> lines</h4>
+
+<p>
+  The <code>go</code> command now understands <code>//go:build</code> lines
+  and prefers them over <code>// +build</code> lines. The new syntax uses
+  boolean expressions, just like Go, and should be less error-prone.
+  As of this release, the new syntax is fully supported, and all Go files
+  should be updated to have both forms with the same meaning. To aid in
+  migration, <a href="#gofmt"><code>gofmt</code></a> now automatically
+  synchronizes the two forms. For more details on the syntax and migration plan,
+  see
+  <a href="https://golang.org/design/draft-gobuild">https://golang.org/design/draft-gobuild</a>.
+</p>
+
+<h4 id="go run"><code>go</code> <code>run</code></h4>
+
+<p><!-- golang.org/issue/42088 -->
+  <code>go</code> <code>run</code> now accepts arguments with version suffixes
+  (for example, <code>go</code> <code>run</code>
+  <code>example.com/cmd@v1.0.0</code>).  This causes <code>go</code>
+  <code>run</code> to build and run packages in module-aware mode, ignoring the
+  <code>go.mod</code> file in the current directory or any parent directory, if
+  there is one. This is useful for running executables without installing them or
+  without changing dependencies of the current module.
+</p>
+
+<h3 id="gofmt">Gofmt</h3>
+
+<p>
+  <code>gofmt</code> (and <code>go</code> <code>fmt</code>) now synchronizes
+  <code>//go:build</code> lines with <code>// +build</code> lines. If a file
+  only has <code>// +build</code> lines, they will be moved to the appropriate
+  location in the file, and matching <code>//go:build</code> lines will be
+  added. Otherwise, <code>// +build</code> lines will be overwritten based on
+  any existing <code>//go:build</code> lines. For more information, see
+  <a href="https://golang.org/design/draft-gobuild">https://golang.org/design/draft-gobuild</a>.
 </p>
 
 <h3 id="vet">Vet</h3>
 
+<h4 id="vet-buildtags">New warning for mismatched <code>//go:build</code> and <code>// +build</code> lines</h4>
+
+<p><!-- CL 240609 -->
+  The <code>vet</code> tool now verifies that <code>//go:build</code> and
+  <code>// +build</code> lines are in the correct part of the file and
+  synchronized with each other. If they aren't,
+  <a href="#gofmt"><code>gofmt</code></a> can be used to fix them. For more
+  information, see
+  <a href="https://golang.org/design/draft-gobuild">https://golang.org/design/draft-gobuild</a>.
+</p>
+
+<h4 id="vet-sigchanyzer">New warning for calling <code>signal.Notify</code> on unbuffered channels</h4>
+
 <p><!-- CL 299532 -->
-  TODO: <a href="https://golang.org/cl/299532">https://golang.org/cl/299532</a>: cmd/vet: bring in sigchanyzer to report unbuffered channels to signal.Notify
+  The vet tool now warns about calls to <a href="/pkg/os/signal/#Notify">signal.Notify</a>
+  with incoming signals being sent to an unbuffered channel. Using an unbuffered channel
+  risks missing signals sent on them as <code>signal.Notify</code> does not block when
+  sending to a channel. For example:
 </p>
 
+<pre>
+c := make(chan os.Signal)
+// signals are sent on c before the channel is read from.
+// This signal may be dropped as c is unbuffered.
+signal.Notify(c, os.Interrupt)
+</pre>
+
 <p>
-  TODO: complete the Vet section
+  Users of <code>signal.Notify</code> should use channels with sufficient buffer space to keep up with the
+  expected signal rate.
 </p>
 
-<h2 id="runtime">Runtime</h2>
+<h4 id="vet-error-stdmethods">New warnings for Is, As and Unwrap methods</h4>
 
-<p><!-- CL 304470 -->
-  TODO: <a href="https://golang.org/cl/304470">https://golang.org/cl/304470</a>: cmd/compile, runtime: add metadata for argument printing in traceback
+<p><!-- CL 321389 -->
+  The vet tool now warns about methods named <code>As</code>, <code>Is</code> or <code>Unwrap</code>
+  on types implementing the <code>error</code> interface that have a different signature than the
+  one expected by the <code>errors</code> package. The <code>errors.{As,Is,Unwrap}</code> functions
+  expect such methods to implement either <code>Is(error)</code> <code>bool</code>,
+  <code>As(interface{})</code> <code>bool</code>, or <code>Unwrap()</code> <code>error</code>
+  respectively. The functions <code>errors.{As,Is,Unwrap}</code> will ignore methods with the same
+  names but a different signature. For example:
 </p>
 
-<p>
-  TODO: complete the Runtime section
+<pre>
+type MyError struct { hint string }
+func (m MyError) Error() string { ... } // MyError implements error.
+func (MyError) Is(target interface{}) bool { ... } // target is interface{} instead of error.
+func Foo() bool {
+	x, y := MyError{"A"}, MyError{"B"}
+	return errors.Is(x, y) // returns false as x != y and MyError does not have an `Is(error) bool` function.
+}
+</pre>
+
+<h3 id="cover">Cover</h3>
+
+<p><!-- CL 249759 -->
+  The <code>cover</code> tool now uses an optimized parser
+  from <code>golang.org/x/tools/cover</code>, which may be noticeably faster
+  when parsing large coverage profiles.
 </p>
 
 <h2 id="compiler">Compiler</h2>
 
-<p>
-  TODO: complete the Compiler section, or delete if not needed
+<p><!-- golang.org/issue/40724 -->
+  Go 1.17 implements a new way of passing function arguments and results using
+  registers instead of the stack.
+  Benchmarks for a representative set of Go packages and programs show
+  performance improvements of about 5%, and a typical reduction in
+  binary size of about 2%.
+  This is currently enabled for Linux, macOS, and Windows on the
+  64-bit x86 architecture (the <code>linux/amd64</code>,
+  <code>darwin/amd64</code>, and <code>windows/amd64</code> ports).
 </p>
 
-<h2 id="linker">Linker</h2>
-
 <p>
-  TODO: complete the Linker section, or delete if not needed
+  This change does not affect the functionality of any safe Go code
+  and is designed to have no impact on most assembly code.
+  It may affect code that violates
+  the <a href="/pkg/unsafe#Pointer"><code>unsafe.Pointer</code></a>
+  rules when accessing function arguments, or that depends on
+  undocumented behavior involving comparing function code pointers.
+  To maintain compatibility with existing assembly functions, the
+  compiler generates adapter functions that convert between the new
+  register-based calling convention and the previous stack-based
+  calling convention.
+  These adapters are typically invisible to users, except that taking
+  the address of a Go function in assembly code or taking the address
+  of an assembly function in Go code
+  using <code>reflect.ValueOf(fn).Pointer()</code>
+  or <code>unsafe.Pointer</code> will now return the address of the
+  adapter.
+  Code that depends on the value of these code pointers may no longer
+  behave as expected.
+  Adapters also may cause a very small performance overhead in two
+  cases: calling an assembly function indirectly from Go via
+  a <code>func</code> value, and calling Go functions from assembly.
+</p>
+
+<p><!-- CL 304470 -->
+  The format of stack traces from the runtime (printed when an uncaught panic
+  occurs, or when <code>runtime.Stack</code> is called) is improved. Previously,
+  the function arguments were printed as hexadecimal words based on the memory
+  layout. Now each argument in the source code is printed separately, separated
+  by commas. Aggregate-typed (struct, array, string, slice, interface, and complex)
+  arguments are delimited by curly braces. A caveat is that the value of an
+  argument that only lives in a register and is not stored to memory may be
+  inaccurate. Function return values (which were usually inaccurate) are no longer
+  printed.
+</p>
+
+<p><!-- CL 283112, golang.org/issue/28727 -->
+  Functions containing closures can now be inlined.
+  One effect of this change is that a function with a closure may
+  produce a distinct closure code pointer for each place that the
+  function is inlined.
+  Go function values are not directly comparable, but this change
+  could reveal bugs in code that uses <code>reflect</code>
+  or <code>unsafe.Pointer</code> to bypass this language restriction
+  and compare functions by code pointer.
 </p>
 
 <h2 id="library">Core library</h2>
 
-<p>
-  TODO: complete the Core library section
-</p>
-
-<h3 id="crypto/tls"><a href="/pkg/crypto/tls">crypto/tls</a></h3>
-
-<p><!-- CL 295370 -->
-  <a href="/pkg/crypto/tls#Conn.HandshakeContext">(*Conn).HandshakeContext</a> was added to
-  allow the user to control cancellation of an in-progress TLS Handshake.
-  The context provided is propagated into the
-  <a href="/pkg/crypto/tls#ClientHelloInfo">ClientHelloInfo</a>
-  and <a href="/pkg/crypto/tls#CertificateRequestInfo">CertificateRequestInfo</a>
-  structs and accessible through the new
-  <a href="/pkg/crypto/tls#ClientHelloInfo.Context">(*ClientHelloInfo).Context</a>
-  and
-  <a href="/pkg/crypto/tls#CertificateRequestInfo.Context">
-      (*CertificateRequestInfo).Context
-  </a> methods respectively. Canceling the context after the handshake has finished
-  has no effect.
-</p>
-
-<p><!-- CL 289209 -->
-  When <a href="/pkg/crypto/tls#Config">Config.NextProtos</a> 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 <code>no_application_protocol</code> alert, as required by RFC 7301.
-</p>
-
 <h3 id="runtime/cgo"><a href="/pkg/runtime/cgo">Cgo</a></h3>
 
 <p>
@@ -236,6 +479,67 @@
   <a href="/pkg/runtime/cgo#Handle">runtime/cgo.Handle</a> for more information.
 </p>
 
+<h3 id="semicolons">URL query parsing</h3>
+<!-- CL 325697, CL 326309 -->
+
+<p>
+  The <code>net/url</code> and <code>net/http</code> packages used to accept
+  <code>";"</code> (semicolon) as a setting separator in URL queries, in
+  addition to <code>"&"</code> (ampersand). Now, settings with non-percent-encoded
+  semicolons are rejected and <code>net/http</code> servers will log a warning to
+  <a href="/pkg/net/http#Server.ErrorLog"><code>Server.ErrorLog</code></a>
+  when encountering one in a request URL.
+</p>
+
+<p>
+  For example, before Go 1.17 the <a href="/pkg/net/url#URL.Query"><code>Query</code></a>
+  method of the URL <code>example?a=1;b=2&c=3</code> would have returned
+  <code>map[a:[1] b:[2] c:[3]]</code>, while now it returns <code>map[c:[3]]</code>.
+</p>
+
+<p>
+  When encountering such a query string,
+  <a href="/pkg/net/url#URL.Query"><code>URL.Query</code></a>
+  and
+  <a href="/pkg/net/http#Request.FormValue"><code>Request.FormValue</code></a>
+  ignore any settings that contain a semicolon,
+  <a href="/pkg/net/url#ParseQuery"><code>ParseQuery</code></a>
+  returns the remaining settings and an error, and
+  <a href="/pkg/net/http#Request.ParseForm"><code>Request.ParseForm</code></a>
+  and
+  <a href="/pkg/net/http#Request.ParseMultipartForm"><code>Request.ParseMultipartForm</code></a>
+  return an error but still set <code>Request</code> fields based on the
+  remaining settings.
+</p>
+
+<p>
+  <code>net/http</code> users can restore the original behavior by using the new
+  <a href="/pkg/net/http#AllowQuerySemicolons"><code>AllowQuerySemicolons</code></a>
+  handler wrapper. This will also suppress the <code>ErrorLog</code> warning.
+  Note that accepting semicolons as query separators can lead to security issues
+  if different systems interpret cache keys differently.
+  See <a href="https://golang.org/issue/25192">issue 25192</a> for more information.
+</p>
+
+<h3 id="ALPN">TLS strict ALPN</h3>
+<!-- CL 289209, CL 325432 -->
+
+<p>
+  When <a href="/pkg/crypto/tls#Config.NextProtos"><code>Config.NextProtos</code></a>
+  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
+  <code>no_application_protocol</code> alert, as required by RFC 7301. This
+  helps mitigate <a href="https://alpaca-attack.com/">the ALPACA cross-protocol attack</a>.
+</p>
+
+<p>
+  As an exception, when the value <code>"h2"</code> is included in the server's
+  <code>Config.NextProtos</code>, HTTP/1.1 clients will be allowed to connect as
+  if they didn't support ALPN.
+  See <a href="https://golang.org/issue/46310">issue 46310</a> for more information.
+</p>
+
 <h3 id="minor_library_changes">Minor changes to the library</h3>
 
 <p>
@@ -247,7 +551,7 @@
 <dl id="archive/zip"><dt><a href="/pkg/archive/zip/">archive/zip</a></dt>
   <dd>
     <p><!-- CL 312310 -->
-      TODO: <a href="https://golang.org/cl/312310">https://golang.org/cl/312310</a>: add File.OpenRaw, Writer.CreateRaw, Writer.Copy
+      The new methods <a href="/pkg/archive/zip#File.OpenRaw"><code>File.OpenRaw</code></a>, <a href="/pkg/archive/zip#Writer.CreateRaw"><code>Writer.CreateRaw</code></a>, <a href="/pkg/archive/zip#Writer.Copy"><code>Writer.Copy</code></a> provide support for cases where performance is a primary concern.
     </p>
   </dd>
 </dl><!-- archive/zip -->
@@ -275,35 +579,170 @@
 <dl id="compress/lzw"><dt><a href="/pkg/compress/lzw/">compress/lzw</a></dt>
   <dd>
     <p><!-- CL 273667 -->
-      The new
-      <a href="/pkg/compress/lzw/#Reader.Reset"><code>Reader.Reset</code></a>
-      and
-      <a href="/pkg/compress/lzw/#Writer.Reset"><code>Writer.Reset</code></a>
-      methods allow reuse of a <code>Reader</code> or <code>Writer</code>.
+      The <a href="/pkg/compress/lzw/#NewReader"><code>NewReader</code></a>
+      function is guaranteed to return a value of the new
+      type <a href="/pkg/compress/lzw/#Reader"><code>Reader</code></a>,
+      and similarly <a href="/pkg/compress/lzw/#NewWriter"><code>NewWriter</code></a>
+      is guaranteed to return a value of the new
+      type <a href="/pkg/compress/lzw/#Writer"><code>Writer</code></a>.
+      These new types both implement a <code>Reset</code> method
+      (<a href="/pkg/compress/lzw/#Reader.Reset"><code>Reader.Reset</code></a>,
+      <a href="/pkg/compress/lzw/#Writer.Reset"><code>Writer.Reset</code></a>)
+      that allows reuse of the <code>Reader</code> or <code>Writer</code>.
     </p>
   </dd>
 </dl><!-- compress/lzw -->
 
-<dl id="crypto/rsa"><dt><a href="/pkg/crypto/rsa/">crypto/rsa</a></dt>
+<dl id="crypto/ed25519"><dt><a href="/pkg/crypto/ed25519/">crypto/ed25519</a></dt>
   <dd>
-    <p><!-- CL 302230 -->
-      TODO: <a href="https://golang.org/cl/302230">https://golang.org/cl/302230</a>: fix salt length calculation with PSSSaltLengthAuto
+    <p><!-- CL 276272 -->
+      The <code>crypto/ed25519</code> package has been rewritten, and all
+      operations are now approximately twice as fast on amd64 and arm64.
+      The observable behavior has not otherwise changed.
     </p>
   </dd>
-</dl><!-- crypto/rsa -->
+</dl><!-- crypto/ed25519 -->
+
+<dl id="crypto/elliptic"><dt><a href="/pkg/crypto/elliptic/">crypto/elliptic</a></dt>
+  <dd>
+    <p><!-- CL 233939 -->
+      <a href="/pkg/crypto/elliptic#CurveParams"><code>CurveParams</code></a>
+      methods now automatically invoke faster and safer dedicated
+      implementations for known curves (P-224, P-256, and P-521) when
+      available. Note that this is a best-effort approach and applications
+      should avoid using the generic, not constant-time <code>CurveParams</code>
+      methods and instead use dedicated
+      <a href="/pkg/crypto/elliptic#Curve"><code>Curve</code></a> implementations
+      such as <a href="/pkg/crypto/elliptic#P256"><code>P256</code></a>.
+    </p>
+
+    <p><!-- CL 315271, CL 315274 -->
+      The <a href="/pkg/crypto/elliptic#P521"><code>P521</code></a> curve
+      implementation has been rewritten using code generated by the
+      <a href="https://github.com/mit-plv/fiat-crypto">fiat-crypto project</a>,
+      which is based on a formally-verified model of the arithmetic
+      operations. It is now constant-time and three times faster on amd64 and
+      arm64. The observable behavior has not otherwise changed.
+    </p>
+  </dd>
+</dl><!-- crypto/elliptic -->
+
+<dl id="crypto/rand"><dt><a href="/pkg/crypto/rand/">crypto/rand</a></dt>
+  <dd>
+    <p><!-- CL 302489, CL 299134, CL 269999 -->
+      The <code>crypto/rand</code> package now uses the <code>getentropy</code>
+      syscall on macOS and the <code>getrandom</code> syscall on Solaris,
+      Illumos, and DragonFlyBSD.
+    </p>
+  </dd>
+</dl><!-- crypto/rand -->
+
+<dl id="crypto/tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
+  <dd>
+    <p><!-- CL 295370 -->
+      The new <a href="/pkg/crypto/tls#Conn.HandshakeContext"><code>Conn.HandshakeContext</code></a>
+      method allows the user to control cancellation of an in-progress TLS
+      handshake. The provided context is accessible from various callbacks through the new
+      <a href="/pkg/crypto/tls#ClientHelloInfo.Context"><code>ClientHelloInfo.Context</code></a> and
+      <a href="/pkg/crypto/tls#CertificateRequestInfo.Context"><code>CertificateRequestInfo.Context</code></a>
+      methods. Canceling the context after the handshake has finished has no effect.
+    </p>
+
+    <p><!-- CL 314609 -->
+      Cipher suite ordering is now handled entirely by the
+      <code>crypto/tls</code> package. Currently, cipher suites are sorted based
+      on their security, performance, and hardware support taking into account
+      both the local and peer's hardware. The order of the
+      <a href="/pkg/crypto/tls#Config.CipherSuites"><code>Config.CipherSuites</code></a>
+      field is now ignored, as well as the
+      <a href="/pkg/crypto/tls#Config.PreferServerCipherSuites"><code>Config.PreferServerCipherSuites</code></a>
+      field. Note that <code>Config.CipherSuites</code> still allows
+      applications to choose what TLS 1.0–1.2 cipher suites to enable.
+    </p>
+
+    <p>
+      The 3DES cipher suites have been moved to
+      <a href="/pkg/crypto/tls#InsecureCipherSuites"><code>InsecureCipherSuites</code></a>
+      due to <a href="https://sweet32.info/">fundamental block size-related
+      weakness</a>. They are still enabled by default but only as a last resort,
+      thanks to the cipher suite ordering change above.
+    </p>
+
+    <p><!-- golang.org/issue/45428 -->
+      Beginning in the next release, Go 1.18, the
+      <a href="/pkg/crypto/tls/#Config.MinVersion"><code>Config.MinVersion</code></a>
+      for <code>crypto/tls</code> 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 <code>Config.MinVersion</code>.
+      This will not affect <code>crypto/tls</code> servers.
+    </p>
+  </dd>
+</dl><!-- crypto/tls -->
+
+<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
+  <dd>
+    <p><!-- CL 224157 -->
+      <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
+      now returns an error if the provided private key doesn't match the
+      parent's public key, if any. The resulting certificate would have failed
+      to verify.
+    </p>
+
+    <p><!-- CL 315209 -->
+      The temporary <code>GODEBUG=x509ignoreCN=0</code> flag has been removed.
+    </p>
+
+    <p><!-- CL 274234 -->
+      <a href="/pkg/crypto/x509/#ParseCertificate"><code>ParseCertificate</code></a>
+      has been rewritten, and now consumes ~70% fewer resources. The observable
+      behavior has not otherwise changed, except for error messages.
+    </p>
+
+    <p><!-- CL 321190 -->
+      On BSD systems, <code>/etc/ssl/certs</code> is now searched for trusted
+      roots. This adds support for the new system trusted certificate store in
+      FreeBSD 12.2+.
+    </p>
+
+    <p><!-- golang.org/issue/41682 -->
+      Beginning in the next release, Go 1.18, <code>crypto/x509</code> will
+      reject certificates signed with the SHA-1 hash function. This doesn't
+      apply to self-signed root certificates. Practical attacks against SHA-1
+      <a href="https://shattered.io/">have been demonstrated in 2017</a> and publicly
+      trusted Certificate Authorities have not issued SHA-1 certificates since 2015.
+    </p>
+  </dd>
+</dl><!-- crypto/x509 -->
 
 <dl id="database/sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
   <dd>
     <p><!-- CL 258360 -->
-      TODO: <a href="https://golang.org/cl/258360">https://golang.org/cl/258360</a>: close driver.Connector if it implements io.Closer
+      The <a href="/pkg/database/sql/#DB.Close"><code>DB.Close</code></a> method now closes
+      the <code>connector</code> field if the type in this field implements the
+      <a href="/pkg/io/#Closer"><code>io.Closer</code></a> interface.
     </p>
 
     <p><!-- CL 311572 -->
-      TODO: <a href="https://golang.org/cl/311572">https://golang.org/cl/311572</a>: add NullInt16 and NullByte
+      The new
+      <a href="/pkg/database/sql/#NullInt16"><code>NullInt16</code></a> 
+      and 
+      <a href="/pkg/database/sql/#NullByte"><code>NullByte</code></a> 
+      structs represent the int16 and byte values that may be null. These can be used as
+      destinations of the <a href="/pkg/database/sql/#Scan"><code>Scan</code></a> method,
+      similar to NullString.
     </p>
   </dd>
 </dl><!-- database/sql -->
 
+<dl id="debug/elf"><dt><a href="/pkg/debug/elf/">debug/elf</a></dt>
+  <dd>
+    <p><!-- CL 239217 -->
+      The <a href="/pkg/debug/elf/#SHT_MIPS_ABIFLAGS"><code>SHT_MIPS_ABIFLAGS</code></a>
+      constant has been added.
+    </p>
+  </dd>
+</dl><!-- debug/elf -->
+
 <dl id="encoding/binary"><dt><a href="/pkg/encoding/binary/">encoding/binary</a></dt>
   <dd>
     <p><!-- CL 299531 -->
@@ -315,18 +754,96 @@
   </dd>
 </dl><!-- encoding/binary -->
 
+<dl id="encoding/csv"><dt><a href="/pkg/encoding/csv/">encoding/csv</a></dt>
+  <dd>
+    <p><!-- CL 291290 -->
+      The new
+      <a href="/pkg/encoding/csv/#Reader.FieldPos"><code>Reader.FieldPos</code></a>
+      method returns the line and column corresponding to the start of
+      a given field in the record most recently returned by
+      <a href="/pkg/encoding/csv/#Reader.Read"><code>Read</code></a>.
+    </p>
+  </dd>
+</dl><!-- encoding/csv -->
+
+<dl id="encoding/xml"><dt><a href="/pkg/encoding/xml/">encoding/xml</a></dt>
+  <dd>
+    <p><!-- CL 277893 -->
+      When a comment appears within a
+      <a href="/pkg/encoding/xml/#Directive"><code>Directive</code></a>, it is now replaced
+      with a single space instead of being completely elided.
+    </p>
+
+    <p>
+      Invalid element or attribute names with leading, trailing, or multiple
+      colons are now stored unmodified into the
+      <a href="/pkg/encoding/xml/#Name"><code>Name.Local</code></a> field.
+    </p>
+  </dd>
+</dl><!-- encoding/xml -->
+
 <dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt>
   <dd>
     <p><!-- CL 271788 -->
-      TODO: <a href="https://golang.org/cl/271788">https://golang.org/cl/271788</a>: panic if flag name begins with - or contains =
+      Flag declarations now panic if an invalid name is specified.
     </p>
   </dd>
 </dl><!-- flag -->
 
+<dl id="go/build"><dt><a href="/pkg/go/build/">go/build</a></dt>
+  <dd>
+    <p><!-- CL 310732 -->
+      The new
+      <a href="/pkg/go/build/#Context.ToolTags"><code>Context.ToolTags</code></a>
+      field holds the build tags appropriate to the current Go
+      toolchain configuration.
+    </p>
+  </dd>
+</dl><!-- go/build -->
+
+<dl id="go/format"><dt><a href="/pkg/go/format/">go/format</a></dt>
+  <dd>
+    <p>
+      The <a href="/pkg/go/format/#Source"><code>Source</code></a> and
+      <a href="/pkg/go/format/#Node"><code>Node</code></a> functions now
+      synchronize <code>//go:build</code> lines with <code>// +build</code>
+      lines. If a file only has <code>// +build</code> lines, they will be
+      moved to the appropriate location in the file, and matching
+      <code>//go:build</code> lines will be added. Otherwise,
+      <code>// +build</code> lines will be overwritten based on any existing
+      <code>//go:build</code> lines. For more information, see
+      <a href="https://golang.org/design/draft-gobuild">https://golang.org/design/draft-gobuild</a>.
+    </p>
+  </dd>
+</dl><!-- go/format -->
+
+<dl id="go/parser"><dt><a href="/pkg/go/parser/">go/parser</a></dt>
+  <dd>
+    <p><!-- CL 306149 -->
+      The new <a href="/pkg/go/parser/#SkipObjectResolution"><code>SkipObjectResolution</code></a>
+      <code>Mode</code> value instructs the parser not to resolve identifiers to
+      their declaration. This may improve parsing speed.
+    </p>
+  </dd>
+</dl><!-- go/parser -->
+
+<dl id="image"><dt><a href="/pkg/image/">image</a></dt>
+  <dd>
+    <p><!-- CL 311129 -->
+      The concrete image types (<code>RGBA</code>, <code>Gray16</code> and so on)
+      now implement a new <a href="/pkg/image/#RGBA64Image"><code>RGBA64Image</code></a>
+      interface. The concrete types that previously implemented
+      <a href="/pkg/image/draw/#Image"><code>draw.Image</code></a> now also implement
+      <a href="/pkg/image/draw/#RGBA64Image"><code>draw.RGBA64Image</code></a>, a
+      new interface in the <code>image/draw</code> package.
+    </p>
+  </dd>
+</dl><!-- image -->
+
 <dl id="io/fs"><dt><a href="/pkg/io/fs/">io/fs</a></dt>
   <dd>
     <p><!-- CL 293649 -->
-      TODO: <a href="https://golang.org/cl/293649">https://golang.org/cl/293649</a>: implement FileInfoToDirEntry
+      The new <a href="/pkg/io/fs/#FileInfoToDirEntry"><code>FileInfoToDirEntry</code></a> function converts a <code>FileInfo</code> to a <code>DirEntry</code>.
     </p>
   </dd>
 </dl><!-- io/fs -->
@@ -334,7 +851,9 @@
 <dl id="math"><dt><a href="/pkg/math/">math</a></dt>
   <dd>
     <p><!-- CL 247058 -->
-      TODO: <a href="https://golang.org/cl/247058">https://golang.org/cl/247058</a>: add MaxUint, MinInt, MaxInt
+      The math package now defines three more constants: <code>MaxUint</code>, <code>MaxInt</code> and <code>MinInt</code>.
+      For 32-bit systems their values are <code>2^32 - 1</code>, <code>2^31 - 1</code> and <code>-2^31</code>, respectively.
+      For 64-bit systems their values are <code>2^64 - 1</code>, <code>2^63 - 1</code> and <code>-2^63</code>, respectively.
     </p>
   </dd>
 </dl><!-- math -->
@@ -342,23 +861,54 @@
 <dl id="mime"><dt><a href="/pkg/mime/">mime</a></dt>
   <dd>
     <p><!-- CL 305230 -->
-      TODO: <a href="https://golang.org/cl/305230">https://golang.org/cl/305230</a>: support reading shared mime-info database on unix systems
+      On Unix systems, the table of MIME types is now read from the local system's
+      <a href="https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-0.21.html">Shared MIME-info Database</a>
+      when available.
     </p>
   </dd>
 </dl><!-- mime -->
 
+<dl id="mime/multipart"><dt><a href="/pkg/mime/multipart/">mime/multipart</a></dt>
+  <dd>
+    <p><!-- CL 313809 -->
+      <a href="/pkg/mime/multipart/#Part.FileName"><code>Part.FileName</code></a>
+      now applies
+      <a href="/pkg/path/filepath/#Base"><code>filepath.Base</code></a> to the
+      return value. This mitigates potential path traversal vulnerabilities in
+      applications that accept multipart messages, such as <code>net/http</code>
+      servers that call
+      <a href="/pkg/net/http/#Request.FormFile"><code>Request.FormFile</code></a>.
+    </p>
+  </dd>
+</dl><!-- mime/multipart -->
+
 <dl id="net"><dt><a href="/pkg/net/">net</a></dt>
   <dd>
     <p><!-- CL 272668 -->
-      TODO: <a href="https://golang.org/cl/272668">https://golang.org/cl/272668</a>: add IP.IsPrivate
+      The new method <a href="/pkg/net/#IP.IsPrivate"><code>IP.IsPrivate</code></a> reports whether an address is
+      a private IPv4 address according to <a href="https://datatracker.ietf.org/doc/rfc1918">RFC 1918</a>
+      or a local IPv6 address according <a href="https://datatracker.ietf.org/doc/rfc4193">RFC 4193</a>.
     </p>
 
     <p><!-- CL 301709 -->
-      TODO: <a href="https://golang.org/cl/301709">https://golang.org/cl/301709</a>: make go resolver aware of network parameter
+      The Go DNS resolver now only sends one DNS query when resolving an address for an IPv4-only or IPv6-only network,
+      rather than querying for both address families.
     </p>
 
     <p><!-- CL 307030 -->
-      TODO: <a href="https://golang.org/cl/307030">https://golang.org/cl/307030</a>: make ErrClosed and ParseError implement net.Error
+      The <a href="/pkg/net/#ErrClosed"><code>ErrClosed</code></a> sentinel error and
+      <a href="/pkg/net/#ParseError"><code>ParseError</code></a> error type now implement
+      the <a href="/pkg/net/#Error"><code>net.Error</code></a> interface.
+    </p>
+
+    <p><!-- CL 325829 -->
+      The <a href="/pkg/net/#ParseIP"><code>ParseIP</code></a> and <a href="/pkg/net/#ParseCIDR"><code>ParseCIDR</code></a>
+      functions now reject IPv4 addresses which contain decimal components with leading zeros.
+
+      These components were always interpreted as decimal, but some operating systems treat them as octal.
+      This mismatch could hypothetically lead to security issues if a Go application was used to validate IP addresses
+      which were then used in their original form with non-Go applications which interpreted components as octal. Generally,
+      it is advisable to always re-encode values after validation, which avoids this class of parser misalignment issues.
     </p>
   </dd>
 </dl><!-- net -->
@@ -373,11 +923,37 @@
     </p>
 
     <p><!-- CL 235437 -->
-      TODO: <a href="https://golang.org/cl/235437">https://golang.org/cl/235437</a>: add to deadlines only when positive
+      Setting the <a href="/pkg/net/http/#Server"><code>Server</code></a>
+      <code>ReadTimeout</code> or <code>WriteTimeout</code> fields to a negative value now indicates no timeout
+      rather than an immediate timeout.
     </p>
 
     <p><!-- CL 308952 -->
-      TODO: <a href="https://golang.org/cl/308952">https://golang.org/cl/308952</a>: make ReadRequest return an error when requests have multiple Host headers
+      The <a href="/pkg/net/http/#ReadRequest"><code>ReadRequest</code></a> function
+      now returns an error when the request has multiple Host headers.
+    </p>
+
+    <p><!-- CL 313950 -->
+      When producing a redirect to the cleaned version of a URL,
+      <a href="/pkg/net/http/#ServeMux"><code>ServeMux</code></a> now always
+      uses relative URLs in the <code>Location</code> 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.
+    </p>
+
+    <p><!-- CL 308009, CL 313489 -->
+      When interpreting certain HTTP headers handled by <code>net/http</code>,
+      non-ASCII characters are now ignored or rejected.
+    </p>
+
+    <p><!-- CL 325697 -->
+      If
+      <a href="/pkg/net/http/#Request.ParseForm"><code>Request.ParseForm</code></a>
+      returns an error when called by
+      <a href="/pkg/net/http/#Request.ParseMultipartForm"><code>Request.ParseMultipartForm</code></a>,
+      the latter now continues populating
+      <a href="/pkg/net/http/#Request.MultipartForm"><code>Request.MultipartForm</code></a>
+      before returning it.
     </p>
   </dd>
 </dl><!-- net/http -->
@@ -385,7 +961,10 @@
 <dl id="net/http/httptest"><dt><a href="/pkg/net/http/httptest/">net/http/httptest</a></dt>
   <dd>
     <p><!-- CL 308950 -->
-      TODO: <a href="https://golang.org/cl/308950">https://golang.org/cl/308950</a>: panic on non-3 digit (XXX) status code in Recorder.WriteHeader
+      <a href="/pkg/net/http/httptest/#ResponseRecorder.WriteHeader"><code>ResponseRecorder.WriteHeader</code></a>
+      now panics when the provided code is not a valid three-digit HTTP status code.
+      This matches the behavior of <a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a>
+      implementations in the <a href="/pkg/net/http/"><code>net/http</code></a> package.
     </p>
   </dd>
 </dl><!-- net/http/httptest -->
@@ -393,7 +972,8 @@
 <dl id="net/url"><dt><a href="/pkg/net/url/">net/url</a></dt>
   <dd>
     <p><!-- CL 314850 -->
-      TODO: <a href="https://golang.org/cl/314850">https://golang.org/cl/314850</a>: add Values.Has
+      The new method <a href="/pkg/net/url/#Values.Has"><code>Values.Has</code></a>
+      reports whether a query parameter is set.
     </p>
   </dd>
 </dl><!-- net/url -->
@@ -401,13 +981,26 @@
 <dl id="os"><dt><a href="/pkg/os/">os</a></dt>
   <dd>
     <p><!-- CL 268020 -->
-      TODO: <a href="https://golang.org/cl/268020">https://golang.org/cl/268020</a>: avoid allocation in File.WriteString
+      The <a href="/pkg/os/#File.WriteString"><code>File.WriteString</code></a> method
+      has been optimized to not make a copy of the input string.
     </p>
   </dd>
 </dl><!-- os -->
 
 <dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
   <dd>
+    <p><!-- CL 334669 -->
+      The new
+      <a href="/pkg/reflect/#Value.CanConvert"><code>Value.CanConvert</code></a>
+      method reports whether a value can be converted to a type.
+      This may be used to avoid a panic when converting a slice to an
+      array pointer type if the slice is too short.
+      Previously it was sufficient to use
+      <a href="/pkg/reflect/#Type.ConvertibleTo"><code>Type.ConvertibleTo</code></a>
+      for this, but the newly permitted conversion from slice to array
+      pointer type can panic even if the types are convertible.
+    </p>
+
     <p><!-- CL 266197 -->
       The new
       <a href="/pkg/reflect/#StructField.IsExported"><code>StructField.IsExported</code></a>
@@ -419,23 +1012,49 @@
     </p>
 
     <p><!-- CL 281233 -->
-      TODO: <a href="https://golang.org/cl/281233">https://golang.org/cl/281233</a>: add VisibleFields function
+      The new <a href="/pkg/reflect/#VisibleFields"><code>VisibleFields</code></a> function
+      returns all the visible fields in a struct type, including fields inside anonymous struct members.
     </p>
 
     <p><!-- CL 284136 -->
-      TODO: <a href="https://golang.org/cl/284136">https://golang.org/cl/284136</a>: panic if ArrayOf is called with negative length
+      The <a href="/pkg/reflect/#ArrayOf"><code>ArrayOf</code></a> function now panics when
+      called with a negative length.
+    </p>
+
+    <p><!-- CL 301652 -->
+      Checking the <a href="/pkg/reflect/#Type"><code>Type.ConvertibleTo</code></a> method
+      is no longer sufficient to guarantee that a call to
+      <a href="/pkg/reflect/#Value.Convert"><code>Value.Convert</code></a> will not panic.
+      It may panic when converting `[]T` to `*[N]T` if the slice's length is less than N.
+      See the <a href="#language">language changes</a> section above.
     </p>
   </dd>
 </dl><!-- reflect -->
 
+<dl id="runtime/metrics"><dt><a href="/pkg/runtime/metrics">runtime/metrics</a></dt>
+  <dd>
+    <p><!-- CL 308933, CL 312431, CL 312909 -->
+      New metrics were added that track total bytes and objects allocated and freed.
+      A new metric tracking the distribution of goroutine scheduling latencies was
+      also added.
+    </p>
+  </dd>
+</dl><!-- runtime/metrics -->
+
+<dl id="runtime/pprof"><dt><a href="/pkg/runtime/pprof">runtime/pprof</a></dt>
+  <dd>
+    <p><!-- CL 299991 -->
+      Block profiles are no longer biased to favor infrequent long events over
+      frequent short events.
+    </p>
+  </dd>
+</dl><!-- runtime/pprof -->
+
 <dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
   <dd>
-    <p><!-- CL 170079 -->
-      TODO: <a href="https://golang.org/cl/170079">https://golang.org/cl/170079</a>: implement Ryū-like algorithm for fixed precision ftoa
-    </p>
-
-    <p><!-- CL 170080 -->
-      TODO: <a href="https://golang.org/cl/170080">https://golang.org/cl/170080</a>: Implement Ryū algorithm for ftoa shortest mode
+    <p><!-- CL 170079, CL 170080 -->
+      The <code>strconv</code> package now uses Ulf Adams's Ryū algorithm for formatting floating-point numbers.
+      This algorithm improves performance on most inputs and is more than 99% faster on worst-case inputs.
     </p>
 
     <p><!-- CL 314775 -->
@@ -460,7 +1079,9 @@
 <dl id="sync/atomic"><dt><a href="/pkg/sync/atomic/">sync/atomic</a></dt>
   <dd>
     <p><!-- CL 241678 -->
-      TODO: <a href="https://golang.org/cl/241678">https://golang.org/cl/241678</a>: add (*Value).Swap and (*Value).CompareAndSwap
+      <code>atomic.Value</code> now has <a href="/pkg/sync/atomic/#Value.Swap"><code>Swap</code></a> and
+      <a href="/pkg/sync/atomic/#Value.CompareAndSwap"><code>CompareAndSwap</code></a> methods that provide
+      additional atomic operations.
     </p>
   </dd>
 </dl><!-- sync/atomic -->
@@ -468,11 +1089,38 @@
 <dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
   <dd>
     <p><!-- CL 295371 -->
-      TODO: <a href="https://golang.org/cl/295371">https://golang.org/cl/295371</a>: do not overflow key memory in GetQueuedCompletionStatus
+    <p>
+      The <a href="/pkg/syscall/#GetQueuedCompletionStatus"><code>GetQueuedCompletionStatus</code></a> and
+      <a href="/pkg/syscall/#PostQueuedCompletionStatus"><code>PostQueuedCompletionStatus</code></a>
+      functions are now deprecated. These functions have incorrect signatures and are superseded by
+      equivalents in the <a href="https://godoc.org/golang.org/x/sys/windows"><code>golang.org/x/sys/windows</code></a> package.
     </p>
 
     <p><!-- CL 313653 -->
-      TODO: <a href="https://golang.org/cl/313653">https://golang.org/cl/313653</a>: restore signal mask after setting foreground process group
+      On Unix-like systems, the process group of a child process is now set with signals blocked.
+      This avoids sending a <code>SIGTTOU</code> to the child when the parent is in a background process group.
+    </p>
+
+    <p><!-- CL 288298, CL 288300 -->
+      The Windows version of
+      <a href="/pkg/syscall/#SysProcAttr"><code>SysProcAttr</code></a>
+      has two new fields. <code>AdditionalInheritedHandles</code> is
+      a list of additional handles to be inherited by the new child
+      process. <code>ParentProcess</code> permits specifying the
+      parent process of the new process.
+
+    <p><!-- CL 311570 -->
+      The constant <code>MSG_CMSG_CLOEXEC</code> is now defined on
+      DragonFly and all OpenBSD systems (it was already defined on
+      some OpenBSD systems and all FreeBSD, NetBSD, and Linux systems).
+    </p>
+
+    <p><!-- CL 315281 -->
+      The constants <code>SYS_WAIT6</code> and <code>WEXITED</code>
+      are now defined on NetBSD systems (<code>SYS_WAIT6</code> was
+      already defined on DragonFly and FreeBSD systems;
+      <code>WEXITED</code> was already defined on Darwin, DragonFly,
+      FreeBSD, Linux, and Solaris systems).
     </p>
   </dd>
 </dl><!-- syscall -->
@@ -480,7 +1128,14 @@
 <dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
   <dd>
     <p><!-- CL 310033 -->
-      TODO: <a href="https://golang.org/cl/310033">https://golang.org/cl/310033</a>: add -shuffle=off|on|N to alter the execution order of tests and benchmarks
+      Added a new <a href="/cmd/go/#hdr-Testing_flags">testing flag</a> <code>-shuffle</code> which controls the execution order of tests and benchmarks.
+    </p>
+    <p><!-- CL 260577 -->
+      The new
+      <a href="/pkg/testing/#T.Setenv"><code>T.Setenv</code></a>
+      and <a href="/pkg/testing/#B.Setenv"><code>B.Setenv</code></a>
+      methods support setting an environment variable for the duration
+      of the test or benchmark.
     </p>
   </dd>
 </dl><!-- testing -->
@@ -488,7 +1143,8 @@
 <dl id="text/template/parse"><dt><a href="/pkg/text/template/parse/">text/template/parse</a></dt>
   <dd>
     <p><!-- CL 301493 -->
-      TODO: <a href="https://golang.org/cl/301493">https://golang.org/cl/301493</a>: add a mode to skip func-check on parsing
+      The new <a href="/pkg/text/template/parse/#Mode"><code>SkipFuncCheck</code></a> <a href=><code>Mode</code></a>
+      value changes the template parser to not verify that functions are defined.
     </p>
   </dd>
 </dl><!-- text/template/parse -->
@@ -496,21 +1152,41 @@
 <dl id="time"><dt><a href="/pkg/time/">time</a></dt>
   <dd>
     <p><!-- CL 260858 -->
-      time.Time now has a <a href="/pkg/time/#Time.GoString">GoString</a>
-      method that will return a more useful value for times when printed with
-      the <code>"%#v"</code> format specifier in the fmt package.
+      The <a href="/pkg/time/#Time"><code>Time</code></a> type now has a
+      <a href="/pkg/time/#Time.GoString"><code>GoString</code></a> method that
+      will return a more useful value for times when printed with the
+      <code>%#v</code> format specifier in the <code>fmt</code> package.
     </p>
 
     <p><!-- CL 264077 -->
-      TODO: <a href="https://golang.org/cl/264077">https://golang.org/cl/264077</a>: add Time.IsDST() to check if its Location is in Daylight Savings Time
+      The new <a href="/pkg/time/#Time.IsDST"><code>Time.IsDST</code></a> method can be used to check whether the time
+      is in Daylight Savings Time in its configured location.
     </p>
 
     <p><!-- CL 293349 -->
-      TODO: <a href="https://golang.org/cl/293349">https://golang.org/cl/293349</a>: add Time.Unix{Milli,Micro} and to-Time helpers UnixMicro, UnixMilli
+      The new <a href="/pkg/time/#Time.UnixMilli"><code>Time.UnixMilli</code></a> and
+      <a href="/pkg/time/#Time.UnixMicro"><code>Time.UnixMicro</code></a>
+      methods return the number of milliseconds and microseconds elapsed since
+      January 1, 1970 UTC respectively.
+      <br />
+      The new <a href="/pkg/time/#UnixMilli"><code>UnixMilli</code></a> and
+      <a href="/pkg/time/#UnixMicro"><code>UnixMicro</code></a> functions
+      return the local <code>Time</code> corresponding to the given Unix time.
     </p>
 
     <p><!-- CL 300996 -->
-      TODO: <a href="https://golang.org/cl/300996">https://golang.org/cl/300996</a>: support &#34;,&#34; as separator for fractional seconds
+      The package now accepts comma "," as a separator for fractional seconds when parsing and formatting time.
+      The following time formats are now accepted:
+      <ul>
+        <li>2006-01-02 14:06:03,999999999 -0700 MST</li>
+        <li>Mon Jan _2 14:06:03,120007 2006</li>
+        <li>Mon Jan 2 14:06:03,120007 2006</li>
+      </ul>
+    </p>
+
+    <p><!-- CL 320252 -->
+      The new constant <a href="/pkg/time/#Layout"><code>Layout</code></a>
+      defines the reference time.
     </p>
   </dd>
 </dl><!-- time -->
diff --git a/doc/go_spec.html b/doc/go_spec.html
index e59b355..0e14a1f 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-	"Subtitle": "Version of Apr 28, 2021",
+	"Subtitle": "Version of Jul 26, 2021",
 	"Path": "/ref/spec"
 }-->
 
@@ -490,8 +490,8 @@
 \n   U+000A line feed or newline
 \r   U+000D carriage return
 \t   U+0009 horizontal tab
-\v   U+000b vertical tab
-\\   U+005c backslash
+\v   U+000B vertical tab
+\\   U+005C backslash
 \'   U+0027 single quote  (valid escape only within rune literals)
 \"   U+0022 double quote  (valid escape only within string literals)
 </pre>
@@ -4334,7 +4334,10 @@
 
 var t []string
 t0 := (*[0]string)(t)    // t0 == nil
-t1 := (*[1]string)(t)    // panics: len([1]string) > len(s)
+t1 := (*[1]string)(t)    // panics: len([1]string) > len(t)
+
+u := make([]byte, 0)
+u0 = (*[0]byte)(u)       // u0 != nil
 </pre>
 
 <h3 id="Constant_expressions">Constant expressions</h3>
@@ -4670,7 +4673,7 @@
 
 <pre>
 append cap complex imag len make new real
-unsafe.Alignof unsafe.Offsetof unsafe.Sizeof
+unsafe.Add unsafe.Alignof unsafe.Offsetof unsafe.Sizeof unsafe.Slice
 </pre>
 
 <pre>
@@ -4909,7 +4912,7 @@
 
 <p>
 "Switch" statements provide multi-way execution.
-An expression or type specifier is compared to the "cases"
+An expression or type is compared to the "cases"
 inside the "switch" to determine which branch
 to execute.
 </p>
@@ -5020,7 +5023,7 @@
 A type switch compares types rather than values. It is otherwise similar
 to an expression switch. It is marked by a special switch expression that
 has the form of a <a href="#Type_assertions">type assertion</a>
-using the reserved word <code>type</code> rather than an actual type:
+using the keyword <code>type</code> rather than an actual type:
 </p>
 
 <pre>
@@ -6782,7 +6785,8 @@
 
 <p>
 The function <code>Slice</code> returns a slice whose underlying array starts at <code>ptr</code>
-and whose length and capacity are <code>len</code>:
+and whose length and capacity are <code>len</code>.
+<code>Slice(ptr, len)</code> is equivalent to
 </p>
 
 <pre>
@@ -6790,10 +6794,17 @@
 </pre>
 
 <p>
+except that, as a special case, if <code>ptr</code>
+is <code>nil</code> and <code>len</code> is zero,
+<code>Slice</code> returns <code>nil</code>.
+</p>
+
+<p>
 The <code>len</code> argument must be of integer type or an untyped <a href="#Constants">constant</a>.
 A constant <code>len</code> argument must be non-negative and <a href="#Representability">representable</a> by a value of type <code>int</code>;
 if it is an untyped constant it is given type <code>int</code>.
-If <code>ptr</code> is <code>nil</code> or <code>len</code> is negative at run time,
+At run time, if <code>len</code> is negative,
+or if <code>ptr</code> is <code>nil</code> and <code>len</code> is not zero,
 a <a href="#Run_time_panics">run-time panic</a> occurs.
 </p>
 
diff --git a/misc/cgo/errors/errors_test.go b/misc/cgo/errors/errors_test.go
index a077b59..68a30a4 100644
--- a/misc/cgo/errors/errors_test.go
+++ b/misc/cgo/errors/errors_test.go
@@ -40,7 +40,8 @@
 			if len(frags) == 1 {
 				continue
 			}
-			re, err := regexp.Compile(string(frags[1]))
+			frag := fmt.Sprintf(":%d:.*%s", i+1, frags[1])
+			re, err := regexp.Compile(frag)
 			if err != nil {
 				t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1])
 				continue
diff --git a/misc/cgo/errors/testdata/err2.go b/misc/cgo/errors/testdata/err2.go
index 1d22401..a90598f 100644
--- a/misc/cgo/errors/testdata/err2.go
+++ b/misc/cgo/errors/testdata/err2.go
@@ -40,15 +40,15 @@
 	C.foop = x // ERROR HERE
 
 	// issue 13129: used to output error about C.unsignedshort with CC=clang
-	var x C.ushort
-	x = int(0) // ERROR HERE: C\.ushort
+	var x1 C.ushort
+	x1 = int(0) // ERROR HERE: C\.ushort
 
 	// issue 13423
 	_ = C.fopen() // ERROR HERE
 
 	// issue 13467
-	var x rune = '✈'
-	var _ rune = C.transform(x) // ERROR HERE: C\.int
+	var x2 rune = '✈'
+	var _ rune = C.transform(x2) // ERROR HERE: C\.int
 
 	// issue 13635: used to output error about C.unsignedchar.
 	// This test tests all such types.
@@ -91,10 +91,10 @@
 
 	// issue 26745
 	_ = func(i int) int {
-		return C.i + 1 // ERROR HERE: :13
+		return C.i + 1 // ERROR HERE: 14
 	}
 	_ = func(i int) {
-		C.fi(i) // ERROR HERE: :6
+		C.fi(i) // ERROR HERE: 7
 	}
 
 	C.fi = C.fi // ERROR HERE
diff --git a/misc/cgo/test/issue1435.go b/misc/cgo/test/issue1435.go
index cf34ce8..92c6b99 100644
--- a/misc/cgo/test/issue1435.go
+++ b/misc/cgo/test/issue1435.go
@@ -9,6 +9,7 @@
 import (
 	"fmt"
 	"os"
+	"sort"
 	"strings"
 	"syscall"
 	"testing"
@@ -105,11 +106,23 @@
 				// "Pid:\t".
 			}
 			if strings.HasPrefix(line, filter) {
-				if line != expected {
-					return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc)
+				if line == expected {
+					foundAThread = true
+					break
 				}
-				foundAThread = true
-				break
+				if filter == "Groups:" && strings.HasPrefix(line, "Groups:\t") {
+					// https://github.com/golang/go/issues/46145
+					// Containers don't reliably output this line in sorted order so manually sort and compare that.
+					a := strings.Split(line[8:], " ")
+					sort.Strings(a)
+					got := strings.Join(a, " ")
+					if got == expected[8:] {
+						foundAThread = true
+						break
+					}
+
+				}
+				return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc)
 			}
 		}
 	}
diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go
index 90d8c36..19ad8c7 100644
--- a/misc/cgo/testcshared/cshared_test.go
+++ b/misc/cgo/testcshared/cshared_test.go
@@ -292,11 +292,60 @@
 		"-installsuffix", "testcshared",
 		"-o", libgoname,
 		filepath.Join(".", "libgo", "libgo.go")}
+	if GOOS == "windows" && strings.HasSuffix(args[6], ".a") {
+		args[6] = strings.TrimSuffix(args[6], ".a") + ".dll"
+	}
 	cmd = exec.Command(args[0], args[1:]...)
 	out, err = cmd.CombinedOutput()
 	if err != nil {
 		return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
 	}
+	if GOOS == "windows" {
+		// We can't simply pass -Wl,--out-implib, because this relies on having imports from multiple packages,
+		// which results in the linkers output implib getting overwritten at each step. So instead build the
+		// import library the traditional way, using a def file.
+		err = os.WriteFile("libgo.def",
+			[]byte("LIBRARY libgo.dll\nEXPORTS\n\tDidInitRun\n\tDidMainRun\n\tDivu\n\tFromPkg\n\t_cgo_dummy_export\n"),
+			0644)
+		if err != nil {
+			return fmt.Errorf("unable to write def file: %v", err)
+		}
+		out, err = exec.Command(cc[0], append(cc[1:], "-print-prog-name=dlltool")...).CombinedOutput()
+		if err != nil {
+			return fmt.Errorf("unable to find dlltool path: %v\n%s\n", err, out)
+		}
+		args := []string{strings.TrimSpace(string(out)), "-D", args[6], "-l", libgoname, "-d", "libgo.def"}
+
+		// This is an unfortunate workaround for https://github.com/mstorsjo/llvm-mingw/issues/205 in which
+		// we basically reimplement the contents of the dlltool.sh wrapper: https://git.io/JZFlU
+		dlltoolContents, err := os.ReadFile(args[0])
+		if err != nil {
+			return fmt.Errorf("unable to read dlltool: %v\n", err)
+		}
+		if bytes.HasPrefix(dlltoolContents, []byte("#!/bin/sh")) && bytes.Contains(dlltoolContents, []byte("llvm-dlltool")) {
+			base, name := filepath.Split(args[0])
+			args[0] = filepath.Join(base, "llvm-dlltool")
+			var machine string
+			switch strings.SplitN(name, "-", 2)[0] {
+			case "i686":
+				machine = "i386"
+			case "x86_64":
+				machine = "i386:x86-64"
+			case "armv7":
+				machine = "arm"
+			case "aarch64":
+				machine = "arm64"
+			}
+			if len(machine) > 0 {
+				args = append(args, "-m", machine)
+			}
+		}
+
+		out, err = exec.Command(args[0], args[1:]...).CombinedOutput()
+		if err != nil {
+			return fmt.Errorf("unable to run dlltool to create import library: %v\n%s\n", err, out)
+		}
+	}
 
 	if runtime.GOOS != GOOS && GOOS == "android" {
 		args = append(adbCmd(), "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname))
@@ -400,7 +449,7 @@
 	defer f.Close()
 	section := f.Section(".edata")
 	if section == nil {
-		t.Fatalf(".edata section is not present")
+		t.Skip(".edata section is not present")
 	}
 
 	// TODO: deduplicate this struct from cmd/link/internal/ld/pe.go
@@ -749,7 +798,12 @@
 	defer os.RemoveAll(tmpdir)
 
 	lib := filepath.Join(tmpdir, "libtestgo2c2go."+libSuffix)
-	run(t, nil, "go", "build", "-buildmode=c-shared", "-o", lib, "./go2c2go/go")
+	var env []string
+	if GOOS == "windows" && strings.HasSuffix(lib, ".a") {
+		env = append(env, "CGO_LDFLAGS=-Wl,--out-implib,"+lib, "CGO_LDFLAGS_ALLOW=.*")
+		lib = strings.TrimSuffix(lib, ".a") + ".dll"
+	}
+	run(t, env, "go", "build", "-buildmode=c-shared", "-o", lib, "./go2c2go/go")
 
 	cgoCflags := os.Getenv("CGO_CFLAGS")
 	if cgoCflags != "" {
diff --git a/misc/cgo/testplugin/plugin_test.go b/misc/cgo/testplugin/plugin_test.go
index 28a8c66..9697dbf 100644
--- a/misc/cgo/testplugin/plugin_test.go
+++ b/misc/cgo/testplugin/plugin_test.go
@@ -263,6 +263,17 @@
 	}
 }
 
+// Test with main using -buildmode=pie with plugin for issue #43228
+func TestIssue25756pie(t *testing.T) {
+	if os.Getenv("GO_BUILDER_NAME") == "darwin-arm64-11_0-toothrot" {
+		t.Skip("broken on darwin/arm64 builder in sharded mode; see issue 46239")
+	}
+
+	goCmd(t, "build", "-buildmode=plugin", "-o", "life.so", "./issue25756/plugin")
+	goCmd(t, "build", "-buildmode=pie", "-o", "issue25756pie.exe", "./issue25756/main.go")
+	run(t, "./issue25756pie.exe")
+}
+
 func TestMethod(t *testing.T) {
 	// Exported symbol's method must be live.
 	goCmd(t, "build", "-buildmode=plugin", "-o", "plugin.so", "./method/plugin.go")
diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js
index 3e41e62..231185a 100644
--- a/misc/wasm/wasm_exec.js
+++ b/misc/wasm/wasm_exec.js
@@ -401,6 +401,7 @@
 							storeValue(sp + 56, result);
 							this.mem.setUint8(sp + 64, 1);
 						} catch (err) {
+							sp = this._inst.exports.getsp() >>> 0; // see comment above
 							storeValue(sp + 56, err);
 							this.mem.setUint8(sp + 64, 0);
 						}
@@ -417,6 +418,7 @@
 							storeValue(sp + 40, result);
 							this.mem.setUint8(sp + 48, 1);
 						} catch (err) {
+							sp = this._inst.exports.getsp() >>> 0; // see comment above
 							storeValue(sp + 40, err);
 							this.mem.setUint8(sp + 48, 0);
 						}
@@ -433,6 +435,7 @@
 							storeValue(sp + 40, result);
 							this.mem.setUint8(sp + 48, 1);
 						} catch (err) {
+							sp = this._inst.exports.getsp() >>> 0; // see comment above
 							storeValue(sp + 40, err);
 							this.mem.setUint8(sp + 48, 0);
 						}
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index 808cf27..2d53f4c 100644
--- a/src/archive/zip/reader.go
+++ b/src/archive/zip/reader.go
@@ -96,7 +96,15 @@
 		return err
 	}
 	z.r = r
-	z.File = make([]*File, 0, end.directoryRecords)
+	// Since the number of directory records is not validated, it is not
+	// safe to preallocate z.File without first checking that the specified
+	// number of files is reasonable, since a malformed archive may
+	// indicate it contains up to 1 << 128 - 1 files. Since each file has a
+	// header which will be _at least_ 30 bytes we can safely preallocate
+	// if (data size / 30) >= end.directoryRecords.
+	if (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
+		z.File = make([]*File, 0, end.directoryRecords)
+	}
 	z.Comment = end.comment
 	rs := io.NewSectionReader(r, 0, size)
 	if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil {
diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go
index 35e681e..37dafe6 100644
--- a/src/archive/zip/reader_test.go
+++ b/src/archive/zip/reader_test.go
@@ -1325,3 +1325,62 @@
 		})
 	}
 }
+
+func TestCVE202133196(t *testing.T) {
+	// Archive that indicates it has 1 << 128 -1 files,
+	// this would previously cause a panic due to attempting
+	// to allocate a slice with 1 << 128 -1 elements.
+	data := []byte{
+		0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08,
+		0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02,
+		0x03, 0x62, 0x61, 0x65, 0x03, 0x04, 0x00, 0x00,
+		0xff, 0xff, 0x50, 0x4b, 0x07, 0x08, 0xbe, 0x20,
+		0x5c, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00,
+		0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00,
+		0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0xbe, 0x20, 0x5c, 0x6c, 0x09, 0x00,
+		0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x01, 0x02, 0x03, 0x50, 0x4b, 0x06, 0x06, 0x2c,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
+		0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0x31, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x50, 0x4b, 0x06, 0x07, 0x00,
+		0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50,
+		0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0x00, 0x00,
+	}
+	_, err := NewReader(bytes.NewReader(data), int64(len(data)))
+	if err != ErrFormat {
+		t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
+	}
+
+	// Also check that an archive containing a handful of empty
+	// files doesn't cause an issue
+	b := bytes.NewBuffer(nil)
+	w := NewWriter(b)
+	for i := 0; i < 5; i++ {
+		_, err := w.Create("")
+		if err != nil {
+			t.Fatalf("Writer.Create failed: %s", err)
+		}
+	}
+	if err := w.Close(); err != nil {
+		t.Fatalf("Writer.Close failed: %s", err)
+	}
+	r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len()))
+	if err != nil {
+		t.Fatalf("NewReader failed: %s", err)
+	}
+	if len(r.File) != 5 {
+		t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File))
+	}
+}
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index ab48632..4cddcf4 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -1003,7 +1003,8 @@
 				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 1146c1a..d8a20ed 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -89,7 +89,7 @@
 	CMP	R1<<33, R2
 	CMP	R22.SXTX, RSP                    // ffe336eb
 	CMP	$0x22220000, RSP                 // CMP $572653568, RSP   // 5b44a4d2ff633beb
-	CMPW	$0x22220000, RSP                 // CMPW $572653568, RSP  // 5b44a452ff633b6b
+	CMPW	$0x22220000, RSP                 // CMPW $572653568, RSP  // 5b44a452ff433b6b
 	CCMN	MI, ZR, R1, $4	                 // e44341ba
 	// MADD Rn,Rm,Ra,Rd
 	MADD	R1, R2, R3, R4                   // 6408019b
@@ -377,6 +377,7 @@
 	MOVD	$0x1000100010001000, RSP      // MOVD	$1152939097061330944, RSP   // ff8304b2
 	MOVW	$0x10001000, RSP              // MOVW	$268439552, RSP             // ff830432
 	ADDW	$0x10001000, R1               // ADDW	$268439552, R1              // fb83043221001b0b
+	ADDW	$0x22220000, RSP, R3          // ADDW	$572653568, RSP, R3         // 5b44a452e3433b0b
 
 // move a large constant to a Vd.
 	VMOVS	$0x80402010, V11                                      // VMOVS	$2151686160, V11
@@ -547,6 +548,7 @@
 // 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 +581,7 @@
 	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/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s
index 66fc910..cf57179 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64error.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64error.s
@@ -52,6 +52,16 @@
 	NEGSW	R7@>2, R5                                        // ERROR "unsupported shift operator"
 	CINC	CS, R2, R3, R4                                   // ERROR "illegal combination"
 	CSEL	LT, R1, R2                                       // ERROR "illegal combination"
+	CINC	AL, R2, R3                                       // ERROR "invalid condition"
+	CINC	NV, R2, R3                                       // ERROR "invalid condition"
+	CINVW	AL, R2, R3                                       // ERROR "invalid condition"
+	CINV	NV, R2, R3                                       // ERROR "invalid condition"
+	CNEG	AL, R2, R3                                       // ERROR "invalid condition"
+	CNEGW	NV, R2, R3                                       // ERROR "invalid condition"
+	CSET	AL, R2                                           // ERROR "invalid condition"
+	CSET	NV, R2                                           // ERROR "invalid condition"
+	CSETMW	AL, R2                                           // ERROR "invalid condition"
+	CSETM	NV, R2                                           // ERROR "invalid condition"
 	LDP.P	8(R2), (R2, R3)                                  // ERROR "constrained unpredictable behavior"
 	LDP.W	8(R3), (R2, R3)                                  // ERROR "constrained unpredictable behavior"
 	LDP	(R1), (R2, R2)                                   // ERROR "constrained unpredictable behavior"
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s
index 1bd4b1e..b6c0aa5 100644
--- a/src/cmd/asm/internal/asm/testdata/ppc64.s
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.s
@@ -41,8 +41,8 @@
 	MOVDBR (R3)(R4), R5             // 7ca41c28
 	MOVWBR (R3)(R4), R5             // 7ca41c2c
 	MOVHBR (R3)(R4), R5             // 7ca41e2c
-	MOVD $foo+4009806848(FP), R5    // 3fe1ef0138bfcc20
-	MOVD $foo(SB), R5               // 3fe0000038bf0000
+	MOVD $foo+4009806848(FP), R5    // 3ca1ef0138a5cc20
+	MOVD $foo(SB), R5               // 3ca0000038a50000
 
 	MOVDU 8(R3), R4                 // e8830009
 	MOVDU (R3)(R4), R5              // 7ca4186a
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index ae61725..a73e998 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1638,6 +1638,8 @@
 		c = append(c, "-maix64")
 		c = append(c, "-mcmodel=large")
 	}
+	// disable LTO so we get an object whose symbols we can read
+	c = append(c, "-fno-lto")
 	c = append(c, "-") //read input from standard input
 	return c
 }
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 03a662e..c6a0c52 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Cgo; see gmp.go for an overview.
+// Cgo; see doc.go for an overview.
 
 // TODO(rsc):
 //	Emit correct line number annotations.
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 8c31d5b..94152f4 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -168,8 +168,18 @@
 			if *gccgo {
 				fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
 			} else {
-				fmt.Fprintf(fm, "extern char %s[];\n", n.C)
-				fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+				// Force a reference to all symbols so that
+				// the external linker will add DT_NEEDED
+				// entries as needed on ELF systems.
+				// Treat function variables differently
+				// to avoid type confict errors from LTO
+				// (Link Time Optimization).
+				if n.Kind == "fpvar" {
+					fmt.Fprintf(fm, "extern void %s();\n", n.C)
+				} else {
+					fmt.Fprintf(fm, "extern char %s[];\n", n.C)
+					fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+				}
 				fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C)
 				fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C)
 				fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C)
@@ -1042,7 +1052,7 @@
 		// This unpacks the argument struct above and calls the Go function.
 		fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
 
-		fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
+		fmt.Fprintf(fm, "void _cgoexp%s_%s(void* p){}\n", cPrefix, exp.ExpName)
 
 		if gccResult != "void" {
 			// Write results back to frame.
diff --git a/src/cmd/compile/abi-internal.md b/src/cmd/compile/abi-internal.md
index f901e70..2bb4055 100644
--- a/src/cmd/compile/abi-internal.md
+++ b/src/cmd/compile/abi-internal.md
@@ -233,7 +233,7 @@
     r1.x    uintptr
     r1.y    [2]uintptr
     a1Spill uint8
-    a2Spill uint8
+    a3Spill uint8
     _       [6]uint8  // alignment padding
 
 In the stack frame, only the `a2` field is initialized on entry; the
@@ -402,7 +402,7 @@
 Special-purpose registers are as follows:
 
 | Register | Call meaning | Return meaning | Body meaning |
-| --- | --- | --- |
+| --- | --- | --- | --- |
 | RSP | Stack pointer | Same | Same |
 | RBP | Frame pointer | Same | Same |
 | RDX | Closure context pointer | Scratch | Scratch |
diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go
index cb8e9d7..d657ddc 100644
--- a/src/cmd/compile/internal/abi/abiutils.go
+++ b/src/cmd/compile/internal/abi/abiutils.go
@@ -446,35 +446,20 @@
 	return result
 }
 
-// parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields)
-var parameterUpdateMu sync.Mutex
-
-// FieldOffsetOf returns a concurency-safe version of f.Offset
-func FieldOffsetOf(f *types.Field) int64 {
-	parameterUpdateMu.Lock()
-	defer parameterUpdateMu.Unlock()
-	return f.Offset
-}
-
 func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn, setNname bool) {
 	// Everything except return values in registers has either a frame home (if not in a register) or a frame spill location.
 	if !isReturn || len(a.Registers) == 0 {
 		// The type frame offset DOES NOT show effects of minimum frame size.
 		// Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set
-		parameterUpdateMu.Lock()
-		defer parameterUpdateMu.Unlock()
 		off := a.FrameOffset(result)
 		fOffset := f.Offset
 		if fOffset == types.BOGUS_FUNARG_OFFSET {
-			// Set the Offset the first time. After that, we may recompute it, but it should never change.
-			f.Offset = off
-			if f.Nname != nil {
-				// always set it in this case.
+			if setNname && f.Nname != nil {
 				f.Nname.(*ir.Name).SetFrameOffset(off)
 				f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false)
 			}
-		} else if fOffset != off {
-			base.Fatalf("offset for %s at %s changed from %d to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset, off)
+		} else {
+			base.Fatalf("field offset for %s at %s has been set to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset)
 		}
 	} else {
 		if setNname && f.Nname != nil {
diff --git a/src/cmd/compile/internal/dwarfgen/dwarf.go b/src/cmd/compile/internal/dwarfgen/dwarf.go
index 422c7e6..0e22b61 100644
--- a/src/cmd/compile/internal/dwarfgen/dwarf.go
+++ b/src/cmd/compile/internal/dwarfgen/dwarf.go
@@ -222,9 +222,64 @@
 		fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
 	}
 
+	// Sort decls and vars.
+	sortDeclsAndVars(fn, decls, vars)
+
 	return decls, vars
 }
 
+// sortDeclsAndVars sorts the decl and dwarf var lists according to
+// parameter declaration order, so as to insure that when a subprogram
+// DIE is emitted, its parameter children appear in declaration order.
+// Prior to the advent of the register ABI, sorting by frame offset
+// would achieve this; with the register we now need to go back to the
+// original function signature.
+func sortDeclsAndVars(fn *ir.Func, decls []*ir.Name, vars []*dwarf.Var) {
+	paramOrder := make(map[*ir.Name]int)
+	idx := 1
+	for _, selfn := range types.RecvsParamsResults {
+		fsl := selfn(fn.Type()).FieldSlice()
+		for _, f := range fsl {
+			if n, ok := f.Nname.(*ir.Name); ok {
+				paramOrder[n] = idx
+				idx++
+			}
+		}
+	}
+	sort.Stable(varsAndDecls{decls, vars, paramOrder})
+}
+
+type varsAndDecls struct {
+	decls      []*ir.Name
+	vars       []*dwarf.Var
+	paramOrder map[*ir.Name]int
+}
+
+func (v varsAndDecls) Len() int {
+	return len(v.decls)
+}
+
+func (v varsAndDecls) Less(i, j int) bool {
+	nameLT := func(ni, nj *ir.Name) bool {
+		oi, foundi := v.paramOrder[ni]
+		oj, foundj := v.paramOrder[nj]
+		if foundi {
+			if foundj {
+				return oi < oj
+			} else {
+				return true
+			}
+		}
+		return false
+	}
+	return nameLT(v.decls[i], v.decls[j])
+}
+
+func (v varsAndDecls) Swap(i, j int) {
+	v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
+	v.decls[i], v.decls[j] = v.decls[j], v.decls[i]
+}
+
 // Given a function that was inlined at some point during the
 // compilation, return a sorted list of nodes corresponding to the
 // autos/locals in that function prior to inlining. If this is a
@@ -476,6 +531,14 @@
 		fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
 	}
 
+	// Adds flag to producer string singalling whether regabi is turned on or
+	// off.
+	// Once regabi is turned on across the board and the relative GOEXPERIMENT
+	// knobs no longer exist this code should be removed.
+	if buildcfg.Experiment.RegabiArgs {
+		cmd.Write([]byte(" regabi"))
+	}
+
 	if cmd.Len() == 0 {
 		return
 	}
diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go
index 3ac7ff1..cd56f07 100644
--- a/src/cmd/compile/internal/escape/escape.go
+++ b/src/cmd/compile/internal/escape/escape.go
@@ -2013,14 +2013,14 @@
 		return "too large for stack"
 	}
 
-	if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Width >= ir.MaxImplicitStackVarSize {
+	if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Width > ir.MaxImplicitStackVarSize {
 		return "too large for stack"
 	}
 
-	if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
+	if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() > ir.MaxImplicitStackVarSize {
 		return "too large for stack"
 	}
-	if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() >= ir.MaxImplicitStackVarSize {
+	if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() > ir.MaxImplicitStackVarSize {
 		return "too large for stack"
 	}
 
@@ -2033,7 +2033,7 @@
 		if !ir.IsSmallIntConst(r) {
 			return "non-constant size"
 		}
-		if t := n.Type(); t.Elem().Width != 0 && ir.Int64Val(r) >= ir.MaxImplicitStackVarSize/t.Elem().Width {
+		if t := n.Type(); t.Elem().Width != 0 && ir.Int64Val(r) > ir.MaxImplicitStackVarSize/t.Elem().Width {
 			return "too large for stack"
 		}
 	}
diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go
index a738051..0050445 100644
--- a/src/cmd/compile/internal/gc/compile.go
+++ b/src/cmd/compile/internal/gc/compile.go
@@ -119,38 +119,51 @@
 		})
 	}
 
-	// We queue up a goroutine per function that needs to be
-	// compiled, but require them to grab an available worker ID
-	// before doing any substantial work to limit parallelism.
-	workerIDs := make(chan int, base.Flag.LowerC)
-	for i := 0; i < base.Flag.LowerC; i++ {
-		workerIDs <- i
+	// By default, we perform work right away on the current goroutine
+	// as the solo worker.
+	queue := func(work func(int)) {
+		work(0)
+	}
+
+	if nWorkers := base.Flag.LowerC; nWorkers > 1 {
+		// For concurrent builds, we create a goroutine per task, but
+		// require them to hold a unique worker ID while performing work
+		// to limit parallelism.
+		workerIDs := make(chan int, nWorkers)
+		for i := 0; i < nWorkers; i++ {
+			workerIDs <- i
+		}
+
+		queue = func(work func(int)) {
+			go func() {
+				worker := <-workerIDs
+				work(worker)
+				workerIDs <- worker
+			}()
+		}
 	}
 
 	var wg sync.WaitGroup
-	var asyncCompile func(*ir.Func)
-	asyncCompile = func(fn *ir.Func) {
-		wg.Add(1)
-		go func() {
-			worker := <-workerIDs
-			ssagen.Compile(fn, worker)
-			workerIDs <- worker
-
-			// Done compiling fn. Schedule it's closures for compilation.
-			for _, closure := range fn.Closures {
-				asyncCompile(closure)
-			}
-			wg.Done()
-		}()
+	var compile func([]*ir.Func)
+	compile = func(fns []*ir.Func) {
+		wg.Add(len(fns))
+		for _, fn := range fns {
+			fn := fn
+			queue(func(worker int) {
+				ssagen.Compile(fn, worker)
+				compile(fn.Closures)
+				wg.Done()
+			})
+		}
 	}
 
 	types.CalcSizeDisabled = true // not safe to calculate sizes concurrently
 	base.Ctxt.InParallel = true
-	for _, fn := range compilequeue {
-		asyncCompile(fn)
-	}
+
+	compile(compilequeue)
 	compilequeue = nil
 	wg.Wait()
+
 	base.Ctxt.InParallel = false
 	types.CalcSizeDisabled = false
 }
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index 0b10cb8..474d718 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -148,6 +148,7 @@
 	if reflectdata.ZeroSize > 0 {
 		zero := base.PkgLinksym("go.map", "zero", obj.ABI0)
 		objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
+		zero.Set(obj.AttrStatic, true)
 	}
 
 	staticdata.WriteFuncSyms()
diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go
index a6829e9..d6b4ced 100644
--- a/src/cmd/compile/internal/inline/inl.go
+++ b/src/cmd/compile/internal/inline/inl.go
@@ -1124,6 +1124,10 @@
 	newclofn *ir.Func
 
 	fn *ir.Func // For debug -- the func that is being inlined
+
+	// If true, then don't update source positions during substitution
+	// (retain old source positions).
+	noPosUpdate bool
 }
 
 // list inlines a list of nodes.
@@ -1219,7 +1223,14 @@
 // closure node.
 func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node {
 	m := ir.Copy(n)
-	m.SetPos(subst.updatedPos(m.Pos()))
+
+	// Prior to the subst edit, set a flag in the inlsubst to
+	// indicated that we don't want to update the source positions in
+	// the new closure. If we do this, it will appear that the closure
+	// itself has things inlined into it, which is not the case. See
+	// issue #46234 for more details.
+	defer func(prev bool) { subst.noPosUpdate = prev }(subst.noPosUpdate)
+	subst.noPosUpdate = true
 	ir.EditChildren(m, subst.edit)
 
 	//fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc))
@@ -1445,6 +1456,9 @@
 }
 
 func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
+	if subst.noPosUpdate {
+		return xpos
+	}
 	pos := base.Ctxt.PosTable.Pos(xpos)
 	oldbase := pos.Base() // can be nil
 	newbase := subst.bases[oldbase]
diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go
index 4c7c9fc..5fcad09 100644
--- a/src/cmd/compile/internal/noder/noder.go
+++ b/src/cmd/compile/internal/noder/noder.go
@@ -882,9 +882,6 @@
 	if n == nil {
 		return nil
 	}
-	if _, ok := n.(ir.Ntype); !ok {
-		ir.Dump("NOT NTYPE", n)
-	}
 	return n.(ir.Ntype)
 }
 
diff --git a/src/cmd/compile/internal/reflectdata/alg.go b/src/cmd/compile/internal/reflectdata/alg.go
index d12d9ca..0707e0b 100644
--- a/src/cmd/compile/internal/reflectdata/alg.go
+++ b/src/cmd/compile/internal/reflectdata/alg.go
@@ -6,6 +6,7 @@
 
 import (
 	"fmt"
+	"math/bits"
 	"sort"
 
 	"cmd/compile/internal/base"
@@ -47,6 +48,11 @@
 func AlgType(t *types.Type) types.AlgKind {
 	a, _ := types.AlgType(t)
 	if a == types.AMEM {
+		if t.Alignment() < int64(base.Ctxt.Arch.Alignment) && t.Alignment() < t.Width {
+			// For example, we can't treat [2]int16 as an int32 if int32s require
+			// 4-byte alignment. See issue 46283.
+			return a
+		}
 		switch t.Width {
 		case 0:
 			return types.AMEM0
@@ -769,6 +775,20 @@
 		if f := t.Field(next); f.Sym.IsBlank() || !isRegularMemory(f.Type) {
 			break
 		}
+		// For issue 46283, don't combine fields if the resulting load would
+		// require a larger alignment than the component fields.
+		if base.Ctxt.Arch.Alignment > 1 {
+			align := t.Alignment()
+			if off := t.Field(start).Offset; off&(align-1) != 0 {
+				// Offset is less aligned than the containing type.
+				// Use offset to determine alignment.
+				align = 1 << uint(bits.TrailingZeros64(uint64(off)))
+			}
+			size := t.Field(next).End() - t.Field(start).Offset
+			if size > align {
+				break
+			}
+		}
 	}
 	return t.Field(next-1).End() - t.Field(start).Offset, next
 }
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 034a092..2dbb938 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -5,6 +5,7 @@
 package reflectdata
 
 import (
+	"encoding/binary"
 	"fmt"
 	"internal/buildcfg"
 	"os"
@@ -473,21 +474,25 @@
 
 // dnameData writes the contents of a reflect.name into s at offset ot.
 func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported bool) int {
-	if len(name) > 1<<16-1 {
-		base.Fatalf("name too long: %s", name)
+	if len(name) >= 1<<29 {
+		base.Fatalf("name too long: %d %s...", len(name), name[:1024])
 	}
-	if len(tag) > 1<<16-1 {
-		base.Fatalf("tag too long: %s", tag)
+	if len(tag) >= 1<<29 {
+		base.Fatalf("tag too long: %d %s...", len(tag), tag[:1024])
 	}
+	var nameLen [binary.MaxVarintLen64]byte
+	nameLenLen := binary.PutUvarint(nameLen[:], uint64(len(name)))
+	var tagLen [binary.MaxVarintLen64]byte
+	tagLenLen := binary.PutUvarint(tagLen[:], uint64(len(tag)))
 
 	// Encode name and tag. See reflect/type.go for details.
 	var bits byte
-	l := 1 + 2 + len(name)
+	l := 1 + nameLenLen + len(name)
 	if exported {
 		bits |= 1 << 0
 	}
 	if len(tag) > 0 {
-		l += 2 + len(tag)
+		l += tagLenLen + len(tag)
 		bits |= 1 << 1
 	}
 	if pkg != nil {
@@ -495,14 +500,12 @@
 	}
 	b := make([]byte, l)
 	b[0] = bits
-	b[1] = uint8(len(name) >> 8)
-	b[2] = uint8(len(name))
-	copy(b[3:], name)
+	copy(b[1:], nameLen[:nameLenLen])
+	copy(b[1+nameLenLen:], name)
 	if len(tag) > 0 {
-		tb := b[3+len(name):]
-		tb[0] = uint8(len(tag) >> 8)
-		tb[1] = uint8(len(tag))
-		copy(tb[2:], tag)
+		tb := b[1+nameLenLen+len(name):]
+		copy(tb, tagLen[:tagLenLen])
+		copy(tb[tagLenLen:], tag)
 	}
 
 	ot = int(s.WriteBytes(base.Ctxt, int64(ot), b))
@@ -666,7 +669,7 @@
 // tflag is documented in reflect/type.go.
 //
 // tflag values must be kept in sync with copies in:
-//	cmd/compile/internal/gc/reflect.go
+//	cmd/compile/internal/reflectdata/reflect.go
 //	cmd/link/internal/ld/decodesym.go
 //	reflect/type.go
 //	runtime/type.go
@@ -1109,6 +1112,15 @@
 		}
 		ot = objw.Uint32(lsym, ot, flags)
 		ot = dextratype(lsym, ot, t, 0)
+		if u := t.Underlying(); u != t {
+			// If t is a named map type, also keep the underlying map
+			// type live in the binary. This is important to make sure that
+			// a named map and that same map cast to its underlying type via
+			// reflection, use the same hash function. See issue 37716.
+			r := obj.Addrel(lsym)
+			r.Sym = writeType(u)
+			r.Type = objabi.R_KEEP
+		}
 
 	case types.TPTR:
 		if t.Elem().Kind() == types.TANY {
@@ -1490,8 +1502,8 @@
 	// will be equal for the above checks, but different in DWARF output.
 	// Sort by source position to ensure deterministic order.
 	// See issues 27013 and 30202.
-	if a[i].t.Kind() == types.TINTER && a[i].t.Methods().Len() > 0 {
-		return a[i].t.Methods().Index(0).Pos.Before(a[j].t.Methods().Index(0).Pos)
+	if a[i].t.Kind() == types.TINTER && a[i].t.AllMethods().Len() > 0 {
+		return a[i].t.AllMethods().Index(0).Pos.Before(a[j].t.AllMethods().Index(0).Pos)
 	}
 	return false
 }
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index 4ffa047..a8393a1 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -147,13 +147,6 @@
 
 	// Given the name for a compound type, returns the name we should use
 	// for the parts of that compound type.
-	SplitString(LocalSlot) (LocalSlot, LocalSlot)
-	SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
-	SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
-	SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
-	SplitStruct(LocalSlot, int) LocalSlot
-	SplitArray(LocalSlot) LocalSlot              // array must be length 1
-	SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
 	SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot
 
 	// DerefItab dereferences an itab function
diff --git a/src/cmd/compile/internal/ssa/copyelim.go b/src/cmd/compile/internal/ssa/copyelim.go
index 5954d3b..17f6512 100644
--- a/src/cmd/compile/internal/ssa/copyelim.go
+++ b/src/cmd/compile/internal/ssa/copyelim.go
@@ -26,7 +26,7 @@
 
 	// Update named values.
 	for _, name := range f.Names {
-		values := f.NamedValues[name]
+		values := f.NamedValues[*name]
 		for i, v := range values {
 			if v.Op == OpCopy {
 				values[i] = v.Args[0]
diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go
index 96b552e..5d10dfe 100644
--- a/src/cmd/compile/internal/ssa/deadcode.go
+++ b/src/cmd/compile/internal/ssa/deadcode.go
@@ -223,7 +223,7 @@
 	for _, name := range f.Names {
 		j := 0
 		s.clear()
-		values := f.NamedValues[name]
+		values := f.NamedValues[*name]
 		for _, v := range values {
 			if live[v.ID] && !s.contains(v.ID) {
 				values[j] = v
@@ -232,19 +232,19 @@
 			}
 		}
 		if j == 0 {
-			delete(f.NamedValues, name)
+			delete(f.NamedValues, *name)
 		} else {
 			f.Names[i] = name
 			i++
 			for k := len(values) - 1; k >= j; k-- {
 				values[k] = nil
 			}
-			f.NamedValues[name] = values[:j]
+			f.NamedValues[*name] = values[:j]
 		}
 	}
 	clearNames := f.Names[i:]
 	for j := range clearNames {
-		clearNames[j] = LocalSlot{}
+		clearNames[j] = nil
 	}
 	f.Names = f.Names[:i]
 
diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go
index 0ca435e..8e28723 100644
--- a/src/cmd/compile/internal/ssa/debug.go
+++ b/src/cmd/compile/internal/ssa/debug.go
@@ -7,10 +7,13 @@
 import (
 	"cmd/compile/internal/abi"
 	"cmd/compile/internal/ir"
+	"cmd/compile/internal/types"
 	"cmd/internal/dwarf"
 	"cmd/internal/obj"
+	"cmd/internal/src"
 	"encoding/hex"
 	"fmt"
+	"internal/buildcfg"
 	"math/bits"
 	"sort"
 	"strings"
@@ -335,6 +338,216 @@
 	return strings.Join(strs, "")
 }
 
+// slotCanonicalizer is a table used to lookup and canonicalize
+// LocalSlot's in a type insensitive way (e.g. taking into account the
+// base name, offset, and width of the slot, but ignoring the slot
+// type).
+type slotCanonicalizer struct {
+	slmap  map[slotKey]SlKeyIdx
+	slkeys []LocalSlot
+}
+
+func newSlotCanonicalizer() *slotCanonicalizer {
+	return &slotCanonicalizer{
+		slmap:  make(map[slotKey]SlKeyIdx),
+		slkeys: []LocalSlot{LocalSlot{N: nil}},
+	}
+}
+
+type SlKeyIdx uint32
+
+const noSlot = SlKeyIdx(0)
+
+// slotKey is a type-insensitive encapsulation of a LocalSlot; it
+// is used to key a map within slotCanonicalizer.
+type slotKey struct {
+	name        *ir.Name
+	offset      int64
+	width       int64
+	splitOf     SlKeyIdx // idx in slkeys slice in slotCanonicalizer
+	splitOffset int64
+}
+
+// lookup looks up a LocalSlot in the slot canonicalizer "sc", returning
+// a canonical index for the slot, and adding it to the table if need
+// be. Return value is the canonical slot index, and a boolean indicating
+// whether the slot was found in the table already (TRUE => found).
+func (sc *slotCanonicalizer) lookup(ls LocalSlot) (SlKeyIdx, bool) {
+	split := noSlot
+	if ls.SplitOf != nil {
+		split, _ = sc.lookup(*ls.SplitOf)
+	}
+	k := slotKey{
+		name: ls.N, offset: ls.Off, width: ls.Type.Width,
+		splitOf: split, splitOffset: ls.SplitOffset,
+	}
+	if idx, ok := sc.slmap[k]; ok {
+		return idx, true
+	}
+	rv := SlKeyIdx(len(sc.slkeys))
+	sc.slkeys = append(sc.slkeys, ls)
+	sc.slmap[k] = rv
+	return rv, false
+}
+
+func (sc *slotCanonicalizer) canonSlot(idx SlKeyIdx) LocalSlot {
+	return sc.slkeys[idx]
+}
+
+// PopulateABIInRegArgOps examines the entry block of the function
+// and looks for incoming parameters that have missing or partial
+// OpArg{Int,Float}Reg values, inserting additional values in
+// cases where they are missing. Example:
+//
+//      func foo(s string, used int, notused int) int {
+//        return len(s) + used
+//      }
+//
+// In the function above, the incoming parameter "used" is fully live,
+// "notused" is not live, and "s" is partially live (only the length
+// field of the string is used). At the point where debug value
+// analysis runs, we might expect to see an entry block with:
+//
+//   b1:
+//     v4 = ArgIntReg <uintptr> {s+8} [0] : BX
+//     v5 = ArgIntReg <int> {used} [0] : CX
+//
+// While this is an accurate picture of the live incoming params,
+// we also want to have debug locations for non-live params (or
+// their non-live pieces), e.g. something like
+//
+//   b1:
+//     v9 = ArgIntReg <*uint8> {s+0} [0] : AX
+//     v4 = ArgIntReg <uintptr> {s+8} [0] : BX
+//     v5 = ArgIntReg <int> {used} [0] : CX
+//     v10 = ArgIntReg <int> {unused} [0] : DI
+//
+// This function examines the live OpArg{Int,Float}Reg values and
+// synthesizes new (dead) values for the non-live params or the
+// non-live pieces of partially live params.
+//
+func PopulateABIInRegArgOps(f *Func) {
+	pri := f.ABISelf.ABIAnalyzeFuncType(f.Type.FuncType())
+
+	// When manufacturing new slots that correspond to splits of
+	// composite parameters, we want to avoid creating a new sub-slot
+	// that differs from some existing sub-slot only by type, since
+	// the debug location analysis will treat that slot as a separate
+	// entity. To achieve this, create a lookup table of existing
+	// slots that is type-insenstitive.
+	sc := newSlotCanonicalizer()
+	for _, sl := range f.Names {
+		sc.lookup(*sl)
+	}
+
+	// Add slot -> value entry to f.NamedValues if not already present.
+	addToNV := func(v *Value, sl LocalSlot) {
+		values, ok := f.NamedValues[sl]
+		if !ok {
+			// Haven't seen this slot yet.
+			sla := f.localSlotAddr(sl)
+			f.Names = append(f.Names, sla)
+		} else {
+			for _, ev := range values {
+				if v == ev {
+					return
+				}
+			}
+		}
+		values = append(values, v)
+		f.NamedValues[sl] = values
+	}
+
+	newValues := []*Value{}
+
+	abiRegIndexToRegister := func(reg abi.RegIndex) int8 {
+		i := f.ABISelf.FloatIndexFor(reg)
+		if i >= 0 { // float PR
+			return f.Config.floatParamRegs[i]
+		} else {
+			return f.Config.intParamRegs[reg]
+		}
+	}
+
+	// Helper to construct a new OpArg{Float,Int}Reg op value.
+	var pos src.XPos
+	if len(f.Entry.Values) != 0 {
+		pos = f.Entry.Values[0].Pos
+	}
+	synthesizeOpIntFloatArg := func(n *ir.Name, t *types.Type, reg abi.RegIndex, sl LocalSlot) *Value {
+		aux := &AuxNameOffset{n, sl.Off}
+		op, auxInt := ArgOpAndRegisterFor(reg, f.ABISelf)
+		v := f.newValueNoBlock(op, t, pos)
+		v.AuxInt = auxInt
+		v.Aux = aux
+		v.Args = nil
+		v.Block = f.Entry
+		newValues = append(newValues, v)
+		addToNV(v, sl)
+		f.setHome(v, &f.Config.registers[abiRegIndexToRegister(reg)])
+		return v
+	}
+
+	// Make a pass through the entry block looking for
+	// OpArg{Int,Float}Reg ops. Record the slots they use in a table
+	// ("sc"). We use a type-insensitive lookup for the slot table,
+	// since the type we get from the ABI analyzer won't always match
+	// what the compiler uses when creating OpArg{Int,Float}Reg ops.
+	for _, v := range f.Entry.Values {
+		if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
+			aux := v.Aux.(*AuxNameOffset)
+			sl := LocalSlot{N: aux.Name, Type: v.Type, Off: aux.Offset}
+			// install slot in lookup table
+			idx, _ := sc.lookup(sl)
+			// add to f.NamedValues if not already present
+			addToNV(v, sc.canonSlot(idx))
+		} else if v.Op.IsCall() {
+			// if we hit a call, we've gone too far.
+			break
+		}
+	}
+
+	// Now make a pass through the ABI in-params, looking for params
+	// or pieces of params that we didn't encounter in the loop above.
+	for _, inp := range pri.InParams() {
+		if !isNamedRegParam(inp) {
+			continue
+		}
+		n := inp.Name.(*ir.Name)
+
+		// Param is spread across one or more registers. Walk through
+		// each piece to see whether we've seen an arg reg op for it.
+		types, offsets := inp.RegisterTypesAndOffsets()
+		for k, t := range types {
+			// Note: this recipe for creating a LocalSlot is designed
+			// to be compatible with the one used in expand_calls.go
+			// as opposed to decompose.go. The expand calls code just
+			// takes the base name and creates an offset into it,
+			// without using the SplitOf/SplitOffset fields. The code
+			// in decompose.go does the opposite -- it creates a
+			// LocalSlot object with "Off" set to zero, but with
+			// SplitOf pointing to a parent slot, and SplitOffset
+			// holding the offset into the parent object.
+			pieceSlot := LocalSlot{N: n, Type: t, Off: offsets[k]}
+
+			// Look up this piece to see if we've seen a reg op
+			// for it. If not, create one.
+			_, found := sc.lookup(pieceSlot)
+			if !found {
+				// This slot doesn't appear in the map, meaning it
+				// corresponds to an in-param that is not live, or
+				// a portion of an in-param that is not live/used.
+				// Add a new dummy OpArg{Int,Float}Reg for it.
+				synthesizeOpIntFloatArg(n, t, inp.Registers[k],
+					pieceSlot)
+			}
+		}
+	}
+
+	// Insert the new values into the head of the block.
+	f.Entry.Values = append(newValues, f.Entry.Values...)
+}
+
 // BuildFuncDebug returns debug information for f.
 // f must be fully processed, so that each Value is where it will be when
 // machine code is emitted.
@@ -349,6 +562,10 @@
 	state.stackOffset = stackOffset
 	state.ctxt = ctxt
 
+	if buildcfg.Experiment.RegabiArgs {
+		PopulateABIInRegArgOps(f)
+	}
+
 	if state.loggingEnabled {
 		state.logf("Generating location lists for function %q\n", f.Name)
 	}
@@ -367,12 +584,12 @@
 	state.slots = state.slots[:0]
 	state.vars = state.vars[:0]
 	for i, slot := range f.Names {
-		state.slots = append(state.slots, slot)
+		state.slots = append(state.slots, *slot)
 		if ir.IsSynthetic(slot.N) {
 			continue
 		}
 
-		topSlot := &slot
+		topSlot := slot
 		for topSlot.SplitOf != nil {
 			topSlot = topSlot.SplitOf
 		}
@@ -436,7 +653,7 @@
 		if ir.IsSynthetic(slot.N) {
 			continue
 		}
-		for _, value := range f.NamedValues[slot] {
+		for _, value := range f.NamedValues[*slot] {
 			state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i))
 		}
 	}
@@ -898,8 +1115,14 @@
 			continue
 		}
 
+		mustBeFirst := func(v *Value) bool {
+			return v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() ||
+				v.Op == OpArgIntReg || v.Op == OpArgFloatReg
+		}
+
 		zeroWidthPending := false
-		apcChangedSize := 0 // size of changedVars for leading Args, Phi, ClosurePtr
+		blockPrologComplete := false // set to true at first non-zero-width op
+		apcChangedSize := 0          // size of changedVars for leading Args, Phi, ClosurePtr
 		// expect to see values in pattern (apc)* (zerowidth|real)*
 		for _, v := range b.Values {
 			slots := state.valueNames[v.ID]
@@ -908,16 +1131,16 @@
 
 			if opcodeTable[v.Op].zeroWidth {
 				if changed {
-					if hasAnyArgOp(v) || v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() {
+					if mustBeFirst(v) || v.Op == OpArg {
 						// These ranges begin at true beginning of block, not after first instruction
-						if zeroWidthPending {
-							panic(fmt.Errorf("Unexpected op '%s' mixed with OpArg/OpPhi/OpLoweredGetClosurePtr at beginning of block %s in %s\n%s", v.LongString(), b, b.Func.Name, b.Func))
+						if blockPrologComplete && mustBeFirst(v) {
+							panic(fmt.Errorf("Unexpected placement of op '%s' appearing after non-pseudo-op at beginning of block %s in %s\n%s", v.LongString(), b, b.Func.Name, b.Func))
 						}
 						apcChangedSize = len(state.changedVars.contents())
+						// Other zero-width ops must wait on a "real" op.
+						zeroWidthPending = true
 						continue
 					}
-					// Other zero-width ops must wait on a "real" op.
-					zeroWidthPending = true
 				}
 				continue
 			}
@@ -928,6 +1151,7 @@
 			// Not zero-width; i.e., a "real" instruction.
 
 			zeroWidthPending = false
+			blockPrologComplete = true
 			for i, varID := range state.changedVars.contents() {
 				if i < apcChangedSize { // buffered true start-of-block changes
 					state.updateVar(VarID(varID), v.Block, BlockStart)
diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go
index ba48b6b..753d69c 100644
--- a/src/cmd/compile/internal/ssa/decompose.go
+++ b/src/cmd/compile/internal/ssa/decompose.go
@@ -36,64 +36,65 @@
 	// accumulate new LocalSlots in newNames for addition after the iteration.  This decomposition is for
 	// builtin types with leaf components, and thus there is no need to reprocess the newly create LocalSlots.
 	var toDelete []namedVal
-	var newNames []LocalSlot
+	var newNames []*LocalSlot
 	for i, name := range f.Names {
 		t := name.Type
 		switch {
 		case t.IsInteger() && t.Size() > f.Config.RegSize:
-			hiName, loName := f.fe.SplitInt64(name)
-			newNames = append(newNames, hiName, loName)
-			for j, v := range f.NamedValues[name] {
+			hiName, loName := f.SplitInt64(name)
+			newNames = maybeAppend2(f, newNames, hiName, loName)
+			for j, v := range f.NamedValues[*name] {
 				if v.Op != OpInt64Make {
 					continue
 				}
-				f.NamedValues[hiName] = append(f.NamedValues[hiName], v.Args[0])
-				f.NamedValues[loName] = append(f.NamedValues[loName], v.Args[1])
+				f.NamedValues[*hiName] = append(f.NamedValues[*hiName], v.Args[0])
+				f.NamedValues[*loName] = append(f.NamedValues[*loName], v.Args[1])
 				toDelete = append(toDelete, namedVal{i, j})
 			}
 		case t.IsComplex():
-			rName, iName := f.fe.SplitComplex(name)
-			newNames = append(newNames, rName, iName)
-			for j, v := range f.NamedValues[name] {
+			rName, iName := f.SplitComplex(name)
+			newNames = maybeAppend2(f, newNames, rName, iName)
+			for j, v := range f.NamedValues[*name] {
 				if v.Op != OpComplexMake {
 					continue
 				}
-				f.NamedValues[rName] = append(f.NamedValues[rName], v.Args[0])
-				f.NamedValues[iName] = append(f.NamedValues[iName], v.Args[1])
+				f.NamedValues[*rName] = append(f.NamedValues[*rName], v.Args[0])
+				f.NamedValues[*iName] = append(f.NamedValues[*iName], v.Args[1])
 				toDelete = append(toDelete, namedVal{i, j})
 			}
 		case t.IsString():
-			ptrName, lenName := f.fe.SplitString(name)
-			newNames = append(newNames, ptrName, lenName)
-			for j, v := range f.NamedValues[name] {
+			ptrName, lenName := f.SplitString(name)
+			newNames = maybeAppend2(f, newNames, ptrName, lenName)
+			for j, v := range f.NamedValues[*name] {
 				if v.Op != OpStringMake {
 					continue
 				}
-				f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
-				f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
+				f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
+				f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
 				toDelete = append(toDelete, namedVal{i, j})
 			}
 		case t.IsSlice():
-			ptrName, lenName, capName := f.fe.SplitSlice(name)
-			newNames = append(newNames, ptrName, lenName, capName)
-			for j, v := range f.NamedValues[name] {
+			ptrName, lenName, capName := f.SplitSlice(name)
+			newNames = maybeAppend2(f, newNames, ptrName, lenName)
+			newNames = maybeAppend(f, newNames, capName)
+			for j, v := range f.NamedValues[*name] {
 				if v.Op != OpSliceMake {
 					continue
 				}
-				f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
-				f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
-				f.NamedValues[capName] = append(f.NamedValues[capName], v.Args[2])
+				f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
+				f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
+				f.NamedValues[*capName] = append(f.NamedValues[*capName], v.Args[2])
 				toDelete = append(toDelete, namedVal{i, j})
 			}
 		case t.IsInterface():
-			typeName, dataName := f.fe.SplitInterface(name)
-			newNames = append(newNames, typeName, dataName)
-			for j, v := range f.NamedValues[name] {
+			typeName, dataName := f.SplitInterface(name)
+			newNames = maybeAppend2(f, newNames, typeName, dataName)
+			for j, v := range f.NamedValues[*name] {
 				if v.Op != OpIMake {
 					continue
 				}
-				f.NamedValues[typeName] = append(f.NamedValues[typeName], v.Args[0])
-				f.NamedValues[dataName] = append(f.NamedValues[dataName], v.Args[1])
+				f.NamedValues[*typeName] = append(f.NamedValues[*typeName], v.Args[0])
+				f.NamedValues[*dataName] = append(f.NamedValues[*dataName], v.Args[1])
 				toDelete = append(toDelete, namedVal{i, j})
 			}
 		case t.IsFloat():
@@ -107,6 +108,18 @@
 	f.Names = append(f.Names, newNames...)
 }
 
+func maybeAppend(f *Func, ss []*LocalSlot, s *LocalSlot) []*LocalSlot {
+	if _, ok := f.NamedValues[*s]; !ok {
+		f.NamedValues[*s] = nil
+		return append(ss, s)
+	}
+	return ss
+}
+
+func maybeAppend2(f *Func, ss []*LocalSlot, s1, s2 *LocalSlot) []*LocalSlot {
+	return maybeAppend(f, maybeAppend(f, ss, s1), s2)
+}
+
 func decomposeBuiltInPhi(v *Value) {
 	switch {
 	case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize:
@@ -230,7 +243,7 @@
 	}
 	// Split up named values into their components.
 	i := 0
-	var newNames []LocalSlot
+	var newNames []*LocalSlot
 	for _, name := range f.Names {
 		t := name.Type
 		switch {
@@ -250,7 +263,7 @@
 // decomposeUserArrayInto creates names for the element(s) of arrays referenced
 // by name where possible, and appends those new names to slots, which is then
 // returned.
-func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
+func decomposeUserArrayInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
 	t := name.Type
 	if t.NumElem() == 0 {
 		// TODO(khr): Not sure what to do here.  Probably nothing.
@@ -261,20 +274,20 @@
 		// shouldn't get here due to CanSSA
 		f.Fatalf("array not of size 1")
 	}
-	elemName := f.fe.SplitArray(name)
+	elemName := f.SplitArray(name)
 	var keep []*Value
-	for _, v := range f.NamedValues[name] {
+	for _, v := range f.NamedValues[*name] {
 		if v.Op != OpArrayMake1 {
 			keep = append(keep, v)
 			continue
 		}
-		f.NamedValues[elemName] = append(f.NamedValues[elemName], v.Args[0])
+		f.NamedValues[*elemName] = append(f.NamedValues[*elemName], v.Args[0])
 	}
 	if len(keep) == 0 {
 		// delete the name for the array as a whole
-		delete(f.NamedValues, name)
+		delete(f.NamedValues, *name)
 	} else {
-		f.NamedValues[name] = keep
+		f.NamedValues[*name] = keep
 	}
 
 	if t.Elem().IsArray() {
@@ -289,38 +302,38 @@
 // decomposeUserStructInto creates names for the fields(s) of structs referenced
 // by name where possible, and appends those new names to slots, which is then
 // returned.
-func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
-	fnames := []LocalSlot{} // slots for struct in name
+func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
+	fnames := []*LocalSlot{} // slots for struct in name
 	t := name.Type
 	n := t.NumFields()
 
 	for i := 0; i < n; i++ {
-		fs := f.fe.SplitStruct(name, i)
+		fs := f.SplitStruct(name, i)
 		fnames = append(fnames, fs)
 		// arrays and structs will be decomposed further, so
 		// there's no need to record a name
 		if !fs.Type.IsArray() && !fs.Type.IsStruct() {
-			slots = append(slots, fs)
+			slots = maybeAppend(f, slots, fs)
 		}
 	}
 
 	makeOp := StructMakeOp(n)
 	var keep []*Value
 	// create named values for each struct field
-	for _, v := range f.NamedValues[name] {
+	for _, v := range f.NamedValues[*name] {
 		if v.Op != makeOp {
 			keep = append(keep, v)
 			continue
 		}
 		for i := 0; i < len(fnames); i++ {
-			f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], v.Args[i])
+			f.NamedValues[*fnames[i]] = append(f.NamedValues[*fnames[i]], v.Args[i])
 		}
 	}
 	if len(keep) == 0 {
 		// delete the name for the struct as a whole
-		delete(f.NamedValues, name)
+		delete(f.NamedValues, *name)
 	} else {
-		f.NamedValues[name] = keep
+		f.NamedValues[*name] = keep
 	}
 
 	// now that this f.NamedValues contains values for the struct
@@ -328,10 +341,10 @@
 	for i := 0; i < n; i++ {
 		if name.Type.FieldType(i).IsStruct() {
 			slots = decomposeUserStructInto(f, fnames[i], slots)
-			delete(f.NamedValues, fnames[i])
+			delete(f.NamedValues, *fnames[i])
 		} else if name.Type.FieldType(i).IsArray() {
 			slots = decomposeUserArrayInto(f, fnames[i], slots)
-			delete(f.NamedValues, fnames[i])
+			delete(f.NamedValues, *fnames[i])
 		}
 	}
 	return slots
@@ -416,9 +429,10 @@
 	locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key
 }
 
-// deleteNamedVals removes particular values with debugger names from f's naming data structures
+// deleteNamedVals removes particular values with debugger names from f's naming data structures,
+// removes all values with OpInvalid, and re-sorts the list of Names.
 func deleteNamedVals(f *Func, toDelete []namedVal) {
-	// Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalid pending indices.
+	// Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalidate pending indices.
 	sort.Slice(toDelete, func(i, j int) bool {
 		if toDelete[i].locIndex != toDelete[j].locIndex {
 			return toDelete[i].locIndex > toDelete[j].locIndex
@@ -430,16 +444,36 @@
 	// Get rid of obsolete names
 	for _, d := range toDelete {
 		loc := f.Names[d.locIndex]
-		vals := f.NamedValues[loc]
+		vals := f.NamedValues[*loc]
 		l := len(vals) - 1
 		if l > 0 {
 			vals[d.valIndex] = vals[l]
-			f.NamedValues[loc] = vals[:l]
-		} else {
-			delete(f.NamedValues, loc)
-			l = len(f.Names) - 1
-			f.Names[d.locIndex] = f.Names[l]
-			f.Names = f.Names[:l]
+		}
+		vals[l] = nil
+		f.NamedValues[*loc] = vals[:l]
+	}
+	// Delete locations with no values attached.
+	end := len(f.Names)
+	for i := len(f.Names) - 1; i >= 0; i-- {
+		loc := f.Names[i]
+		vals := f.NamedValues[*loc]
+		last := len(vals)
+		for j := len(vals) - 1; j >= 0; j-- {
+			if vals[j].Op == OpInvalid {
+				last--
+				vals[j] = vals[last]
+				vals[last] = nil
+			}
+		}
+		if last < len(vals) {
+			f.NamedValues[*loc] = vals[:last]
+		}
+		if len(vals) == 0 {
+			delete(f.NamedValues, *loc)
+			end--
+			f.Names[i] = f.Names[end]
+			f.Names[end] = nil
 		}
 	}
+	f.Names = f.Names[:end]
 }
diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go
index 2852753..7e973ab 100644
--- a/src/cmd/compile/internal/ssa/expand_calls.go
+++ b/src/cmd/compile/internal/ssa/expand_calls.go
@@ -243,10 +243,10 @@
 }
 
 // splitSlots splits one "field" (specified by sfx, offset, and ty) out of the LocalSlots in ls and returns the new LocalSlots this generates.
-func (x *expandState) splitSlots(ls []LocalSlot, sfx string, offset int64, ty *types.Type) []LocalSlot {
-	var locs []LocalSlot
+func (x *expandState) splitSlots(ls []*LocalSlot, sfx string, offset int64, ty *types.Type) []*LocalSlot {
+	var locs []*LocalSlot
 	for i := range ls {
-		locs = append(locs, x.f.fe.SplitSlot(&ls[i], sfx, offset, ty))
+		locs = append(locs, x.f.SplitSlot(ls[i], sfx, offset, ty))
 	}
 	return locs
 }
@@ -301,13 +301,13 @@
 // It emits the code necessary to implement the leaf select operation that leads to the root.
 //
 // TODO when registers really arrive, must also decompose anything split across two registers or registers and memory.
-func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []LocalSlot {
+func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []*LocalSlot {
 	if x.debug {
 		x.indent(3)
 		defer x.indent(-3)
 		x.Printf("rewriteSelect(%s; %s; memOff=%d; regOff=%d)\n", leaf.LongString(), selector.LongString(), offset, regOffset)
 	}
-	var locs []LocalSlot
+	var locs []*LocalSlot
 	leafType := leaf.Type
 	if len(selector.Args) > 0 {
 		w := selector.Args[0]
@@ -477,7 +477,7 @@
 
 	case OpStructSelect:
 		w := selector.Args[0]
-		var ls []LocalSlot
+		var ls []*LocalSlot
 		if w.Type.Kind() != types.TSTRUCT { // IData artifact
 			ls = x.rewriteSelect(leaf, w, offset, regOffset)
 		} else {
@@ -485,7 +485,7 @@
 			ls = x.rewriteSelect(leaf, w, offset+w.Type.FieldOff(fldi), regOffset+x.regOffset(w.Type, fldi))
 			if w.Op != OpIData {
 				for _, l := range ls {
-					locs = append(locs, x.f.fe.SplitStruct(l, int(selector.AuxInt)))
+					locs = append(locs, x.f.SplitStruct(l, int(selector.AuxInt)))
 				}
 			}
 		}
@@ -662,7 +662,7 @@
 func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
 
 	pa := x.prAssignForArg(source)
-	var locs []LocalSlot
+	var locs []*LocalSlot
 	for _, s := range x.namedSelects[source] {
 		locs = append(locs, x.f.Names[s.locIndex])
 	}
@@ -756,12 +756,15 @@
 	return nil
 }
 
-func (x *expandState) splitSlotsIntoNames(locs []LocalSlot, suffix string, off int64, rt *types.Type, w *Value) {
+func (x *expandState) splitSlotsIntoNames(locs []*LocalSlot, suffix string, off int64, rt *types.Type, w *Value) {
 	wlocs := x.splitSlots(locs, suffix, off, rt)
 	for _, l := range wlocs {
-		x.f.NamedValues[l] = append(x.f.NamedValues[l], w)
+		old, ok := x.f.NamedValues[*l]
+		x.f.NamedValues[*l] = append(old, w)
+		if !ok {
+			x.f.Names = append(x.f.Names, l)
+		}
 	}
-	x.f.Names = append(x.f.Names, wlocs...)
 }
 
 // decomposeLoad is a helper for storeArgOrLoad.
@@ -826,7 +829,7 @@
 // storeOneArg creates a decomposed (one step) arg that is then stored.
 // pos and b locate the store instruction, source is the "base" of the value input,
 // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases.
-func storeOneArg(x *expandState, pos src.XPos, b *Block, locs []LocalSlot, suffix string, source, mem *Value, t *types.Type, argOffset, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
+func storeOneArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suffix string, source, mem *Value, t *types.Type, argOffset, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
 	if x.debug {
 		x.indent(3)
 		defer x.indent(-3)
@@ -848,7 +851,7 @@
 	return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc)
 }
 
-func storeTwoArg(x *expandState, pos src.XPos, b *Block, locs []LocalSlot, suffix1 string, suffix2 string, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
+func storeTwoArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suffix1 string, suffix2 string, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
 	mem = storeOneArg(x, pos, b, locs, suffix1, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1))
 	pos = pos.WithNotStmt()
 	t1Size := t1.Size()
@@ -1168,7 +1171,7 @@
 	for i, name := range f.Names {
 		t := name.Type
 		if x.isAlreadyExpandedAggregateType(t) {
-			for j, v := range f.NamedValues[name] {
+			for j, v := range f.NamedValues[*name] {
 				if v.Op == OpSelectN || v.Op == OpArg && x.isAlreadyExpandedAggregateType(v.Type) {
 					ns := x.namedSelects[v]
 					x.namedSelects[v] = append(ns, namedVal{locIndex: i, valIndex: j})
@@ -1477,10 +1480,10 @@
 		// Leaf types may have debug locations
 		if !x.isAlreadyExpandedAggregateType(v.Type) {
 			for _, l := range locs {
-				if _, ok := f.NamedValues[l]; !ok {
+				if _, ok := f.NamedValues[*l]; !ok {
 					f.Names = append(f.Names, l)
 				}
-				f.NamedValues[l] = append(f.NamedValues[l], v)
+				f.NamedValues[*l] = append(f.NamedValues[*l], v)
 			}
 			continue
 		}
@@ -1553,7 +1556,7 @@
 	// Step 6: elide any copies introduced.
 	// Update named values.
 	for _, name := range f.Names {
-		values := f.NamedValues[name]
+		values := f.NamedValues[*name]
 		for i, v := range values {
 			if v.Op == OpCopy {
 				a := v.Args[0]
@@ -1714,21 +1717,6 @@
 	} else {
 		w = baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux)
 	}
-	// If we are creating an OpArgIntReg/OpArgFloatReg that
-	// corresponds to an in-param that fits entirely in a register,
-	// then enter it into the name/value table. The LocalSlot
-	// is somewhat fictitious, since there is no incoming live
-	// memory version of the parameter, but we need an entry in
-	// NamedValues in order for ssa debug tracking to include
-	// the value in the tracking analysis.
-	if len(pa.Registers) == 1 {
-		loc := LocalSlot{N: aux.Name, Type: t, Off: 0}
-		values, ok := x.f.NamedValues[loc]
-		if !ok {
-			x.f.Names = append(x.f.Names, loc)
-		}
-		x.f.NamedValues[loc] = append(values, w)
-	}
 	x.commonArgs[key] = w
 	if toReplace != nil {
 		toReplace.copyOf(w)
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index 32e6d09..8ed8a0c 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -73,36 +73,6 @@
 	n.Class = ir.PAUTO
 	return n
 }
-func (d TestFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
-	return LocalSlot{N: s.N, Type: testTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.Int, Off: s.Off + 8}
-}
-func (d TestFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) {
-	return LocalSlot{N: s.N, Type: testTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.BytePtr, Off: s.Off + 8}
-}
-func (d TestFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) {
-	return LocalSlot{N: s.N, Type: s.Type.Elem().PtrTo(), Off: s.Off},
-		LocalSlot{N: s.N, Type: testTypes.Int, Off: s.Off + 8},
-		LocalSlot{N: s.N, Type: testTypes.Int, Off: s.Off + 16}
-}
-func (d TestFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
-	if s.Type.Size() == 16 {
-		return LocalSlot{N: s.N, Type: testTypes.Float64, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.Float64, Off: s.Off + 8}
-	}
-	return LocalSlot{N: s.N, Type: testTypes.Float32, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.Float32, Off: s.Off + 4}
-}
-func (d TestFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
-	if s.Type.IsSigned() {
-		return LocalSlot{N: s.N, Type: testTypes.Int32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: testTypes.UInt32, Off: s.Off}
-	}
-	return LocalSlot{N: s.N, Type: testTypes.UInt32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: testTypes.UInt32, Off: s.Off}
-}
-func (d TestFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
-	return LocalSlot{N: s.N, Type: s.Type.FieldType(i), Off: s.Off + s.Type.FieldOff(i)}
-}
-func (d TestFrontend) SplitArray(s LocalSlot) LocalSlot {
-	return LocalSlot{N: s.N, Type: s.Type.Elem(), Off: s.Off}
-}
-
 func (d TestFrontend) SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot {
 	return LocalSlot{N: parent.N, Type: t, Off: offset}
 }
diff --git a/src/cmd/compile/internal/ssa/flags_amd64_test.s b/src/cmd/compile/internal/ssa/flags_amd64_test.s
index 8bd8701..7402f6b 100644
--- a/src/cmd/compile/internal/ssa/flags_amd64_test.s
+++ b/src/cmd/compile/internal/ssa/flags_amd64_test.s
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64
-
 #include "textflag.h"
 
 TEXT ·asmAddFlags(SB),NOSPLIT,$0-24
diff --git a/src/cmd/compile/internal/ssa/flags_arm64_test.s b/src/cmd/compile/internal/ssa/flags_arm64_test.s
index f201bcc..639d7e3 100644
--- a/src/cmd/compile/internal/ssa/flags_arm64_test.s
+++ b/src/cmd/compile/internal/ssa/flags_arm64_test.s
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build arm64
-
 #include "textflag.h"
 
 TEXT ·asmAddFlags(SB),NOSPLIT,$0-24
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index 378a73a..fac876c 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -6,6 +6,7 @@
 
 import (
 	"cmd/compile/internal/abi"
+	"cmd/compile/internal/base"
 	"cmd/compile/internal/types"
 	"cmd/internal/src"
 	"crypto/sha1"
@@ -61,7 +62,11 @@
 	NamedValues map[LocalSlot][]*Value
 	// Names is a copy of NamedValues.Keys. We keep a separate list
 	// of keys to make iteration order deterministic.
-	Names []LocalSlot
+	Names []*LocalSlot
+	// Canonicalize root/top-level local slots, and canonicalize their pieces.
+	// Because LocalSlot pieces refer to their parents with a pointer, this ensures that equivalent slots really are equal.
+	CanonicalLocalSlots  map[LocalSlot]*LocalSlot
+	CanonicalLocalSplits map[LocalSlotSplitKey]*LocalSlot
 
 	// RegArgs is a slice of register-memory pairs that must be spilled and unspilled in the uncommon path of function entry.
 	RegArgs []Spill
@@ -87,10 +92,16 @@
 	constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
 }
 
+type LocalSlotSplitKey struct {
+	parent *LocalSlot
+	Off    int64       // offset of slot in N
+	Type   *types.Type // type of slot
+}
+
 // NewFunc returns a new, empty function object.
 // Caller must set f.Config and f.Cache before using f.
 func NewFunc(fe Frontend) *Func {
-	return &Func{fe: fe, NamedValues: make(map[LocalSlot][]*Value)}
+	return &Func{fe: fe, NamedValues: make(map[LocalSlot][]*Value), CanonicalLocalSlots: make(map[LocalSlot]*LocalSlot), CanonicalLocalSplits: make(map[LocalSlotSplitKey]*LocalSlot)}
 }
 
 // NumBlocks returns an integer larger than the id of any Block in the Func.
@@ -193,6 +204,101 @@
 	f.Cache.deadcode.liveOrderStmts = liveOrderStmts
 }
 
+func (f *Func) localSlotAddr(slot LocalSlot) *LocalSlot {
+	a, ok := f.CanonicalLocalSlots[slot]
+	if !ok {
+		a = new(LocalSlot)
+		*a = slot // don't escape slot
+		f.CanonicalLocalSlots[slot] = a
+	}
+	return a
+}
+
+func (f *Func) SplitString(name *LocalSlot) (*LocalSlot, *LocalSlot) {
+	ptrType := types.NewPtr(types.Types[types.TUINT8])
+	lenType := types.Types[types.TINT]
+	// Split this string up into two separate variables.
+	p := f.SplitSlot(name, ".ptr", 0, ptrType)
+	l := f.SplitSlot(name, ".len", ptrType.Size(), lenType)
+	return p, l
+}
+
+func (f *Func) SplitInterface(name *LocalSlot) (*LocalSlot, *LocalSlot) {
+	n := name.N
+	u := types.Types[types.TUINTPTR]
+	t := types.NewPtr(types.Types[types.TUINT8])
+	// Split this interface up into two separate variables.
+	sfx := ".itab"
+	if n.Type().IsEmptyInterface() {
+		sfx = ".type"
+	}
+	c := f.SplitSlot(name, sfx, 0, u) // see comment in typebits.Set
+	d := f.SplitSlot(name, ".data", u.Size(), t)
+	return c, d
+}
+
+func (f *Func) SplitSlice(name *LocalSlot) (*LocalSlot, *LocalSlot, *LocalSlot) {
+	ptrType := types.NewPtr(name.Type.Elem())
+	lenType := types.Types[types.TINT]
+	p := f.SplitSlot(name, ".ptr", 0, ptrType)
+	l := f.SplitSlot(name, ".len", ptrType.Size(), lenType)
+	c := f.SplitSlot(name, ".cap", ptrType.Size()+lenType.Size(), lenType)
+	return p, l, c
+}
+
+func (f *Func) SplitComplex(name *LocalSlot) (*LocalSlot, *LocalSlot) {
+	s := name.Type.Size() / 2
+	var t *types.Type
+	if s == 8 {
+		t = types.Types[types.TFLOAT64]
+	} else {
+		t = types.Types[types.TFLOAT32]
+	}
+	r := f.SplitSlot(name, ".real", 0, t)
+	i := f.SplitSlot(name, ".imag", t.Size(), t)
+	return r, i
+}
+
+func (f *Func) SplitInt64(name *LocalSlot) (*LocalSlot, *LocalSlot) {
+	var t *types.Type
+	if name.Type.IsSigned() {
+		t = types.Types[types.TINT32]
+	} else {
+		t = types.Types[types.TUINT32]
+	}
+	if f.Config.BigEndian {
+		return f.SplitSlot(name, ".hi", 0, t), f.SplitSlot(name, ".lo", t.Size(), types.Types[types.TUINT32])
+	}
+	return f.SplitSlot(name, ".hi", t.Size(), t), f.SplitSlot(name, ".lo", 0, types.Types[types.TUINT32])
+}
+
+func (f *Func) SplitStruct(name *LocalSlot, i int) *LocalSlot {
+	st := name.Type
+	return f.SplitSlot(name, st.FieldName(i), st.FieldOff(i), st.FieldType(i))
+}
+func (f *Func) SplitArray(name *LocalSlot) *LocalSlot {
+	n := name.N
+	at := name.Type
+	if at.NumElem() != 1 {
+		base.FatalfAt(n.Pos(), "bad array size")
+	}
+	et := at.Elem()
+	return f.SplitSlot(name, "[0]", 0, et)
+}
+
+func (f *Func) SplitSlot(name *LocalSlot, sfx string, offset int64, t *types.Type) *LocalSlot {
+	lssk := LocalSlotSplitKey{name, offset, t}
+	if als, ok := f.CanonicalLocalSplits[lssk]; ok {
+		return als
+	}
+	// Note: the _ field may appear several times.  But
+	// have no fear, identically-named but distinct Autos are
+	// ok, albeit maybe confusing for a debugger.
+	ls := f.fe.SplitSlot(name, sfx, offset, t)
+	f.CanonicalLocalSplits[lssk] = &ls
+	return &ls
+}
+
 // newValue allocates a new Value with the given fields and places it at the end of b.Values.
 func (f *Func) newValue(op Op, t *types.Type, b *Block, pos src.XPos) *Value {
 	var v *Value
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index ec91ea1..4cd0073 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -2216,3 +2216,22 @@
 (MOVOstore [dstOff] {dstSym} ptr (MOVOload [srcOff] {srcSym} (SB) _) mem) && symIsRO(srcSym) =>
   (MOVQstore [dstOff+8] {dstSym} ptr (MOVQconst [int64(read64(srcSym, int64(srcOff)+8, config.ctxt.Arch.ByteOrder))])
     (MOVQstore [dstOff] {dstSym} ptr (MOVQconst [int64(read64(srcSym, int64(srcOff), config.ctxt.Arch.ByteOrder))]) mem))
+
+// Arch-specific inlining for small or disjoint runtime.memmove
+// Match post-lowering calls, memory version.
+(SelectN [0] call:(CALLstatic {sym} s1:(MOVQstoreconst _ [sc] s2:(MOVQstore _ src s3:(MOVQstore _ dst mem)))))
+	&& sc.Val64() >= 0
+	&& isSameCall(sym, "runtime.memmove")
+	&& s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1
+	&& isInlinableMemmove(dst, src, sc.Val64(), config)
+	&& clobber(s1, s2, s3, call)
+	=> (Move [sc.Val64()] dst src mem)
+
+// Match post-lowering calls, register version.
+(SelectN [0] call:(CALLstatic {sym} dst src (MOVQconst [sz]) mem))
+	&& sz >= 0
+	&& isSameCall(sym, "runtime.memmove")
+	&& call.Uses == 1
+	&& isInlinableMemmove(dst, src, sz, config)
+	&& clobber(call)
+	=> (Move [sz] dst src mem)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index 3d27594..62699f2 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -2859,3 +2859,12 @@
 (MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))])
 (MOVWUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))])
 (MOVDload  [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read64(sym, int64(off), config.ctxt.Arch.ByteOrder))])
+
+// Arch-specific inlining for small or disjoint runtime.memmove
+(SelectN [0] call:(CALLstatic {sym} s1:(MOVDstore _ (MOVDconst [sz]) s2:(MOVDstore  _ src s3:(MOVDstore {t} _ dst mem)))))
+	&& sz >= 0
+	&& isSameCall(sym, "runtime.memmove")
+	&& s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1
+	&& isInlinableMemmove(dst, src, sz, config)
+	&& clobber(s1, s2, s3, call)
+	=> (Move [sz] dst src mem)
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index aad7600..5cbc70c 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -2065,7 +2065,7 @@
 (SelectN [0] call:(StaticCall {sym} s1:(Store _ (Const(64|32) [sz]) s2:(Store  _ src s3:(Store {t} _ dst mem)))))
 	&& sz >= 0
 	&& isSameCall(sym, "runtime.memmove")
-	&& t.IsPtr() // avoids TUINTPTR, see issue 30061
+	&& t.IsPtr() // avoids TUNSAFEPTR, see issue 30061
 	&& s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1
 	&& isInlinableMemmove(dst, src, int64(sz), config)
 	&& clobber(s1, s2, s3, call)
@@ -2076,7 +2076,7 @@
 	&& sz >= 0
 	&& call.Uses == 1 // this will exclude all calls with results
 	&& isSameCall(sym, "runtime.memmove")
-	&& dst.Type.IsPtr() // avoids TUINTPTR, see issue 30061
+	&& dst.Type.IsPtr() // avoids TUNSAFEPTR, see issue 30061
 	&& isInlinableMemmove(dst, src, int64(sz), config)
 	&& clobber(call)
 	=> (Move {dst.Type.Elem()} [int64(sz)] dst src mem)
@@ -2086,7 +2086,7 @@
 	&& sz >= 0
 	&& call.Uses == 1 // this will exclude all calls with results
 	&& isSameCall(sym, "runtime.memmove")
-	&& dst.Type.IsPtr() // avoids TUINTPTR, see issue 30061
+	&& dst.Type.IsPtr() // avoids TUNSAFEPTR, see issue 30061
 	&& isInlinableMemmove(dst, src, int64(sz), config)
 	&& clobber(call)
 	=> (Move {dst.Type.Elem()} [int64(sz)] dst src mem)
diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go
index a7fd73a..6abdb0d 100644
--- a/src/cmd/compile/internal/ssa/layout.go
+++ b/src/cmd/compile/internal/ssa/layout.go
@@ -12,26 +12,10 @@
 }
 
 // Register allocation may use a different order which has constraints
-// imposed by the linear-scan algorithm. Note that f.pass here is
-// regalloc, so the switch is conditional on -d=ssa/regalloc/test=N
+// imposed by the linear-scan algorithm.
 func layoutRegallocOrder(f *Func) []*Block {
-
-	switch f.pass.test {
-	case 0: // layout order
-		return layoutOrder(f)
-	case 1: // existing block order
-		return f.Blocks
-	case 2: // reverse of postorder; legal, but usually not good.
-		po := f.postorder()
-		visitOrder := make([]*Block, len(po))
-		for i, b := range po {
-			j := len(po) - i - 1
-			visitOrder[j] = b
-		}
-		return visitOrder
-	}
-
-	return nil
+	// remnant of an experiment; perhaps there will be another.
+	return layoutOrder(f)
 }
 
 func layoutOrder(f *Func) []*Block {
diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go
index 36f09c3..d917183 100644
--- a/src/cmd/compile/internal/ssa/print.go
+++ b/src/cmd/compile/internal/ssa/print.go
@@ -154,6 +154,6 @@
 		p.endBlock(b)
 	}
 	for _, name := range f.Names {
-		p.named(name, f.NamedValues[name])
+		p.named(*name, f.NamedValues[*name])
 	}
 }
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
index c81d557..3b90b87 100644
--- a/src/cmd/compile/internal/ssa/regalloc.go
+++ b/src/cmd/compile/internal/ssa/regalloc.go
@@ -1882,6 +1882,10 @@
 		phiRegs[b.ID] = m
 	}
 
+	mustBeFirst := func(op Op) bool {
+		return op.isLoweredGetClosurePtr() || op == OpPhi || op == OpArgIntReg || op == OpArgFloatReg
+	}
+
 	// Start maps block IDs to the list of spills
 	// that go at the start of the block (but after any phis).
 	start := map[ID][]*Value{}
@@ -1971,7 +1975,7 @@
 		// Put the spill in the best block we found.
 		spill.Block = best
 		spill.AddArg(bestArg)
-		if best == v.Block && v.Op != OpPhi {
+		if best == v.Block && !mustBeFirst(v.Op) {
 			// Place immediately after v.
 			after[v.ID] = append(after[v.ID], spill)
 		} else {
@@ -1983,15 +1987,15 @@
 	// Insert spill instructions into the block schedules.
 	var oldSched []*Value
 	for _, b := range s.visitOrder {
-		nphi := 0
+		nfirst := 0
 		for _, v := range b.Values {
-			if v.Op != OpPhi {
+			if !mustBeFirst(v.Op) {
 				break
 			}
-			nphi++
+			nfirst++
 		}
-		oldSched = append(oldSched[:0], b.Values[nphi:]...)
-		b.Values = b.Values[:nphi]
+		oldSched = append(oldSched[:0], b.Values[nfirst:]...)
+		b.Values = b.Values[:nfirst]
 		b.Values = append(b.Values, start[b.ID]...)
 		for _, v := range oldSched {
 			b.Values = append(b.Values, v)
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index efb5d27..5045ba7 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -1038,6 +1038,8 @@
 		return rewriteValueAMD64_OpSelect0(v)
 	case OpSelect1:
 		return rewriteValueAMD64_OpSelect1(v)
+	case OpSelectN:
+		return rewriteValueAMD64_OpSelectN(v)
 	case OpSignExt16to32:
 		v.Op = OpAMD64MOVWQSX
 		return true
@@ -32981,6 +32983,78 @@
 	}
 	return false
 }
+func rewriteValueAMD64_OpSelectN(v *Value) bool {
+	v_0 := v.Args[0]
+	b := v.Block
+	config := b.Func.Config
+	// match: (SelectN [0] call:(CALLstatic {sym} s1:(MOVQstoreconst _ [sc] s2:(MOVQstore _ src s3:(MOVQstore _ dst mem)))))
+	// cond: sc.Val64() >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sc.Val64(), config) && clobber(s1, s2, s3, call)
+	// result: (Move [sc.Val64()] dst src mem)
+	for {
+		if auxIntToInt64(v.AuxInt) != 0 {
+			break
+		}
+		call := v_0
+		if call.Op != OpAMD64CALLstatic || len(call.Args) != 1 {
+			break
+		}
+		sym := auxToCall(call.Aux)
+		s1 := call.Args[0]
+		if s1.Op != OpAMD64MOVQstoreconst {
+			break
+		}
+		sc := auxIntToValAndOff(s1.AuxInt)
+		_ = s1.Args[1]
+		s2 := s1.Args[1]
+		if s2.Op != OpAMD64MOVQstore {
+			break
+		}
+		_ = s2.Args[2]
+		src := s2.Args[1]
+		s3 := s2.Args[2]
+		if s3.Op != OpAMD64MOVQstore {
+			break
+		}
+		mem := s3.Args[2]
+		dst := s3.Args[1]
+		if !(sc.Val64() >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sc.Val64(), config) && clobber(s1, s2, s3, call)) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = int64ToAuxInt(sc.Val64())
+		v.AddArg3(dst, src, mem)
+		return true
+	}
+	// match: (SelectN [0] call:(CALLstatic {sym} dst src (MOVQconst [sz]) mem))
+	// cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && call.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(call)
+	// result: (Move [sz] dst src mem)
+	for {
+		if auxIntToInt64(v.AuxInt) != 0 {
+			break
+		}
+		call := v_0
+		if call.Op != OpAMD64CALLstatic || len(call.Args) != 4 {
+			break
+		}
+		sym := auxToCall(call.Aux)
+		mem := call.Args[3]
+		dst := call.Args[0]
+		src := call.Args[1]
+		call_2 := call.Args[2]
+		if call_2.Op != OpAMD64MOVQconst {
+			break
+		}
+		sz := auxIntToInt64(call_2.AuxInt)
+		if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && call.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(call)) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = int64ToAuxInt(sz)
+		v.AddArg3(dst, src, mem)
+		return true
+	}
+	return false
+}
 func rewriteValueAMD64_OpSlicemask(v *Value) bool {
 	v_0 := v.Args[0]
 	b := v.Block
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index 0ba3951..3cdc4d3 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -984,6 +984,8 @@
 		return rewriteValueARM64_OpSelect0(v)
 	case OpSelect1:
 		return rewriteValueARM64_OpSelect1(v)
+	case OpSelectN:
+		return rewriteValueARM64_OpSelectN(v)
 	case OpSignExt16to32:
 		v.Op = OpARM64MOVHreg
 		return true
@@ -25983,6 +25985,54 @@
 	}
 	return false
 }
+func rewriteValueARM64_OpSelectN(v *Value) bool {
+	v_0 := v.Args[0]
+	b := v.Block
+	config := b.Func.Config
+	// match: (SelectN [0] call:(CALLstatic {sym} s1:(MOVDstore _ (MOVDconst [sz]) s2:(MOVDstore _ src s3:(MOVDstore {t} _ dst mem)))))
+	// cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1, s2, s3, call)
+	// result: (Move [sz] dst src mem)
+	for {
+		if auxIntToInt64(v.AuxInt) != 0 {
+			break
+		}
+		call := v_0
+		if call.Op != OpARM64CALLstatic {
+			break
+		}
+		sym := auxToCall(call.Aux)
+		s1 := call.Args[0]
+		if s1.Op != OpARM64MOVDstore {
+			break
+		}
+		_ = s1.Args[2]
+		s1_1 := s1.Args[1]
+		if s1_1.Op != OpARM64MOVDconst {
+			break
+		}
+		sz := auxIntToInt64(s1_1.AuxInt)
+		s2 := s1.Args[2]
+		if s2.Op != OpARM64MOVDstore {
+			break
+		}
+		_ = s2.Args[2]
+		src := s2.Args[1]
+		s3 := s2.Args[2]
+		if s3.Op != OpARM64MOVDstore {
+			break
+		}
+		mem := s3.Args[2]
+		dst := s3.Args[1]
+		if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1, s2, s3, call)) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = int64ToAuxInt(sz)
+		v.AddArg3(dst, src, mem)
+		return true
+	}
+	return false
+}
 func rewriteValueARM64_OpSlicemask(v *Value) bool {
 	v_0 := v.Args[0]
 	b := v.Block
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
index d962579..d41f399 100644
--- a/src/cmd/compile/internal/ssa/stackalloc.go
+++ b/src/cmd/compile/internal/ssa/stackalloc.go
@@ -141,10 +141,11 @@
 		s.names = make([]LocalSlot, n)
 	}
 	names := s.names
+	empty := LocalSlot{}
 	for _, name := range f.Names {
 		// Note: not "range f.NamedValues" above, because
 		// that would be nondeterministic.
-		for _, v := range f.NamedValues[name] {
+		for _, v := range f.NamedValues[*name] {
 			if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
 				aux := v.Aux.(*AuxNameOffset)
 				// Never let an arg be bound to a differently named thing.
@@ -162,10 +163,12 @@
 				continue
 			}
 
-			if f.pass.debug > stackDebug {
-				fmt.Printf("stackalloc value %s to name %s\n", v, name)
+			if names[v.ID] == empty {
+				if f.pass.debug > stackDebug {
+					fmt.Printf("stackalloc value %s to name %s\n", v, *name)
+				}
+				names[v.ID] = *name
 			}
-			names[v.ID] = name
 		}
 	}
 
diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index 2abd701..dfa7600 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -8,7 +8,6 @@
 	"bufio"
 	"bytes"
 	"cmd/compile/internal/abi"
-	"encoding/binary"
 	"fmt"
 	"go/constant"
 	"html"
@@ -1297,7 +1296,7 @@
 		if f.Sym.IsBlank() {
 			continue
 		}
-		offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), abi.FieldOffsetOf(f), addr)
+		offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr)
 		s.instrumentFields(f.Type, offptr, kind)
 	}
 }
@@ -3175,7 +3174,7 @@
 		arrlen := s.constInt(types.Types[types.TINT], n.Type().Elem().NumElem())
 		cap := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], v)
 		s.boundsCheck(arrlen, cap, ssa.BoundsConvert, false)
-		return s.newValue1(ssa.OpSlicePtrUnchecked, types.Types[types.TINT], v)
+		return s.newValue1(ssa.OpSlicePtrUnchecked, n.Type(), v)
 
 	case ir.OCALLFUNC:
 		n := n.(*ir.CallExpr)
@@ -5054,19 +5053,23 @@
 		ft := fn.Type()
 		off := t.FieldOff(12) // TODO register args: be sure this isn't a hardcoded param stack offset.
 		args := n.Args
+		i0 := 0
 
 		// Set receiver (for interface calls). Always a pointer.
 		if rcvr != nil {
 			p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr)
 			s.store(types.Types[types.TUINTPTR], p, rcvr)
+			i0 = 1
 		}
 		// Set receiver (for method calls).
 		if n.Op() == ir.OCALLMETH {
 			base.Fatalf("OCALLMETH missed by walkCall")
 		}
 		// Set other args.
-		for _, f := range ft.Params().Fields().Slice() {
-			s.storeArgWithBase(args[0], f.Type, addr, off+abi.FieldOffsetOf(f))
+		// This code is only used when RegabiDefer is not enabled, and arguments are always
+		// passed on stack.
+		for i, f := range ft.Params().Fields().Slice() {
+			s.storeArgWithBase(args[0], f.Type, addr, off+params.InParam(i+i0).FrameOffset(params))
 			args = args[1:]
 		}
 
@@ -5079,7 +5082,6 @@
 		if stksize < int64(types.PtrSize) {
 			// We need room for both the call to deferprocStack and the call to
 			// the deferred function.
-			// TODO(register args) Revisit this if/when we pass args in registers.
 			stksize = int64(types.PtrSize)
 		}
 		call.AuxInt = stksize
@@ -6463,7 +6465,8 @@
 	loc := ssa.LocalSlot{N: n, Type: n.Type(), Off: 0}
 	values, ok := s.f.NamedValues[loc]
 	if !ok {
-		s.f.Names = append(s.f.Names, loc)
+		s.f.Names = append(s.f.Names, &loc)
+		s.f.CanonicalLocalSlots[loc] = &loc
 	}
 	s.f.NamedValues[loc] = append(values, v)
 }
@@ -6598,6 +6601,7 @@
 	x := base.Ctxt.Lookup(fmt.Sprintf("%s.arginfo%d", f.LSym.Name, f.ABI))
 
 	PtrSize := int64(types.PtrSize)
+	uintptrTyp := types.Types[types.TUINTPTR]
 
 	isAggregate := func(t *types.Type) bool {
 		return t.IsStruct() || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice()
@@ -6641,12 +6645,8 @@
 	n := 0
 	writebyte := func(o uint8) { wOff = objw.Uint8(x, wOff, o) }
 
-	// Write one non-aggrgate arg/field/element if there is room.
-	// Returns whether to continue.
-	write1 := func(sz, offset int64) bool {
-		if n >= limit {
-			return false
-		}
+	// Write one non-aggrgate arg/field/element.
+	write1 := func(sz, offset int64) {
 		if offset >= _special {
 			writebyte(_offsetTooLarge)
 		} else {
@@ -6654,7 +6654,6 @@
 			writebyte(uint8(sz))
 		}
 		n++
-		return true
 	}
 
 	// Visit t recursively and write it out.
@@ -6662,10 +6661,12 @@
 	var visitType func(baseOffset int64, t *types.Type, depth int) bool
 	visitType = func(baseOffset int64, t *types.Type, depth int) bool {
 		if n >= limit {
+			writebyte(_dotdotdot)
 			return false
 		}
 		if !isAggregate(t) {
-			return write1(t.Size(), baseOffset)
+			write1(t.Size(), baseOffset)
+			return true
 		}
 		writebyte(_startAgg)
 		depth++
@@ -6675,58 +6676,47 @@
 			n++
 			return true
 		}
-		var r bool
 		switch {
 		case t.IsInterface(), t.IsString():
-			r = write1(PtrSize, baseOffset) &&
-				write1(PtrSize, baseOffset+PtrSize)
+			_ = visitType(baseOffset, uintptrTyp, depth) &&
+				visitType(baseOffset+PtrSize, uintptrTyp, depth)
 		case t.IsSlice():
-			r = write1(PtrSize, baseOffset) &&
-				write1(PtrSize, baseOffset+PtrSize) &&
-				write1(PtrSize, baseOffset+PtrSize*2)
+			_ = visitType(baseOffset, uintptrTyp, depth) &&
+				visitType(baseOffset+PtrSize, uintptrTyp, depth) &&
+				visitType(baseOffset+PtrSize*2, uintptrTyp, depth)
 		case t.IsComplex():
-			r = write1(t.Size()/2, baseOffset) &&
-				write1(t.Size()/2, baseOffset+t.Size()/2)
+			_ = visitType(baseOffset, types.FloatForComplex(t), depth) &&
+				visitType(baseOffset+t.Size()/2, types.FloatForComplex(t), depth)
 		case t.IsArray():
-			r = true
 			if t.NumElem() == 0 {
 				n++ // {} counts as a component
 				break
 			}
 			for i := int64(0); i < t.NumElem(); i++ {
 				if !visitType(baseOffset, t.Elem(), depth) {
-					r = false
 					break
 				}
 				baseOffset += t.Elem().Size()
 			}
 		case t.IsStruct():
-			r = true
 			if t.NumFields() == 0 {
 				n++ // {} counts as a component
 				break
 			}
 			for _, field := range t.Fields().Slice() {
 				if !visitType(baseOffset+field.Offset, field.Type, depth) {
-					r = false
 					break
 				}
 			}
 		}
-		if !r {
-			writebyte(_dotdotdot)
-		}
 		writebyte(_endAgg)
-		return r
+		return true
 	}
 
-	c := true
 	for _, a := range abiInfo.InParams() {
-		if !c {
-			writebyte(_dotdotdot)
+		if !visitType(a.FrameOffset(abiInfo), a.Type, 0) {
 			break
 		}
-		c = visitType(a.FrameOffset(abiInfo), a.Type, 0)
 	}
 	writebyte(_endSeq)
 	if wOff > maxLen {
@@ -7552,82 +7542,6 @@
 	return typecheck.TempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
 }
 
-func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
-	ptrType := types.NewPtr(types.Types[types.TUINT8])
-	lenType := types.Types[types.TINT]
-	// Split this string up into two separate variables.
-	p := e.SplitSlot(&name, ".ptr", 0, ptrType)
-	l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
-	return p, l
-}
-
-func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
-	n := name.N
-	u := types.Types[types.TUINTPTR]
-	t := types.NewPtr(types.Types[types.TUINT8])
-	// Split this interface up into two separate variables.
-	f := ".itab"
-	if n.Type().IsEmptyInterface() {
-		f = ".type"
-	}
-	c := e.SplitSlot(&name, f, 0, u) // see comment in typebits.Set
-	d := e.SplitSlot(&name, ".data", u.Size(), t)
-	return c, d
-}
-
-func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
-	ptrType := types.NewPtr(name.Type.Elem())
-	lenType := types.Types[types.TINT]
-	p := e.SplitSlot(&name, ".ptr", 0, ptrType)
-	l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
-	c := e.SplitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
-	return p, l, c
-}
-
-func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
-	s := name.Type.Size() / 2
-	var t *types.Type
-	if s == 8 {
-		t = types.Types[types.TFLOAT64]
-	} else {
-		t = types.Types[types.TFLOAT32]
-	}
-	r := e.SplitSlot(&name, ".real", 0, t)
-	i := e.SplitSlot(&name, ".imag", t.Size(), t)
-	return r, i
-}
-
-func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
-	var t *types.Type
-	if name.Type.IsSigned() {
-		t = types.Types[types.TINT32]
-	} else {
-		t = types.Types[types.TUINT32]
-	}
-	if Arch.LinkArch.ByteOrder == binary.BigEndian {
-		return e.SplitSlot(&name, ".hi", 0, t), e.SplitSlot(&name, ".lo", t.Size(), types.Types[types.TUINT32])
-	}
-	return e.SplitSlot(&name, ".hi", t.Size(), t), e.SplitSlot(&name, ".lo", 0, types.Types[types.TUINT32])
-}
-
-func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
-	st := name.Type
-	// Note: the _ field may appear several times.  But
-	// have no fear, identically-named but distinct Autos are
-	// ok, albeit maybe confusing for a debugger.
-	return e.SplitSlot(&name, "."+st.FieldName(i), st.FieldOff(i), st.FieldType(i))
-}
-
-func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
-	n := name.N
-	at := name.Type
-	if at.NumElem() != 1 {
-		e.Fatalf(n.Pos(), "bad array size")
-	}
-	et := at.Elem()
-	return e.SplitSlot(&name, "[0]", 0, et)
-}
-
 func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
 	return reflectdata.ITabSym(it, offset)
 }
diff --git a/src/cmd/compile/internal/test/align_test.go b/src/cmd/compile/internal/test/align_test.go
new file mode 100644
index 0000000..32afc92
--- /dev/null
+++ b/src/cmd/compile/internal/test/align_test.go
@@ -0,0 +1,96 @@
+// 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.
+
+// Test to make sure that equality functions (and hash
+// functions) don't do unaligned reads on architectures
+// that can't do unaligned reads. See issue 46283.
+
+package test
+
+import "testing"
+
+type T1 struct {
+	x          float32
+	a, b, c, d int16 // memequal64
+}
+type T2 struct {
+	x          float32
+	a, b, c, d int32 // memequal128
+}
+
+type A2 [2]byte // eq uses a 2-byte load
+type A4 [4]byte // eq uses a 4-byte load
+type A8 [8]byte // eq uses an 8-byte load
+
+//go:noinline
+func cmpT1(p, q *T1) {
+	if *p != *q {
+		panic("comparison test wrong")
+	}
+}
+
+//go:noinline
+func cmpT2(p, q *T2) {
+	if *p != *q {
+		panic("comparison test wrong")
+	}
+}
+
+//go:noinline
+func cmpA2(p, q *A2) {
+	if *p != *q {
+		panic("comparison test wrong")
+	}
+}
+
+//go:noinline
+func cmpA4(p, q *A4) {
+	if *p != *q {
+		panic("comparison test wrong")
+	}
+}
+
+//go:noinline
+func cmpA8(p, q *A8) {
+	if *p != *q {
+		panic("comparison test wrong")
+	}
+}
+
+func TestAlignEqual(t *testing.T) {
+	cmpT1(&T1{}, &T1{})
+	cmpT2(&T2{}, &T2{})
+
+	m1 := map[T1]bool{}
+	m1[T1{}] = true
+	m1[T1{}] = false
+	if len(m1) != 1 {
+		t.Fatalf("len(m1)=%d, want 1", len(m1))
+	}
+	m2 := map[T2]bool{}
+	m2[T2{}] = true
+	m2[T2{}] = false
+	if len(m2) != 1 {
+		t.Fatalf("len(m2)=%d, want 1", len(m2))
+	}
+
+	type X2 struct {
+		y byte
+		z A2
+	}
+	var x2 X2
+	cmpA2(&x2.z, &A2{})
+	type X4 struct {
+		y byte
+		z A4
+	}
+	var x4 X4
+	cmpA4(&x4.z, &A4{})
+	type X8 struct {
+		y byte
+		z A8
+	}
+	var x8 X8
+	cmpA8(&x8.z, &A8{})
+}
diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go
index 67a894c..833b17b 100644
--- a/src/cmd/compile/internal/typecheck/builtin.go
+++ b/src/cmd/compile/internal/typecheck/builtin.go
@@ -138,6 +138,7 @@
 	{"growslice", funcTag, 116},
 	{"unsafeslice", funcTag, 117},
 	{"unsafeslice64", funcTag, 118},
+	{"unsafeslicecheckptr", funcTag, 118},
 	{"memmove", funcTag, 119},
 	{"memclrNoHeapPointers", funcTag, 120},
 	{"memclrHasPointers", funcTag, 120},
@@ -341,8 +342,8 @@
 	typs[114] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
 	typs[115] = types.NewSlice(typs[2])
 	typs[116] = newSig(params(typs[1], typs[115], typs[15]), params(typs[115]))
-	typs[117] = newSig(params(typs[1], typs[15]), nil)
-	typs[118] = newSig(params(typs[1], typs[22]), nil)
+	typs[117] = newSig(params(typs[1], typs[7], typs[15]), nil)
+	typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil)
 	typs[119] = newSig(params(typs[3], typs[3], typs[5]), nil)
 	typs[120] = newSig(params(typs[7], typs[5]), nil)
 	typs[121] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go
index ebeaeae..2b29ea3 100644
--- a/src/cmd/compile/internal/typecheck/builtin/runtime.go
+++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go
@@ -183,8 +183,9 @@
 func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer
 func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
 func growslice(typ *byte, old []any, cap int) (ary []any)
-func unsafeslice(typ *byte, len int)
-func unsafeslice64(typ *byte, len int64)
+func unsafeslice(typ *byte, ptr unsafe.Pointer, len int)
+func unsafeslice64(typ *byte, ptr unsafe.Pointer, len int64)
+func unsafeslicecheckptr(typ *byte, ptr unsafe.Pointer, len int64)
 
 func memmove(to *any, frm *any, length uintptr)
 func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go
index 5a35eea..761b043 100644
--- a/src/cmd/compile/internal/typecheck/const.go
+++ b/src/cmd/compile/internal/typecheck/const.go
@@ -633,6 +633,17 @@
 	if l.Type() == nil || r.Type() == nil {
 		return l, r
 	}
+
+	if !l.Type().IsInterface() && !r.Type().IsInterface() {
+		// Can't mix bool with non-bool, string with non-string.
+		if l.Type().IsBoolean() != r.Type().IsBoolean() {
+			return l, r
+		}
+		if l.Type().IsString() != r.Type().IsString() {
+			return l, r
+		}
+	}
+
 	if !l.Type().IsUntyped() {
 		r = convlit(r, l.Type())
 		return l, r
@@ -647,17 +658,10 @@
 		return l, r
 	}
 
-	// Can't mix bool with non-bool, string with non-string, or nil with anything (untyped).
-	if l.Type().IsBoolean() != r.Type().IsBoolean() {
-		return l, r
-	}
-	if l.Type().IsString() != r.Type().IsString() {
-		return l, r
-	}
+	// Can't mix nil with anything untyped.
 	if ir.IsNil(l) || ir.IsNil(r) {
 		return l, r
 	}
-
 	t := defaultType(mixUntyped(l.Type(), r.Type()))
 	l = convlit(l, t)
 	r = convlit(r, t)
diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go
index f3058d8..5b771e3 100644
--- a/src/cmd/compile/internal/typecheck/dcl.go
+++ b/src/cmd/compile/internal/typecheck/dcl.go
@@ -106,7 +106,17 @@
 // Redeclared emits a diagnostic about symbol s being redeclared at pos.
 func Redeclared(pos src.XPos, s *types.Sym, where string) {
 	if !s.Lastlineno.IsKnown() {
-		pkgName := DotImportRefs[s.Def.(*ir.Ident)]
+		var pkgName *ir.PkgName
+		if s.Def == nil {
+			for id, pkg := range DotImportRefs {
+				if id.Sym().Name == s.Name {
+					pkgName = pkg
+					break
+				}
+			}
+		} else {
+			pkgName = DotImportRefs[s.Def.(*ir.Ident)]
+		}
 		base.ErrorfAt(pos, "%v redeclared %s\n"+
 			"\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
 	} else {
diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go
index f381e1d..fbcc784 100644
--- a/src/cmd/compile/internal/typecheck/func.go
+++ b/src/cmd/compile/internal/typecheck/func.go
@@ -981,6 +981,12 @@
 
 // tcUnsafeAdd typechecks an OUNSAFEADD node.
 func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr {
+	if !types.AllowsGoVersion(curpkg(), 1, 17) {
+		base.ErrorfVers("go1.17", "unsafe.Add")
+		n.SetType(nil)
+		return n
+	}
+
 	n.X = AssignConv(Expr(n.X), types.Types[types.TUNSAFEPTR], "argument to unsafe.Add")
 	n.Y = DefaultLit(Expr(n.Y), types.Types[types.TINT])
 	if n.X.Type() == nil || n.Y.Type() == nil {
@@ -997,6 +1003,12 @@
 
 // tcUnsafeSlice typechecks an OUNSAFESLICE node.
 func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr {
+	if !types.AllowsGoVersion(curpkg(), 1, 17) {
+		base.ErrorfVers("go1.17", "unsafe.Slice")
+		n.SetType(nil)
+		return n
+	}
+
 	n.X = Expr(n.X)
 	n.Y = Expr(n.Y)
 	if n.X.Type() == nil || n.Y.Type() == nil {
@@ -1006,7 +1018,14 @@
 	t := n.X.Type()
 	if !t.IsPtr() {
 		base.Errorf("first argument to unsafe.Slice must be pointer; have %L", t)
+	} else if t.Elem().NotInHeap() {
+		// TODO(mdempsky): This can be relaxed, but should only affect the
+		// Go runtime itself. End users should only see //go:notinheap
+		// types due to incomplete C structs in cgo, and those types don't
+		// have a meaningful size anyway.
+		base.Errorf("unsafe.Slice of incomplete (or unallocatable) type not allowed")
 	}
+
 	if !checkunsafeslice(&n.Y) {
 		n.SetType(nil)
 		return n
diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go
index a5ddbb5..37f5a7b 100644
--- a/src/cmd/compile/internal/typecheck/iimport.go
+++ b/src/cmd/compile/internal/typecheck/iimport.go
@@ -1540,7 +1540,7 @@
 func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr {
 	if go117ExportTypes {
 		// These should all be encoded as direct ops, not OCALL.
-		base.Fatalf("builtinCall should not be invoked when types are included in inport/export")
+		base.Fatalf("builtinCall should not be invoked when types are included in import/export")
 	}
 	return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
 }
diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go
index 175216f..922a01b 100644
--- a/src/cmd/compile/internal/typecheck/stmt.go
+++ b/src/cmd/compile/internal/typecheck/stmt.go
@@ -204,8 +204,20 @@
 		r.Use = ir.CallUseList
 		rtyp := r.Type()
 
+		mismatched := false
+		failed := false
 		for i := range lhs {
-			assignType(i, rtyp.Field(i).Type)
+			result := rtyp.Field(i).Type
+			assignType(i, result)
+
+			if lhs[i].Type() == nil || result == nil {
+				failed = true
+			} else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) {
+				mismatched = true
+			}
+		}
+		if mismatched && !failed {
+			rewriteMultiValueCall(stmt, r)
 		}
 		return
 	}
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index 95f7b50..359f662 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -945,16 +945,18 @@
 		return
 	}
 
-	// Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...).
-
 	// Save n as n.Orig for fmt.go.
 	if ir.Orig(n) == n {
 		n.(ir.OrigNode).SetOrig(ir.SepCopy(n))
 	}
 
-	as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-	as.Rhs.Append(list...)
+	// Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...).
+	rewriteMultiValueCall(n, list[0])
+}
 
+// rewriteMultiValueCall rewrites multi-valued f() to use temporaries,
+// so the backend wouldn't need to worry about tuple-valued expressions.
+func rewriteMultiValueCall(n ir.InitNode, call ir.Node) {
 	// If we're outside of function context, then this call will
 	// be executed during the generated init function. However,
 	// init.go hasn't yet created it. Instead, associate the
@@ -964,25 +966,40 @@
 	if static {
 		ir.CurFunc = InitTodoFunc
 	}
-	list = nil
-	for _, f := range t.FieldSlice() {
-		t := Temp(f.Type)
-		as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t))
-		as.Lhs.Append(t)
-		list = append(list, t)
+
+	as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, []ir.Node{call})
+	results := call.Type().FieldSlice()
+	list := make([]ir.Node, len(results))
+	for i, result := range results {
+		tmp := Temp(result.Type)
+		as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, tmp))
+		as.Lhs.Append(tmp)
+		list[i] = tmp
 	}
 	if static {
 		ir.CurFunc = nil
 	}
 
+	n.PtrInit().Append(Stmt(as))
+
 	switch n := n.(type) {
+	default:
+		base.Fatalf("rewriteMultiValueCall %+v", n.Op())
 	case *ir.CallExpr:
 		n.Args = list
 	case *ir.ReturnStmt:
 		n.Results = list
+	case *ir.AssignListStmt:
+		if n.Op() != ir.OAS2FUNC {
+			base.Fatalf("rewriteMultiValueCall: invalid op %v", n.Op())
+		}
+		as.SetOp(ir.OAS2FUNC)
+		n.SetOp(ir.OAS2)
+		n.Rhs = make([]ir.Node, len(list))
+		for i, tmp := range list {
+			n.Rhs[i] = AssignConv(tmp, n.Lhs[i].Type(), "assignment")
+		}
 	}
-
-	n.PtrInit().Append(Stmt(as))
 }
 
 func checksliceindex(l ir.Node, r ir.Node, tp *types.Type) bool {
@@ -1443,15 +1460,22 @@
 }
 
 func errorDetails(nl ir.Nodes, tstruct *types.Type, isddd bool) string {
-	// If we don't know any type at a call site, let's suppress any return
-	// message signatures. See Issue https://golang.org/issues/19012.
+	// Suppress any return message signatures if:
+	//
+	// (1) We don't know any type at a call site (see #19012).
+	// (2) Any node has an unknown type.
+	// (3) Invalid type for variadic parameter (see #46957).
 	if tstruct == nil {
-		return ""
+		return "" // case 1
 	}
-	// If any node has an unknown type, suppress it as well
+
+	if isddd && !nl[len(nl)-1].Type().IsSlice() {
+		return "" // case 3
+	}
+
 	for _, n := range nl {
 		if n.Type() == nil {
-			return ""
+			return "" // case 2
 		}
 	}
 	return fmt.Sprintf("\n\thave %s\n\twant %v", fmtSignature(nl, isddd), tstruct)
diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go
index b538ea8..8b98895 100644
--- a/src/cmd/compile/internal/types/fmt.go
+++ b/src/cmd/compile/internal/types/fmt.go
@@ -109,14 +109,18 @@
 		return "<S>"
 	}
 
-	if s.Name == "_" {
-		return "_"
+	q := pkgqual(s.Pkg, verb, mode)
+	if q == "" {
+		return s.Name
 	}
+
 	buf := fmtBufferPool.Get().(*bytes.Buffer)
 	buf.Reset()
 	defer fmtBufferPool.Put(buf)
 
-	symfmt(buf, s, verb, mode)
+	buf.WriteString(q)
+	buf.WriteByte('.')
+	buf.WriteString(s.Name)
 	return InternString(buf.Bytes())
 }
 
@@ -128,56 +132,49 @@
 		b.WriteString("<S>")
 		return
 	}
-	if s.Name == "_" {
-		b.WriteString("_")
-		return
-	}
 
 	symfmt(b, s, verb, mode)
 }
 
 func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
+	if q := pkgqual(s.Pkg, verb, mode); q != "" {
+		b.WriteString(q)
+		b.WriteByte('.')
+	}
+	b.WriteString(s.Name)
+}
+
+// pkgqual returns the qualifier that should be used for printing
+// symbols from the given package in the given mode.
+// If it returns the empty string, no qualification is needed.
+func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string {
 	if verb != 'S' {
 		switch mode {
 		case fmtGo: // This is for the user
-			if s.Pkg == BuiltinPkg || s.Pkg == LocalPkg {
-				b.WriteString(s.Name)
-				return
+			if pkg == BuiltinPkg || pkg == LocalPkg {
+				return ""
 			}
 
 			// If the name was used by multiple packages, display the full path,
-			if s.Pkg.Name != "" && NumImport[s.Pkg.Name] > 1 {
-				fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name)
-				return
+			if pkg.Name != "" && NumImport[pkg.Name] > 1 {
+				return strconv.Quote(pkg.Path)
 			}
-			b.WriteString(s.Pkg.Name)
-			b.WriteByte('.')
-			b.WriteString(s.Name)
-			return
+			return pkg.Name
 
 		case fmtDebug:
-			b.WriteString(s.Pkg.Name)
-			b.WriteByte('.')
-			b.WriteString(s.Name)
-			return
+			return pkg.Name
 
 		case fmtTypeIDName:
 			// dcommontype, typehash
-			b.WriteString(s.Pkg.Name)
-			b.WriteByte('.')
-			b.WriteString(s.Name)
-			return
+			return pkg.Name
 
 		case fmtTypeID:
 			// (methodsym), typesym, weaksym
-			b.WriteString(s.Pkg.Prefix)
-			b.WriteByte('.')
-			b.WriteString(s.Name)
-			return
+			return pkg.Prefix
 		}
 	}
 
-	b.WriteString(s.Name)
+	return ""
 }
 
 // Type
diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go
index b9e178d..f90e06f 100644
--- a/src/cmd/compile/internal/types2/builtins.go
+++ b/src/cmd/compile/internal/types2/builtins.go
@@ -579,6 +579,11 @@
 
 	case _Add:
 		// unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer
+		if !check.allowVersion(check.pkg, 1, 17) {
+			check.error(call.Fun, "unsafe.Add requires go1.17 or later")
+			return
+		}
+
 		check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add")
 		if x.mode == invalid {
 			return
@@ -675,6 +680,11 @@
 
 	case _Slice:
 		// unsafe.Slice(ptr *T, len IntegerType) []T
+		if !check.allowVersion(check.pkg, 1, 17) {
+			check.error(call.Fun, "unsafe.Slice requires go1.17 or later")
+			return
+		}
+
 		typ := asPointer(x.typ)
 		if typ == nil {
 			check.errorf(x, invalidArg+"%s is not a pointer", x)
diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go
index 62eb429..14efc05 100644
--- a/src/cmd/compile/internal/walk/builtin.go
+++ b/src/cmd/compile/internal/walk/builtin.go
@@ -489,7 +489,7 @@
 		base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", n.Type().Elem())
 	}
 	if n.Esc() == ir.EscNone {
-		if t.Size() >= ir.MaxImplicitStackVarSize {
+		if t.Size() > ir.MaxImplicitStackVarSize {
 			base.Fatalf("large ONEW with EscNone: %v", n)
 		}
 		return stackTempAddr(init, t)
@@ -654,36 +654,28 @@
 }
 
 func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
+	ptr := safeExpr(n.X, init)
 	len := safeExpr(n.Y, init)
 
 	fnname := "unsafeslice64"
-	argtype := types.Types[types.TINT64]
+	lenType := types.Types[types.TINT64]
 
 	// Type checking guarantees that TIDEAL len/cap are positive and fit in an int.
 	// The case of len or cap overflow when converting TUINT or TUINTPTR to TINT
 	// will be handled by the negative range checks in unsafeslice during runtime.
-	if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
+	if ir.ShouldCheckPtr(ir.CurFunc, 1) {
+		fnname = "unsafeslicecheckptr"
+		// for simplicity, unsafeslicecheckptr always uses int64
+	} else if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
 		fnname = "unsafeslice"
-		argtype = types.Types[types.TINT]
+		lenType = types.Types[types.TINT]
 	}
 
 	t := n.Type()
 
-	// Call runtime.unsafeslice[64] to check that the length argument is
-	// non-negative and smaller than the max length allowed for the
-	// element type.
+	// Call runtime.unsafeslice{,64,checkptr} to check ptr and len.
 	fn := typecheck.LookupRuntime(fnname)
-	init.Append(mkcall1(fn, nil, init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(len, argtype)))
-
-	ptr := walkExpr(n.X, init)
-
-	c := ir.NewUnaryExpr(n.Pos(), ir.OCHECKNIL, ptr)
-	c.SetTypecheck(1)
-	init.Append(c)
-
-	// TODO(mdempsky): checkptr instrumentation. Maybe merge into length
-	// check above, along with nil check? Need to be careful about
-	// notinheap pointers though: can't pass them as unsafe.Pointer.
+	init.Append(mkcall1(fn, nil, init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]), typecheck.Conv(len, lenType)))
 
 	h := ir.NewSliceHeaderExpr(n.Pos(), t,
 		typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go
index fe2c62c..26da6e3 100644
--- a/src/cmd/compile/internal/walk/walk.go
+++ b/src/cmd/compile/internal/walk/walk.go
@@ -313,7 +313,7 @@
 			return true
 
 		case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR,
-			ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD:
+			ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD, ir.OSLICE2ARRPTR:
 			// These ops might panic, make sure they are done
 			// before we start marshaling args for a call. See issue 16760.
 			return true
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 00e23ef..1abb03b 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -1607,6 +1607,18 @@
 	"linux/sparc64": true,
 }
 
+// List of platforms which are first class ports. See golang.org/issue/38874.
+var firstClass = map[string]bool{
+	"darwin/amd64":  true,
+	"darwin/arm64":  true,
+	"linux/386":     true,
+	"linux/amd64":   true,
+	"linux/arm":     true,
+	"linux/arm64":   true,
+	"windows/386":   true,
+	"windows/amd64": true,
+}
+
 func needCC() bool {
 	switch os.Getenv("CGO_ENABLED") {
 	case "1":
@@ -1743,6 +1755,7 @@
 		GOOS         string
 		GOARCH       string
 		CgoSupported bool
+		FirstClass   bool
 	}
 	var results []jsonResult
 	for _, p := range plats {
@@ -1750,7 +1763,8 @@
 		results = append(results, jsonResult{
 			GOOS:         fields[0],
 			GOARCH:       fields[1],
-			CgoSupported: cgoEnabled[p]})
+			CgoSupported: cgoEnabled[p],
+			FirstClass:   firstClass[p]})
 	}
 	out, err := json.MarshalIndent(results, "", "\t")
 	if err != nil {
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 50bf80b..f40fa92 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -722,14 +722,29 @@
 				},
 			})
 			if t.hasCxx() {
-				t.tests = append(t.tests, distTest{
-					name:    "swig_callback",
-					heading: "../misc/swig/callback",
-					fn: func(dt *distTest) error {
-						t.addCmd(dt, "misc/swig/callback", t.goTest())
-						return nil
+				t.tests = append(t.tests,
+					distTest{
+						name:    "swig_callback",
+						heading: "../misc/swig/callback",
+						fn: func(dt *distTest) error {
+							t.addCmd(dt, "misc/swig/callback", t.goTest())
+							return nil
+						},
 					},
-				})
+					distTest{
+						name:    "swig_callback_lto",
+						heading: "../misc/swig/callback",
+						fn: func(dt *distTest) error {
+							cmd := t.addCmd(dt, "misc/swig/callback", t.goTest())
+							cmd.Env = append(os.Environ(),
+								"CGO_CFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
+								"CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
+								"CGO_LDFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
+							)
+							return nil
+						},
+					},
+				)
 			}
 		}
 	}
@@ -766,7 +781,7 @@
 			t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", ".")
 		}
 		if goos == "linux" && goarch != "ppc64le" {
-			// because syscall.SysProcAttri struct used in misc/cgo/testsanitizers is only built on linux.
+			// because syscall.SysProcAttr struct used in misc/cgo/testsanitizers is only built on linux.
 			// Some inconsistent failures happen on ppc64le so disable for now.
 			t.registerHostTest("testsanitizers", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
 		}
@@ -1042,7 +1057,7 @@
 			"darwin-amd64", "darwin-arm64",
 			"freebsd-amd64",
 			"android-arm", "android-arm64", "android-386",
-			"windows-amd64", "windows-386":
+			"windows-amd64", "windows-386", "windows-arm64":
 			return true
 		}
 		return false
diff --git a/src/cmd/dist/vfp_arm.s b/src/cmd/dist/vfp_arm.s
index d571f8b..525ee9b 100644
--- a/src/cmd/dist/vfp_arm.s
+++ b/src/cmd/dist/vfp_arm.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build gc,arm
+//go:build gc
+// +build gc
 
 #include "textflag.h"
 
diff --git a/src/cmd/dist/vfp_default.s b/src/cmd/dist/vfp_default.s
index 84829be..0c1e16b0 100644
--- a/src/cmd/dist/vfp_default.s
+++ b/src/cmd/dist/vfp_default.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !arm,gc
+//go:build gc && !arm
+// +build gc,!arm
 
 #include "textflag.h"
 
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
index a15cbe0..cd03968e 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -3,13 +3,13 @@
 go 1.17
 
 require (
-	github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5
+	github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a
 	github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
 	golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
 	golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect
-	golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a
-	golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 // indirect
+	golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
+	golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
 	golang.org/x/term v0.0.0-20210503060354-a79de5458b56
-	golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5
+	golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
 )
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
index 8a7ad42..d728aca 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -1,22 +1,45 @@
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 h1:zIaiqGYDQwa4HVx5wGRTXbx38Pqxjemn4BP98wpzpXo=
-github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a h1:jmAp/2PZAScNd62lTD3Mcb0Ey9FvIIJtLohPhtxZJ+Q=
+github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e h1:pv3V0NlNSh5Q6AX/StwGLBjcLS7UN4m4Gq+V+uSecqM=
 golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
 golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
-golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a h1:wbpC/7Wbo5WFVox32n+KjhRRLmTLq8YW/wRlL2iVAhk=
-golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a h1:e8qnjKz4EE6OjRki9wTadWSIogINvq10sMcuBRORxMY=
+golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c=
-golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q=
+golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
 golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
-golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5 h1:ImcI7RFHWLu2QWpFDXaReu0j+sQAHIy65vUFZImXiqY=
-golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5/go.mod h1:sH/Eidr0EddymY8HZSakBo32zU3fG5ovDq874hJLjVg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 h1:2XlR/j4I4xz5GQZI7zBjqTfezYyRIE2jD5IMousB2rg=
+golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 052b61c..7f88d32 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -174,8 +174,8 @@
 // 		a build will run as if the disk file path exists with the contents
 // 		given by the backing file paths, or as if the disk file path does not
 // 		exist if its backing file path is empty. Support for the -overlay flag
-// 		has some limitations:importantly, cgo files included from outside the
-// 		include path must be  in the same directory as the Go package they are
+// 		has some limitations: importantly, cgo files included from outside the
+// 		include path must be in the same directory as the Go package they are
 // 		included from, and overlays will not appear when binaries and tests are
 // 		run through go run and go test respectively.
 // 	-pkgdir dir
@@ -293,7 +293,7 @@
 //
 // Usage:
 //
-// 	go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]
+// 	go doc [doc flags] [package|[package.]symbol[.methodOrField]]
 //
 // Doc prints the documentation comments associated with the item identified by its
 // arguments (a package, const, func, type, var, method, or struct field)
@@ -1078,7 +1078,7 @@
 //
 // Usage:
 //
-// 	go mod edit [editing flags] [go.mod]
+// 	go mod edit [editing flags] [-fmt|-print|-json] [go.mod]
 //
 // Edit provides a command-line interface for editing go.mod,
 // for use primarily by tools or scripts. It reads only go.mod;
@@ -1186,13 +1186,17 @@
 //
 // Usage:
 //
-// 	go mod graph
+// 	go mod graph [-go=version]
 //
 // Graph prints the module requirement graph (with replacements applied)
 // in text form. Each line in the output has two space-separated fields: a module
 // and one of its requirements. Each module is identified as a string of the form
 // path@version, except for the main module, which has no @version suffix.
 //
+// The -go flag causes graph to report the module graph as loaded by the
+// given Go version, instead of the version indicated by the 'go' directive
+// in the go.mod file.
+//
 // See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'.
 //
 //
@@ -1200,7 +1204,7 @@
 //
 // Usage:
 //
-// 	go mod init [module]
+// 	go mod init [module-path]
 //
 // Init initializes and writes a new go.mod file in the current directory, in
 // effect creating a new module rooted at the current directory. The go.mod file
@@ -1221,7 +1225,7 @@
 //
 // Usage:
 //
-// 	go mod tidy [-e] [-v] [-go=version]
+// 	go mod tidy [-e] [-v] [-go=version] [-compat=version]
 //
 // Tidy makes sure go.mod matches the source code in the module.
 // It adds any missing modules necessary to build the current module's
@@ -1241,6 +1245,14 @@
 // (Go versions 1.17 and higher retain more requirements in order to
 // support lazy module loading.)
 //
+// The -compat flag preserves any additional checksums needed for the
+// 'go' command from the indicated major Go release to successfully load
+// the module graph, and causes tidy to error out if that version of the
+// 'go' command would load any imported package from a different module
+// version. By default, tidy acts as if the -compat flag were set to the
+// version prior to the one indicated by the 'go' directive in the go.mod
+// file.
+//
 // See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'.
 //
 //
@@ -1560,7 +1572,7 @@
 //
 // A build constraint, also known as a build tag, is a line comment that begins
 //
-// 	// +build
+// 	//go:build
 //
 // that lists the conditions under which a file should be included in the package.
 // Constraints may appear in any kind of source file (not just Go), but
@@ -1568,30 +1580,20 @@
 // only by blank lines and other line comments. These rules mean that in Go
 // files a build constraint must appear before the package clause.
 //
-// To distinguish build constraints from package documentation, a series of
-// build constraints must be followed by a blank line.
+// To distinguish build constraints from package documentation,
+// a build constraint should be followed by a blank line.
 //
-// A build constraint is evaluated as the OR of space-separated options.
-// Each option evaluates as the AND of its comma-separated terms.
-// Each term consists of letters, digits, underscores, and dots.
-// A term may be negated with a preceding !.
-// For example, the build constraint:
+// A build constraint is evaluated as an expression containing options
+// combined by ||, &&, and ! operators and parentheses. Operators have
+// the same meaning as in Go.
 //
-// 	// +build linux,386 darwin,!cgo
+// For example, the following build constraint constrains a file to
+// build when the "linux" and "386" constraints are satisfied, or when
+// "darwin" is satisfied and "cgo" is not:
 //
-// corresponds to the boolean formula:
+// 	//go:build (linux && 386) || (darwin && !cgo)
 //
-// 	(linux AND 386) OR (darwin AND (NOT cgo))
-//
-// A file may have multiple build constraints. The overall constraint is the AND
-// of the individual constraints. That is, the build constraints:
-//
-// 	// +build linux darwin
-// 	// +build amd64
-//
-// corresponds to the boolean formula:
-//
-// 	(linux OR darwin) AND amd64
+// It is an error for a file to have more than one //go:build line.
 //
 // During a particular build, the following words are satisfied:
 //
@@ -1629,24 +1631,28 @@
 //
 // To keep a file from being considered for the build:
 //
-// 	// +build ignore
+// 	//go:build ignore
 //
 // (any other unsatisfied word will work as well, but "ignore" is conventional.)
 //
 // To build a file only when using cgo, and only on Linux and OS X:
 //
-// 	// +build linux,cgo darwin,cgo
+// 	//go:build cgo && (linux || darwin)
 //
 // Such a file is usually paired with another file implementing the
 // default functionality for other systems, which in this case would
 // carry the constraint:
 //
-// 	// +build !linux,!darwin !cgo
+// 	//go:build !(cgo && (linux || darwin))
 //
 // Naming a file dns_windows.go will cause it to be included only when
 // building the package for Windows; similarly, math_386.s will be included
 // only when building the package for 32-bit x86.
 //
+// Go versions 1.16 and earlier used a different syntax for build constraints,
+// with a "// +build" prefix. The gofmt command will add an equivalent //go:build
+// constraint when encountering the older syntax.
+//
 //
 // Build modes
 //
@@ -1885,6 +1891,9 @@
 // 	GOMIPS64
 // 		For GOARCH=mips64{,le}, whether to use floating point instructions.
 // 		Valid values are hardfloat (default), softfloat.
+// 	GOPPC64
+// 		For GOARCH=ppc64{,le}, the target ISA (Instruction Set Architecture).
+// 		Valid values are power8 (default), power9.
 // 	GOWASM
 // 		For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use.
 // 		Valid values are satconv, signext.
@@ -1894,6 +1903,12 @@
 // 	GCCGOTOOLDIR
 // 		If set, where to find gccgo tools, such as cgo.
 // 		The default is based on how gccgo was configured.
+// 	GOEXPERIMENT
+// 		Comma-separated list of toolchain experiments to enable or disable.
+// 		The list of available experiments may change arbitrarily over time.
+// 		See src/internal/goexperiment/flags.go for currently valid values.
+// 		Warning: This variable is provided for the development and testing
+// 		of the Go toolchain itself. Use beyond that purpose is unsupported.
 // 	GOROOT_FINAL
 // 		The root of the installed Go tree, when it is
 // 		installed in a location other than where it is built.
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index 52b11fb..5e2833f 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -72,7 +72,6 @@
 // (temp) directory.
 var testGOROOT string
 
-var testCC string
 var testGOCACHE string
 
 var testGo string
@@ -179,13 +178,6 @@
 			os.Exit(2)
 		}
 
-		out, err = exec.Command(gotool, "env", "CC").CombinedOutput()
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "could not find testing CC: %v\n%s", err, out)
-			os.Exit(2)
-		}
-		testCC = strings.TrimSpace(string(out))
-
 		cmd := exec.Command(testGo, "env", "CGO_ENABLED")
 		cmd.Stderr = new(strings.Builder)
 		if out, err := cmd.Output(); err != nil {
@@ -2193,7 +2185,7 @@
 			// See https://sourceware.org/bugzilla/show_bug.cgi?id=19011
 			section := f.Section(".edata")
 			if section == nil {
-				t.Fatalf(".edata section is not present")
+				t.Skip(".edata section is not present")
 			}
 			// TODO: deduplicate this struct from cmd/link/internal/ld/pe.go
 			type IMAGE_EXPORT_DIRECTORY struct {
@@ -2864,3 +2856,35 @@
 	// `go version` should not fail
 	tg.run("version")
 }
+
+// A missing C compiler should not force the net package to be stale.
+// Issue 47215.
+func TestMissingCC(t *testing.T) {
+	if !canCgo {
+		t.Skip("test is only meaningful on systems with cgo")
+	}
+	cc := os.Getenv("CC")
+	if cc == "" {
+		cc = "gcc"
+	}
+	if filepath.IsAbs(cc) {
+		t.Skipf(`"CC" (%s) is an absolute path`, cc)
+	}
+	_, err := exec.LookPath(cc)
+	if err != nil {
+		t.Skipf(`"CC" (%s) not on PATH`, cc)
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	netStale, _ := tg.isStale("net")
+	if netStale {
+		t.Skip(`skipping test because "net" package is currently stale`)
+	}
+
+	tg.setenv("PATH", "") // No C compiler on PATH.
+	netStale, _ = tg.isStale("net")
+	if netStale {
+		t.Error(`clearing "PATH" causes "net" to be stale`)
+	}
+}
diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
index b47eb81..57a3c1f 100644
--- a/src/cmd/go/internal/cfg/cfg.go
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -77,6 +77,14 @@
 	ctxt.GOOS = envOr("GOOS", ctxt.GOOS)
 	ctxt.GOARCH = envOr("GOARCH", ctxt.GOARCH)
 
+	// The experiments flags are based on GOARCH, so they may
+	// need to change.  TODO: This should be cleaned up.
+	buildcfg.UpdateExperiments(ctxt.GOOS, ctxt.GOARCH, envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT))
+	ctxt.ToolTags = nil
+	for _, exp := range buildcfg.EnabledExperiments() {
+		ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp)
+	}
+
 	// The go/build rule for whether cgo is enabled is:
 	//	1. If $CGO_ENABLED is set, respect it.
 	//	2. Otherwise, if this is a cross-compile, disable cgo.
diff --git a/src/cmd/go/internal/doc/doc.go b/src/cmd/go/internal/doc/doc.go
index 67f76e2..8580a5d 100644
--- a/src/cmd/go/internal/doc/doc.go
+++ b/src/cmd/go/internal/doc/doc.go
@@ -13,7 +13,7 @@
 
 var CmdDoc = &base.Command{
 	Run:         runDoc,
-	UsageLine:   "go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]",
+	UsageLine:   "go doc [doc flags] [package|[package.]symbol[.methodOrField]]",
 	CustomFlags: true,
 	Short:       "show documentation for package or symbol",
 	Long: `
diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
index b30c37a..1553d26 100644
--- a/src/cmd/go/internal/envcmd/env.go
+++ b/src/cmd/go/internal/envcmd/env.go
@@ -10,6 +10,7 @@
 	"encoding/json"
 	"fmt"
 	"go/build"
+	"internal/buildcfg"
 	"io"
 	"os"
 	"path/filepath"
@@ -72,6 +73,7 @@
 		{Name: "GOCACHE", Value: cache.DefaultDir()},
 		{Name: "GOENV", Value: envFile},
 		{Name: "GOEXE", Value: cfg.ExeSuffix},
+		{Name: "GOEXPERIMENT", Value: buildcfg.GOEXPERIMENT()},
 		{Name: "GOFLAGS", Value: cfg.Getenv("GOFLAGS")},
 		{Name: "GOHOSTARCH", Value: runtime.GOARCH},
 		{Name: "GOHOSTOS", Value: runtime.GOOS},
@@ -197,6 +199,21 @@
 	if *envU && *envW {
 		base.Fatalf("go env: cannot use -u with -w")
 	}
+
+	// Handle 'go env -w' and 'go env -u' before calling buildcfg.Check,
+	// so they can be used to recover from an invalid configuration.
+	if *envW {
+		runEnvW(args)
+		return
+	}
+
+	if *envU {
+		runEnvU(args)
+		return
+	}
+
+	buildcfg.Check()
+
 	env := cfg.CmdEnv
 	env = append(env, ExtraEnvVars()...)
 
@@ -206,14 +223,7 @@
 
 	// Do we need to call ExtraEnvVarsCostly, which is a bit expensive?
 	needCostly := false
-	if *envU || *envW {
-		// We're overwriting or removing default settings,
-		// so it doesn't really matter what the existing settings are.
-		//
-		// Moreover, we haven't validated the new settings yet, so it is
-		// important that we NOT perform any actions based on them,
-		// such as initializing the builder to compute other variables.
-	} else if len(args) == 0 {
+	if len(args) == 0 {
 		// We're listing all environment variables ("go env"),
 		// including the expensive ones.
 		needCostly = true
@@ -238,95 +248,6 @@
 		env = append(env, ExtraEnvVarsCostly()...)
 	}
 
-	if *envW {
-		// Process and sanity-check command line.
-		if len(args) == 0 {
-			base.Fatalf("go env -w: no KEY=VALUE arguments given")
-		}
-		osEnv := make(map[string]string)
-		for _, e := range cfg.OrigEnv {
-			if i := strings.Index(e, "="); i >= 0 {
-				osEnv[e[:i]] = e[i+1:]
-			}
-		}
-		add := make(map[string]string)
-		for _, arg := range args {
-			i := strings.Index(arg, "=")
-			if i < 0 {
-				base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg)
-			}
-			key, val := arg[:i], arg[i+1:]
-			if err := checkEnvWrite(key, val); err != nil {
-				base.Fatalf("go env -w: %v", err)
-			}
-			if _, ok := add[key]; ok {
-				base.Fatalf("go env -w: multiple values for key: %s", key)
-			}
-			add[key] = val
-			if osVal := osEnv[key]; osVal != "" && osVal != val {
-				fmt.Fprintf(os.Stderr, "warning: go env -w %s=... does not override conflicting OS environment variable\n", key)
-			}
-		}
-
-		goos, okGOOS := add["GOOS"]
-		goarch, okGOARCH := add["GOARCH"]
-		if okGOOS || okGOARCH {
-			if !okGOOS {
-				goos = cfg.Goos
-			}
-			if !okGOARCH {
-				goarch = cfg.Goarch
-			}
-			if err := work.CheckGOOSARCHPair(goos, goarch); err != nil {
-				base.Fatalf("go env -w: %v", err)
-			}
-		}
-
-		gotmp, okGOTMP := add["GOTMPDIR"]
-		if okGOTMP {
-			if !filepath.IsAbs(gotmp) && gotmp != "" {
-				base.Fatalf("go env -w: GOTMPDIR must be an absolute path")
-			}
-		}
-
-		updateEnvFile(add, nil)
-		return
-	}
-
-	if *envU {
-		// Process and sanity-check command line.
-		if len(args) == 0 {
-			base.Fatalf("go env -u: no arguments given")
-		}
-		del := make(map[string]bool)
-		for _, arg := range args {
-			if err := checkEnvWrite(arg, ""); err != nil {
-				base.Fatalf("go env -u: %v", err)
-			}
-			del[arg] = true
-		}
-		if del["GOOS"] || del["GOARCH"] {
-			goos, goarch := cfg.Goos, cfg.Goarch
-			if del["GOOS"] {
-				goos = getOrigEnv("GOOS")
-				if goos == "" {
-					goos = build.Default.GOOS
-				}
-			}
-			if del["GOARCH"] {
-				goarch = getOrigEnv("GOARCH")
-				if goarch == "" {
-					goarch = build.Default.GOARCH
-				}
-			}
-			if err := work.CheckGOOSARCHPair(goos, goarch); err != nil {
-				base.Fatalf("go env -u: %v", err)
-			}
-		}
-		updateEnvFile(nil, del)
-		return
-	}
-
 	if len(args) > 0 {
 		if *envJson {
 			var es []cfg.EnvVar
@@ -351,6 +272,109 @@
 	PrintEnv(os.Stdout, env)
 }
 
+func runEnvW(args []string) {
+	// Process and sanity-check command line.
+	if len(args) == 0 {
+		base.Fatalf("go env -w: no KEY=VALUE arguments given")
+	}
+	osEnv := make(map[string]string)
+	for _, e := range cfg.OrigEnv {
+		if i := strings.Index(e, "="); i >= 0 {
+			osEnv[e[:i]] = e[i+1:]
+		}
+	}
+	add := make(map[string]string)
+	for _, arg := range args {
+		i := strings.Index(arg, "=")
+		if i < 0 {
+			base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg)
+		}
+		key, val := arg[:i], arg[i+1:]
+		if err := checkEnvWrite(key, val); err != nil {
+			base.Fatalf("go env -w: %v", err)
+		}
+		if _, ok := add[key]; ok {
+			base.Fatalf("go env -w: multiple values for key: %s", key)
+		}
+		add[key] = val
+		if osVal := osEnv[key]; osVal != "" && osVal != val {
+			fmt.Fprintf(os.Stderr, "warning: go env -w %s=... does not override conflicting OS environment variable\n", key)
+		}
+	}
+
+	if err := checkBuildConfig(add, nil); err != nil {
+		base.Fatalf("go env -w: %v", err)
+	}
+
+	gotmp, okGOTMP := add["GOTMPDIR"]
+	if okGOTMP {
+		if !filepath.IsAbs(gotmp) && gotmp != "" {
+			base.Fatalf("go env -w: GOTMPDIR must be an absolute path")
+		}
+	}
+
+	updateEnvFile(add, nil)
+}
+
+func runEnvU(args []string) {
+	// Process and sanity-check command line.
+	if len(args) == 0 {
+		base.Fatalf("go env -u: no arguments given")
+	}
+	del := make(map[string]bool)
+	for _, arg := range args {
+		if err := checkEnvWrite(arg, ""); err != nil {
+			base.Fatalf("go env -u: %v", err)
+		}
+		del[arg] = true
+	}
+
+	if err := checkBuildConfig(nil, del); err != nil {
+		base.Fatalf("go env -u: %v", err)
+	}
+
+	updateEnvFile(nil, del)
+}
+
+// checkBuildConfig checks whether the build configuration is valid
+// after the specified configuration environment changes are applied.
+func checkBuildConfig(add map[string]string, del map[string]bool) error {
+	// get returns the value for key after applying add and del and
+	// reports whether it changed. cur should be the current value
+	// (i.e., before applying changes) and def should be the default
+	// value (i.e., when no environment variables are provided at all).
+	get := func(key, cur, def string) (string, bool) {
+		if val, ok := add[key]; ok {
+			return val, true
+		}
+		if del[key] {
+			val := getOrigEnv(key)
+			if val == "" {
+				val = def
+			}
+			return val, true
+		}
+		return cur, false
+	}
+
+	goos, okGOOS := get("GOOS", cfg.Goos, build.Default.GOOS)
+	goarch, okGOARCH := get("GOARCH", cfg.Goarch, build.Default.GOARCH)
+	if okGOOS || okGOARCH {
+		if err := work.CheckGOOSARCHPair(goos, goarch); err != nil {
+			return err
+		}
+	}
+
+	goexperiment, okGOEXPERIMENT := get("GOEXPERIMENT", buildcfg.GOEXPERIMENT(), "")
+	if okGOEXPERIMENT {
+		if _, _, err := buildcfg.ParseGOEXPERIMENT(goos, goarch, goexperiment); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 // PrintEnv prints the environment variables to w.
 func PrintEnv(w io.Writer, env []cfg.EnvVar) {
 	for _, e := range env {
diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
index 2f86e41..490ff1f 100644
--- a/src/cmd/go/internal/help/helpdoc.go
+++ b/src/cmd/go/internal/help/helpdoc.go
@@ -598,6 +598,9 @@
 	GOMIPS64
 		For GOARCH=mips64{,le}, whether to use floating point instructions.
 		Valid values are hardfloat (default), softfloat.
+	GOPPC64
+		For GOARCH=ppc64{,le}, the target ISA (Instruction Set Architecture).
+		Valid values are power8 (default), power9.
 	GOWASM
 		For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use.
 		Valid values are satconv, signext.
@@ -607,6 +610,12 @@
 	GCCGOTOOLDIR
 		If set, where to find gccgo tools, such as cgo.
 		The default is based on how gccgo was configured.
+	GOEXPERIMENT
+		Comma-separated list of toolchain experiments to enable or disable.
+		The list of available experiments may change arbitrarily over time.
+		See src/internal/goexperiment/flags.go for currently valid values.
+		Warning: This variable is provided for the development and testing
+		of the Go toolchain itself. Use beyond that purpose is unsupported.
 	GOROOT_FINAL
 		The root of the installed Go tree, when it is
 		installed in a location other than where it is built.
@@ -784,7 +793,7 @@
 	Long: `
 A build constraint, also known as a build tag, is a line comment that begins
 
-	// +build
+	//go:build
 
 that lists the conditions under which a file should be included in the package.
 Constraints may appear in any kind of source file (not just Go), but
@@ -792,30 +801,20 @@
 only by blank lines and other line comments. These rules mean that in Go
 files a build constraint must appear before the package clause.
 
-To distinguish build constraints from package documentation, a series of
-build constraints must be followed by a blank line.
+To distinguish build constraints from package documentation,
+a build constraint should be followed by a blank line.
 
-A build constraint is evaluated as the OR of space-separated options.
-Each option evaluates as the AND of its comma-separated terms.
-Each term consists of letters, digits, underscores, and dots.
-A term may be negated with a preceding !.
-For example, the build constraint:
+A build constraint is evaluated as an expression containing options
+combined by ||, &&, and ! operators and parentheses. Operators have
+the same meaning as in Go.
 
-	// +build linux,386 darwin,!cgo
+For example, the following build constraint constrains a file to
+build when the "linux" and "386" constraints are satisfied, or when
+"darwin" is satisfied and "cgo" is not:
 
-corresponds to the boolean formula:
+	//go:build (linux && 386) || (darwin && !cgo)
 
-	(linux AND 386) OR (darwin AND (NOT cgo))
-
-A file may have multiple build constraints. The overall constraint is the AND
-of the individual constraints. That is, the build constraints:
-
-	// +build linux darwin
-	// +build amd64
-
-corresponds to the boolean formula:
-
-	(linux OR darwin) AND amd64
+It is an error for a file to have more than one //go:build line.
 
 During a particular build, the following words are satisfied:
 
@@ -853,22 +852,26 @@
 
 To keep a file from being considered for the build:
 
-	// +build ignore
+	//go:build ignore
 
 (any other unsatisfied word will work as well, but "ignore" is conventional.)
 
 To build a file only when using cgo, and only on Linux and OS X:
 
-	// +build linux,cgo darwin,cgo
+	//go:build cgo && (linux || darwin)
 
 Such a file is usually paired with another file implementing the
 default functionality for other systems, which in this case would
 carry the constraint:
 
-	// +build !linux,!darwin !cgo
+	//go:build !(cgo && (linux || darwin))
 
 Naming a file dns_windows.go will cause it to be included only when
 building the package for Windows; similarly, math_386.s will be included
 only when building the package for 32-bit x86.
+
+Go versions 1.16 and earlier used a different syntax for build constraints,
+with a "// +build" prefix. The gofmt command will add an equivalent //go:build
+constraint when encountering the older syntax.
 `,
 }
diff --git a/src/cmd/go/internal/imports/read.go b/src/cmd/go/internal/imports/read.go
index 5e27078..70d5190 100644
--- a/src/cmd/go/internal/imports/read.go
+++ b/src/cmd/go/internal/imports/read.go
@@ -8,6 +8,7 @@
 
 import (
 	"bufio"
+	"bytes"
 	"errors"
 	"io"
 	"unicode/utf8"
@@ -22,6 +23,19 @@
 	nerr int
 }
 
+var bom = []byte{0xef, 0xbb, 0xbf}
+
+func newImportReader(b *bufio.Reader) *importReader {
+	// Remove leading UTF-8 BOM.
+	// Per https://golang.org/ref/spec#Source_code_representation:
+	// a compiler may ignore a UTF-8-encoded byte order mark (U+FEFF)
+	// if it is the first Unicode code point in the source text.
+	if leadingBytes, err := b.Peek(3); err == nil && bytes.Equal(leadingBytes, bom) {
+		b.Discard(3)
+	}
+	return &importReader{b: b}
+}
+
 func isIdent(c byte) bool {
 	return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
 }
@@ -201,7 +215,7 @@
 // ReadComments is like io.ReadAll, except that it only reads the leading
 // block of comments in the file.
 func ReadComments(f io.Reader) ([]byte, error) {
-	r := &importReader{b: bufio.NewReader(f)}
+	r := newImportReader(bufio.NewReader(f))
 	r.peekByte(true)
 	if r.err == nil && !r.eof {
 		// Didn't reach EOF, so must have found a non-space byte. Remove it.
@@ -213,7 +227,7 @@
 // ReadImports is like io.ReadAll, except that it expects a Go file as input
 // and stops reading the input once the imports have completed.
 func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
-	r := &importReader{b: bufio.NewReader(f)}
+	r := newImportReader(bufio.NewReader(f))
 
 	r.readKeyword("package")
 	r.readIdent()
diff --git a/src/cmd/go/internal/imports/read_test.go b/src/cmd/go/internal/imports/read_test.go
index 6ea356f..6a1a652 100644
--- a/src/cmd/go/internal/imports/read_test.go
+++ b/src/cmd/go/internal/imports/read_test.go
@@ -66,6 +66,10 @@
 		`,
 		"",
 	},
+	{
+		"\ufeff𝔻" + `package p; import "x";ℙvar x = 1`,
+		"",
+	},
 }
 
 var readCommentsTests = []readTest{
@@ -82,6 +86,10 @@
 		"",
 	},
 	{
+		"\ufeff𝔻" + `ℙpackage p; import . "x"`,
+		"",
+	},
+	{
 		`// foo
 
 		/* bar */
@@ -94,6 +102,19 @@
 		ℙHello, world`,
 		"",
 	},
+	{
+		"\ufeff𝔻" + `// foo
+
+		/* bar */
+
+		/* quux */ // baz
+
+		/*/ zot */
+
+		// asdf
+		ℙHello, world`,
+		"",
+	},
 }
 
 func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, error)) {
@@ -107,6 +128,11 @@
 			in = tt.in[:j] + tt.in[j+len("ℙ"):]
 			testOut = tt.in[:j]
 		}
+		d := strings.Index(tt.in, "𝔻")
+		if d >= 0 {
+			in = in[:d] + in[d+len("𝔻"):]
+			testOut = testOut[d+len("𝔻"):]
+		}
 		r := strings.NewReader(in)
 		buf, err := read(r)
 		if err != nil {
diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go
index 53aaf31..7cb9ec6 100644
--- a/src/cmd/go/internal/list/list.go
+++ b/src/cmd/go/internal/list/list.go
@@ -724,8 +724,18 @@
 
 	// Record non-identity import mappings in p.ImportMap.
 	for _, p := range pkgs {
-		for i, srcPath := range p.Internal.RawImports {
-			path := p.Imports[i]
+		nRaw := len(p.Internal.RawImports)
+		for i, path := range p.Imports {
+			var srcPath string
+			if i < nRaw {
+				srcPath = p.Internal.RawImports[i]
+			} else {
+				// This path is not within the raw imports, so it must be an import
+				// found only within CompiledGoFiles. Those paths are found in
+				// CompiledImports.
+				srcPath = p.Internal.CompiledImports[i-nRaw]
+			}
+
 			if path != srcPath {
 				if p.ImportMap == nil {
 					p.ImportMap = make(map[string]string)
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index fa040bf..b3527c7 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -87,6 +87,7 @@
 	CgoFiles          []string `json:",omitempty"` // .go source files that import "C"
 	CompiledGoFiles   []string `json:",omitempty"` // .go output from running cgo on CgoFiles
 	IgnoredGoFiles    []string `json:",omitempty"` // .go source files ignored due to build constraints
+	InvalidGoFiles    []string `json:",omitempty"` // .go source files with detected problems (parse error, wrong package name, and so on)
 	IgnoredOtherFiles []string `json:",omitempty"` // non-.go source files ignored due to build constraints
 	CFiles            []string `json:",omitempty"` // .c source files
 	CXXFiles          []string `json:",omitempty"` // .cc, .cpp and .cxx source files
@@ -144,6 +145,7 @@
 		p.CgoFiles,
 		// no p.CompiledGoFiles, because they are from GoFiles or generated by us
 		p.IgnoredGoFiles,
+		// no p.InvalidGoFiles, because they are from GoFiles
 		p.IgnoredOtherFiles,
 		p.CFiles,
 		p.CXXFiles,
@@ -192,8 +194,8 @@
 	// Unexported fields are not part of the public API.
 	Build             *build.Package
 	Imports           []*Package           // this package's direct imports
-	CompiledImports   []string             // additional Imports necessary when using CompiledGoFiles (all from standard library)
-	RawImports        []string             // this package's original imports as they appear in the text of the program
+	CompiledImports   []string             // additional Imports necessary when using CompiledGoFiles (all from standard library); 1:1 with the end of PackagePublic.Imports
+	RawImports        []string             // this package's original imports as they appear in the text of the program; 1:1 with the end of PackagePublic.Imports
 	ForceLibrary      bool                 // this package is a library (even if named "main")
 	CmdlineFiles      bool                 // package built from files listed on command line
 	CmdlinePkg        bool                 // package listed on command line
@@ -371,6 +373,7 @@
 	p.GoFiles = pp.GoFiles
 	p.CgoFiles = pp.CgoFiles
 	p.IgnoredGoFiles = pp.IgnoredGoFiles
+	p.InvalidGoFiles = pp.InvalidGoFiles
 	p.IgnoredOtherFiles = pp.IgnoredOtherFiles
 	p.CFiles = pp.CFiles
 	p.CXXFiles = pp.CXXFiles
@@ -852,7 +855,9 @@
 				buildMode = build.ImportComment
 			}
 			data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode)
-			if data.p.Root == "" && cfg.ModulesEnabled {
+			if cfg.ModulesEnabled {
+				// Override data.p.Root, since ImportDir sets it to $GOPATH, if
+				// the module is inside $GOPATH/src.
 				if info := modload.PackageModuleInfo(ctx, path); info != nil {
 					data.p.Root = info.Dir
 				}
@@ -1800,35 +1805,37 @@
 		}
 	}
 
-	// Cgo translation adds imports of "unsafe", "runtime/cgo" and "syscall",
-	// except for certain packages, to avoid circular dependencies.
-	if p.UsesCgo() {
-		addImport("unsafe", true)
-	}
-	if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
-		addImport("runtime/cgo", true)
-	}
-	if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
-		addImport("syscall", true)
-	}
-
-	// SWIG adds imports of some standard packages.
-	if p.UsesSwig() {
-		addImport("unsafe", true)
-		if cfg.BuildContext.Compiler != "gccgo" {
+	if !opts.IgnoreImports {
+		// Cgo translation adds imports of "unsafe", "runtime/cgo" and "syscall",
+		// except for certain packages, to avoid circular dependencies.
+		if p.UsesCgo() {
+			addImport("unsafe", true)
+		}
+		if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
 			addImport("runtime/cgo", true)
 		}
-		addImport("syscall", true)
-		addImport("sync", true)
+		if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
+			addImport("syscall", true)
+		}
 
-		// TODO: The .swig and .swigcxx files can use
-		// %go_import directives to import other packages.
-	}
+		// SWIG adds imports of some standard packages.
+		if p.UsesSwig() {
+			addImport("unsafe", true)
+			if cfg.BuildContext.Compiler != "gccgo" {
+				addImport("runtime/cgo", true)
+			}
+			addImport("syscall", true)
+			addImport("sync", true)
 
-	// The linker loads implicit dependencies.
-	if p.Name == "main" && !p.Internal.ForceLibrary {
-		for _, dep := range LinkerDeps(p) {
-			addImport(dep, false)
+			// TODO: The .swig and .swigcxx files can use
+			// %go_import directives to import other packages.
+		}
+
+		// The linker loads implicit dependencies.
+		if p.Name == "main" && !p.Internal.ForceLibrary {
+			for _, dep := range LinkerDeps(p) {
+				addImport(dep, false)
+			}
 		}
 	}
 
@@ -2390,7 +2397,9 @@
 // PackageOpts control the behavior of PackagesAndErrors and other package
 // loading functions.
 type PackageOpts struct {
-	// IgnoreImports controls whether we ignore imports when loading packages.
+	// IgnoreImports controls whether we ignore explicit and implicit imports
+	// when loading packages.  Implicit imports are added when supporting Cgo
+	// or SWIG and when linking main packages.
 	IgnoreImports bool
 
 	// ModResolveTests indicates whether calls to the module loader should also
@@ -2499,7 +2508,7 @@
 	}
 
 	if opts.MainOnly {
-		pkgs = mainPackagesOnly(pkgs, patterns)
+		pkgs = mainPackagesOnly(pkgs, matches)
 	}
 
 	// Now that CmdlinePkg is set correctly,
@@ -2553,50 +2562,63 @@
 // mainPackagesOnly filters out non-main packages matched only by arguments
 // containing "..." and returns the remaining main packages.
 //
+// Packages with missing, invalid, or ambiguous names may be treated as
+// possibly-main packages.
+//
 // mainPackagesOnly sets a non-main package's Error field and returns it if it
 // is named by a literal argument.
 //
 // mainPackagesOnly prints warnings for non-literal arguments that only match
 // non-main packages.
-func mainPackagesOnly(pkgs []*Package, patterns []string) []*Package {
-	matchers := make([]func(string) bool, len(patterns))
-	for i, p := range patterns {
-		if strings.Contains(p, "...") {
-			matchers[i] = search.MatchPattern(p)
+func mainPackagesOnly(pkgs []*Package, matches []*search.Match) []*Package {
+	treatAsMain := map[string]bool{}
+	for _, m := range matches {
+		if m.IsLiteral() {
+			for _, path := range m.Pkgs {
+				treatAsMain[path] = true
+			}
 		}
 	}
 
-	matchedPkgs := make([]*Package, 0, len(pkgs))
-	mainCount := make([]int, len(patterns))
-	nonMainCount := make([]int, len(patterns))
+	var mains []*Package
 	for _, pkg := range pkgs {
-		if pkg.Name == "main" || (pkg.Incomplete && pkg.Name == "") {
-			matchedPkgs = append(matchedPkgs, pkg)
-			for i := range patterns {
-				if matchers[i] != nil && matchers[i](pkg.ImportPath) {
-					mainCount[i]++
-				}
-			}
-		} else {
-			for i := range patterns {
-				if matchers[i] == nil && patterns[i] == pkg.ImportPath {
-					if pkg.Error == nil {
-						pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
-					}
-					matchedPkgs = append(matchedPkgs, pkg)
-				} else if matchers[i] != nil && matchers[i](pkg.ImportPath) {
-					nonMainCount[i]++
-				}
-			}
+		if pkg.Name == "main" {
+			treatAsMain[pkg.ImportPath] = true
+			mains = append(mains, pkg)
+			continue
 		}
-	}
-	for i, p := range patterns {
-		if matchers[i] != nil && mainCount[i] == 0 && nonMainCount[i] > 0 {
-			fmt.Fprintf(os.Stderr, "go: warning: %q matched no main packages\n", p)
+
+		if len(pkg.InvalidGoFiles) > 0 { // TODO(#45999): && pkg.Name == "", but currently go/build sets pkg.Name arbitrarily if it is ambiguous.
+			// The package has (or may have) conflicting names, and we can't easily
+			// tell whether one of them is "main". So assume that it could be, and
+			// report an error for the package.
+			treatAsMain[pkg.ImportPath] = true
+		}
+		if treatAsMain[pkg.ImportPath] {
+			if pkg.Error == nil {
+				pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
+			}
+			mains = append(mains, pkg)
 		}
 	}
 
-	return matchedPkgs
+	for _, m := range matches {
+		if m.IsLiteral() || len(m.Pkgs) == 0 {
+			continue
+		}
+		foundMain := false
+		for _, path := range m.Pkgs {
+			if treatAsMain[path] {
+				foundMain = true
+				break
+			}
+		}
+		if !foundMain {
+			fmt.Fprintf(os.Stderr, "go: warning: %q matched only non-main packages\n", m.Pattern())
+		}
+	}
+
+	return mains
 }
 
 type mainPackageError struct {
diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go
index 6baa1db..c828296 100644
--- a/src/cmd/go/internal/load/test.go
+++ b/src/cmd/go/internal/load/test.go
@@ -116,7 +116,7 @@
 			// Can't change that code, because that code is only for loading the
 			// non-test copy of a package.
 			ptestErr = &PackageError{
-				ImportStack:   testImportStack(stk[0], p1, p.ImportPath),
+				ImportStack:   importCycleStack(p1, p.ImportPath),
 				Err:           errors.New("import cycle not allowed in test"),
 				IsImportCycle: true,
 			}
@@ -375,22 +375,44 @@
 	return pmain, ptest, pxtest
 }
 
-func testImportStack(top string, p *Package, target string) []string {
-	stk := []string{top, p.ImportPath}
-Search:
-	for p.ImportPath != target {
-		for _, p1 := range p.Internal.Imports {
-			if p1.ImportPath == target || str.Contains(p1.Deps, target) {
-				stk = append(stk, p1.ImportPath)
-				p = p1
-				continue Search
+// importCycleStack returns an import stack from p to the package whose import
+// path is target.
+func importCycleStack(p *Package, target string) []string {
+	// importerOf maps each import path to its importer nearest to p.
+	importerOf := map[string]string{p.ImportPath: ""}
+
+	// q is a breadth-first queue of packages to search for target.
+	// Every package added to q has a corresponding entry in pathTo.
+	//
+	// We search breadth-first for two reasons:
+	//
+	// 	1. We want to report the shortest cycle.
+	//
+	// 	2. If p contains multiple cycles, the first cycle we encounter might not
+	// 	   contain target. To ensure termination, we have to break all cycles
+	// 	   other than the first.
+	q := []*Package{p}
+
+	for len(q) > 0 {
+		p := q[0]
+		q = q[1:]
+		if path := p.ImportPath; path == target {
+			var stk []string
+			for path != "" {
+				stk = append(stk, path)
+				path = importerOf[path]
+			}
+			return stk
+		}
+		for _, dep := range p.Internal.Imports {
+			if _, ok := importerOf[dep.ImportPath]; !ok {
+				importerOf[dep.ImportPath] = p.ImportPath
+				q = append(q, dep)
 			}
 		}
-		// Can't happen, but in case it does...
-		stk = append(stk, "<lost path to cycle>")
-		break
 	}
-	return stk
+
+	panic("lost path to cycle")
 }
 
 // recompileForTest copies and replaces certain packages in pmain's dependency
diff --git a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go
index 729df5c..e4923f6 100644
--- a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go
+++ b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go
@@ -11,7 +11,6 @@
 	"io/fs"
 	"os"
 
-	"cmd/go/internal/fsys"
 	"cmd/go/internal/lockedfile/internal/filelock"
 )
 
@@ -21,7 +20,7 @@
 	// calls for Linux and Windows anyway, so it's simpler to use that approach
 	// consistently.
 
-	f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm)
+	f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm)
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go
index 3d4b97d..979118b 100644
--- a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go
+++ b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go
@@ -13,8 +13,6 @@
 	"os"
 	"strings"
 	"time"
-
-	"cmd/go/internal/fsys"
 )
 
 // Opening an exclusive-use file returns an error.
@@ -59,7 +57,7 @@
 	// If the file was unpacked or created by some other program, it might not
 	// have the ModeExclusive bit set. Set it before we call OpenFile, so that we
 	// can be confident that a successful OpenFile implies exclusive use.
-	if fi, err := fsys.Stat(name); err == nil {
+	if fi, err := os.Stat(name); err == nil {
 		if fi.Mode()&fs.ModeExclusive == 0 {
 			if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil {
 				return nil, err
@@ -72,7 +70,7 @@
 	nextSleep := 1 * time.Millisecond
 	const maxSleep = 500 * time.Millisecond
 	for {
-		f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive)
+		f, err := os.OpenFile(name, flag, perm|fs.ModeExclusive)
 		if err == nil {
 			return f, nil
 		}
diff --git a/src/cmd/go/internal/modcmd/download.go b/src/cmd/go/internal/modcmd/download.go
index a6c6d91..0e5af85 100644
--- a/src/cmd/go/internal/modcmd/download.go
+++ b/src/cmd/go/internal/modcmd/download.go
@@ -86,9 +86,11 @@
 	if !modload.HasModRoot() && len(args) == 0 {
 		base.Fatalf("go mod download: no modules specified (see 'go help mod download')")
 	}
-	if len(args) == 0 {
+	haveExplicitArgs := len(args) > 0
+	if !haveExplicitArgs {
 		args = []string{"all"}
-	} else if modload.HasModRoot() {
+	}
+	if modload.HasModRoot() {
 		modload.LoadModFile(ctx) // to fill Target
 		targetAtUpgrade := modload.Target.Path + "@upgrade"
 		targetAtPatch := modload.Target.Path + "@patch"
@@ -135,6 +137,18 @@
 	type token struct{}
 	sem := make(chan token, runtime.GOMAXPROCS(0))
 	infos, infosErr := modload.ListModules(ctx, args, 0)
+	if !haveExplicitArgs {
+		// 'go mod download' is sometimes run without arguments to pre-populate the
+		// module cache. It may fetch modules that aren't needed to build packages
+		// in the main mdoule. This is usually not intended, so don't save sums for
+		// downloaded modules (golang.org/issue/45332).
+		// TODO(golang.org/issue/45551): For now, in ListModules, save sums needed
+		// to load the build list (same as 1.15 behavior). In the future, report an
+		// error if go.mod or go.sum need to be updated after loading the build
+		// list.
+		modload.DisallowWriteGoMod()
+	}
+
 	for _, info := range infos {
 		if info.Replace != nil {
 			info = info.Replace
@@ -185,8 +199,15 @@
 		base.ExitIfErrors()
 	}
 
-	// Update go.mod and especially go.sum if needed.
-	modload.WriteGoMod(ctx)
+	// If there were explicit arguments, update go.mod and especially go.sum.
+	// 'go mod download mod@version' is a useful way to add a sum without using
+	// 'go get mod@version', which may have other side effects. We print this in
+	// some error message hints.
+	//
+	// Don't save sums for 'go mod download' without arguments; see comment above.
+	if haveExplicitArgs {
+		modload.WriteGoMod(ctx)
+	}
 
 	// If there was an error matching some of the requested packages, emit it now
 	// (after we've written the checksums for the modules that were downloaded
diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go
index 79a93ca..bb3d521 100644
--- a/src/cmd/go/internal/modcmd/edit.go
+++ b/src/cmd/go/internal/modcmd/edit.go
@@ -25,7 +25,7 @@
 )
 
 var cmdEdit = &base.Command{
-	UsageLine: "go mod edit [editing flags] [go.mod]",
+	UsageLine: "go mod edit [editing flags] [-fmt|-print|-json] [go.mod]",
 	Short:     "edit go.mod from tools or scripts",
 	Long: `
 Edit provides a command-line interface for editing go.mod,
@@ -196,7 +196,7 @@
 
 	if *editGo != "" {
 		if !modfile.GoVersionRE.MatchString(*editGo) {
-			base.Fatalf(`go mod: invalid -go option; expecting something like "-go 1.12"`)
+			base.Fatalf(`go mod: invalid -go option; expecting something like "-go %s"`, modload.LatestGoVersion())
 		}
 	}
 
diff --git a/src/cmd/go/internal/modcmd/graph.go b/src/cmd/go/internal/modcmd/graph.go
index 7785330..ac81f26 100644
--- a/src/cmd/go/internal/modcmd/graph.go
+++ b/src/cmd/go/internal/modcmd/graph.go
@@ -18,7 +18,7 @@
 )
 
 var cmdGraph = &base.Command{
-	UsageLine: "go mod graph",
+	UsageLine: "go mod graph [-go=version]",
 	Short:     "print module requirement graph",
 	Long: `
 Graph prints the module requirement graph (with replacements applied)
@@ -26,12 +26,21 @@
 and one of its requirements. Each module is identified as a string of the form
 path@version, except for the main module, which has no @version suffix.
 
+The -go flag causes graph to report the module graph as loaded by the
+given Go version, instead of the version indicated by the 'go' directive
+in the go.mod file.
+
 See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'.
 	`,
 	Run: runGraph,
 }
 
+var (
+	graphGo goVersionFlag
+)
+
 func init() {
+	cmdGraph.Flag.Var(&graphGo, "go", "")
 	base.AddModCommonFlags(&cmdGraph.Flag)
 }
 
@@ -41,7 +50,7 @@
 	}
 	modload.ForceUseModules = true
 	modload.RootMode = modload.NeedRoot
-	mg := modload.LoadModGraph(ctx)
+	mg := modload.LoadModGraph(ctx, graphGo.String())
 
 	w := bufio.NewWriter(os.Stdout)
 	defer w.Flush()
diff --git a/src/cmd/go/internal/modcmd/init.go b/src/cmd/go/internal/modcmd/init.go
index 73cc282..958c306 100644
--- a/src/cmd/go/internal/modcmd/init.go
+++ b/src/cmd/go/internal/modcmd/init.go
@@ -13,7 +13,7 @@
 )
 
 var cmdInit = &base.Command{
-	UsageLine: "go mod init [module]",
+	UsageLine: "go mod init [module-path]",
 	Short:     "initialize new module in current directory",
 	Long: `
 Init initializes and writes a new go.mod file in the current directory, in
diff --git a/src/cmd/go/internal/modcmd/tidy.go b/src/cmd/go/internal/modcmd/tidy.go
index c72ec30..fe25507 100644
--- a/src/cmd/go/internal/modcmd/tidy.go
+++ b/src/cmd/go/internal/modcmd/tidy.go
@@ -12,12 +12,14 @@
 	"cmd/go/internal/imports"
 	"cmd/go/internal/modload"
 	"context"
+	"fmt"
 
 	"golang.org/x/mod/modfile"
+	"golang.org/x/mod/semver"
 )
 
 var cmdTidy = &base.Command{
-	UsageLine: "go mod tidy [-e] [-v] [-go=version]",
+	UsageLine: "go mod tidy [-e] [-v] [-go=version] [-compat=version]",
 	Short:     "add missing and remove unused modules",
 	Long: `
 Tidy makes sure go.mod matches the source code in the module.
@@ -38,34 +40,64 @@
 (Go versions 1.17 and higher retain more requirements in order to
 support lazy module loading.)
 
+The -compat flag preserves any additional checksums needed for the
+'go' command from the indicated major Go release to successfully load
+the module graph, and causes tidy to error out if that version of the
+'go' command would load any imported package from a different module
+version. By default, tidy acts as if the -compat flag were set to the
+version prior to the one indicated by the 'go' directive in the go.mod
+file.
+
 See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'.
 	`,
 	Run: runTidy,
 }
 
 var (
-	tidyE  bool   // if true, report errors but proceed anyway.
-	tidyGo string // go version to write to the tidied go.mod file (toggles lazy loading)
+	tidyE      bool          // if true, report errors but proceed anyway.
+	tidyGo     goVersionFlag // go version to write to the tidied go.mod file (toggles lazy loading)
+	tidyCompat goVersionFlag // go version for which the tidied go.mod and go.sum files should be “compatible”
 )
 
 func init() {
 	cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "")
 	cmdTidy.Flag.BoolVar(&tidyE, "e", false, "")
-	cmdTidy.Flag.StringVar(&tidyGo, "go", "", "")
+	cmdTidy.Flag.Var(&tidyGo, "go", "")
+	cmdTidy.Flag.Var(&tidyCompat, "compat", "")
 	base.AddModCommonFlags(&cmdTidy.Flag)
 }
 
+// A goVersionFlag is a flag.Value representing a supported Go version.
+//
+// (Note that the -go argument to 'go mod edit' is *not* a goVersionFlag.
+// It intentionally allows newer-than-supported versions as arguments.)
+type goVersionFlag struct {
+	v string
+}
+
+func (f *goVersionFlag) String() string   { return f.v }
+func (f *goVersionFlag) Get() interface{} { return f.v }
+
+func (f *goVersionFlag) Set(s string) error {
+	if s != "" {
+		latest := modload.LatestGoVersion()
+		if !modfile.GoVersionRE.MatchString(s) {
+			return fmt.Errorf("expecting a Go version like %q", latest)
+		}
+		if semver.Compare("v"+s, "v"+latest) > 0 {
+			return fmt.Errorf("maximum supported Go version is %s", latest)
+		}
+	}
+
+	f.v = s
+	return nil
+}
+
 func runTidy(ctx context.Context, cmd *base.Command, args []string) {
 	if len(args) > 0 {
 		base.Fatalf("go mod tidy: no arguments allowed")
 	}
 
-	if tidyGo != "" {
-		if !modfile.GoVersionRE.MatchString(tidyGo) {
-			base.Fatalf(`go mod: invalid -go option %q; expecting something like "-go 1.17"`, tidyGo)
-		}
-	}
-
 	// Tidy aims to make 'go test' reproducible for any package in 'all', so we
 	// need to include test dependencies. For modules that specify go 1.15 or
 	// earlier this is a no-op (because 'all' saturates transitive test
@@ -80,9 +112,10 @@
 	modload.RootMode = modload.NeedRoot
 
 	modload.LoadPackages(ctx, modload.PackageOpts{
-		GoVersion:                tidyGo,
+		GoVersion:                tidyGo.String(),
 		Tags:                     imports.AnyTags(),
 		Tidy:                     true,
+		TidyCompatibleVersion:    tidyCompat.String(),
 		VendorModulesInGOROOTSrc: true,
 		ResolveMissingImports:    true,
 		LoadTests:                true,
diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go
index 8e1c043..713d5f9 100644
--- a/src/cmd/go/internal/modcmd/vendor.go
+++ b/src/cmd/go/internal/modcmd/vendor.go
@@ -13,6 +13,7 @@
 	"io"
 	"io/fs"
 	"os"
+	"path"
 	"path/filepath"
 	"sort"
 	"strings"
@@ -299,7 +300,7 @@
 		if modPath == pkg {
 			break
 		}
-		pkg = filepath.Dir(pkg)
+		pkg = path.Dir(pkg)
 		dst = filepath.Dir(dst)
 		src = filepath.Dir(src)
 	}
diff --git a/src/cmd/go/internal/modcmd/verify.go b/src/cmd/go/internal/modcmd/verify.go
index 5c321c7..5a6eca3 100644
--- a/src/cmd/go/internal/modcmd/verify.go
+++ b/src/cmd/go/internal/modcmd/verify.go
@@ -54,7 +54,8 @@
 	sem := make(chan token, runtime.GOMAXPROCS(0))
 
 	// Use a slice of result channels, so that the output is deterministic.
-	mods := modload.LoadModGraph(ctx).BuildList()[1:]
+	const defaultGoVersion = ""
+	mods := modload.LoadModGraph(ctx, defaultGoVersion).BuildList()[1:]
 	errsChans := make([]<-chan []error, len(mods))
 
 	for i, mod := range mods {
diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go
index f3b58a1..b01b467 100644
--- a/src/cmd/go/internal/modfetch/cache.go
+++ b/src/cmd/go/internal/modfetch/cache.go
@@ -152,7 +152,7 @@
 // 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/modfetch/codehost/git_test.go b/src/cmd/go/internal/modfetch/codehost/git_test.go
index 89a73ba..a684fa1 100644
--- a/src/cmd/go/internal/modfetch/codehost/git_test.go
+++ b/src/cmd/go/internal/modfetch/codehost/git_test.go
@@ -8,7 +8,6 @@
 	"archive/zip"
 	"bytes"
 	"flag"
-	"fmt"
 	"internal/testenv"
 	"io"
 	"io/fs"
@@ -47,12 +46,6 @@
 var localGitRepo string
 
 func testMain(m *testing.M) int {
-	if _, err := exec.LookPath("git"); err != nil {
-		fmt.Fprintln(os.Stderr, "skipping because git binary not found")
-		fmt.Println("PASS")
-		return 0
-	}
-
 	dir, err := os.MkdirTemp("", "gitrepo-test-")
 	if err != nil {
 		log.Fatal(err)
@@ -60,23 +53,25 @@
 	defer os.RemoveAll(dir)
 
 	if testenv.HasExternalNetwork() && testenv.HasExec() {
-		// Clone gitrepo1 into a local directory.
-		// If we use a file:// URL to access the local directory,
-		// then git starts up all the usual protocol machinery,
-		// which will let us test remote git archive invocations.
-		localGitRepo = filepath.Join(dir, "gitrepo2")
-		if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil {
-			log.Fatal(err)
-		}
-		if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil {
-			log.Fatal(err)
+		if _, err := exec.LookPath("git"); err == nil {
+			// Clone gitrepo1 into a local directory.
+			// If we use a file:// URL to access the local directory,
+			// then git starts up all the usual protocol machinery,
+			// which will let us test remote git archive invocations.
+			localGitRepo = filepath.Join(dir, "gitrepo2")
+			if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil {
+				log.Fatal(err)
+			}
+			if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil {
+				log.Fatal(err)
+			}
 		}
 	}
 
 	return m.Run()
 }
 
-func testRepo(remote string) (Repo, error) {
+func testRepo(t *testing.T, remote string) (Repo, error) {
 	if remote == "localGitRepo" {
 		// Convert absolute path to file URL. LocalGitRepo will not accept
 		// Windows absolute paths because they look like a host:path remote.
@@ -87,15 +82,17 @@
 		} else {
 			url = "file:///" + filepath.ToSlash(localGitRepo)
 		}
+		testenv.MustHaveExecPath(t, "git")
 		return LocalGitRepo(url)
 	}
-	kind := "git"
+	vcs := "git"
 	for _, k := range []string{"hg"} {
 		if strings.Contains(remote, "/"+k+"/") {
-			kind = k
+			vcs = k
 		}
 	}
-	return NewRepo(kind, remote)
+	testenv.MustHaveExecPath(t, vcs)
+	return NewRepo(vcs, remote)
 }
 
 var tagsTests = []struct {
@@ -116,7 +113,7 @@
 
 	for _, tt := range tagsTests {
 		f := func(t *testing.T) {
-			r, err := testRepo(tt.repo)
+			r, err := testRepo(t, tt.repo)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -168,7 +165,7 @@
 
 	for _, tt := range latestTests {
 		f := func(t *testing.T) {
-			r, err := testRepo(tt.repo)
+			r, err := testRepo(t, tt.repo)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -221,7 +218,7 @@
 
 	for _, tt := range readFileTests {
 		f := func(t *testing.T) {
-			r, err := testRepo(tt.repo)
+			r, err := testRepo(t, tt.repo)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -412,7 +409,7 @@
 
 	for _, tt := range readZipTests {
 		f := func(t *testing.T) {
-			r, err := testRepo(tt.repo)
+			r, err := testRepo(t, tt.repo)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -581,7 +578,7 @@
 
 	for _, tt := range statTests {
 		f := func(t *testing.T) {
-			r, err := testRepo(tt.repo)
+			r, err := testRepo(t, tt.repo)
 			if err != nil {
 				t.Fatal(err)
 			}
diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go
index f817a04..dfef9f7 100644
--- a/src/cmd/go/internal/modfetch/coderepo.go
+++ b/src/cmd/go/internal/modfetch/coderepo.go
@@ -864,22 +864,25 @@
 	data, err = r.code.ReadFile(rev, path.Join(dir, "go.mod"), codehost.MaxGoMod)
 	if err != nil {
 		if os.IsNotExist(err) {
-			return r.legacyGoMod(rev, dir), nil
+			return LegacyGoMod(r.modPath), nil
 		}
 		return nil, err
 	}
 	return data, nil
 }
 
-func (r *codeRepo) legacyGoMod(rev, dir string) []byte {
-	// We used to try to build a go.mod reflecting pre-existing
-	// package management metadata files, but the conversion
-	// was inherently imperfect (because those files don't have
-	// exactly the same semantics as go.mod) and, when done
-	// for dependencies in the middle of a build, impossible to
-	// correct. So we stopped.
-	// Return a fake go.mod that simply declares the module path.
-	return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(r.modPath)))
+// LegacyGoMod generates a fake go.mod file for a module that doesn't have one.
+// The go.mod file contains a module directive and nothing else: no go version,
+// no requirements.
+//
+// We used to try to build a go.mod reflecting pre-existing
+// package management metadata files, but the conversion
+// was inherently imperfect (because those files don't have
+// exactly the same semantics as go.mod) and, when done
+// for dependencies in the middle of a build, impossible to
+// correct. So we stopped.
+func LegacyGoMod(modPath string) []byte {
+	return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(modPath)))
 }
 
 func (r *codeRepo) modPrefix(rev string) string {
diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go
index e40593a..d3d30d9 100644
--- a/src/cmd/go/internal/modfetch/fetch.go
+++ b/src/cmd/go/internal/modfetch/fetch.go
@@ -22,6 +22,7 @@
 
 	"cmd/go/internal/base"
 	"cmd/go/internal/cfg"
+	"cmd/go/internal/fsys"
 	"cmd/go/internal/lockedfile"
 	"cmd/go/internal/par"
 	"cmd/go/internal/robustio"
@@ -416,7 +417,18 @@
 
 	goSum.m = make(map[module.Version][]string)
 	goSum.status = make(map[modSum]modSumStatus)
-	data, err := lockedfile.Read(GoSumFile)
+	var (
+		data []byte
+		err  error
+	)
+	if actualSumFile, ok := fsys.OverlayPath(GoSumFile); ok {
+		// Don't lock go.sum if it's part of the overlay.
+		// On Plan 9, locking requires chmod, and we don't want to modify any file
+		// in the overlay. See #44700.
+		data, err = os.ReadFile(actualSumFile)
+	} else {
+		data, err = lockedfile.Read(GoSumFile)
+	}
 	if err != nil && !os.IsNotExist(err) {
 		return false, err
 	}
@@ -716,6 +728,9 @@
 	if cfg.BuildMod == "readonly" {
 		base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly")
 	}
+	if _, ok := fsys.OverlayPath(GoSumFile); ok {
+		base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay")
+	}
 
 	// Make a best-effort attempt to acquire the side lock, only to exclude
 	// previous versions of the 'go' command from making simultaneous edits.
diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go
index 3a24b6a..9672e55 100644
--- a/src/cmd/go/internal/modget/get.go
+++ b/src/cmd/go/internal/modget/get.go
@@ -38,6 +38,7 @@
 	"cmd/go/internal/base"
 	"cmd/go/internal/imports"
 	"cmd/go/internal/load"
+	"cmd/go/internal/modfetch"
 	"cmd/go/internal/modload"
 	"cmd/go/internal/par"
 	"cmd/go/internal/search"
@@ -386,14 +387,14 @@
 		}
 		load.CheckPackageErrors(pkgs)
 
-		haveExe := false
+		haveExternalExe := false
 		for _, pkg := range pkgs {
-			if pkg.Name == "main" {
-				haveExe = true
+			if pkg.Name == "main" && pkg.Module != nil && pkg.Module.Path != modload.Target.Path {
+				haveExternalExe = true
 				break
 			}
 		}
-		if haveExe {
+		if haveExternalExe {
 			fmt.Fprint(os.Stderr, "go get: installing executables with 'go get' in module mode is deprecated.")
 			var altMsg string
 			if modload.HasModRoot() {
@@ -505,7 +506,8 @@
 func newResolver(ctx context.Context, queries []*query) *resolver {
 	// LoadModGraph also sets modload.Target, which is needed by various resolver
 	// methods.
-	mg := modload.LoadModGraph(ctx)
+	const defaultGoVersion = ""
+	mg := modload.LoadModGraph(ctx, defaultGoVersion)
 
 	buildList := mg.BuildList()
 	initialVersion := make(map[string]string, len(buildList))
@@ -1152,6 +1154,7 @@
 		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.
 	}
 
@@ -1466,6 +1469,8 @@
 // checkPackageProblems reloads packages for the given patterns and reports
 // missing and ambiguous package errors. It also reports retractions and
 // deprecations for resolved modules and modules needed to build named packages.
+// It also adds a sum for each updated module in the build list if we had one
+// before and didn't get one while loading packages.
 //
 // We skip missing-package errors earlier in the process, since we want to
 // resolve pathSets ourselves, but at that point, we don't have enough context
@@ -1593,12 +1598,55 @@
 		})
 	}
 
+	// Load sums for updated modules that had sums before. When we update a
+	// module, we may update another module in the build list that provides a
+	// package in 'all' that wasn't loaded as part of this 'go get' command.
+	// If we don't add a sum for that module, builds may fail later.
+	// Note that an incidentally updated package could still import packages
+	// from unknown modules or from modules in the build list that we didn't
+	// need previously. We can't handle that case without loading 'all'.
+	sumErrs := make([]error, len(r.buildList))
+	for i := range r.buildList {
+		i := i
+		m := r.buildList[i]
+		mActual := m
+		if mRepl := modload.Replacement(m); mRepl.Path != "" {
+			mActual = mRepl
+		}
+		old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]}
+		if old.Version == "" {
+			continue
+		}
+		oldActual := old
+		if oldRepl := modload.Replacement(old); oldRepl.Path != "" {
+			oldActual = oldRepl
+		}
+		if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) {
+			continue
+		}
+		r.work.Add(func() {
+			if _, err := modfetch.DownloadZip(ctx, mActual); err != nil {
+				verb := "upgraded"
+				if semver.Compare(m.Version, old.Version) < 0 {
+					verb = "downgraded"
+				}
+				replaced := ""
+				if mActual != m {
+					replaced = fmt.Sprintf(" (replaced by %s)", mActual)
+				}
+				err = fmt.Errorf("%s %s %s => %s%s: error finding sum for %s: %v", verb, m.Path, old.Version, m.Version, replaced, mActual, err)
+				sumErrs[i] = err
+			}
+		})
+	}
+
 	<-r.work.Idle()
 
-	// Report deprecations, then retractions.
+	// Report deprecations, then retractions, then errors fetching sums.
+	// Only errors fetching sums are hard errors.
 	for _, mm := range deprecations {
 		if mm.message != "" {
-			fmt.Fprintf(os.Stderr, "go: warning: module %s is deprecated: %s\n", mm.m.Path, mm.message)
+			fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", mm.m.Path, mm.message)
 		}
 	}
 	var retractPath string
@@ -1615,6 +1663,12 @@
 	if retractPath != "" {
 		fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath)
 	}
+	for _, err := range sumErrs {
+		if err != nil {
+			base.Errorf("go: %v", err)
+		}
+	}
+	base.ExitIfErrors()
 }
 
 // reportChanges logs version changes to os.Stderr.
@@ -1750,7 +1804,8 @@
 		return false
 	}
 
-	r.buildList = modload.LoadModGraph(ctx).BuildList()
+	const defaultGoVersion = ""
+	r.buildList = modload.LoadModGraph(ctx, defaultGoVersion).BuildList()
 	r.buildListVersion = make(map[string]string, len(r.buildList))
 	for _, m := range r.buildList {
 		r.buildListVersion[m.Path] = m.Version
diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go
index 7a0cea4..604a57b 100644
--- a/src/cmd/go/internal/modload/buildlist.go
+++ b/src/cmd/go/internal/modload/buildlist.go
@@ -403,11 +403,33 @@
 // LoadModGraph loads and returns the graph of module dependencies of the main module,
 // without loading any packages.
 //
+// If the goVersion string is non-empty, the returned graph is the graph
+// as interpreted by the given Go version (instead of the version indicated
+// in the go.mod file).
+//
 // Modules are loaded automatically (and lazily) in LoadPackages:
 // LoadModGraph need only be called if LoadPackages is not,
 // typically in commands that care about modules but no particular package.
-func LoadModGraph(ctx context.Context) *ModuleGraph {
-	rs, mg, err := expandGraph(ctx, LoadModFile(ctx))
+func LoadModGraph(ctx context.Context, goVersion string) *ModuleGraph {
+	rs := LoadModFile(ctx)
+
+	if goVersion != "" {
+		depth := modDepthFromGoVersion(goVersion)
+		if depth == eager && rs.depth != eager {
+			// Use newRequirements instead of convertDepth because convertDepth
+			// also updates roots; here, we want to report the unmodified roots
+			// even though they may seem inconsistent.
+			rs = newRequirements(eager, rs.rootModules, rs.direct)
+		}
+
+		mg, err := rs.Graph(ctx)
+		if err != nil {
+			base.Fatalf("go: %v", err)
+		}
+		return mg
+	}
+
+	rs, mg, err := expandGraph(ctx, rs)
 	if err != nil {
 		base.Fatalf("go: %v", err)
 	}
@@ -443,7 +465,7 @@
 		// 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 +539,11 @@
 	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 +683,7 @@
 //
 // (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 +710,10 @@
 			//
 			// (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
@@ -815,7 +841,8 @@
 
 		roots = make([]module.Version, 0, len(rs.rootModules))
 		rootsUpgraded = false
-		inRootPaths := make(map[string]bool, len(rs.rootModules))
+		inRootPaths := make(map[string]bool, len(rs.rootModules)+1)
+		inRootPaths[Target.Path] = true
 		for _, m := range rs.rootModules {
 			if inRootPaths[m.Path] {
 				// This root specifies a redundant path. We already retained the
diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go
index f76befc..d2bbe5c 100644
--- a/src/cmd/go/internal/modload/import.go
+++ b/src/cmd/go/internal/modload/import.go
@@ -178,11 +178,13 @@
 		// Importing package is unknown, or the missing package was named on the
 		// command line. Recommend 'go mod download' for the modules that could
 		// provide the package, since that shouldn't change go.mod.
-		args := make([]string, len(e.mods))
-		for i, mod := range e.mods {
-			args[i] = mod.Path
+		if len(e.mods) > 0 {
+			args := make([]string, len(e.mods))
+			for i, mod := range e.mods {
+				args[i] = mod.Path
+			}
+			hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " "))
 		}
-		hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " "))
 	} else {
 		// Importing package is known (common case). Recommend 'go get' on the
 		// current version of the importing package.
@@ -426,6 +428,15 @@
 					mv = module.ZeroPseudoVersion("v0")
 				}
 			}
+			mg, err := rs.Graph(ctx)
+			if err != nil {
+				return module.Version{}, err
+			}
+			if cmpVersion(mg.Selected(mp), mv) >= 0 {
+				// We can't resolve the import by adding mp@mv to the module graph,
+				// because the selected version of mp is already at least mv.
+				continue
+			}
 			mods = append(mods, module.Version{Path: mp, Version: mv})
 		}
 
diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go
index 5cdea12..a8cbd9f 100644
--- a/src/cmd/go/internal/modload/init.go
+++ b/src/cmd/go/internal/modload/init.go
@@ -71,7 +71,7 @@
 const (
 	// AutoRoot is the default for most commands. modload.Init will look for
 	// a go.mod file in the current directory or any parent. If none is found,
-	// modules may be disabled (GO111MODULE=on) or commands may run in a
+	// modules may be disabled (GO111MODULE=auto) or commands may run in a
 	// limited module mode.
 	AutoRoot Root = iota
 
@@ -405,14 +405,23 @@
 	if modRoot == "" {
 		Target = module.Version{Path: "command-line-arguments"}
 		targetPrefix = "command-line-arguments"
-		goVersion := latestGoVersion()
+		goVersion := LatestGoVersion()
 		rawGoVersion.Store(Target, goVersion)
 		requirements = newRequirements(modDepthFromGoVersion(goVersion), nil, nil)
 		return requirements, false
 	}
 
 	gomod := ModFilePath()
-	data, err := lockedfile.Read(gomod)
+	var data []byte
+	var err error
+	if gomodActual, ok := fsys.OverlayPath(gomod); ok {
+		// Don't lock go.mod if it's part of the overlay.
+		// On Plan 9, locking requires chmod, and we don't want to modify any file
+		// in the overlay. See #44700.
+		data, err = os.ReadFile(gomodActual)
+	} else {
+		data, err = lockedfile.Read(gomodActual)
+	}
 	if err != nil {
 		base.Fatalf("go: %v", err)
 	}
@@ -432,7 +441,10 @@
 	initTarget(f.Module.Mod)
 	index = indexModFile(data, f, fixed)
 
-	if err := checkModulePathLax(f.Module.Mod.Path); err != nil {
+	if err := module.CheckImportPath(f.Module.Mod.Path); err != nil {
+		if pathErr, ok := err.(*module.InvalidPathError); ok {
+			pathErr.Kind = "module"
+		}
 		base.Fatalf("go: %v", err)
 	}
 
@@ -448,7 +460,7 @@
 		// TODO(#45551): Do something more principled instead of checking
 		// cfg.CmdName directly here.
 		if cfg.BuildMod == "mod" && cfg.CmdName != "mod graph" && cfg.CmdName != "mod why" {
-			addGoStmt(latestGoVersion())
+			addGoStmt(LatestGoVersion())
 			if go117EnableLazyLoading {
 				// We need to add a 'go' version to the go.mod file, but we must assume
 				// that its existing contents match something between Go 1.11 and 1.16.
@@ -492,7 +504,15 @@
 		if err != nil {
 			base.Fatalf("go: %v", err)
 		}
-	} else if err := checkModulePathLax(modPath); err != nil {
+	} else if err := module.CheckImportPath(modPath); err != nil {
+		if pathErr, ok := err.(*module.InvalidPathError); ok {
+			pathErr.Kind = "module"
+			// Same as build.IsLocalPath()
+			if pathErr.Path == "." || pathErr.Path == ".." ||
+				strings.HasPrefix(pathErr.Path, "./") || strings.HasPrefix(pathErr.Path, "../") {
+				pathErr.Err = errors.New("is a local import path")
+			}
+		}
 		base.Fatalf("go: %v", err)
 	}
 
@@ -500,7 +520,7 @@
 	modFile = new(modfile.File)
 	modFile.AddModuleStmt(modPath)
 	initTarget(modFile.Module.Mod)
-	addGoStmt(latestGoVersion()) // Add the go directive before converted module requirements.
+	addGoStmt(LatestGoVersion()) // Add the go directive before converted module requirements.
 
 	convertedFrom, err := convertLegacyConfig(modPath)
 	if convertedFrom != "" {
@@ -536,49 +556,6 @@
 	}
 }
 
-// checkModulePathLax checks that the path meets some minimum requirements
-// to avoid confusing users or the module cache. The requirements are weaker
-// than those of module.CheckPath to allow room for weakening module path
-// requirements in the future, but strong enough to help users avoid significant
-// problems.
-func checkModulePathLax(p string) error {
-	// TODO(matloob): Replace calls of this function in this CL with calls
-	// to module.CheckImportPath once it's been laxened, if it becomes laxened.
-	// See golang.org/issue/29101 for a discussion about whether to make CheckImportPath
-	// more lax or more strict.
-
-	errorf := func(format string, args ...interface{}) error {
-		return fmt.Errorf("invalid module path %q: %s", p, fmt.Sprintf(format, args...))
-	}
-
-	// Disallow shell characters " ' * < > ? ` | to avoid triggering bugs
-	// with file systems and subcommands. Disallow file path separators : and \
-	// because path separators other than / will confuse the module cache.
-	// See fileNameOK in golang.org/x/mod/module/module.go.
-	shellChars := "`" + `"'*<>?|`
-	fsChars := `\:`
-	if i := strings.IndexAny(p, shellChars); i >= 0 {
-		return errorf("contains disallowed shell character %q", p[i])
-	}
-	if i := strings.IndexAny(p, fsChars); i >= 0 {
-		return errorf("contains disallowed path separator character %q", p[i])
-	}
-
-	// Ensure path.IsAbs and build.IsLocalImport are false, and that the path is
-	// invariant under path.Clean, also to avoid confusing the module cache.
-	if path.IsAbs(p) {
-		return errorf("is an absolute path")
-	}
-	if build.IsLocalImport(p) {
-		return errorf("is a local import path")
-	}
-	if path.Clean(p) != p {
-		return errorf("is not clean")
-	}
-
-	return nil
-}
-
 // fixVersion returns a modfile.VersionFixer implemented using the Query function.
 //
 // It resolves commit hashes and branch names to versions,
@@ -693,7 +670,7 @@
 	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)
 			}
@@ -793,17 +770,39 @@
 	rawGoVersion.Store(Target, v)
 }
 
-// latestGoVersion returns the latest version of the Go language supported by
+// LatestGoVersion returns the latest version of the Go language supported by
 // this toolchain, like "1.17".
-func latestGoVersion() string {
+func LatestGoVersion() string {
 	tags := build.Default.ReleaseTags
 	version := tags[len(tags)-1]
 	if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) {
-		base.Fatalf("go: unrecognized default version %q", version)
+		base.Fatalf("go: internal error: unrecognized default version %q", version)
 	}
 	return version[2:]
 }
 
+// priorGoVersion returns the Go major release immediately preceding v,
+// or v itself if v is the first Go major release (1.0) or not a supported
+// Go version.
+func priorGoVersion(v string) string {
+	vTag := "go" + v
+	tags := build.Default.ReleaseTags
+	for i, tag := range tags {
+		if tag == vTag {
+			if i == 0 {
+				return v
+			}
+
+			version := tags[i-1]
+			if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) {
+				base.Fatalf("go: internal error: unrecognized version %q", version)
+			}
+			return version[2:]
+		}
+	}
+	return v
+}
+
 var altConfigs = []string{
 	"Gopkg.lock",
 
@@ -918,14 +917,8 @@
 		}
 		if rel := search.InDir(dir, filepath.Join(gpdir, "src")); rel != "" && rel != "." {
 			path := filepath.ToSlash(rel)
-			// TODO(matloob): replace this with module.CheckImportPath
-			// once it's been laxened.
-			// Only checkModulePathLax here. There are some unpublishable
-			// module names that are compatible with checkModulePathLax
-			// but they already work in GOPATH so don't break users
-			// trying to do a build with modules. gorelease will alert users
-			// publishing their modules to fix their paths.
-			if err := checkModulePathLax(path); err != nil {
+			// gorelease will alert users publishing their modules to fix their paths.
+			if err := module.CheckImportPath(path); err != nil {
 				badPathErr = err
 				break
 			}
@@ -1015,10 +1008,14 @@
 			Indirect: !rs.direct[m.Path],
 		})
 	}
-	modFile.SetRequire(list)
 	if goVersion != "" {
 		modFile.AddGoStmt(goVersion)
 	}
+	if semver.Compare("v"+modFileGoVersion(), separateIndirectVersionV) < 0 {
+		modFile.SetRequire(list)
+	} else {
+		modFile.SetRequireSeparateIndirect(list)
+	}
 	modFile.Cleanup()
 
 	dirty := index.modFileIsDirty(modFile)
@@ -1038,6 +1035,13 @@
 		}
 		return
 	}
+	gomod := ModFilePath()
+	if _, ok := fsys.OverlayPath(gomod); ok {
+		if dirty {
+			base.Fatalf("go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay")
+		}
+		return
+	}
 
 	new, err := modFile.Format()
 	if err != nil {
@@ -1138,12 +1142,11 @@
 		}
 	}
 
-	if rs.depth == lazy && rs.graph.Load() == nil {
-		// The main module is lazy and we haven't needed to load the module graph so
-		// far. Don't incur the cost of loading it now — since we haven't loaded the
-		// graph, we probably don't have any checksums to contribute to the distant
-		// parts of the graph anyway. Instead, just request sums for the roots that
-		// we know about.
+	if rs.graph.Load() == nil {
+		// The module graph was not loaded, possibly because the main module is lazy
+		// or possibly because we haven't needed to load the graph yet.
+		// Save sums for the root modules (or their replacements), but don't
+		// incur the cost of loading the graph just to find and retain the sums.
 		for _, m := range rs.rootModules {
 			r := resolveReplacement(m)
 			keep[modkey(r)] = true
diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go
index f30ac6e..bce9ad8 100644
--- a/src/cmd/go/internal/modload/load.go
+++ b/src/cmd/go/internal/modload/load.go
@@ -152,6 +152,13 @@
 	// packages.
 	Tidy bool
 
+	// TidyCompatibleVersion is the oldest Go version that must be able to
+	// reproducibly reload the requested packages.
+	//
+	// If empty, the compatible version is the Go version immediately prior to the
+	// 'go' version listed in the go.mod file.
+	TidyCompatibleVersion string
+
 	// VendorModulesInGOROOTSrc indicates that if we are within a module in
 	// GOROOT/src, packages in the module's vendor directory should be resolved as
 	// actual module dependencies (instead of standard-library packages).
@@ -164,6 +171,11 @@
 	// 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
@@ -314,10 +326,6 @@
 
 	initialRS, _ := loadModFile(ctx) // Ignore needCommit — we're going to commit at the end regardless.
 
-	if opts.GoVersion == "" {
-		opts.GoVersion = modFileGoVersion()
-	}
-
 	ld := loadFromRoots(ctx, loaderParams{
 		PackageOpts:  opts,
 		requirements: initialRS,
@@ -375,12 +383,31 @@
 			}
 		}
 
-		modfetch.TrimGoSum(keepSums(ctx, ld, ld.requirements, loadedZipSumsOnly))
+		keep := keepSums(ctx, ld, ld.requirements, loadedZipSumsOnly)
+		if compatDepth := modDepthFromGoVersion(ld.TidyCompatibleVersion); compatDepth != ld.requirements.depth {
+			compatRS := newRequirements(compatDepth, ld.requirements.rootModules, ld.requirements.direct)
+			ld.checkTidyCompatibility(ctx, compatRS)
+
+			for m := range keepSums(ctx, ld, compatRS, loadedZipSumsOnly) {
+				keep[m] = true
+			}
+		}
+
+		if allowWriteGoMod {
+			modfetch.TrimGoSum(keep)
+
+			// commitRequirements below will also call WriteGoSum, but the "keep" map
+			// we have here could be strictly larger: commitRequirements only commits
+			// loaded.requirements, but here we may have also loaded (and want to
+			// preserve checksums for) additional entities from compatRS, which are
+			// only needed for compatibility with ld.TidyCompatibleVersion.
+			modfetch.WriteGoSum(keep)
+		}
 	}
 
 	// Success! Update go.mod and go.sum (if needed) and return the results.
 	loaded = ld
-	commitRequirements(ctx, opts.GoVersion, loaded.requirements)
+	commitRequirements(ctx, loaded.GoVersion, loaded.requirements)
 
 	for _, pkg := range ld.pkgs {
 		if !pkg.isTest() {
@@ -605,10 +632,8 @@
 		base.Fatalf("go: %v", err)
 	}
 
-	goVersion := modFileGoVersion()
 	loaded = loadFromRoots(ctx, loaderParams{
 		PackageOpts: PackageOpts{
-			GoVersion:             goVersion,
 			Tags:                  tags,
 			ResolveMissingImports: true,
 			SilencePackageErrors:  true,
@@ -620,7 +645,7 @@
 			return roots
 		},
 	})
-	commitRequirements(ctx, goVersion, loaded.requirements)
+	commitRequirements(ctx, loaded.GoVersion, loaded.requirements)
 }
 
 // DirImportPath returns the effective import path for dir,
@@ -650,20 +675,6 @@
 	return "."
 }
 
-// TargetPackages returns the list of packages in the target (top-level) module
-// matching pattern, which may be relative to the working directory, under all
-// build tag settings.
-func TargetPackages(ctx context.Context, pattern string) *search.Match {
-	// TargetPackages is relative to the main module, so ensure that the main
-	// module is a thing that can contain packages.
-	LoadModFile(ctx) // Sets Target.
-	ModRoot()        // Emits an error if Target cannot contain packages.
-
-	m := search.NewMatch(pattern)
-	matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{Target})
-	return m
-}
-
 // ImportMap returns the actual package import path
 // for an import path found in source code.
 // If the given import path does not appear in the source code
@@ -695,29 +706,6 @@
 	return pkg.mod
 }
 
-// PackageImports returns the imports for the package named by the import path.
-// Test imports will be returned as well if tests were loaded for the package
-// (i.e., if "all" was loaded or if LoadTests was set and the path was matched
-// by a command line argument). PackageImports will return nil for
-// unknown package paths.
-func PackageImports(path string) (imports, testImports []string) {
-	pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
-	if !ok {
-		return nil, nil
-	}
-	imports = make([]string, len(pkg.imports))
-	for i, p := range pkg.imports {
-		imports[i] = p.path
-	}
-	if pkg.test != nil {
-		testImports = make([]string, len(pkg.test.imports))
-		for i, p := range pkg.test.imports {
-			testImports[i] = p.path
-		}
-	}
-	return imports, testImports
-}
-
 // Lookup returns the source directory, import path, and any loading error for
 // the package at path as imported from the package in parentDir.
 // Lookup requires that one of the Load functions in this package has already
@@ -855,6 +843,11 @@
 	// 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
@@ -921,22 +914,38 @@
 		work:         par.NewQueue(runtime.GOMAXPROCS(0)),
 	}
 
-	if params.GoVersion != "" {
-		if semver.Compare("v"+params.GoVersion, narrowAllVersionV) < 0 && !ld.UseVendorAll {
-			// The module's go version explicitly predates the change in "all" for lazy
-			// loading, so continue to use the older interpretation.
-			// (If params.GoVersion is empty, we are probably not in any module at all
-			// and should use the latest semantics.)
-			ld.allClosesOverTests = true
-		}
+	if ld.GoVersion == "" {
+		ld.GoVersion = modFileGoVersion()
 
-		var err error
-		ld.requirements, err = convertDepth(ctx, ld.requirements, modDepthFromGoVersion(params.GoVersion))
-		if err != nil {
-			ld.errorf("go: %v\n", err)
+		if ld.Tidy && semver.Compare("v"+ld.GoVersion, "v"+LatestGoVersion()) > 0 {
+			ld.errorf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", ld.GoVersion, LatestGoVersion())
+			base.ExitIfErrors()
 		}
 	}
 
+	if ld.Tidy {
+		if ld.TidyCompatibleVersion == "" {
+			ld.TidyCompatibleVersion = priorGoVersion(ld.GoVersion)
+		} else if semver.Compare("v"+ld.TidyCompatibleVersion, "v"+ld.GoVersion) > 0 {
+			// Each version of the Go toolchain knows how to interpret go.mod and
+			// go.sum files produced by all previous versions, so a compatibility
+			// version higher than the go.mod version adds nothing.
+			ld.TidyCompatibleVersion = ld.GoVersion
+		}
+	}
+
+	if semver.Compare("v"+ld.GoVersion, narrowAllVersionV) < 0 && !ld.UseVendorAll {
+		// The module's go version explicitly predates the change in "all" for lazy
+		// loading, so continue to use the older interpretation.
+		ld.allClosesOverTests = true
+	}
+
+	var err error
+	ld.requirements, err = convertDepth(ctx, ld.requirements, modDepthFromGoVersion(ld.GoVersion))
+	if err != nil {
+		ld.errorf("go: %v\n", err)
+	}
+
 	if ld.requirements.depth == eager {
 		var err error
 		ld.requirements, _, err = expandGraph(ctx, ld.requirements)
@@ -1032,7 +1041,7 @@
 		// 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
@@ -1073,7 +1082,7 @@
 			// If that is not the case, there is a bug in the loading loop above.
 			for _, m := range rs.rootModules {
 				if v, ok := ld.requirements.rootSelected(m.Path); !ok || v != m.Version {
-					ld.errorf("go: internal error: a requirement on %v is needed but was not added during package loading\n", m)
+					ld.errorf("go mod tidy: internal error: a requirement on %v is needed but was not added during package loading\n", m)
 					base.ExitIfErrors()
 				}
 			}
@@ -1238,7 +1247,7 @@
 		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
@@ -1397,6 +1406,9 @@
 		// 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
@@ -1451,6 +1463,12 @@
 			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
@@ -1513,7 +1531,7 @@
 	}
 	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
@@ -1744,6 +1762,219 @@
 	}
 }
 
+// checkTidyCompatibility emits an error if any package would be loaded from a
+// different module under rs than under ld.requirements.
+func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements) {
+	suggestUpgrade := false
+	suggestEFlag := false
+	suggestFixes := func() {
+		if ld.AllowErrors {
+			// The user is explicitly ignoring these errors, so don't bother them with
+			// other options.
+			return
+		}
+
+		// We print directly to os.Stderr because this information is advice about
+		// how to fix errors, not actually an error itself.
+		// (The actual errors should have been logged already.)
+
+		fmt.Fprintln(os.Stderr)
+
+		goFlag := ""
+		if ld.GoVersion != modFileGoVersion() {
+			goFlag = " -go=" + ld.GoVersion
+		}
+
+		compatFlag := ""
+		if ld.TidyCompatibleVersion != priorGoVersion(ld.GoVersion) {
+			compatFlag = " -compat=" + ld.TidyCompatibleVersion
+		}
+		if suggestUpgrade {
+			eDesc := ""
+			eFlag := ""
+			if suggestEFlag {
+				eDesc = ", leaving some packages unresolved"
+				eFlag = " -e"
+			}
+			fmt.Fprintf(os.Stderr, "To upgrade to the versions selected by go %s%s:\n\tgo mod tidy%s -go=%s && go mod tidy%s -go=%s%s\n", ld.TidyCompatibleVersion, eDesc, eFlag, ld.TidyCompatibleVersion, eFlag, ld.GoVersion, compatFlag)
+		} else if suggestEFlag {
+			// If some packages are missing but no package is upgraded, then we
+			// shouldn't suggest upgrading to the Go 1.16 versions explicitly — that
+			// wouldn't actually fix anything for Go 1.16 users, and *would* break
+			// something for Go 1.17 users.
+			fmt.Fprintf(os.Stderr, "To proceed despite packages unresolved in go %s:\n\tgo mod tidy -e%s%s\n", ld.TidyCompatibleVersion, goFlag, compatFlag)
+		}
+
+		fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", ld.TidyCompatibleVersion, goFlag, ld.GoVersion)
+
+		// TODO(#46141): Populate the linked wiki page.
+		fmt.Fprintf(os.Stderr, "For other options, see:\n\thttps://golang.org/doc/modules/pruning\n")
+	}
+
+	mg, err := rs.Graph(ctx)
+	if err != nil {
+		ld.errorf("go mod tidy: error loading go %s module graph: %v\n", ld.TidyCompatibleVersion, err)
+		suggestFixes()
+		return
+	}
+
+	// Re-resolve packages in parallel.
+	//
+	// We re-resolve each package — rather than just checking versions — to ensure
+	// that we have fetched module source code (and, importantly, checksums for
+	// that source code) for all modules that are necessary to ensure that imports
+	// are unambiguous. That also produces clearer diagnostics, since we can say
+	// exactly what happened to the package if it became ambiguous or disappeared
+	// entirely.
+	//
+	// We re-resolve the packages in parallel because this process involves disk
+	// I/O to check for package sources, and because the process of checking for
+	// ambiguous imports may require us to download additional modules that are
+	// otherwise pruned out in Go 1.17 — we don't want to block progress on other
+	// packages while we wait for a single new download.
+	type mismatch struct {
+		mod module.Version
+		err error
+	}
+	mismatchMu := make(chan map[*loadPkg]mismatch, 1)
+	mismatchMu <- map[*loadPkg]mismatch{}
+	for _, pkg := range ld.pkgs {
+		if pkg.mod.Path == "" && pkg.err == nil {
+			// This package is from the standard library (which does not vary based on
+			// the module graph).
+			continue
+		}
+
+		pkg := pkg
+		ld.work.Add(func() {
+			mod, _, err := importFromModules(ctx, pkg.path, rs, mg)
+			if mod != pkg.mod {
+				mismatches := <-mismatchMu
+				mismatches[pkg] = mismatch{mod: mod, err: err}
+				mismatchMu <- mismatches
+			}
+		})
+	}
+	<-ld.work.Idle()
+
+	mismatches := <-mismatchMu
+	if len(mismatches) == 0 {
+		// Since we're running as part of 'go mod tidy', the roots of the module
+		// graph should contain only modules that are relevant to some package in
+		// the package graph. We checked every package in the package graph and
+		// didn't find any mismatches, so that must mean that all of the roots of
+		// the module graph are also consistent.
+		//
+		// If we're wrong, Go 1.16 in -mod=readonly mode will error out with
+		// "updates to go.mod needed", which would be very confusing. So instead,
+		// we'll double-check that our reasoning above actually holds — if it
+		// doesn't, we'll emit an internal error and hopefully the user will report
+		// it as a bug.
+		for _, m := range ld.requirements.rootModules {
+			if v := mg.Selected(m.Path); v != m.Version {
+				fmt.Fprintln(os.Stderr)
+				base.Fatalf("go: internal error: failed to diagnose selected-version mismatch for module %s: go %s selects %s, but go %s selects %s\n\tPlease report this at https://golang.org/issue.", m.Path, ld.GoVersion, m.Version, ld.TidyCompatibleVersion, v)
+			}
+		}
+		return
+	}
+
+	// Iterate over the packages (instead of the mismatches map) to emit errors in
+	// deterministic order.
+	for _, pkg := range ld.pkgs {
+		mismatch, ok := mismatches[pkg]
+		if !ok {
+			continue
+		}
+
+		if pkg.isTest() {
+			// We already did (or will) report an error for the package itself,
+			// so don't report a duplicate (and more vebose) error for its test.
+			if _, ok := mismatches[pkg.testOf]; !ok {
+				base.Fatalf("go: internal error: mismatch recorded for test %s, but not its non-test package", pkg.path)
+			}
+			continue
+		}
+
+		switch {
+		case mismatch.err != nil:
+			// pkg resolved successfully, but errors out using the requirements in rs.
+			//
+			// This could occur because the import is provided by a single lazy root
+			// (and is thus unambiguous in lazy mode) and also one or more
+			// transitive dependencies (and is ambiguous in eager mode).
+			//
+			// It could also occur because some transitive dependency upgrades the
+			// module that previously provided the package to a version that no
+			// longer does, or to a version for which the module source code (but
+			// not the go.mod file in isolation) has a checksum error.
+			if missing := (*ImportMissingError)(nil); errors.As(mismatch.err, &missing) {
+				selected := module.Version{
+					Path:    pkg.mod.Path,
+					Version: mg.Selected(pkg.mod.Path),
+				}
+				ld.errorf("%s loaded from %v,\n\tbut go %s would fail to locate it in %s\n", pkg.stackText(), pkg.mod, ld.TidyCompatibleVersion, selected)
+			} else {
+				if ambiguous := (*AmbiguousImportError)(nil); errors.As(mismatch.err, &ambiguous) {
+					// TODO: Is this check needed?
+				}
+				ld.errorf("%s loaded from %v,\n\tbut go %s would fail to locate it:\n\t%v\n", pkg.stackText(), pkg.mod, ld.TidyCompatibleVersion, mismatch.err)
+			}
+
+			suggestEFlag = true
+
+			// Even if we press ahead with the '-e' flag, the older version will
+			// error out in readonly mode if it thinks the go.mod file contains
+			// any *explicit* dependency that is not at its selected version,
+			// even if that dependency is not relevant to any package being loaded.
+			//
+			// We check for that condition here. If all of the roots are consistent
+			// the '-e' flag suffices, but otherwise we need to suggest an upgrade.
+			if !suggestUpgrade {
+				for _, m := range ld.requirements.rootModules {
+					if v := mg.Selected(m.Path); v != m.Version {
+						suggestUpgrade = true
+						break
+					}
+				}
+			}
+
+		case pkg.err != nil:
+			// pkg had an error in lazy mode (presumably suppressed with the -e flag),
+			// but not in eager mode.
+			//
+			// This is possible, if, say, the import is unresolved in lazy mode
+			// (because the "latest" version of each candidate module either is
+			// unavailable or does not contain the package), but is resolved in
+			// eager mode due to a newer-than-latest dependency that is normally
+			// runed out of the module graph.
+			//
+			// This could also occur if the source code for the module providing the
+			// package in lazy mode has a checksum error, but eager mode upgrades
+			// that module to a version with a correct checksum.
+			//
+			// pkg.err should have already been logged elsewhere — along with a
+			// stack trace — so log only the import path and non-error info here.
+			suggestUpgrade = true
+			ld.errorf("%s failed to load from any module,\n\tbut go %s would load it from %v\n", pkg.path, ld.TidyCompatibleVersion, mismatch.mod)
+
+		case pkg.mod != mismatch.mod:
+			// The package is loaded successfully by both Go versions, but from a
+			// different module in each. This could lead to subtle (and perhaps even
+			// unnoticed!) variations in behavior between builds with different
+			// toolchains.
+			suggestUpgrade = true
+			ld.errorf("%s loaded from %v,\n\tbut go %s would select %v\n", pkg.stackText(), pkg.mod, ld.TidyCompatibleVersion, mismatch.mod.Version)
+
+		default:
+			base.Fatalf("go: internal error: mismatch recorded for package %s, but no differences found", pkg.path)
+		}
+	}
+
+	suggestFixes()
+	base.ExitIfErrors()
+}
+
 // scanDir is like imports.ScanDir but elides known magic imports from the list,
 // so that we do not go looking for packages that don't really exist.
 //
diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go
index bafff3e..03e02e7 100644
--- a/src/cmd/go/internal/modload/modfile.go
+++ b/src/cmd/go/internal/modload/modfile.go
@@ -8,6 +8,7 @@
 	"context"
 	"errors"
 	"fmt"
+	"os"
 	"path/filepath"
 	"strings"
 	"sync"
@@ -15,6 +16,7 @@
 
 	"cmd/go/internal/base"
 	"cmd/go/internal/cfg"
+	"cmd/go/internal/fsys"
 	"cmd/go/internal/lockedfile"
 	"cmd/go/internal/modfetch"
 	"cmd/go/internal/par"
@@ -35,6 +37,11 @@
 	// module's go.mod file is expected to list explicit requirements on every
 	// module that provides any package transitively imported by that module.
 	lazyLoadingVersionV = "v1.17"
+
+	// separateIndirectVersionV is the Go version (plus leading "v") at which
+	// "// indirect" dependencies are added in a block separate from the direct
+	// ones. See https://golang.org/issue/45965.
+	separateIndirectVersionV = "v1.17"
 )
 
 const (
@@ -55,7 +62,7 @@
 // in modFile are intepreted, or the latest Go version if modFile is nil.
 func modFileGoVersion() string {
 	if modFile == nil {
-		return latestGoVersion()
+		return LatestGoVersion()
 	}
 	if modFile.Go == nil || modFile.Go.Version == "" {
 		// The main module necessarily has a go.mod file, and that file lacks a
@@ -588,39 +595,14 @@
 	}
 	c := rawGoModSummaryCache.Do(m, func() interface{} {
 		summary := new(modFileSummary)
-		var f *modfile.File
-		if m.Version == "" {
-			// m is a replacement module with only a file path.
-			dir := m.Path
-			if !filepath.IsAbs(dir) {
-				dir = filepath.Join(ModRoot(), dir)
-			}
-			gomod := filepath.Join(dir, "go.mod")
-
-			data, err := lockedfile.Read(gomod)
-			if err != nil {
-				return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))}
-			}
-			f, err = modfile.ParseLax(gomod, data, nil)
-			if err != nil {
-				return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err))}
-			}
-		} else {
-			if !semver.IsValid(m.Version) {
-				// Disallow the broader queries supported by fetch.Lookup.
-				base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version)
-			}
-
-			data, err := modfetch.GoMod(m.Path, m.Version)
-			if err != nil {
-				return cached{nil, err}
-			}
-			f, err = modfile.ParseLax("go.mod", data, nil)
-			if err != nil {
-				return cached{nil, module.VersionError(m, fmt.Errorf("parsing go.mod: %v", err))}
-			}
+		name, data, err := rawGoModData(m)
+		if err != nil {
+			return cached{nil, err}
 		}
-
+		f, err := modfile.ParseLax(name, data, nil)
+		if err != nil {
+			return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(name), err))}
+		}
 		if f.Module != nil {
 			summary.module = f.Module.Mod
 			summary.deprecated = f.Module.Deprecated
@@ -656,6 +638,43 @@
 
 var rawGoModSummaryCache par.Cache // module.Version → rawGoModSummary result
 
+// rawGoModData returns the content of the go.mod file for module m, ignoring
+// all replacements that may apply to m.
+//
+// rawGoModData cannot be used on the Target module.
+//
+// Unlike rawGoModSummary, rawGoModData does not cache its results in memory.
+// Use rawGoModSummary instead unless you specifically need these bytes.
+func rawGoModData(m module.Version) (name string, data []byte, err error) {
+	if m.Version == "" {
+		// m is a replacement module with only a file path.
+		dir := m.Path
+		if !filepath.IsAbs(dir) {
+			dir = filepath.Join(ModRoot(), dir)
+		}
+		name = filepath.Join(dir, "go.mod")
+		if gomodActual, ok := fsys.OverlayPath(name); ok {
+			// Don't lock go.mod if it's part of the overlay.
+			// On Plan 9, locking requires chmod, and we don't want to modify any file
+			// in the overlay. See #44700.
+			data, err = os.ReadFile(gomodActual)
+		} else {
+			data, err = lockedfile.Read(gomodActual)
+		}
+		if err != nil {
+			return "", nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(name), err))
+		}
+	} else {
+		if !semver.IsValid(m.Version) {
+			// Disallow the broader queries supported by fetch.Lookup.
+			base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version)
+		}
+		name = "go.mod"
+		data, err = modfetch.GoMod(m.Path, m.Version)
+	}
+	return name, data, err
+}
+
 // queryLatestVersionIgnoringRetractions looks up the latest version of the
 // module with the given path without considering retracted or excluded
 // versions.
diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go
index 6f6c6e8..e737ca9 100644
--- a/src/cmd/go/internal/modload/query.go
+++ b/src/cmd/go/internal/modload/query.go
@@ -5,13 +5,13 @@
 package modload
 
 import (
+	"bytes"
 	"context"
 	"errors"
 	"fmt"
 	"io/fs"
 	"os"
 	pathpkg "path"
-	"path/filepath"
 	"sort"
 	"strings"
 	"sync"
@@ -920,8 +920,8 @@
 	return ""
 }
 
-// ModuleHasRootPackage returns whether module m contains a package m.Path.
-func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) {
+// moduleHasRootPackage returns whether module m contains a package m.Path.
+func moduleHasRootPackage(ctx context.Context, m module.Version) (bool, error) {
 	needSum := false
 	root, isLocal, err := fetch(ctx, m, needSum)
 	if err != nil {
@@ -931,14 +931,32 @@
 	return ok, err
 }
 
-func versionHasGoMod(ctx context.Context, m module.Version) (bool, error) {
-	needSum := false
-	root, _, err := fetch(ctx, m, needSum)
+// versionHasGoMod returns whether a version has a go.mod file.
+//
+// versionHasGoMod fetches the go.mod file (possibly a fake) and true if it
+// contains anything other than a module directive with the same path. When a
+// module does not have a real go.mod file, the go command acts as if it had one
+// that only contained a module directive. Normal go.mod files created after
+// 1.12 at least have a go directive.
+//
+// This function is a heuristic, since it's possible to commit a file that would
+// pass this test. However, we only need a heurstic for determining whether
+// +incompatible versions may be "latest", which is what this function is used
+// for.
+//
+// This heuristic is useful for two reasons: first, when using a proxy,
+// this lets us fetch from the .mod endpoint which is much faster than the .zip
+// endpoint. The .mod file is used anyway, even if the .zip file contains a
+// go.mod with different content. Second, if we don't fetch the .zip, then
+// we don't need to verify it in go.sum. This makes 'go list -m -u' faster
+// and simpler.
+func versionHasGoMod(_ context.Context, m module.Version) (bool, error) {
+	_, data, err := rawGoModData(m)
 	if err != nil {
 		return false, err
 	}
-	fi, err := os.Stat(filepath.Join(root, "go.mod"))
-	return err == nil && !fi.IsDir(), nil
+	isFake := bytes.Equal(data, modfetch.LegacyGoMod(m.Path))
+	return !isFake, nil
 }
 
 // A versionRepo is a subset of modfetch.Repo that can report information about
diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go
index 1babbda..0ed2389 100644
--- a/src/cmd/go/internal/work/build.go
+++ b/src/cmd/go/internal/work/build.go
@@ -128,8 +128,8 @@
 		a build will run as if the disk file path exists with the contents
 		given by the backing file paths, or as if the disk file path does not
 		exist if its backing file path is empty. Support for the -overlay flag
-		has some limitations:importantly, cgo files included from outside the
-		include path must be  in the same directory as the Go package they are
+		has some limitations: importantly, cgo files included from outside the
+		include path must be in the same directory as the Go package they are
 		included from, and overlays will not appear when binaries and tests are
 		run through go run and go test respectively.
 	-pkgdir dir
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index b506b83..5a225fb 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -252,8 +252,15 @@
 
 		ccExe := b.ccExe()
 		fmt.Fprintf(h, "CC=%q %q %q %q\n", ccExe, cppflags, cflags, ldflags)
-		if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil {
-			fmt.Fprintf(h, "CC ID=%q\n", ccID)
+		// Include the C compiler tool ID so that if the C
+		// compiler changes we rebuild the package.
+		// But don't do that for standard library packages like net,
+		// so that the prebuilt .a files from a Go binary install
+		// don't need to be rebuilt with the local compiler.
+		if !p.Standard {
+			if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil {
+				fmt.Fprintf(h, "CC ID=%q\n", ccID)
+			}
 		}
 		if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 {
 			cxxExe := b.cxxExe()
diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go
index 36bbab3..e9b9f6c 100644
--- a/src/cmd/go/internal/work/security.go
+++ b/src/cmd/go/internal/work/security.go
@@ -208,8 +208,8 @@
 	re(`-Wl,-z,(no)?execstack`),
 	re(`-Wl,-z,relro`),
 
-	re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
-	re(`\./.*\.(a|o|obj|dll|dylib|so)`),
+	re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so|tbd)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
+	re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`),
 }
 
 var validLinkerFlagsWithNextArg = []string{
diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go
index 4f2e0eb..8d4be0a 100644
--- a/src/cmd/go/internal/work/security_test.go
+++ b/src/cmd/go/internal/work/security_test.go
@@ -164,6 +164,8 @@
 	{"-Wl,-framework", "-Wl,Chocolate"},
 	{"-Wl,-framework,Chocolate"},
 	{"-Wl,-unresolved-symbols=ignore-all"},
+	{"libcgotbdtest.tbd"},
+	{"./libcgotbdtest.tbd"},
 }
 
 var badLinkerFlags = [][]string{
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 02174a5..16361e0 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -145,24 +145,6 @@
 		os.Exit(2)
 	}
 
-	if err := buildcfg.Error; err != nil {
-		fmt.Fprintf(os.Stderr, "go: %v\n", buildcfg.Error)
-		os.Exit(2)
-	}
-
-	// Set environment (GOOS, GOARCH, etc) explicitly.
-	// In theory all the commands we invoke should have
-	// the same default computation of these as we do,
-	// but in practice there might be skew
-	// This makes sure we all agree.
-	cfg.OrigEnv = os.Environ()
-	cfg.CmdEnv = envcmd.MkEnv()
-	for _, env := range cfg.CmdEnv {
-		if os.Getenv(env.Name) != env.Value {
-			os.Setenv(env.Name, env.Value)
-		}
-	}
-
 BigCmdLoop:
 	for bigCmd := base.Go; ; {
 		for _, cmd := range bigCmd.Commands {
@@ -188,18 +170,7 @@
 			if !cmd.Runnable() {
 				continue
 			}
-			cmd.Flag.Usage = func() { cmd.Usage() }
-			if cmd.CustomFlags {
-				args = args[1:]
-			} else {
-				base.SetFromGOFLAGS(&cmd.Flag)
-				cmd.Flag.Parse(args[1:])
-				args = cmd.Flag.Args()
-			}
-			ctx := maybeStartTrace(context.Background())
-			ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command"))
-			cmd.Run(ctx, cmd, args)
-			span.Done()
+			invoke(cmd, args)
 			base.Exit()
 			return
 		}
@@ -213,6 +184,39 @@
 	}
 }
 
+func invoke(cmd *base.Command, args []string) {
+	// 'go env' handles checking the build config
+	if cmd != envcmd.CmdEnv {
+		buildcfg.Check()
+	}
+
+	// Set environment (GOOS, GOARCH, etc) explicitly.
+	// In theory all the commands we invoke should have
+	// the same default computation of these as we do,
+	// but in practice there might be skew
+	// This makes sure we all agree.
+	cfg.OrigEnv = os.Environ()
+	cfg.CmdEnv = envcmd.MkEnv()
+	for _, env := range cfg.CmdEnv {
+		if os.Getenv(env.Name) != env.Value {
+			os.Setenv(env.Name, env.Value)
+		}
+	}
+
+	cmd.Flag.Usage = func() { cmd.Usage() }
+	if cmd.CustomFlags {
+		args = args[1:]
+	} else {
+		base.SetFromGOFLAGS(&cmd.Flag)
+		cmd.Flag.Parse(args[1:])
+		args = cmd.Flag.Args()
+	}
+	ctx := maybeStartTrace(context.Background())
+	ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command"))
+	cmd.Run(ctx, cmd, args)
+	span.Done()
+}
+
 func init() {
 	base.Usage = mainUsage
 }
diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go
index 327eaff..639e907 100644
--- a/src/cmd/go/script_test.go
+++ b/src/cmd/go/script_test.go
@@ -517,7 +517,7 @@
 		ts.fatalf("usage: cd dir")
 	}
 
-	dir := args[0]
+	dir := filepath.FromSlash(args[0])
 	if !filepath.IsAbs(dir) {
 		dir = filepath.Join(ts.cd, dir)
 	}
diff --git a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt
index 00b71bf..7982ccc 100644
--- a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt
+++ b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt
@@ -5,7 +5,7 @@
 
 require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
 -- .info --
-{"Version":"v1.2.1","Name":"cac3af4f8a0ab40054fa6f8d423108a63a1255bb","Short":"cac3af4f8a0a","Time":"2018-02-13T18:16:22Z"}EOF
+{"Version":"v1.2.1","Name":"cac3af4f8a0ab40054fa6f8d423108a63a1255bb","Short":"cac3af4f8a0a","Time":"2018-02-13T18:16:22Z"}
 -- hello.go --
 // Copyright 2018 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README
index d7e67bb..48e4055 100644
--- a/src/cmd/go/testdata/script/README
+++ b/src/cmd/go/testdata/script/README
@@ -102,6 +102,7 @@
 
 - cd dir
   Change to the given directory for future commands.
+  The directory must use slashes as path separator.
 
 - chmod perm path...
   Change the permissions of the files or directories named by the path arguments
diff --git a/src/cmd/go/testdata/script/badgo.txt b/src/cmd/go/testdata/script/badgo.txt
new file mode 100644
index 0000000..cf4e258
--- /dev/null
+++ b/src/cmd/go/testdata/script/badgo.txt
@@ -0,0 +1,50 @@
+go get example.net/badgo@v1.0.0
+go get example.net/badgo@v1.1.0
+go get example.net/badgo@v1.2.0
+go get example.net/badgo@v1.3.0
+go get example.net/badgo@v1.4.0
+go get example.net/badgo@v1.5.0
+! go get example.net/badgo@v1.6.0
+stderr 'invalid go version .X.Y.: must match format 1.23'
+
+-- go.mod --
+module m
+
+replace (
+	example.net/badgo v1.0.0 => ./v1.0.0
+	example.net/badgo v1.1.0 => ./v1.1.0
+	example.net/badgo v1.2.0 => ./v1.2.0
+	example.net/badgo v1.3.0 => ./v1.3.0
+	example.net/badgo v1.4.0 => ./v1.4.0
+	example.net/badgo v1.5.0 => ./v1.5.0
+	example.net/badgo v1.6.0 => ./v1.6.0
+)
+
+-- v1.0.0/go.mod --
+module example.net/badgo
+go 1.17.0
+
+-- v1.1.0/go.mod --
+module example.net/badgo
+go 1.17rc2
+
+-- v1.2.0/go.mod --
+module example.net/badgo
+go 1.17.1
+
+-- v1.3.0/go.mod --
+module example.net/badgo
+go v1.17.0
+
+-- v1.4.0/go.mod --
+module example.net/badgo
+go v1.17.0-rc.2
+
+-- v1.5.0/go.mod --
+module example.net/badgo
+go v1.17.1
+
+-- v1.6.0/go.mod --
+module example.net/badgo
+go X.Y
+
diff --git a/src/cmd/go/testdata/script/build_ignore_leading_bom.txt b/src/cmd/go/testdata/script/build_ignore_leading_bom.txt
new file mode 100644
index 0000000..37141f3
--- /dev/null
+++ b/src/cmd/go/testdata/script/build_ignore_leading_bom.txt
@@ -0,0 +1,27 @@
+# Per https://golang.org/ref/spec#Source_code_representation:
+# a compiler may ignore a UTF-8-encoded byte order mark (U+FEFF)
+# if it is the first Unicode code point in the source text.
+
+go list -f 'Imports: {{.Imports}} EmbedFiles: {{.EmbedFiles}}' .
+stdout '^Imports: \[embed m/hello\] EmbedFiles: \[.*file\]$'
+
+-- go.mod --
+module m
+
+go 1.16
+-- m.go --
+package main
+
+import (
+	_ "embed"
+
+	"m/hello"
+)
+
+//go:embed file
+var s string
+
+-- hello/hello.go --
+package hello
+
+-- file --
diff --git a/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt b/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt
deleted file mode 100644
index 38a151e..0000000
--- a/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-# Tests Issue #12690
-
-[gccgo] skip 'gccgo does not have GOROOT'
-
-! stale runtime
-! stale os
-! stale io
-
-env GOROOT=$GOROOT'/'
-
-! stale runtime
-! stale os
-! stale io
\ No newline at end of file
diff --git a/src/cmd/go/testdata/script/cgo_stale.txt b/src/cmd/go/testdata/script/cgo_stale.txt
new file mode 100644
index 0000000..9e46855
--- /dev/null
+++ b/src/cmd/go/testdata/script/cgo_stale.txt
@@ -0,0 +1,39 @@
+# golang.org/issue/46347: a stale runtime/cgo should only force a single rebuild
+
+[!cgo] skip
+[short] skip
+
+
+# If we set a unique CGO_CFLAGS, the installed copy of runtime/cgo
+# should be reported as stale.
+
+env CGO_CFLAGS=-DTestScript_cgo_stale=true
+stale runtime/cgo
+
+
+# If we then build a package that uses cgo, runtime/cgo should be rebuilt and
+# cached with the new flag, but not installed to GOROOT (and thus still stale).
+
+env GOCACHE=$WORK/cache  # Use a fresh cache to avoid interference between runs.
+
+go build -x .
+stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo'
+stale runtime/cgo
+
+
+# After runtime/cgo has been rebuilt and cached, it should not be rebuilt again
+# even though it is still reported as stale.
+
+go build -x .
+! stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo'
+stale runtime/cgo
+
+
+-- go.mod --
+module example.com/m
+
+go 1.17
+-- m.go --
+package m
+
+import "C"
diff --git a/src/cmd/go/testdata/script/env_cross_build.txt b/src/cmd/go/testdata/script/env_cross_build.txt
new file mode 100644
index 0000000..3feeba6
--- /dev/null
+++ b/src/cmd/go/testdata/script/env_cross_build.txt
@@ -0,0 +1,29 @@
+# Test that the corect default GOEXPERIMENT is used when cross
+# building with GOENV (#46815).
+
+# Unset variables set by the TestScript harness. Users typically won't
+# explicitly configure these, and #46815 doesn't repro if they are.
+env GOOS=
+env GOARCH=
+env GOEXPERIMENT=
+
+env GOENV=windows-amd64
+go build internal/abi
+
+env GOENV=ios-arm64
+go build internal/abi
+
+env GOENV=linux-mips
+go build internal/abi
+
+-- windows-amd64 --
+GOOS=windows
+GOARCH=amd64
+
+-- ios-arm64 --
+GOOS=ios
+GOARCH=arm64
+
+-- linux-mips --
+GOOS=linux
+GOARCH=mips
diff --git a/src/cmd/go/testdata/script/env_exp.txt b/src/cmd/go/testdata/script/env_exp.txt
new file mode 100644
index 0000000..681512d
--- /dev/null
+++ b/src/cmd/go/testdata/script/env_exp.txt
@@ -0,0 +1,17 @@
+# Test GOEXPERIMENT variable
+
+# go env shows default empty GOEXPERIMENT
+go env
+stdout GOEXPERIMENT=
+
+# go env shows valid experiments
+env GOEXPERIMENT=fieldtrack,staticlockranking
+go env GOEXPERIMENT
+stdout '.*fieldtrack.*staticlockranking.*'
+go env
+stdout 'GOEXPERIMENT=.*fieldtrack.*staticlockranking.*'
+
+# go env rejects unknown experiments
+env GOEXPERIMENT=bad
+! go env GOEXPERIMENT
+stderr 'unknown GOEXPERIMENT bad'
diff --git a/src/cmd/go/testdata/script/env_unset.txt b/src/cmd/go/testdata/script/env_unset.txt
new file mode 100644
index 0000000..4e0f249
--- /dev/null
+++ b/src/cmd/go/testdata/script/env_unset.txt
@@ -0,0 +1,30 @@
+# Test that we can unset variables, even if initially invalid,
+# as long as resulting config is valid.
+
+env GOENV=badenv
+env GOOS=
+env GOARCH=
+env GOEXPERIMENT=
+
+! go env
+stderr '^go(\.exe)?: unknown GOEXPERIMENT badexp$'
+
+go env -u GOEXPERIMENT
+
+! go env
+stderr '^cmd/go: unsupported GOOS/GOARCH pair bados/badarch$'
+
+! go env -u GOOS
+stderr '^go env -u: unsupported GOOS/GOARCH pair \w+/badarch$'
+
+! go env -u GOARCH
+stderr '^go env -u: unsupported GOOS/GOARCH pair bados/\w+$'
+
+go env -u GOOS GOARCH
+
+go env
+
+-- badenv --
+GOOS=bados
+GOARCH=badarch
+GOEXPERIMENT=badexp
diff --git a/src/cmd/go/testdata/script/env_write.txt b/src/cmd/go/testdata/script/env_write.txt
index 4fa39df..b5e9739 100644
--- a/src/cmd/go/testdata/script/env_write.txt
+++ b/src/cmd/go/testdata/script/env_write.txt
@@ -179,3 +179,9 @@
 stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "~/test"'
 ! go env -w GOMODCACHE=./test
 stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "./test"'
+
+# go env -w checks validity of GOEXPERIMENT
+env GOEXPERIMENT=
+! go env -w GOEXPERIMENT=badexp
+stderr 'unknown GOEXPERIMENT badexp'
+go env -w GOEXPERIMENT=fieldtrack
diff --git a/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt b/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt
new file mode 100644
index 0000000..3d68ef3
--- /dev/null
+++ b/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt
@@ -0,0 +1,38 @@
+# Regression test for https://golang.org/issue/46462.
+#
+# The "runtime/cgo" import found in synthesized .go files (reported in
+# the CompiledGoFiles field) should have a corresponding entry in the
+# ImportMap field when a runtime/cgo variant (such as a test variant)
+# will be used.
+
+[short] skip  # -compiled can be slow (because it compiles things)
+[!cgo] skip
+
+env CGO_ENABLED=1
+env GOFLAGS=-tags=netcgo  # Force net to use cgo even on Windows.
+
+
+# "runtime/cgo [runtime.test]" appears in the the test dependencies of "runtime",
+# because "runtime/cgo" itself depends on "runtime"
+
+go list -deps -test -compiled -f '{{if eq .ImportPath "net [runtime.test]"}}{{printf "%q" .Imports}}{{end}}' runtime
+
+	# Control case: the explicitly-imported package "sync" is a test variant,
+	# because "sync" depends on "runtime".
+stdout '"sync \[runtime\.test\]"'
+! stdout '"sync"'
+
+	# Experiment: the implicitly-imported package "runtime/cgo" is also a test variant,
+	# because "runtime/cgo" also depends on "runtime".
+stdout '"runtime/cgo \[runtime\.test\]"'
+! stdout '"runtime/cgo"'
+
+
+# Because the import of "runtime/cgo" in the cgo-generated file actually refers
+# to "runtime/cgo [runtime.test]", the latter should be listed in the ImportMap.
+# BUG(#46462): Today, it is not.
+
+go list -deps -test -compiled -f '{{if eq .ImportPath "net [runtime.test]"}}{{printf "%q" .ImportMap}}{{end}}' runtime
+
+stdout '"sync":"sync \[runtime\.test\]"'                # control
+stdout '"runtime/cgo":"runtime/cgo \[runtime\.test\]"'  # experiment
diff --git a/src/cmd/go/testdata/script/list_find_nodeps.txt b/src/cmd/go/testdata/script/list_find_nodeps.txt
new file mode 100644
index 0000000..e08ce78
--- /dev/null
+++ b/src/cmd/go/testdata/script/list_find_nodeps.txt
@@ -0,0 +1,49 @@
+# Issue #46092
+# go list -find should always return a package with an empty Deps list
+
+# The linker loads implicit dependencies
+go list -find -f {{.Deps}} ./cmd
+stdout '\[\]'
+
+# Cgo translation may add imports of "unsafe", "runtime/cgo" and "syscall"
+go list -find -f {{.Deps}} ./cgo
+stdout '\[\]'
+
+# SWIG adds imports of some standard packages
+go list -find -f {{.Deps}} ./swig
+stdout '\[\]'
+
+-- go.mod --
+module listfind
+
+-- cmd/main.go --
+package main
+
+func main() {}
+
+-- cgo/pkg.go --
+package cgopkg
+
+/*
+#include <limits.h>
+*/
+import "C"
+
+func F() {
+    println(C.INT_MAX)
+}
+
+-- cgo/pkg_notcgo.go --
+//go:build !cgo
+// +build !cgo
+
+package cgopkg
+
+func F() {
+    println(0)
+}
+
+-- swig/pkg.go --
+package swigpkg
+
+-- swig/a.swigcxx --
diff --git a/src/cmd/go/testdata/script/list_gomod_in_gopath.txt b/src/cmd/go/testdata/script/list_gomod_in_gopath.txt
new file mode 100644
index 0000000..064f33a
--- /dev/null
+++ b/src/cmd/go/testdata/script/list_gomod_in_gopath.txt
@@ -0,0 +1,23 @@
+# Issue 46119
+
+# When a module is inside a GOPATH workspace, Package.Root should be set to
+# Module.Dir instead of $GOPATH/src.
+
+env GOPATH=$WORK/tmp
+cd $WORK/tmp/src/test
+
+go list -f {{.Root}}
+stdout ^$PWD$
+
+# Were we really inside a GOPATH workspace?
+env GO111MODULE=off
+go list -f {{.Root}}
+stdout ^$WORK/tmp$
+
+-- $WORK/tmp/src/test/go.mod --
+module test
+
+-- $WORK/tmp/src/test/main.go --
+package main
+
+func main() {}
diff --git a/src/cmd/go/testdata/script/list_load_err.txt b/src/cmd/go/testdata/script/list_load_err.txt
index b3b7271..0cfa7fb 100644
--- a/src/cmd/go/testdata/script/list_load_err.txt
+++ b/src/cmd/go/testdata/script/list_load_err.txt
@@ -2,26 +2,42 @@
 # other files in the same package cause go/build.Import to return an error.
 # Verfifies golang.org/issue/38568
 
-
 go list -e -deps ./scan
 stdout m/want
 
-
 go list -e -deps ./multi
 stdout m/want
 
-
 go list -e -deps ./constraint
 stdout m/want
 
-
 [cgo] go list -e -test -deps ./cgotest
 [cgo] stdout m/want
 
-
 [cgo] go list -e -deps ./cgoflag
 [cgo] stdout m/want
 
+
+# go list -e should include files with errors in GoFiles, TestGoFiles, and
+# other lists, assuming they match constraints.
+# Verifies golang.org/issue/39986
+go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./scan
+stdout '^good.go,scan.go,$'
+
+go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./multi
+stdout '^a.go,b.go,$'
+
+go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./constraint
+stdout '^good.go,$'
+go list -e -f '{{range .IgnoredGoFiles}}{{.}},{{end}}' ./constraint
+stdout '^constraint.go,$'
+
+[cgo] go list -e -f '{{range .XTestGoFiles}}{{.}},{{end}}' ./cgotest
+[cgo] stdout '^cgo_test.go,$'
+
+[cgo] go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./cgoflag
+[cgo] stdout '^cgoflag.go,$'
+
 -- go.mod --
 module m
 
diff --git a/src/cmd/go/testdata/script/list_std_stale.txt b/src/cmd/go/testdata/script/list_std_stale.txt
deleted file mode 100644
index e5c1f33..0000000
--- a/src/cmd/go/testdata/script/list_std_stale.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-# https://golang.org/issue/44725: packages in std should not be reported as stale,
-# regardless of whether they are listed from within or outside GOROOT/src.
-
-# Control case: net should not be stale at the start of the test,
-# and should depend on vendor/golang.org/… instead of golang.org/….
-
-! stale net
-
-go list -deps net
-stdout '^vendor/golang.org/x/net'
-! stdout '^golang.org/x/net'
-
-# Net should also not be stale when viewed from within GOROOT/src,
-# and should still report the same package dependencies.
-
-cd $GOROOT/src
-! stale net
-
-go list -deps net
-stdout '^vendor/golang.org/x/net'
-! stdout '^golang.org/x/net'
-
-
-# However, 'go mod' and 'go get' subcommands should report the original module
-# dependencies, not the vendored packages.
-
-[!net] stop
-
-env GOPROXY=
-go mod why -m golang.org/x/net
-stdout '^# golang.org/x/net\nnet\ngolang.org/x/net'
diff --git a/src/cmd/go/testdata/script/list_std_vendor.txt b/src/cmd/go/testdata/script/list_std_vendor.txt
new file mode 100644
index 0000000..8f27cc1
--- /dev/null
+++ b/src/cmd/go/testdata/script/list_std_vendor.txt
@@ -0,0 +1,32 @@
+# https://golang.org/issue/44725: packages in std should have the same
+# dependencies regardless of whether they are listed from within or outside
+# GOROOT/src.
+
+# Control case: net, viewed from outside the 'std' module,
+# should depend on vendor/golang.org/… instead of golang.org/….
+
+go list -deps net
+stdout '^vendor/golang.org/x/net'
+! stdout '^golang.org/x/net'
+cp stdout $WORK/net-deps.txt
+
+
+# It should still report the same package dependencies when viewed from
+# within GOROOT/src.
+
+cd $GOROOT/src
+
+go list -deps net
+stdout '^vendor/golang.org/x/net'
+! stdout '^golang.org/x/net'
+cmp stdout $WORK/net-deps.txt
+
+
+# However, 'go mod' and 'go get' subcommands should report the original module
+# dependencies, not the vendored packages.
+
+[!net] stop
+
+env GOPROXY=
+go mod why -m golang.org/x/net
+stdout '^# golang.org/x/net\nnet\ngolang.org/x/net'
diff --git a/src/cmd/go/testdata/script/mod_deprecate_message.txt b/src/cmd/go/testdata/script/mod_deprecate_message.txt
index 4a0674b..5670279 100644
--- a/src/cmd/go/testdata/script/mod_deprecate_message.txt
+++ b/src/cmd/go/testdata/script/mod_deprecate_message.txt
@@ -1,26 +1,26 @@
 # When there is a short single-line message, 'go get' should print it all.
 go get -d short
-stderr '^go: warning: module short is deprecated: short$'
+stderr '^go: module short is deprecated: short$'
 go list -m -u -f '{{.Deprecated}}' short
 stdout '^short$'
 
 # When there is a multi-line message, 'go get' should print the first line.
 go get -d multiline
-stderr '^go: warning: module multiline is deprecated: first line$'
+stderr '^go: module multiline is deprecated: first line$'
 ! stderr 'second line'
 go list -m -u -f '{{.Deprecated}}' multiline
 stdout '^first line\nsecond line.$'
 
 # When there is a long message, 'go get' should print a placeholder.
 go get -d long
-stderr '^go: warning: module long is deprecated: \(message omitted: too long\)$'
+stderr '^go: module long is deprecated: \(message omitted: too long\)$'
 go list -m -u -f '{{.Deprecated}}' long
 stdout '^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$'
 
 # When a message contains unprintable chracters, 'go get' should say that
 # without printing the message.
 go get -d unprintable
-stderr '^go: warning: module unprintable is deprecated: \(message omitted: contains non-printable characters\)$'
+stderr '^go: module unprintable is deprecated: \(message omitted: contains non-printable characters\)$'
 go list -m -u -f '{{.Deprecated}}' unprintable
 stdout '^message contains ASCII BEL\x07$'
 
diff --git a/src/cmd/go/testdata/script/mod_download.txt b/src/cmd/go/testdata/script/mod_download.txt
index 8a9faff..c2b72b2 100644
--- a/src/cmd/go/testdata/script/mod_download.txt
+++ b/src/cmd/go/testdata/script/mod_download.txt
@@ -107,13 +107,28 @@
 ! go mod download m@latest
 stderr '^go mod download: m@latest: malformed module path "m": missing dot in first path element$'
 
-# download updates go.mod and populates go.sum
+# download without arguments updates go.mod and go.sum after loading the
+# build list, but does not save sums for downloaded zips.
 cd update
+cp go.mod.orig go.mod
 ! exists go.sum
 go mod download
+cmp go.mod.update go.mod
+cmp go.sum.update go.sum
+cp go.mod.orig go.mod
+rm go.sum
+
+# download with arguments (even "all") does update go.mod and go.sum.
+go mod download rsc.io/sampler
+cmp go.mod.update go.mod
 grep '^rsc.io/sampler v1.3.0 ' go.sum
-go list -m rsc.io/sampler
-stdout '^rsc.io/sampler v1.3.0$'
+cp go.mod.orig go.mod
+rm go.sum
+
+go mod download all
+cmp go.mod.update go.mod
+grep '^rsc.io/sampler v1.3.0 ' go.sum
+cd ..
 
 # allow go mod download without go.mod
 env GO111MODULE=auto
@@ -131,7 +146,7 @@
 -- go.mod --
 module m
 
--- update/go.mod --
+-- update/go.mod.orig --
 module m
 
 go 1.16
@@ -140,3 +155,16 @@
 	rsc.io/quote v1.5.2
 	rsc.io/sampler v1.2.1 // older version than in build list
 )
+-- update/go.mod.update --
+module m
+
+go 1.16
+
+require (
+	rsc.io/quote v1.5.2
+	rsc.io/sampler v1.3.0 // older version than in build list
+)
+-- update/go.sum.update --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
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 0000000..ced15bb
--- /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_deprecate_install.txt b/src/cmd/go/testdata/script/mod_get_deprecate_install.txt
index d832b5f..63cd27a 100644
--- a/src/cmd/go/testdata/script/mod_get_deprecate_install.txt
+++ b/src/cmd/go/testdata/script/mod_get_deprecate_install.txt
@@ -7,16 +7,33 @@
 stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$'
 stderr 'Use ''go install pkg@version'' instead.'
 
-
-go mod init m
+cp go.mod.orig go.mod
 
 # 'go get' inside a module with a non-main package does not print a message.
 # This will stop building in the future, but it's the command we want to use.
 go get rsc.io/quote
 ! stderr deprecated
+cp go.mod.orig go.mod
 
 # 'go get' inside a module with an executable prints a different
 # deprecation message.
 go get example.com/cmd/a
 stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$'
 stderr 'To adjust and download dependencies of the current module, use ''go get -d'''
+cp go.mod.orig go.mod
+
+# 'go get' should not print a warning for a main package inside the main module.
+# The intent is most likely to update the dependencies of that package.
+# 'go install' would be used otherwise.
+go get m
+! stderr .
+cp go.mod.orig go.mod
+
+-- go.mod.orig --
+module m
+
+go 1.17
+-- main.go --
+package main
+
+func main() {}
diff --git a/src/cmd/go/testdata/script/mod_get_deprecated.txt b/src/cmd/go/testdata/script/mod_get_deprecated.txt
index 4633009..7bdd7a5 100644
--- a/src/cmd/go/testdata/script/mod_get_deprecated.txt
+++ b/src/cmd/go/testdata/script/mod_get_deprecated.txt
@@ -4,14 +4,14 @@
 
 # 'go get pkg' should show a deprecation message for the module providing pkg.
 go get -d example.com/deprecated/a
-stderr '^go: warning: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$'
+stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$'
 go get -d example.com/deprecated/a@v1.0.0
-stderr '^go: warning: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$'
+stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$'
 
 # 'go get pkg' should show a deprecation message for a module providing
 # packages directly imported by pkg.
 go get -d ./use/a
-stderr '^go: warning: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$'
+stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$'
 
 # 'go get pkg' may show a deprecation message for an indirectly required module
 # if it provides a package named on the command line.
@@ -20,7 +20,7 @@
 go get -d local/use
 ! stderr 'module.*is deprecated'
 go get -d example.com/deprecated/b
-stderr '^go: warning: module example.com/deprecated/b is deprecated: in example.com/deprecated/b@v1.9.0$'
+stderr '^go: module example.com/deprecated/b is deprecated: in example.com/deprecated/b@v1.9.0$'
 
 # 'go get pkg' does not show a deprecation message for a module providing a
 # directly imported package if the module is no longer deprecated in its
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 0000000..1cef9d1
--- /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_get_trailing_slash.txt b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt
index 3b38d8b..c536693 100644
--- a/src/cmd/go/testdata/script/mod_get_trailing_slash.txt
+++ b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt
@@ -1,6 +1,3 @@
-# Populate go.sum
-go mod download
-
 # go list should succeed to load a package ending with ".go" if the path does
 # not correspond to an existing local file. Listing a pattern ending with
 # ".go/" should try to list a package regardless of whether a file exists at the
@@ -31,3 +28,10 @@
 go 1.13
 
 require example.com/dotgo.go v1.0.0
+-- go.sum --
+example.com/dotgo.go v1.0.0 h1:XKJfs0V8x2PvY2tX8bJBCEbCDLnt15ma2onwhVpew/I=
+example.com/dotgo.go v1.0.0/go.mod h1:Qi6z/X3AC5vHiuMt6HF2ICx3KhIBGrMdrA7YoPDKqR0=
+-- use.go --
+package use
+
+import _ "example.com/dotgo.go"
diff --git a/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt b/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt
new file mode 100644
index 0000000..0093c0e
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt
@@ -0,0 +1,120 @@
+# Check that 'go get' adds sums for updated modules if we had sums before,
+# even if we didn't load packages from them.
+# Verifies #44129.
+
+env fmt='{{.ImportPath}}: {{if .Error}}{{.Error.Err}}{{else}}ok{{end}}'
+
+# Control case: before upgrading, we have the sums we need.
+# go list -deps -e -f $fmt .
+# stdout '^rsc.io/quote: ok$'
+# ! stdout rsc.io/sampler  # not imported by quote in this version
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+go mod tidy
+cmp go.mod.orig go.mod
+cmp go.sum.orig go.sum
+
+
+# Upgrade a module. This also upgrades rsc.io/quote, and though we didn't load
+# a package from it, we had the sum for its old version, so we need the
+# sum for the new version, too.
+go get -d example.com/upgrade@v0.0.2
+grep '^rsc.io/quote v1.5.2 ' go.sum
+
+# The upgrade still breaks the build because the new version of quote imports
+# rsc.io/sampler, and we don't have its zip sum.
+go list -deps -e -f $fmt
+stdout 'rsc.io/quote: ok'
+stdout 'rsc.io/sampler: missing go.sum entry for module providing package rsc.io/sampler'
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Replace the old version with a directory before upgrading.
+# We didn't need a sum for it before (even though we had one), so we won't
+# fetch a new sum.
+go mod edit -replace rsc.io/quote@v1.0.0=./dummy
+go get -d example.com/upgrade@v0.0.2
+! grep '^rsc.io/quote v1.5.2 ' go.sum
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Replace the new version with a directory before upgrading.
+# We can't get a sum for a directory.
+go mod edit -replace rsc.io/quote@v1.5.2=./dummy
+go get -d example.com/upgrade@v0.0.2
+! grep '^rsc.io/quote v1.5.2 ' go.sum
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Replace the new version with a different version.
+# We should get a sum for that version.
+go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1
+go get -d example.com/upgrade@v0.0.2
+! grep '^rsc.io/quote v1.5.2 ' go.sum
+grep '^rsc.io/quote v1.5.1 ' go.sum
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Delete the new version's zip (but not mod) from the cache and go offline.
+# 'go get' should fail when fetching the zip.
+rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+env GOPROXY=off
+! go get -d example.com/upgrade@v0.0.2
+stderr '^go: upgraded rsc.io/quote v1.0.0 => v1.5.2: error finding sum for rsc.io/quote@v1.5.2: module lookup disabled by GOPROXY=off$'
+
+-- go.mod.orig --
+module m
+
+go 1.16
+
+require (
+	example.com/upgrade v0.0.1
+	rsc.io/quote v1.0.0
+)
+
+replace (
+	example.com/upgrade v0.0.1 => ./upgrade1
+	example.com/upgrade v0.0.2 => ./upgrade2
+)
+-- go.sum.orig --
+rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw=
+rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA=
+-- go.sum.want --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw=
+rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA=
+rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+-- use.go --
+package use
+
+import (
+	_ "example.com/upgrade"
+	_ "rsc.io/quote"
+)
+-- upgrade1/go.mod --
+module example.com/upgrade
+
+go 1.16
+-- upgrade1/upgrade.go --
+package upgrade
+-- upgrade2/go.mod --
+module example.com/upgrade
+
+go 1.16
+
+require rsc.io/quote v1.5.2 // indirect
+-- upgrade2/upgrade.go --
+package upgrade
+-- dummy/go.mod --
+module rsc.io/quote
+
+go 1.16
+-- dummy/quote.go --
+package quote
+
diff --git a/src/cmd/go/testdata/script/mod_go_version_missing.txt b/src/cmd/go/testdata/script/mod_go_version_missing.txt
index aca36a0..d704816 100644
--- a/src/cmd/go/testdata/script/mod_go_version_missing.txt
+++ b/src/cmd/go/testdata/script/mod_go_version_missing.txt
@@ -73,10 +73,9 @@
 
 go $goversion
 
-require (
-	example.com/dep v0.1.0
-	example.com/testdep v0.1.0 // indirect
-)
+require example.com/dep v0.1.0
+
+require example.com/testdep v0.1.0 // indirect
 
 replace (
 	example.com/dep v0.1.0 => ./dep
diff --git a/src/cmd/go/testdata/script/mod_graph_version.txt b/src/cmd/go/testdata/script/mod_graph_version.txt
new file mode 100644
index 0000000..f9a73f4
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_graph_version.txt
@@ -0,0 +1,101 @@
+# For this module, Go 1.17 prunes out a (transitive and otherwise-irrelevant)
+# requirement on a retracted higher version of a dependency.
+# However, when Go 1.16 reads the same requirements from the go.mod file,
+# it does not prune out that requirement, and selects the retracted version.
+#
+# The Go 1.16 module graph looks like:
+#
+# m ---- lazy v0.1.0 ---- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible
+# |        |
+# + -------+------------- incompatible v1.0.0
+#
+# The Go 1.17 module graph is the same except that the dependencies of
+# requireincompatible are pruned out (because the module that requires
+# it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to
+# the main module).
+
+cp go.mod go.mod.orig
+
+go mod graph
+cp stdout graph-1.17.txt
+stdout '^example\.com/m example\.com/retract/incompatible@v1\.0\.0$'
+stdout '^example\.net/lazy@v0\.1\.0 example\.com/retract/incompatible@v1\.0\.0$'
+! stdout 'example\.com/retract/incompatible@v2\.0\.0\+incompatible'
+
+go mod graph -go=1.17
+cmp stdout graph-1.17.txt
+
+cmp go.mod go.mod.orig
+
+
+# Setting -go=1.16 should report the graph as viewed by Go 1.16,
+# but should not edit the go.mod file.
+
+go mod graph -go=1.16
+cp stdout graph-1.16.txt
+stdout '^example\.com/m example\.com/retract/incompatible@v1\.0\.0$'
+stdout '^example\.net/lazy@v0\.1\.0 example.com/retract/incompatible@v1\.0\.0$'
+stdout '^example.net/requireincompatible@v0.1.0 example.com/retract/incompatible@v2\.0\.0\+incompatible$'
+
+cmp go.mod go.mod.orig
+
+
+# If we actually update the go.mod file to the requested go version,
+# we should get the same selected versions, but the roots of the graph
+# may be updated.
+#
+# TODO(#45551): The roots should not be updated.
+
+go mod edit -go=1.16
+go mod graph
+! stdout '^example\.com/m example\.com/retract/incompatible@v1\.0\.0$'
+stdout '^example\.net/lazy@v0.1.0 example.com/retract/incompatible@v1\.0\.0$'
+stdout '^example.net/requireincompatible@v0.1.0 example.com/retract/incompatible@v2\.0\.0\+incompatible$'
+	# TODO(#45551): cmp stdout graph-1.16.txt
+
+
+# Unsupported go versions should be rejected, since we don't know
+# what versions they would report.
+! go mod graph -go=1.99999999999
+stderr '^invalid value "1\.99999999999" for flag -go: maximum supported Go version is '$goversion'\nusage: go mod graph \[-go=version\]\nRun ''go help mod graph'' for details.$'
+
+
+-- go.mod --
+// Module m indirectly imports a package from
+// example.com/retract/incompatible. Its selected version of
+// that module is lower under Go 1.17 semantics than under Go 1.16.
+module example.com/m
+
+go 1.17
+
+replace (
+	example.net/lazy v0.1.0 => ./lazy
+	example.net/requireincompatible v0.1.0 => ./requireincompatible
+)
+
+require (
+	example.com/retract/incompatible v1.0.0 // indirect
+	example.net/lazy v0.1.0
+)
+-- lazy/go.mod --
+// Module lazy requires example.com/retract/incompatible v1.0.0.
+//
+// When viewed from the outside it also has a transitive dependency
+// on v2.0.0+incompatible, but in lazy mode that transitive dependency
+// is pruned out.
+module example.net/lazy
+
+go 1.17
+
+exclude example.com/retract/incompatible v2.0.0+incompatible
+
+require (
+	example.com/retract/incompatible v1.0.0
+	example.net/requireincompatible v0.1.0
+)
+-- requireincompatible/go.mod --
+module example.net/requireincompatible
+
+go 1.15
+
+require example.com/retract/incompatible v2.0.0+incompatible
diff --git a/src/cmd/go/testdata/script/mod_init_path.txt b/src/cmd/go/testdata/script/mod_init_path.txt
index ccdfc92..e5fd4dd 100644
--- a/src/cmd/go/testdata/script/mod_init_path.txt
+++ b/src/cmd/go/testdata/script/mod_init_path.txt
@@ -1,7 +1,7 @@
 env GO111MODULE=on
 
 ! go mod init .
-stderr '^go: invalid module path "\.": is a local import path$'
+stderr '^go: malformed module path ".": is a local import path$'
 
 cd x
 go mod init example.com/x
diff --git a/src/cmd/go/testdata/script/mod_install_hint.txt b/src/cmd/go/testdata/script/mod_install_hint.txt
new file mode 100644
index 0000000..ab02840
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_install_hint.txt
@@ -0,0 +1,5 @@
+# Module is replaced but not required. No hint appears as no module is suggested.

+go mod init m

+go mod edit -replace=github.com/notrequired@v0.5.0=github.com/doesnotexist@v0.5.0

+! go install github.com/notrequired

+! stderr 'to add it:'
\ No newline at end of file
diff --git a/src/cmd/go/testdata/script/mod_install_pkg_version.txt b/src/cmd/go/testdata/script/mod_install_pkg_version.txt
index 2c14ef7..fd02392 100644
--- a/src/cmd/go/testdata/script/mod_install_pkg_version.txt
+++ b/src/cmd/go/testdata/script/mod_install_pkg_version.txt
@@ -143,7 +143,7 @@
 
 # If a wildcard matches only non-main packges, we should see a different warning.
 go install example.com/cmd/err...@v1.0.0
-stderr '^go: warning: "example.com/cmd/err\.\.\." matched no main packages$'
+stderr '^go: warning: "example.com/cmd/err\.\.\." matched only non-main packages$'
 
 
 # 'go install pkg@version' should report errors if the module contains
diff --git a/src/cmd/go/testdata/script/mod_invalid_path.txt b/src/cmd/go/testdata/script/mod_invalid_path.txt
index c8c075d..333a3ff 100644
--- a/src/cmd/go/testdata/script/mod_invalid_path.txt
+++ b/src/cmd/go/testdata/script/mod_invalid_path.txt
@@ -8,11 +8,8 @@
 # Test that go mod init in GOPATH doesn't add a module declaration
 # with a path that can't possibly be a module path, because
 # it isn't even a valid import path.
-# The single quote and backtick are the only characters  we don't allow
-# in checkModulePathLax, but is allowed in a Windows file name.
-# TODO(matloob): choose a different character once
-# module.CheckImportPath is laxened and replaces
-# checkModulePathLax.
+# The single quote and backtick are the only characters which are not allowed
+# but are a valid Windows file name.
 cd $WORK/'gopath/src/m''d'
 ! go mod init
 stderr 'cannot determine module path'
@@ -21,7 +18,7 @@
 # possibly be a module path, because it isn't even a valid import path
 cd $WORK/gopath/src/badname
 ! go list .
-stderr 'invalid module path'
+stderr 'malformed module path'
 
 # Test that an import path containing an element with a leading dot is valid,
 # but such a module path is not.
diff --git a/src/cmd/go/testdata/script/mod_invalid_version.txt b/src/cmd/go/testdata/script/mod_invalid_version.txt
index 34d9c47..6846a79 100644
--- a/src/cmd/go/testdata/script/mod_invalid_version.txt
+++ b/src/cmd/go/testdata/script/mod_invalid_version.txt
@@ -19,7 +19,7 @@
 go mod edit -require golang.org/x/text@14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\..\): parsing ../go.mod: '$WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3'
+stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3'
 cd ..
 go list -m golang.org/x/text
 stdout 'golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c'
@@ -47,10 +47,10 @@
 go mod edit -require golang.org/x/text@v2.1.1-0.20170915032832-14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ../go.mod: '$WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2'
+stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2'
 cd ..
 ! go list -m golang.org/x/text
-stderr $WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2'
+stderr $WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2'
 
 # A pseudo-version with fewer than 12 digits of SHA-1 prefix is invalid.
 cp go.mod.orig go.mod
diff --git a/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt
index 3dc1515..97718c4 100644
--- a/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt
+++ b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt
@@ -139,9 +139,10 @@
 require (
 	a v0.1.0
 	b v0.1.0
-	c v0.1.0 // indirect
 )
 
+require c v0.1.0 // indirect
+
 replace (
 	a v0.1.0 => ./a1
 	b v0.1.0 => ./b1
diff --git a/src/cmd/go/testdata/script/mod_lazy_new_import.txt b/src/cmd/go/testdata/script/mod_lazy_new_import.txt
index 86b14b6..4272a52 100644
--- a/src/cmd/go/testdata/script/mod_lazy_new_import.txt
+++ b/src/cmd/go/testdata/script/mod_lazy_new_import.txt
@@ -78,10 +78,9 @@
 
 go 1.17
 
-require (
-	example.com/a v0.1.0
-	example.com/b v0.1.0 // indirect
-)
+require example.com/a v0.1.0
+
+require example.com/b v0.1.0 // indirect
 
 replace (
 	example.com/a v0.1.0 => ./a
@@ -94,8 +93,9 @@
 
 go 1.17
 
+require example.com/a v0.1.0
+
 require (
-	example.com/a v0.1.0
 	example.com/b v0.1.0 // indirect
 	example.com/c v0.1.0 // indirect
 )
diff --git a/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt
index 722712d..68a5b6d 100644
--- a/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt
+++ b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt
@@ -148,10 +148,9 @@
 
 go 1.17
 
-require (
-	example.com/a v0.1.0
-	example.com/b v0.1.0 // indirect
-)
+require example.com/a v0.1.0
+
+require example.com/b v0.1.0 // indirect
 
 replace (
 	example.com/a v0.1.0 => ./a
diff --git a/src/cmd/go/testdata/script/mod_list_test_cycle.txt b/src/cmd/go/testdata/script/mod_list_test_cycle.txt
new file mode 100644
index 0000000..755e50b
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_list_test_cycle.txt
@@ -0,0 +1,23 @@
+# https://golang.org/issue/45863: a typo in a test package leading to an
+# import cycle should be diagnosed, instead of causing an infinite loop.
+# The failure mode of this test prior to the fix was a timeout or OOM crash.
+
+go list -e -test -deps ./datastore/sql
+
+-- go.mod --
+module golang.org/issue45863
+
+go 1.17
+-- datastore/datastore_health.go --
+package datastore
+
+import (
+	"golang.org/issue45863/datastore"
+	"golang.org/issue45863/datastore/sql"
+)
+-- datastore/sql/sql.go --
+package sql
+-- datastore/sql/sql_test.go --
+package sql
+
+import _ "golang.org/issue45863/datastore"
diff --git a/src/cmd/go/testdata/script/mod_overlay.txt b/src/cmd/go/testdata/script/mod_overlay.txt
index 92e79c7..86ab04b 100644
--- a/src/cmd/go/testdata/script/mod_overlay.txt
+++ b/src/cmd/go/testdata/script/mod_overlay.txt
@@ -21,7 +21,7 @@
 cd $WORK/gopath/src/get-doesnt-add-dep
 cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
 ! go get -d -overlay overlay.json .
-stderr 'overlaid files can''t be opened for write'
+stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
 cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
 
 # Content of overlaid go.sum is used.
@@ -41,10 +41,10 @@
 # attempting to update the file
 cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
 ! go get -d -overlay overlay.json .
-stderr 'overlaid files can''t be opened for write'
+stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$'
 cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
 ! go mod tidy -overlay overlay.json
-stderr 'overlaid files can''t be opened for write'
+stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$'
 cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
 
 # -overlay works with -modfile.
@@ -56,7 +56,7 @@
 stdout 'found.the/module'
 # Even with -modfile, overlaid files can't be opened for write.
 ! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote
-stderr 'overlaid files can''t be opened for write'
+stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
 
 # Carving out a module by adding an overlaid go.mod file
 cd $WORK/gopath/src/carve
@@ -78,7 +78,7 @@
 stdout ^carve2/nomod$
 # Editing go.mod file fails because overlay is read only
 ! go get -overlay overlay.json -d rsc.io/quote
-stderr 'overlaid files can''t be opened for write'
+stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
 ! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod
 # Editing go.mod file succeeds because we use -modfile to redirect to same file
 go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote
diff --git a/src/cmd/go/testdata/script/mod_query.txt b/src/cmd/go/testdata/script/mod_query.txt
index e101857..a75f86e 100644
--- a/src/cmd/go/testdata/script/mod_query.txt
+++ b/src/cmd/go/testdata/script/mod_query.txt
@@ -1,9 +1,7 @@
 env GO111MODULE=on
 
-# Populate go.sum.
 # TODO(golang.org/issue/41297): we shouldn't need go.sum. None of the commands
 # below depend on the build list.
-go mod download
 
 go list -m -versions rsc.io/quote
 stdout '^rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1$'
@@ -36,6 +34,9 @@
 module x
 require rsc.io/quote v1.0.0
 
+-- go.sum --
+rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw=
+rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA=
 -- use.go --
 package use
 
diff --git a/src/cmd/go/testdata/script/mod_replace.txt b/src/cmd/go/testdata/script/mod_replace.txt
index dc9667f..a0a367f 100644
--- a/src/cmd/go/testdata/script/mod_replace.txt
+++ b/src/cmd/go/testdata/script/mod_replace.txt
@@ -48,7 +48,7 @@
 # The reported Dir and GoMod for a replaced module should be accurate.
 cp go.mod.orig go.mod
 go mod edit -replace=rsc.io/quote/v3=not-rsc.io/quote@v0.1.0-nomod
-go mod download
+go mod download rsc.io/quote/v3
 go list -m -f '{{.Path}} {{.Version}} {{.Dir}} {{.GoMod}}{{with .Replace}} => {{.Path}} {{.Version}} {{.Dir}} {{.GoMod}}{{end}}' rsc.io/quote/v3
 stdout '^rsc.io/quote/v3 v3.0.0 '$GOPATH'[/\\]pkg[/\\]mod[/\\]not-rsc.io[/\\]quote@v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]not-rsc.io[/\\]quote[/\\]@v[/\\]v0.1.0-nomod.mod => not-rsc.io/quote v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]not-rsc.io[/\\]quote@v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]not-rsc.io[/\\]quote[/\\]@v[/\\]v0.1.0-nomod.mod$'
 
diff --git a/src/cmd/go/testdata/script/mod_retention.txt b/src/cmd/go/testdata/script/mod_retention.txt
index 0e639db..7a371b1 100644
--- a/src/cmd/go/testdata/script/mod_retention.txt
+++ b/src/cmd/go/testdata/script/mod_retention.txt
@@ -140,8 +140,9 @@
 go $goversion
 
 require (
-	golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
 	rsc.io/quote v1.5.2
 	rsc.io/sampler v1.3.0 // indirect
 	rsc.io/testonly v1.0.0 // indirect
 )
+
+require golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
diff --git a/src/cmd/go/testdata/script/mod_retract.txt b/src/cmd/go/testdata/script/mod_retract.txt
index a52e05b..4f95ece 100644
--- a/src/cmd/go/testdata/script/mod_retract.txt
+++ b/src/cmd/go/testdata/script/mod_retract.txt
@@ -1,8 +1,5 @@
 cp go.mod go.mod.orig
 
-# Populate go.sum.
-go mod download
-
 # 'go list pkg' does not report an error when a retracted version is used.
 go list -e -f '{{if .Error}}{{.Error}}{{end}}' ./use
 ! stdout .
@@ -32,6 +29,11 @@
 
 require example.com/retract v1.0.0-bad
 
+-- go.sum --
+example.com/retract v1.0.0-bad h1:liAW69rbtjY67x2CcNzat668L/w+YGgNX3lhJsWIJis=
+example.com/retract v1.0.0-bad/go.mod h1:0DvGGofJ9hr1q63cBrOY/jSY52OwhRGA0K47NE80I5Y=
+example.com/retract/self/prev v1.1.0 h1:0/8I/GTG+1eJTFeDQ/fUbgrMsVHHyKhh3Z8DSZp1fuA=
+example.com/retract/self/prev v1.1.0/go.mod h1:xl2EcklWuZZHVtHWcpzfSJQmnzAGpKZYpA/Wto7SZN4=
 -- use/use.go --
 package use
 
diff --git a/src/cmd/go/testdata/script/mod_run_nonmain.txt b/src/cmd/go/testdata/script/mod_run_nonmain.txt
new file mode 100644
index 0000000..036755d
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_run_nonmain.txt
@@ -0,0 +1,18 @@
+! go run $PWD
+! stderr 'no packages loaded'
+stderr '^package example.net/nonmain is not a main package$'
+
+! go run .
+stderr '^package example.net/nonmain is not a main package$'
+
+! go run ./...
+stderr '^go: warning: "\./\.\.\." matched only non-main packages$'
+stderr '^go run: no packages loaded from \./\.\.\.$'
+
+-- go.mod --
+module example.net/nonmain
+
+go 1.17
+-- nonmain.go --
+// Package nonmain is not a main package.
+package nonmain
diff --git a/src/cmd/go/testdata/script/mod_run_pkgerror.txt b/src/cmd/go/testdata/script/mod_run_pkgerror.txt
new file mode 100644
index 0000000..48f900d
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_run_pkgerror.txt
@@ -0,0 +1,32 @@
+# https://golang.org/issue/39986: files reported as invalid by go/build should
+# be listed in InvalidGoFiles.
+
+go list -e -f '{{.Incomplete}}{{"\n"}}{{.Error}}{{"\n"}}{{.InvalidGoFiles}}{{"\n"}}' .
+stdout '^true\nfound packages m \(m\.go\) and main \(main\.go\) in '$PWD'\n\[main.go\]\n'
+
+
+# https://golang.org/issue/45827: 'go run .' should report the same package
+# errors as 'go build' and 'go list'.
+
+! go build
+stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$'
+
+! go list .
+stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$'
+
+! go run .
+! stderr 'no packages loaded'
+stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$'
+
+! go run ./...
+! stderr 'no packages loaded'
+stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$'
+
+-- go.mod --
+module m
+
+go 1.17
+-- m.go --
+package m
+-- main.go --
+package main
diff --git a/src/cmd/go/testdata/script/mod_sumdb_golang.txt b/src/cmd/go/testdata/script/mod_sumdb_golang.txt
index cc0b0da..becd88b 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 @@
 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/go/testdata/script/mod_tidy_compat.txt b/src/cmd/go/testdata/script/mod_tidy_compat.txt
new file mode 100644
index 0000000..e6edef5
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_compat.txt
@@ -0,0 +1,95 @@
+# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by
+# default preserve enough checksums for the module to be used by Go 1.16.
+#
+# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the
+# 'go' version in the go.mod file to 1.16, without actually updating the
+# requirements to match.
+
+[short] skip
+
+env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
+
+
+# This module has the same module dependency graph in Go 1.16 as in Go 1.17,
+# but in 1.16 requires (checksums for) additional (irrelevant) go.mod files.
+#
+# The module graph under both versions looks like:
+#
+# m ---- example.com/version v1.1.0
+# |
+# + ---- example.net/lazy v0.1.0 ---- example.com/version v1.0.1
+#
+# Go 1.17 avoids loading the go.mod file for example.com/version v1.0.1
+# (because it is lower than the verison explicitly required by m,
+# and the module that requires it — m — specifies 'go 1.17').
+#
+# That go.mod file happens not to affect the final 1.16 module graph anyway,
+# so the pruned graph is equivalent to the unpruned one.
+
+cp go.mod go.mod.orig
+go mod tidy
+cmp go.mod go.mod.orig
+
+go list -m all
+cmp stdout m_all.txt
+
+go mod edit -go=1.16
+go list -m all
+cmp stdout m_all.txt
+
+
+# If we explicitly drop compatibility with 1.16, we retain fewer checksums,
+# which gives a cleaner go.sum file but causes 1.16 to fail in readonly mode.
+
+cp go.mod.orig go.mod
+go mod tidy -compat=1.17
+cmp go.mod go.mod.orig
+
+go list -m all
+cmp stdout m_all.txt
+
+go mod edit -go=1.16
+! go list -m all
+stderr '^go list -m: example.net/lazy@v0.1.0 requires\n\texample.com/version@v1.0.1: missing go.sum entry; to add it:\n\tgo mod download example.com/version$'
+
+
+-- go.mod --
+// Module m happens to have the exact same build list as what would be
+// selected under Go 1.16, but computes that build list without looking at
+// as many go.mod files.
+module example.com/m
+
+go 1.17
+
+replace example.net/lazy v0.1.0 => ./lazy
+
+require (
+	example.com/version v1.1.0
+	example.net/lazy v0.1.0
+)
+-- m_all.txt --
+example.com/m
+example.com/version v1.1.0
+example.net/lazy v0.1.0 => ./lazy
+-- compatible.go --
+package compatible
+
+import (
+	_ "example.com/version"
+	_ "example.net/lazy"
+)
+-- lazy/go.mod --
+// Module lazy requires example.com/version v1.0.1.
+//
+// However, since this module is lazy, its dependents
+// should not need checksums for that version of the module
+// unless they actually import packages from it.
+module example.net/lazy
+
+go 1.17
+
+require example.com/version v1.0.1
+-- lazy/lazy.go --
+package lazy
+
+import _ "example.com/version"
diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_added.txt b/src/cmd/go/testdata/script/mod_tidy_compat_added.txt
new file mode 100644
index 0000000..94fa79b
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_compat_added.txt
@@ -0,0 +1,105 @@
+# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by
+# default preserve enough checksums for the module to be used by Go 1.16.
+#
+# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the
+# 'go' version in the go.mod file to 1.16, without actually updating the
+# requirements to match.
+
+[short] skip
+
+env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
+
+
+# For this module, Go 1.17 produces an error for one module, and Go 1.16
+# produces a different error for a different module.
+
+cp go.mod go.mod.orig
+
+! go mod tidy
+
+stderr '^example\.com/m imports\n\texample\.net/added: module example\.net/added@latest found \(v0\.3\.0, replaced by \./a1\), but does not contain package example\.net/added$'
+
+cmp go.mod go.mod.orig
+
+
+# When we run 'go mod tidy -e', we should proceed past the first error and follow
+# it with a second error describing the version descrepancy.
+#
+# We should not provide advice on how to push past the version descrepancy,
+# because the '-e' flag should already do that, writing out an otherwise-tidied
+# go.mod file.
+
+go mod tidy -e
+
+stderr '^example\.com/m imports\n\texample\.net/added: module example\.net/added@latest found \(v0\.3\.0, replaced by \./a1\), but does not contain package example\.net/added\nexample\.net/added failed to load from any module,\n\tbut go 1\.16 would load it from example\.net/added@v0\.2\.0$'
+
+! stderr '\n\tgo mod tidy'
+
+cmp go.mod go.mod.tidy
+
+
+-- go.mod --
+module example.com/m
+
+go 1.17
+
+replace (
+	example.net/added v0.1.0 => ./a1
+	example.net/added v0.2.0 => ./a2
+	example.net/added v0.3.0 => ./a1
+	example.net/lazy v0.1.0 => ./lazy
+	example.net/pruned v0.1.0 => ./pruned
+)
+
+require (
+	example.net/added v0.1.0
+	example.net/lazy v0.1.0
+)
+-- go.mod.tidy --
+module example.com/m
+
+go 1.17
+
+replace (
+	example.net/added v0.1.0 => ./a1
+	example.net/added v0.2.0 => ./a2
+	example.net/added v0.3.0 => ./a1
+	example.net/lazy v0.1.0 => ./lazy
+	example.net/pruned v0.1.0 => ./pruned
+)
+
+require example.net/lazy v0.1.0
+-- m.go --
+package m
+
+import (
+	_ "example.net/added"
+	_ "example.net/lazy"
+)
+
+-- a1/go.mod --
+module example.net/added
+
+go 1.17
+-- a2/go.mod --
+module example.net/added
+
+go 1.17
+-- a2/added.go --
+package added
+
+-- lazy/go.mod --
+module example.net/lazy
+
+go 1.17
+
+require example.net/pruned v0.1.0
+-- lazy/lazy.go --
+package lazy
+
+-- pruned/go.mod --
+module example.net/pruned
+
+go 1.17
+
+require example.net/added v0.2.0
diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt
new file mode 100644
index 0000000..c544cb7
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt
@@ -0,0 +1,98 @@
+# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by
+# default preserve enough checksums for the module to be used by Go 1.16.
+#
+# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the
+# 'go' version in the go.mod file to 1.16, without actually updating the
+# requirements to match.
+
+[short] skip
+
+env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
+
+# For this module, the dependency providing package
+# example.net/ambiguous/nested/pkg is unambiguous in Go 1.17 (because only one
+# root of the module graph contains the package), whereas it is ambiguous in
+# Go 1.16 (because two different modules contain plausible packages and Go 1.16
+# does not privilege roots above other dependencies).
+#
+# However, the overall build list is identical for both versions.
+
+cp go.mod go.mod.orig
+
+! go mod tidy
+
+stderr '^example\.com/m imports\n\texample\.net/indirect imports\n\texample\.net/ambiguous/nested/pkg loaded from example\.net/ambiguous/nested@v0\.1\.0,\n\tbut go 1.16 would fail to locate it:\n\tambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0.1.0 \(.*\)\n\texample\.net/ambiguous/nested v0.1.0 \(.*\)\n\n'
+
+stderr '\n\nTo proceed despite packages unresolved in go 1\.16:\n\tgo mod tidy -e\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n'
+
+cmp go.mod go.mod.orig
+
+
+# If we run 'go mod tidy -e', we should still save enough checksums to run
+# 'go list -m all' reproducibly with go 1.16, even though we can't list
+# the specific package.
+
+go mod tidy -e
+! stderr '\n\tgo mod tidy'
+cmp go.mod go.mod.orig
+
+go list -m all
+cmp stdout all-m.txt
+
+go list -f $MODFMT example.net/ambiguous/nested/pkg
+stdout '^example.net/ambiguous/nested v0\.1\.0$'
+! stderr .
+
+go mod edit -go=1.16
+go list -m all
+cmp stdout all-m.txt
+
+! go list -f $MODFMT example.net/ambiguous/nested/pkg
+stderr '^ambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0\.1\.0 \(.*\)\n\texample\.net/ambiguous/nested v0\.1\.0 \(.*\)\n'
+
+
+# On the other hand, if we use -compat=1.17, 1.16 can't even load
+# the build list (due to missing checksums).
+
+cp go.mod.orig go.mod
+go mod tidy -compat=1.17
+! stderr .
+go list -m all
+cmp stdout all-m.txt
+
+go mod edit -go=1.16
+! go list -m all
+stderr '^go list -m: example\.net/indirect@v0\.1\.0 requires\n\texample\.net/ambiguous@v0\.1\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.net/ambiguous\n'
+
+
+-- go.mod --
+module example.com/m
+
+go 1.17
+
+replace example.net/indirect v0.1.0 => ./indirect
+
+require (
+	example.net/ambiguous/nested v0.1.0 // indirect
+	example.net/indirect v0.1.0
+)
+-- all-m.txt --
+example.com/m
+example.net/ambiguous v0.1.0
+example.net/ambiguous/nested v0.1.0
+example.net/indirect v0.1.0 => ./indirect
+-- m.go --
+package m
+
+import _ "example.net/indirect"
+
+-- indirect/go.mod --
+module example.net/indirect
+
+go 1.17
+
+require example.net/ambiguous v0.1.0
+-- indirect/indirect.go --
+package indirect
+
+import _ "example.net/ambiguous/nested/pkg"
diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt
new file mode 100644
index 0000000..dcf13e2
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt
@@ -0,0 +1,128 @@
+# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by
+# default preserve enough checksums for the module to be used by Go 1.16.
+#
+# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the
+# 'go' version in the go.mod file to 1.16, without actually updating the
+# requirements to match.
+
+[short] skip
+
+env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
+
+
+# For this module, the "deleted" dependency contains an imported package, but
+# Go 1.16 selects a higher version (in which that package has been deleted).
+
+cp go.mod go.mod.orig
+
+! go mod tidy
+
+stderr '^example\.com/m imports\n\texample\.net/deleted loaded from example\.net/deleted@v0\.1\.0,\n\tbut go 1\.16 would fail to locate it in example\.net/deleted@v0\.2\.0\n\n'
+
+stderr '\n\nTo upgrade to the versions selected by go 1.16, leaving some packages unresolved:\n\tgo mod tidy -e -go=1\.16 && go mod tidy -e -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n'
+
+
+# The suggested 'go mod tidy -e' command should proceed anyway.
+
+go mod tidy -e
+cmp go.mod go.mod.tidy
+
+
+# In 'go 1.16' mode we should error out in the way we claimed.
+
+cd 116-outside
+! go list -deps -f $MODFMT example.com/m
+stderr '^\.\.[/\\]m\.go:4:2: no required module provides package example\.net/deleted; to add it:\n\tgo get example\.net/deleted$'
+cd ..
+
+go mod edit -go=1.16
+! go list -deps -f $MODFMT example.com/m
+stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$'
+
+! go mod tidy
+stderr '^example\.com/m imports\n\texample\.net/deleted: module example\.net/deleted@latest found \(v0\.2\.0, replaced by \./d2\), but does not contain package example\.net/deleted$'
+
+
+-- go.mod --
+module example.com/m
+
+go 1.17
+
+replace (
+	example.net/deleted v0.1.0 => ./d1
+	example.net/deleted v0.2.0 => ./d2
+	example.net/lazy v0.1.0 => ./lazy
+	example.net/pruned v0.1.0 => ./pruned
+)
+
+require (
+	example.net/deleted v0.1.0
+	example.net/deleted v0.1.0 // redundant
+	example.net/lazy v0.1.0
+)
+-- go.mod.tidy --
+module example.com/m
+
+go 1.17
+
+replace (
+	example.net/deleted v0.1.0 => ./d1
+	example.net/deleted v0.2.0 => ./d2
+	example.net/lazy v0.1.0 => ./lazy
+	example.net/pruned v0.1.0 => ./pruned
+)
+
+require (
+	example.net/deleted v0.1.0
+	example.net/lazy v0.1.0
+)
+-- 116-outside/go.mod --
+module outside
+
+go 1.16
+
+replace (
+	example.com/m => ../
+	example.net/deleted v0.1.0 => ../d1
+	example.net/deleted v0.2.0 => ../d2
+	example.net/lazy v0.1.0 => ../lazy
+	example.net/pruned v0.1.0 => ../pruned
+)
+
+require example.com/m v0.1.0
+-- m.go --
+package m
+
+import (
+	_ "example.net/deleted"
+	_ "example.net/lazy"
+)
+
+-- d1/go.mod --
+module example.net/deleted
+
+go 1.17
+-- d1/deleted.go --
+package deleted
+-- d2/go.mod --
+module example.net/deleted
+
+go 1.17
+-- d2/README --
+There is no longer a Go package here.
+
+-- lazy/go.mod --
+module example.net/lazy
+
+go 1.17
+
+require example.net/pruned v0.1.0
+-- lazy/lazy.go --
+package lazy
+
+-- pruned/go.mod --
+module example.net/pruned
+
+go 1.17
+
+require example.net/deleted v0.2.0
diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt
new file mode 100644
index 0000000..186a3f8
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt
@@ -0,0 +1,129 @@
+# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by
+# default preserve enough checksums for the module to be used by Go 1.16.
+#
+# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the
+# 'go' version in the go.mod file to 1.16, without actually updating the
+# requirements to match.
+
+[short] skip
+
+env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
+
+
+# For this module, Go 1.16 selects the same versions of all explicit dependencies
+# as Go 1.17 does. However, Go 1.16 selects a higher version of an *implicit*
+# dependency, imported by a test of one of the (external) imported packages.
+# As a result, Go 1.16 also needs checksums for the module sources for that higher
+# version.
+#
+# The Go 1.16 module graph looks like:
+#
+# m ---- lazy v0.1.0 ---- incompatible v1.0.0
+#         |
+#         + ------------- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible
+#
+# The Go 1.17 module graph is the same except that the dependencies of
+# requireincompatible are pruned out (because the module that requires
+# it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to
+# the main module).
+
+# 'go mod tidy' should by default diagnose the difference in dependencies as an
+# error, with useful suggestions about how to resolve it.
+
+cp go.mod go.mod.orig
+! go mod tidy
+stderr '^example\.com/m imports\n\texample\.net/lazy tested by\n\texample\.net/lazy.test imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n'
+stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n'
+
+cmp go.mod go.mod.orig
+
+# The suggested '-compat' flag to ignore differences should silence the error
+# and leave go.mod unchanged, resulting in checksum errors when Go 1.16 tries
+# to load a module pruned out by Go 1.17.
+
+go mod tidy -compat=1.17
+! stderr .
+cmp go.mod go.mod.orig
+
+go list -deps -test -f $MODFMT all
+stdout '^example\.com/retract/incompatible v1\.0\.0$'
+
+go mod edit -go=1.16
+! go list -deps -test -f $MODFMT all
+
+	# TODO(#46160): -count=1 instead of -count=2.
+stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v1\.0\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.com/retract/incompatible$'
+
+
+# If we combine a Go 1.16 go.sum file...
+go mod tidy -go=1.16
+
+# ...with a Go 1.17 go.mod file...
+cp go.mod.orig go.mod
+
+# ...then Go 1.17 no longer works. 😞
+! go list -deps -test -f $MODFMT all
+stderr -count=1 '^can''t load test package: lazy[/\\]lazy_test.go:3:8: missing go\.sum entry for module providing package example\.com/retract/incompatible \(imported by example\.net/lazy\); to add:\n\tgo get -t example.net/lazy@v0\.1\.0$'
+
+
+# However, if we take the union of the go.sum files...
+go list -mod=mod -deps -test all
+cmp go.mod go.mod.orig
+
+# ...then Go 1.17 continues to work...
+go list -deps -test -f $MODFMT all
+stdout '^example\.com/retract/incompatible v1\.0\.0$'
+
+# ...and 1.16 also works(‽), but selects a different version for the
+# external-test dependency.
+go mod edit -go=1.16
+go list -deps -test -f $MODFMT all
+stdout '^example\.com/retract/incompatible v2\.0\.0\+incompatible$'
+
+
+-- go.mod --
+// Module m imports packages from the same versions under Go 1.17
+// as under Go 1.16, but under 1.16 its (implicit) external test dependencies
+// are higher.
+module example.com/m
+
+go 1.17
+
+replace (
+	example.net/lazy v0.1.0 => ./lazy
+	example.net/requireincompatible v0.1.0 => ./requireincompatible
+)
+
+require example.net/lazy v0.1.0
+-- implicit.go --
+package implicit
+
+import _ "example.net/lazy"
+-- lazy/go.mod --
+// Module lazy requires example.com/retract/incompatible v1.0.0.
+//
+// When viewed from the outside it also has a transitive dependency
+// on v2.0.0+incompatible, but in lazy mode that transitive dependency
+// is pruned out.
+module example.net/lazy
+
+go 1.17
+
+exclude example.com/retract/incompatible v2.0.0+incompatible
+
+require (
+	example.com/retract/incompatible v1.0.0
+	example.net/requireincompatible v0.1.0
+)
+-- lazy/lazy.go --
+package lazy
+-- lazy/lazy_test.go --
+package lazy_test
+
+import _ "example.com/retract/incompatible"
+-- requireincompatible/go.mod --
+module example.net/requireincompatible
+
+go 1.15
+
+require example.com/retract/incompatible v2.0.0+incompatible
diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt
new file mode 100644
index 0000000..ea9e42e
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt
@@ -0,0 +1,135 @@
+# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by
+# default preserve enough checksums for the module to be used by Go 1.16.
+#
+# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the
+# 'go' version in the go.mod file to 1.16, without actually updating the
+# requirements to match.
+
+[short] skip
+
+env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
+
+
+# For this module, Go 1.17 prunes out a (transitive and otherwise-irrelevant)
+# requirement on a retracted higher version of a dependency.
+# However, when Go 1.16 reads the same requirements from the go.mod file,
+# it does not prune out that requirement, and selects the retracted version.
+#
+# The Go 1.16 module graph looks like:
+#
+# m ---- lazy v0.1.0 ---- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible
+# |        |
+# + -------+------------- incompatible v1.0.0
+#
+# The Go 1.17 module graph is the same except that the dependencies of
+# requireincompatible are pruned out (because the module that requires
+# it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to
+# the main module).
+
+
+# 'go mod tidy' should by default diagnose the difference in dependencies as an
+# error, with useful suggestions about how to resolve it.
+
+cp go.mod go.mod.orig
+! go mod tidy
+stderr '^example\.com/m imports\n\texample\.net/lazy imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n'
+stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1\.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n'
+
+cmp go.mod go.mod.orig
+
+
+# The suggested '-compat' flag to ignore differences should silence the error
+# and leave go.mod unchanged, resulting in checksum errors when Go 1.16 tries
+# to load a module pruned out by Go 1.17.
+
+go mod tidy -compat=1.17
+! stderr .
+cmp go.mod go.mod.orig
+
+go mod edit -go=1.16
+! go list -f $MODFMT -deps ./...
+	# TODO(#46160): -count=1 instead of -count=2.
+stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.net/requireincompatible@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v2\.0\.0\+incompatible: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$'
+
+
+# There are two ways for the module author to bring the two into alignment.
+# One is to *explicitly* 'exclude' the version that is already *implicitly*
+# pruned out under 1.17.
+
+go mod edit -exclude=example.com/retract/incompatible@v2.0.0+incompatible
+go list -f $MODFMT -deps ./...
+stdout '^example.com/retract/incompatible v1\.0\.0$'
+! stdout 'v2\.0\.0'
+
+
+# The other is to explicitly upgrade the version required under Go 1.17
+# to match the version selected by Go 1.16. The commands suggested by
+# 'go mod tidy' should do exactly that.
+
+cp go.mod.orig go.mod
+
+go mod tidy -go=1.16
+go list -f $MODFMT -deps ./...
+stdout '^example.com/retract/incompatible v2\.0\.0\+incompatible$'
+! stdout 'v1\.0\.0'
+
+go mod tidy -go=1.17
+go list -f $MODFMT -deps ./...
+stdout '^example.com/retract/incompatible v2\.0\.0\+incompatible$'
+! stdout 'v1\.0\.0'
+
+go mod edit -go=1.16
+go list -f $MODFMT -deps ./...
+stdout '^example.com/retract/incompatible v2\.0\.0\+incompatible$'
+! stdout 'v1\.0\.0'
+
+
+-- go.mod --
+// Module m indirectly imports a package from
+// example.com/retract/incompatible. Its selected version of
+// that module is lower under Go 1.17 semantics than under Go 1.16.
+module example.com/m
+
+go 1.17
+
+replace (
+	example.net/lazy v0.1.0 => ./lazy
+	example.net/requireincompatible v0.1.0 => ./requireincompatible
+)
+
+require (
+	example.com/retract/incompatible v1.0.0 // indirect
+	example.net/lazy v0.1.0
+)
+-- incompatible.go --
+package incompatible
+
+import _ "example.net/lazy"
+
+-- lazy/go.mod --
+// Module lazy requires example.com/retract/incompatible v1.0.0.
+//
+// When viewed from the outside it also has a transitive dependency
+// on v2.0.0+incompatible, but in lazy mode that transitive dependency
+// is pruned out.
+module example.net/lazy
+
+go 1.17
+
+exclude example.com/retract/incompatible v2.0.0+incompatible
+
+require (
+	example.com/retract/incompatible v1.0.0
+	example.net/requireincompatible v0.1.0
+)
+-- lazy/lazy.go --
+package lazy
+
+import _ "example.com/retract/incompatible"
+
+-- requireincompatible/go.mod --
+module example.net/requireincompatible
+
+go 1.15
+
+require example.com/retract/incompatible v2.0.0+incompatible
diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt b/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt
new file mode 100644
index 0000000..7c22fca
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt
@@ -0,0 +1,99 @@
+# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by
+# default preserve enough checksums for the module to be used by Go 1.16.
+#
+# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the
+# 'go' version in the go.mod file to 1.16, without actually updating the
+# requirements to match.
+
+[short] skip
+
+env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
+
+
+# This module selects the same versions in Go 1.16 and 1.17 for all modules
+# that provide packages (or test dependencies of packages) imported by the
+# main module. However, in Go 1.16 it selects a higher version of a
+# transitive module dependency that is not otherwise relevant to the main module.
+# As a result, Go 1.16 needs an additional checksum for the go.mod file of
+# that irrelevant dependency.
+#
+# The Go 1.16 module graph looks like:
+#
+# m ---- lazy v0.1.0 ---- incompatible v1.0.0
+#         |
+#         + ------------- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible
+
+cp go.mod go.mod.orig
+go mod tidy
+cmp go.mod go.mod.orig
+
+go list -deps -test -f $MODFMT all
+cp stdout out-117.txt
+
+go mod edit -go=1.16
+go list -deps -test -f $MODFMT all
+cmp stdout out-117.txt
+
+
+# If we explicitly drop compatibility with 1.16, we retain fewer checksums,
+# which gives a cleaner go.sum file but causes 1.16 to fail in readonly mode.
+
+cp go.mod.orig go.mod
+go mod tidy -compat=1.17
+cmp go.mod go.mod.orig
+
+go list -deps -test -f $MODFMT all
+cmp stdout out-117.txt
+
+go mod edit -go=1.16
+! go list -deps -test -f $MODFMT all
+	# TODO(#46160): -count=1 instead of -count=2.
+stderr -count=2 '^go: example.net/lazy@v0.1.0 requires\n\texample.com/retract/incompatible@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$'
+
+
+-- go.mod --
+// Module m imports packages from the same versions under Go 1.17
+// as under Go 1.16, but under 1.16 its (implicit) external test dependencies
+// are higher.
+module example.com/m
+
+go 1.17
+
+replace (
+	example.net/lazy v0.1.0 => ./lazy
+	example.net/requireincompatible v0.1.0 => ./requireincompatible
+)
+
+require example.net/lazy v0.1.0
+-- m.go --
+package m
+
+import _ "example.net/lazy"
+-- lazy/go.mod --
+// Module lazy requires example.com/retract/incompatible v1.0.0.
+//
+// When viewed from the outside it also has a transitive dependency
+// on v2.0.0+incompatible, but in lazy mode that transitive dependency
+// is pruned out.
+module example.net/lazy
+
+go 1.17
+
+exclude example.com/retract/incompatible v2.0.0+incompatible
+
+require (
+	example.com/retract/incompatible v1.0.0
+	example.net/requireincompatible v0.1.0
+)
+-- lazy/lazy.go --
+package lazy
+-- lazy/unimported/unimported.go --
+package unimported
+
+import _ "example.com/retract/incompatible"
+-- requireincompatible/go.mod --
+module example.net/requireincompatible
+
+go 1.15
+
+require example.com/retract/incompatible v2.0.0+incompatible
diff --git a/src/cmd/go/testdata/script/mod_tidy_convergence.txt b/src/cmd/go/testdata/script/mod_tidy_convergence.txt
index 22c8fc6..09c46f7 100644
--- a/src/cmd/go/testdata/script/mod_tidy_convergence.txt
+++ b/src/cmd/go/testdata/script/mod_tidy_convergence.txt
@@ -90,7 +90,6 @@
 cp go.mod.orig go.mod
 go mod edit -go=1.17 go.mod
 go mod edit -go=1.17 go.mod.tidye
-go mod edit -go=1.17 go.mod.postget
 
 go mod tidy -e
 cmp go.mod go.mod.tidye
@@ -99,7 +98,7 @@
 
 go get -d example.net/x@v0.1.0 example.net/y@v0.1.0
 go mod tidy
-cmp go.mod go.mod.postget
+cmp go.mod go.mod.postget-117
 
 
 -- go.mod --
@@ -144,6 +143,21 @@
 	example.net/x v0.1.0
 	example.net/y v0.1.0 // indirect
 )
+-- go.mod.postget-117 --
+module example.net/m
+
+go 1.17
+
+replace (
+	example.net/x v0.1.0 => ./x1
+	example.net/x v0.2.0-pre => ./x2-pre
+	example.net/y v0.1.0 => ./y1
+	example.net/y v0.2.0 => ./y2
+)
+
+require example.net/x v0.1.0
+
+require example.net/y v0.1.0 // indirect
 -- m.go --
 package m
 
diff --git a/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt b/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt
new file mode 100644
index 0000000..ffcea18
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt
@@ -0,0 +1,71 @@
+# Regression test for https://golang.org/issue/46078:
+# 'go mod tidy' should not panic if the main module initially
+# requires an older version of itself.
+
+
+# A module that explicitly requires an older version of itself should be
+# rejected as inconsistent: we enforce that every explicit requirement is the
+# selected version of its module path, but the selected version of the main
+# module is always itself — not some explicit version.
+
+! go list -m all
+stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$'
+
+
+# The suggested 'go mod tidy' command should succeed (not crash).
+
+go mod tidy
+
+
+# We prune out redundant roots very early on in module loading, and at that
+# point the indirect requirement on example.net/x v0.1.0 appears to be
+# irrelevant. It should be pruned out; when the import of "example.net/x" is
+# later resolved, it should resolve at the latest version (v0.2.0), not the
+# version implied by the (former) misleading requirement on the older version of
+# the main module.
+
+cmp go.mod go.mod.tidy
+
+
+-- go.mod --
+module golang.org/issue/46078
+
+go 1.17
+
+replace (
+	example.net/x v0.1.0 => ./x
+	example.net/x v0.2.0 => ./x
+	golang.org/issue/46078 v0.1.0 => ./old
+)
+
+require golang.org/issue/46078 v0.1.0
+-- go.mod.tidy --
+module golang.org/issue/46078
+
+go 1.17
+
+replace (
+	example.net/x v0.1.0 => ./x
+	example.net/x v0.2.0 => ./x
+	golang.org/issue/46078 v0.1.0 => ./old
+)
+
+require example.net/x v0.2.0
+-- issue46078/issue.go --
+package issue46078
+
+import _ "example.net/x"
+
+-- old/go.mod --
+module golang.org/issue/46078
+
+go 1.17
+
+require example.net/x v0.1.0
+
+-- x/go.mod --
+module example.net/x
+
+go 1.17
+-- x/x.go --
+package x
diff --git a/src/cmd/go/testdata/script/mod_tidy_oldgo.txt b/src/cmd/go/testdata/script/mod_tidy_oldgo.txt
new file mode 100644
index 0000000..0e88b06
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_oldgo.txt
@@ -0,0 +1,21 @@
+# Modules were introduced in Go 1.11, but for various reasons users may
+# decide to declare a (much!) older go version in their go.mod file.
+# Modules with very old versions should not be rejected, and should have
+# the same module-graph semantics as in Go 1.11.
+
+cp go.mod go.mod.orig
+go mod tidy
+cmp go.mod go.mod.orig
+
+-- go.mod --
+module example.com/legacy/go1
+
+go 1.0
+
+require golang.org/x/text v0.3.0
+-- main.go --
+package main
+
+import _ "golang.org/x/text/language"
+
+func main() {}
diff --git a/src/cmd/go/testdata/script/mod_tidy_replace_old.txt b/src/cmd/go/testdata/script/mod_tidy_replace_old.txt
new file mode 100644
index 0000000..cfd3792
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_replace_old.txt
@@ -0,0 +1,34 @@
+# Regression test for https://golang.org/issue/46659.
+#
+# If a 'replace' directive specifies an older-than-selected version of a module,
+# 'go mod tidy' shouldn't try to add that version to the build list to resolve a
+# missing package: it won't be selected, and would cause the module loader to
+# loop indefinitely trying to resolve the package.
+
+cp go.mod go.mod.orig
+
+! go mod tidy
+! stderr panic
+stderr '^golang\.org/issue46659 imports\n\texample\.com/missingpkg/deprecated: package example\.com/missingpkg/deprecated provided by example\.com/missingpkg at latest version v1\.0\.0 but not at required version v1\.0\.1-beta$'
+
+go mod tidy -e
+
+cmp go.mod go.mod.orig
+
+-- go.mod --
+module golang.org/issue46659
+
+go 1.17
+
+replace example.com/missingpkg v1.0.1-alpha => example.com/missingpkg v1.0.0
+
+require example.com/usemissingpre v1.0.0
+
+require example.com/missingpkg v1.0.1-beta // indirect
+-- m.go --
+package m
+
+import (
+	_ "example.com/missingpkg/deprecated"
+	_ "example.com/usemissingpre"
+)
diff --git a/src/cmd/go/testdata/script/mod_tidy_too_new.txt b/src/cmd/go/testdata/script/mod_tidy_too_new.txt
new file mode 100644
index 0000000..b9c53b5
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_too_new.txt
@@ -0,0 +1,57 @@
+# https://golang.org/issue/46142: 'go mod tidy' should error out if the version
+# in the go.mod file is newer than the most recent supported version.
+
+cp go.mod go.mod.orig
+
+
+# If the go.mod file specifies an unsupported Go version, 'go mod tidy' should
+# refuse to edit it: we don't know what a tidy go.mod file for that version
+# would look like.
+
+! go mod tidy
+stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$'
+cmp go.mod go.mod.orig
+
+
+# The -e flag should push past the error and edit the file anyway,
+# but preserve the too-high version.
+
+cp go.mod.orig go.mod
+go mod tidy -e
+stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$'
+cmp go.mod go.mod.tidy
+
+
+# Explicitly switching to a supported version should suppress the error completely.
+
+cp go.mod.orig go.mod
+go mod tidy -go=1.17
+! stderr 'maximum supported version'
+go mod edit -go=1.17 go.mod.tidy
+cmp go.mod go.mod.tidy
+
+
+-- go.mod --
+module example.net/from/the/future
+
+go 2000.0
+
+replace example.net/m v0.0.0 => ./m
+-- go.mod.tidy --
+module example.net/from/the/future
+
+go 2000.0
+
+replace example.net/m v0.0.0 => ./m
+
+require example.net/m v0.0.0
+-- x.go --
+package x
+
+import "example.net/m"
+-- m/go.mod --
+module example.net/m
+
+go 1.17
+-- m/m.go --
+package m
diff --git a/src/cmd/go/testdata/script/mod_tidy_version.txt b/src/cmd/go/testdata/script/mod_tidy_version.txt
index 5441d9c..3bc97bc 100644
--- a/src/cmd/go/testdata/script/mod_tidy_version.txt
+++ b/src/cmd/go/testdata/script/mod_tidy_version.txt
@@ -32,12 +32,22 @@
 
 cp go.mod go.mod.orig
 
+
 # An invalid argument should be rejected.
 
 ! go mod tidy -go=bananas
-stderr '^go mod: invalid -go option "bananas"; expecting something like "-go 1.17"$'
+stderr '^invalid value "bananas" for flag -go: expecting a Go version like "'$goversion'"$'
 cmp go.mod go.mod.orig
 
+! go mod tidy -go=0.9
+stderr '^invalid value "0.9" for flag -go: expecting a Go version like "'$goversion'"$'
+
+! go mod tidy -go=2000.0
+stderr '^invalid value "2000.0" for flag -go: maximum supported Go version is '$goversion'$'
+
+
+# Supported versions should change the go.mod file to be tidy according to the
+# indicated version.
 
 go mod tidy -go=1.15
 cmp go.mod go.mod.115
@@ -82,8 +92,9 @@
 -- go.mod --
 module example.com/m
 
+require example.net/a v0.1.0
+
 require (
-	example.net/a v0.1.0
 	example.net/c v0.1.0 // indirect
 	example.net/d v0.1.0 // indirect
 )
@@ -108,8 +119,9 @@
 
 go 1.15
 
+require example.net/a v0.1.0
+
 require (
-	example.net/a v0.1.0
 	example.net/c v0.1.0 // indirect
 	example.net/d v0.1.0 // indirect
 )
@@ -129,8 +141,9 @@
 
 go 1.15
 
+require example.net/a v0.1.0
+
 require (
-	example.net/a v0.1.0
 	example.net/c v0.1.0 // indirect
 	example.net/d v0.2.0 // indirect
 )
@@ -150,10 +163,9 @@
 
 go 1.16
 
-require (
-	example.net/a v0.1.0
-	example.net/c v0.1.0 // indirect
-)
+require example.net/a v0.1.0
+
+require example.net/c v0.1.0 // indirect
 
 replace (
 	example.net/a v0.1.0 => ./a
@@ -170,8 +182,9 @@
 
 go 1.17
 
+require example.net/a v0.1.0
+
 require (
-	example.net/a v0.1.0
 	example.net/b v0.1.0 // indirect
 	example.net/c v0.1.0 // indirect
 )
@@ -191,8 +204,9 @@
 
 go $goversion
 
+require example.net/a v0.1.0
+
 require (
-	example.net/a v0.1.0
 	example.net/b v0.1.0 // indirect
 	example.net/c v0.1.0 // indirect
 )
diff --git a/src/cmd/go/testdata/script/mod_update_sum_readonly.txt b/src/cmd/go/testdata/script/mod_update_sum_readonly.txt
new file mode 100644
index 0000000..41f12e4
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_update_sum_readonly.txt
@@ -0,0 +1,34 @@
+# When finding the latest version of a module, we should not download version
+# contents. Previously, we downloaded .zip files to determine whether a real
+# .mod file was present in order to decide whether +incompatible versions
+# could be "latest".
+#
+# Verifies #47377.
+
+# rsc.io/breaker has two versions, neither of which has a .mod file.
+go list -m -versions rsc.io/breaker
+stdout '^rsc.io/breaker v1.0.0 v2.0.0\+incompatible$'
+go mod download rsc.io/breaker@v1.0.0
+! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.mod
+go mod download rsc.io/breaker@v2.0.0+incompatible
+! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.mod
+
+# Delete downloaded .zip files.
+go clean -modcache
+
+# Check for updates.
+go list -m -u rsc.io/breaker
+stdout '^rsc.io/breaker v1.0.0 \[v2.0.0\+incompatible\]$'
+
+# We should not have downloaded zips.
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.zip
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.zip
+
+-- go.mod --
+module m
+
+go 1.16
+
+require rsc.io/breaker v1.0.0
+-- go.sum --
+rsc.io/breaker v1.0.0/go.mod h1:s5yxDXvD88U1/ESC23I2FK3Lkv4YIKaB1ij/Hbm805g=
diff --git a/src/cmd/go/testdata/script/mod_vendor_issue46867.txt b/src/cmd/go/testdata/script/mod_vendor_issue46867.txt
new file mode 100644
index 0000000..38ae87b
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_vendor_issue46867.txt
@@ -0,0 +1,31 @@
+# Regression test for golang.org/issue/46867:
+# 'go mod vendor' on Windows attempted to open and copy
+# files from directories outside of the module.
+
+cd subdir
+go mod vendor
+! exists vendor/example.net/NOTICE
+exists vendor/example.net/m/NOTICE
+
+-- subdir/go.mod --
+module golang.org/issue46867
+
+go 1.17
+
+replace example.net/m v0.1.0 => ./m
+
+require example.net/m v0.1.0
+-- subdir/issue.go --
+package issue
+
+import _ "example.net/m/n"
+-- subdir/m/go.mod --
+module example.net/m
+
+go 1.17
+-- subdir/m/n/n.go --
+package n
+-- subdir/m/NOTICE --
+This notice is in module m and SHOULD be vendored.
+-- subdir/NOTICE --
+This notice is outside of module m and SHOULD NOT be vendored.
diff --git a/src/cmd/go/testdata/script/test_race_install_cgo.txt b/src/cmd/go/testdata/script/test_race_install_cgo.txt
index 3f4eb90..e1fe4f2 100644
--- a/src/cmd/go/testdata/script/test_race_install_cgo.txt
+++ b/src/cmd/go/testdata/script/test_race_install_cgo.txt
@@ -2,8 +2,6 @@
 
 [!race] skip
 
-[!darwin] ! stale cmd/cgo  # The darwin builders are spuriously stale; see #33598.
-
 env GOBIN=$WORK/bin
 go install m/mtime m/sametime
 
diff --git a/src/cmd/go/testdata/script/test_script_cmdcd.txt b/src/cmd/go/testdata/script/test_script_cmdcd.txt
new file mode 100644
index 0000000..6e6f67e
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_script_cmdcd.txt
@@ -0,0 +1,13 @@
+# Tests that after a cd command, where usually the UNIX path separator is used,
+# a match against $PWD does not fail on Windows.
+
+cd $WORK/a/b/c/pkg
+
+go list -find -f {{.Root}}
+stdout $PWD
+
+-- $WORK/a/b/c/pkg/go.mod --
+module pkg
+
+-- $WORK/a/b/c/pkg/pkg.go --
+package pkg
diff --git a/src/cmd/go/testdata/script/toolexec.txt b/src/cmd/go/testdata/script/toolexec.txt
index 4f26da6..bb86467 100644
--- a/src/cmd/go/testdata/script/toolexec.txt
+++ b/src/cmd/go/testdata/script/toolexec.txt
@@ -3,6 +3,12 @@
 # Build our simple toolexec program.
 go build ./cmd/mytool
 
+# Use an ephemeral build cache so that our toolexec output is not cached
+# for any stale standard-library dependencies.
+#
+# TODO(#27628): This should not be necessary.
+env GOCACHE=$WORK/gocache
+
 # Build the main package with our toolexec program. For each action, it will
 # print the tool's name and the TOOLEXEC_IMPORTPATH value. We expect to compile
 # each package once, and link the main package once.
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 68476e7..e340665 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -26,9 +26,6 @@
 		Do not print reformatted sources to standard output.
 		If a file's formatting is different from gofmt's, print its name
 		to standard output.
-	-G
-		Allow generic code, using type parameters.
-		See golang.org/issues/43651 for more information.
 	-r rule
 		Apply the rewrite rule to the source before reformatting.
 	-s
diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go
index ba574f4..56c3b25 100644
--- a/src/cmd/internal/moddeps/moddeps_test.go
+++ b/src/cmd/internal/moddeps/moddeps_test.go
@@ -5,6 +5,7 @@
 package moddeps_test
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
 	"internal/testenv"
@@ -68,7 +69,7 @@
 
 			// There is no vendor directory, so the module must have no dependencies.
 			// Check that the list of active modules contains only the main module.
-			cmd := exec.Command(goBin, "list", "-mod=mod", "-m", "all")
+			cmd := exec.Command(goBin, "list", "-mod=readonly", "-m", "all")
 			cmd.Env = append(os.Environ(), "GO111MODULE=on")
 			cmd.Dir = m.Dir
 			cmd.Stderr = new(strings.Builder)
@@ -123,10 +124,38 @@
 		t.Skip("skipping because a diff command with support for --recursive and --unified flags is unavailable")
 	}
 
+	// We're going to check the standard modules for tidiness, so we need a usable
+	// GOMODCACHE. If the default directory doesn't exist, use a temporary
+	// directory instead. (That can occur, for example, when running under
+	// run.bash with GO_TEST_SHORT=0: run.bash sets GOPATH=/nonexist-gopath, and
+	// GO_TEST_SHORT=0 causes it to run this portion of the test.)
+	var modcacheEnv []string
+	{
+		out, err := exec.Command(goBin, "env", "GOMODCACHE").Output()
+		if err != nil {
+			t.Fatalf("%s env GOMODCACHE: %v", goBin, err)
+		}
+		modcacheOk := false
+		if gomodcache := string(bytes.TrimSpace(out)); gomodcache != "" {
+			if _, err := os.Stat(gomodcache); err == nil {
+				modcacheOk = true
+			}
+		}
+		if !modcacheOk {
+			modcacheEnv = []string{
+				"GOMODCACHE=" + t.TempDir(),
+				"GOFLAGS=" + os.Getenv("GOFLAGS") + " -modcacherw", // Allow t.TempDir() to clean up subdirectories.
+			}
+		}
+	}
+
 	// Build the bundle binary at the golang.org/x/tools
 	// module version specified in GOROOT/src/cmd/go.mod.
 	bundleDir := t.TempDir()
-	r := runner{Dir: filepath.Join(runtime.GOROOT(), "src/cmd")}
+	r := runner{
+		Dir: filepath.Join(runtime.GOROOT(), "src/cmd"),
+		Env: append(os.Environ(), modcacheEnv...),
+	}
 	r.run(t, goBin, "build", "-mod=readonly", "-o", bundleDir, "golang.org/x/tools/cmd/bundle")
 
 	var gorootCopyDir string
@@ -160,7 +189,7 @@
 			}
 			r := runner{
 				Dir: filepath.Join(gorootCopyDir, rel),
-				Env: append(os.Environ(),
+				Env: append(append(os.Environ(), modcacheEnv...),
 					// Set GOROOT.
 					"GOROOT="+gorootCopyDir,
 					// Explicitly override PWD and clear GOROOT_FINAL so that GOROOT=gorootCopyDir is definitely used.
@@ -227,7 +256,7 @@
 		if err != nil {
 			return err
 		}
-		if src == filepath.Join(runtime.GOROOT(), ".git") {
+		if info.IsDir() && src == filepath.Join(runtime.GOROOT(), ".git") {
 			return filepath.SkipDir
 		}
 
@@ -237,9 +266,8 @@
 		}
 		dst := filepath.Join(gorootCopyDir, rel)
 
-		switch src {
-		case filepath.Join(runtime.GOROOT(), "bin"),
-			filepath.Join(runtime.GOROOT(), "pkg"):
+		if info.IsDir() && (src == filepath.Join(runtime.GOROOT(), "bin") ||
+			src == filepath.Join(runtime.GOROOT(), "pkg")) {
 			// If the OS supports symlinks, use them instead
 			// of copying the bin and pkg directories.
 			if err := os.Symlink(src, dst); err == nil {
@@ -414,7 +442,7 @@
 			if info.IsDir() && (info.Name() == "vendor" || info.Name() == "testdata") {
 				return filepath.SkipDir
 			}
-			if path == filepath.Join(runtime.GOROOT(), "pkg") {
+			if info.IsDir() && path == filepath.Join(runtime.GOROOT(), "pkg") {
 				// GOROOT/pkg contains generated artifacts, not source code.
 				//
 				// In https://golang.org/issue/37929 it was observed to somehow contain
@@ -422,7 +450,7 @@
 				// running time of this test anyway.)
 				return filepath.SkipDir
 			}
-			if strings.HasPrefix(info.Name(), "_") || strings.HasPrefix(info.Name(), ".") {
+			if info.IsDir() && (strings.HasPrefix(info.Name(), "_") || strings.HasPrefix(info.Name(), ".")) {
 				// _ and . prefixed directories can be used for internal modules
 				// without a vendor directory that don't contribute to the build
 				// but might be used for example as code generators.
@@ -457,8 +485,31 @@
 			goroot.modules = append(goroot.modules, m)
 			return nil
 		})
-	})
+		if goroot.err != nil {
+			return
+		}
 
+		// knownGOROOTModules is a hard-coded list of modules that are known to exist in GOROOT.
+		// If findGorootModules doesn't find a module, it won't be covered by tests at all,
+		// so make sure at least these modules are found. See issue 46254. If this list
+		// becomes a nuisance to update, can be replaced with len(goroot.modules) check.
+		knownGOROOTModules := [...]string{
+			"std",
+			"cmd",
+			"misc",
+			"test/bench/go1",
+		}
+		var seen = make(map[string]bool) // Key is module path.
+		for _, m := range goroot.modules {
+			seen[m.Path] = true
+		}
+		for _, m := range knownGOROOTModules {
+			if !seen[m] {
+				goroot.err = fmt.Errorf("findGorootModules didn't find the well-known module %q", m)
+				break
+			}
+		}
+	})
 	if goroot.err != nil {
 		t.Fatal(goroot.err)
 	}
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 575436d..d99afa3 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -3536,27 +3536,25 @@
 		o1 = c.oprrr(p, p.As)
 
 		cond := int(p.From.Reg)
-		if cond < COND_EQ || cond > COND_NV {
+		// AL and NV are not allowed for CINC/CINV/CNEG/CSET/CSETM instructions
+		if cond < COND_EQ || cond > COND_NV || (cond == COND_AL || cond == COND_NV) && p.From3Type() == obj.TYPE_NONE {
 			c.ctxt.Diag("invalid condition: %v", p)
 		} else {
 			cond -= COND_EQ
 		}
 
 		r := int(p.Reg)
-		var rf int
-		if r != 0 {
-			if p.From3Type() == obj.TYPE_NONE {
-				/* CINC/CINV/CNEG */
-				rf = r
-				cond ^= 1
-			} else {
-				rf = int(p.GetFrom3().Reg) /* CSEL */
+		var rf int = r
+		if p.From3Type() == obj.TYPE_NONE {
+			/* CINC/CINV/CNEG or CSET/CSETM*/
+			if r == 0 {
+				/* CSET/CSETM */
+				rf = REGZERO
+				r = rf
 			}
-		} else {
-			/* CSET */
-			rf = REGZERO
-			r = rf
 			cond ^= 1
+		} else {
+			rf = int(p.GetFrom3().Reg) /* CSEL */
 		}
 
 		rt := int(p.To.Reg)
@@ -4335,8 +4333,10 @@
 		if p.To.Reg == REG_RSP && isADDSop(p.As) {
 			c.ctxt.Diag("illegal destination register: %v\n", p)
 		}
+		lsl0 := LSL0_64
 		if isADDWop(p.As) || isANDWop(p.As) {
 			o1 = c.omovconst(AMOVW, p, &p.From, REGTMP)
+			lsl0 = LSL0_32
 		} else {
 			o1 = c.omovconst(AMOVD, p, &p.From, REGTMP)
 		}
@@ -4352,7 +4352,7 @@
 		if p.To.Reg == REGSP || r == REGSP {
 			o2 = c.opxrrr(p, p.As, false)
 			o2 |= REGTMP & 31 << 16
-			o2 |= LSL0_64
+			o2 |= uint32(lsl0)
 		} else {
 			o2 = c.oprrr(p, p.As)
 			o2 |= REGTMP & 31 << 16 /* shift is 0 */
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 69f967a..316959f 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -2220,7 +2220,7 @@
 
 // Encode instructions and create relocation for accessing s+d according to the
 // instruction op with source or destination (as appropriate) register reg.
-func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 uint32) {
+func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32, reuse bool) (o1, o2 uint32) {
 	if c.ctxt.Headtype == objabi.Haix {
 		// Every symbol access must be made via a TOC anchor.
 		c.ctxt.Diag("symbolAccess called for %s", s.Name)
@@ -2232,8 +2232,15 @@
 	} else {
 		base = REG_R0
 	}
-	o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0)
-	o2 = AOP_IRR(op, uint32(reg), REGTMP, 0)
+	// If reg can be reused when computing the symbol address,
+	// use it instead of REGTMP.
+	if !reuse {
+		o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0)
+		o2 = AOP_IRR(op, uint32(reg), REGTMP, 0)
+	} else {
+		o1 = AOP_IRR(OP_ADDIS, uint32(reg), base, 0)
+		o2 = AOP_IRR(op, uint32(reg), uint32(reg), 0)
+	}
 	rel := obj.Addrel(c.cursym)
 	rel.Off = int32(c.pc)
 	rel.Siz = 8
@@ -2877,14 +2884,14 @@
 		switch p.From.Name {
 		case obj.NAME_EXTERN, obj.NAME_STATIC:
 			// Load a 32 bit constant, or relocation depending on if a symbol is attached
-			o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI)
+			o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI, true)
 		default:
 			if r == 0 {
 				r = c.getimpliedreg(&p.From, p)
 			}
 			// Add a 32 bit offset to a register.
-			o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(int32(v))))
-			o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v))
+			o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(int32(v))))
+			o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
 		}
 
 	case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
@@ -3043,10 +3050,10 @@
 		if r == 0 {
 			r = c.getimpliedreg(&p.From, p)
 		}
-		o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
-		o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), REGTMP, uint32(v))
+		o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v)))
+		o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
 
-		// Sign extend MOVB operations. This is ignored for other cases (o.size == 8).
+		// Sign extend MOVB if needed
 		o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
 	case 40: /* word */
@@ -3404,7 +3411,8 @@
 		if c.opform(inst) == DS_FORM && v&0x3 != 0 {
 			log.Fatalf("invalid offset for DS form load/store %v", p)
 		}
-		o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst)
+		// Can't reuse base for store instructions.
+		o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst, false)
 
 	case 75: // 32 bit offset symbol loads (got/toc/addr)
 		v := p.From.Offset
@@ -3432,10 +3440,11 @@
 				rel.Type = objabi.R_ADDRPOWER_TOCREL_DS
 			}
 		default:
-			o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst)
+			reuseBaseReg := p.As != AFMOVD && p.As != AFMOVS
+			// Reuse To.Reg as base register if not FP move.
+			o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg)
 		}
 
-		// Sign extend MOVB operations. This is ignored for other cases (o.size == 8).
 		o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
 	case 79:
diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go
index ea55fa3..52827a6 100644
--- a/src/cmd/internal/objabi/reloctype.go
+++ b/src/cmd/internal/objabi/reloctype.go
@@ -101,6 +101,9 @@
 	// *rtype, and may be set to zero by the linker if it determines the method
 	// text is unreachable by the linked program.
 	R_METHODOFF
+	// R_KEEP tells the linker to keep the referred-to symbol in the final binary
+	// if the symbol containing the R_KEEP relocation is in the final binary.
+	R_KEEP
 	R_POWER_TOC
 	R_GOTPCREL
 	// R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address
diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go
index 8882d19..4638ef1 100644
--- a/src/cmd/internal/objabi/reloctype_string.go
+++ b/src/cmd/internal/objabi/reloctype_string.go
@@ -34,44 +34,45 @@
 	_ = x[R_USEIFACE-24]
 	_ = x[R_USEIFACEMETHOD-25]
 	_ = x[R_METHODOFF-26]
-	_ = x[R_POWER_TOC-27]
-	_ = x[R_GOTPCREL-28]
-	_ = x[R_JMPMIPS-29]
-	_ = x[R_DWARFSECREF-30]
-	_ = x[R_DWARFFILEREF-31]
-	_ = x[R_ARM64_TLS_LE-32]
-	_ = x[R_ARM64_TLS_IE-33]
-	_ = x[R_ARM64_GOTPCREL-34]
-	_ = x[R_ARM64_GOT-35]
-	_ = x[R_ARM64_PCREL-36]
-	_ = x[R_ARM64_LDST8-37]
-	_ = x[R_ARM64_LDST16-38]
-	_ = x[R_ARM64_LDST32-39]
-	_ = x[R_ARM64_LDST64-40]
-	_ = x[R_ARM64_LDST128-41]
-	_ = x[R_POWER_TLS_LE-42]
-	_ = x[R_POWER_TLS_IE-43]
-	_ = x[R_POWER_TLS-44]
-	_ = x[R_ADDRPOWER_DS-45]
-	_ = x[R_ADDRPOWER_GOT-46]
-	_ = x[R_ADDRPOWER_PCREL-47]
-	_ = x[R_ADDRPOWER_TOCREL-48]
-	_ = x[R_ADDRPOWER_TOCREL_DS-49]
-	_ = x[R_RISCV_PCREL_ITYPE-50]
-	_ = x[R_RISCV_PCREL_STYPE-51]
-	_ = x[R_RISCV_TLS_IE_ITYPE-52]
-	_ = x[R_RISCV_TLS_IE_STYPE-53]
-	_ = x[R_PCRELDBL-54]
-	_ = x[R_ADDRMIPSU-55]
-	_ = x[R_ADDRMIPSTLS-56]
-	_ = x[R_ADDRCUOFF-57]
-	_ = x[R_WASMIMPORT-58]
-	_ = x[R_XCOFFREF-59]
+	_ = x[R_KEEP-27]
+	_ = x[R_POWER_TOC-28]
+	_ = x[R_GOTPCREL-29]
+	_ = x[R_JMPMIPS-30]
+	_ = x[R_DWARFSECREF-31]
+	_ = x[R_DWARFFILEREF-32]
+	_ = x[R_ARM64_TLS_LE-33]
+	_ = x[R_ARM64_TLS_IE-34]
+	_ = x[R_ARM64_GOTPCREL-35]
+	_ = x[R_ARM64_GOT-36]
+	_ = x[R_ARM64_PCREL-37]
+	_ = x[R_ARM64_LDST8-38]
+	_ = x[R_ARM64_LDST16-39]
+	_ = x[R_ARM64_LDST32-40]
+	_ = x[R_ARM64_LDST64-41]
+	_ = x[R_ARM64_LDST128-42]
+	_ = x[R_POWER_TLS_LE-43]
+	_ = x[R_POWER_TLS_IE-44]
+	_ = x[R_POWER_TLS-45]
+	_ = x[R_ADDRPOWER_DS-46]
+	_ = x[R_ADDRPOWER_GOT-47]
+	_ = x[R_ADDRPOWER_PCREL-48]
+	_ = x[R_ADDRPOWER_TOCREL-49]
+	_ = x[R_ADDRPOWER_TOCREL_DS-50]
+	_ = x[R_RISCV_PCREL_ITYPE-51]
+	_ = x[R_RISCV_PCREL_STYPE-52]
+	_ = x[R_RISCV_TLS_IE_ITYPE-53]
+	_ = x[R_RISCV_TLS_IE_STYPE-54]
+	_ = x[R_PCRELDBL-55]
+	_ = x[R_ADDRMIPSU-56]
+	_ = x[R_ADDRMIPSTLS-57]
+	_ = x[R_ADDRCUOFF-58]
+	_ = x[R_WASMIMPORT-59]
+	_ = x[R_XCOFFREF-60]
 }
 
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
 
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 120, 127, 134, 142, 150, 158, 164, 170, 176, 186, 195, 205, 221, 232, 243, 253, 262, 275, 289, 303, 317, 333, 344, 357, 370, 384, 398, 412, 427, 441, 455, 466, 480, 495, 512, 530, 551, 570, 589, 609, 629, 639, 650, 663, 674, 686, 696}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 120, 127, 134, 142, 150, 158, 164, 170, 176, 186, 195, 205, 221, 232, 238, 249, 259, 268, 281, 295, 309, 323, 339, 350, 363, 376, 390, 404, 418, 433, 447, 461, 472, 486, 501, 518, 536, 557, 576, 595, 615, 635, 645, 656, 669, 680, 692, 702}
 
 func (i RelocType) String() string {
 	i -= 1
diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go
index f19bec5..dd21d22 100644
--- a/src/cmd/internal/objfile/goobj.go
+++ b/src/cmd/internal/objfile/goobj.go
@@ -168,7 +168,7 @@
 			code = 'T'
 		case objabi.SRODATA:
 			code = 'R'
-		case objabi.SDATA:
+		case objabi.SNOPTRDATA, objabi.SDATA:
 			code = 'D'
 		case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
 			code = 'B'
diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go
index e868736..a3e3976 100644
--- a/src/cmd/internal/sys/arch.go
+++ b/src/cmd/internal/sys/arch.go
@@ -40,6 +40,12 @@
 
 	// MinLC is the minimum length of an instruction code.
 	MinLC int
+
+	// Alignment is maximum alignment required by the architecture
+	// for any (compiler-generated) load or store instruction.
+	// Loads or stores smaller than Alignment must be naturally aligned.
+	// Loads or stores larger than Alignment need only be Alignment-aligned.
+	Alignment int8
 }
 
 // InFamily reports whether a is a member of any of the specified
@@ -60,6 +66,7 @@
 	PtrSize:   4,
 	RegSize:   4,
 	MinLC:     1,
+	Alignment: 1,
 }
 
 var ArchAMD64 = &Arch{
@@ -69,6 +76,7 @@
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     1,
+	Alignment: 1,
 }
 
 var ArchARM = &Arch{
@@ -78,6 +86,7 @@
 	PtrSize:   4,
 	RegSize:   4,
 	MinLC:     4,
+	Alignment: 4, // TODO: just for arm5?
 }
 
 var ArchARM64 = &Arch{
@@ -87,6 +96,7 @@
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
+	Alignment: 1,
 }
 
 var ArchMIPS = &Arch{
@@ -96,6 +106,7 @@
 	PtrSize:   4,
 	RegSize:   4,
 	MinLC:     4,
+	Alignment: 4,
 }
 
 var ArchMIPSLE = &Arch{
@@ -105,6 +116,7 @@
 	PtrSize:   4,
 	RegSize:   4,
 	MinLC:     4,
+	Alignment: 4,
 }
 
 var ArchMIPS64 = &Arch{
@@ -114,6 +126,7 @@
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
+	Alignment: 8,
 }
 
 var ArchMIPS64LE = &Arch{
@@ -123,6 +136,7 @@
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
+	Alignment: 8,
 }
 
 var ArchPPC64 = &Arch{
@@ -132,6 +146,7 @@
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
+	Alignment: 1,
 }
 
 var ArchPPC64LE = &Arch{
@@ -141,6 +156,7 @@
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
+	Alignment: 1,
 }
 
 var ArchRISCV64 = &Arch{
@@ -150,6 +166,7 @@
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
+	Alignment: 8, // riscv unaligned loads work, but are really slow (trap + simulated by OS)
 }
 
 var ArchS390X = &Arch{
@@ -159,6 +176,7 @@
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     2,
+	Alignment: 1,
 }
 
 var ArchWasm = &Arch{
@@ -168,6 +186,7 @@
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     1,
+	Alignment: 1,
 }
 
 var Archs = [...]*Arch{
diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go
index fa477b8..0d2bad9 100644
--- a/src/cmd/internal/sys/supported.go
+++ b/src/cmd/internal/sys/supported.go
@@ -74,7 +74,7 @@
 			"android/amd64", "android/arm", "android/arm64", "android/386",
 			"freebsd/amd64",
 			"darwin/amd64", "darwin/arm64",
-			"windows/amd64", "windows/386":
+			"windows/amd64", "windows/386", "windows/arm64":
 			return true
 		}
 		return false
diff --git a/src/cmd/link/cgo_test.go b/src/cmd/link/cgo_test.go
new file mode 100644
index 0000000..26ab802
--- /dev/null
+++ b/src/cmd/link/cgo_test.go
@@ -0,0 +1,141 @@
+// 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 (
+	"bytes"
+	"fmt"
+	"internal/testenv"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"testing"
+)
+
+// Issues 43830, 46295
+func TestCGOLTO(t *testing.T) {
+	testenv.MustHaveCGO(t)
+	testenv.MustHaveGoBuild(t)
+
+	t.Parallel()
+
+	for _, cc := range []string{"gcc", "clang"} {
+		for test := 0; test < 2; test++ {
+			t.Run(fmt.Sprintf("%s-%d", cc, test), func(t *testing.T) {
+				testCGOLTO(t, cc, test)
+			})
+		}
+	}
+}
+
+const test1_main = `
+package main
+
+/*
+extern int myadd(int, int);
+int c_add(int a, int b) {
+	return myadd(a, b);
+}
+*/
+import "C"
+
+func main() {
+	println(C.c_add(1, 2))
+}
+`
+
+const test1_add = `
+package main
+
+import "C"
+
+/* test */
+
+//export myadd
+func myadd(a C.int, b C.int) C.int {
+	return a + b
+}
+`
+
+const test2_main = `
+package main
+
+import "fmt"
+
+/*
+#include <stdio.h>
+
+void hello(void) {
+  printf("hello\n");
+}
+*/
+import "C"
+
+func main() {
+	hello := C.hello
+	fmt.Printf("%v\n", hello)
+}
+`
+
+func testCGOLTO(t *testing.T, cc string, test int) {
+	t.Parallel()
+
+	if _, err := exec.LookPath(cc); err != nil {
+		t.Skipf("no %s compiler", cc)
+	}
+
+	dir := t.TempDir()
+
+	writeTempFile := func(name, contents string) {
+		if err := os.WriteFile(filepath.Join(dir, name), []byte(contents), 0644); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	writeTempFile("go.mod", "module cgolto\n")
+
+	switch test {
+	case 0:
+		writeTempFile("main.go", test1_main)
+		writeTempFile("add.go", test1_add)
+	case 1:
+		writeTempFile("main.go", test2_main)
+	default:
+		t.Fatalf("bad case %d", test)
+	}
+
+	cmd := exec.Command(testenv.GoToolPath(t), "build")
+	cmd.Dir = dir
+	cmd.Env = append(os.Environ(),
+		"CC="+cc,
+		"CGO_CFLAGS=-flto",
+	)
+
+	t.Log("go build")
+	out, err := cmd.CombinedOutput()
+	t.Logf("%s", out)
+
+	if err != nil {
+		t.Logf("go build failed: %v", err)
+
+		// Error messages we've seen indicating that LTO is not supported.
+		// These errors come from GCC or clang, not Go.
+		var noLTO = []string{
+			`unrecognized command line option "-flto"`,
+			"unable to pass LLVM bit-code files to linker",
+			"file not recognized: File format not recognized",
+			"LTO support has not been enabled",
+			"linker command failed with exit code",
+			"gcc: can't load library",
+		}
+		for _, msg := range noLTO {
+			if bytes.Contains(out, []byte(msg)) {
+				t.Skipf("C compiler %v does not support LTO", cc)
+			}
+		}
+
+		t.Error("failed")
+	}
+}
diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go
index 0419613..3ca59bd 100644
--- a/src/cmd/link/dwarf_test.go
+++ b/src/cmd/link/dwarf_test.go
@@ -19,6 +19,36 @@
 	"testing"
 )
 
+// TestMain allows this test binary to run as a -toolexec wrapper for the 'go'
+// command. If LINK_TEST_TOOLEXEC is set, TestMain runs the binary as if it were
+// cmd/link, and otherwise runs the requested tool as a subprocess.
+//
+// This allows the test to verify the behavior of the current contents of the
+// cmd/link package even if the installed cmd/link binary is stale.
+func TestMain(m *testing.M) {
+	if os.Getenv("LINK_TEST_TOOLEXEC") == "" {
+		// Not running as a -toolexec wrapper. Just run the tests.
+		os.Exit(m.Run())
+	}
+
+	if strings.TrimSuffix(filepath.Base(os.Args[1]), ".exe") == "link" {
+		// Running as a -toolexec linker, and the tool is cmd/link.
+		// Substitute this test binary for the linker.
+		os.Args = os.Args[1:]
+		main()
+		os.Exit(0)
+	}
+
+	cmd := exec.Command(os.Args[1], os.Args[2:]...)
+	cmd.Stdin = os.Stdin
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	if err := cmd.Run(); err != nil {
+		os.Exit(1)
+	}
+	os.Exit(0)
+}
+
 func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) {
 	testenv.MustHaveCGO(t)
 	testenv.MustHaveGoBuild(t)
@@ -29,17 +59,6 @@
 
 	t.Parallel()
 
-	out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "cmd/link").CombinedOutput()
-	if err != nil {
-		t.Fatalf("go list: %v\n%s", err, out)
-	}
-	if string(out) != "false\n" {
-		if strings.HasPrefix(testenv.Builder(), "darwin-") {
-			t.Skipf("cmd/link is spuriously stale on Darwin builders - see #33598")
-		}
-		t.Fatalf("cmd/link is stale - run go install cmd/link")
-	}
-
 	for _, prog := range []string{"testprog", "testprogcgo"} {
 		prog := prog
 		expectDWARF := expectDWARF
@@ -48,11 +67,11 @@
 			if extld == "" {
 				extld = "gcc"
 			}
+			var err error
 			expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld)
 			if err != nil {
 				t.Fatal(err)
 			}
-
 		}
 
 		t.Run(prog, func(t *testing.T) {
@@ -62,15 +81,14 @@
 
 			exe := filepath.Join(tmpDir, prog+".exe")
 			dir := "../../runtime/testdata/" + prog
-			cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
+			cmd := exec.Command(testenv.GoToolPath(t), "build", "-toolexec", os.Args[0], "-o", exe)
 			if buildmode != "" {
 				cmd.Args = append(cmd.Args, "-buildmode", buildmode)
 			}
 			cmd.Args = append(cmd.Args, dir)
-			if env != nil {
-				cmd.Env = append(os.Environ(), env...)
-				cmd.Env = append(cmd.Env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459
-			}
+			cmd.Env = append(os.Environ(), env...)
+			cmd.Env = append(cmd.Env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459
+			cmd.Env = append(cmd.Env, "LINK_TEST_TOOLEXEC=1")
 			out, err := cmd.CombinedOutput()
 			if err != nil {
 				t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go
index 22f53a4..23915f9 100644
--- a/src/cmd/link/internal/ld/ar.go
+++ b/src/cmd/link/internal/ld/ar.go
@@ -124,6 +124,10 @@
 
 			libgcc := sym.Library{Pkg: "libgcc"}
 			h := ldobj(ctxt, f, &libgcc, l, pname, name)
+			if h.ld == nil {
+				Errorf(nil, "%s unrecognized object file at offset %d", name, off)
+				continue
+			}
 			f.MustSeek(h.off, 0)
 			h.ld(ctxt, f, h.pkg, h.length, h.pn)
 		}
diff --git a/src/cmd/link/internal/ld/asmb.go b/src/cmd/link/internal/ld/asmb.go
index 3754669..d6ecb28 100644
--- a/src/cmd/link/internal/ld/asmb.go
+++ b/src/cmd/link/internal/ld/asmb.go
@@ -167,7 +167,10 @@
 		}
 	}
 	filesz := ctxt.Out.Offset() + sz
-	ctxt.Out.Mmap(uint64(filesz))
+	err := ctxt.Out.Mmap(uint64(filesz))
+	if err != nil {
+		Exitf("mapping output file failed: %v", err)
+	}
 }
 
 // relocSectFn wraps the function writing relocations of a section
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index ae0d752..20f1d0b 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -241,6 +241,10 @@
 		return true, "dynamically linking with a shared library"
 	}
 
+	if unknownObjFormat {
+		return true, "some input objects have an unrecognized file format"
+	}
+
 	return false, ""
 }
 
@@ -248,7 +252,7 @@
 //
 // It is called after flags are processed and inputs are processed,
 // so the ctxt.LinkMode variable has an initial value from the -linkmode
-// flag and the iscgo externalobj variables are set.
+// flag and the iscgo, externalobj, and unknownObjFormat variables are set.
 func determineLinkMode(ctxt *Link) {
 	extNeeded, extReason := mustLinkExternal(ctxt)
 	via := ""
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 6659e95..70fbb9d 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -340,6 +340,7 @@
 			if weak && !ldr.AttrReachable(rs) {
 				// Redirect it to runtime.unreachableMethod, which will throw if called.
 				rs = syms.unreachableMethod
+				rs = ldr.ResolveABIAlias(rs)
 			}
 			if target.IsExternal() {
 				nExtReloc++
@@ -623,6 +624,7 @@
 		rs := ldr.ResolveABIAlias(r.Sym())
 		if r.Weak() && !ldr.AttrReachable(rs) {
 			rs = ctxt.ArchSyms.unreachableMethod
+			rs = ldr.ResolveABIAlias(rs)
 		}
 		rs, off := FoldSubSymbolOffset(ldr, rs)
 		rr.Xadd = r.Add() + off
@@ -1548,7 +1550,7 @@
 
 	if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
 		// These symbols must have the same alignment as their section.
-		// Otherwize, ld might change the layout of Go sections.
+		// Otherwise, ld might change the layout of Go sections.
 		ldr.SetSymAlign(ldr.Lookup("runtime.data", 0), state.dataMaxAlign[sym.SDATA])
 		ldr.SetSymAlign(ldr.Lookup("runtime.bss", 0), state.dataMaxAlign[sym.SBSS])
 	}
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index 1ed5598..416e5da 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -65,26 +65,26 @@
 			}
 		}
 		names = append(names, *flagEntrySymbol)
-		// runtime.unreachableMethod is a function that will throw if called.
-		// We redirect unreachable methods to it.
-		names = append(names, "runtime.unreachableMethod")
-		if !d.ctxt.linkShared && d.ctxt.BuildMode != BuildModePlugin {
-			// runtime.buildVersion and runtime.modinfo are referenced in .go.buildinfo section
-			// (see function buildinfo in data.go). They should normally be reachable from the
-			// runtime. Just make it explicit, in case.
-			names = append(names, "runtime.buildVersion", "runtime.modinfo")
-		}
-		if d.ctxt.BuildMode == BuildModePlugin {
-			names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
+	}
+	// runtime.unreachableMethod is a function that will throw if called.
+	// We redirect unreachable methods to it.
+	names = append(names, "runtime.unreachableMethod")
+	if !d.ctxt.linkShared && d.ctxt.BuildMode != BuildModePlugin {
+		// runtime.buildVersion and runtime.modinfo are referenced in .go.buildinfo section
+		// (see function buildinfo in data.go). They should normally be reachable from the
+		// runtime. Just make it explicit, in case.
+		names = append(names, "runtime.buildVersion", "runtime.modinfo")
+	}
+	if d.ctxt.BuildMode == BuildModePlugin {
+		names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
 
-			// We don't keep the go.plugin.exports symbol,
-			// but we do keep the symbols it refers to.
-			exportsIdx := d.ldr.Lookup("go.plugin.exports", 0)
-			if exportsIdx != 0 {
-				relocs := d.ldr.Relocs(exportsIdx)
-				for i := 0; i < relocs.Count(); i++ {
-					d.mark(relocs.At(i).Sym(), 0)
-				}
+		// We don't keep the go.plugin.exports symbol,
+		// but we do keep the symbols it refers to.
+		exportsIdx := d.ldr.Lookup("go.plugin.exports", 0)
+		if exportsIdx != 0 {
+			relocs := d.ldr.Relocs(exportsIdx)
+			for i := 0; i < relocs.Count(); i++ {
+				d.mark(relocs.At(i).Sym(), 0)
 			}
 		}
 	}
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index fc179fc..629bdcf 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -10,17 +10,18 @@
 	"cmd/link/internal/loader"
 	"cmd/link/internal/sym"
 	"debug/elf"
+	"encoding/binary"
 	"log"
 )
 
 // Decoding the type.* symbols.	 This has to be in sync with
 // ../../runtime/type.go, or more specifically, with what
-// cmd/compile/internal/gc/reflect.go stuffs in these.
+// cmd/compile/internal/reflectdata/reflect.go stuffs in these.
 
 // tflag is documented in reflect/type.go.
 //
 // tflag values must be kept in sync with copies in:
-//	cmd/compile/internal/gc/reflect.go
+//	cmd/compile/internal/reflectdata/reflect.go
 //	cmd/link/internal/ld/decodesym.go
 //	reflect/type.go
 //	runtime/type.go
@@ -126,8 +127,8 @@
 	}
 
 	data := ldr.Data(r)
-	namelen := int(uint16(data[1])<<8 | uint16(data[2]))
-	return string(data[3 : 3+namelen])
+	nameLen, nameLenLen := binary.Uvarint(data[1:])
+	return string(data[1+nameLenLen : 1+nameLenLen+int(nameLen)])
 }
 
 func decodetypeFuncInType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go
index 5cc4800..2f59c2f 100644
--- a/src/cmd/link/internal/ld/dwarf_test.go
+++ b/src/cmd/link/internal/ld/dwarf_test.go
@@ -1660,16 +1660,16 @@
 package main
 
 //go:noinline
-func ABC(p1, p2, p3 int, f1, f2, f3 float32, b1 [1024]int) (r1 int, r2 int, r3 [1024]int, r4 byte) {
-	b1[0] = 6
-	r1, r2, r3, r4 = p3, p2, b1, 'a'
+func ABC(c1, c2, c3 int, d1, d2, d3, d4 string, f1, f2, f3 float32, g1 [1024]int) (r1 int, r2 int, r3 [1024]int, r4 byte, r5 string, r6 float32) {
+	g1[0] = 6
+	r1, r2, r3, r4, r5, r6 = c3, c2+c1, g1, 'a', d1+d2+d3+d4, f1+f2+f3
 	return
 }
 
 func main() {
 	a := [1024]int{}
-	v1, v2, v3, v4 := ABC(1, 2, 3, 1.0, 2.0, 1.0, a)
-	println(v1, v2, v3[0], v4)
+	v1, v2, v3, v4, v5, v6 := ABC(1, 2, 3, "a", "b", "c", "d", 1.0, 2.0, 1.0, a)
+	println(v1, v2, v3[0], v4, v5, v6)
 }
 `
 	dir := t.TempDir()
@@ -1708,18 +1708,20 @@
 	// OK to have it missing for input parameters, but for the moment
 	// we verify that the attr is present but set to false.
 
-	// Values in this map:
+	// Values in this map are of the form <order>:<varparam>
+	// where order is the order within the child DIE list of the param,
+	// and <varparam> is an integer:
 	//
-	//   0: <no param of this name>
 	//  -1: varparm attr not found
 	//   1: varparm found with value false
 	//   2: varparm found with value true
 	//
-	foundParams := make(map[string]int)
+	foundParams := make(map[string]string)
 
 	// Walk ABCs's children looking for params.
 	abcIdx := ex.idxFromOffset(abcdie.Offset)
 	childDies := ex.Children(abcIdx)
+	idx := 0
 	for _, child := range childDies {
 		if child.Tag == dwarf.TagFormalParameter {
 			st := -1
@@ -1731,7 +1733,8 @@
 				}
 			}
 			if name, ok := child.Val(dwarf.AttrName).(string); ok {
-				foundParams[name] = st
+				foundParams[name] = fmt.Sprintf("%d:%d", idx, st)
+				idx++
 			}
 		}
 	}
@@ -1739,13 +1742,14 @@
 	// Digest the result.
 	found := make([]string, 0, len(foundParams))
 	for k, v := range foundParams {
-		found = append(found, fmt.Sprintf("%s:%d", k, v))
+		found = append(found, fmt.Sprintf("%s:%s", k, v))
 	}
 	sort.Strings(found)
 
-	// Make sure we see all of the expected params, that they have
-	// the varparam attr, and the varparm is set for the returns.
-	expected := "[b1:1 f1:1 f2:1 f3:1 p1:1 p2:1 p3:1 r1:2 r2:2 r3:2 r4:2]"
+	// Make sure we see all of the expected params in the proper
+	// order, that they have the varparam attr, and the varparm is set
+	// for the returns.
+	expected := "[c1:0:1 c2:1:1 c3:2:1 d1:3:1 d2:4:1 d3:5:1 d4:6:1 f1:7:1 f2:8:1 f3:9:1 g1:10:1 r1:11:2 r2:12:2 r3:13:2 r4:14:2 r5:15:2 r6:16:2]"
 	if fmt.Sprintf("%+v", found) != expected {
 		t.Errorf("param check failed, wanted %s got %s\n",
 			expected, found)
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 87d88dd..8101163 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -950,6 +950,11 @@
 	}
 
 	s = ldr.CreateSymForUpdate(".dynamic", 0)
+	if ctxt.BuildMode == BuildModePIE {
+		// https://github.com/bminor/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/elf/elf.h#L986
+		const DTFLAGS_1_PIE = 0x08000000
+		Elfwritedynent(ctxt.Arch, s, elf.DT_FLAGS_1, uint64(DTFLAGS_1_PIE))
+	}
 	elfverneed = nfile
 	if elfverneed != 0 {
 		elfWriteDynEntSym(ctxt, s, elf.DT_VERNEED, gnuVersionR.Sym())
@@ -1171,7 +1176,7 @@
 		}
 	}
 
-	eaddr := int32(sect.Vaddr + sect.Length)
+	eaddr := sect.Vaddr + sect.Length
 	for _, s := range syms {
 		if !ldr.AttrReachable(s) {
 			continue
diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go
index ca76463..3702a4d 100644
--- a/src/cmd/link/internal/ld/ld_test.go
+++ b/src/cmd/link/internal/ld/ld_test.go
@@ -174,6 +174,8 @@
 		t.Skip("skipping windows amd64/386 only test")
 	}
 
+	testenv.MustHaveCGO(t)
+
 	t.Run("aslr", func(t *testing.T) {
 		testWindowsBuildmodeCSharedASLR(t, true)
 	})
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index eb85c88..d7e4086 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -343,10 +343,16 @@
 const pkgdef = "__.PKGDEF"
 
 var (
-	// Set if we see an object compiled by the host compiler that is not
-	// from a package that is known to support internal linking mode.
+	// externalobj is set to true if we see an object compiled by
+	// the host compiler that is not from a package that is known
+	// to support internal linking mode.
 	externalobj = false
-	theline     string
+
+	// unknownObjFormat is set to true if we see an object whose
+	// format we don't recognize.
+	unknownObjFormat = false
+
+	theline string
 )
 
 func Lflag(ctxt *Link, arg string) {
@@ -1066,6 +1072,10 @@
 		}
 
 		f.MustSeek(h.off, 0)
+		if h.ld == nil {
+			Errorf(nil, "%s: unrecognized object file format", h.pn)
+			continue
+		}
 		h.ld(ctxt, f, h.pkg, h.length, h.pn)
 		f.Close()
 	}
@@ -1856,6 +1866,14 @@
 		return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
 	}
 
+	if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
+		// An unrecognized object is just passed to the external linker.
+		// If we try to read symbols from this object, we will
+		// report an error at that time.
+		unknownObjFormat = true
+		return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
+	}
+
 	/* check the header */
 	line, err := f.ReadString('\n')
 	if err != nil {
@@ -1875,7 +1893,7 @@
 			return nil
 		}
 
-		Errorf(nil, "%s: not an object file: @%d %02x%02x%02x%02x", pn, start, c1, c2, c3, c4)
+		Errorf(nil, "%s: not an object file: @%d %q", pn, start, line)
 		return nil
 	}
 
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index 642113c..45a3971 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -1194,7 +1194,7 @@
 		}
 	}
 
-	eaddr := int32(sect.Vaddr + sect.Length)
+	eaddr := sect.Vaddr + sect.Length
 	for _, s := range syms {
 		if !ldr.AttrReachable(s) {
 			continue
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index adb39d0..cba0e3d 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -334,7 +334,7 @@
 		// Don't mmap if we're building for Wasm. Wasm file
 		// layout is very different so filesize is meaningless.
 		if err := ctxt.Out.Mmap(filesize); err != nil {
-			panic(err)
+			Exitf("mapping output file failed: %v", err)
 		}
 	}
 	// asmb will redirect symbols to the output file mmap, and relocations
diff --git a/src/cmd/link/internal/ld/outbuf.go b/src/cmd/link/internal/ld/outbuf.go
index 530836e..9d5e885 100644
--- a/src/cmd/link/internal/ld/outbuf.go
+++ b/src/cmd/link/internal/ld/outbuf.go
@@ -160,7 +160,7 @@
 	total := uint64(bufLen + heapLen)
 	if heapLen != 0 {
 		if err := out.Mmap(total); err != nil { // Mmap will copy out.heap over to out.buf
-			panic(err)
+			Exitf("mapping output file failed: %v", err)
 		}
 	}
 	return true
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 3540c07..8eb4231 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -475,7 +475,7 @@
 	off := f.stringTable.add(name)
 	h := f.addSection(name, size, size)
 	h.shortName = fmt.Sprintf("/%d", off)
-	h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA
+	h.characteristics = IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA
 	return h
 }
 
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 1b71a66..9d5319c 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -459,6 +459,15 @@
 		if l.flags&FlagStrictDups != 0 {
 			l.checkdup(name, r, li, oldi)
 		}
+		// Fix for issue #47185 -- given two dupok symbols with
+		// different sizes, favor symbol with larger size. See
+		// also issue #46653.
+		szdup := l.SymSize(oldi)
+		sz := int64(r.Sym(li).Siz())
+		if szdup < sz {
+			// new symbol overwrites old symbol.
+			l.objSyms[oldi] = objSym{r.objidx, li}
+		}
 		return oldi
 	}
 	oldr, oldli := l.toLocal(oldi)
@@ -699,12 +708,18 @@
 	p := r.Data(li)
 	rdup, ldup := l.toLocal(dup)
 	pdup := rdup.Data(ldup)
-	if bytes.Equal(p, pdup) {
-		return
-	}
 	reason := "same length but different contents"
 	if len(p) != len(pdup) {
 		reason = fmt.Sprintf("new length %d != old length %d", len(p), len(pdup))
+	} else if bytes.Equal(p, pdup) {
+		// For BSS symbols, we need to check size as well, see issue 46653.
+		szdup := l.SymSize(dup)
+		sz := int64(r.Sym(li).Siz())
+		if szdup == sz {
+			return
+		}
+		reason = fmt.Sprintf("different sizes: new size %d != old size %d",
+			sz, szdup)
 	}
 	fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason)
 
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index 8805ff1..7230054 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -470,10 +470,30 @@
 	JMP	0(PC)
 `
 
+const testStrictDupAsmSrc3 = `
+#include "textflag.h"
+GLOBL ·rcon(SB), RODATA|DUPOK, $64
+`
+
+const testStrictDupAsmSrc4 = `
+#include "textflag.h"
+GLOBL ·rcon(SB), RODATA|DUPOK, $32
+`
+
 func TestStrictDup(t *testing.T) {
 	// Check that -strictdups flag works.
 	testenv.MustHaveGoBuild(t)
 
+	asmfiles := []struct {
+		fname   string
+		payload string
+	}{
+		{"a", testStrictDupAsmSrc1},
+		{"b", testStrictDupAsmSrc2},
+		{"c", testStrictDupAsmSrc3},
+		{"d", testStrictDupAsmSrc4},
+	}
+
 	t.Parallel()
 
 	tmpdir := t.TempDir()
@@ -483,15 +503,12 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	src = filepath.Join(tmpdir, "a.s")
-	err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc1), 0666)
-	if err != nil {
-		t.Fatal(err)
-	}
-	src = filepath.Join(tmpdir, "b.s")
-	err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc2), 0666)
-	if err != nil {
-		t.Fatal(err)
+	for _, af := range asmfiles {
+		src = filepath.Join(tmpdir, af.fname+".s")
+		err = ioutil.WriteFile(src, []byte(af.payload), 0666)
+		if err != nil {
+			t.Fatal(err)
+		}
 	}
 	src = filepath.Join(tmpdir, "go.mod")
 	err = ioutil.WriteFile(src, []byte("module teststrictdup\n"), 0666)
@@ -503,7 +520,7 @@
 	cmd.Dir = tmpdir
 	out, err := cmd.CombinedOutput()
 	if err != nil {
-		t.Errorf("linking with -strictdups=1 failed: %v", err)
+		t.Errorf("linking with -strictdups=1 failed: %v\n%s", err, string(out))
 	}
 	if !bytes.Contains(out, []byte("mismatched payload")) {
 		t.Errorf("unexpected output:\n%s", out)
@@ -515,7 +532,11 @@
 	if err == nil {
 		t.Errorf("linking with -strictdups=2 did not fail")
 	}
-	if !bytes.Contains(out, []byte("mismatched payload")) {
+	// NB: on amd64 we get the 'new length' error, on arm64 the 'different
+	// contents' error.
+	if !(bytes.Contains(out, []byte("mismatched payload: new length")) ||
+		bytes.Contains(out, []byte("mismatched payload: same length but different contents"))) ||
+		!bytes.Contains(out, []byte("mismatched payload: different sizes")) {
 		t.Errorf("unexpected output:\n%s", out)
 	}
 }
@@ -698,7 +719,7 @@
 	if err != nil {
 		t.Errorf("executable failed to run: %v\n%s", err, out)
 	}
-	if string(out) != "hello\n" {
+	if string(out) != "hello\n" && string(out) != "hello\r\n" {
 		t.Errorf("unexpected output:\n%s", out)
 	}
 
@@ -717,7 +738,7 @@
 	if err != nil {
 		t.Errorf("executable failed to run: %v\n%s", err, out)
 	}
-	if string(out) != "hello\n" {
+	if string(out) != "hello\n" && string(out) != "hello\r\n" {
 		t.Errorf("unexpected output:\n%s", out)
 	}
 }
diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go
index 11f91cb..e72c765 100644
--- a/src/cmd/pprof/pprof.go
+++ b/src/cmd/pprof/pprof.go
@@ -232,9 +232,9 @@
 	return f.name
 }
 
-func (f *file) Base() uint64 {
-	// No support for shared libraries.
-	return 0
+func (f *file) ObjAddr(addr uint64) (uint64, error) {
+	// 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 0000000..11e251b
--- /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 0000000..5b68287
--- /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/cmd/vendor/github.com/google/pprof/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/driver/driver.go
index e65bc2f..fc05f91 100644
--- a/src/cmd/vendor/github.com/google/pprof/driver/driver.go
+++ b/src/cmd/vendor/github.com/google/pprof/driver/driver.go
@@ -159,8 +159,8 @@
 	// Name returns the underlying file name, if available.
 	Name() string
 
-	// Base returns the base address to use when looking up symbols in the file.
-	Base() uint64
+	// ObjAddr returns the objdump address corresponding to a runtime address.
+	ObjAddr(addr uint64) (uint64, error)
 
 	// BuildID returns the GNU build ID of the file, or an empty string.
 	BuildID() string
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
index 576a6ee..5ed8a1f 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
@@ -42,7 +42,12 @@
 	rep *binrep
 }
 
-var objdumpLLVMVerRE = regexp.MustCompile(`LLVM version (?:(\d*)\.(\d*)\.(\d*)|.*(trunk).*)`)
+var (
+	objdumpLLVMVerRE = regexp.MustCompile(`LLVM version (?:(\d*)\.(\d*)\.(\d*)|.*(trunk).*)`)
+
+	// Defined for testing
+	elfOpen = elf.Open
+)
 
 // binrep is an immutable representation for Binutils.  It is atomically
 // replaced on every mutation to provide thread-safe access.
@@ -421,14 +426,23 @@
 }
 
 func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
-	ef, err := elf.Open(name)
+	ef, err := elfOpen(name)
 	if err != nil {
 		return nil, fmt.Errorf("error parsing %s: %v", name, err)
 	}
 	defer ef.Close()
 
-	var stextOffset *uint64
-	var pageAligned = func(addr uint64) bool { return addr%4096 == 0 }
+	buildID := ""
+	if f, err := os.Open(name); err == nil {
+		if id, err := elfexec.GetBuildID(f); err == nil {
+			buildID = fmt.Sprintf("%x", id)
+		}
+	}
+
+	var (
+		stextOffset *uint64
+		pageAligned = func(addr uint64) bool { return addr%4096 == 0 }
+	)
 	if strings.Contains(name, "vmlinux") || !pageAligned(start) || !pageAligned(limit) || !pageAligned(offset) {
 		// Reading all Symbols is expensive, and we only rarely need it so
 		// we don't want to do it every time. But if _stext happens to be
@@ -450,38 +464,29 @@
 		}
 	}
 
-	var ph *elf.ProgHeader
-	// For user space executables, find the actual program segment that is
-	// associated with the given mapping. Skip this search if limit <= start.
-	// We cannot use just a check on the start address of the mapping to tell if
-	// it's a kernel / .ko module mapping, because with quipper address remapping
-	// enabled, the address would be in the lower half of the address space.
-	if stextOffset == nil && start < limit && limit < (uint64(1)<<63) {
-		ph, err = elfexec.FindProgHeaderForMapping(ef, offset, limit-start)
-		if err != nil {
-			return nil, fmt.Errorf("failed to find program header for file %q, mapping pgoff %x, memsz=%x: %v", name, offset, limit-start, err)
-		}
-	} else {
-		// For the kernel, find the program segment that includes the .text section.
-		ph = elfexec.FindTextProgHeader(ef)
-	}
-
-	base, err := elfexec.GetBase(&ef.FileHeader, ph, stextOffset, start, limit, offset)
-	if err != nil {
+	// Check that we can compute a base for the binary. This may not be the
+	// correct base value, so we don't save it. We delay computing the actual base
+	// value until we have a sample address for this mapping, so that we can
+	// correctly identify the associated program segment that is needed to compute
+	// the base.
+	if _, err := elfexec.GetBase(&ef.FileHeader, elfexec.FindTextProgHeader(ef), stextOffset, start, limit, offset); err != nil {
 		return nil, fmt.Errorf("could not identify base for %s: %v", name, err)
 	}
 
-	buildID := ""
-	if f, err := os.Open(name); err == nil {
-		if id, err := elfexec.GetBuildID(f); err == nil {
-			buildID = fmt.Sprintf("%x", id)
-		}
-	}
-	isData := ph != nil && ph.Flags&elf.PF_X == 0
 	if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) {
-		return &fileNM{file: file{b, name, base, buildID, isData}}, nil
+		return &fileNM{file: file{
+			b:       b,
+			name:    name,
+			buildID: buildID,
+			m:       &elfMapping{start: start, limit: limit, offset: offset, stextOffset: stextOffset},
+		}}, nil
 	}
-	return &fileAddr2Line{file: file{b, name, base, buildID, isData}}, nil
+	return &fileAddr2Line{file: file{
+		b:       b,
+		name:    name,
+		buildID: buildID,
+		m:       &elfMapping{start: start, limit: limit, offset: offset, stextOffset: stextOffset},
+	}}, nil
 }
 
 func (b *binrep) openPE(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
@@ -511,21 +516,119 @@
 	return &fileAddr2Line{file: file{b: b, name: name, base: base}}, nil
 }
 
+// elfMapping stores the parameters of a runtime mapping that are needed to
+// identify the ELF segment associated with a mapping.
+type elfMapping struct {
+	// Runtime mapping parameters.
+	start, limit, offset uint64
+	// Offset of _stext symbol. Only defined for kernel images, nil otherwise.
+	stextOffset *uint64
+}
+
 // file implements the binutils.ObjFile interface.
 type file struct {
 	b       *binrep
 	name    string
-	base    uint64
 	buildID string
-	isData  bool
+
+	baseOnce sync.Once // Ensures the base, baseErr and isData are computed once.
+	base     uint64
+	baseErr  error // Any eventual error while computing the base.
+	isData   bool
+	// Mapping information. Relevant only for ELF files, nil otherwise.
+	m *elfMapping
+}
+
+// computeBase computes the relocation base for the given binary file only if
+// the elfMapping field is set. It populates the base and isData fields and
+// returns an error.
+func (f *file) computeBase(addr uint64) error {
+	if f == nil || f.m == nil {
+		return nil
+	}
+	if addr < f.m.start || addr >= f.m.limit {
+		return fmt.Errorf("specified address %x is outside the mapping range [%x, %x] for file %q", addr, f.m.start, f.m.limit, f.name)
+	}
+	ef, err := elfOpen(f.name)
+	if err != nil {
+		return fmt.Errorf("error parsing %s: %v", f.name, err)
+	}
+	defer ef.Close()
+
+	var ph *elf.ProgHeader
+	// For user space executables, find the actual program segment that is
+	// associated with the given mapping. Skip this search if limit <= start.
+	// We cannot use just a check on the start address of the mapping to tell if
+	// it's a kernel / .ko module mapping, because with quipper address remapping
+	// enabled, the address would be in the lower half of the address space.
+	if f.m.stextOffset == nil && f.m.start < f.m.limit && f.m.limit < (uint64(1)<<63) {
+		// Get all program headers associated with the mapping.
+		headers, hasLoadables := elfexec.ProgramHeadersForMapping(ef, f.m.offset, f.m.limit-f.m.start)
+
+		// Some ELF files don't contain any loadable program segments, e.g. .ko
+		// kernel modules. It's not an error to have no header in such cases.
+		if hasLoadables {
+			ph, err = matchUniqueHeader(headers, addr-f.m.start+f.m.offset)
+			if err != nil {
+				return fmt.Errorf("failed to find program header for file %q, ELF mapping %#v, address %x: %v", f.name, *f.m, addr, err)
+			}
+		}
+	} else {
+		// For the kernel, find the program segment that includes the .text section.
+		ph = elfexec.FindTextProgHeader(ef)
+	}
+
+	base, err := elfexec.GetBase(&ef.FileHeader, ph, f.m.stextOffset, f.m.start, f.m.limit, f.m.offset)
+	if err != nil {
+		return err
+	}
+	f.base = base
+	f.isData = ph != nil && ph.Flags&elf.PF_X == 0
+	return nil
+}
+
+// matchUniqueHeader attempts to identify a unique header from the given list,
+// using the given file offset to disambiguate between multiple segments. It
+// returns an error if the header list is empty or if it cannot identify a
+// unique header.
+func matchUniqueHeader(headers []*elf.ProgHeader, fileOffset uint64) (*elf.ProgHeader, error) {
+	if len(headers) == 0 {
+		return nil, errors.New("no program header matches mapping info")
+	}
+	if len(headers) == 1 {
+		// Don't use the file offset if we already have a single header.
+		return headers[0], nil
+	}
+	// We have multiple input segments. Attempt to identify a unique one
+	// based on the given file offset.
+	var ph *elf.ProgHeader
+	for _, h := range headers {
+		if fileOffset >= h.Off && fileOffset < h.Off+h.Memsz {
+			if ph != nil {
+				// Assuming no other bugs, this can only happen if we have two or
+				// more small program segments that fit on the same page, and a
+				// segment other than the last one includes uninitialized data.
+				return nil, fmt.Errorf("found second program header (%#v) that matches file offset %x, first program header is %#v. Does first program segment contain uninitialized data?", *h, fileOffset, *ph)
+			}
+			ph = h
+		}
+	}
+	if ph == nil {
+		return nil, fmt.Errorf("no program header matches file offset %x", fileOffset)
+	}
+	return ph, nil
 }
 
 func (f *file) Name() string {
 	return f.name
 }
 
-func (f *file) Base() uint64 {
-	return f.base
+func (f *file) ObjAddr(addr uint64) (uint64, error) {
+	f.baseOnce.Do(func() { f.baseErr = f.computeBase(addr) })
+	if f.baseErr != nil {
+		return 0, f.baseErr
+	}
+	return addr - f.base, nil
 }
 
 func (f *file) BuildID() string {
@@ -533,7 +636,11 @@
 }
 
 func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) {
-	return []plugin.Frame{}, nil
+	f.baseOnce.Do(func() { f.baseErr = f.computeBase(addr) })
+	if f.baseErr != nil {
+		return nil, f.baseErr
+	}
+	return nil, nil
 }
 
 func (f *file) Close() error {
@@ -560,6 +667,10 @@
 }
 
 func (f *fileNM) SourceLine(addr uint64) ([]plugin.Frame, error) {
+	f.baseOnce.Do(func() { f.baseErr = f.computeBase(addr) })
+	if f.baseErr != nil {
+		return nil, f.baseErr
+	}
 	if f.addr2linernm == nil {
 		addr2liner, err := newAddr2LinerNM(f.b.nm, f.name, f.base)
 		if err != nil {
@@ -579,9 +690,14 @@
 	file
 	addr2liner     *addr2Liner
 	llvmSymbolizer *llvmSymbolizer
+	isData         bool
 }
 
 func (f *fileAddr2Line) SourceLine(addr uint64) ([]plugin.Frame, error) {
+	f.baseOnce.Do(func() { f.baseErr = f.computeBase(addr) })
+	if f.baseErr != nil {
+		return nil, f.baseErr
+	}
 	f.once.Do(f.init)
 	if f.llvmSymbolizer != nil {
 		return f.llvmSymbolizer.addrInfo(addr)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go
index 3b3c6ee..2638b2d 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go
@@ -284,83 +284,71 @@
 	return nil
 }
 
-// FindProgHeaderForMapping returns the loadable program segment header that is
-// fully contained in the runtime mapping with file offset pgoff and memory size
-// memsz, or an error if the segment cannot be determined. The function returns
-// a nil program header and no error if the ELF binary has no loadable segments.
-func FindProgHeaderForMapping(f *elf.File, pgoff, memsz uint64) (*elf.ProgHeader, error) {
+// ProgramHeadersForMapping returns the loadable program segment headers that
+// are fully contained in the runtime mapping with file offset pgoff and memory
+// size memsz, and if the binary includes any loadable segments.
+func ProgramHeadersForMapping(f *elf.File, pgoff, memsz uint64) ([]*elf.ProgHeader, bool) {
+	const (
+		// pageSize defines the virtual memory page size used by the loader. This
+		// value is dependent on the memory management unit of the CPU. The page
+		// size is 4KB virtually on all the architectures that we care about, so we
+		// define this metric as a constant. If we encounter architectures where
+		// page sie is not 4KB, we must try to guess the page size on the system
+		// where the profile was collected, possibly using the architecture
+		// specified in the ELF file header.
+		pageSize       = 4096
+		pageOffsetMask = pageSize - 1
+		pageMask       = ^uint64(pageOffsetMask)
+	)
 	var headers []*elf.ProgHeader
-	loadables := 0
+	hasLoadables := false
 	for _, p := range f.Progs {
+		// The segment must be fully included in the mapping.
 		if p.Type == elf.PT_LOAD && pgoff <= p.Off && p.Off+p.Memsz <= pgoff+memsz {
-			headers = append(headers, &p.ProgHeader)
+			alignedOffset := uint64(0)
+			if p.Off > (p.Vaddr & pageOffsetMask) {
+				alignedOffset = p.Off - (p.Vaddr & pageOffsetMask)
+			}
+			if alignedOffset <= pgoff {
+				headers = append(headers, &p.ProgHeader)
+			}
 		}
 		if p.Type == elf.PT_LOAD {
-			loadables++
+			hasLoadables = true
 		}
 	}
-	if len(headers) == 1 {
-		return headers[0], nil
-	}
-	// Some ELF files don't contain any program segments, e.g. .ko loadable kernel
-	// modules. Don't return an error in such cases.
-	if loadables == 0 {
-		return nil, nil
-	}
-	if len(headers) == 0 {
-		return nil, fmt.Errorf("no program header matches file offset %x and memory size %x", pgoff, memsz)
+	if len(headers) < 2 {
+		return headers, hasLoadables
 	}
 
-	// Segments are mapped page aligned. In some cases, segments may be smaller
-	// than a page, which causes the next segment to start at a file offset that
-	// is logically on the same page if we were to align file offsets by page.
-	// Example:
-	//  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
-	//                 0x00000000000006fc 0x00000000000006fc  R E    0x200000
-	//  LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
-	//                 0x0000000000000230 0x0000000000000238  RW     0x200000
-	//
-	// In this case, perf records the following mappings for this executable:
-	// 0 0 [0xc0]: PERF_RECORD_MMAP2 87867/87867: [0x400000(0x1000) @ 0 00:3c 512041 0]: r-xp exename
-	// 0 0 [0xc0]: PERF_RECORD_MMAP2 87867/87867: [0x600000(0x2000) @ 0 00:3c 512041 0]: rw-p exename
-	//
-	// Both mappings have file offset 0. The first mapping is one page length and
-	// it can include only the first loadable segment. Due to page alignment, the
-	// second mapping starts also at file offset 0, and it spans two pages. It can
-	// include both the first and the second loadable segments. We must return the
-	// correct program header to compute the correct base offset.
-	//
-	// We cannot use the mapping protections to distinguish between segments,
-	// because protections are not passed through to this function.
-	// We cannot use the start address to differentiate between segments, because
-	// with ASLR, the mapping start address can be any value.
-	//
-	// We use a heuristic to compute the minimum mapping size required for a
-	// segment, assuming mappings are 4k page aligned, and return the segment that
-	// matches the given mapping size.
-	const pageSize = 4096
-
+	// If we have more than one matching segments, try a strict check on the
+	// segment memory size. We use a heuristic to compute the minimum mapping size
+	// required for a segment, assuming mappings are page aligned.
 	// The memory size based heuristic makes sense only if the mapping size is a
-	// multiple of 4k page size.
+	// multiple of page size.
 	if memsz%pageSize != 0 {
-		return nil, fmt.Errorf("mapping size = %x and %d segments match the passed in mapping", memsz, len(headers))
+		return headers, hasLoadables
 	}
 
-	// Return an error if no segment, or multiple segments match the size, so we can debug.
+	// Return all found headers if we cannot narrow the selection to a single
+	// program segment.
 	var ph *elf.ProgHeader
-	pageMask := ^uint64(pageSize - 1)
 	for _, h := range headers {
 		wantSize := (h.Vaddr+h.Memsz+pageSize-1)&pageMask - (h.Vaddr & pageMask)
 		if wantSize != memsz {
 			continue
 		}
 		if ph != nil {
-			return nil, fmt.Errorf("found second program header (%#v) that matches memsz %x, first program header is %#v", *h, memsz, *ph)
+			// Found a second program header matching, so return all previously
+			// identified headers.
+			return headers, hasLoadables
 		}
 		ph = h
 	}
 	if ph == nil {
-		return nil, fmt.Errorf("found %d matching program headers, but none matches mapping size %x", len(headers), memsz)
+		// No matching header for the strict check. Return all previously identified
+		// headers.
+		return headers, hasLoadables
 	}
-	return ph, nil
+	return []*elf.ProgHeader{ph}, hasLoadables
 }
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
index 3a8d0af..a57a0b2 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
@@ -131,8 +131,9 @@
 	// Name returns the underlyinf file name, if available
 	Name() string
 
-	// Base returns the base address to use when looking up symbols in the file.
-	Base() uint64
+	// ObjAddr returns the objdump (linker) address corresponding to a runtime
+	// address, and an error.
+	ObjAddr(addr uint64) (uint64, error)
 
 	// BuildID returns the GNU build ID of the file, or an empty string.
 	BuildID() string
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
index bc5685d..4a86554 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
@@ -445,7 +445,7 @@
 			return err
 		}
 
-		ns := annotateAssembly(insts, sns, s.base)
+		ns := annotateAssembly(insts, sns, s.file)
 
 		fmt.Fprintf(w, "ROUTINE ======================== %s\n", s.sym.Name[0])
 		for _, name := range s.sym.Name[1:] {
@@ -534,7 +534,6 @@
 			addr = *address
 		}
 		msyms, err := f.Symbols(rx, addr)
-		base := f.Base()
 		f.Close()
 		if err != nil {
 			continue
@@ -543,7 +542,6 @@
 			objSyms = append(objSyms,
 				&objSymbol{
 					sym:  ms,
-					base: base,
 					file: f,
 				},
 			)
@@ -558,7 +556,6 @@
 // added to correspond to sample addresses
 type objSymbol struct {
 	sym  *plugin.Sym
-	base uint64
 	file plugin.ObjFile
 }
 
@@ -578,8 +575,7 @@
 	for _, s := range symbols {
 		// Gather samples for this symbol.
 		for _, n := range ns {
-			address := n.Info.Address - s.base
-			if address >= s.sym.Start && address < s.sym.End {
+			if address, err := s.file.ObjAddr(n.Info.Address); err == nil && address >= s.sym.Start && address < s.sym.End {
 				symNodes[s] = append(symNodes[s], n)
 			}
 		}
@@ -621,7 +617,7 @@
 // annotateAssembly annotates a set of assembly instructions with a
 // set of samples. It returns a set of nodes to display. base is an
 // offset to adjust the sample addresses.
-func annotateAssembly(insts []plugin.Inst, samples graph.Nodes, base uint64) []assemblyInstruction {
+func annotateAssembly(insts []plugin.Inst, samples graph.Nodes, file plugin.ObjFile) []assemblyInstruction {
 	// Add end marker to simplify printing loop.
 	insts = append(insts, plugin.Inst{
 		Addr: ^uint64(0),
@@ -645,7 +641,10 @@
 
 		// Sum all the samples until the next instruction (to account
 		// for samples attributed to the middle of an instruction).
-		for next := insts[ix+1].Addr; s < len(samples) && samples[s].Info.Address-base < next; s++ {
+		for next := insts[ix+1].Addr; s < len(samples); s++ {
+			if addr, err := file.ObjAddr(samples[s].Info.Address); err != nil || addr >= next {
+				break
+			}
 			sample := samples[s]
 			n.flatDiv += sample.FlatDiv
 			n.flat += sample.Flat
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
index 4f841ef..54245e5 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
@@ -132,6 +132,7 @@
 // sourcePrinter holds state needed for generating source+asm HTML listing.
 type sourcePrinter struct {
 	reader     *sourceReader
+	synth      *synthCode
 	objectTool plugin.ObjTool
 	objects    map[string]plugin.ObjFile  // Opened object files
 	sym        *regexp.Regexp             // May be nil
@@ -146,6 +147,12 @@
 	prettyNames map[string]string
 }
 
+// addrInfo holds information for an address we are interested in.
+type addrInfo struct {
+	loc *profile.Location // Always non-nil
+	obj plugin.ObjFile    // May be nil
+}
+
 // instructionInfo holds collected information for an instruction.
 type instructionInfo struct {
 	objAddr   uint64 // Address in object file (with base subtracted out)
@@ -207,6 +214,7 @@
 func newSourcePrinter(rpt *Report, obj plugin.ObjTool, sourcePath string) *sourcePrinter {
 	sp := &sourcePrinter{
 		reader:      newSourceReader(sourcePath, rpt.options.TrimPath),
+		synth:       newSynthCode(rpt.prof.Mapping),
 		objectTool:  obj,
 		objects:     map[string]plugin.ObjFile{},
 		sym:         rpt.options.Symbol,
@@ -225,19 +233,21 @@
 		}
 	}
 
-	addrs := map[uint64]bool{}
+	addrs := map[uint64]addrInfo{}
 	flat := map[uint64]int64{}
 	cum := map[uint64]int64{}
 
 	// Record an interest in the function corresponding to lines[index].
-	markInterest := func(addr uint64, lines []profile.Line, index int) {
-		fn := lines[index]
+	markInterest := func(addr uint64, loc *profile.Location, index int) {
+		fn := loc.Line[index]
 		if fn.Function == nil {
 			return
 		}
 		sp.interest[fn.Function.Name] = true
 		sp.interest[fn.Function.SystemName] = true
-		addrs[addr] = true
+		if _, ok := addrs[addr]; !ok {
+			addrs[addr] = addrInfo{loc, sp.objectFile(loc.Mapping)}
+		}
 	}
 
 	// See if sp.sym matches line.
@@ -270,15 +280,21 @@
 				sp.prettyNames[line.Function.SystemName] = line.Function.Name
 			}
 
-			cum[loc.Address] += value
-			if i == 0 {
-				flat[loc.Address] += value
+			addr := loc.Address
+			if addr == 0 {
+				// Some profiles are missing valid addresses.
+				addr = sp.synth.address(loc)
 			}
 
-			if sp.sym == nil || (address != nil && loc.Address == *address) {
+			cum[addr] += value
+			if i == 0 {
+				flat[addr] += value
+			}
+
+			if sp.sym == nil || (address != nil && addr == *address) {
 				// Interested in top-level entry of stack.
 				if len(loc.Line) > 0 {
-					markInterest(loc.Address, loc.Line, len(loc.Line)-1)
+					markInterest(addr, loc, len(loc.Line)-1)
 				}
 				continue
 			}
@@ -287,7 +303,7 @@
 			matchFile := (loc.Mapping != nil && sp.sym.MatchString(loc.Mapping.File))
 			for j, line := range loc.Line {
 				if (j == 0 && matchFile) || matches(line) {
-					markInterest(loc.Address, loc.Line, j)
+					markInterest(addr, loc, j)
 				}
 			}
 		}
@@ -306,10 +322,11 @@
 	}
 }
 
-func (sp *sourcePrinter) expandAddresses(rpt *Report, addrs map[uint64]bool, flat map[uint64]int64) {
+func (sp *sourcePrinter) expandAddresses(rpt *Report, addrs map[uint64]addrInfo, flat map[uint64]int64) {
 	// We found interesting addresses (ones with non-zero samples) above.
 	// Get covering address ranges and disassemble the ranges.
-	ranges := sp.splitIntoRanges(rpt.prof, addrs, flat)
+	ranges, unprocessed := sp.splitIntoRanges(rpt.prof, addrs, flat)
+	sp.handleUnprocessed(addrs, unprocessed)
 
 	// Trim ranges if there are too many.
 	const maxRanges = 25
@@ -321,9 +338,18 @@
 	}
 
 	for _, r := range ranges {
-		base := r.obj.Base()
-		insts, err := sp.objectTool.Disasm(r.mapping.File, r.begin-base, r.end-base,
-			rpt.options.IntelSyntax)
+		objBegin, err := r.obj.ObjAddr(r.begin)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Failed to compute objdump address for range start %x: %v\n", r.begin, err)
+			continue
+		}
+		objEnd, err := r.obj.ObjAddr(r.end)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Failed to compute objdump address for range end %x: %v\n", r.end, err)
+			continue
+		}
+		base := r.begin - objBegin
+		insts, err := sp.objectTool.Disasm(r.mapping.File, objBegin, objEnd, rpt.options.IntelSyntax)
 		if err != nil {
 			// TODO(sanjay): Report that the covered addresses are missing.
 			continue
@@ -385,78 +411,115 @@
 				frames = lastFrames
 			}
 
-			// See if the stack contains a function we are interested in.
-			for i, f := range frames {
-				if !sp.interest[f.Func] {
-					continue
-				}
-
-				// Record sub-stack under frame's file/line.
-				fname := canonicalizeFileName(f.File)
-				file := sp.files[fname]
-				if file == nil {
-					file = &sourceFile{
-						fname:    fname,
-						lines:    map[int][]sourceInst{},
-						funcName: map[int]string{},
-					}
-					sp.files[fname] = file
-				}
-				callees := frames[:i]
-				stack := make([]callID, 0, len(callees))
-				for j := len(callees) - 1; j >= 0; j-- { // Reverse so caller is first
-					stack = append(stack, callID{
-						file: callees[j].File,
-						line: callees[j].Line,
-					})
-				}
-				file.lines[f.Line] = append(file.lines[f.Line], sourceInst{addr, stack})
-
-				// Remember the first function name encountered per source line
-				// and assume that that line belongs to that function.
-				if _, ok := file.funcName[f.Line]; !ok {
-					file.funcName[f.Line] = f.Func
-				}
-			}
+			sp.addStack(addr, frames)
 		}
 	}
 }
 
-// splitIntoRanges converts the set of addresses we are interested in into a set of address
-// ranges to disassemble.
-func (sp *sourcePrinter) splitIntoRanges(prof *profile.Profile, set map[uint64]bool, flat map[uint64]int64) []addressRange {
-	// List of mappings so we can stop expanding address ranges at mapping boundaries.
-	mappings := append([]*profile.Mapping{}, prof.Mapping...)
-	sort.Slice(mappings, func(i, j int) bool { return mappings[i].Start < mappings[j].Start })
+func (sp *sourcePrinter) addStack(addr uint64, frames []plugin.Frame) {
+	// See if the stack contains a function we are interested in.
+	for i, f := range frames {
+		if !sp.interest[f.Func] {
+			continue
+		}
 
-	var result []addressRange
-	addrs := make([]uint64, 0, len(set))
-	for addr := range set {
-		addrs = append(addrs, addr)
+		// Record sub-stack under frame's file/line.
+		fname := canonicalizeFileName(f.File)
+		file := sp.files[fname]
+		if file == nil {
+			file = &sourceFile{
+				fname:    fname,
+				lines:    map[int][]sourceInst{},
+				funcName: map[int]string{},
+			}
+			sp.files[fname] = file
+		}
+		callees := frames[:i]
+		stack := make([]callID, 0, len(callees))
+		for j := len(callees) - 1; j >= 0; j-- { // Reverse so caller is first
+			stack = append(stack, callID{
+				file: callees[j].File,
+				line: callees[j].Line,
+			})
+		}
+		file.lines[f.Line] = append(file.lines[f.Line], sourceInst{addr, stack})
+
+		// Remember the first function name encountered per source line
+		// and assume that that line belongs to that function.
+		if _, ok := file.funcName[f.Line]; !ok {
+			file.funcName[f.Line] = f.Func
+		}
+	}
+}
+
+// synthAsm is the special disassembler value used for instructions without an object file.
+const synthAsm = ""
+
+// handleUnprocessed handles addresses that were skipped by splitIntoRanges because they
+// did not belong to a known object file.
+func (sp *sourcePrinter) handleUnprocessed(addrs map[uint64]addrInfo, unprocessed []uint64) {
+	// makeFrames synthesizes a []plugin.Frame list for the specified address.
+	// The result will typically have length 1, but may be longer if address corresponds
+	// to inlined calls.
+	makeFrames := func(addr uint64) []plugin.Frame {
+		loc := addrs[addr].loc
+		stack := make([]plugin.Frame, 0, len(loc.Line))
+		for _, line := range loc.Line {
+			fn := line.Function
+			if fn == nil {
+				continue
+			}
+			stack = append(stack, plugin.Frame{
+				Func: fn.Name,
+				File: fn.Filename,
+				Line: int(line.Line),
+			})
+		}
+		return stack
+	}
+
+	for _, addr := range unprocessed {
+		frames := makeFrames(addr)
+		x := instructionInfo{
+			objAddr: addr,
+			length:  1,
+			disasm:  synthAsm,
+		}
+		if len(frames) > 0 {
+			x.file = frames[0].File
+			x.line = frames[0].Line
+		}
+		sp.insts[addr] = x
+
+		sp.addStack(addr, frames)
+	}
+}
+
+// splitIntoRanges converts the set of addresses we are interested in into a set of address
+// ranges to disassemble. It also returns the set of addresses found that did not have an
+// associated object file and were therefore not added to an address range.
+func (sp *sourcePrinter) splitIntoRanges(prof *profile.Profile, addrMap map[uint64]addrInfo, flat map[uint64]int64) ([]addressRange, []uint64) {
+	// Partition addresses into two sets: ones with a known object file, and ones without.
+	var addrs, unprocessed []uint64
+	for addr, info := range addrMap {
+		if info.obj != nil {
+			addrs = append(addrs, addr)
+		} else {
+			unprocessed = append(unprocessed, addr)
+		}
 	}
 	sort.Slice(addrs, func(i, j int) bool { return addrs[i] < addrs[j] })
 
-	mappingIndex := 0
 	const expand = 500 // How much to expand range to pick up nearby addresses.
+	var result []addressRange
 	for i, n := 0, len(addrs); i < n; {
 		begin, end := addrs[i], addrs[i]
 		sum := flat[begin]
 		i++
 
-		// Advance to mapping containing addrs[i]
-		for mappingIndex < len(mappings) && mappings[mappingIndex].Limit <= begin {
-			mappingIndex++
-		}
-		if mappingIndex >= len(mappings) {
-			// TODO(sanjay): Report missed address and its samples.
-			break
-		}
-		m := mappings[mappingIndex]
-		obj := sp.objectFile(m)
-		if obj == nil {
-			// TODO(sanjay): Report missed address and its samples.
-			continue
-		}
+		info := addrMap[begin]
+		m := info.loc.Mapping
+		obj := info.obj // Non-nil because of the partitioning done above.
 
 		// Find following addresses that are close enough to addrs[i].
 		for i < n && addrs[i] <= end+2*expand && addrs[i] < m.Limit {
@@ -479,7 +542,7 @@
 
 		result = append(result, addressRange{begin, end, obj, m, sum})
 	}
-	return result
+	return result, unprocessed
 }
 
 func (sp *sourcePrinter) initSamples(flat, cum map[uint64]int64) {
@@ -665,9 +728,12 @@
 	return funcs
 }
 
-// objectFile return the object for the named file, opening it if necessary.
+// objectFile return the object for the specified mapping, opening it if necessary.
 // It returns nil on error.
 func (sp *sourcePrinter) objectFile(m *profile.Mapping) plugin.ObjFile {
+	if m == nil {
+		return nil
+	}
 	if object, ok := sp.objects[m.File]; ok {
 		return object // May be nil if we detected an error earlier.
 	}
@@ -725,12 +791,28 @@
 		return
 	}
 
+	nestedInfo := false
+	cl := "deadsrc"
+	for _, an := range assembly {
+		if len(an.inlineCalls) > 0 || an.instruction != synthAsm {
+			nestedInfo = true
+			cl = "livesrc"
+		}
+	}
+
 	fmt.Fprintf(w,
-		"<span class=line> %6d</span> <span class=deadsrc>  %10s %10s %8s  %s </span>",
-		lineNo,
+		"<span class=line> %6d</span> <span class=%s>  %10s %10s %8s  %s </span>",
+		lineNo, cl,
 		valueOrDot(flat, rpt), valueOrDot(cum, rpt),
 		"", template.HTMLEscapeString(lineContents))
-	srcIndent := indentation(lineContents)
+	if nestedInfo {
+		srcIndent := indentation(lineContents)
+		printNested(w, srcIndent, assembly, reader, rpt)
+	}
+	fmt.Fprintln(w)
+}
+
+func printNested(w io.Writer, srcIndent int, assembly []assemblyInstruction, reader *sourceReader, rpt *Report) {
 	fmt.Fprint(w, "<span class=asm>")
 	var curCalls []callID
 	for i, an := range assembly {
@@ -763,6 +845,9 @@
 				template.HTMLEscapeString(filepath.Base(c.file)), c.line)
 		}
 		curCalls = an.inlineCalls
+		if an.instruction == synthAsm {
+			continue
+		}
 		text := strings.Repeat(" ", srcIndent+4+4*len(curCalls)) + an.instruction
 		fmt.Fprintf(w, " %8s %10s %10s %8x: %s <span class=unimportant>%s</span>\n",
 			"", valueOrDot(flat, rpt), valueOrDot(cum, rpt), an.address,
@@ -772,7 +857,7 @@
 			// would cause double-escaping of file name.
 			fileline)
 	}
-	fmt.Fprintln(w, "</span>")
+	fmt.Fprint(w, "</span>")
 }
 
 // printFunctionClosing prints the end of a function in a weblist report.
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go
index 26e8bdb..17c9f6e 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go
@@ -40,14 +40,7 @@
 .inlinesrc {
   color: #000066;
 }
-.deadsrc {
-cursor: pointer;
-}
-.deadsrc:hover {
-background-color: #eeeeee;
-}
 .livesrc {
-color: #0000ff;
 cursor: pointer;
 }
 .livesrc:hover {
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/synth.go b/src/cmd/vendor/github.com/google/pprof/internal/report/synth.go
new file mode 100644
index 0000000..7a35bbc
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/synth.go
@@ -0,0 +1,39 @@
+package report
+
+import (
+	"github.com/google/pprof/profile"
+)
+
+// synthCode assigns addresses to locations without an address.
+type synthCode struct {
+	next uint64
+	addr map[*profile.Location]uint64 // Synthesized address assigned to a location
+}
+
+func newSynthCode(mappings []*profile.Mapping) *synthCode {
+	// Find a larger address than any mapping.
+	s := &synthCode{next: 1}
+	for _, m := range mappings {
+		if s.next < m.Limit {
+			s.next = m.Limit
+		}
+	}
+	return s
+}
+
+// address returns the synthetic address for loc, creating one if needed.
+func (s *synthCode) address(loc *profile.Location) uint64 {
+	if loc.Address != 0 {
+		panic("can only synthesize addresses for locations without an address")
+	}
+	if addr, ok := s.addr[loc]; ok {
+		return addr
+	}
+	if s.addr == nil {
+		s.addr = map[*profile.Location]uint64{}
+	}
+	addr := s.next
+	s.next++
+	s.addr[loc] = addr
+	return addr
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/encode.go b/src/cmd/vendor/github.com/google/pprof/profile/encode.go
index 1e84c72..ab7f03a 100644
--- a/src/cmd/vendor/github.com/google/pprof/profile/encode.go
+++ b/src/cmd/vendor/github.com/google/pprof/profile/encode.go
@@ -308,7 +308,7 @@
 			if l.strX != 0 {
 				value, err = getString(p.stringTable, &l.strX, err)
 				labels[key] = append(labels[key], value)
-			} else if l.numX != 0 {
+			} else if l.numX != 0 || l.unitX != 0 {
 				numValues := numLabels[key]
 				units := numUnits[key]
 				if l.unitX != 0 {
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/merge.go b/src/cmd/vendor/github.com/google/pprof/profile/merge.go
index 5ab6e9b..9978e73 100644
--- a/src/cmd/vendor/github.com/google/pprof/profile/merge.go
+++ b/src/cmd/vendor/github.com/google/pprof/profile/merge.go
@@ -231,7 +231,6 @@
 	}
 
 	if l, ok := pm.locationsByID[src.ID]; ok {
-		pm.locationsByID[src.ID] = l
 		return l
 	}
 
diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/read.go b/src/cmd/vendor/golang.org/x/mod/modfile/read.go
index 2a961ca..956f30c 100644
--- a/src/cmd/vendor/golang.org/x/mod/modfile/read.go
+++ b/src/cmd/vendor/golang.org/x/mod/modfile/read.go
@@ -194,12 +194,15 @@
 	line.Token = tokens
 }
 
-func (x *FileSyntax) removeLine(line *Line) {
+// markRemoved modifies line so that it (and its end-of-line comment, if any)
+// will be dropped by (*FileSyntax).Cleanup.
+func (line *Line) markRemoved() {
 	line.Token = nil
+	line.Comments.Suffix = nil
 }
 
 // Cleanup cleans up the file syntax x after any edit operations.
-// To avoid quadratic behavior, removeLine marks the line as dead
+// To avoid quadratic behavior, (*Line).markRemoved marks the line as dead
 // by setting line.Token = nil but does not remove it from the slice
 // in which it appears. After edits have all been indicated,
 // calling Cleanup cleans out the dead lines.
diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go
index d8242de..78f83fa 100644
--- a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go
+++ b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go
@@ -58,13 +58,6 @@
 	Syntax  *Line
 }
 
-// A Require is a single require statement.
-type Require struct {
-	Mod      module.Version
-	Indirect bool // has "// indirect" comment
-	Syntax   *Line
-}
-
 // An Exclude is a single exclude statement.
 type Exclude struct {
 	Mod    module.Version
@@ -93,6 +86,93 @@
 	Low, High string
 }
 
+// A Require is a single require statement.
+type Require struct {
+	Mod      module.Version
+	Indirect bool // has "// indirect" comment
+	Syntax   *Line
+}
+
+func (r *Require) markRemoved() {
+	r.Syntax.markRemoved()
+	*r = Require{}
+}
+
+func (r *Require) setVersion(v string) {
+	r.Mod.Version = v
+
+	if line := r.Syntax; len(line.Token) > 0 {
+		if line.InBlock {
+			// If the line is preceded by an empty line, remove it; see
+			// https://golang.org/issue/33779.
+			if len(line.Comments.Before) == 1 && len(line.Comments.Before[0].Token) == 0 {
+				line.Comments.Before = line.Comments.Before[:0]
+			}
+			if len(line.Token) >= 2 { // example.com v1.2.3
+				line.Token[1] = v
+			}
+		} else {
+			if len(line.Token) >= 3 { // require example.com v1.2.3
+				line.Token[2] = v
+			}
+		}
+	}
+}
+
+// setIndirect sets line to have (or not have) a "// indirect" comment.
+func (r *Require) setIndirect(indirect bool) {
+	r.Indirect = indirect
+	line := r.Syntax
+	if isIndirect(line) == indirect {
+		return
+	}
+	if indirect {
+		// Adding comment.
+		if len(line.Suffix) == 0 {
+			// New comment.
+			line.Suffix = []Comment{{Token: "// indirect", Suffix: true}}
+			return
+		}
+
+		com := &line.Suffix[0]
+		text := strings.TrimSpace(strings.TrimPrefix(com.Token, string(slashSlash)))
+		if text == "" {
+			// Empty comment.
+			com.Token = "// indirect"
+			return
+		}
+
+		// Insert at beginning of existing comment.
+		com.Token = "// indirect; " + text
+		return
+	}
+
+	// Removing comment.
+	f := strings.TrimSpace(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash)))
+	if f == "indirect" {
+		// Remove whole comment.
+		line.Suffix = nil
+		return
+	}
+
+	// Remove comment prefix.
+	com := &line.Suffix[0]
+	i := strings.Index(com.Token, "indirect;")
+	com.Token = "//" + com.Token[i+len("indirect;"):]
+}
+
+// isIndirect reports whether line has a "// indirect" comment,
+// meaning it is in go.mod only for its effect on indirect dependencies,
+// so that it can be dropped entirely once the effective version of the
+// indirect dependency reaches the given minimum version.
+func isIndirect(line *Line) bool {
+	if len(line.Suffix) == 0 {
+		return false
+	}
+	f := strings.Fields(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash)))
+	return (len(f) == 1 && f[0] == "indirect" || len(f) > 1 && f[0] == "indirect;")
+}
+
 func (f *File) AddModuleStmt(path string) error {
 	if f.Syntax == nil {
 		f.Syntax = new(FileSyntax)
@@ -217,6 +297,7 @@
 }
 
 var GoVersionRE = lazyregexp.New(`^([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
+var laxGoVersionRE = lazyregexp.New(`^v?(([1-9][0-9]*)\.(0|[1-9][0-9]*))([^0-9].*)$`)
 
 func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, args []string, fix VersionFixer, strict bool) {
 	// If strict is false, this module is a dependency.
@@ -267,8 +348,17 @@
 			errorf("go directive expects exactly one argument")
 			return
 		} else if !GoVersionRE.MatchString(args[0]) {
-			errorf("invalid go version '%s': must match format 1.23", args[0])
-			return
+			fixed := false
+			if !strict {
+				if m := laxGoVersionRE.FindStringSubmatch(args[0]); m != nil {
+					args[0] = m[1]
+					fixed = true
+				}
+			}
+			if !fixed {
+				errorf("invalid go version '%s': must match format 1.23", args[0])
+				return
+			}
 		}
 
 		f.Go = &Go{Syntax: line}
@@ -466,58 +556,6 @@
 	}
 }
 
-// isIndirect reports whether line has a "// indirect" comment,
-// meaning it is in go.mod only for its effect on indirect dependencies,
-// so that it can be dropped entirely once the effective version of the
-// indirect dependency reaches the given minimum version.
-func isIndirect(line *Line) bool {
-	if len(line.Suffix) == 0 {
-		return false
-	}
-	f := strings.Fields(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash)))
-	return (len(f) == 1 && f[0] == "indirect" || len(f) > 1 && f[0] == "indirect;")
-}
-
-// setIndirect sets line to have (or not have) a "// indirect" comment.
-func setIndirect(line *Line, indirect bool) {
-	if isIndirect(line) == indirect {
-		return
-	}
-	if indirect {
-		// Adding comment.
-		if len(line.Suffix) == 0 {
-			// New comment.
-			line.Suffix = []Comment{{Token: "// indirect", Suffix: true}}
-			return
-		}
-
-		com := &line.Suffix[0]
-		text := strings.TrimSpace(strings.TrimPrefix(com.Token, string(slashSlash)))
-		if text == "" {
-			// Empty comment.
-			com.Token = "// indirect"
-			return
-		}
-
-		// Insert at beginning of existing comment.
-		com.Token = "// indirect; " + text
-		return
-	}
-
-	// Removing comment.
-	f := strings.TrimSpace(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash)))
-	if f == "indirect" {
-		// Remove whole comment.
-		line.Suffix = nil
-		return
-	}
-
-	// Remove comment prefix.
-	com := &line.Suffix[0]
-	i := strings.Index(com.Token, "indirect;")
-	com.Token = "//" + com.Token[i+len("indirect;"):]
-}
-
 // IsDirectoryPath reports whether the given path should be interpreted
 // as a directory path. Just like on the go command line, relative paths
 // and rooted paths are directory paths; the rest are module paths.
@@ -825,6 +863,12 @@
 	return nil
 }
 
+// AddRequire sets the first require line for path to version vers,
+// preserving any existing comments for that line and removing all
+// other lines for path.
+//
+// If no line currently exists for path, AddRequire adds a new line
+// at the end of the last require block.
 func (f *File) AddRequire(path, vers string) error {
 	need := true
 	for _, r := range f.Require {
@@ -834,7 +878,7 @@
 				f.Syntax.updateLine(r.Syntax, "require", AutoQuote(path), vers)
 				need = false
 			} else {
-				f.Syntax.removeLine(r.Syntax)
+				r.Syntax.markRemoved()
 				*r = Require{}
 			}
 		}
@@ -846,69 +890,235 @@
 	return nil
 }
 
+// AddNewRequire adds a new require line for path at version vers at the end of
+// the last require block, regardless of any existing require lines for path.
 func (f *File) AddNewRequire(path, vers string, indirect bool) {
 	line := f.Syntax.addLine(nil, "require", AutoQuote(path), vers)
-	setIndirect(line, indirect)
-	f.Require = append(f.Require, &Require{module.Version{Path: path, Version: vers}, indirect, line})
+	r := &Require{
+		Mod:    module.Version{Path: path, Version: vers},
+		Syntax: line,
+	}
+	r.setIndirect(indirect)
+	f.Require = append(f.Require, r)
 }
 
+// SetRequire updates the requirements of f to contain exactly req, preserving
+// the existing block structure and line comment contents (except for 'indirect'
+// markings) for the first requirement on each named module path.
+//
+// The Syntax field is ignored for the requirements in req.
+//
+// Any requirements not already present in the file are added to the block
+// containing the last require line.
+//
+// The requirements in req must specify at most one distinct version for each
+// module path.
+//
+// If any existing requirements may be removed, the caller should call Cleanup
+// after all edits are complete.
 func (f *File) SetRequire(req []*Require) {
-	need := make(map[string]string)
-	indirect := make(map[string]bool)
+	type elem struct {
+		version  string
+		indirect bool
+	}
+	need := make(map[string]elem)
 	for _, r := range req {
-		need[r.Mod.Path] = r.Mod.Version
-		indirect[r.Mod.Path] = r.Indirect
-	}
-
-	for _, r := range f.Require {
-		if v, ok := need[r.Mod.Path]; ok {
-			r.Mod.Version = v
-			r.Indirect = indirect[r.Mod.Path]
-		} else {
-			*r = Require{}
+		if prev, dup := need[r.Mod.Path]; dup && prev.version != r.Mod.Version {
+			panic(fmt.Errorf("SetRequire called with conflicting versions for path %s (%s and %s)", r.Mod.Path, prev.version, r.Mod.Version))
 		}
+		need[r.Mod.Path] = elem{r.Mod.Version, r.Indirect}
 	}
 
-	var newStmts []Expr
+	// Update or delete the existing Require entries to preserve
+	// only the first for each module path in req.
+	for _, r := range f.Require {
+		e, ok := need[r.Mod.Path]
+		if ok {
+			r.setVersion(e.version)
+			r.setIndirect(e.indirect)
+		} else {
+			r.markRemoved()
+		}
+		delete(need, r.Mod.Path)
+	}
+
+	// Add new entries in the last block of the file for any paths that weren't
+	// already present.
+	//
+	// This step is nondeterministic, but the final result will be deterministic
+	// because we will sort the block.
+	for path, e := range need {
+		f.AddNewRequire(path, e.version, e.indirect)
+	}
+
+	f.SortBlocks()
+}
+
+// SetRequireSeparateIndirect updates the requirements of f to contain the given
+// requirements. Comment contents (except for 'indirect' markings) are retained
+// from the first existing requirement for each module path, and block structure
+// is maintained as long as the indirect markings match.
+//
+// Any requirements on paths not already present in the file are added. Direct
+// requirements are added to the last block containing *any* other direct
+// requirement. Indirect requirements are added to the last block containing
+// *only* other indirect requirements. If no suitable block exists, a new one is
+// added, with the last block containing a direct dependency (if any)
+// immediately before the first block containing only indirect dependencies.
+//
+// The Syntax field is ignored for requirements in the given blocks.
+func (f *File) SetRequireSeparateIndirect(req []*Require) {
+	type modKey struct {
+		path     string
+		indirect bool
+	}
+	need := make(map[modKey]string)
+	for _, r := range req {
+		need[modKey{r.Mod.Path, r.Indirect}] = r.Mod.Version
+	}
+
+	comments := make(map[string]Comments)
+	for _, r := range f.Require {
+		v, ok := need[modKey{r.Mod.Path, r.Indirect}]
+		if !ok {
+			if _, ok := need[modKey{r.Mod.Path, !r.Indirect}]; ok {
+				if _, dup := comments[r.Mod.Path]; !dup {
+					comments[r.Mod.Path] = r.Syntax.Comments
+				}
+			}
+			r.markRemoved()
+			continue
+		}
+		r.setVersion(v)
+		delete(need, modKey{r.Mod.Path, r.Indirect})
+	}
+
+	var (
+		lastDirectOrMixedBlock Expr
+		firstIndirectOnlyBlock Expr
+		lastIndirectOnlyBlock  Expr
+	)
 	for _, stmt := range f.Syntax.Stmt {
 		switch stmt := stmt.(type) {
-		case *LineBlock:
-			if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
-				var newLines []*Line
-				for _, line := range stmt.Line {
-					if p, err := parseString(&line.Token[0]); err == nil && need[p] != "" {
-						if len(line.Comments.Before) == 1 && len(line.Comments.Before[0].Token) == 0 {
-							line.Comments.Before = line.Comments.Before[:0]
-						}
-						line.Token[1] = need[p]
-						delete(need, p)
-						setIndirect(line, indirect[p])
-						newLines = append(newLines, line)
-					}
-				}
-				if len(newLines) == 0 {
-					continue // drop stmt
-				}
-				stmt.Line = newLines
-			}
-
 		case *Line:
-			if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
-				if p, err := parseString(&stmt.Token[1]); err == nil && need[p] != "" {
-					stmt.Token[2] = need[p]
-					delete(need, p)
-					setIndirect(stmt, indirect[p])
-				} else {
-					continue // drop stmt
+			if len(stmt.Token) == 0 || stmt.Token[0] != "require" {
+				continue
+			}
+			if isIndirect(stmt) {
+				lastIndirectOnlyBlock = stmt
+			} else {
+				lastDirectOrMixedBlock = stmt
+			}
+		case *LineBlock:
+			if len(stmt.Token) == 0 || stmt.Token[0] != "require" {
+				continue
+			}
+			indirectOnly := true
+			for _, line := range stmt.Line {
+				if len(line.Token) == 0 {
+					continue
+				}
+				if !isIndirect(line) {
+					indirectOnly = false
+					break
+				}
+			}
+			if indirectOnly {
+				lastIndirectOnlyBlock = stmt
+				if firstIndirectOnlyBlock == nil {
+					firstIndirectOnlyBlock = stmt
+				}
+			} else {
+				lastDirectOrMixedBlock = stmt
+			}
+		}
+	}
+
+	isOrContainsStmt := func(stmt Expr, target Expr) bool {
+		if stmt == target {
+			return true
+		}
+		if stmt, ok := stmt.(*LineBlock); ok {
+			if target, ok := target.(*Line); ok {
+				for _, line := range stmt.Line {
+					if line == target {
+						return true
+					}
 				}
 			}
 		}
-		newStmts = append(newStmts, stmt)
+		return false
 	}
-	f.Syntax.Stmt = newStmts
 
-	for path, vers := range need {
-		f.AddNewRequire(path, vers, indirect[path])
+	addRequire := func(path, vers string, indirect bool, comments Comments) {
+		var line *Line
+		if indirect {
+			if lastIndirectOnlyBlock != nil {
+				line = f.Syntax.addLine(lastIndirectOnlyBlock, "require", path, vers)
+			} else {
+				// Add a new require block after the last direct-only or mixed "require"
+				// block (if any).
+				//
+				// (f.Syntax.addLine would add the line to an existing "require" block if
+				// present, but here the existing "require" blocks are all direct-only, so
+				// we know we need to add a new block instead.)
+				line = &Line{Token: []string{"require", path, vers}}
+				lastIndirectOnlyBlock = line
+				firstIndirectOnlyBlock = line // only block implies first block
+				if lastDirectOrMixedBlock == nil {
+					f.Syntax.Stmt = append(f.Syntax.Stmt, line)
+				} else {
+					for i, stmt := range f.Syntax.Stmt {
+						if isOrContainsStmt(stmt, lastDirectOrMixedBlock) {
+							f.Syntax.Stmt = append(f.Syntax.Stmt, nil)     // increase size
+							copy(f.Syntax.Stmt[i+2:], f.Syntax.Stmt[i+1:]) // shuffle elements up
+							f.Syntax.Stmt[i+1] = line
+							break
+						}
+					}
+				}
+			}
+		} else {
+			if lastDirectOrMixedBlock != nil {
+				line = f.Syntax.addLine(lastDirectOrMixedBlock, "require", path, vers)
+			} else {
+				// Add a new require block before the first indirect block (if any).
+				//
+				// That way if the file initially contains only indirect lines,
+				// the direct lines still appear before it: we preserve existing
+				// structure, but only to the extent that that structure already
+				// reflects the direct/indirect split.
+				line = &Line{Token: []string{"require", path, vers}}
+				lastDirectOrMixedBlock = line
+				if firstIndirectOnlyBlock == nil {
+					f.Syntax.Stmt = append(f.Syntax.Stmt, line)
+				} else {
+					for i, stmt := range f.Syntax.Stmt {
+						if isOrContainsStmt(stmt, firstIndirectOnlyBlock) {
+							f.Syntax.Stmt = append(f.Syntax.Stmt, nil)   // increase size
+							copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:]) // shuffle elements up
+							f.Syntax.Stmt[i] = line
+							break
+						}
+					}
+				}
+			}
+		}
+
+		line.Comments.Before = commentsAdd(line.Comments.Before, comments.Before)
+		line.Comments.Suffix = commentsAdd(line.Comments.Suffix, comments.Suffix)
+
+		r := &Require{
+			Mod:      module.Version{Path: path, Version: vers},
+			Indirect: indirect,
+			Syntax:   line,
+		}
+		r.setIndirect(indirect)
+		f.Require = append(f.Require, r)
+	}
+
+	for k, vers := range need {
+		addRequire(k.path, vers, k.indirect, comments[k.path])
 	}
 	f.SortBlocks()
 }
@@ -916,7 +1126,7 @@
 func (f *File) DropRequire(path string) error {
 	for _, r := range f.Require {
 		if r.Mod.Path == path {
-			f.Syntax.removeLine(r.Syntax)
+			r.Syntax.markRemoved()
 			*r = Require{}
 		}
 	}
@@ -947,7 +1157,7 @@
 func (f *File) DropExclude(path, vers string) error {
 	for _, x := range f.Exclude {
 		if x.Mod.Path == path && x.Mod.Version == vers {
-			f.Syntax.removeLine(x.Syntax)
+			x.Syntax.markRemoved()
 			*x = Exclude{}
 		}
 	}
@@ -978,7 +1188,7 @@
 				continue
 			}
 			// Already added; delete other replacements for same.
-			f.Syntax.removeLine(r.Syntax)
+			r.Syntax.markRemoved()
 			*r = Replace{}
 		}
 		if r.Old.Path == oldPath {
@@ -994,7 +1204,7 @@
 func (f *File) DropReplace(oldPath, oldVers string) error {
 	for _, r := range f.Replace {
 		if r.Old.Path == oldPath && r.Old.Version == oldVers {
-			f.Syntax.removeLine(r.Syntax)
+			r.Syntax.markRemoved()
 			*r = Replace{}
 		}
 	}
@@ -1035,7 +1245,7 @@
 func (f *File) DropRetract(vi VersionInterval) error {
 	for _, r := range f.Retract {
 		if r.VersionInterval == vi {
-			f.Syntax.removeLine(r.Syntax)
+			r.Syntax.markRemoved()
 			*r = Retract{}
 		}
 	}
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/mkall.sh b/src/cmd/vendor/golang.org/x/sys/unix/mkall.sh
index d727cad..396aadf 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/mkall.sh
+++ b/src/cmd/vendor/golang.org/x/sys/unix/mkall.sh
@@ -70,23 +70,11 @@
 	mksyscall="go run mksyscall_aix_ppc64.go -aix"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
-darwin_386)
-	mkerrors="$mkerrors -m32"
-	mksyscall="go run mksyscall.go -l32"
-	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
-	mkasm="go run mkasm_darwin.go"
-	;;
 darwin_amd64)
 	mkerrors="$mkerrors -m64"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	mkasm="go run mkasm_darwin.go"
 	;;
-darwin_arm)
-	mkerrors="$mkerrors"
-	mksyscall="go run mksyscall.go -l32"
-	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
-	mkasm="go run mkasm_darwin.go"
-	;;
 darwin_arm64)
 	mkerrors="$mkerrors -m64"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go
index 5fc3cda..1596426 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go
@@ -17,7 +17,7 @@
 //sys	readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
 
 func fdopendir(fd int) (dir uintptr, err error) {
-	r0, _, e1 := syscall_syscallPtr(funcPC(libc_fdopendir_trampoline), uintptr(fd), 0, 0)
+	r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0)
 	dir = uintptr(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -25,7 +25,7 @@
 	return
 }
 
-func libc_fdopendir_trampoline()
+var libc_fdopendir_trampoline_addr uintptr
 
 //go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"
 
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go
deleted file mode 100644
index 6474677..0000000
--- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2009 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.
-
-//go:build 386 && darwin
-// +build 386,darwin
-
-package unix
-
-import "syscall"
-
-func setTimespec(sec, nsec int64) Timespec {
-	return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
-}
-
-func setTimeval(sec, usec int64) Timeval {
-	return Timeval{Sec: int32(sec), Usec: int32(usec)}
-}
-
-func SetKevent(k *Kevent_t, fd, mode, flags int) {
-	k.Ident = uint32(fd)
-	k.Filter = int16(mode)
-	k.Flags = uint16(flags)
-}
-
-func (iov *Iovec) SetLen(length int) {
-	iov.Len = uint32(length)
-}
-
-func (msghdr *Msghdr) SetControllen(length int) {
-	msghdr.Controllen = uint32(length)
-}
-
-func (msghdr *Msghdr) SetIovlen(length int) {
-	msghdr.Iovlen = int32(length)
-}
-
-func (cmsg *Cmsghdr) SetLen(length int) {
-	cmsg.Len = uint32(length)
-}
-
-func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
-
-//sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
-//sys	Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
-//sys	Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
-//sys	getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
-//sys	Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
-//sys	ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
-//sys	Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
-//sys	Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go
deleted file mode 100644
index d30735c..0000000
--- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 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 unix
-
-import "syscall"
-
-func ptrace1(request int, pid int, addr uintptr, data uintptr) error {
-	return ENOTSUP
-}
-
-func setTimespec(sec, nsec int64) Timespec {
-	return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
-}
-
-func setTimeval(sec, usec int64) Timeval {
-	return Timeval{Sec: int32(sec), Usec: int32(usec)}
-}
-
-func SetKevent(k *Kevent_t, fd, mode, flags int) {
-	k.Ident = uint32(fd)
-	k.Filter = int16(mode)
-	k.Flags = uint16(flags)
-}
-
-func (iov *Iovec) SetLen(length int) {
-	iov.Len = uint32(length)
-}
-
-func (msghdr *Msghdr) SetControllen(length int) {
-	msghdr.Controllen = uint32(length)
-}
-
-func (msghdr *Msghdr) SetIovlen(length int) {
-	msghdr.Iovlen = int32(length)
-}
-
-func (cmsg *Cmsghdr) SetLen(length int) {
-	cmsg.Len = uint32(length)
-}
-
-func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic
-
-//sys	Fstat(fd int, stat *Stat_t) (err error)
-//sys	Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
-//sys	Fstatfs(fd int, stat *Statfs_t) (err error)
-//sys	getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT
-//sys	Lstat(path string, stat *Stat_t) (err error)
-//sys	Stat(path string, stat *Stat_t) (err error)
-//sys	Statfs(path string, stat *Statfs_t) (err error)
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
index 38bec30..53c9664 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
@@ -7,7 +7,7 @@
 
 package unix
 
-import "unsafe"
+import _ "unsafe"
 
 // Implemented in the runtime package (runtime/sys_darwin.go)
 func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
@@ -25,10 +25,3 @@
 //go:linkname syscall_rawSyscall syscall.rawSyscall
 //go:linkname syscall_rawSyscall6 syscall.rawSyscall6
 //go:linkname syscall_syscallPtr syscall.syscallPtr
-
-// Find the entry point for f. See comments in runtime/proc.go for the
-// function of the same name.
-//go:nosplit
-func funcPC(f func()) uintptr {
-	return **(**uintptr)(unsafe.Pointer(&f))
-}
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go
deleted file mode 100644
index 7ee196f..0000000
--- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go
+++ /dev/null
@@ -1,1789 +0,0 @@
-// mkerrors.sh -m32
-// Code generated by the command above; see README.md. DO NOT EDIT.
-
-//go:build 386 && darwin
-// +build 386,darwin
-
-// Code generated by cmd/cgo -godefs; DO NOT EDIT.
-// cgo -godefs -- -m32 _const.go
-
-package unix
-
-import "syscall"
-
-const (
-	AF_APPLETALK                      = 0x10
-	AF_CCITT                          = 0xa
-	AF_CHAOS                          = 0x5
-	AF_CNT                            = 0x15
-	AF_COIP                           = 0x14
-	AF_DATAKIT                        = 0x9
-	AF_DECnet                         = 0xc
-	AF_DLI                            = 0xd
-	AF_E164                           = 0x1c
-	AF_ECMA                           = 0x8
-	AF_HYLINK                         = 0xf
-	AF_IEEE80211                      = 0x25
-	AF_IMPLINK                        = 0x3
-	AF_INET                           = 0x2
-	AF_INET6                          = 0x1e
-	AF_IPX                            = 0x17
-	AF_ISDN                           = 0x1c
-	AF_ISO                            = 0x7
-	AF_LAT                            = 0xe
-	AF_LINK                           = 0x12
-	AF_LOCAL                          = 0x1
-	AF_MAX                            = 0x28
-	AF_NATM                           = 0x1f
-	AF_NDRV                           = 0x1b
-	AF_NETBIOS                        = 0x21
-	AF_NS                             = 0x6
-	AF_OSI                            = 0x7
-	AF_PPP                            = 0x22
-	AF_PUP                            = 0x4
-	AF_RESERVED_36                    = 0x24
-	AF_ROUTE                          = 0x11
-	AF_SIP                            = 0x18
-	AF_SNA                            = 0xb
-	AF_SYSTEM                         = 0x20
-	AF_SYS_CONTROL                    = 0x2
-	AF_UNIX                           = 0x1
-	AF_UNSPEC                         = 0x0
-	AF_UTUN                           = 0x26
-	ALTWERASE                         = 0x200
-	ATTR_BIT_MAP_COUNT                = 0x5
-	ATTR_CMN_ACCESSMASK               = 0x20000
-	ATTR_CMN_ACCTIME                  = 0x1000
-	ATTR_CMN_ADDEDTIME                = 0x10000000
-	ATTR_CMN_BKUPTIME                 = 0x2000
-	ATTR_CMN_CHGTIME                  = 0x800
-	ATTR_CMN_CRTIME                   = 0x200
-	ATTR_CMN_DATA_PROTECT_FLAGS       = 0x40000000
-	ATTR_CMN_DEVID                    = 0x2
-	ATTR_CMN_DOCUMENT_ID              = 0x100000
-	ATTR_CMN_ERROR                    = 0x20000000
-	ATTR_CMN_EXTENDED_SECURITY        = 0x400000
-	ATTR_CMN_FILEID                   = 0x2000000
-	ATTR_CMN_FLAGS                    = 0x40000
-	ATTR_CMN_FNDRINFO                 = 0x4000
-	ATTR_CMN_FSID                     = 0x4
-	ATTR_CMN_FULLPATH                 = 0x8000000
-	ATTR_CMN_GEN_COUNT                = 0x80000
-	ATTR_CMN_GRPID                    = 0x10000
-	ATTR_CMN_GRPUUID                  = 0x1000000
-	ATTR_CMN_MODTIME                  = 0x400
-	ATTR_CMN_NAME                     = 0x1
-	ATTR_CMN_NAMEDATTRCOUNT           = 0x80000
-	ATTR_CMN_NAMEDATTRLIST            = 0x100000
-	ATTR_CMN_OBJID                    = 0x20
-	ATTR_CMN_OBJPERMANENTID           = 0x40
-	ATTR_CMN_OBJTAG                   = 0x10
-	ATTR_CMN_OBJTYPE                  = 0x8
-	ATTR_CMN_OWNERID                  = 0x8000
-	ATTR_CMN_PARENTID                 = 0x4000000
-	ATTR_CMN_PAROBJID                 = 0x80
-	ATTR_CMN_RETURNED_ATTRS           = 0x80000000
-	ATTR_CMN_SCRIPT                   = 0x100
-	ATTR_CMN_SETMASK                  = 0x41c7ff00
-	ATTR_CMN_USERACCESS               = 0x200000
-	ATTR_CMN_UUID                     = 0x800000
-	ATTR_CMN_VALIDMASK                = 0xffffffff
-	ATTR_CMN_VOLSETMASK               = 0x6700
-	ATTR_FILE_ALLOCSIZE               = 0x4
-	ATTR_FILE_CLUMPSIZE               = 0x10
-	ATTR_FILE_DATAALLOCSIZE           = 0x400
-	ATTR_FILE_DATAEXTENTS             = 0x800
-	ATTR_FILE_DATALENGTH              = 0x200
-	ATTR_FILE_DEVTYPE                 = 0x20
-	ATTR_FILE_FILETYPE                = 0x40
-	ATTR_FILE_FORKCOUNT               = 0x80
-	ATTR_FILE_FORKLIST                = 0x100
-	ATTR_FILE_IOBLOCKSIZE             = 0x8
-	ATTR_FILE_LINKCOUNT               = 0x1
-	ATTR_FILE_RSRCALLOCSIZE           = 0x2000
-	ATTR_FILE_RSRCEXTENTS             = 0x4000
-	ATTR_FILE_RSRCLENGTH              = 0x1000
-	ATTR_FILE_SETMASK                 = 0x20
-	ATTR_FILE_TOTALSIZE               = 0x2
-	ATTR_FILE_VALIDMASK               = 0x37ff
-	ATTR_VOL_ALLOCATIONCLUMP          = 0x40
-	ATTR_VOL_ATTRIBUTES               = 0x40000000
-	ATTR_VOL_CAPABILITIES             = 0x20000
-	ATTR_VOL_DIRCOUNT                 = 0x400
-	ATTR_VOL_ENCODINGSUSED            = 0x10000
-	ATTR_VOL_FILECOUNT                = 0x200
-	ATTR_VOL_FSTYPE                   = 0x1
-	ATTR_VOL_INFO                     = 0x80000000
-	ATTR_VOL_IOBLOCKSIZE              = 0x80
-	ATTR_VOL_MAXOBJCOUNT              = 0x800
-	ATTR_VOL_MINALLOCATION            = 0x20
-	ATTR_VOL_MOUNTEDDEVICE            = 0x8000
-	ATTR_VOL_MOUNTFLAGS               = 0x4000
-	ATTR_VOL_MOUNTPOINT               = 0x1000
-	ATTR_VOL_NAME                     = 0x2000
-	ATTR_VOL_OBJCOUNT                 = 0x100
-	ATTR_VOL_QUOTA_SIZE               = 0x10000000
-	ATTR_VOL_RESERVED_SIZE            = 0x20000000
-	ATTR_VOL_SETMASK                  = 0x80002000
-	ATTR_VOL_SIGNATURE                = 0x2
-	ATTR_VOL_SIZE                     = 0x4
-	ATTR_VOL_SPACEAVAIL               = 0x10
-	ATTR_VOL_SPACEFREE                = 0x8
-	ATTR_VOL_UUID                     = 0x40000
-	ATTR_VOL_VALIDMASK                = 0xf007ffff
-	B0                                = 0x0
-	B110                              = 0x6e
-	B115200                           = 0x1c200
-	B1200                             = 0x4b0
-	B134                              = 0x86
-	B14400                            = 0x3840
-	B150                              = 0x96
-	B1800                             = 0x708
-	B19200                            = 0x4b00
-	B200                              = 0xc8
-	B230400                           = 0x38400
-	B2400                             = 0x960
-	B28800                            = 0x7080
-	B300                              = 0x12c
-	B38400                            = 0x9600
-	B4800                             = 0x12c0
-	B50                               = 0x32
-	B57600                            = 0xe100
-	B600                              = 0x258
-	B7200                             = 0x1c20
-	B75                               = 0x4b
-	B76800                            = 0x12c00
-	B9600                             = 0x2580
-	BIOCFLUSH                         = 0x20004268
-	BIOCGBLEN                         = 0x40044266
-	BIOCGDLT                          = 0x4004426a
-	BIOCGDLTLIST                      = 0xc00c4279
-	BIOCGETIF                         = 0x4020426b
-	BIOCGHDRCMPLT                     = 0x40044274
-	BIOCGRSIG                         = 0x40044272
-	BIOCGRTIMEOUT                     = 0x4008426e
-	BIOCGSEESENT                      = 0x40044276
-	BIOCGSTATS                        = 0x4008426f
-	BIOCIMMEDIATE                     = 0x80044270
-	BIOCPROMISC                       = 0x20004269
-	BIOCSBLEN                         = 0xc0044266
-	BIOCSDLT                          = 0x80044278
-	BIOCSETF                          = 0x80084267
-	BIOCSETFNR                        = 0x8008427e
-	BIOCSETIF                         = 0x8020426c
-	BIOCSHDRCMPLT                     = 0x80044275
-	BIOCSRSIG                         = 0x80044273
-	BIOCSRTIMEOUT                     = 0x8008426d
-	BIOCSSEESENT                      = 0x80044277
-	BIOCVERSION                       = 0x40044271
-	BPF_A                             = 0x10
-	BPF_ABS                           = 0x20
-	BPF_ADD                           = 0x0
-	BPF_ALIGNMENT                     = 0x4
-	BPF_ALU                           = 0x4
-	BPF_AND                           = 0x50
-	BPF_B                             = 0x10
-	BPF_DIV                           = 0x30
-	BPF_H                             = 0x8
-	BPF_IMM                           = 0x0
-	BPF_IND                           = 0x40
-	BPF_JA                            = 0x0
-	BPF_JEQ                           = 0x10
-	BPF_JGE                           = 0x30
-	BPF_JGT                           = 0x20
-	BPF_JMP                           = 0x5
-	BPF_JSET                          = 0x40
-	BPF_K                             = 0x0
-	BPF_LD                            = 0x0
-	BPF_LDX                           = 0x1
-	BPF_LEN                           = 0x80
-	BPF_LSH                           = 0x60
-	BPF_MAJOR_VERSION                 = 0x1
-	BPF_MAXBUFSIZE                    = 0x80000
-	BPF_MAXINSNS                      = 0x200
-	BPF_MEM                           = 0x60
-	BPF_MEMWORDS                      = 0x10
-	BPF_MINBUFSIZE                    = 0x20
-	BPF_MINOR_VERSION                 = 0x1
-	BPF_MISC                          = 0x7
-	BPF_MSH                           = 0xa0
-	BPF_MUL                           = 0x20
-	BPF_NEG                           = 0x80
-	BPF_OR                            = 0x40
-	BPF_RELEASE                       = 0x30bb6
-	BPF_RET                           = 0x6
-	BPF_RSH                           = 0x70
-	BPF_ST                            = 0x2
-	BPF_STX