aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd/go.mod10
-rw-r--r--src/cmd/go.sum20
-rw-r--r--src/cmd/vendor/golang.org/x/sys/plan9/syscall_plan9.go8
-rw-r--r--src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go229
-rw-r--r--src/cmd/vendor/golang.org/x/sys/windows/aliases.go1
-rw-r--r--src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go15
-rw-r--r--src/cmd/vendor/golang.org/x/sys/windows/types_windows.go85
-rw-r--r--src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go7
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go19
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go67
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go3
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/atomictypes.go255
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go41
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go25
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/fmtappendf.go90
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go9
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go43
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go41
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go30
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go20
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go24
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go29
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go215
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscutprefix.go3
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go14
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroupgo.go (renamed from src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroup.go)13
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/ast/inspector/cursor.go34
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/version.go8
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/fix.go15
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/astutil/stringlit.go56
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go121
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/diff/unified.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go1
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go10
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go7
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/inline.go72
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/refactor/refactor.go7
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/typesinternal/typeindex/typeindex.go8
-rw-r--r--src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go7
-rw-r--r--src/cmd/vendor/modules.txt20
-rw-r--r--src/go.mod2
-rw-r--r--src/go.sum4
-rw-r--r--src/vendor/golang.org/x/sys/cpu/asm_darwin_arm64_gc.s12
-rw-r--r--src/vendor/golang.org/x/sys/cpu/cpu_arm64.go9
-rw-r--r--src/vendor/golang.org/x/sys/cpu/cpu_darwin_arm64.go67
-rw-r--r--src/vendor/golang.org/x/sys/cpu/cpu_darwin_arm64_other.go29
-rw-r--r--src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go1
-rw-r--r--src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go6
-rw-r--r--src/vendor/golang.org/x/sys/cpu/syscall_darwin_arm64_gc.go54
-rw-r--r--src/vendor/modules.txt4
55 files changed, 1351 insertions, 531 deletions
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
index 3bc9833971..d15db1306b 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -6,12 +6,12 @@ require (
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83
golang.org/x/arch v0.23.1-0.20260109160903-657d90bd6695
golang.org/x/build v0.0.0-20260122183339-3ba88df37c64
- golang.org/x/mod v0.32.0
- golang.org/x/sync v0.19.0
- golang.org/x/sys v0.40.1-0.20260116220947-d25a7aaff8c2
- golang.org/x/telemetry v0.0.0-20260116145544-c6413dc483f5
+ golang.org/x/mod v0.34.0
+ golang.org/x/sync v0.20.0
+ golang.org/x/sys v0.42.1-0.20260320201212-a76ec62d6c53
+ golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c
golang.org/x/term v0.39.0
- golang.org/x/tools v0.41.1-0.20260122210857-a60613f0795e
+ golang.org/x/tools v0.43.1-0.20260319213245-5d7afbc08aec
)
require (
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
index 224585feb6..23627773f0 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -10,19 +10,19 @@ golang.org/x/arch v0.23.1-0.20260109160903-657d90bd6695 h1:q45HsUyFzBjBk4mHGgUew
golang.org/x/arch v0.23.1-0.20260109160903-657d90bd6695/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/build v0.0.0-20260122183339-3ba88df37c64 h1:BNhBATNmH/VtzGolB+ksQPPvn6ZyffiR8TmKenqNo+A=
golang.org/x/build v0.0.0-20260122183339-3ba88df37c64/go.mod h1:3QmSbNil8ZWqC94m80Glej1v8b92gYzPIQPTtSa0c+4=
-golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
-golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.40.1-0.20260116220947-d25a7aaff8c2 h1:jUsftZdK5NYH1tUlaQUfascfiJtOm7qHnRPWsG6hb4w=
-golang.org/x/sys v0.40.1-0.20260116220947-d25a7aaff8c2/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/telemetry v0.0.0-20260116145544-c6413dc483f5 h1:i0p03B68+xC1kD2QUO8JzDTPXCzhN56OLJ+IhHY8U3A=
-golang.org/x/telemetry v0.0.0-20260116145544-c6413dc483f5/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8=
+golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
+golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.42.1-0.20260320201212-a76ec62d6c53 h1:0T1C9w/fKTlj64Z8y0UtRoCAD7UZ+l5ZCSHcs3GYSCI=
+golang.org/x/sys v0.42.1-0.20260320201212-a76ec62d6c53/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c h1:6a8FdnNk6bTXBjR4AGKFgUKuo+7GnR3FX5L7CbveeZc=
+golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c/go.mod h1:TpUTTEp9frx7rTdLpC9gFG9kdI7zVLFTFFlqaH2Cncw=
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
golang.org/x/text v0.33.1-0.20260122225119-3264de9174be h1:EwuAS7HtEmZVDSL0zq464yhyVIjdDETleE+K94kfwxg=
golang.org/x/text v0.33.1-0.20260122225119-3264de9174be/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
-golang.org/x/tools v0.41.1-0.20260122210857-a60613f0795e h1:+CX08Gt13e9ttPSqktf4tM6Ft1hv8yedWyIfcwmakSQ=
-golang.org/x/tools v0.41.1-0.20260122210857-a60613f0795e/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
+golang.org/x/tools v0.43.1-0.20260319213245-5d7afbc08aec h1:kTU64nIpH5vbfY0lQLyoZB98LkAmp2WzOvYoylbOIhg=
+golang.org/x/tools v0.43.1-0.20260319213245-5d7afbc08aec/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef h1:mqLYrXCXYEZOop9/Dbo6RPX11539nwiCNBb1icVPmw8=
rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef/go.mod h1:8xcPgWmwlZONN1D9bjxtHEjrUtSEa3fakVF8iaewYKQ=
diff --git a/src/cmd/vendor/golang.org/x/sys/plan9/syscall_plan9.go b/src/cmd/vendor/golang.org/x/sys/plan9/syscall_plan9.go
index d079d8116e..761912237f 100644
--- a/src/cmd/vendor/golang.org/x/sys/plan9/syscall_plan9.go
+++ b/src/cmd/vendor/golang.org/x/sys/plan9/syscall_plan9.go
@@ -19,13 +19,7 @@ import (
// A Note is a string describing a process note.
// It implements the os.Signal interface.
-type Note string
-
-func (n Note) Signal() {}
-
-func (n Note) String() string {
- return string(n)
-}
+type Note = syscall.Note
var (
Stdin = 0
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go
index c1a4670171..45476a73c6 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go
@@ -593,110 +593,115 @@ const (
)
const (
- NDA_UNSPEC = 0x0
- NDA_DST = 0x1
- NDA_LLADDR = 0x2
- NDA_CACHEINFO = 0x3
- NDA_PROBES = 0x4
- NDA_VLAN = 0x5
- NDA_PORT = 0x6
- NDA_VNI = 0x7
- NDA_IFINDEX = 0x8
- NDA_MASTER = 0x9
- NDA_LINK_NETNSID = 0xa
- NDA_SRC_VNI = 0xb
- NTF_USE = 0x1
- NTF_SELF = 0x2
- NTF_MASTER = 0x4
- NTF_PROXY = 0x8
- NTF_EXT_LEARNED = 0x10
- NTF_OFFLOADED = 0x20
- NTF_ROUTER = 0x80
- NUD_INCOMPLETE = 0x1
- NUD_REACHABLE = 0x2
- NUD_STALE = 0x4
- NUD_DELAY = 0x8
- NUD_PROBE = 0x10
- NUD_FAILED = 0x20
- NUD_NOARP = 0x40
- NUD_PERMANENT = 0x80
- NUD_NONE = 0x0
- IFA_UNSPEC = 0x0
- IFA_ADDRESS = 0x1
- IFA_LOCAL = 0x2
- IFA_LABEL = 0x3
- IFA_BROADCAST = 0x4
- IFA_ANYCAST = 0x5
- IFA_CACHEINFO = 0x6
- IFA_MULTICAST = 0x7
- IFA_FLAGS = 0x8
- IFA_RT_PRIORITY = 0x9
- IFA_TARGET_NETNSID = 0xa
- IFAL_LABEL = 0x2
- IFAL_ADDRESS = 0x1
- RT_SCOPE_UNIVERSE = 0x0
- RT_SCOPE_SITE = 0xc8
- RT_SCOPE_LINK = 0xfd
- RT_SCOPE_HOST = 0xfe
- RT_SCOPE_NOWHERE = 0xff
- RT_TABLE_UNSPEC = 0x0
- RT_TABLE_COMPAT = 0xfc
- RT_TABLE_DEFAULT = 0xfd
- RT_TABLE_MAIN = 0xfe
- RT_TABLE_LOCAL = 0xff
- RT_TABLE_MAX = 0xffffffff
- RTA_UNSPEC = 0x0
- RTA_DST = 0x1
- RTA_SRC = 0x2
- RTA_IIF = 0x3
- RTA_OIF = 0x4
- RTA_GATEWAY = 0x5
- RTA_PRIORITY = 0x6
- RTA_PREFSRC = 0x7
- RTA_METRICS = 0x8
- RTA_MULTIPATH = 0x9
- RTA_FLOW = 0xb
- RTA_CACHEINFO = 0xc
- RTA_TABLE = 0xf
- RTA_MARK = 0x10
- RTA_MFC_STATS = 0x11
- RTA_VIA = 0x12
- RTA_NEWDST = 0x13
- RTA_PREF = 0x14
- RTA_ENCAP_TYPE = 0x15
- RTA_ENCAP = 0x16
- RTA_EXPIRES = 0x17
- RTA_PAD = 0x18
- RTA_UID = 0x19
- RTA_TTL_PROPAGATE = 0x1a
- RTA_IP_PROTO = 0x1b
- RTA_SPORT = 0x1c
- RTA_DPORT = 0x1d
- RTN_UNSPEC = 0x0
- RTN_UNICAST = 0x1
- RTN_LOCAL = 0x2
- RTN_BROADCAST = 0x3
- RTN_ANYCAST = 0x4
- RTN_MULTICAST = 0x5
- RTN_BLACKHOLE = 0x6
- RTN_UNREACHABLE = 0x7
- RTN_PROHIBIT = 0x8
- RTN_THROW = 0x9
- RTN_NAT = 0xa
- RTN_XRESOLVE = 0xb
- SizeofNlMsghdr = 0x10
- SizeofNlMsgerr = 0x14
- SizeofRtGenmsg = 0x1
- SizeofNlAttr = 0x4
- SizeofRtAttr = 0x4
- SizeofIfInfomsg = 0x10
- SizeofIfAddrmsg = 0x8
- SizeofIfAddrlblmsg = 0xc
- SizeofIfaCacheinfo = 0x10
- SizeofRtMsg = 0xc
- SizeofRtNexthop = 0x8
- SizeofNdUseroptmsg = 0x10
- SizeofNdMsg = 0xc
+ NDA_UNSPEC = 0x0
+ NDA_DST = 0x1
+ NDA_LLADDR = 0x2
+ NDA_CACHEINFO = 0x3
+ NDA_PROBES = 0x4
+ NDA_VLAN = 0x5
+ NDA_PORT = 0x6
+ NDA_VNI = 0x7
+ NDA_IFINDEX = 0x8
+ NDA_MASTER = 0x9
+ NDA_LINK_NETNSID = 0xa
+ NDA_SRC_VNI = 0xb
+ NTF_USE = 0x1
+ NTF_SELF = 0x2
+ NTF_MASTER = 0x4
+ NTF_PROXY = 0x8
+ NTF_EXT_LEARNED = 0x10
+ NTF_OFFLOADED = 0x20
+ NTF_ROUTER = 0x80
+ NUD_INCOMPLETE = 0x1
+ NUD_REACHABLE = 0x2
+ NUD_STALE = 0x4
+ NUD_DELAY = 0x8
+ NUD_PROBE = 0x10
+ NUD_FAILED = 0x20
+ NUD_NOARP = 0x40
+ NUD_PERMANENT = 0x80
+ NUD_NONE = 0x0
+ IFA_UNSPEC = 0x0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFA_FLAGS = 0x8
+ IFA_RT_PRIORITY = 0x9
+ IFA_TARGET_NETNSID = 0xa
+ IFAL_LABEL = 0x2
+ IFAL_ADDRESS = 0x1
+ RT_SCOPE_UNIVERSE = 0x0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0x0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0x0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTA_MARK = 0x10
+ RTA_MFC_STATS = 0x11
+ RTA_VIA = 0x12
+ RTA_NEWDST = 0x13
+ RTA_PREF = 0x14
+ RTA_ENCAP_TYPE = 0x15
+ RTA_ENCAP = 0x16
+ RTA_EXPIRES = 0x17
+ RTA_PAD = 0x18
+ RTA_UID = 0x19
+ RTA_TTL_PROPAGATE = 0x1a
+ RTA_IP_PROTO = 0x1b
+ RTA_SPORT = 0x1c
+ RTA_DPORT = 0x1d
+ RTN_UNSPEC = 0x0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ PREFIX_UNSPEC = 0x0
+ PREFIX_ADDRESS = 0x1
+ PREFIX_CACHEINFO = 0x2
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofPrefixmsg = 0xc
+ SizeofPrefixCacheinfo = 0x8
+ SizeofIfAddrmsg = 0x8
+ SizeofIfAddrlblmsg = 0xc
+ SizeofIfaCacheinfo = 0x10
+ SizeofRtMsg = 0xc
+ SizeofRtNexthop = 0x8
+ SizeofNdUseroptmsg = 0x10
+ SizeofNdMsg = 0xc
)
type NlMsghdr struct {
@@ -735,6 +740,22 @@ type IfInfomsg struct {
Change uint32
}
+type Prefixmsg struct {
+ Family uint8
+ Pad1 uint8
+ Pad2 uint16
+ Ifindex int32
+ Type uint8
+ Len uint8
+ Flags uint8
+ Pad3 uint8
+}
+
+type PrefixCacheinfo struct {
+ Preferred_time uint32
+ Valid_time uint32
+}
+
type IfAddrmsg struct {
Family uint8
Prefixlen uint8
diff --git a/src/cmd/vendor/golang.org/x/sys/windows/aliases.go b/src/cmd/vendor/golang.org/x/sys/windows/aliases.go
index 16f90560a2..96317966e5 100644
--- a/src/cmd/vendor/golang.org/x/sys/windows/aliases.go
+++ b/src/cmd/vendor/golang.org/x/sys/windows/aliases.go
@@ -8,5 +8,6 @@ package windows
import "syscall"
+type Signal = syscall.Signal
type Errno = syscall.Errno
type SysProcAttr = syscall.SysProcAttr
diff --git a/src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go b/src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go
index 69439df2a4..d766436587 100644
--- a/src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -900,6 +900,7 @@ const socket_error = uintptr(^uint32(0))
//sys NotifyRouteChange2(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyRouteChange2
//sys NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyUnicastIpAddressChange
//sys CancelMibChangeNotify2(notificationHandle Handle) (errcode error) = iphlpapi.CancelMibChangeNotify2
+//sys IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) = kernel32.IsProcessorFeaturePresent
// For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT.
@@ -1489,20 +1490,6 @@ func Getgid() (gid int) { return -1 }
func Getegid() (egid int) { return -1 }
func Getgroups() (gids []int, err error) { return nil, syscall.EWINDOWS }
-type Signal int
-
-func (s Signal) Signal() {}
-
-func (s Signal) String() string {
- if 0 <= s && int(s) < len(signals) {
- str := signals[s]
- if str != "" {
- return str
- }
- }
- return "signal " + itoa(int(s))
-}
-
func LoadCreateSymbolicLink() error {
return procCreateSymbolicLinkW.Find()
}
diff --git a/src/cmd/vendor/golang.org/x/sys/windows/types_windows.go b/src/cmd/vendor/golang.org/x/sys/windows/types_windows.go
index 6e4f50eb48..d5658a138c 100644
--- a/src/cmd/vendor/golang.org/x/sys/windows/types_windows.go
+++ b/src/cmd/vendor/golang.org/x/sys/windows/types_windows.go
@@ -3938,3 +3938,88 @@ const (
MOUSE_EVENT = 0x0002
WINDOW_BUFFER_SIZE_EVENT = 0x0004
)
+
+// The processor features to be tested for IsProcessorFeaturePresent, see
+// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
+const (
+ PF_ARM_64BIT_LOADSTORE_ATOMIC = 25
+ PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE = 24
+ PF_ARM_EXTERNAL_CACHE_AVAILABLE = 26
+ PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE = 27
+ PF_ARM_VFP_32_REGISTERS_AVAILABLE = 18
+ PF_3DNOW_INSTRUCTIONS_AVAILABLE = 7
+ PF_CHANNELS_ENABLED = 16
+ PF_COMPARE_EXCHANGE_DOUBLE = 2
+ PF_COMPARE_EXCHANGE128 = 14
+ PF_COMPARE64_EXCHANGE128 = 15
+ PF_FASTFAIL_AVAILABLE = 23
+ PF_FLOATING_POINT_EMULATED = 1
+ PF_FLOATING_POINT_PRECISION_ERRATA = 0
+ PF_MMX_INSTRUCTIONS_AVAILABLE = 3
+ PF_NX_ENABLED = 12
+ PF_PAE_ENABLED = 9
+ PF_RDTSC_INSTRUCTION_AVAILABLE = 8
+ PF_RDWRFSGSBASE_AVAILABLE = 22
+ PF_SECOND_LEVEL_ADDRESS_TRANSLATION = 20
+ PF_SSE3_INSTRUCTIONS_AVAILABLE = 13
+ PF_SSSE3_INSTRUCTIONS_AVAILABLE = 36
+ PF_SSE4_1_INSTRUCTIONS_AVAILABLE = 37
+ PF_SSE4_2_INSTRUCTIONS_AVAILABLE = 38
+ PF_AVX_INSTRUCTIONS_AVAILABLE = 39
+ PF_AVX2_INSTRUCTIONS_AVAILABLE = 40
+ PF_AVX512F_INSTRUCTIONS_AVAILABLE = 41
+ PF_VIRT_FIRMWARE_ENABLED = 21
+ PF_XMMI_INSTRUCTIONS_AVAILABLE = 6
+ PF_XMMI64_INSTRUCTIONS_AVAILABLE = 10
+ PF_XSAVE_ENABLED = 17
+ PF_ARM_V8_INSTRUCTIONS_AVAILABLE = 29
+ PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30
+ PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31
+ PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34
+ PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE = 43
+ PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44
+ PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE = 45
+ PF_ARM_SVE_INSTRUCTIONS_AVAILABLE = 46
+ PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE = 47
+ PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE = 48
+ PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE = 49
+ PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE = 50
+ PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE = 51
+ PF_ARM_SVE_BF16_INSTRUCTIONS_AVAILABLE = 52
+ PF_ARM_SVE_EBF16_INSTRUCTIONS_AVAILABLE = 53
+ PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE = 54
+ PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE = 55
+ PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE = 56
+ PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE = 57
+ PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE = 58
+ PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE = 59
+ PF_BMI2_INSTRUCTIONS_AVAILABLE = 60
+ PF_MOVDIR64B_INSTRUCTION_AVAILABLE = 61
+ PF_ARM_LSE2_AVAILABLE = 62
+ PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE = 64
+ PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE = 65
+ PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE = 66
+ PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE = 67
+ PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE = 68
+ PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE = 69
+ PF_ARM_SME_INSTRUCTIONS_AVAILABLE = 70
+ PF_ARM_SME2_INSTRUCTIONS_AVAILABLE = 71
+ PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE = 72
+ PF_ARM_SME2_2_INSTRUCTIONS_AVAILABLE = 73
+ PF_ARM_SME_AES_INSTRUCTIONS_AVAILABLE = 74
+ PF_ARM_SME_SBITPERM_INSTRUCTIONS_AVAILABLE = 75
+ PF_ARM_SME_SF8MM4_INSTRUCTIONS_AVAILABLE = 76
+ PF_ARM_SME_SF8MM8_INSTRUCTIONS_AVAILABLE = 77
+ PF_ARM_SME_SF8DP2_INSTRUCTIONS_AVAILABLE = 78
+ PF_ARM_SME_SF8DP4_INSTRUCTIONS_AVAILABLE = 79
+ PF_ARM_SME_SF8FMA_INSTRUCTIONS_AVAILABLE = 80
+ PF_ARM_SME_F8F32_INSTRUCTIONS_AVAILABLE = 81
+ PF_ARM_SME_F8F16_INSTRUCTIONS_AVAILABLE = 82
+ PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE = 83
+ PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE = 84
+ PF_ARM_SME_F64F64_INSTRUCTIONS_AVAILABLE = 85
+ PF_ARM_SME_I16I64_INSTRUCTIONS_AVAILABLE = 86
+ PF_ARM_SME_LUTv2_INSTRUCTIONS_AVAILABLE = 87
+ PF_ARM_SME_FA64_INSTRUCTIONS_AVAILABLE = 88
+ PF_UMONITOR_INSTRUCTION_AVAILABLE = 89
+)
diff --git a/src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index f25b7308a1..fe7a4ea124 100644
--- a/src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -320,6 +320,7 @@ var (
procGetVolumePathNamesForVolumeNameW = modkernel32.NewProc("GetVolumePathNamesForVolumeNameW")
procGetWindowsDirectoryW = modkernel32.NewProc("GetWindowsDirectoryW")
procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList")
+ procIsProcessorFeaturePresent = modkernel32.NewProc("IsProcessorFeaturePresent")
procIsWow64Process = modkernel32.NewProc("IsWow64Process")
procIsWow64Process2 = modkernel32.NewProc("IsWow64Process2")
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
@@ -2786,6 +2787,12 @@ func initializeProcThreadAttributeList(attrlist *ProcThreadAttributeList, attrco
return
}
+func IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) {
+ r0, _, _ := syscall.SyscallN(procIsProcessorFeaturePresent.Addr(), uintptr(ProcessorFeature))
+ ret = r0 != 0
+ return
+}
+
func IsWow64Process(handle Handle, isWow64 *bool) (err error) {
var _p0 uint32
if *isWow64 {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
index a7df4d1fe4..786c29d55d 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
@@ -11,6 +11,7 @@ import (
"go/token"
"go/types"
"reflect"
+ "time"
)
// An Analyzer describes an analysis function and its options.
@@ -250,7 +251,19 @@ type Fact interface {
// A Module describes the module to which a package belongs.
type Module struct {
- Path string // module path
- Version string // module version ("" if unknown, such as for workspace modules)
- GoVersion string // go version used in module (e.g. "go1.22.0")
+ Path string // module path
+ Version string // module version ("" if unknown, such as for workspace modules)
+ Replace *Module // replaced by this module
+ Time *time.Time // time version was created
+ Main bool // is this the main module?
+ Indirect bool // is this module only an indirect dependency of main module?
+ Dir string // directory holding files for this module, if any
+ GoMod string // path to go.mod file used when loading this module, if any
+ GoVersion string // go version used in module (e.g. "go1.22.0")
+ Error *ModuleError // error loading module
+}
+
+// ModuleError holds errors loading a module.
+type ModuleError struct {
+ Err string // the error itself
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
index c7637df00a..2c4a8e7339 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
@@ -52,7 +52,7 @@ func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer {
prefix = a.Name + "."
enable := new(triState)
- enableUsage := "enable " + a.Name + " analysis"
+ enableUsage := fmt.Sprintf("enable %q analysis", a.Name)
flag.Var(enable, a.Name, enableUsage)
enabled[a] = enable
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go
index 9049145e22..415058db80 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go
@@ -315,12 +315,43 @@ func (a *analyzer) inlineAlias(tn *types.TypeName, curId inspector.Cursor) {
curPath := a.pass.Pkg.Path()
curFile := astutil.EnclosingFile(curId)
id := curId.Node().(*ast.Ident)
+
+ // Find the complete identifier, which may take any of these forms:
+ // Id
+ // Id[T]
+ // Id[K, V]
+ // pkg.Id
+ // pkg.Id[T]
+ // pkg.Id[K, V]
+ var expr ast.Expr = id
+ if curId.ParentEdgeKind() == edge.SelectorExpr_Sel {
+ curId = curId.Parent()
+ expr = curId.Node().(ast.Expr)
+ }
+ // If expr is part of an IndexExpr or IndexListExpr, we'll need that node.
+ // Given C[int], TypeOf(C) is generic but TypeOf(C[int]) is instantiated.
+ switch curId.ParentEdgeKind() {
+ case edge.IndexExpr_X:
+ expr = curId.Parent().Node().(*ast.IndexExpr)
+ case edge.IndexListExpr_X:
+ expr = curId.Parent().Node().(*ast.IndexListExpr)
+ }
+ t := a.pass.TypesInfo.TypeOf(expr).(*types.Alias) // type of entire identifier
+ if targs := t.TypeArgs(); targs.Len() > 0 {
+ // Instantiate the alias with the type args from this use.
+ // For example, given type A = M[K, V], compute the type of the use
+ // A[int, Foo] as M[int, Foo].
+ // Don't validate instantiation: it can't panic unless we have a bug,
+ // in which case seeing the stack trace via telemetry would be helpful.
+ instAlias, _ := types.Instantiate(nil, alias, slices.Collect(targs.Types()), false)
+ rhs = instAlias.(*types.Alias).Rhs()
+ }
+
// We have an identifier A here (n), possibly qualified by a package
// identifier (sel.n), and an inlinable "type A = rhs" elsewhere.
//
// We can replace A with rhs if no name in rhs is shadowed at n's position,
// and every package in rhs is importable by the current package.
-
var (
importPrefixes = map[string]string{curPath: ""} // from pkg path to prefix
edits []analysis.TextEdit
@@ -349,6 +380,7 @@ func (a *analyzer) inlineAlias(tn *types.TypeName, curId inspector.Cursor) {
return
} else if _, ok := importPrefixes[pkgPath]; !ok {
// Use AddImport to add pkgPath if it's not there already. Associate the prefix it assigns
+ // with the prefix it assigns
// with the package path for use by the TypeString qualifier below.
prefix, eds := refactor.AddImport(
a.pass.TypesInfo, curFile, pkgName, pkgPath, tn.Name(), id.Pos())
@@ -356,36 +388,7 @@ func (a *analyzer) inlineAlias(tn *types.TypeName, curId inspector.Cursor) {
edits = append(edits, eds...)
}
}
- // Find the complete identifier, which may take any of these forms:
- // Id
- // Id[T]
- // Id[K, V]
- // pkg.Id
- // pkg.Id[T]
- // pkg.Id[K, V]
- var expr ast.Expr = id
- if astutil.IsChildOf(curId, edge.SelectorExpr_Sel) {
- curId = curId.Parent()
- expr = curId.Node().(ast.Expr)
- }
- // If expr is part of an IndexExpr or IndexListExpr, we'll need that node.
- // Given C[int], TypeOf(C) is generic but TypeOf(C[int]) is instantiated.
- switch ek, _ := curId.ParentEdge(); ek {
- case edge.IndexExpr_X:
- expr = curId.Parent().Node().(*ast.IndexExpr)
- case edge.IndexListExpr_X:
- expr = curId.Parent().Node().(*ast.IndexListExpr)
- }
- t := a.pass.TypesInfo.TypeOf(expr).(*types.Alias) // type of entire identifier
- if targs := t.TypeArgs(); targs.Len() > 0 {
- // Instantiate the alias with the type args from this use.
- // For example, given type A = M[K, V], compute the type of the use
- // A[int, Foo] as M[int, Foo].
- // Don't validate instantiation: it can't panic unless we have a bug,
- // in which case seeing the stack trace via telemetry would be helpful.
- instAlias, _ := types.Instantiate(nil, alias, slices.Collect(targs.Types()), false)
- rhs = instAlias.(*types.Alias).Rhs()
- }
+
// To get the replacement text, render the alias RHS using the package prefixes
// we assigned above.
newText := types.TypeString(rhs, func(p *types.Package) string {
@@ -526,7 +529,7 @@ func (a *analyzer) inlineConst(con *types.Const, cur inspector.Cursor) {
}
// If n is qualified by a package identifier, we'll need the full selector expression.
var expr ast.Expr = n
- if astutil.IsChildOf(cur, edge.SelectorExpr_Sel) {
+ if cur.ParentEdgeKind() == edge.SelectorExpr_Sel {
expr = cur.Parent().Node().(ast.Expr)
}
a.reportInline("constant", "Constant", expr, edits, importPrefix+incon.RHSName)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
index 28a5f6cd93..dfc4313679 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
@@ -16,7 +16,6 @@ import (
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/cfg"
"golang.org/x/tools/internal/analysis/analyzerutil"
- "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -84,7 +83,7 @@ func runFunc(pass *analysis.Pass, node ast.Node) {
// {FuncDecl,FuncLit,CallExpr,SelectorExpr}.
// Find the set of cancel vars to analyze.
- astutil.PreorderStack(node, nil, func(n ast.Node, stack []ast.Node) bool {
+ ast.PreorderStack(node, nil, func(n ast.Node, stack []ast.Node) bool {
if _, ok := n.(*ast.FuncLit); ok && len(stack) > 0 {
return false // don't stray into nested functions
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/atomictypes.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/atomictypes.go
new file mode 100644
index 0000000000..2f314b2972
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/atomictypes.go
@@ -0,0 +1,255 @@
+// Copyright 2026 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 modernize
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/types"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/edge"
+ "golang.org/x/tools/go/ast/inspector"
+ "golang.org/x/tools/go/types/typeutil"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
+ typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
+ "golang.org/x/tools/internal/astutil"
+ "golang.org/x/tools/internal/goplsexport"
+ "golang.org/x/tools/internal/refactor"
+ "golang.org/x/tools/internal/typesinternal"
+ "golang.org/x/tools/internal/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
+)
+
+var atomicTypesAnalyzer = &analysis.Analyzer{
+ Name: "atomictypes",
+ Doc: analyzerutil.MustExtractDoc(doc, "atomictypes"),
+ Requires: []*analysis.Analyzer{
+ inspect.Analyzer,
+ typeindexanalyzer.Analyzer,
+ },
+ Run: runAtomic,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#atomictypes",
+}
+
+func init() {
+ // Export to gopls until this is a published modernizer.
+ goplsexport.AtomicTypesModernizer = atomicTypesAnalyzer
+}
+
+// TODO(mkalil): support the Pointer variants.
+// Consider the following function signatures for pointer loading:
+// func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
+// func (x *Pointer[T]) Load() *T
+// Since the former uses *unsafe.Pointer while the latter uses *Pointer[T],
+// we would need to determine the type T to apply the transformation, and there
+// will be additional edits required to remove any *unsafe.Pointer casts.
+// "LoadPointer", "StorePointer", "SwapPointer", "CompareAndSwapPointer"
+
+// sync/atomic functions of interest. Some added in go1.19, some added in go1.23.
+var syncAtomicFuncs = []string{
+ // Added in go1.19.
+ "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr",
+ "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr",
+ "LoadInt32", "LoadInt64", "LoadUint32", "LoadUint64", "LoadUintptr",
+ "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr",
+ "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr",
+ // Added in go1.23.
+ "AndInt32", "AndInt64", "AndUint32", "AndUint64", "AndUintptr",
+ "OrInt32", "OrInt64", "OrUint32", "OrUint64", "OrUintptr",
+}
+
+func runAtomic(pass *analysis.Pass) (any, error) {
+ if !typesinternal.Imports(pass.Pkg, "sync/atomic") {
+ return nil, nil // doesn't directly import sync/atomic
+ }
+
+ var (
+ index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
+ info = pass.TypesInfo
+ )
+
+ // Gather all candidate variables v appearing
+ // in calls to atomic.AddInt32(&v, ...) et al.
+ var (
+ atomicPkg *types.Package
+ vars = make(map[*types.Var]string) // maps candidate vars v to the name of the call they appear in
+ )
+ for _, funcName := range syncAtomicFuncs {
+ obj := index.Object("sync/atomic", funcName)
+ if obj == nil {
+ continue
+ }
+ atomicPkg = obj.Pkg()
+ for curCall := range index.Calls(obj) {
+ call := curCall.Node().(*ast.CallExpr)
+ if unary, ok := call.Args[0].(*ast.UnaryExpr); ok && unary.Op == token.AND {
+ var v *types.Var
+ switch x := unary.X.(type) {
+ case *ast.Ident:
+ v, _ = info.Uses[x].(*types.Var)
+ case *ast.SelectorExpr:
+ if seln, ok := info.Selections[x]; ok {
+ v, _ = seln.Obj().(*types.Var)
+ }
+ }
+ if v != nil && !v.Exported() {
+ // v must be a non-exported package or local var, or a struct field.
+ switch v.Kind() {
+ case types.RecvVar, types.ParamVar, types.ResultVar:
+ continue // fix would change func signature
+ }
+ vars[v] = funcName
+ }
+ }
+ }
+ }
+
+ // Check that all uses of each candidate variable
+ // appear in calls of the form atomic.AddInt32(&v, ...).
+nextvar:
+ for v, funcName := range vars {
+ var edits []analysis.TextEdit
+ fixFiles := make(map[*ast.File]bool) // unique files involved in the current fix
+
+ // Check the form of the declaration: var v int or struct { v int }
+ def, ok := index.Def(v)
+ if !ok {
+ continue
+ }
+ var (
+ typ ast.Expr
+ names []*ast.Ident
+ )
+ switch parent := def.Parent().Node().(type) {
+ case *ast.Field: // struct { v int }
+ names = parent.Names
+ typ = parent.Type
+ case *ast.ValueSpec: // var v int
+ if len(parent.Values) > 0 {
+ // e.g. var v int = 5
+ // skip because rewriting as `var v atomic.Int32 = 5` is invalid
+ continue
+ }
+ names = parent.Names
+ typ = parent.Type
+ }
+ if len(names) != 1 || typ == nil {
+ continue // v is not the sole var declared here (e.g. var x, y int32); or no explicit type
+ }
+ oldType := info.TypeOf(typ) // e.g. "int32"
+ newType := strings.Title(oldType.Underlying().String()) // e.g. "Int32"
+
+ // Get package prefix to avoid shadowing.
+ file := astutil.EnclosingFile(def)
+ pkgPrefix, impEdits := refactor.AddImport(pass.TypesInfo, file, "atomic", "sync/atomic", "", def.Node().Pos())
+ if len(impEdits) > 0 {
+ panic("unexpected import edits") // atomic PkgName should be in scope already
+ }
+ // Edit the type.
+ //
+ // var v int32
+ // ------------
+ // var v atomic.Int32
+ edits = append(edits, analysis.TextEdit{
+ Pos: typ.Pos(),
+ End: typ.End(),
+ NewText: fmt.Appendf(nil, "%s%s", pkgPrefix, newType),
+ })
+ fixFiles[file] = true
+
+ // Each valid use is an Ident v or Selector expr.v within an atomic.F(&...) call.
+ var validUses []inspector.Cursor
+ for cur := range index.Uses(v) {
+ if v.IsField() && cur.ParentEdgeKind() == edge.KeyValueExpr_Key {
+ continue nextvar // we cannot fix initial an value assignment T{v: 1}
+ }
+ if cur.ParentEdgeKind() == edge.SelectorExpr_Sel {
+ cur = cur.Parent() // ascend from v to expr.v
+ }
+ // Inv: cur is the l-value expression denoting v.
+ // v must appear beneath atomic.AddInt32(&v, ...) call.
+ valid := false
+ if cur.ParentEdgeKind() == edge.UnaryExpr_X &&
+ cur.Parent().Node().(*ast.UnaryExpr).Op == token.AND {
+ if ek, idx := cur.Parent().ParentEdge(); ek == edge.CallExpr_Args && idx == 0 {
+ curCall := cur.Parent().Parent()
+ call := curCall.Node().(*ast.CallExpr)
+ if fn, ok := typeutil.Callee(info, call).(*types.Func); ok && fn.Pkg() == atomicPkg {
+ valid = true
+ }
+ }
+ }
+
+ if !valid {
+ // More complex case: reject candidate.
+ //
+ // For example, cur may be an unsynchronized load (e.g. v == 0). To
+ // avoid a type conversion error, we'd have to rewrite this as
+ // v.Load(). However, this is an invalid rewrite: if the program is
+ // mixing atomic operations with unsynchronized reads, the author
+ // might have accidentally introduced a data race and the suggested
+ // fix could obscure the mistake. Or, if the usage is intentional,
+ // rewriting may result in a behavior change.
+ continue nextvar
+ }
+ validUses = append(validUses, cur)
+ }
+
+ for _, cur := range validUses {
+ vexpr := cur.Node()
+ call := cur.Parent().Parent().Node().(*ast.CallExpr)
+ fn := typeutil.Callee(info, call).(*types.Func)
+ // atomic.AddInt32(&v, ...)
+ // ----------------- -----
+ // v.Add(...)
+ after := vexpr.End() // LoadInt32(&v⁁)
+ if len(call.Args) > 1 {
+ after = call.Args[1].Pos() // AddInt32(&v, ⁁...)
+ }
+ verb := strings.TrimSuffix(fn.Name(), newType) // "AddInt32" => "Add"
+ edits = append(edits, []analysis.TextEdit{
+ {
+ Pos: call.Pos(),
+ End: vexpr.Pos(),
+ },
+ {
+ Pos: vexpr.End(),
+ End: after,
+ NewText: fmt.Appendf(nil, ".%s(", verb),
+ },
+ }...)
+ fixFiles[astutil.EnclosingFile(cur)] = true
+ }
+
+ // Check minimum Go version: go1.19, or 1.23 for the And/Or functions.
+ if !(analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_19) ||
+ analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_23) &&
+ (strings.HasPrefix(funcName, "And") || strings.HasPrefix(funcName, "Or"))) {
+ continue
+ }
+
+ // Skip if v is not local and the package has ignored files as it may be
+ // an incomplete transformation.
+ if !isLocal(v) && len(pass.IgnoredFiles) > 0 {
+ continue
+ }
+
+ pass.Report(analysis.Diagnostic{
+ Pos: names[0].Pos(),
+ End: typ.End(),
+ Message: fmt.Sprintf("var %s %s may be simplified using atomic.%s", v.Name(), oldType, newType),
+ SuggestedFixes: []analysis.SuggestedFix{{
+ Message: fmt.Sprintf("Replace %s by atomic.%s", oldType, newType),
+ TextEdits: edits,
+ }},
+ })
+ }
+
+ return nil, nil
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go
index 0425faf8d4..7aa7046b39 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go
@@ -65,6 +65,26 @@ This analyzer is currently disabled by default as the
transformation does not preserve the nilness of the base slice in
all cases; see https://go.dev/issue/73557.
+# Analyzer atomictypes
+
+atomictypes: replace basic types in sync/atomic calls with atomic types
+
+The atomictypes analyzer suggests replacing the primitive sync/atomic functions with
+the strongly typed atomic wrapper types introduced in Go1.19 (e.g.
+atomic.Int32). For example,
+
+ var x int32
+ atomic.AddInt32(&x, 1)
+
+would become
+
+ var x atomic.Int32
+ x.Add(1)
+
+The atomic types are safer because they don't allow non-atomic access, which is
+a common source of bugs. These types also resolve memory alignment issues that
+plagued the old atomic functions on 32-bit architectures.
+
# Analyzer bloop
bloop: replace for-range over b.N with b.Loop
@@ -263,11 +283,15 @@ is known at compile time, for example:
reflect.TypeOf(uint32(0)) -> reflect.TypeFor[uint32]()
reflect.TypeOf((*ast.File)(nil)) -> reflect.TypeFor[*ast.File]()
-It also offers a fix to simplify the construction below, which uses
+It also offers a fix to simplify the constructions below, which use
reflect.TypeOf to return the runtime type for an interface type,
reflect.TypeOf((*io.Reader)(nil)).Elem()
+or:
+
+ reflect.TypeOf([]io.Reader(nil)).Elem()
+
to:
reflect.TypeFor[io.Reader]()
@@ -460,14 +484,15 @@ is replaced by:
This avoids quadratic memory allocation and improves performance.
-The analyzer requires that all references to s except the final one
+The analyzer requires that all references to s before the final uses
are += operations. To avoid warning about trivial cases, at least one
must appear within a loop. The variable s must be a local
variable, not a global or parameter.
-The sole use of the finished string must be the last reference to the
-variable s. (It may appear within an intervening loop or function literal,
-since even s.String() is called repeatedly, it does not allocate memory.)
+All uses of the finished string must come after the last += operation.
+Each such use will be replaced by a call to strings.Builder's String method.
+(These may appear within an intervening loop or function literal, since even
+if s.String() is called repeatedly, it does not allocate memory.)
Often the addend is a call to fmt.Sprintf, as in this example:
@@ -519,11 +544,11 @@ where ptr is an unsafe.Pointer, is replaced by:
unsafe.Add(ptr, n)
-# Analyzer waitgroup
+# Analyzer waitgroupgo
-waitgroup: replace wg.Add(1)/go/wg.Done() with wg.Go
+waitgroupgo: replace wg.Add(1)/go/wg.Done() with wg.Go
-The waitgroup analyzer simplifies goroutine management with `sync.WaitGroup`.
+The waitgroupgo analyzer simplifies goroutine management with `sync.WaitGroup`.
It replaces the common pattern
wg.Add(1)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go
index d9a922f846..8603d54712 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go
@@ -125,22 +125,11 @@ func errorsastype(pass *analysis.Pass) (any, error) {
errtype := types.TypeString(v.Type(), qual)
// Choose a name for the "ok" variable.
- // TODO(adonovan): this pattern also appears in stditerators,
- // and is wanted elsewhere; factor.
- okName := "ok"
- if okVar := lookup(info, curCall, "ok"); okVar != nil {
- // The name 'ok' is already declared, but
- // don't choose a fresh name unless okVar
- // is also used within the if-statement.
- curIf := curCall.Parent()
- for curUse := range index.Uses(okVar) {
- if curIf.Contains(curUse) {
- scope := info.Scopes[curIf.Node().(*ast.IfStmt)]
- okName = refactor.FreshName(scope, v.Pos(), "ok")
- break
- }
- }
- }
+ // We generate a new name only if 'ok' is already declared at
+ // curCall and it also used within the if-statement.
+ curIf := curCall.Parent()
+ ifScope := info.Scopes[curIf.Node().(*ast.IfStmt)]
+ okName := freshName(info, index, ifScope, v.Pos(), curCall, curIf, token.NoPos, "ok")
pass.Report(analysis.Diagnostic{
Pos: call.Fun.Pos(),
@@ -189,7 +178,7 @@ func errorsastype(pass *analysis.Pass) (any, error) {
// declaration of the typed error var. The var must not be
// used outside the if statement.
func canUseErrorsAsType(info *types.Info, index *typeindex.Index, curCall inspector.Cursor) (_ *types.Var, _ inspector.Cursor) {
- if !astutil.IsChildOf(curCall, edge.IfStmt_Cond) {
+ if curCall.ParentEdgeKind() != edge.IfStmt_Cond {
return // not beneath if statement
}
var (
@@ -221,7 +210,7 @@ func canUseErrorsAsType(info *types.Info, index *typeindex.Index, curCall inspec
return // v used before/after if statement
}
}
- if !astutil.IsChildOf(curDef, edge.ValueSpec_Names) {
+ if curDef.ParentEdgeKind() != edge.ValueSpec_Names {
return // v not declared by "var v T"
}
var (
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/fmtappendf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/fmtappendf.go
index 389f703466..8210654131 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/fmtappendf.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/fmtappendf.go
@@ -7,6 +7,7 @@ package modernize
import (
"fmt"
"go/ast"
+ "go/constant"
"go/types"
"strings"
@@ -16,6 +17,7 @@ import (
"golang.org/x/tools/internal/analysis/analyzerutil"
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
"golang.org/x/tools/internal/astutil"
+ "golang.org/x/tools/internal/fmtstr"
"golang.org/x/tools/internal/typesinternal/typeindex"
"golang.org/x/tools/internal/versions"
)
@@ -45,10 +47,24 @@ func fmtappendf(pass *analysis.Pass) (any, error) {
if ek, idx := curCall.ParentEdge(); ek == edge.CallExpr_Args && idx == 0 {
// Is parent a T(fmt.SprintX(...)) conversion?
conv := curCall.Parent().Node().(*ast.CallExpr)
- tv := pass.TypesInfo.Types[conv.Fun]
- if tv.IsType() && types.Identical(tv.Type, byteSliceType) &&
- analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(curCall), versions.Go1_19) {
+ info := pass.TypesInfo
+ tv := info.Types[conv.Fun]
+ if tv.IsType() && types.Identical(tv.Type, byteSliceType) {
// Have: []byte(fmt.SprintX(...))
+ if len(call.Args) == 0 {
+ continue
+ }
+ // fmt.Sprint(f) and fmt.Append(f) have different nil semantics
+ // when the format produces an empty string:
+ // []byte(fmt.Sprintf("")) returns an empty but non-nil
+ // []byte{}, while fmt.Appendf(nil, "") returns nil) so we
+ // should skip these cases.
+ if fn.Name() == "Sprint" || fn.Name() == "Sprintf" {
+ format := info.Types[call.Args[0]].Value
+ if format != nil && mayFormatEmpty(constant.StringVal(format)) {
+ continue
+ }
+ }
// Find "Sprint" identifier.
var id *ast.Ident
@@ -62,13 +78,18 @@ func fmtappendf(pass *analysis.Pass) (any, error) {
old, new := fn.Name(), strings.Replace(fn.Name(), "Sprint", "Append", 1)
edits := []analysis.TextEdit{
{
- // delete "[]byte("
+ // Delete "[]byte(", including any spaces before the first argument.
Pos: conv.Pos(),
- End: conv.Lparen + 1,
+ End: conv.Args[0].Pos(), // always exactly one argument in a valid byte slice conversion
},
{
- // remove ")"
- Pos: conv.Rparen,
+ // Delete ")", including any non-args (space or
+ // commas) that come before the right parenthesis.
+ // Leaving an extra comma here produces invalid
+ // code. (See golang/go#74709)
+ // Unfortunately, this and the edit above may result
+ // in deleting some comments.
+ Pos: conv.Args[0].End(),
End: conv.Rparen + 1,
},
{
@@ -81,19 +102,8 @@ func fmtappendf(pass *analysis.Pass) (any, error) {
NewText: []byte("nil, "),
},
}
- if len(conv.Args) == 1 {
- arg := conv.Args[0]
- // Determine if we have T(fmt.SprintX(...)<non-args,
- // like a space or a comma>). If so, delete the non-args
- // that come before the right parenthesis. Leaving an
- // extra comma here produces invalid code. (See
- // golang/go#74709)
- if arg.End() < conv.Rparen {
- edits = append(edits, analysis.TextEdit{
- Pos: arg.End(),
- End: conv.Rparen,
- })
- }
+ if !analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(curCall), versions.Go1_19) {
+ continue
}
pass.Report(analysis.Diagnostic{
Pos: conv.Pos(),
@@ -110,3 +120,43 @@ func fmtappendf(pass *analysis.Pass) (any, error) {
}
return nil, nil
}
+
+// mayFormatEmpty reports whether fmt.Sprintf might produce an empty string.
+// It returns false in the following two cases:
+// 1. formatStr contains non-operation characters.
+// 2. formatStr contains formatting verbs besides s, v, x, X (verbs which may
+// produce empty results)
+//
+// In all other cases it returns true.
+func mayFormatEmpty(formatStr string) bool {
+ if formatStr == "" {
+ return true
+ }
+ operations, err := fmtstr.Parse(formatStr, 0)
+ if err != nil {
+ // If formatStr is malformed, the printf analyzer will report a
+ // diagnostic, so we can ignore this error.
+ // Calling Parse on a string without % formatters also returns an error,
+ // in which case we can safely return false.
+ return false
+ }
+ totalOpsLen := 0
+ for _, op := range operations {
+ totalOpsLen += len(op.Text)
+ if !strings.ContainsRune("svxX", rune(op.Verb.Verb)) && op.Prec.Fixed != 0 {
+ // A non [s, v, x, X] formatter with non-zero precision cannot
+ // produce an empty string.
+ return false
+ }
+ }
+ // If the format string contains non-operation characters, it cannot produce
+ // the empty string.
+ if totalOpsLen != len(formatStr) {
+ return false
+ }
+ // If we get here, it means that all formatting verbs are %s, %v, %x, %X,
+ // and there are no additional non-operation characters. We conservatively
+ // report that this may format as an empty string, ignoring uses of
+ // precision and the values of the formatter args.
+ return true
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go
index 23a0977f21..b4b8dba3d1 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go
@@ -147,6 +147,13 @@ func minmax(pass *analysis.Pass) (any, error) {
lhs0 := fassign.Lhs[0]
rhs0 := fassign.Rhs[0]
+ // If the assignment occurs within a select
+ // comms clause (like "case lhs0 := <-rhs0:"),
+ // there's no way of rewriting it into a min/max call.
+ if prev.ParentEdgeKind() == edge.CommClause_Comm {
+ return
+ }
+
if astutil.EqualSyntax(lhs, lhs0) {
if astutil.EqualSyntax(rhs, a) && (astutil.EqualSyntax(rhs0, b) || astutil.EqualSyntax(lhs0, b)) {
sign = +sign
@@ -209,7 +216,7 @@ func minmax(pass *analysis.Pass) (any, error) {
// (This case would require introducing another block
// if cond { ... } else { if a < b { lhs = rhs } }
// and checking that there is no following "else".)
- if astutil.IsChildOf(curIfStmt, edge.IfStmt_Else) {
+ if curIfStmt.ParentEdgeKind() == edge.IfStmt_Else {
continue
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go
index f2947b1d88..42519eab53 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go
@@ -20,7 +20,9 @@ import (
"golang.org/x/tools/go/ast/edge"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/analysis/analyzerutil"
- "golang.org/x/tools/internal/astutil"
+ "golang.org/x/tools/internal/refactor"
+ "golang.org/x/tools/internal/typesinternal/typeindex"
+
"golang.org/x/tools/internal/moreiters"
"golang.org/x/tools/internal/packagepath"
"golang.org/x/tools/internal/stdlib"
@@ -33,6 +35,7 @@ var doc string
// Suite lists all modernize analyzers.
var Suite = []*analysis.Analyzer{
AnyAnalyzer,
+ atomicTypesAnalyzer,
// AppendClippedAnalyzer, // not nil-preserving!
// BLoopAnalyzer, // may skew benchmark results, see golang/go#74967
FmtAppendfAnalyzer,
@@ -54,7 +57,7 @@ var Suite = []*analysis.Analyzer{
StringsBuilderAnalyzer,
TestingContextAnalyzer,
unsafeFuncsAnalyzer,
- WaitGroupAnalyzer,
+ WaitGroupGoAnalyzer,
}
// -- helpers --
@@ -114,7 +117,7 @@ func within(pass *analysis.Pass, pkgs ...string) bool {
// unparenEnclosing removes enclosing parens from cur in
// preparation for a call to [Cursor.ParentEdge].
func unparenEnclosing(cur inspector.Cursor) inspector.Cursor {
- for astutil.IsChildOf(cur, edge.ParenExpr_X) {
+ for cur.ParentEdgeKind() == edge.ParenExpr_X {
cur = cur.Parent()
}
return cur
@@ -144,3 +147,37 @@ func lookup(info *types.Info, cur inspector.Cursor, name string) types.Object {
}
func first[T any](x T, _ any) T { return x }
+
+// freshName returns a fresh name at the given pos and scope based on preferredName.
+// It generates a new name using refactor.FreshName only if:
+// (a) the preferred name is already defined at definedCur, and
+// (b) there are references to it from within usedCur.
+// If useAfterPos.IsValid(), the references must be after
+// useAfterPos within usedCur in order to warrant a fresh name.
+// Otherwise, it returns preferredName, since shadowing is valid in this case.
+// (declaredCur and usedCur may be identical in some use cases).
+func freshName(info *types.Info, index *typeindex.Index, scope *types.Scope, pos token.Pos, defCur inspector.Cursor, useCur inspector.Cursor, useAfterPos token.Pos, preferredName string) string {
+ obj := lookup(info, defCur, preferredName)
+ if obj == nil {
+ // preferredName has not been declared here.
+ return preferredName
+ }
+ for use := range index.Uses(obj) {
+ if useCur.Contains(use) && use.Node().Pos() >= useAfterPos {
+ return refactor.FreshName(scope, pos, preferredName)
+ }
+ }
+ // Name is taken but not used in the given block; shadowing is acceptable.
+ return preferredName
+}
+
+// isLocal reports whether obj is local to some function.
+// Precondition: not a struct field or interface method.
+func isLocal(obj types.Object) bool {
+ // [... 5=stmt 4=func 3=file 2=pkg 1=universe]
+ var depth int
+ for scope := obj.Parent(); scope != nil; scope = scope.Parent() {
+ depth++
+ }
+ return depth >= 4
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go
index 57b502ab80..ff6c90551e 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go
@@ -29,6 +29,8 @@ func init() {
func plusbuild(pass *analysis.Pass) (any, error) {
check := func(f *ast.File) {
+ // "//go:build" directives were added in go1.17, but
+ // we didn't start eliminating +build directives till go1.18.
if !analyzerutil.FileUsesGoVersion(pass, f, versions.Go1_18) {
return
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go
index 600c561fe3..03c7fd4f3f 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go
@@ -18,7 +18,6 @@ import (
"golang.org/x/tools/internal/analysis/analyzerutil"
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
"golang.org/x/tools/internal/astutil"
- "golang.org/x/tools/internal/moreiters"
"golang.org/x/tools/internal/typesinternal"
"golang.org/x/tools/internal/typesinternal/typeindex"
"golang.org/x/tools/internal/versions"
@@ -142,15 +141,12 @@ func rangeint(pass *analysis.Pass) (any, error) {
// Find references to i within the loop body.
v := info.ObjectOf(index).(*types.Var)
- // TODO(adonovan): use go1.25 v.Kind() == types.PackageVar
- if typesinternal.IsPackageLevel(v) {
+ switch v.Kind() {
+ case types.PackageVar:
continue nextLoop
- }
-
- // If v is a named result, it is implicitly
- // used after the loop (go.dev/issue/76880).
- // TODO(adonovan): use go1.25 v.Kind() == types.ResultVar.
- if moreiters.Contains(enclosingSignature(curLoop, info).Results().Variables(), v) {
+ case types.ResultVar:
+ // If v is a named result, it is implicitly
+ // used after the loop (go.dev/issue/76880).
continue nextLoop
}
@@ -230,7 +226,7 @@ func rangeint(pass *analysis.Pass) (any, error) {
// such as "const limit = 1e3", its effective type may
// differ between the two forms.
// In a for loop, it must be comparable with int i,
- // for i := 0; i < limit; i++
+ // for i := 0; i < limit; i++ {}
// but in a range loop it would become a float,
// for i := range limit {}
// which is a type error. We need to convert it to int
@@ -249,9 +245,24 @@ func rangeint(pass *analysis.Pass) (any, error) {
beforeLimit, afterLimit = fmt.Sprintf("%s(", types.TypeString(tVar, qual)), ")"
info2 := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
if types.CheckExpr(pass.Fset, pass.Pkg, limit.Pos(), limit, info2) == nil {
- tLimit := types.Default(info2.TypeOf(limit))
- if types.AssignableTo(tLimit, tVar) {
- beforeLimit, afterLimit = "", ""
+ tLimit := info2.TypeOf(limit)
+ // Eliminate conversion when safe.
+ //
+ // Redundant conversions are not only unsightly but may in some cases cause
+ // architecture-specific types (e.g. syscall.Timespec.Nsec) to be inserted
+ // into otherwise portable files.
+ //
+ // The operand must have an integer type (not, say, '1e6')
+ // even when assigning to an existing integer variable.
+ if isInteger(tLimit) {
+ // When declaring a new var from an untyped limit,
+ // the limit's default type is what matters.
+ if init.Tok != token.ASSIGN {
+ tLimit = types.Default(tLimit)
+ }
+ if types.AssignableTo(tLimit, tVar) {
+ beforeLimit, afterLimit = "", ""
+ }
}
}
}
@@ -316,10 +327,10 @@ func isScalarLvalue(info *types.Info, curId inspector.Cursor) bool {
cur := curId
// Strip enclosing parens.
- ek, _ := cur.ParentEdge()
+ ek := cur.ParentEdgeKind()
for ek == edge.ParenExpr_X {
cur = cur.Parent()
- ek, _ = cur.ParentEdge()
+ ek = cur.ParentEdgeKind()
}
switch ek {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go
index 2611f6cf09..fb1f2e2efc 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go
@@ -47,6 +47,14 @@ func reflecttypefor(pass *analysis.Pass) (any, error) {
// Have: reflect.TypeOf(expr)
expr := call.Args[0]
+
+ // reflect.TypeFor cannot be instantiated with an untyped nil.
+ // We use type information rather than checking the identifier name
+ // to correctly handle edge cases where "nil" is shadowed (e.g. nil := "nil").
+ if info.Types[expr].IsNil() {
+ continue
+ }
+
if !typesinternal.NoEffects(info, expr) {
continue // don't eliminate operand: may have effects
}
@@ -54,20 +62,20 @@ func reflecttypefor(pass *analysis.Pass) (any, error) {
t := info.TypeOf(expr)
var edits []analysis.TextEdit
- // Special case for TypeOf((*T)(nil)).Elem(),
- // needed when T is an interface type.
- if astutil.IsChildOf(curCall, edge.SelectorExpr_X) {
+ // Special cases for TypeOf((*T)(nil)).Elem(), and
+ // TypeOf([]T(nil)).Elem(), needed when T is an interface type.
+ if curCall.ParentEdgeKind() == edge.SelectorExpr_X {
curSel := unparenEnclosing(curCall).Parent()
- if astutil.IsChildOf(curSel, edge.CallExpr_Fun) {
- call2 := unparenEnclosing(curSel).Parent().Node().(*ast.CallExpr)
+ if curSel.ParentEdgeKind() == edge.CallExpr_Fun {
+ call2 := unparenEnclosing(curSel).Parent().Node().(*ast.CallExpr) // potentially .Elem()
obj := typeutil.Callee(info, call2)
if typesinternal.IsMethodNamed(obj, "reflect", "Type", "Elem") {
- if ptr, ok := t.(*types.Pointer); ok {
- // Have: TypeOf(expr).Elem() where expr : *T
- t = ptr.Elem()
- // reflect.TypeOf(expr).Elem()
- // -------
- // reflect.TypeOf(expr)
+ // reflect.TypeOf(expr).Elem()
+ // -------
+ // reflect.TypeOf(expr)
+ if typ, hasElem := t.(interface{ Elem() types.Type }); hasElem {
+ // Have: TypeOf(expr).Elem() where expr is *T, []T, [k]T, chan T, map[K]T, etc.
+ t = typ.Elem()
edits = []analysis.TextEdit{{
Pos: call.End(),
End: call2.End(),
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go
index 3b32685266..c1d42188f6 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go
@@ -231,7 +231,9 @@ func slicescontains(pass *analysis.Pass) (any, error) {
// that might affected by melting down the loop.
//
// TODO(adonovan): relax check by analyzing branch target.
+ numBodyStmts := 0
for curBodyStmt := range curBody.Children() {
+ numBodyStmts += 1
if curBodyStmt != curLastStmt {
for range curBodyStmt.Preorder((*ast.BranchStmt)(nil), (*ast.ReturnStmt)(nil)) {
return
@@ -292,7 +294,16 @@ func slicescontains(pass *analysis.Pass) (any, error) {
case *ast.BranchStmt:
if lastStmt.Tok == token.BREAK && lastStmt.Label == nil { // unlabeled break
// Have: for ... { if ... { stmts; break } }
-
+ if numBodyStmts == 1 {
+ // If the only stmt in the body is an unlabeled "break" that
+ // will get deleted in the fix, don't suggest a fix, as it
+ // produces confusing code:
+ // if slices.Contains(slice, f) {}
+ // Explicitly discarding the result isn't much better:
+ // _ = slices.Contains(slice, f) // just for effects
+ // See https://go.dev/issue/77677.
+ return
+ }
var prevStmt ast.Stmt // previous statement to range (if any)
if curPrev, ok := curRange.PrevSibling(); ok {
// If the RangeStmt's previous sibling is a Stmt,
@@ -316,12 +327,13 @@ func slicescontains(pass *analysis.Pass) (any, error) {
len(assign.Rhs) == 1 {
// Have: body={ lhs = rhs; break }
+ assignBool := isTrueOrFalse(info, assign.Rhs[0])
if prevAssign, ok := prevStmt.(*ast.AssignStmt); ok &&
len(prevAssign.Lhs) == 1 &&
len(prevAssign.Rhs) == 1 &&
+ assignBool != 0 && // non-bool assignments don't apply in this case
astutil.EqualSyntax(prevAssign.Lhs[0], assign.Lhs[0]) &&
- isTrueOrFalse(info, assign.Rhs[0]) ==
- -isTrueOrFalse(info, prevAssign.Rhs[0]) {
+ assignBool == -isTrueOrFalse(info, prevAssign.Rhs[0]) {
// Have:
// lhs = false
@@ -332,7 +344,7 @@ func slicescontains(pass *analysis.Pass) (any, error) {
// TODO(adonovan):
// - support "var lhs bool = false" and variants.
// - allow the break to be omitted.
- neg := cond(isTrueOrFalse(info, assign.Rhs[0]) < 0, "!", "")
+ neg := cond(assignBool < 0, "!", "")
report([]analysis.TextEdit{
// Replace "rhs" of previous assignment by [!]slices.Contains(...)
{
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go
index 95f2127fbf..86e1c8fd42 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go
@@ -18,7 +18,6 @@ import (
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/goplsexport"
- "golang.org/x/tools/internal/refactor"
"golang.org/x/tools/internal/stdlib"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
@@ -182,22 +181,9 @@ func stditerators(pass *analysis.Pass) (any, error) {
}
loop := curBody.Parent().Node()
-
- // Choose a fresh name only if
- // (a) the preferred name is already declared here, and
- // (b) there are references to it from the loop body.
- // TODO(adonovan): this pattern also appears in errorsastype,
- // and is wanted elsewhere; factor.
- name := row.elemname
- if v := lookup(info, curBody, name); v != nil {
- // is it free in body?
- for curUse := range index.Uses(v) {
- if curBody.Contains(curUse) {
- name = refactor.FreshName(info.Scopes[loop], loop.Pos(), name)
- break
- }
- }
- }
+ // We generate a new name only if the preferred name is already declared here
+ // and is used within the loop body.
+ name := freshName(info, index, info.Scopes[loop], loop.Pos(), curBody, curBody, token.NoPos, row.elemname)
return name, nil
}
@@ -220,7 +206,7 @@ func stditerators(pass *analysis.Pass) (any, error) {
)
// Analyze enclosing loop.
- switch first(curLenCall.ParentEdge()) {
+ switch curLenCall.ParentEdgeKind() {
case edge.BinaryExpr_Y:
// pattern 1: for i := 0; i < x.Len(); i++ { ... }
var (
@@ -228,7 +214,7 @@ func stditerators(pass *analysis.Pass) (any, error) {
cmp = curCmp.Node().(*ast.BinaryExpr)
)
if cmp.Op != token.LSS ||
- !astutil.IsChildOf(curCmp, edge.ForStmt_Cond) {
+ curCmp.ParentEdgeKind() != edge.ForStmt_Cond {
continue
}
if id, ok := cmp.X.(*ast.Ident); ok {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go
index 3cb266986d..e89baa9b0e 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go
@@ -22,7 +22,6 @@ import (
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/refactor"
- "golang.org/x/tools/internal/typesinternal"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
@@ -57,7 +56,7 @@ func stringsbuilder(pass *analysis.Pass) (any, error) {
assign := curAssign.Node().(*ast.AssignStmt)
if assign.Tok == token.ADD_ASSIGN && is[*ast.Ident](assign.Lhs[0]) {
if v, ok := pass.TypesInfo.Uses[assign.Lhs[0].(*ast.Ident)].(*types.Var); ok &&
- !typesinternal.IsPackageLevel(v) && // TODO(adonovan): in go1.25, use v.Kind() == types.LocalVar &&
+ v.Kind() == types.LocalVar &&
types.Identical(v.Type(), builtinString.Type()) {
candidates[v] = true
}
@@ -102,7 +101,7 @@ nextcand:
continue
}
- ek, _ := def.ParentEdge()
+ ek := def.ParentEdgeKind()
if ek == edge.AssignStmt_Lhs &&
len(def.Parent().Node().(*ast.AssignStmt).Lhs) == 1 {
// Have: s := expr
@@ -254,8 +253,8 @@ nextcand:
// var s string
// for ... { s += expr }
//
- // - The final use of s must be as an rvalue (e.g. use(s), not &s).
- // This will become s.String().
+ // - All uses of s after the last += must be rvalue uses (e.g. use(s), not &s).
+ // Each of these will become s.String().
//
// Perhaps surprisingly, it is fine for there to be an
// intervening loop or lambda w.r.t. the declaration of s:
@@ -270,19 +269,14 @@ nextcand:
var (
numLoopAssigns int // number of += assignments within a loop
loopAssign *ast.AssignStmt // first += assignment within a loop
- seenRvalueUse bool // => we've seen the sole final use of s as an rvalue
+ seenRvalueUse bool // => we've seen at least one rvalue use of s
)
for curUse := range index.Uses(v) {
// Strip enclosing parens around Ident.
- ek, _ := curUse.ParentEdge()
+ ek := curUse.ParentEdgeKind()
for ek == edge.ParenExpr_X {
curUse = curUse.Parent()
- ek, _ = curUse.ParentEdge()
- }
-
- // The rvalueUse must be the lexically last use.
- if seenRvalueUse {
- continue nextcand
+ ek = curUse.ParentEdgeKind()
}
// intervening reports whether cur has an ancestor of
@@ -297,6 +291,11 @@ nextcand:
}
if ek == edge.AssignStmt_Lhs {
+ // After an rvalue use, no more assignments are allowed.
+ if seenRvalueUse {
+ continue nextcand
+ }
+
assign := curUse.Parent().Node().(*ast.AssignStmt)
if assign.Tok != token.ADD_ASSIGN {
continue nextcand
@@ -317,9 +316,9 @@ nextcand:
// ------------- -
// s.WriteString(expr)
edits = append(edits, []analysis.TextEdit{
- // replace += with .WriteString()
+ // replace " += " with ".WriteString("
{
- Pos: assign.TokPos,
+ Pos: assign.Lhs[0].End(),
End: assign.Rhs[0].Pos(),
NewText: []byte(".WriteString("),
},
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go
index 62088f0e91..6192c56fa3 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go
@@ -22,7 +22,7 @@ import (
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/goplsexport"
- "golang.org/x/tools/internal/refactor"
+ "golang.org/x/tools/internal/moreiters"
"golang.org/x/tools/internal/typesinternal"
"golang.org/x/tools/internal/typesinternal/typeindex"
"golang.org/x/tools/internal/versions"
@@ -124,6 +124,8 @@ func stringscut(pass *analysis.Pass) (any, error) {
bytesIndexByte = index.Object("bytes", "IndexByte")
)
+ scopeFixCount := make(map[*types.Scope]int) // the number of times we have offered a fix within a given scope in the current pass
+
for _, obj := range []types.Object{
stringsIndex,
stringsIndexByte,
@@ -183,7 +185,7 @@ func stringscut(pass *analysis.Pass) (any, error) {
// len(substr)]), then we can replace the call to Index()
// with a call to Cut() and use the returned ok, before,
// and after variables accordingly.
- negative, nonnegative, beforeSlice, afterSlice := checkIdxUses(pass.TypesInfo, index.Uses(iObj), s, substr)
+ negative, nonnegative, beforeSlice, afterSlice := checkIdxUses(pass.TypesInfo, index.Uses(iObj), s, substr, iObj)
// Either there are no uses of before, after, or ok, or some use
// of i does not match our criteria - don't suggest a fix.
@@ -194,14 +196,48 @@ func stringscut(pass *analysis.Pass) (any, error) {
// If the only uses are ok and !ok, don't suggest a Cut() fix - these should be using Contains()
isContains := (len(negative) > 0 || len(nonnegative) > 0) && len(beforeSlice) == 0 && len(afterSlice) == 0
+ enclosingBlock, ok := moreiters.First(curCall.Enclosing((*ast.BlockStmt)(nil)))
+ if !ok {
+ continue
+ }
scope := iObj.Parent()
- var (
- // TODO(adonovan): avoid FreshName when not needed; see errorsastype.
- okVarName = refactor.FreshName(scope, iIdent.Pos(), "ok")
- beforeVarName = refactor.FreshName(scope, iIdent.Pos(), "before")
- afterVarName = refactor.FreshName(scope, iIdent.Pos(), "after")
- foundVarName = refactor.FreshName(scope, iIdent.Pos(), "found") // for Contains()
- )
+ // Generate fresh names for ok, before, after, found, but only if
+ // they are defined by the end of the enclosing block and used
+ // within the enclosing block after the Index call. We need a Cursor
+ // for the end of the enclosing block, but we can't just find the
+ // Cursor at scope.End() because it corresponds to the entire
+ // enclosingBlock. Instead, get the last child of the enclosing
+ // block.
+ lastStmtCur, _ := enclosingBlock.LastChild()
+ lastStmt := lastStmtCur.Node()
+
+ fresh := func(preferred string) string {
+ return freshName(info, index, scope, lastStmt.End(), lastStmtCur, enclosingBlock, iIdent.Pos(), preferred)
+ }
+
+ var okVarName, beforeVarName, afterVarName, foundVarName string
+ if isContains {
+ foundVarName = fresh("found")
+ } else {
+ okVarName = fresh("ok")
+ beforeVarName = fresh("before")
+ afterVarName = fresh("after")
+ }
+
+ // If we are already suggesting a fix within the index's scope, we
+ // must get fresh names for before, after and ok.
+ // This is a specific symptom of the general problem that analyzers
+ // can generate conflicting fixes.
+ if scopeFixCount[scope] > 0 {
+ suffix := scopeFixCount[scope] - 1 // start at 0
+ if isContains {
+ foundVarName = fresh(fmt.Sprintf("%s%d", foundVarName, suffix))
+ } else {
+ okVarName = fresh(fmt.Sprintf("%s%d", okVarName, suffix))
+ beforeVarName = fresh(fmt.Sprintf("%s%d", beforeVarName, suffix))
+ afterVarName = fresh(fmt.Sprintf("%s%d", afterVarName, suffix))
+ }
+ }
// If there will be no uses of ok, before, or after, use the
// blank identifier instead.
@@ -313,6 +349,7 @@ func stringscut(pass *analysis.Pass) (any, error) {
}...)
}
}
+ scopeFixCount[scope]++
pass.Report(analysis.Diagnostic{
Pos: indexCall.Fun.Pos(),
End: indexCall.Fun.End(),
@@ -374,14 +411,31 @@ func indexArgValid(info *types.Info, index *typeindex.Index, expr ast.Expr, afte
// 2. nonnegative - a condition equivalent to i >= 0
// 3. beforeSlice - a slice of `s` that matches either s[:i], s[0:i]
// 4. afterSlice - a slice of `s` that matches one of: s[i+len(substr):], s[len(substr) + i:], s[i + const], s[k + i] (where k = len(substr))
-func checkIdxUses(info *types.Info, uses iter.Seq[inspector.Cursor], s, substr ast.Expr) (negative, nonnegative, beforeSlice, afterSlice []ast.Expr) {
+//
+// Additionally, all beforeSlice and afterSlice uses must be dominated by a
+// nonnegative guard on i (i.e., inside the body of an if whose condition
+// checks i >= 0, or in the else of a negative check, or after an
+// early-return negative check). This ensures that the rewrite from
+// s[i+len(sep):] to "after" preserves semantics, since when i == -1,
+// s[i+len(sep):] may yield a valid substring (e.g. s[0:] for single-byte
+// separators), but "after" would be "".
+//
+// When len(substr)==1, it's safe to use s[i+1:] even when i < 0.
+// Otherwise, each replacement of s[i+1:] must be guarded by a check
+// that i is nonnegative.
+func checkIdxUses(info *types.Info, uses iter.Seq[inspector.Cursor], s, substr ast.Expr, iObj types.Object) (negative, nonnegative, beforeSlice, afterSlice []ast.Expr) {
+ requireGuard := true
+ if l := constSubstrLen(info, substr); l != -1 && l != 1 {
+ requireGuard = false
+ }
+
use := func(cur inspector.Cursor) bool {
- ek, _ := cur.ParentEdge()
+ ek := cur.ParentEdgeKind()
n := cur.Parent().Node()
switch ek {
case edge.BinaryExpr_X, edge.BinaryExpr_Y:
check := n.(*ast.BinaryExpr)
- switch checkIdxComparison(info, check) {
+ switch checkIdxComparison(info, check, iObj) {
case -1:
negative = append(negative, check)
return true
@@ -397,10 +451,10 @@ func checkIdxUses(info *types.Info, uses iter.Seq[inspector.Cursor], s, substr a
if slice, ok := cur.Parent().Parent().Node().(*ast.SliceExpr); ok &&
sameObject(info, s, slice.X) &&
slice.Max == nil {
- if isBeforeSlice(info, ek, slice) {
+ if isBeforeSlice(info, ek, slice) && (!requireGuard || isSliceIndexGuarded(info, cur, iObj)) {
beforeSlice = append(beforeSlice, slice)
return true
- } else if isAfterSlice(info, ek, slice, substr) {
+ } else if isAfterSlice(info, ek, slice, substr) && (!requireGuard || isSliceIndexGuarded(info, cur, iObj)) {
afterSlice = append(afterSlice, slice)
return true
}
@@ -410,10 +464,10 @@ func checkIdxUses(info *types.Info, uses iter.Seq[inspector.Cursor], s, substr a
// Check that the thing being sliced is s and that the slice doesn't
// have a max index.
if sameObject(info, s, slice.X) && slice.Max == nil {
- if isBeforeSlice(info, ek, slice) {
+ if isBeforeSlice(info, ek, slice) && (!requireGuard || isSliceIndexGuarded(info, cur, iObj)) {
beforeSlice = append(beforeSlice, slice)
return true
- } else if isAfterSlice(info, ek, slice, substr) {
+ } else if isAfterSlice(info, ek, slice, substr) && (!requireGuard || isSliceIndexGuarded(info, cur, iObj)) {
afterSlice = append(afterSlice, slice)
return true
}
@@ -435,7 +489,7 @@ func checkIdxUses(info *types.Info, uses iter.Seq[inspector.Cursor], s, substr a
// considered.
func hasModifyingUses(info *types.Info, uses iter.Seq[inspector.Cursor], afterPos token.Pos) bool {
for curUse := range uses {
- ek, _ := curUse.ParentEdge()
+ ek := curUse.ParentEdgeKind()
if ek == edge.AssignStmt_Lhs {
if curUse.Node().Pos() <= afterPos {
continue
@@ -465,8 +519,15 @@ func hasModifyingUses(info *types.Info, uses iter.Seq[inspector.Cursor], afterPo
// Since strings.Index returns exactly -1 if the substring is not found, we
// don't need to handle expressions like i <= -3.
// We return 0 if the expression does not match any of these options.
-// We assume that a check passed to checkIdxComparison has i as one of its operands.
-func checkIdxComparison(info *types.Info, check *ast.BinaryExpr) int {
+func checkIdxComparison(info *types.Info, check *ast.BinaryExpr, iObj types.Object) int {
+ isI := func(e ast.Expr) bool {
+ id, ok := e.(*ast.Ident)
+ return ok && info.Uses[id] == iObj
+ }
+ if !isI(check.X) && !isI(check.Y) {
+ return 0
+ }
+
// Ensure that the constant (if any) is on the right.
x, op, y := check.X, check.Op, check.Y
if info.Types[x].Value != nil {
@@ -515,44 +576,49 @@ func isBeforeSlice(info *types.Info, ek edge.Kind, slice *ast.SliceExpr) bool {
return ek == edge.SliceExpr_High && (slice.Low == nil || isZeroIntConst(info, slice.Low))
}
-// isAfterSlice reports whether the SliceExpr is of the form s[i+len(substr):],
-// or s[i + k:] where k is a const is equal to len(substr).
-func isAfterSlice(info *types.Info, ek edge.Kind, slice *ast.SliceExpr, substr ast.Expr) bool {
- lowExpr, ok := slice.Low.(*ast.BinaryExpr)
- if !ok || slice.High != nil {
- return false
- }
- // Returns true if the expression is a call to len(substr).
- isLenCall := func(expr ast.Expr) bool {
- call, ok := expr.(*ast.CallExpr)
- if !ok || len(call.Args) != 1 {
- return false
- }
- return sameObject(info, substr, call.Args[0]) && typeutil.Callee(info, call) == builtinLen
- }
-
+// constSubstrLen returns the constant length of substr, or -1 if unknown.
+func constSubstrLen(info *types.Info, substr ast.Expr) int {
// Handle len([]byte(substr))
- if is[*ast.CallExpr](substr) {
- call := substr.(*ast.CallExpr)
+ if call, ok := substr.(*ast.CallExpr); ok {
tv := info.Types[call.Fun]
if tv.IsType() && types.Identical(tv.Type, byteSliceType) {
// Only one arg in []byte conversion.
substr = call.Args[0]
}
}
- substrLen := -1
substrVal := info.Types[substr].Value
if substrVal != nil {
switch substrVal.Kind() {
case constant.String:
- substrLen = len(constant.StringVal(substrVal))
+ return len(constant.StringVal(substrVal))
case constant.Int:
// constant.Value is a byte literal, e.g. bytes.IndexByte(_, 'a')
// or a numeric byte literal, e.g. bytes.IndexByte(_, 65)
- substrLen = 1
+ // ([]byte(rune) is not legal.)
+ return 1
+ }
+ }
+ return -1
+}
+
+// isAfterSlice reports whether the SliceExpr is of the form s[i+len(substr):],
+// or s[i + k:] where k is a const is equal to len(substr).
+func isAfterSlice(info *types.Info, ek edge.Kind, slice *ast.SliceExpr, substr ast.Expr) bool {
+ lowExpr, ok := slice.Low.(*ast.BinaryExpr)
+ if !ok || slice.High != nil {
+ return false
+ }
+ // Returns true if the expression is a call to len(substr).
+ isLenCall := func(expr ast.Expr) bool {
+ call, ok := expr.(*ast.CallExpr)
+ if !ok || len(call.Args) != 1 {
+ return false
}
+ return sameObject(info, substr, call.Args[0]) && typeutil.Callee(info, call) == builtinLen
}
+ substrLen := constSubstrLen(info, substr)
+
switch ek {
case edge.BinaryExpr_X:
kVal := info.Types[lowExpr.Y].Value
@@ -578,6 +644,75 @@ func isAfterSlice(info *types.Info, ek edge.Kind, slice *ast.SliceExpr, substr a
return false
}
+// isSliceIndexGuarded reports whether a use of the index variable i (at the given cursor)
+// inside a slice expression is dominated by a nonnegative guard.
+// A use is considered guarded if any of the following are true:
+// - It is inside the Body of an IfStmt whose condition is a nonnegative check on i.
+// - It is inside the Else of an IfStmt whose condition is a negative check on i.
+// - It is preceded (in the same block) by an IfStmt whose condition is a
+// negative check on i with a terminating body (e.g., early return).
+//
+// Conversely, a use is immediately rejected if:
+// - It is inside the Body of an IfStmt whose condition is a negative check on i.
+// - It is inside the Else of an IfStmt whose condition is a nonnegative check on i.
+//
+// We have already checked (see [hasModifyingUses]) that there are no
+// intervening uses (incl. via aliases) of i that might alter its value.
+func isSliceIndexGuarded(info *types.Info, cur inspector.Cursor, iObj types.Object) bool {
+ for anc := range cur.Enclosing() {
+ switch anc.ParentEdgeKind() {
+ case edge.IfStmt_Body, edge.IfStmt_Else:
+ ifStmt := anc.Parent().Node().(*ast.IfStmt)
+ check := condChecksIdx(info, ifStmt.Cond, iObj)
+ if anc.ParentEdgeKind() == edge.IfStmt_Else {
+ check = -check
+ }
+ if check > 0 {
+ return true // inside nonnegative-guarded block (i >= 0 here)
+ }
+ if check < 0 {
+ return false // inside negative-guarded block (i < 0 here)
+ }
+ case edge.BlockStmt_List:
+ // Check preceding siblings for early-return negative checks.
+ for sib, ok := anc.PrevSibling(); ok; sib, ok = sib.PrevSibling() {
+ ifStmt, ok := sib.Node().(*ast.IfStmt)
+ if ok && condChecksIdx(info, ifStmt.Cond, iObj) < 0 && bodyTerminates(ifStmt.Body) {
+ return true // preceded by early-return negative check
+ }
+ }
+ case edge.FuncDecl_Body, edge.FuncLit_Body:
+ return false // stop at function boundary
+ }
+ }
+ return false
+}
+
+// condChecksIdx reports whether cond is a BinaryExpr that checks
+// the index variable iObj for negativity or non-negativity.
+// Returns -1 for negative (e.g. i < 0), +1 for nonnegative (e.g. i >= 0), 0 otherwise.
+func condChecksIdx(info *types.Info, cond ast.Expr, iObj types.Object) int {
+ binExpr, ok := cond.(*ast.BinaryExpr)
+ if !ok {
+ return 0
+ }
+ return checkIdxComparison(info, binExpr, iObj)
+}
+
+// bodyTerminates reports whether the given block statement unconditionally
+// terminates execution (via return, break, continue, or goto).
+func bodyTerminates(block *ast.BlockStmt) bool {
+ if len(block.List) == 0 {
+ return false
+ }
+ last := block.List[len(block.List)-1]
+ switch last.(type) {
+ case *ast.ReturnStmt, *ast.BranchStmt:
+ return true // return, break, continue, goto
+ }
+ return false
+}
+
// sameObject reports whether we know that the expressions resolve to the same object.
func sameObject(info *types.Info, expr1, expr2 ast.Expr) bool {
if ident1, ok := expr1.(*ast.Ident); ok {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscutprefix.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscutprefix.go
index 7dc11308dd..ae63454005 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscutprefix.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscutprefix.go
@@ -201,8 +201,7 @@ func stringscutprefix(pass *analysis.Pass) (any, error) {
if astutil.EqualSyntax(lhs, bin.X) && astutil.EqualSyntax(call.Args[0], bin.Y) ||
(astutil.EqualSyntax(lhs, bin.Y) && astutil.EqualSyntax(call.Args[0], bin.X)) {
- // TODO(adonovan): avoid FreshName when not needed; see errorsastype.
- okVarName := refactor.FreshName(info.Scopes[ifStmt], ifStmt.Pos(), "ok")
+ okVarName := freshName(info, index, info.Scopes[ifStmt], ifStmt.Pos(), curIfStmt, curIfStmt, token.NoPos, "ok")
// Have one of:
// if rest := TrimPrefix(s, prefix); rest != s { (ditto Suffix)
// if rest := TrimPrefix(s, prefix); s != rest { (ditto Suffix)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go
index d3549e7103..191eba95c9 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go
@@ -56,11 +56,6 @@ func unsafefuncs(pass *analysis.Pass) (any, error) {
tUnsafePointer = types.Typ[types.UnsafePointer]
)
- isInteger := func(t types.Type) bool {
- basic, ok := t.Underlying().(*types.Basic)
- return ok && basic.Info()&types.IsInteger != 0
- }
-
// isConversion reports whether e is a conversion T(x).
// If so, it returns T and x.
isConversion := func(curExpr inspector.Cursor) (t types.Type, x inspector.Cursor) {
@@ -88,7 +83,7 @@ func unsafefuncs(pass *analysis.Pass) (any, error) {
if sum, ok := curSum.Node().(*ast.BinaryExpr); ok &&
sum.Op == token.ADD &&
types.Identical(info.TypeOf(sum.X), types.Typ[types.Uintptr]) &&
- astutil.IsChildOf(curSum, edge.CallExpr_Args) {
+ curSum.ParentEdgeKind() == edge.CallExpr_Args {
// Have: sum ≡ T(x:...uintptr... + y:...uintptr...)
curX := curSum.ChildAt(edge.BinaryExpr_X, -1)
curY := curSum.ChildAt(edge.BinaryExpr_Y, -1)
@@ -102,7 +97,7 @@ func unsafefuncs(pass *analysis.Pass) (any, error) {
// Is sum.x converted from unsafe.Pointer?
_, curPtr := isConversion(curX)
- if !astutil.CursorValid(curPtr) {
+ if !curPtr.Valid() {
continue
}
ptr := curPtr.Node().(ast.Expr)
@@ -208,3 +203,8 @@ func deleteConv(cur inspector.Cursor) []analysis.TextEdit {
},
}
}
+
+func isInteger(t types.Type) bool {
+ basic, ok := t.Underlying().(*types.Basic)
+ return ok && basic.Info()&types.IsInteger != 0
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroup.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroupgo.go
index abf5885cee..9af2d3bdc7 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroup.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroupgo.go
@@ -22,18 +22,18 @@ import (
"golang.org/x/tools/internal/versions"
)
-var WaitGroupAnalyzer = &analysis.Analyzer{
- Name: "waitgroup",
- Doc: analyzerutil.MustExtractDoc(doc, "waitgroup"),
+var WaitGroupGoAnalyzer = &analysis.Analyzer{
+ Name: "waitgroupgo",
+ Doc: analyzerutil.MustExtractDoc(doc, "waitgroupgo"),
Requires: []*analysis.Analyzer{
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
Run: waitgroup,
- URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#waitgroup",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#waitgroupgo",
}
-// The waitgroup pass replaces old more complex code with
+// The waitgroupgo pass replaces old more complex code with
// go1.25 added API WaitGroup.Go.
//
// Patterns:
@@ -97,6 +97,9 @@ func waitgroup(pass *analysis.Pass) (any, error) {
if !ok || len(goStmt.Call.Args) != 0 {
continue // go argument is not func(){...}()
}
+ if lit.Type.Results != nil && len(lit.Type.Results.List) > 0 {
+ continue // function literal has return values; wg.Go requires func()
+ }
list := lit.Body.List
if len(list) == 0 {
continue
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
index 1afb07c452..1e130f4290 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
@@ -318,7 +318,7 @@ func findPrintLike(pass *analysis.Pass, res *Result) {
// An interface method has no body, but acts
// like an implicit call to each implementing method.
- if w.curBody.Inspector() == nil {
+ if !w.curBody.Valid() {
for impl := range impls[w.obj.(*types.Func)] {
doCall(w, impl, nil)
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
index bc15ef8b96..cc67252426 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
@@ -122,7 +122,7 @@ Usage of %[1]s:
os.Exit(0)
}
if len(args) != 1 || !strings.HasSuffix(args[0], ".cfg") {
- log.Fatalf(`invoking "go tool vet" directly is unsupported; use "go vet"`)
+ log.Fatalf(`invoking "go tool %[1]s" directly is unsupported; use "go %[1]s"`, progname)
}
Run(args[0], analyzers)
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/cursor.go b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/cursor.go
index 60ad425f34..239b10c4da 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/cursor.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/cursor.go
@@ -18,8 +18,11 @@ import (
//
// Two Cursors compare equal if they represent the same node.
//
-// Call [Inspector.Root] to obtain a valid cursor for the virtual root
-// node of the traversal.
+// The zero value of Cursor is not valid.
+//
+// Call [Inspector.Root] to obtain a cursor for the virtual root node
+// of the traversal. This is the sole valid cursor for which [Cursor.Node]
+// returns nil.
//
// Use the following methods to navigate efficiently around the tree:
// - for ancestors, use [Cursor.Parent] and [Cursor.Enclosing];
@@ -37,7 +40,7 @@ type Cursor struct {
index int32 // index of push node; -1 for virtual root node
}
-// Root returns a cursor for the virtual root node,
+// Root returns a valid cursor for the virtual root node,
// whose children are the files provided to [New].
//
// Its [Cursor.Node] method return nil.
@@ -61,14 +64,23 @@ func (in *Inspector) At(index int32) Cursor {
return Cursor{in, index}
}
+// Valid reports whether the cursor is valid.
+// The zero value of cursor is invalid.
+// Unless otherwise documented, it is not safe to call
+// any other method on an invalid cursor.
+func (c Cursor) Valid() bool {
+ return c.in != nil
+}
+
// Inspector returns the cursor's Inspector.
+// It returns nil if the Cursor is not valid.
func (c Cursor) Inspector() *Inspector { return c.in }
// Index returns the index of this cursor position within the package.
//
// Clients should not assume anything about the numeric Index value
// except that it increases monotonically throughout the traversal.
-// It is provided for use with [At].
+// It is provided for use with [Inspector.At].
//
// Index must not be called on the Root node.
func (c Cursor) Index() int32 {
@@ -89,7 +101,7 @@ func (c Cursor) Node() ast.Node {
// String returns information about the cursor's node, if any.
func (c Cursor) String() string {
- if c.in == nil {
+ if !c.Valid() {
return "(invalid)"
}
if c.index < 0 {
@@ -233,6 +245,18 @@ func (c Cursor) ParentEdge() (edge.Kind, int) {
return unpackEdgeKindAndIndex(events[pop].parent)
}
+// ParentEdgeKind returns the kind component of the result of [Cursor.ParentEdge].
+func (c Cursor) ParentEdgeKind() edge.Kind {
+ ek, _ := c.ParentEdge()
+ return ek
+}
+
+// ParentEdgeIndex returns the index component of the result of [Cursor.ParentEdge].
+func (c Cursor) ParentEdgeIndex() int {
+ _, index := c.ParentEdge()
+ return index
+}
+
// ChildAt returns the cursor for the child of the
// current node identified by its edge and index.
// The index must be -1 if the edge.Kind is not a slice.
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/version.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/version.go
index 0b9bcc37b6..700d53effc 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/version.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/version.go
@@ -17,6 +17,9 @@ import (
// FileUsesGoVersion reports whether the specified file may use features of the
// specified version of Go (e.g. "go1.24").
//
+// It returns false when version information is not available,
+// such as for parsed files that are ignored by the type checker.
+//
// Tip: we recommend using this check "late", just before calling
// pass.Report, rather than "early" (when entering each ast.File, or
// each candidate node of interest, during the traversal), because the
@@ -24,7 +27,10 @@ import (
// fraction of files that pass most version checks is high and
// increases over time.
func FileUsesGoVersion(pass *analysis.Pass, file *ast.File, version string) (_res bool) {
- fileVersion := pass.TypesInfo.FileVersions[file]
+ fileVersion, ok := pass.TypesInfo.FileVersions[file]
+ if !ok {
+ return false // be conservative in the absence of information (e.g. IgnoredFiles)
+ }
// Standard packages that are part of toolchain bootstrapping
// are not considered to use a version of Go later than the
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/fix.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/fix.go
index 7769b39beb..4bda3f76bb 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/fix.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/fix.go
@@ -386,11 +386,20 @@ func FormatSourceRemoveImports(pkg *types.Package, src []byte) ([]byte, error) {
// particular the name that would implicitly be declared by a
// non-renaming import of a given existing dependency.
func removeUnneededImports(fset *token.FileSet, pkg *types.Package, file *ast.File) {
- // Map each existing dependency to its default import name.
+ // Map each existing dependency and its transitive dependencies to its default import name.
// (We'll need this to interpret non-renaming imports.)
packageNames := make(map[string]string)
+ var visit func(pkg *types.Package)
+ visit = func(pkg *types.Package) {
+ if packageNames[pkg.Path()] == "" {
+ packageNames[pkg.Path()] = pkg.Name()
+ for _, imp := range pkg.Imports() {
+ visit(imp)
+ }
+ }
+ }
for _, imp := range pkg.Imports() {
- packageNames[imp.Path()] = imp.Name()
+ visit(imp)
}
// Compute the set of free names of the file,
@@ -426,7 +435,7 @@ func removeUnneededImports(fset *token.FileSet, pkg *types.Package, file *ast.Fi
}
switch name {
case "":
- continue // assume it's a new import
+ continue // assume it's a new import, and we didn't find its default name while searching the import graph
case ".":
continue // dot imports are tricky
case "_":
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go
index 7e52aeaaac..5ed4765c72 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go
@@ -31,7 +31,7 @@ func Deprecation(doc *ast.CommentGroup) string {
// -- plundered from the future (CL 605517, issue #68021) --
-// TODO(adonovan): replace with ast.Directive after go1.25 (#68021).
+// TODO(adonovan): replace with ast.Directive in go1.26 (#68021).
// Beware of our local mods to handle analysistest
// "want" comments on the same line.
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/stringlit.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/stringlit.go
index ce1e7de882..eb49d45125 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/astutil/stringlit.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/stringlit.go
@@ -40,20 +40,64 @@ func PosInStringLiteral(lit *ast.BasicLit, offset int) (token.Pos, error) {
return 0, fmt.Errorf("invalid offset")
}
+ pos, _ := walkStringLiteral(lit, lit.End(), offset)
+ return pos, nil
+}
+
+// OffsetInStringLiteral returns the byte offset within the logical (unquoted)
+// string corresponding to the specified source position.
+func OffsetInStringLiteral(lit *ast.BasicLit, pos token.Pos) (int, error) {
+ if !NodeContainsPos(lit, pos) {
+ return 0, fmt.Errorf("invalid position")
+ }
+
+ raw := lit.Value
+
+ value, err := strconv.Unquote(raw)
+ if err != nil {
+ return 0, err
+ }
+
+ _, offset := walkStringLiteral(lit, pos, len(value))
+ return offset, nil
+}
+
+// walkStringLiteral iterates through the raw string literal to map between
+// a file position and a logical byte offset. It stops when it reaches
+// either the targetPos or the targetOffset.
+//
+// TODO(hxjiang): consider making an iterator.
+func walkStringLiteral(lit *ast.BasicLit, targetPos token.Pos, targetOffset int) (token.Pos, int) {
+ raw := lit.Value
+ norm := int(lit.End()-lit.Pos()) > len(lit.Value)
+
// remove quotes
quote := raw[0] // '"' or '`'
raw = raw[1 : len(raw)-1]
var (
- i = 0 // byte index within logical value
- pos = lit.ValuePos + 1 // position within literal
+ i = 0 // byte index within logical value
+ pos = lit.Pos() + 1 // position within literal
)
- for raw != "" && i < offset {
+
+ for raw != "" {
r, _, rest, _ := strconv.UnquoteChar(raw, quote) // can't fail
sz := len(raw) - len(rest) // length of literal char in raw bytes
- pos += token.Pos(sz)
+
+ nextPos := pos + token.Pos(sz)
+ if norm && r == '\n' {
+ nextPos++
+ }
+ nextI := i + utf8.RuneLen(r) // length of logical char in "cooked" bytes
+
+ if nextPos > targetPos || nextI > targetOffset {
+ break
+ }
+
raw = raw[sz:]
- i += utf8.RuneLen(r)
+ i = nextI
+ pos = nextPos
}
- return pos, nil
+
+ return pos, i
}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go
index 6820ba4cda..f211d2cc3d 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go
@@ -11,45 +11,10 @@ import (
"go/token"
"strings"
- "golang.org/x/tools/go/ast/edge"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/moreiters"
)
-// PreorderStack traverses the tree rooted at root,
-// calling f before visiting each node.
-//
-// Each call to f provides the current node and traversal stack,
-// consisting of the original value of stack appended with all nodes
-// from root to n, excluding n itself. (This design allows calls
-// to PreorderStack to be nested without double counting.)
-//
-// If f returns false, the traversal skips over that subtree. Unlike
-// [ast.Inspect], no second call to f is made after visiting node n.
-// In practice, the second call is nearly always used only to pop the
-// stack, and it is surprisingly tricky to do this correctly; see
-// https://go.dev/issue/73319.
-//
-// TODO(adonovan): replace with [ast.PreorderStack] when go1.25 is assured.
-func PreorderStack(root ast.Node, stack []ast.Node, f func(n ast.Node, stack []ast.Node) bool) {
- before := len(stack)
- ast.Inspect(root, func(n ast.Node) bool {
- if n != nil {
- if !f(n, stack) {
- // Do not push, as there will be no corresponding pop.
- return false
- }
- stack = append(stack, n) // push
- } else {
- stack = stack[:len(stack)-1] // pop
- }
- return true
- })
- if len(stack) != before {
- panic("push/pop mismatch")
- }
-}
-
// NodeContains reports whether the Pos/End range of node n encloses
// the given range.
//
@@ -73,14 +38,6 @@ func NodeContainsPos(n ast.Node, pos token.Pos) bool {
return NodeRange(n).ContainsPos(pos)
}
-// IsChildOf reports whether cur.ParentEdge is ek.
-//
-// TODO(adonovan): promote to a method of Cursor.
-func IsChildOf(cur inspector.Cursor, ek edge.Kind) bool {
- got, _ := cur.ParentEdge()
- return got == ek
-}
-
// EnclosingFile returns the syntax tree for the file enclosing c.
//
// TODO(adonovan): promote this to a method of Cursor.
@@ -204,19 +161,19 @@ func Select(curFile inspector.Cursor, start, end token.Pos) (_enclosing, _start,
for cur := range curEnclosing.Preorder() {
if rng.Contains(NodeRange(cur.Node())) {
// The start node has the least Pos.
- if !CursorValid(curStart) {
+ if !curStart.Valid() {
curStart = cur
}
// The end node has the greatest End.
// End positions do not change monotonically,
// so we must compute the max.
- if !CursorValid(curEnd) ||
+ if !curEnd.Valid() ||
cur.Node().End() > curEnd.Node().End() {
curEnd = cur
}
}
}
- if !CursorValid(curStart) {
+ if !curStart.Valid() {
// The selection is valid (inside curEnclosing) but contains no
// complete nodes. This happens for point selections (start == end),
// or selections covering only only spaces, comments, and punctuation
@@ -227,15 +184,69 @@ func Select(curFile inspector.Cursor, start, end token.Pos) (_enclosing, _start,
return curEnclosing, curStart, curEnd, nil
}
-// CursorValid reports whether the cursor is valid.
-//
-// A valid cursor may yet be the virtual root node,
-// cur.Inspector.Root(), which has no [Cursor.Node].
+var noCursor inspector.Cursor
+
+// MaybeParenthesize returns new, possibly wrapped in parens if needed
+// to preserve operator precedence when it replaces old, whose parent
+// is parentNode.
//
-// TODO(adonovan): move to cursorutil package, and move that package into x/tools.
-// Ultimately, make this a method of Cursor. Needs a proposal.
-func CursorValid(cur inspector.Cursor) bool {
- return cur.Inspector() != nil
+// (This would be more naturally written in terms of Cursor, but one of
+// the callers--the inliner--does not have cursors handy.)
+func MaybeParenthesize(parentNode ast.Node, old, new ast.Expr) ast.Expr {
+ if needsParens(parentNode, old, new) {
+ new = &ast.ParenExpr{X: new}
+ }
+ return new
}
-var noCursor inspector.Cursor
+func needsParens(parentNode ast.Node, old, new ast.Expr) bool {
+ // An expression beneath a non-expression
+ // has no precedence ambiguity.
+ parent, ok := parentNode.(ast.Expr)
+ if !ok {
+ return false
+ }
+
+ precedence := func(n ast.Node) int {
+ switch n := n.(type) {
+ case *ast.UnaryExpr, *ast.StarExpr:
+ return token.UnaryPrec
+ case *ast.BinaryExpr:
+ return n.Op.Precedence()
+ }
+ return -1
+ }
+
+ // Parens are not required if the new node
+ // is not unary or binary.
+ newprec := precedence(new)
+ if newprec < 0 {
+ return false
+ }
+
+ // Parens are required if parent and child are both
+ // unary or binary and the parent has higher precedence.
+ if precedence(parent) > newprec {
+ return true
+ }
+
+ // Was the old node the operand of a postfix operator?
+ // f().sel
+ // f()[i:j]
+ // f()[i]
+ // f().(T)
+ // f()(x)
+ switch parent := parent.(type) {
+ case *ast.SelectorExpr:
+ return parent.X == old
+ case *ast.IndexExpr:
+ return parent.X == old
+ case *ast.SliceExpr:
+ return parent.X == old
+ case *ast.TypeAssertExpr:
+ return parent.X == old
+ case *ast.CallExpr:
+ return parent.Fun == old
+ }
+ return false
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/diff/unified.go b/src/cmd/vendor/golang.org/x/tools/internal/diff/unified.go
index a6ebe9f950..df8f2fcc12 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/diff/unified.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/diff/unified.go
@@ -20,7 +20,7 @@ const DefaultContextLines = 3
// The old and new labels are the names of the old and new files.
// If the strings are equal, it returns the empty string.
func Unified(oldLabel, newLabel, old, new string) string {
- edits := Strings(old, new)
+ edits := Lines(old, new)
unified, err := ToUnified(oldLabel, newLabel, old, edits, DefaultContextLines)
if err != nil {
// Can't happen: edits are consistent.
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go b/src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go
index b0572f5968..e960b36db4 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go
@@ -14,4 +14,5 @@ var (
PlusBuildModernizer *analysis.Analyzer // = modernize.plusbuildAnalyzer
StringsCutModernizer *analysis.Analyzer // = modernize.stringscutAnalyzer
UnsafeFuncsModernizer *analysis.Analyzer // = modernize.unsafeFuncsAnalyzer
+ AtomicTypesModernizer *analysis.Analyzer // = modernize.atomicTypesAnalyzer
)
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go b/src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go
index 54d0b5f038..25547f04f0 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go
@@ -32,7 +32,7 @@ import (
// If it cannot make the necessary edits, such as for a function
// parameter or result, it returns nil.
func DeleteVar(tokFile *token.File, info *types.Info, curId inspector.Cursor) []Edit {
- switch ek, _ := curId.ParentEdge(); ek {
+ switch curId.ParentEdgeKind() {
case edge.ValueSpec_Names:
return deleteVarFromValueSpec(tokFile, info, curId)
@@ -74,7 +74,7 @@ func deleteVarFromValueSpec(tokFile *token.File, info *types.Info, curIdent insp
// at least one LHS, or for effects on RHS.
// Blank out or delete just one LHS.
- _, index := curIdent.ParentEdge() // index of LHS within ValueSpec.Names
+ index := curIdent.ParentEdgeIndex() // index of LHS within ValueSpec.Names
// If there is no RHS, we can delete the LHS.
if len(spec.Values) == 0 {
@@ -181,7 +181,7 @@ func deleteVarFromAssignStmt(tokFile *token.File, info *types.Info, curIdent ins
// If the assignment is 1:1 and the RHS has no effects,
// we can delete the LHS and its corresponding RHS.
- _, index := curIdent.ParentEdge()
+ index := curIdent.ParentEdgeIndex()
if len(assign.Lhs) > 1 &&
len(assign.Lhs) == len(assign.Rhs) &&
typesinternal.NoEffects(info, assign.Rhs[index]) {
@@ -259,7 +259,7 @@ func DeleteSpec(tokFile *token.File, curSpec inspector.Cursor) []Edit {
}
// Delete the spec and its comments.
- _, index := curSpec.ParentEdge() // index of ValueSpec within GenDecl.Specs
+ index := curSpec.ParentEdgeIndex() // index of ValueSpec within GenDecl.Specs
pos, end := spec.Pos(), spec.End()
if doc := astutil.DocComment(spec); doc != nil {
pos = doc.Pos() // leading comment
@@ -288,7 +288,7 @@ func DeleteSpec(tokFile *token.File, curSpec inspector.Cursor) []Edit {
func DeleteDecl(tokFile *token.File, curDecl inspector.Cursor) []Edit {
decl := curDecl.Node().(ast.Decl)
- ek, _ := curDecl.ParentEdge()
+ ek := curDecl.ParentEdgeKind()
switch ek {
case edge.DeclStmt_Decl:
return DeleteStmt(tokFile, curDecl.Parent())
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go
index 9a960bd293..815c8c0bba 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go
@@ -18,7 +18,6 @@ import (
"strings"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal"
)
@@ -145,7 +144,7 @@ func AnalyzeCallee(logf func(string, ...any), fset *token.FileSet, pkg *types.Pa
var f func(n ast.Node, stack []ast.Node) bool
var stack []ast.Node
stack = append(stack, decl.Type) // for scope of function itself
- visit := func(n ast.Node, stack []ast.Node) { astutil.PreorderStack(n, stack, f) }
+ visit := func(n ast.Node, stack []ast.Node) { ast.PreorderStack(n, stack, f) }
f = func(n ast.Node, stack []ast.Node) bool {
switch n := n.(type) {
case *ast.SelectorExpr:
@@ -469,7 +468,7 @@ func analyzeParams(logf func(string, ...any), fset *token.FileSet, info *types.I
fieldObjs := fieldObjs(sig)
var stack []ast.Node
stack = append(stack, decl.Type) // for scope of function itself
- astutil.PreorderStack(decl.Body, stack, func(n ast.Node, stack []ast.Node) bool {
+ ast.PreorderStack(decl.Body, stack, func(n ast.Node, stack []ast.Node) bool {
if id, ok := n.(*ast.Ident); ok {
if v, ok := info.Uses[id].(*types.Var); ok {
if pinfo, ok := paramInfos[v]; ok {
@@ -533,7 +532,7 @@ func analyzeTypeParams(_ logger, fset *token.FileSet, info *types.Info, decl *as
// TODO(jba): can we nevertheless combine this with the traversal in analyzeParams?
var stack []ast.Node
stack = append(stack, decl.Type) // for scope of function itself
- astutil.PreorderStack(decl.Body, stack, func(n ast.Node, stack []ast.Node) bool {
+ ast.PreorderStack(decl.Body, stack, func(n ast.Node, stack []ast.Node) bool {
if id, ok := n.(*ast.Ident); ok {
if v, ok := info.Uses[id].(*types.TypeName); ok {
if pinfo, ok := paramInfos[v]; ok {
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/inline.go b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/inline.go
index f7e37fd7da..e968908fd6 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/inline.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/inline.go
@@ -132,8 +132,9 @@ func (st *state) inline() (*Result, error) {
// the x subtree is subject to precedence ambiguity
// (replacing x by p+q would give p+q[y:z] which is wrong)
// but the y and z subtrees are safe.
- if needsParens(caller.path, res.old, res.new) {
- res.new = &ast.ParenExpr{X: res.new.(ast.Expr)}
+ if new, ok := res.new.(ast.Expr); ok {
+ parent := caller.path[slices.Index(caller.path, res.old)+1]
+ res.new = internalastutil.MaybeParenthesize(parent, res.old.(ast.Expr), new)
}
// Some reduction strategies return a new block holding the
@@ -3137,73 +3138,6 @@ func last[T any](slice []T) T {
return *new(T)
}
-// needsParens reports whether parens are required to avoid ambiguity
-// around the new node replacing the specified old node (which is some
-// ancestor of the CallExpr identified by its PathEnclosingInterval).
-func needsParens(callPath []ast.Node, old, new ast.Node) bool {
- // Find enclosing old node and its parent.
- i := slices.Index(callPath, old)
- if i == -1 {
- panic("not found")
- }
-
- // There is no precedence ambiguity when replacing
- // (e.g.) a statement enclosing the call.
- if !is[ast.Expr](old) {
- return false
- }
-
- // An expression beneath a non-expression
- // has no precedence ambiguity.
- parent, ok := callPath[i+1].(ast.Expr)
- if !ok {
- return false
- }
-
- precedence := func(n ast.Node) int {
- switch n := n.(type) {
- case *ast.UnaryExpr, *ast.StarExpr:
- return token.UnaryPrec
- case *ast.BinaryExpr:
- return n.Op.Precedence()
- }
- return -1
- }
-
- // Parens are not required if the new node
- // is not unary or binary.
- newprec := precedence(new)
- if newprec < 0 {
- return false
- }
-
- // Parens are required if parent and child are both
- // unary or binary and the parent has higher precedence.
- if precedence(parent) > newprec {
- return true
- }
-
- // Was the old node the operand of a postfix operator?
- // f().sel
- // f()[i:j]
- // f()[i]
- // f().(T)
- // f()(x)
- switch parent := parent.(type) {
- case *ast.SelectorExpr:
- return parent.X == old
- case *ast.IndexExpr:
- return parent.X == old
- case *ast.SliceExpr:
- return parent.X == old
- case *ast.TypeAssertExpr:
- return parent.X == old
- case *ast.CallExpr:
- return parent.Fun == old
- }
- return false
-}
-
// declares returns the set of lexical names declared by a
// sequence of statements from the same block, excluding sub-blocks.
// (Lexical names do not include control labels.)
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/refactor.go b/src/cmd/vendor/golang.org/x/tools/internal/refactor/refactor.go
index 8664377f85..1d6c054332 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/refactor.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/refactor/refactor.go
@@ -17,10 +17,9 @@ import (
// FreshName returns the name of an identifier that is undefined
// at the specified position, based on the preferred name.
//
-// TODO(adonovan): refine this to choose a fresh name only when there
-// would be a conflict with the existing declaration: it's fine to
-// redeclare a name in a narrower scope so long as there are no free
-// references to the outer name from within the narrower scope.
+// export/use freshName in go/analysis/passes/modernize/modernize.go if you want
+// to generate a fresh name only when necessary (i.e., there is both an existing
+// declaration and some free reference to the name within a narrower scope)
func FreshName(scope *types.Scope, pos token.Pos, preferred string) string {
newName := preferred
for i := 0; ; i++ {
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/typeindex/typeindex.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/typeindex/typeindex.go
index 01ad7b9cf7..222ada55a2 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/typeindex/typeindex.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/typeindex/typeindex.go
@@ -217,7 +217,7 @@ func (ix *Index) Selection(path, typename, name string) types.Object {
func (ix *Index) Calls(callee types.Object) iter.Seq[inspector.Cursor] {
return func(yield func(inspector.Cursor) bool) {
for cur := range ix.Uses(callee) {
- ek, _ := cur.ParentEdge()
+ ek := cur.ParentEdgeKind()
// The call may be of the form f() or x.f(),
// optionally with parens; ascend from f to call.
@@ -231,19 +231,19 @@ func (ix *Index) Calls(callee types.Object) iter.Seq[inspector.Cursor] {
// inverse unparen: f -> (f)
for ek == edge.ParenExpr_X {
cur = cur.Parent()
- ek, _ = cur.ParentEdge()
+ ek = cur.ParentEdgeKind()
}
// ascend selector: f -> x.f
if ek == edge.SelectorExpr_Sel {
cur = cur.Parent()
- ek, _ = cur.ParentEdge()
+ ek = cur.ParentEdgeKind()
}
// inverse unparen again
for ek == edge.ParenExpr_X {
cur = cur.Parent()
- ek, _ = cur.ParentEdge()
+ ek = cur.ParentEdgeKind()
}
// ascend from f or x.f to call
diff --git a/src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go b/src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go
index bb38375531..3d21ce6d26 100644
--- a/src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go
+++ b/src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go
@@ -395,8 +395,11 @@ func (f *Finder) expr(e ast.Expr) types.Type {
f.expr(e.X)
case *ast.SelectorExpr:
- if _, ok := f.info.Selections[e]; ok {
- f.expr(e.X) // selection
+ if seln, ok := f.info.Selections[e]; ok {
+ // If e.X is a type (e.g., e is interface{ m() }.m), don't visit it.
+ if seln.Kind() != types.MethodExpr {
+ f.expr(e.X)
+ }
} else {
return f.info.Uses[e.Sel].Type() // qualified identifier
}
diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt
index ceed574b32..7b5b9aa37f 100644
--- a/src/cmd/vendor/modules.txt
+++ b/src/cmd/vendor/modules.txt
@@ -28,8 +28,8 @@ golang.org/x/arch/x86/x86asm
# golang.org/x/build v0.0.0-20260122183339-3ba88df37c64
## explicit; go 1.24.9
golang.org/x/build/relnote
-# golang.org/x/mod v0.32.0
-## explicit; go 1.24.0
+# golang.org/x/mod v0.34.0
+## explicit; go 1.25.0
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
golang.org/x/mod/module
@@ -39,17 +39,17 @@ golang.org/x/mod/sumdb/dirhash
golang.org/x/mod/sumdb/note
golang.org/x/mod/sumdb/tlog
golang.org/x/mod/zip
-# golang.org/x/sync v0.19.0
-## explicit; go 1.24.0
+# golang.org/x/sync v0.20.0
+## explicit; go 1.25.0
golang.org/x/sync/errgroup
golang.org/x/sync/semaphore
-# golang.org/x/sys v0.40.1-0.20260116220947-d25a7aaff8c2
-## explicit; go 1.24.0
+# golang.org/x/sys v0.42.1-0.20260320201212-a76ec62d6c53
+## explicit; go 1.25.0
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/telemetry v0.0.0-20260116145544-c6413dc483f5
-## explicit; go 1.24.0
+# golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c
+## explicit; go 1.25.0
golang.org/x/telemetry
golang.org/x/telemetry/counter
golang.org/x/telemetry/counter/countertest
@@ -73,8 +73,8 @@ golang.org/x/text/internal/tag
golang.org/x/text/language
golang.org/x/text/transform
golang.org/x/text/unicode/norm
-# golang.org/x/tools v0.41.1-0.20260122210857-a60613f0795e
-## explicit; go 1.24.0
+# golang.org/x/tools v0.43.1-0.20260319213245-5d7afbc08aec
+## explicit; go 1.25.0
golang.org/x/tools/cmd/bisect
golang.org/x/tools/cover
golang.org/x/tools/go/analysis
diff --git a/src/go.mod b/src/go.mod
index d6c515017a..2ac54d7b35 100644
--- a/src/go.mod
+++ b/src/go.mod
@@ -8,6 +8,6 @@ require (
)
require (
- golang.org/x/sys v0.40.1-0.20260116220947-d25a7aaff8c2 // indirect
+ golang.org/x/sys v0.42.1-0.20260320201212-a76ec62d6c53 // indirect
golang.org/x/text v0.33.1-0.20260122225119-3264de9174be // indirect
)
diff --git a/src/go.sum b/src/go.sum
index 2223d2a7c2..ba6fd05766 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -2,7 +2,7 @@ golang.org/x/crypto v0.47.1-0.20260113154411-7d0074ccc6f1 h1:peTBrYsTa5Rr+jB2pbg
golang.org/x/crypto v0.47.1-0.20260113154411-7d0074ccc6f1/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/net v0.49.1-0.20260122225915-f2078620ee33 h1:pNHjOZ0w6qb8R9EDmEsBXmV4o2YKLvtRiEk4q5gN5Hg=
golang.org/x/net v0.49.1-0.20260122225915-f2078620ee33/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
-golang.org/x/sys v0.40.1-0.20260116220947-d25a7aaff8c2 h1:jUsftZdK5NYH1tUlaQUfascfiJtOm7qHnRPWsG6hb4w=
-golang.org/x/sys v0.40.1-0.20260116220947-d25a7aaff8c2/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.42.1-0.20260320201212-a76ec62d6c53 h1:0T1C9w/fKTlj64Z8y0UtRoCAD7UZ+l5ZCSHcs3GYSCI=
+golang.org/x/sys v0.42.1-0.20260320201212-a76ec62d6c53/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.33.1-0.20260122225119-3264de9174be h1:EwuAS7HtEmZVDSL0zq464yhyVIjdDETleE+K94kfwxg=
golang.org/x/text v0.33.1-0.20260122225119-3264de9174be/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
diff --git a/src/vendor/golang.org/x/sys/cpu/asm_darwin_arm64_gc.s b/src/vendor/golang.org/x/sys/cpu/asm_darwin_arm64_gc.s
new file mode 100644
index 0000000000..e07fa75eb5
--- /dev/null
+++ b/src/vendor/golang.org/x/sys/cpu/asm_darwin_arm64_gc.s
@@ -0,0 +1,12 @@
+// Copyright 2024 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 darwin && arm64 && gc
+
+#include "textflag.h"
+
+TEXT libc_sysctlbyname_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_sysctlbyname(SB)
+GLOBL ·libc_sysctlbyname_trampoline_addr(SB), RODATA, $8
+DATA ·libc_sysctlbyname_trampoline_addr(SB)/8, $libc_sysctlbyname_trampoline<>(SB)
diff --git a/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go
index af2aa99f9f..5fc09e2935 100644
--- a/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go
+++ b/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go
@@ -44,14 +44,11 @@ func initOptions() {
}
func archInit() {
- switch runtime.GOOS {
- case "freebsd":
+ if runtime.GOOS == "freebsd" {
readARM64Registers()
- case "linux", "netbsd", "openbsd":
+ } else {
+ // Most platforms don't seem to allow directly reading these registers.
doinit()
- default:
- // Many platforms don't seem to allow reading these registers.
- setMinimalFeatures()
}
}
diff --git a/src/vendor/golang.org/x/sys/cpu/cpu_darwin_arm64.go b/src/vendor/golang.org/x/sys/cpu/cpu_darwin_arm64.go
new file mode 100644
index 0000000000..0b470744a0
--- /dev/null
+++ b/src/vendor/golang.org/x/sys/cpu/cpu_darwin_arm64.go
@@ -0,0 +1,67 @@
+// Copyright 2026 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 darwin && arm64 && gc
+
+package cpu
+
+func doinit() {
+ setMinimalFeatures()
+
+ // The feature flags are explained in [Instruction Set Detection].
+ // There are some differences between MacOS versions:
+ //
+ // MacOS 11 and 12 do not have "hw.optional" sysctl values for some of the features.
+ //
+ // MacOS 13 changed some of the naming conventions to align with ARM Architecture Reference Manual.
+ // For example "hw.optional.armv8_2_sha512" became "hw.optional.arm.FEAT_SHA512".
+ // It currently checks both to stay compatible with MacOS 11 and 12.
+ // The old names also work with MacOS 13, however it's not clear whether
+ // they will continue working with future OS releases.
+ //
+ // Once MacOS 12 is no longer supported the old names can be removed.
+ //
+ // [Instruction Set Detection]: https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
+
+ // Encryption, hashing and checksum capabilities
+
+ // For the following flags there are no MacOS 11 sysctl flags.
+ ARM64.HasAES = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_AES\x00"))
+ ARM64.HasPMULL = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_PMULL\x00"))
+ ARM64.HasSHA1 = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA1\x00"))
+ ARM64.HasSHA2 = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA256\x00"))
+
+ ARM64.HasSHA3 = darwinSysctlEnabled([]byte("hw.optional.armv8_2_sha3\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA3\x00"))
+ ARM64.HasSHA512 = darwinSysctlEnabled([]byte("hw.optional.armv8_2_sha512\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA512\x00"))
+
+ ARM64.HasCRC32 = darwinSysctlEnabled([]byte("hw.optional.armv8_crc32\x00"))
+
+ // Atomic and memory ordering
+ ARM64.HasATOMICS = darwinSysctlEnabled([]byte("hw.optional.armv8_1_atomics\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_LSE\x00"))
+ ARM64.HasLRCPC = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_LRCPC\x00"))
+
+ // SIMD and floating point capabilities
+ ARM64.HasFPHP = darwinSysctlEnabled([]byte("hw.optional.neon_fp16\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_FP16\x00"))
+ ARM64.HasASIMDHP = darwinSysctlEnabled([]byte("hw.optional.neon_hpfp\x00")) || darwinSysctlEnabled([]byte("hw.optional.AdvSIMD_HPFPCvt\x00"))
+ ARM64.HasASIMDRDM = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_RDM\x00"))
+ ARM64.HasASIMDDP = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_DotProd\x00"))
+ ARM64.HasASIMDFHM = darwinSysctlEnabled([]byte("hw.optional.armv8_2_fhm\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_FHM\x00"))
+ ARM64.HasI8MM = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_I8MM\x00"))
+
+ ARM64.HasJSCVT = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_JSCVT\x00"))
+ ARM64.HasFCMA = darwinSysctlEnabled([]byte("hw.optional.armv8_3_compnum\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_FCMA\x00"))
+
+ // Miscellaneous
+ ARM64.HasDCPOP = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_DPB\x00"))
+ ARM64.HasEVTSTRM = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_ECV\x00"))
+ ARM64.HasDIT = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_DIT\x00"))
+
+ // Not supported, but added for completeness
+ ARM64.HasCPUID = false
+
+ ARM64.HasSM3 = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SM3\x00"))
+ ARM64.HasSM4 = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SM4\x00"))
+ ARM64.HasSVE = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SVE\x00"))
+ ARM64.HasSVE2 = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SVE2\x00"))
+}
diff --git a/src/vendor/golang.org/x/sys/cpu/cpu_darwin_arm64_other.go b/src/vendor/golang.org/x/sys/cpu/cpu_darwin_arm64_other.go
new file mode 100644
index 0000000000..4ee68e38d9
--- /dev/null
+++ b/src/vendor/golang.org/x/sys/cpu/cpu_darwin_arm64_other.go
@@ -0,0 +1,29 @@
+// Copyright 2026 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 darwin && arm64 && !gc
+
+package cpu
+
+func doinit() {
+ setMinimalFeatures()
+
+ ARM64.HasASIMD = true
+ ARM64.HasFP = true
+
+ // Go already assumes these to be available because they were on the M1
+ // and these are supported on all Apple arm64 chips.
+ ARM64.HasAES = true
+ ARM64.HasPMULL = true
+ ARM64.HasSHA1 = true
+ ARM64.HasSHA2 = true
+
+ if runtime.GOOS != "ios" {
+ // Apple A7 processors do not support these, however
+ // M-series SoCs are at least armv8.4-a
+ ARM64.HasCRC32 = true // armv8.1
+ ARM64.HasATOMICS = true // armv8.2
+ ARM64.HasJSCVT = true // armv8.3, if HasFP
+ }
+}
diff --git a/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go b/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go
index 7f1946780b..05913081ec 100644
--- a/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go
+++ b/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go
@@ -9,3 +9,4 @@ package cpu
func getisar0() uint64 { return 0 }
func getisar1() uint64 { return 0 }
func getpfr0() uint64 { return 0 }
+func getzfr0() uint64 { return 0 }
diff --git a/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go b/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go
index 5341e7f88d..53f814d7a6 100644
--- a/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go
+++ b/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build !linux && !netbsd && !openbsd && arm64
+//go:build !darwin && !linux && !netbsd && !openbsd && arm64
package cpu
-func doinit() {}
+func doinit() {
+ setMinimalFeatures()
+}
diff --git a/src/vendor/golang.org/x/sys/cpu/syscall_darwin_arm64_gc.go b/src/vendor/golang.org/x/sys/cpu/syscall_darwin_arm64_gc.go
new file mode 100644
index 0000000000..7b4e67ff9c
--- /dev/null
+++ b/src/vendor/golang.org/x/sys/cpu/syscall_darwin_arm64_gc.go
@@ -0,0 +1,54 @@
+// Copyright 2024 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.
+
+// Minimal copy from internal/cpu and runtime to make sysctl calls.
+
+//go:build darwin && arm64 && gc
+
+package cpu
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+type Errno = syscall.Errno
+
+// adapted from internal/cpu/cpu_arm64_darwin.go
+func darwinSysctlEnabled(name []byte) bool {
+ out := int32(0)
+ nout := unsafe.Sizeof(out)
+ if ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); ret != nil {
+ return false
+ }
+ return out > 0
+}
+
+//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib"
+
+var libc_sysctlbyname_trampoline_addr uintptr
+
+// adapted from runtime/sys_darwin.go in the pattern of sysctl() above, as defined in x/sys/unix
+func sysctlbyname(name *byte, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
+ if _, _, err := syscall_syscall6(
+ libc_sysctlbyname_trampoline_addr,
+ uintptr(unsafe.Pointer(name)),
+ uintptr(unsafe.Pointer(old)),
+ uintptr(unsafe.Pointer(oldlen)),
+ uintptr(unsafe.Pointer(new)),
+ uintptr(newlen),
+ 0,
+ ); err != 0 {
+ return err
+ }
+
+ return nil
+}
+
+//go:cgo_import_dynamic libc_sysctlbyname sysctlbyname "/usr/lib/libSystem.B.dylib"
+
+// Implemented in the runtime package (runtime/sys_darwin.go)
+func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+
+//go:linkname syscall_syscall6 syscall.syscall6
diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt
index 48967bc9ee..e8c6f1efb0 100644
--- a/src/vendor/modules.txt
+++ b/src/vendor/modules.txt
@@ -15,8 +15,8 @@ golang.org/x/net/http2/hpack
golang.org/x/net/idna
golang.org/x/net/lif
golang.org/x/net/nettest
-# golang.org/x/sys v0.40.1-0.20260116220947-d25a7aaff8c2
-## explicit; go 1.24.0
+# golang.org/x/sys v0.42.1-0.20260320201212-a76ec62d6c53
+## explicit; go 1.25.0
golang.org/x/sys/cpu
# golang.org/x/text v0.33.1-0.20260122225119-3264de9174be
## explicit; go 1.24.0