aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/asm/internal/asm/testdata/amd64dynlinkerror.s5
-rw-r--r--src/cmd/asm/internal/asm/testdata/loong64enc1.s6
-rw-r--r--src/cmd/asm/internal/flags/flags.go7
-rw-r--r--src/cmd/asm/main.go1
-rw-r--r--src/cmd/compile/internal/base/debug.go1
-rw-r--r--src/cmd/compile/internal/base/flag.go2
-rw-r--r--src/cmd/compile/internal/deadlocals/deadlocals.go5
-rw-r--r--src/cmd/compile/internal/escape/leaks.go18
-rw-r--r--src/cmd/compile/internal/gc/main.go3
-rw-r--r--src/cmd/compile/internal/ir/expr.go26
-rw-r--r--src/cmd/compile/internal/ir/fmt.go2
-rw-r--r--src/cmd/compile/internal/ir/name.go2
-rw-r--r--src/cmd/compile/internal/ir/node.go1
-rw-r--r--src/cmd/compile/internal/ir/node_gen.go28
-rw-r--r--src/cmd/compile/internal/ir/op_string.go19
-rw-r--r--src/cmd/compile/internal/ir/stmt.go1
-rw-r--r--src/cmd/compile/internal/ir/symtab.go5
-rw-r--r--src/cmd/compile/internal/loong64/ssa.go153
-rw-r--r--src/cmd/compile/internal/slice/slice.go455
-rw-r--r--src/cmd/compile/internal/ssa/_gen/AMD64Ops.go3
-rw-r--r--src/cmd/compile/internal/ssa/_gen/ARM64.rules6
-rw-r--r--src/cmd/compile/internal/ssa/_gen/LOONG64.rules3
-rw-r--r--src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go1
-rw-r--r--src/cmd/compile/internal/ssa/_gen/RISCV64.rules39
-rw-r--r--src/cmd/compile/internal/ssa/_gen/dec.rules9
-rw-r--r--src/cmd/compile/internal/ssa/_gen/generic.rules19
-rw-r--r--src/cmd/compile/internal/ssa/expand_calls.go9
-rw-r--r--src/cmd/compile/internal/ssa/fuse.go8
-rw-r--r--src/cmd/compile/internal/ssa/fuse_comparisons.go45
-rw-r--r--src/cmd/compile/internal/ssa/opGen.go3
-rw-r--r--src/cmd/compile/internal/ssa/prove.go223
-rw-r--r--src/cmd/compile/internal/ssa/regalloc.go9
-rw-r--r--src/cmd/compile/internal/ssa/rewrite.go14
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM64.go79
-rw-r--r--src/cmd/compile/internal/ssa/rewriteLOONG64.go39
-rw-r--r--src/cmd/compile/internal/ssa/rewriteRISCV64.go103
-rw-r--r--src/cmd/compile/internal/ssa/rewritedec.go52
-rw-r--r--src/cmd/compile/internal/ssa/rewritegeneric.go553
-rw-r--r--src/cmd/compile/internal/ssagen/ssa.go266
-rw-r--r--src/cmd/compile/internal/test/testdata/arith_test.go14
-rw-r--r--src/cmd/compile/internal/typecheck/_builtin/runtime.go6
-rw-r--r--src/cmd/compile/internal/typecheck/builtin.go212
-rw-r--r--src/cmd/compile/internal/types/type.go21
-rw-r--r--src/cmd/compile/internal/types2/check.go31
-rw-r--r--src/cmd/compile/internal/types2/cycles.go1
-rw-r--r--src/cmd/compile/internal/types2/decl.go158
-rw-r--r--src/cmd/compile/internal/types2/object.go54
-rw-r--r--src/cmd/compile/internal/types2/scope.go2
-rw-r--r--src/cmd/compile/internal/types2/sizeof_test.go16
-rw-r--r--src/cmd/compile/internal/types2/typexpr.go20
-rw-r--r--src/cmd/compile/internal/types2/universe.go8
-rw-r--r--src/cmd/compile/internal/walk/expr.go5
-rw-r--r--src/cmd/go.mod10
-rw-r--r--src/cmd/go.sum20
-rw-r--r--src/cmd/go/internal/cache/hash.go3
-rw-r--r--src/cmd/go/internal/vcweb/script.go8
-rw-r--r--src/cmd/go/scriptconds_test.go8
-rw-r--r--src/cmd/go/testdata/script/README4
-rw-r--r--src/cmd/go/testdata/script/build_git_sha256_go_get_branch.txt2
-rw-r--r--src/cmd/go/testdata/script/build_git_sha256_moddep.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_download_git_bareRepository_sha256.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_get_direct.txt4
-rw-r--r--src/cmd/go/testdata/vcstest/git/gitrepo-sha256.txt2
-rw-r--r--src/cmd/internal/obj/link.go61
-rw-r--r--src/cmd/internal/obj/loong64/a.out.go4
-rw-r--r--src/cmd/internal/obj/loong64/anames.go2
-rw-r--r--src/cmd/internal/obj/loong64/asm.go6
-rw-r--r--src/cmd/internal/obj/riscv/asm_test.go16
-rw-r--r--src/cmd/internal/obj/riscv/cpu.go3
-rw-r--r--src/cmd/internal/obj/riscv/doc.go297
-rw-r--r--src/cmd/internal/obj/riscv/obj.go189
-rw-r--r--src/cmd/internal/obj/x86/obj6.go25
-rw-r--r--src/cmd/internal/sys/arch.go2
-rw-r--r--src/cmd/link/internal/ld/dwarf.go8
-rw-r--r--src/cmd/link/internal/ld/ld_test.go4
-rw-r--r--src/cmd/link/internal/ld/main.go6
-rw-r--r--src/cmd/link/internal/loader/loader.go3
-rw-r--r--src/cmd/link/link_test.go1
-rw-r--r--src/cmd/link/testdata/linkname/freegc.go18
-rw-r--r--src/cmd/trace/procgen.go8
-rw-r--r--src/cmd/trace/threadgen.go12
-rw-r--r--src/cmd/vendor/golang.org/x/mod/modfile/print.go2
-rw-r--r--src/cmd/vendor/golang.org/x/mod/modfile/read.go4
-rw-r--r--src/cmd/vendor/golang.org/x/mod/modfile/rule.go8
-rw-r--r--src/cmd/vendor/golang.org/x/mod/module/module.go6
-rw-r--r--src/cmd/vendor/golang.org/x/mod/semver/semver.go4
-rw-r--r--src/cmd/vendor/golang.org/x/mod/sumdb/cache.go6
-rw-r--r--src/cmd/vendor/golang.org/x/mod/sumdb/client.go6
-rw-r--r--src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go22
-rw-r--r--src/cmd/vendor/golang.org/x/mod/sumdb/server.go3
-rw-r--r--src/cmd/vendor/golang.org/x/mod/sumdb/test.go2
-rw-r--r--src/cmd/vendor/golang.org/x/mod/sumdb/tlog/note.go4
-rw-r--r--src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go4
-rw-r--r--src/cmd/vendor/golang.org/x/mod/zip/zip.go2
-rw-r--r--src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go2
-rw-r--r--src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh2
-rw-r--r--src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go6
-rw-r--r--src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go359
-rw-r--r--src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go10
-rw-r--r--src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go31
-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.go76
-rw-r--r--src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go37
-rw-r--r--src/cmd/vendor/golang.org/x/telemetry/codereview.cfg1
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go5
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go159
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go90
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/hostport/hostport.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go (renamed from src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/gofix.go)61
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/ctrlflowinternal/ctrlflowinternal.go17
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go43
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go8
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/any.go24
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/bloop.go36
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go46
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go16
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/fmtappendf.go13
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/forvar.go99
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/maps.go22
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go14
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go49
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/newexpr.go38
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/omitzero.go49
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go7
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go23
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go12
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slices.go25
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go52
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesdelete.go25
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/sortslice.go13
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go67
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go10
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go580
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscutprefix.go20
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsseq.go19
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/testingcontext.go13
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroup.go13
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go24
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go16
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go8
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go10
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go7
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go6
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go8
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go11
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go28
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/ast/inspector/cursor.go17
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/cfg/builder.go16
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/cfg/cfg.go54
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go3
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/doc.go6
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/extractdoc.go (renamed from src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go)4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/readfile.go30
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/version.go42
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/fix.go (renamed from src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/fix.go)225
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/print.go161
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/readfile.go43
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/url.go (renamed from src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/url.go)2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/validatefix.go (renamed from src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go)70
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysis/typeindex/typeindex.go (renamed from src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/typeindex/typeindex.go)4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/generated/generated.go41
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/astutil/free/free.go (renamed from src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/free.go)206
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/astutil/stringlit.go8
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go146
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/cfginternal/cfginternal.go16
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/diff/lcs/old.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/facts/imports.go36
-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.go239
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go35
-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/inline/util.go1
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/refactor/refactor.go5
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/stdlib/deps.go770
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/stdlib/import.go8
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go41
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/typeparams/normalize.go6
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/typesinternal/element.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/typesinternal/isnamed.go4
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go14
-rw-r--r--src/cmd/vendor/golang.org/x/tools/internal/versions/features.go6
-rw-r--r--src/cmd/vendor/modules.txt19
-rw-r--r--src/cmd/vet/testdata/print/print.go2
206 files changed, 6128 insertions, 2220 deletions
diff --git a/src/cmd/asm/internal/asm/testdata/amd64dynlinkerror.s b/src/cmd/asm/internal/asm/testdata/amd64dynlinkerror.s
index 4bf58a39a4..8b104307cd 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64dynlinkerror.s
+++ b/src/cmd/asm/internal/asm/testdata/amd64dynlinkerror.s
@@ -169,3 +169,8 @@ TEXT ·a34(SB), 0, $0-0
SHLXQ AX, CX, R15
ADDQ $1, R15
RET
+
+// Ensure from3 get GOT-rewritten without errors.
+TEXT ·a35(SB), 0, $0-0
+ VGF2P8AFFINEQB $0, runtime·writeBarrier(SB), Z1, Z1
+ RET
diff --git a/src/cmd/asm/internal/asm/testdata/loong64enc1.s b/src/cmd/asm/internal/asm/testdata/loong64enc1.s
index c820a0a5a1..277396bf27 100644
--- a/src/cmd/asm/internal/asm/testdata/loong64enc1.s
+++ b/src/cmd/asm/internal/asm/testdata/loong64enc1.s
@@ -212,6 +212,12 @@ lable2:
SRLV $32, R4, R5 // 85804500
SRLV $32, R4 // 84804500
+ // MULW.D.W[U] instructions
+ MULWVW R4, R5 // a5101f00
+ MULWVW R4, R5, R6 // a6101f00
+ MULWVWU R4, R5 // a5901f00
+ MULWVWU R4, R5, R6 // a6901f00
+
MASKEQZ R4, R5, R6 // a6101300
MASKNEZ R4, R5, R6 // a6901300
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
index e15a062749..19aa65630f 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -29,8 +29,9 @@ var (
)
var DebugFlags struct {
- MayMoreStack string `help:"call named function before all stack growth checks"`
- PCTab string `help:"print named pc-value table\nOne of: pctospadj, pctofile, pctoline, pctoinline, pctopcdata"`
+ CompressInstructions int `help:"use compressed instructions when possible (if supported by architecture)"`
+ MayMoreStack string `help:"call named function before all stack growth checks"`
+ PCTab string `help:"print named pc-value table\nOne of: pctospadj, pctofile, pctoline, pctoinline, pctopcdata"`
}
var (
@@ -47,6 +48,8 @@ func init() {
flag.Var(objabi.NewDebugFlag(&DebugFlags, nil), "d", "enable debugging settings; try -d help")
objabi.AddVersionFlag() // -V
objabi.Flagcount("S", "print assembly and machine code", &PrintOut)
+
+ DebugFlags.CompressInstructions = 1
}
// MultiFlag allows setting a value multiple times to collect a list, as in -I=dir1 -I=dir2.
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index f2697db516..25cf307140 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -40,6 +40,7 @@ func main() {
log.Fatalf("unrecognized architecture %s", GOARCH)
}
ctxt := obj.Linknew(architecture.LinkArch)
+ ctxt.CompressInstructions = flags.DebugFlags.CompressInstructions != 0
ctxt.Debugasm = flags.PrintOut
ctxt.Debugvlog = flags.DebugV
ctxt.Flag_dynlink = *flags.Dynlink
diff --git a/src/cmd/compile/internal/base/debug.go b/src/cmd/compile/internal/base/debug.go
index 9e8ab2f488..b532bf435e 100644
--- a/src/cmd/compile/internal/base/debug.go
+++ b/src/cmd/compile/internal/base/debug.go
@@ -20,6 +20,7 @@ type DebugFlags struct {
Append int `help:"print information about append compilation"`
Checkptr int `help:"instrument unsafe pointer conversions\n0: instrumentation disabled\n1: conversions involving unsafe.Pointer are instrumented\n2: conversions to unsafe.Pointer force heap allocation" concurrent:"ok"`
Closure int `help:"print information about closure compilation"`
+ CompressInstructions int `help:"use compressed instructions when possible (if supported by architecture)"`
Converthash string `help:"hash value for use in debugging changes to platform-dependent float-to-[u]int conversion" concurrent:"ok"`
Defer int `help:"print information about defer compilation"`
DisableNil int `help:"disable nil checks" concurrent:"ok"`
diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go
index 1d211e0a2d..63cae41524 100644
--- a/src/cmd/compile/internal/base/flag.go
+++ b/src/cmd/compile/internal/base/flag.go
@@ -177,6 +177,7 @@ func ParseFlags() {
Flag.WB = true
Debug.ConcurrentOk = true
+ Debug.CompressInstructions = 1
Debug.MaxShapeLen = 500
Debug.AlignHot = 1
Debug.InlFuncsWithClosures = 1
@@ -299,6 +300,7 @@ func ParseFlags() {
}
parseSpectre(Flag.Spectre) // left as string for RecordFlags
+ Ctxt.CompressInstructions = Debug.CompressInstructions != 0
Ctxt.Flag_shared = Ctxt.Flag_dynlink || Ctxt.Flag_shared
Ctxt.Flag_optimize = Flag.N == 0
Ctxt.Debugasm = int(Flag.S)
diff --git a/src/cmd/compile/internal/deadlocals/deadlocals.go b/src/cmd/compile/internal/deadlocals/deadlocals.go
index 238450416a..55ad0387a4 100644
--- a/src/cmd/compile/internal/deadlocals/deadlocals.go
+++ b/src/cmd/compile/internal/deadlocals/deadlocals.go
@@ -44,6 +44,11 @@ func Funcs(fns []*ir.Func) {
*as.lhs = ir.BlankNode
*as.rhs = zero
}
+ if len(assigns) > 0 {
+ // k.Defn might be pointing at one of the
+ // assignments we're overwriting.
+ k.Defn = nil
+ }
}
}
}
diff --git a/src/cmd/compile/internal/escape/leaks.go b/src/cmd/compile/internal/escape/leaks.go
index 942f87d2a2..176bccd847 100644
--- a/src/cmd/compile/internal/escape/leaks.go
+++ b/src/cmd/compile/internal/escape/leaks.go
@@ -124,3 +124,21 @@ func parseLeaks(s string) leaks {
copy(l[:], s[4:])
return l
}
+
+func ParseLeaks(s string) leaks {
+ return parseLeaks(s)
+}
+
+// Any reports whether the value flows anywhere at all.
+func (l leaks) Any() bool {
+ // TODO: do mutator/callee matter?
+ if l.Heap() >= 0 || l.Mutator() >= 0 || l.Callee() >= 0 {
+ return true
+ }
+ for i := range numEscResults {
+ if l.Result(i) >= 0 {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 918d3f3514..6418ab9357 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -22,6 +22,7 @@ import (
"cmd/compile/internal/pkginit"
"cmd/compile/internal/reflectdata"
"cmd/compile/internal/rttype"
+ "cmd/compile/internal/slice"
"cmd/compile/internal/ssa"
"cmd/compile/internal/ssagen"
"cmd/compile/internal/staticinit"
@@ -271,6 +272,8 @@ func Main(archInit func(*ssagen.ArchInfo)) {
base.Timer.Start("fe", "escapes")
escape.Funcs(typecheck.Target.Funcs)
+ slice.Funcs(typecheck.Target.Funcs)
+
loopvar.LogTransformations(transformed)
// Collect information for go:nowritebarrierrec
diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go
index 25654ca253..1a3514db6c 100644
--- a/src/cmd/compile/internal/ir/expr.go
+++ b/src/cmd/compile/internal/ir/expr.go
@@ -192,6 +192,7 @@ type CallExpr struct {
IsDDD bool
GoDefer bool // whether this call is part of a go or defer statement
NoInline bool // whether this call must not be inlined
+ UseBuf bool // use stack buffer for backing store (OAPPEND only)
}
func NewCallExpr(pos src.XPos, op Op, fun Node, args []Node) *CallExpr {
@@ -1280,3 +1281,28 @@ func MethodExprFunc(n Node) *types.Field {
base.Fatalf("unexpected node: %v (%v)", n, n.Op())
panic("unreachable")
}
+
+// A MoveToHeapExpr takes a slice as input and moves it to the
+// heap (by copying the backing store if it is not already
+// on the heap).
+type MoveToHeapExpr struct {
+ miniExpr
+ Slice Node
+ // An expression that evaluates to a *runtime._type
+ // that represents the slice element type.
+ RType Node
+ // If PreserveCapacity is true, the capacity of
+ // the resulting slice, and all of the elements in
+ // [len:cap], must be preserved.
+ // If PreserveCapacity is false, the resulting
+ // slice may have any capacity >= len, with any
+ // elements in the resulting [len:cap] range zeroed.
+ PreserveCapacity bool
+}
+
+func NewMoveToHeapExpr(pos src.XPos, slice Node) *MoveToHeapExpr {
+ n := &MoveToHeapExpr{Slice: slice}
+ n.pos = pos
+ n.op = OMOVE2HEAP
+ return n
+}
diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go
index ae4ff62652..eb64cce47b 100644
--- a/src/cmd/compile/internal/ir/fmt.go
+++ b/src/cmd/compile/internal/ir/fmt.go
@@ -574,7 +574,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
// Special case for rune constants.
if typ == types.RuneType || typ == types.UntypedRune {
if x, ok := constant.Uint64Val(val); ok && x <= utf8.MaxRune {
- fmt.Fprintf(s, "%q", x)
+ fmt.Fprintf(s, "%q", rune(x))
return
}
}
diff --git a/src/cmd/compile/internal/ir/name.go b/src/cmd/compile/internal/ir/name.go
index 01f1c0c502..63f1b1c931 100644
--- a/src/cmd/compile/internal/ir/name.go
+++ b/src/cmd/compile/internal/ir/name.go
@@ -43,7 +43,7 @@ type Name struct {
Func *Func // TODO(austin): nil for I.M
Offset_ int64
val constant.Value
- Opt any // for use by escape analysis
+ Opt any // for use by escape or slice analysis
Embed *[]Embed // list of embedded files, for ONAME var
// For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go
index 8c61bb6ed5..f26f61cb18 100644
--- a/src/cmd/compile/internal/ir/node.go
+++ b/src/cmd/compile/internal/ir/node.go
@@ -293,6 +293,7 @@ const (
OLINKSYMOFFSET // offset within a name
OJUMPTABLE // A jump table structure for implementing dense expression switches
OINTERFACESWITCH // A type switch with interface cases
+ OMOVE2HEAP // Promote a stack-backed slice to heap
// opcodes for generics
ODYNAMICDOTTYPE // x = i.(T) where T is a type parameter (or derived from a type parameter)
diff --git a/src/cmd/compile/internal/ir/node_gen.go b/src/cmd/compile/internal/ir/node_gen.go
index 2221045c93..4298b3a43d 100644
--- a/src/cmd/compile/internal/ir/node_gen.go
+++ b/src/cmd/compile/internal/ir/node_gen.go
@@ -1175,6 +1175,34 @@ func (n *MakeExpr) editChildrenWithHidden(edit func(Node) Node) {
}
}
+func (n *MoveToHeapExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
+func (n *MoveToHeapExpr) copy() Node {
+ c := *n
+ c.init = copyNodes(c.init)
+ return &c
+}
+func (n *MoveToHeapExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Slice != nil && do(n.Slice) {
+ return true
+ }
+ return false
+}
+func (n *MoveToHeapExpr) doChildrenWithHidden(do func(Node) bool) bool {
+ return n.doChildren(do)
+}
+func (n *MoveToHeapExpr) editChildren(edit func(Node) Node) {
+ editNodes(n.init, edit)
+ if n.Slice != nil {
+ n.Slice = edit(n.Slice).(Node)
+ }
+}
+func (n *MoveToHeapExpr) editChildrenWithHidden(edit func(Node) Node) {
+ n.editChildren(edit)
+}
+
func (n *Name) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *NilExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go
index 7494beee4c..f042ad84a4 100644
--- a/src/cmd/compile/internal/ir/op_string.go
+++ b/src/cmd/compile/internal/ir/op_string.go
@@ -151,18 +151,19 @@ func _() {
_ = x[OLINKSYMOFFSET-140]
_ = x[OJUMPTABLE-141]
_ = x[OINTERFACESWITCH-142]
- _ = x[ODYNAMICDOTTYPE-143]
- _ = x[ODYNAMICDOTTYPE2-144]
- _ = x[ODYNAMICTYPE-145]
- _ = x[OTAILCALL-146]
- _ = x[OGETG-147]
- _ = x[OGETCALLERSP-148]
- _ = x[OEND-149]
+ _ = x[OMOVE2HEAP-143]
+ _ = x[ODYNAMICDOTTYPE-144]
+ _ = x[ODYNAMICDOTTYPE2-145]
+ _ = x[ODYNAMICTYPE-146]
+ _ = x[OTAILCALL-147]
+ _ = x[OGETG-148]
+ _ = x[OGETCALLERSP-149]
+ _ = x[OEND-150]
}
-const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLEARCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTLNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECVRUNESTRSELRECV2MINMAXREALIMAGCOMPLEXUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWINLCALLMAKEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEINTERFACESWITCHDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERSPEND"
+const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLEARCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTLNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECVRUNESTRSELRECV2MINMAXREALIMAGCOMPLEXUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWINLCALLMAKEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEINTERFACESWITCHMOVE2HEAPDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERSPEND"
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 129, 141, 143, 146, 156, 163, 170, 177, 181, 185, 193, 201, 210, 213, 218, 223, 230, 237, 243, 252, 260, 268, 274, 278, 287, 294, 298, 301, 308, 314, 317, 323, 330, 338, 342, 349, 357, 359, 361, 363, 365, 367, 369, 374, 379, 387, 390, 399, 402, 406, 414, 421, 430, 443, 446, 449, 452, 455, 458, 461, 467, 470, 473, 479, 483, 486, 490, 495, 500, 507, 512, 516, 521, 529, 537, 543, 552, 563, 575, 582, 586, 593, 601, 604, 607, 611, 615, 622, 631, 642, 657, 669, 685, 693, 702, 707, 712, 716, 724, 729, 733, 736, 740, 742, 747, 749, 754, 760, 766, 772, 778, 785, 793, 797, 802, 806, 811, 819, 825, 832, 845, 854, 869, 883, 898, 909, 917, 921, 932, 935}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 129, 141, 143, 146, 156, 163, 170, 177, 181, 185, 193, 201, 210, 213, 218, 223, 230, 237, 243, 252, 260, 268, 274, 278, 287, 294, 298, 301, 308, 314, 317, 323, 330, 338, 342, 349, 357, 359, 361, 363, 365, 367, 369, 374, 379, 387, 390, 399, 402, 406, 414, 421, 430, 443, 446, 449, 452, 455, 458, 461, 467, 470, 473, 479, 483, 486, 490, 495, 500, 507, 512, 516, 521, 529, 537, 543, 552, 563, 575, 582, 586, 593, 601, 604, 607, 611, 615, 622, 631, 642, 657, 669, 685, 693, 702, 707, 712, 716, 724, 729, 733, 736, 740, 742, 747, 749, 754, 760, 766, 772, 778, 785, 793, 797, 802, 806, 811, 819, 825, 832, 845, 854, 869, 878, 892, 907, 918, 926, 930, 941, 944}
func (i Op) String() string {
if i >= Op(len(_Op_index)-1) {
diff --git a/src/cmd/compile/internal/ir/stmt.go b/src/cmd/compile/internal/ir/stmt.go
index 0801ecdd9e..affa5f4551 100644
--- a/src/cmd/compile/internal/ir/stmt.go
+++ b/src/cmd/compile/internal/ir/stmt.go
@@ -42,6 +42,7 @@ func (*Decl) isStmt() {}
type Stmt interface {
Node
isStmt()
+ PtrInit() *Nodes
}
// A miniStmt is a miniNode with extra fields common to statements.
diff --git a/src/cmd/compile/internal/ir/symtab.go b/src/cmd/compile/internal/ir/symtab.go
index 344985f7be..4b5bf17a3d 100644
--- a/src/cmd/compile/internal/ir/symtab.go
+++ b/src/cmd/compile/internal/ir/symtab.go
@@ -29,6 +29,11 @@ type symsStruct struct {
GCWriteBarrier [8]*obj.LSym
Goschedguarded *obj.LSym
Growslice *obj.LSym
+ GrowsliceBuf *obj.LSym
+ MoveSlice *obj.LSym
+ MoveSliceNoScan *obj.LSym
+ MoveSliceNoCap *obj.LSym
+ MoveSliceNoCapNoScan *obj.LSym
InterfaceSwitch *obj.LSym
MallocGC *obj.LSym
MallocGCSmallNoScan [27]*obj.LSym
diff --git a/src/cmd/compile/internal/loong64/ssa.go b/src/cmd/compile/internal/loong64/ssa.go
index 84bbf9b394..71953109c4 100644
--- a/src/cmd/compile/internal/loong64/ssa.go
+++ b/src/cmd/compile/internal/loong64/ssa.go
@@ -575,6 +575,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
case ssa.OpLOONG64LoweredZeroLoop:
ptrReg := v.Args[0].Reg()
countReg := v.RegTmp()
+ flagReg := int16(loong64.REGTMP)
var off int64
n := v.AuxInt
loopSize := int64(64)
@@ -587,58 +588,119 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
// vs
// 16 instuctions in the straightline code
// Might as well use straightline code.
- v.Fatalf("ZeroLoop size tool small %d", n)
+ v.Fatalf("ZeroLoop size too small %d", n)
}
- // Put iteration count in a register.
- // MOVV $n/loopSize, countReg
- p := s.Prog(loong64.AMOVV)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = n / loopSize
- p.To.Type = obj.TYPE_REG
- p.To.Reg = countReg
- cntInit := p
+ // MOVV $n/loopSize, countReg
+ // MOVBU ir.Syms.Loong64HasLSX, flagReg
+ // BNE flagReg, lsxInit
+ // genericInit:
+ // for off = 0; off < loopSize; off += 8 {
+ // zero8(s, ptrReg, off)
+ // }
+ // ADDV $loopSize, ptrReg
+ // SUBV $1, countReg
+ // BNE countReg, genericInit
+ // JMP tail
+ // lsxInit:
+ // VXORV V31, V31, V31, v31 = 0
+ // for off = 0; off < loopSize; off += 16 {
+ // zero16(s, V31, ptrReg, off)
+ // }
+ // ADDV $loopSize, ptrReg
+ // SUBV $1, countReg
+ // BNE countReg, lsxInit
+ // tail:
+ // n %= loopSize
+ // for off = 0; n >= 8; off += 8, n -= 8 {
+ // zero8(s, ptrReg, off)
+ // }
+ //
+ // if n != 0 {
+ // zero8(s, ptrReg, off+n-8)
+ // }
- // Zero loopSize bytes starting at ptrReg.
- for range loopSize / 8 {
- // MOVV ZR, off(ptrReg)
+ p1 := s.Prog(loong64.AMOVV)
+ p1.From.Type = obj.TYPE_CONST
+ p1.From.Offset = n / loopSize
+ p1.To.Type = obj.TYPE_REG
+ p1.To.Reg = countReg
+
+ p2 := s.Prog(loong64.AMOVBU)
+ p2.From.Type = obj.TYPE_MEM
+ p2.From.Name = obj.NAME_EXTERN
+ p2.From.Sym = ir.Syms.Loong64HasLSX
+ p2.To.Type = obj.TYPE_REG
+ p2.To.Reg = flagReg
+
+ p3 := s.Prog(loong64.ABNE)
+ p3.From.Type = obj.TYPE_REG
+ p3.From.Reg = flagReg
+ p3.To.Type = obj.TYPE_BRANCH
+
+ for off = 0; off < loopSize; off += 8 {
zero8(s, ptrReg, off)
- off += 8
}
- // Increment ptrReg by loopSize.
- // ADDV $loopSize, ptrReg
- p = s.Prog(loong64.AADDV)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = loopSize
- p.To.Type = obj.TYPE_REG
- p.To.Reg = ptrReg
+ p4 := s.Prog(loong64.AADDV)
+ p4.From.Type = obj.TYPE_CONST
+ p4.From.Offset = loopSize
+ p4.To.Type = obj.TYPE_REG
+ p4.To.Reg = ptrReg
- // Decrement loop count.
- // SUBV $1, countReg
- p = s.Prog(loong64.ASUBV)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 1
- p.To.Type = obj.TYPE_REG
- p.To.Reg = countReg
+ p5 := s.Prog(loong64.ASUBV)
+ p5.From.Type = obj.TYPE_CONST
+ p5.From.Offset = 1
+ p5.To.Type = obj.TYPE_REG
+ p5.To.Reg = countReg
- // Jump to loop header if we're not done yet.
- // BNE countReg, loop header
- p = s.Prog(loong64.ABNE)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = countReg
- p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(cntInit.Link)
+ p6 := s.Prog(loong64.ABNE)
+ p6.From.Type = obj.TYPE_REG
+ p6.From.Reg = countReg
+ p6.To.Type = obj.TYPE_BRANCH
+ p6.To.SetTarget(p3.Link)
+
+ p7 := s.Prog(obj.AJMP)
+ p7.To.Type = obj.TYPE_BRANCH
+
+ p8 := s.Prog(loong64.AVXORV)
+ p8.From.Type = obj.TYPE_REG
+ p8.From.Reg = loong64.REG_V31
+ p8.To.Type = obj.TYPE_REG
+ p8.To.Reg = loong64.REG_V31
+ p3.To.SetTarget(p8)
+
+ for off = 0; off < loopSize; off += 16 {
+ zero16(s, loong64.REG_V31, ptrReg, off)
+ }
+
+ p9 := s.Prog(loong64.AADDV)
+ p9.From.Type = obj.TYPE_CONST
+ p9.From.Offset = loopSize
+ p9.To.Type = obj.TYPE_REG
+ p9.To.Reg = ptrReg
+
+ p10 := s.Prog(loong64.ASUBV)
+ p10.From.Type = obj.TYPE_CONST
+ p10.From.Offset = 1
+ p10.To.Type = obj.TYPE_REG
+ p10.To.Reg = countReg
+
+ p11 := s.Prog(loong64.ABNE)
+ p11.From.Type = obj.TYPE_REG
+ p11.From.Reg = countReg
+ p11.To.Type = obj.TYPE_BRANCH
+ p11.To.SetTarget(p8.Link)
+
+ p12 := s.Prog(obj.ANOP)
+ p7.To.SetTarget(p12)
// Multiples of the loop size are now done.
n %= loopSize
-
- off = 0
// Write any fractional portion.
- for n >= 8 {
- // MOVV ZR, off(ptrReg)
+ for off = 0; n >= 8; off += 8 {
+ // MOVV ZR, off(ptrReg)
zero8(s, ptrReg, off)
- off += 8
n -= 8
}
@@ -1333,7 +1395,7 @@ func move8(s *ssagen.State, src, dst, tmp int16, off int64) {
// zero8 zeroes 8 bytes at reg+off.
func zero8(s *ssagen.State, reg int16, off int64) {
- // MOVV ZR, off(reg)
+ // MOVV ZR, off(reg)
p := s.Prog(loong64.AMOVV)
p.From.Type = obj.TYPE_REG
p.From.Reg = loong64.REGZERO
@@ -1341,3 +1403,14 @@ func zero8(s *ssagen.State, reg int16, off int64) {
p.To.Reg = reg
p.To.Offset = off
}
+
+// zero16 zeroes 16 bytes at reg+off.
+func zero16(s *ssagen.State, regZero, regBase int16, off int64) {
+ // VMOVQ regZero, off(regBase)
+ p := s.Prog(loong64.AVMOVQ)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = regZero
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = regBase
+ p.To.Offset = off
+}
diff --git a/src/cmd/compile/internal/slice/slice.go b/src/cmd/compile/internal/slice/slice.go
new file mode 100644
index 0000000000..7a32e7adbd
--- /dev/null
+++ b/src/cmd/compile/internal/slice/slice.go
@@ -0,0 +1,455 @@
+// Copyright 2025 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 slice
+
+// This file implements a stack-allocation optimization
+// for the backing store of slices.
+//
+// Consider the code:
+//
+// var s []int
+// for i := range ... {
+// s = append(s, i)
+// }
+// return s
+//
+// Some of the append operations will need to do an allocation
+// by calling growslice. This will happen on the 1st, 2nd, 4th,
+// 8th, etc. append calls. The allocations done by all but the
+// last growslice call will then immediately be garbage.
+//
+// We'd like to avoid doing some of those intermediate
+// allocations if possible.
+//
+// If we can determine that the "return s" statement is the
+// *only* way that the backing store for s escapes, then we
+// can rewrite the code to something like:
+//
+// var s []int
+// for i := range N {
+// s = append(s, i)
+// }
+// s = move2heap(s)
+// return s
+//
+// Using the move2heap runtime function, which does:
+//
+// move2heap(s):
+// If s is not backed by a stackframe-allocated
+// backing store, return s. Otherwise, copy s
+// to the heap and return the copy.
+//
+// Now we can treat the backing store of s allocated at the
+// append site as not escaping. Previous stack allocation
+// optimizations now apply, which can use a fixed-size
+// stack-allocated backing store for s when appending.
+// (See ../ssagen/ssa.go:(*state).append)
+//
+// It is tricky to do this optimization safely. To describe
+// our analysis, we first define what an "exclusive" slice
+// variable is.
+//
+// A slice variable (a variable of slice type) is called
+// "exclusive" if, when it has a reference to a
+// stackframe-allocated backing store, it is the only
+// variable with such a reference.
+//
+// In other words, a slice variable is exclusive if
+// any of the following holds:
+// 1) It points to a heap-allocated backing store
+// 2) It points to a stack-allocated backing store
+// for any parent frame.
+// 3) It is the only variable that references its
+// backing store.
+// 4) It is nil.
+//
+// The nice thing about exclusive slice variables is that
+// it is always safe to do
+// s = move2heap(s)
+// whenever s is an exclusive slice variable. Because no
+// one else has a reference to the backing store, no one
+// else can tell that we moved the backing store from one
+// location to another.
+//
+// Note that exclusiveness is a dynamic property. A slice
+// variable may be exclusive during some parts of execution
+// and not exclusive during others.
+//
+// The following operations set or preserve the exclusivity
+// of a slice variable s:
+// s = nil
+// s = append(s, ...)
+// s = s[i:j]
+// ... = s[i]
+// s[i] = ...
+// f(s) where f does not escape its argument
+// Other operations destroy exclusivity. A non-exhaustive list includes:
+// x = s
+// *p = s
+// f(s) where f escapes its argument
+// return s
+// To err on the safe side, we white list exclusivity-preserving
+// operations and we asssume that any other operations that mention s
+// destroy its exclusivity.
+//
+// Our strategy is to move the backing store of s to the heap before
+// any exclusive->nonexclusive transition. That way, s will only ever
+// have a reference to a stack backing store while it is exclusive.
+//
+// move2heap for a variable s is implemented with:
+// if s points to within the stack frame {
+// s2 := make([]T, s.len, s.cap)
+// copy(s2[:s.cap], s[:s.cap])
+// s = s2
+// }
+// Note that in general we need to copy all of s[:cap(s)] elements when
+// moving to the heap. As an optimization, we keep track of slice variables
+// whose capacity, and the elements in s[len(s):cap(s)], are never accessed.
+// For those slice variables, we can allocate to the next size class above
+// the length, which saves memory and copying cost.
+
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/escape"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/reflectdata"
+)
+
+func Funcs(all []*ir.Func) {
+ if base.Flag.N != 0 {
+ return
+ }
+ for _, fn := range all {
+ analyze(fn)
+ }
+}
+
+func analyze(fn *ir.Func) {
+ type sliceInfo struct {
+ // Slice variable.
+ s *ir.Name
+
+ // Count of uses that this pass understands.
+ okUses int32
+ // Count of all uses found.
+ allUses int32
+
+ // A place where the slice variable transitions from
+ // exclusive to nonexclusive.
+ // We could keep track of more than one, but one is enough for now.
+ // Currently, this can be either a return statement or
+ // an assignment.
+ // TODO: other possible transitions?
+ transition ir.Stmt
+
+ // Each s = append(s, ...) instance we found.
+ appends []*ir.CallExpr
+
+ // Weight of the number of s = append(s, ...) instances we found.
+ // The optimizations we do are only really useful if there are at
+ // least weight 2. (Note: appends in loops have weight >= 2.)
+ appendWeight int
+
+ // Whether we ever do cap(s), or other operations that use cap(s)
+ // (possibly implicitly), like s[i:j].
+ capUsed bool
+ }
+
+ // Every variable (*ir.Name) that we are tracking will have
+ // a non-nil *sliceInfo in its Opt field.
+ haveLocalSlice := false
+ maxStackSize := int64(base.Debug.VariableMakeThreshold)
+ var namedRets []*ir.Name
+ for _, s := range fn.Dcl {
+ if !s.Type().IsSlice() {
+ continue
+ }
+ if s.Type().Elem().Size() > maxStackSize {
+ continue
+ }
+ if !base.VariableMakeHash.MatchPos(s.Pos(), nil) {
+ continue
+ }
+ s.Opt = &sliceInfo{s: s} // start tracking s
+ haveLocalSlice = true
+ if s.Class == ir.PPARAMOUT {
+ namedRets = append(namedRets, s)
+ }
+ }
+ if !haveLocalSlice {
+ return
+ }
+
+ // Keep track of loop depth while walking.
+ loopDepth := 0
+
+ // tracking returns the info for the slice variable if n is a slice
+ // variable that we're still considering, or nil otherwise.
+ tracking := func(n ir.Node) *sliceInfo {
+ if n == nil || n.Op() != ir.ONAME {
+ return nil
+ }
+ s := n.(*ir.Name)
+ if s.Opt == nil {
+ return nil
+ }
+ return s.Opt.(*sliceInfo)
+ }
+
+ // addTransition(n, loc) records that s experiences an exclusive->nonexclusive
+ // transition somewhere within loc.
+ addTransition := func(i *sliceInfo, loc ir.Stmt) {
+ if i.transition != nil {
+ // We only keep track of a single exclusive->nonexclusive transition
+ // for a slice variable. If we find more than one, give up.
+ // (More than one transition location would be fine, but we would
+ // start to get worried about introducing too much additional code.)
+ i.s.Opt = nil
+ return
+ }
+ i.transition = loc
+ }
+
+ // Examine an x = y assignment that occurs somewhere within statement stmt.
+ assign := func(x, y ir.Node, stmt ir.Stmt) {
+ if i := tracking(x); i != nil {
+ // s = y. Check for understood patterns for y.
+ if y == nil || y.Op() == ir.ONIL {
+ // s = nil is ok.
+ i.okUses++
+ } else if y.Op() == ir.OSLICELIT {
+ // s = []{...} is ok.
+ // Note: this reveals capacity. Should it?
+ i.okUses++
+ i.capUsed = true
+ } else if y.Op() == ir.OSLICE {
+ y := y.(*ir.SliceExpr)
+ if y.X == i.s {
+ // s = s[...:...] is ok
+ i.okUses += 2
+ i.capUsed = true
+ }
+ } else if y.Op() == ir.OAPPEND {
+ y := y.(*ir.CallExpr)
+ if y.Args[0] == i.s {
+ // s = append(s, ...) is ok
+ i.okUses += 2
+ i.appends = append(i.appends, y)
+ i.appendWeight += 1 + loopDepth
+ }
+ // TODO: s = append(nil, ...)?
+ }
+ // Note that technically s = make([]T, ...) preserves exclusivity, but
+ // we don't track that because we assume users who wrote that know
+ // better than the compiler does.
+
+ // TODO: figure out how to handle s = fn(..., s, ...)
+ // It would be nice to maintain exclusivity of s in this situation.
+ // But unfortunately, fn can return one of its other arguments, which
+ // may be a slice with a stack-allocated backing store other than s.
+ // (which may have preexisting references to its backing store).
+ //
+ // Maybe we could do it if s is the only argument?
+ }
+
+ if i := tracking(y); i != nil {
+ // ... = s
+ // Treat this as an exclusive->nonexclusive transition.
+ i.okUses++
+ addTransition(i, stmt)
+ }
+ }
+
+ var do func(ir.Node) bool
+ do = func(n ir.Node) bool {
+ if n == nil {
+ return false
+ }
+ switch n.Op() {
+ case ir.ONAME:
+ if i := tracking(n); i != nil {
+ // A use of a slice variable. Count it.
+ i.allUses++
+ }
+ case ir.ODCL:
+ n := n.(*ir.Decl)
+ if i := tracking(n.X); i != nil {
+ i.okUses++
+ }
+ case ir.OINDEX:
+ n := n.(*ir.IndexExpr)
+ if i := tracking(n.X); i != nil {
+ // s[i] is ok.
+ i.okUses++
+ }
+ case ir.OLEN:
+ n := n.(*ir.UnaryExpr)
+ if i := tracking(n.X); i != nil {
+ // len(s) is ok
+ i.okUses++
+ }
+ case ir.OCAP:
+ n := n.(*ir.UnaryExpr)
+ if i := tracking(n.X); i != nil {
+ // cap(s) is ok
+ i.okUses++
+ i.capUsed = true
+ }
+ case ir.OADDR:
+ n := n.(*ir.AddrExpr)
+ if n.X.Op() == ir.OINDEX {
+ n := n.X.(*ir.IndexExpr)
+ if i := tracking(n.X); i != nil {
+ // &s[i] is definitely a nonexclusive transition.
+ // (We need this case because s[i] is ok, but &s[i] is not.)
+ i.s.Opt = nil
+ }
+ }
+ case ir.ORETURN:
+ n := n.(*ir.ReturnStmt)
+ for _, x := range n.Results {
+ if i := tracking(x); i != nil {
+ i.okUses++
+ // We go exclusive->nonexclusive here
+ addTransition(i, n)
+ }
+ }
+ if len(n.Results) == 0 {
+ // Uses of named result variables are implicit here.
+ for _, x := range namedRets {
+ if i := tracking(x); i != nil {
+ addTransition(i, n)
+ }
+ }
+ }
+ case ir.OCALLFUNC:
+ n := n.(*ir.CallExpr)
+ for idx, arg := range n.Args {
+ if i := tracking(arg); i != nil {
+ if !argLeak(n, idx) {
+ // Passing s to a nonescaping arg is ok.
+ i.okUses++
+ i.capUsed = true
+ }
+ }
+ }
+ case ir.ORANGE:
+ // Range over slice is ok.
+ n := n.(*ir.RangeStmt)
+ if i := tracking(n.X); i != nil {
+ i.okUses++
+ }
+ case ir.OAS:
+ n := n.(*ir.AssignStmt)
+ assign(n.X, n.Y, n)
+ case ir.OAS2:
+ n := n.(*ir.AssignListStmt)
+ for i := range len(n.Lhs) {
+ assign(n.Lhs[i], n.Rhs[i], n)
+ }
+ case ir.OCLOSURE:
+ n := n.(*ir.ClosureExpr)
+ for _, v := range n.Func.ClosureVars {
+ do(v.Outer)
+ }
+ }
+ if n.Op() == ir.OFOR || n.Op() == ir.ORANGE {
+ // Note: loopDepth isn't really right for init portion
+ // of the for statement, but that's ok. Correctness
+ // does not depend on depth info.
+ loopDepth++
+ defer func() { loopDepth-- }()
+ }
+ // Check all the children.
+ ir.DoChildren(n, do)
+ return false
+ }
+
+ // Run the analysis over the whole body.
+ for _, stmt := range fn.Body {
+ do(stmt)
+ }
+
+ // Process accumulated info to find slice variables
+ // that we can allocate on the stack.
+ for _, s := range fn.Dcl {
+ if s.Opt == nil {
+ continue
+ }
+ i := s.Opt.(*sliceInfo)
+ s.Opt = nil
+ if i.okUses != i.allUses {
+ // Some use of i.s that don't understand lurks. Give up.
+ continue
+ }
+
+ // At this point, we've decided that we *can* do
+ // the optimization.
+
+ if i.transition == nil {
+ // Exclusive for its whole lifetime. That means it
+ // didn't escape. We can already handle nonescaping
+ // slices without this pass.
+ continue
+ }
+ if i.appendWeight < 2 {
+ // This optimization only really helps if there is
+ // (dynamically) more than one append.
+ continue
+ }
+
+ // Commit point - at this point we've decided we *should*
+ // do the optimization.
+
+ // Insert a move2heap operation before the exclusive->nonexclusive
+ // transition.
+ move := ir.NewMoveToHeapExpr(i.transition.Pos(), i.s)
+ if i.capUsed {
+ move.PreserveCapacity = true
+ }
+ move.RType = reflectdata.AppendElemRType(i.transition.Pos(), i.appends[0])
+ move.SetType(i.s.Type())
+ move.SetTypecheck(1)
+ as := ir.NewAssignStmt(i.transition.Pos(), i.s, move)
+ as.SetTypecheck(1)
+ i.transition.PtrInit().Prepend(as)
+ // Note: we prepend because we need to put the move2heap
+ // operation first, before any other init work, as the transition
+ // might occur in the init work.
+
+ // Now that we've inserted a move2heap operation before every
+ // exclusive -> nonexclusive transition, appends can now use
+ // stack backing stores.
+ // (This is the whole point of this pass, to enable stack
+ // allocation of append backing stores.)
+ for _, a := range i.appends {
+ a.SetEsc(ir.EscNone)
+ if i.capUsed {
+ a.UseBuf = true
+ }
+ }
+ }
+}
+
+// argLeak reports if the idx'th argument to the call n escapes anywhere
+// (to the heap, another argument, return value, etc.)
+// If unknown returns true.
+func argLeak(n *ir.CallExpr, idx int) bool {
+ if n.Op() != ir.OCALLFUNC {
+ return true
+ }
+ fn := ir.StaticCalleeName(ir.StaticValue(n.Fun))
+ if fn == nil {
+ return true
+ }
+ fntype := fn.Type()
+ if recv := fntype.Recv(); recv != nil {
+ if idx == 0 {
+ return escape.ParseLeaks(recv.Note).Any()
+ }
+ idx--
+ }
+ return escape.ParseLeaks(fntype.Params()[idx].Note).Any()
+}
diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go
index 1e9eb0146e..e77f55ab5e 100644
--- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go
@@ -156,6 +156,7 @@ func init() {
gp11sb = regInfo{inputs: []regMask{gpspsbg}, outputs: gponly}
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
+ gp21sp2 = regInfo{inputs: []regMask{gp, gpsp}, outputs: gponly}
gp21sb = regInfo{inputs: []regMask{gpspsbg, gpsp}, outputs: gponly}
gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}}
gp31shift = regInfo{inputs: []regMask{gp, gp, cx}, outputs: []regMask{gp}}
@@ -361,7 +362,7 @@ func init() {
{name: "ADDQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"},
{name: "ADDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"},
- {name: "SUBQ", argLength: 2, reg: gp21, asm: "SUBQ", resultInArg0: true, clobberFlags: true},
+ {name: "SUBQ", argLength: 2, reg: gp21sp2, asm: "SUBQ", resultInArg0: true, clobberFlags: true},
{name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true, clobberFlags: true},
{name: "SUBQconst", argLength: 1, reg: gp11, asm: "SUBQ", aux: "Int32", resultInArg0: true, clobberFlags: true},
{name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true, clobberFlags: true},
diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64.rules b/src/cmd/compile/internal/ssa/_gen/ARM64.rules
index f54a692725..53bb35d289 100644
--- a/src/cmd/compile/internal/ssa/_gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/ARM64.rules
@@ -573,6 +573,8 @@
(TBNZ [0] (GreaterThanF cc) yes no) => (FGT cc yes no)
(TBNZ [0] (GreaterEqualF cc) yes no) => (FGE cc yes no)
+(TB(Z|NZ) [0] (XORconst [1] x) yes no) => (TB(NZ|Z) [0] x yes no)
+
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 => ((EQ|NE|LT|LE|GT|GE) (TST x y) yes no)
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] x:(ANDconst [c] y)) yes no) && x.Uses == 1 => ((EQ|NE|LT|LE|GT|GE) (TSTconst [c] y) yes no)
((EQ|NE|LT|LE|GT|GE) (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 => ((EQ|NE|LT|LE|GT|GE) (TSTW x y) yes no)
@@ -1814,3 +1816,7 @@
(Select0 (Mul64uover x y)) => (MUL x y)
(Select1 (Mul64uover x y)) => (NotEqual (CMPconst (UMULH <typ.UInt64> x y) [0]))
+
+// 32 mul 32 -> 64
+(MUL r:(MOVWUreg x) s:(MOVWUreg y)) && r.Uses == 1 && s.Uses == 1 => (UMULL x y)
+(MUL r:(MOVWreg x) s:(MOVWreg y)) && r.Uses == 1 && s.Uses == 1 => (MULL x y)
diff --git a/src/cmd/compile/internal/ssa/_gen/LOONG64.rules b/src/cmd/compile/internal/ssa/_gen/LOONG64.rules
index 9691296043..2beba0b1c5 100644
--- a/src/cmd/compile/internal/ssa/_gen/LOONG64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/LOONG64.rules
@@ -743,9 +743,6 @@
(MULV x (MOVVconst [c])) && canMulStrengthReduce(config, c) => {mulStrengthReduce(v, x, c)}
-(MULV (NEGV x) (MOVVconst [c])) => (MULV x (MOVVconst [-c]))
-(MULV (NEGV x) (NEGV y)) => (MULV x y)
-
(ADDV x0 x1:(SLLVconst [c] y)) && x1.Uses == 1 && c > 0 && c <= 4 => (ADDshiftLLV x0 y [c])
// fold constant in ADDshift op
diff --git a/src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go b/src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go
index 7e8b8bf497..81d3a3665b 100644
--- a/src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go
+++ b/src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go
@@ -388,6 +388,7 @@ func init() {
argLength: 2,
reg: regInfo{
inputs: []regMask{gp},
+ clobbers: buildReg("F31"),
clobbersArg0: true,
},
faultOnNilArg0: true,
diff --git a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
index 646948f2df..13a8cab3b5 100644
--- a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
@@ -689,36 +689,36 @@
(MOVDnop (MOVDconst [c])) => (MOVDconst [c])
// Avoid unnecessary zero and sign extension when right shifting.
-(SRAI <t> [x] (MOVWreg y)) && x >= 0 && x <= 31 => (SRAIW <t> [int64(x)] y)
-(SRLI <t> [x] (MOVWUreg y)) && x >= 0 && x <= 31 => (SRLIW <t> [int64(x)] y)
+(SRAI [x] (MOVWreg y)) && x >= 0 && x <= 31 => (SRAIW [x] y)
+(SRLI [x] (MOVWUreg y)) && x >= 0 && x <= 31 => (SRLIW [x] y)
// Replace right shifts that exceed size of signed type.
(SRAI <t> [x] (MOVBreg y)) && x >= 8 => (SRAI [63] (SLLI <t> [56] y))
(SRAI <t> [x] (MOVHreg y)) && x >= 16 => (SRAI [63] (SLLI <t> [48] y))
-(SRAI <t> [x] (MOVWreg y)) && x >= 32 => (SRAIW [31] y)
+(SRAI [x] (MOVWreg y)) && x >= 32 => (SRAIW [31] y)
// Eliminate right shifts that exceed size of unsigned type.
-(SRLI <t> [x] (MOVBUreg y)) && x >= 8 => (MOVDconst <t> [0])
-(SRLI <t> [x] (MOVHUreg y)) && x >= 16 => (MOVDconst <t> [0])
-(SRLI <t> [x] (MOVWUreg y)) && x >= 32 => (MOVDconst <t> [0])
+(SRLI [x] (MOVBUreg y)) && x >= 8 => (MOVDconst [0])
+(SRLI [x] (MOVHUreg y)) && x >= 16 => (MOVDconst [0])
+(SRLI [x] (MOVWUreg y)) && x >= 32 => (MOVDconst [0])
// Fold constant into immediate instructions where possible.
(ADD (MOVDconst <t> [val]) x) && is32Bit(val) && !t.IsPtr() => (ADDI [val] x)
(AND (MOVDconst [val]) x) && is32Bit(val) => (ANDI [val] x)
(OR (MOVDconst [val]) x) && is32Bit(val) => (ORI [val] x)
(XOR (MOVDconst [val]) x) && is32Bit(val) => (XORI [val] x)
-(ROL x (MOVDconst [val])) => (RORI [int64(int8(-val)&63)] x)
-(ROLW x (MOVDconst [val])) => (RORIW [int64(int8(-val)&31)] x)
-(ROR x (MOVDconst [val])) => (RORI [int64(val&63)] x)
-(RORW x (MOVDconst [val])) => (RORIW [int64(val&31)] x)
-(SLL x (MOVDconst [val])) => (SLLI [int64(val&63)] x)
-(SRL x (MOVDconst [val])) => (SRLI [int64(val&63)] x)
-(SLLW x (MOVDconst [val])) => (SLLIW [int64(val&31)] x)
-(SRLW x (MOVDconst [val])) => (SRLIW [int64(val&31)] x)
-(SRA x (MOVDconst [val])) => (SRAI [int64(val&63)] x)
-(SRAW x (MOVDconst [val])) => (SRAIW [int64(val&31)] x)
-(SLT x (MOVDconst [val])) && val >= -2048 && val <= 2047 => (SLTI [val] x)
-(SLTU x (MOVDconst [val])) && val >= -2048 && val <= 2047 => (SLTIU [val] x)
+(ROL x (MOVDconst [val])) => (RORI [-val&63] x)
+(ROLW x (MOVDconst [val])) => (RORIW [-val&31] x)
+(ROR x (MOVDconst [val])) => (RORI [val&63] x)
+(RORW x (MOVDconst [val])) => (RORIW [val&31] x)
+(SLL x (MOVDconst [val])) => (SLLI [val&63] x)
+(SLLW x (MOVDconst [val])) => (SLLIW [val&31] x)
+(SRL x (MOVDconst [val])) => (SRLI [val&63] x)
+(SRLW x (MOVDconst [val])) => (SRLIW [val&31] x)
+(SRA x (MOVDconst [val])) => (SRAI [val&63] x)
+(SRAW x (MOVDconst [val])) => (SRAIW [val&31] x)
+(SLT x (MOVDconst [val])) && is12Bit(val) => (SLTI [val] x)
+(SLTU x (MOVDconst [val])) && is12Bit(val) => (SLTIU [val] x)
// Replace negated left rotation with right rotation.
(ROL x (NEG y)) => (ROR x y)
@@ -782,7 +782,7 @@
(SRAI [x] (MOVDconst [y])) => (MOVDconst [int64(y) >> uint32(x)])
// Combine doubling via addition with shift.
-(SLLI <t> [c] (ADD x x)) && c < t.Size() * 8 - 1 => (SLLI <t> [c+1] x)
+(SLLI <t> [c] (ADD x x)) && c < t.Size() * 8 - 1 => (SLLI [c+1] x)
(SLLI <t> [c] (ADD x x)) && c >= t.Size() * 8 - 1 => (MOVDconst [0])
// SLTI/SLTIU with constants.
@@ -792,7 +792,6 @@
// SLTI/SLTIU with known outcomes.
(SLTI [x] (ANDI [y] _)) && y >= 0 && int64(y) < int64(x) => (MOVDconst [1])
(SLTIU [x] (ANDI [y] _)) && y >= 0 && uint64(y) < uint64(x) => (MOVDconst [1])
-(SLTI [x] (ORI [y] _)) && y >= 0 && int64(y) >= int64(x) => (MOVDconst [0])
(SLTIU [x] (ORI [y] _)) && y >= 0 && uint64(y) >= uint64(x) => (MOVDconst [0])
// SLT/SLTU with known outcomes.
diff --git a/src/cmd/compile/internal/ssa/_gen/dec.rules b/src/cmd/compile/internal/ssa/_gen/dec.rules
index 9f6dc36975..fce0026211 100644
--- a/src/cmd/compile/internal/ssa/_gen/dec.rules
+++ b/src/cmd/compile/internal/ssa/_gen/dec.rules
@@ -97,8 +97,10 @@
// Helpers for expand calls
// Some of these are copied from generic.rules
-(IMake _typ (StructMake val)) => (IMake _typ val)
-(StructSelect [0] (IData x)) => (IData x)
+(IMake _typ (StructMake ___)) => imakeOfStructMake(v)
+(StructSelect (IData x)) && v.Type.Size() > 0 => (IData x)
+(StructSelect (IData x)) && v.Type.Size() == 0 && v.Type.IsStruct() => (StructMake)
+(StructSelect (IData x)) && v.Type.Size() == 0 && v.Type.IsArray() => (ArrayMake0)
(StructSelect [i] x:(StructMake ___)) => x.Args[i]
@@ -109,7 +111,7 @@
// More annoying case: (ArraySelect[0] (StructSelect[0] isAPtr))
// There, result of the StructSelect is an Array (not a pointer) and
// the pre-rewrite input to the ArraySelect is a struct, not a pointer.
-(StructSelect [0] x) && x.Type.IsPtrShaped() => x
+(StructSelect x) && x.Type.IsPtrShaped() => x
(ArraySelect [0] x) && x.Type.IsPtrShaped() => x
// These, too. Bits is bits.
@@ -119,6 +121,7 @@
(Store _ (StructMake ___) _) => rewriteStructStore(v)
+(IMake _typ (ArrayMake1 val)) => (IMake _typ val)
(ArraySelect (ArrayMake1 x)) => x
(ArraySelect [0] (IData x)) => (IData x)
diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules
index ccdf0bf50d..6a213cd03a 100644
--- a/src/cmd/compile/internal/ssa/_gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/_gen/generic.rules
@@ -195,6 +195,11 @@
// Convert x * -1 to -x.
(Mul(8|16|32|64) (Const(8|16|32|64) [-1]) x) => (Neg(8|16|32|64) x)
+// Convert -x * c to x * -c
+(Mul(8|16|32|64) (Const(8|16|32|64) <t> [c]) (Neg(8|16|32|64) x)) => (Mul(8|16|32|64) x (Const(8|16|32|64) <t> [-c]))
+
+(Mul(8|16|32|64) (Neg(8|16|32|64) x) (Neg(8|16|32|64) y)) => (Mul(8|16|32|64) x y)
+
// DeMorgan's Laws
(And(8|16|32|64) <t> (Com(8|16|32|64) x) (Com(8|16|32|64) y)) => (Com(8|16|32|64) (Or(8|16|32|64) <t> x y))
(Or(8|16|32|64) <t> (Com(8|16|32|64) x) (Com(8|16|32|64) y)) => (Com(8|16|32|64) (And(8|16|32|64) <t> x y))
@@ -337,6 +342,12 @@
(OrB ((Less|Leq)16U (Const16 [c]) x) (Leq16U x (Const16 [d]))) && uint16(c) >= uint16(d+1) && uint16(d+1) > uint16(d) => ((Less|Leq)16U (Const16 <x.Type> [c-d-1]) (Sub16 <x.Type> x (Const16 <x.Type> [d+1])))
(OrB ((Less|Leq)8U (Const8 [c]) x) (Leq8U x (Const8 [d]))) && uint8(c) >= uint8(d+1) && uint8(d+1) > uint8(d) => ((Less|Leq)8U (Const8 <x.Type> [c-d-1]) (Sub8 <x.Type> x (Const8 <x.Type> [d+1])))
+// single bit difference: ( x != c && x != d ) -> ( x|(c^d) != c )
+(AndB (Neq(64|32|16|8) x cv:(Const(64|32|16|8) [c])) (Neq(64|32|16|8) x (Const(64|32|16|8) [d]))) && c|d == c && oneBit(c^d) => (Neq(64|32|16|8) (Or(64|32|16|8) <x.Type> x (Const(64|32|16|8) <x.Type> [c^d])) cv)
+
+// single bit difference: ( x == c || x == d ) -> ( x|(c^d) == c )
+(OrB (Eq(64|32|16|8) x cv:(Const(64|32|16|8) [c])) (Eq(64|32|16|8) x (Const(64|32|16|8) [d]))) && c|d == c && oneBit(c^d) => (Eq(64|32|16|8) (Or(64|32|16|8) <x.Type> x (Const(64|32|16|8) <x.Type> [c^d])) cv)
+
// NaN check: ( x != x || x (>|>=|<|<=) c ) -> ( !(c (>=|>|<=|<) x) )
(OrB (Neq64F x x) ((Less|Leq)64F x y:(Const64F [c]))) => (Not ((Leq|Less)64F y x))
(OrB (Neq64F x x) ((Less|Leq)64F y:(Const64F [c]) x)) => (Not ((Leq|Less)64F x y))
@@ -933,8 +944,10 @@
@x.Block (Load <v.Type> (OffPtr <v.Type.PtrTo()> [t.FieldOff(int(i))] ptr) mem)
// Putting struct{*byte} and similar into direct interfaces.
-(IMake _typ (StructMake val)) => (IMake _typ val)
-(StructSelect [0] (IData x)) => (IData x)
+(IMake _typ (StructMake ___)) => imakeOfStructMake(v)
+(StructSelect (IData x)) && v.Type.Size() > 0 => (IData x)
+(StructSelect (IData x)) && v.Type.Size() == 0 && v.Type.IsStruct() => (StructMake)
+(StructSelect (IData x)) && v.Type.Size() == 0 && v.Type.IsArray() => (ArrayMake0)
// un-SSAable values use mem->mem copies
(Store {t} dst (Load src mem) mem) && !CanSSA(t) =>
@@ -2222,4 +2235,4 @@
(Neq(64|32|16) (SignExt8to(64|32|16) (CvtBoolToUint8 x)) (Const(64|32|16) [0])) => x
(Neq(64|32|16) (SignExt8to(64|32|16) (CvtBoolToUint8 x)) (Const(64|32|16) [1])) => (Not x)
(Eq(64|32|16) (SignExt8to(64|32|16) (CvtBoolToUint8 x)) (Const(64|32|16) [1])) => x
-(Eq(64|32|16) (SignExt8to(64|32|16) (CvtBoolToUint8 x)) (Const(64|32|16) [0])) => (Not x) \ No newline at end of file
+(Eq(64|32|16) (SignExt8to(64|32|16) (CvtBoolToUint8 x)) (Const(64|32|16) [0])) => (Not x)
diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go
index c1726b2797..1a2985d5af 100644
--- a/src/cmd/compile/internal/ssa/expand_calls.go
+++ b/src/cmd/compile/internal/ssa/expand_calls.go
@@ -426,7 +426,14 @@ func (x *expandState) decomposeAsNecessary(pos src.XPos, b *Block, a, m0 *Value,
if a.Op == OpIMake {
data := a.Args[1]
for data.Op == OpStructMake || data.Op == OpArrayMake1 {
- data = data.Args[0]
+ // A struct make might have a few zero-sized fields.
+ // Use the pointer-y one we know is there.
+ for _, a := range data.Args {
+ if a.Type.Size() > 0 {
+ data = a
+ break
+ }
+ }
}
return x.decomposeAsNecessary(pos, b, data, mem, rc.next(data.Type))
}
diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go
index 0cee91b532..e95064c1df 100644
--- a/src/cmd/compile/internal/ssa/fuse.go
+++ b/src/cmd/compile/internal/ssa/fuse.go
@@ -10,7 +10,9 @@ import (
)
// fuseEarly runs fuse(f, fuseTypePlain|fuseTypeIntInRange|fuseTypeNanCheck).
-func fuseEarly(f *Func) { fuse(f, fuseTypePlain|fuseTypeIntInRange|fuseTypeNanCheck) }
+func fuseEarly(f *Func) {
+ fuse(f, fuseTypePlain|fuseTypeIntInRange|fuseTypeSingleBitDifference|fuseTypeNanCheck)
+}
// fuseLate runs fuse(f, fuseTypePlain|fuseTypeIf|fuseTypeBranchRedirect).
func fuseLate(f *Func) { fuse(f, fuseTypePlain|fuseTypeIf|fuseTypeBranchRedirect) }
@@ -21,6 +23,7 @@ const (
fuseTypePlain fuseType = 1 << iota
fuseTypeIf
fuseTypeIntInRange
+ fuseTypeSingleBitDifference
fuseTypeNanCheck
fuseTypeBranchRedirect
fuseTypeShortCircuit
@@ -41,6 +44,9 @@ func fuse(f *Func, typ fuseType) {
if typ&fuseTypeIntInRange != 0 {
changed = fuseIntInRange(b) || changed
}
+ if typ&fuseTypeSingleBitDifference != 0 {
+ changed = fuseSingleBitDifference(b) || changed
+ }
if typ&fuseTypeNanCheck != 0 {
changed = fuseNanCheck(b) || changed
}
diff --git a/src/cmd/compile/internal/ssa/fuse_comparisons.go b/src/cmd/compile/internal/ssa/fuse_comparisons.go
index b6eb8fcb90..898c034485 100644
--- a/src/cmd/compile/internal/ssa/fuse_comparisons.go
+++ b/src/cmd/compile/internal/ssa/fuse_comparisons.go
@@ -19,6 +19,14 @@ func fuseNanCheck(b *Block) bool {
return fuseComparisons(b, canOptNanCheck)
}
+// fuseSingleBitDifference replaces the short-circuit operators between equality checks with
+// constants that only differ by a single bit. For example, it would convert
+// `if x == 4 || x == 6 { ... }` into `if (x == 4) | (x == 6) { ... }`. Rewrite rules can
+// then optimize these using a bitwise operation, in this case generating `if x|2 == 6 { ... }`.
+func fuseSingleBitDifference(b *Block) bool {
+ return fuseComparisons(b, canOptSingleBitDifference)
+}
+
// fuseComparisons looks for control graphs that match this pattern:
//
// p - predecessor
@@ -229,3 +237,40 @@ func canOptNanCheck(x, y *Value, op Op) bool {
}
return false
}
+
+// canOptSingleBitDifference returns true if x op y matches either:
+//
+// v == c || v == d
+// v != c && v != d
+//
+// Where c and d are constant values that differ by a single bit.
+func canOptSingleBitDifference(x, y *Value, op Op) bool {
+ if x.Op != y.Op {
+ return false
+ }
+ switch x.Op {
+ case OpEq64, OpEq32, OpEq16, OpEq8:
+ if op != OpOrB {
+ return false
+ }
+ case OpNeq64, OpNeq32, OpNeq16, OpNeq8:
+ if op != OpAndB {
+ return false
+ }
+ default:
+ return false
+ }
+
+ xi := getConstIntArgIndex(x)
+ if xi < 0 {
+ return false
+ }
+ yi := getConstIntArgIndex(y)
+ if yi < 0 {
+ return false
+ }
+ if x.Args[xi^1] != y.Args[yi^1] {
+ return false
+ }
+ return oneBit(x.Args[xi].AuxInt ^ y.Args[yi].AuxInt)
+}
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 9c5d79fa56..ea5491362f 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -11481,7 +11481,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
- {1, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+ {1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
},
outputs: []outputInfo{
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
@@ -68770,6 +68770,7 @@ var opcodeTable = [...]opInfo{
inputs: []inputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
},
+ clobbers: 2305843009213693952, // F31
clobbersArg0: true,
},
},
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index 4919d6ad37..d4e7ed14b1 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -466,57 +466,56 @@ func (ft *factsTable) initLimitForNewValue(v *Value) {
// signedMin records the fact that we know v is at least
// min in the signed domain.
-func (ft *factsTable) signedMin(v *Value, min int64) bool {
- return ft.newLimit(v, limit{min: min, max: math.MaxInt64, umin: 0, umax: math.MaxUint64})
+func (ft *factsTable) signedMin(v *Value, min int64) {
+ ft.newLimit(v, limit{min: min, max: math.MaxInt64, umin: 0, umax: math.MaxUint64})
}
// signedMax records the fact that we know v is at most
// max in the signed domain.
-func (ft *factsTable) signedMax(v *Value, max int64) bool {
- return ft.newLimit(v, limit{min: math.MinInt64, max: max, umin: 0, umax: math.MaxUint64})
+func (ft *factsTable) signedMax(v *Value, max int64) {
+ ft.newLimit(v, limit{min: math.MinInt64, max: max, umin: 0, umax: math.MaxUint64})
}
-func (ft *factsTable) signedMinMax(v *Value, min, max int64) bool {
- return ft.newLimit(v, limit{min: min, max: max, umin: 0, umax: math.MaxUint64})
+func (ft *factsTable) signedMinMax(v *Value, min, max int64) {
+ ft.newLimit(v, limit{min: min, max: max, umin: 0, umax: math.MaxUint64})
}
// setNonNegative records the fact that v is known to be non-negative.
-func (ft *factsTable) setNonNegative(v *Value) bool {
- return ft.signedMin(v, 0)
+func (ft *factsTable) setNonNegative(v *Value) {
+ ft.signedMin(v, 0)
}
// unsignedMin records the fact that we know v is at least
// min in the unsigned domain.
-func (ft *factsTable) unsignedMin(v *Value, min uint64) bool {
- return ft.newLimit(v, limit{min: math.MinInt64, max: math.MaxInt64, umin: min, umax: math.MaxUint64})
+func (ft *factsTable) unsignedMin(v *Value, min uint64) {
+ ft.newLimit(v, limit{min: math.MinInt64, max: math.MaxInt64, umin: min, umax: math.MaxUint64})
}
// unsignedMax records the fact that we know v is at most
// max in the unsigned domain.
-func (ft *factsTable) unsignedMax(v *Value, max uint64) bool {
- return ft.newLimit(v, limit{min: math.MinInt64, max: math.MaxInt64, umin: 0, umax: max})
+func (ft *factsTable) unsignedMax(v *Value, max uint64) {
+ ft.newLimit(v, limit{min: math.MinInt64, max: math.MaxInt64, umin: 0, umax: max})
}
-func (ft *factsTable) unsignedMinMax(v *Value, min, max uint64) bool {
- return ft.newLimit(v, limit{min: math.MinInt64, max: math.MaxInt64, umin: min, umax: max})
+func (ft *factsTable) unsignedMinMax(v *Value, min, max uint64) {
+ ft.newLimit(v, limit{min: math.MinInt64, max: math.MaxInt64, umin: min, umax: max})
}
-func (ft *factsTable) booleanFalse(v *Value) bool {
- return ft.newLimit(v, limit{min: 0, max: 0, umin: 0, umax: 0})
+func (ft *factsTable) booleanFalse(v *Value) {
+ ft.newLimit(v, limit{min: 0, max: 0, umin: 0, umax: 0})
}
-func (ft *factsTable) booleanTrue(v *Value) bool {
- return ft.newLimit(v, limit{min: 1, max: 1, umin: 1, umax: 1})
+func (ft *factsTable) booleanTrue(v *Value) {
+ ft.newLimit(v, limit{min: 1, max: 1, umin: 1, umax: 1})
}
-func (ft *factsTable) pointerNil(v *Value) bool {
- return ft.newLimit(v, limit{min: 0, max: 0, umin: 0, umax: 0})
+func (ft *factsTable) pointerNil(v *Value) {
+ ft.newLimit(v, limit{min: 0, max: 0, umin: 0, umax: 0})
}
-func (ft *factsTable) pointerNonNil(v *Value) bool {
+func (ft *factsTable) pointerNonNil(v *Value) {
l := noLimit
l.umin = 1
- return ft.newLimit(v, l)
+ ft.newLimit(v, l)
}
// newLimit adds new limiting information for v.
-// Returns true if the new limit added any new information.
-func (ft *factsTable) newLimit(v *Value, newLim limit) bool {
+func (ft *factsTable) newLimit(v *Value, newLim limit) {
oldLim := ft.limits[v.ID]
// Merge old and new information.
@@ -531,13 +530,12 @@ func (ft *factsTable) newLimit(v *Value, newLim limit) bool {
}
if lim == oldLim {
- return false // nothing new to record
+ return // nothing new to record
}
if lim.unsat() {
- r := !ft.unsat
ft.unsat = true
- return r
+ return
}
// Check for recursion. This normally happens because in unsatisfiable
@@ -548,7 +546,7 @@ func (ft *factsTable) newLimit(v *Value, newLim limit) bool {
// the posets will not notice.
if ft.recurseCheck[v.ID] {
// This should only happen for unsatisfiable cases. TODO: check
- return false
+ return
}
ft.recurseCheck[v.ID] = true
defer func() {
@@ -713,8 +711,6 @@ func (ft *factsTable) newLimit(v *Value, newLim limit) bool {
}
}
}
-
- return true
}
func (ft *factsTable) addOrdering(v, w *Value, d domain, r relation) {
@@ -1825,7 +1821,7 @@ func initLimit(v *Value) limit {
return lim
}
-// flowLimit updates the known limits of v in ft. Returns true if anything changed.
+// flowLimit updates the known limits of v in ft.
// flowLimit can use the ranges of input arguments.
//
// Note: this calculation only happens at the point the value is defined. We do not reevaluate
@@ -1838,10 +1834,10 @@ func initLimit(v *Value) limit {
// block. We could recompute the range of v once we enter the block so
// we know that it is 0 <= v <= 8, but we don't have a mechanism to do
// that right now.
-func (ft *factsTable) flowLimit(v *Value) bool {
+func (ft *factsTable) flowLimit(v *Value) {
if !v.Type.IsInteger() {
// TODO: boolean?
- return false
+ return
}
// Additional limits based on opcode and argument.
@@ -1851,36 +1847,36 @@ func (ft *factsTable) flowLimit(v *Value) bool {
// extensions
case OpZeroExt8to64, OpZeroExt8to32, OpZeroExt8to16, OpZeroExt16to64, OpZeroExt16to32, OpZeroExt32to64:
a := ft.limits[v.Args[0].ID]
- return ft.unsignedMinMax(v, a.umin, a.umax)
+ ft.unsignedMinMax(v, a.umin, a.umax)
case OpSignExt8to64, OpSignExt8to32, OpSignExt8to16, OpSignExt16to64, OpSignExt16to32, OpSignExt32to64:
a := ft.limits[v.Args[0].ID]
- return ft.signedMinMax(v, a.min, a.max)
+ ft.signedMinMax(v, a.min, a.max)
case OpTrunc64to8, OpTrunc64to16, OpTrunc64to32, OpTrunc32to8, OpTrunc32to16, OpTrunc16to8:
a := ft.limits[v.Args[0].ID]
if a.umax <= 1<<(uint64(v.Type.Size())*8)-1 {
- return ft.unsignedMinMax(v, a.umin, a.umax)
+ ft.unsignedMinMax(v, a.umin, a.umax)
}
// math/bits
case OpCtz64:
a := ft.limits[v.Args[0].ID]
if a.nonzero() {
- return ft.unsignedMax(v, uint64(bits.Len64(a.umax)-1))
+ ft.unsignedMax(v, uint64(bits.Len64(a.umax)-1))
}
case OpCtz32:
a := ft.limits[v.Args[0].ID]
if a.nonzero() {
- return ft.unsignedMax(v, uint64(bits.Len32(uint32(a.umax))-1))
+ ft.unsignedMax(v, uint64(bits.Len32(uint32(a.umax))-1))
}
case OpCtz16:
a := ft.limits[v.Args[0].ID]
if a.nonzero() {
- return ft.unsignedMax(v, uint64(bits.Len16(uint16(a.umax))-1))
+ ft.unsignedMax(v, uint64(bits.Len16(uint16(a.umax))-1))
}
case OpCtz8:
a := ft.limits[v.Args[0].ID]
if a.nonzero() {
- return ft.unsignedMax(v, uint64(bits.Len8(uint8(a.umax))-1))
+ ft.unsignedMax(v, uint64(bits.Len8(uint8(a.umax))-1))
}
case OpPopCount64, OpPopCount32, OpPopCount16, OpPopCount8:
@@ -1889,26 +1885,26 @@ func (ft *factsTable) flowLimit(v *Value) bool {
sharedLeadingMask := ^(uint64(1)<<changingBitsCount - 1)
fixedBits := a.umax & sharedLeadingMask
min := uint64(bits.OnesCount64(fixedBits))
- return ft.unsignedMinMax(v, min, min+changingBitsCount)
+ ft.unsignedMinMax(v, min, min+changingBitsCount)
case OpBitLen64:
a := ft.limits[v.Args[0].ID]
- return ft.unsignedMinMax(v,
+ ft.unsignedMinMax(v,
uint64(bits.Len64(a.umin)),
uint64(bits.Len64(a.umax)))
case OpBitLen32:
a := ft.limits[v.Args[0].ID]
- return ft.unsignedMinMax(v,
+ ft.unsignedMinMax(v,
uint64(bits.Len32(uint32(a.umin))),
uint64(bits.Len32(uint32(a.umax))))
case OpBitLen16:
a := ft.limits[v.Args[0].ID]
- return ft.unsignedMinMax(v,
+ ft.unsignedMinMax(v,
uint64(bits.Len16(uint16(a.umin))),
uint64(bits.Len16(uint16(a.umax))))
case OpBitLen8:
a := ft.limits[v.Args[0].ID]
- return ft.unsignedMinMax(v,
+ ft.unsignedMinMax(v,
uint64(bits.Len8(uint8(a.umin))),
uint64(bits.Len8(uint8(a.umax))))
@@ -1921,43 +1917,43 @@ func (ft *factsTable) flowLimit(v *Value) bool {
// AND can only make the value smaller.
a := ft.limits[v.Args[0].ID]
b := ft.limits[v.Args[1].ID]
- return ft.unsignedMax(v, min(a.umax, b.umax))
+ ft.unsignedMax(v, min(a.umax, b.umax))
case OpOr64, OpOr32, OpOr16, OpOr8:
// OR can only make the value bigger and can't flip bits proved to be zero in both inputs.
a := ft.limits[v.Args[0].ID]
b := ft.limits[v.Args[1].ID]
- return ft.unsignedMinMax(v,
+ ft.unsignedMinMax(v,
max(a.umin, b.umin),
1<<bits.Len64(a.umax|b.umax)-1)
case OpXor64, OpXor32, OpXor16, OpXor8:
// XOR can't flip bits that are proved to be zero in both inputs.
a := ft.limits[v.Args[0].ID]
b := ft.limits[v.Args[1].ID]
- return ft.unsignedMax(v, 1<<bits.Len64(a.umax|b.umax)-1)
+ ft.unsignedMax(v, 1<<bits.Len64(a.umax|b.umax)-1)
case OpCom64, OpCom32, OpCom16, OpCom8:
a := ft.limits[v.Args[0].ID]
- return ft.newLimit(v, a.com(uint(v.Type.Size())*8))
+ ft.newLimit(v, a.com(uint(v.Type.Size())*8))
// Arithmetic.
case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
a := ft.limits[v.Args[0].ID]
b := ft.limits[v.Args[1].ID]
- return ft.newLimit(v, a.add(b, uint(v.Type.Size())*8))
+ ft.newLimit(v, a.add(b, uint(v.Type.Size())*8))
case OpSub64, OpSub32, OpSub16, OpSub8:
a := ft.limits[v.Args[0].ID]
b := ft.limits[v.Args[1].ID]
- sub := ft.newLimit(v, a.sub(b, uint(v.Type.Size())*8))
- mod := ft.detectMod(v)
- inferred := ft.detectSliceLenRelation(v)
- return sub || mod || inferred
+ ft.newLimit(v, a.sub(b, uint(v.Type.Size())*8))
+ ft.detectMod(v)
+ ft.detectSliceLenRelation(v)
+ ft.detectSubRelations(v)
case OpNeg64, OpNeg32, OpNeg16, OpNeg8:
a := ft.limits[v.Args[0].ID]
bitsize := uint(v.Type.Size()) * 8
- return ft.newLimit(v, a.com(bitsize).add(limit{min: 1, max: 1, umin: 1, umax: 1}, bitsize))
+ ft.newLimit(v, a.com(bitsize).add(limit{min: 1, max: 1, umin: 1, umax: 1}, bitsize))
case OpMul64, OpMul32, OpMul16, OpMul8:
a := ft.limits[v.Args[0].ID]
b := ft.limits[v.Args[1].ID]
- return ft.newLimit(v, a.mul(b, uint(v.Type.Size())*8))
+ ft.newLimit(v, a.mul(b, uint(v.Type.Size())*8))
case OpLsh64x64, OpLsh64x32, OpLsh64x16, OpLsh64x8,
OpLsh32x64, OpLsh32x32, OpLsh32x16, OpLsh32x8,
OpLsh16x64, OpLsh16x32, OpLsh16x16, OpLsh16x8,
@@ -1965,7 +1961,7 @@ func (ft *factsTable) flowLimit(v *Value) bool {
a := ft.limits[v.Args[0].ID]
b := ft.limits[v.Args[1].ID]
bitsize := uint(v.Type.Size()) * 8
- return ft.newLimit(v, a.mul(b.exp2(bitsize), bitsize))
+ ft.newLimit(v, a.mul(b.exp2(bitsize), bitsize))
case OpRsh64x64, OpRsh64x32, OpRsh64x16, OpRsh64x8,
OpRsh32x64, OpRsh32x32, OpRsh32x16, OpRsh32x8,
OpRsh16x64, OpRsh16x32, OpRsh16x16, OpRsh16x8,
@@ -1979,7 +1975,7 @@ func (ft *factsTable) flowLimit(v *Value) bool {
// Easier to compute min and max of both than to write sign logic.
vmin := min(a.min>>b.min, a.min>>b.max)
vmax := max(a.max>>b.min, a.max>>b.max)
- return ft.signedMinMax(v, vmin, vmax)
+ ft.signedMinMax(v, vmin, vmax)
}
case OpRsh64Ux64, OpRsh64Ux32, OpRsh64Ux16, OpRsh64Ux8,
OpRsh32Ux64, OpRsh32Ux32, OpRsh32Ux16, OpRsh32Ux8,
@@ -1988,7 +1984,7 @@ func (ft *factsTable) flowLimit(v *Value) bool {
a := ft.limits[v.Args[0].ID]
b := ft.limits[v.Args[1].ID]
if b.min >= 0 {
- return ft.unsignedMinMax(v, a.umin>>b.max, a.umax>>b.min)
+ ft.unsignedMinMax(v, a.umin>>b.max, a.umax>>b.min)
}
case OpDiv64, OpDiv32, OpDiv16, OpDiv8:
a := ft.limits[v.Args[0].ID]
@@ -2008,11 +2004,11 @@ func (ft *factsTable) flowLimit(v *Value) bool {
if b.umin > 0 {
lim = lim.unsignedMax(a.umax / b.umin)
}
- return ft.newLimit(v, lim)
+ ft.newLimit(v, lim)
case OpMod64, OpMod32, OpMod16, OpMod8:
- return ft.modLimit(true, v, v.Args[0], v.Args[1])
+ ft.modLimit(true, v, v.Args[0], v.Args[1])
case OpMod64u, OpMod32u, OpMod16u, OpMod8u:
- return ft.modLimit(false, v, v.Args[0], v.Args[1])
+ ft.modLimit(false, v, v.Args[0], v.Args[1])
case OpPhi:
// Compute the union of all the input phis.
@@ -2032,9 +2028,8 @@ func (ft *factsTable) flowLimit(v *Value) bool {
l.umin = min(l.umin, l2.umin)
l.umax = max(l.umax, l2.umax)
}
- return ft.newLimit(v, l)
+ ft.newLimit(v, l)
}
- return false
}
// detectSliceLenRelation matches the pattern where
@@ -2047,13 +2042,13 @@ func (ft *factsTable) flowLimit(v *Value) bool {
//
// Note that "index" is not useed for indexing in this pattern, but
// in the motivating example (chunked slice iteration) it is.
-func (ft *factsTable) detectSliceLenRelation(v *Value) (inferred bool) {
+func (ft *factsTable) detectSliceLenRelation(v *Value) {
if v.Op != OpSub64 {
- return false
+ return
}
if !(v.Args[0].Op == OpSliceLen || v.Args[0].Op == OpSliceCap) {
- return false
+ return
}
slice := v.Args[0].Args[0]
@@ -2093,13 +2088,54 @@ func (ft *factsTable) detectSliceLenRelation(v *Value) (inferred bool) {
if K < 0 { // We hate thinking about overflow
continue
}
- inferred = inferred || ft.signedMin(v, K)
+ ft.signedMin(v, K)
+ }
+}
+
+// v must be Sub{64,32,16,8}.
+func (ft *factsTable) detectSubRelations(v *Value) {
+ // v = x-y
+ x := v.Args[0]
+ y := v.Args[1]
+ if x == y {
+ ft.signedMinMax(v, 0, 0)
+ return
+ }
+ xLim := ft.limits[x.ID]
+ yLim := ft.limits[y.ID]
+
+ // Check if we might wrap around. If so, give up.
+ width := uint(v.Type.Size()) * 8
+ if _, ok := safeSub(xLim.min, yLim.max, width); !ok {
+ return // x-y might underflow
+ }
+ if _, ok := safeSub(xLim.max, yLim.min, width); !ok {
+ return // x-y might overflow
+ }
+
+ // Subtracting a positive number only makes
+ // things smaller.
+ if yLim.min >= 0 {
+ ft.update(v.Block, v, x, signed, lt|eq)
+ // TODO: is this worth it?
+ //if yLim.min > 0 {
+ // ft.update(v.Block, v, x, signed, lt)
+ //}
+ }
+
+ // Subtracting a number from a bigger one
+ // can't go below 0.
+ if ft.orderS.OrderedOrEqual(y, x) {
+ ft.setNonNegative(v)
+ // TODO: is this worth it?
+ //if ft.orderS.Ordered(y, x) {
+ // ft.signedMin(v, 1)
+ //}
}
- return inferred
}
// x%d has been rewritten to x - (x/d)*d.
-func (ft *factsTable) detectMod(v *Value) bool {
+func (ft *factsTable) detectMod(v *Value) {
var opDiv, opDivU, opMul, opConst Op
switch v.Op {
case OpSub64:
@@ -2126,36 +2162,37 @@ func (ft *factsTable) detectMod(v *Value) bool {
mul := v.Args[1]
if mul.Op != opMul {
- return false
+ return
}
div, con := mul.Args[0], mul.Args[1]
if div.Op == opConst {
div, con = con, div
}
if con.Op != opConst || (div.Op != opDiv && div.Op != opDivU) || div.Args[0] != v.Args[0] || div.Args[1].Op != opConst || div.Args[1].AuxInt != con.AuxInt {
- return false
+ return
}
- return ft.modLimit(div.Op == opDiv, v, v.Args[0], con)
+ ft.modLimit(div.Op == opDiv, v, v.Args[0], con)
}
// modLimit sets v with facts derived from v = p % q.
-func (ft *factsTable) modLimit(signed bool, v, p, q *Value) bool {
+func (ft *factsTable) modLimit(signed bool, v, p, q *Value) {
a := ft.limits[p.ID]
b := ft.limits[q.ID]
if signed {
if a.min < 0 && b.min > 0 {
- return ft.signedMinMax(v, -(b.max - 1), b.max-1)
+ ft.signedMinMax(v, -(b.max - 1), b.max-1)
+ return
}
if !(a.nonnegative() && b.nonnegative()) {
// TODO: we could handle signed limits but I didn't bother.
- return false
+ return
}
if a.min >= 0 && b.min > 0 {
ft.setNonNegative(v)
}
}
// Underflow in the arithmetic below is ok, it gives to MaxUint64 which does nothing to the limit.
- return ft.unsignedMax(v, min(a.umax, b.umax-1))
+ ft.unsignedMax(v, min(a.umax, b.umax-1))
}
// getBranch returns the range restrictions added by p
@@ -2466,15 +2503,13 @@ func addLocalFacts(ft *factsTable, b *Block) {
xl := ft.limits[x.ID]
y := add.Args[1]
yl := ft.limits[y.ID]
- if unsignedAddOverflows(xl.umax, yl.umax, add.Type) {
- continue
- }
-
- if xl.umax < uminDivisor {
- ft.update(b, v, y, unsigned, lt|eq)
- }
- if yl.umax < uminDivisor {
- ft.update(b, v, x, unsigned, lt|eq)
+ if !unsignedAddOverflows(xl.umax, yl.umax, add.Type) {
+ if xl.umax < uminDivisor {
+ ft.update(b, v, y, unsigned, lt|eq)
+ }
+ if yl.umax < uminDivisor {
+ ft.update(b, v, x, unsigned, lt|eq)
+ }
}
}
ft.update(b, v, v.Args[0], unsigned, lt|eq)
@@ -2993,16 +3028,14 @@ func (ft *factsTable) topoSortValuesInBlock(b *Block) {
want := f.NumValues()
scores := ft.reusedTopoSortScoresTable
- if len(scores) < want {
- if want <= cap(scores) {
- scores = scores[:want]
- } else {
- if cap(scores) > 0 {
- f.Cache.freeUintSlice(scores)
- }
- scores = f.Cache.allocUintSlice(want)
- ft.reusedTopoSortScoresTable = scores
+ if want <= cap(scores) {
+ scores = scores[:want]
+ } else {
+ if cap(scores) > 0 {
+ f.Cache.freeUintSlice(scores)
}
+ scores = f.Cache.allocUintSlice(want)
+ ft.reusedTopoSortScoresTable = scores
}
for _, v := range b.Values {
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
index 4d022555b7..11dd53bfc7 100644
--- a/src/cmd/compile/internal/ssa/regalloc.go
+++ b/src/cmd/compile/internal/ssa/regalloc.go
@@ -596,17 +596,18 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos
var c *Value
if vi.regs != 0 {
// Copy from a register that v is already in.
- r2 := pickReg(vi.regs)
var current *Value
- if !s.allocatable.contains(r2) {
- current = v // v is in a fixed register
+ if vi.regs&^s.allocatable != 0 {
+ // v is in a fixed register, prefer that
+ current = v
} else {
+ r2 := pickReg(vi.regs)
if s.regs[r2].v != v {
panic("bad register state")
}
current = s.regs[r2].c
+ s.usedSinceBlockStart |= regMask(1) << r2
}
- s.usedSinceBlockStart |= regMask(1) << r2
c = s.curBlock.NewValue1(pos, OpCopy, v.Type, current)
} else if v.rematerializeable() {
// Rematerialize instead of loading from the spill location.
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index 07308973b1..af2568ae89 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -2772,3 +2772,17 @@ func panicBoundsCCToAux(p PanicBoundsCC) Aux {
func isDictArgSym(sym Sym) bool {
return sym.(*ir.Name).Sym().Name == typecheck.LocalDictName
}
+
+// When v is (IMake typ (StructMake ...)), convert to
+// (IMake typ arg) where arg is the pointer-y argument to
+// the StructMake (there must be exactly one).
+func imakeOfStructMake(v *Value) *Value {
+ var arg *Value
+ for _, a := range v.Args[1].Args {
+ if a.Type.Size() > 0 {
+ arg = a
+ break
+ }
+ }
+ return v.Block.NewValue2(v.Pos, OpIMake, v.Type, v.Args[0], arg)
+}
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index 6af1558833..b3f790dbda 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -12556,6 +12556,54 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
}
break
}
+ // match: (MUL r:(MOVWUreg x) s:(MOVWUreg y))
+ // cond: r.Uses == 1 && s.Uses == 1
+ // result: (UMULL x y)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ r := v_0
+ if r.Op != OpARM64MOVWUreg {
+ continue
+ }
+ x := r.Args[0]
+ s := v_1
+ if s.Op != OpARM64MOVWUreg {
+ continue
+ }
+ y := s.Args[0]
+ if !(r.Uses == 1 && s.Uses == 1) {
+ continue
+ }
+ v.reset(OpARM64UMULL)
+ v.AddArg2(x, y)
+ return true
+ }
+ break
+ }
+ // match: (MUL r:(MOVWreg x) s:(MOVWreg y))
+ // cond: r.Uses == 1 && s.Uses == 1
+ // result: (MULL x y)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ r := v_0
+ if r.Op != OpARM64MOVWreg {
+ continue
+ }
+ x := r.Args[0]
+ s := v_1
+ if s.Op != OpARM64MOVWreg {
+ continue
+ }
+ y := s.Args[0]
+ if !(r.Uses == 1 && s.Uses == 1) {
+ continue
+ }
+ v.reset(OpARM64MULL)
+ v.AddArg2(x, y)
+ return true
+ }
+ break
+ }
return false
}
func rewriteValueARM64_OpARM64MULW(v *Value) bool {
@@ -25273,6 +25321,37 @@ func rewriteBlockARM64(b *Block) bool {
b.resetWithControl(BlockARM64FGE, cc)
return true
}
+ // match: (TBNZ [0] (XORconst [1] x) yes no)
+ // result: (TBZ [0] x yes no)
+ for b.Controls[0].Op == OpARM64XORconst {
+ v_0 := b.Controls[0]
+ if auxIntToInt64(v_0.AuxInt) != 1 {
+ break
+ }
+ x := v_0.Args[0]
+ if auxIntToInt64(b.AuxInt) != 0 {
+ break
+ }
+ b.resetWithControl(BlockARM64TBZ, x)
+ b.AuxInt = int64ToAuxInt(0)
+ return true
+ }
+ case BlockARM64TBZ:
+ // match: (TBZ [0] (XORconst [1] x) yes no)
+ // result: (TBNZ [0] x yes no)
+ for b.Controls[0].Op == OpARM64XORconst {
+ v_0 := b.Controls[0]
+ if auxIntToInt64(v_0.AuxInt) != 1 {
+ break
+ }
+ x := v_0.Args[0]
+ if auxIntToInt64(b.AuxInt) != 0 {
+ break
+ }
+ b.resetWithControl(BlockARM64TBNZ, x)
+ b.AuxInt = int64ToAuxInt(0)
+ return true
+ }
case BlockARM64UGE:
// match: (UGE (FlagConstant [fc]) yes no)
// cond: fc.uge()
diff --git a/src/cmd/compile/internal/ssa/rewriteLOONG64.go b/src/cmd/compile/internal/ssa/rewriteLOONG64.go
index 4262d4e0fb..bf2dd114a9 100644
--- a/src/cmd/compile/internal/ssa/rewriteLOONG64.go
+++ b/src/cmd/compile/internal/ssa/rewriteLOONG64.go
@@ -5866,7 +5866,6 @@ func rewriteValueLOONG64_OpLOONG64MULV(v *Value) bool {
v_0 := v.Args[0]
b := v.Block
config := b.Func.Config
- typ := &b.Func.Config.Types
// match: (MULV _ (MOVVconst [0]))
// result: (MOVVconst [0])
for {
@@ -5911,44 +5910,6 @@ func rewriteValueLOONG64_OpLOONG64MULV(v *Value) bool {
}
break
}
- // match: (MULV (NEGV x) (MOVVconst [c]))
- // result: (MULV x (MOVVconst [-c]))
- for {
- for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
- if v_0.Op != OpLOONG64NEGV {
- continue
- }
- x := v_0.Args[0]
- if v_1.Op != OpLOONG64MOVVconst {
- continue
- }
- c := auxIntToInt64(v_1.AuxInt)
- v.reset(OpLOONG64MULV)
- v0 := b.NewValue0(v.Pos, OpLOONG64MOVVconst, typ.UInt64)
- v0.AuxInt = int64ToAuxInt(-c)
- v.AddArg2(x, v0)
- return true
- }
- break
- }
- // match: (MULV (NEGV x) (NEGV y))
- // result: (MULV x y)
- for {
- for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
- if v_0.Op != OpLOONG64NEGV {
- continue
- }
- x := v_0.Args[0]
- if v_1.Op != OpLOONG64NEGV {
- continue
- }
- y := v_1.Args[0]
- v.reset(OpLOONG64MULV)
- v.AddArg2(x, y)
- return true
- }
- break
- }
// match: (MULV (MOVVconst [c]) (MOVVconst [d]))
// result: (MOVVconst [c*d])
for {
diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
index 191c7b3d48..284d88967b 100644
--- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go
+++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
@@ -7027,7 +7027,7 @@ func rewriteValueRISCV64_OpRISCV64ROL(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (ROL x (MOVDconst [val]))
- // result: (RORI [int64(int8(-val)&63)] x)
+ // result: (RORI [-val&63] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7035,7 +7035,7 @@ func rewriteValueRISCV64_OpRISCV64ROL(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64RORI)
- v.AuxInt = int64ToAuxInt(int64(int8(-val) & 63))
+ v.AuxInt = int64ToAuxInt(-val & 63)
v.AddArg(x)
return true
}
@@ -7057,7 +7057,7 @@ func rewriteValueRISCV64_OpRISCV64ROLW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (ROLW x (MOVDconst [val]))
- // result: (RORIW [int64(int8(-val)&31)] x)
+ // result: (RORIW [-val&31] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7065,7 +7065,7 @@ func rewriteValueRISCV64_OpRISCV64ROLW(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64RORIW)
- v.AuxInt = int64ToAuxInt(int64(int8(-val) & 31))
+ v.AuxInt = int64ToAuxInt(-val & 31)
v.AddArg(x)
return true
}
@@ -7087,7 +7087,7 @@ func rewriteValueRISCV64_OpRISCV64ROR(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (ROR x (MOVDconst [val]))
- // result: (RORI [int64(val&63)] x)
+ // result: (RORI [val&63] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7095,7 +7095,7 @@ func rewriteValueRISCV64_OpRISCV64ROR(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64RORI)
- v.AuxInt = int64ToAuxInt(int64(val & 63))
+ v.AuxInt = int64ToAuxInt(val & 63)
v.AddArg(x)
return true
}
@@ -7105,7 +7105,7 @@ func rewriteValueRISCV64_OpRISCV64RORW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (RORW x (MOVDconst [val]))
- // result: (RORIW [int64(val&31)] x)
+ // result: (RORIW [val&31] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7113,7 +7113,7 @@ func rewriteValueRISCV64_OpRISCV64RORW(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64RORIW)
- v.AuxInt = int64ToAuxInt(int64(val & 31))
+ v.AuxInt = int64ToAuxInt(val & 31)
v.AddArg(x)
return true
}
@@ -7212,7 +7212,7 @@ func rewriteValueRISCV64_OpRISCV64SLL(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLL x (MOVDconst [val]))
- // result: (SLLI [int64(val&63)] x)
+ // result: (SLLI [val&63] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7220,7 +7220,7 @@ func rewriteValueRISCV64_OpRISCV64SLL(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64SLLI)
- v.AuxInt = int64ToAuxInt(int64(val & 63))
+ v.AuxInt = int64ToAuxInt(val & 63)
v.AddArg(x)
return true
}
@@ -7246,7 +7246,7 @@ func rewriteValueRISCV64_OpRISCV64SLLI(v *Value) bool {
}
// match: (SLLI <t> [c] (ADD x x))
// cond: c < t.Size() * 8 - 1
- // result: (SLLI <t> [c+1] x)
+ // result: (SLLI [c+1] x)
for {
t := v.Type
c := auxIntToInt64(v.AuxInt)
@@ -7258,7 +7258,6 @@ func rewriteValueRISCV64_OpRISCV64SLLI(v *Value) bool {
break
}
v.reset(OpRISCV64SLLI)
- v.Type = t
v.AuxInt = int64ToAuxInt(c + 1)
v.AddArg(x)
return true
@@ -7286,7 +7285,7 @@ func rewriteValueRISCV64_OpRISCV64SLLW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLLW x (MOVDconst [val]))
- // result: (SLLIW [int64(val&31)] x)
+ // result: (SLLIW [val&31] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7294,7 +7293,7 @@ func rewriteValueRISCV64_OpRISCV64SLLW(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64SLLIW)
- v.AuxInt = int64ToAuxInt(int64(val & 31))
+ v.AuxInt = int64ToAuxInt(val & 31)
v.AddArg(x)
return true
}
@@ -7304,7 +7303,7 @@ func rewriteValueRISCV64_OpRISCV64SLT(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLT x (MOVDconst [val]))
- // cond: val >= -2048 && val <= 2047
+ // cond: is12Bit(val)
// result: (SLTI [val] x)
for {
x := v_0
@@ -7312,7 +7311,7 @@ func rewriteValueRISCV64_OpRISCV64SLT(v *Value) bool {
break
}
val := auxIntToInt64(v_1.AuxInt)
- if !(val >= -2048 && val <= 2047) {
+ if !(is12Bit(val)) {
break
}
v.reset(OpRISCV64SLTI)
@@ -7363,22 +7362,6 @@ func rewriteValueRISCV64_OpRISCV64SLTI(v *Value) bool {
v.AuxInt = int64ToAuxInt(1)
return true
}
- // match: (SLTI [x] (ORI [y] _))
- // cond: y >= 0 && int64(y) >= int64(x)
- // result: (MOVDconst [0])
- for {
- x := auxIntToInt64(v.AuxInt)
- if v_0.Op != OpRISCV64ORI {
- break
- }
- y := auxIntToInt64(v_0.AuxInt)
- if !(y >= 0 && int64(y) >= int64(x)) {
- break
- }
- v.reset(OpRISCV64MOVDconst)
- v.AuxInt = int64ToAuxInt(0)
- return true
- }
return false
}
func rewriteValueRISCV64_OpRISCV64SLTIU(v *Value) bool {
@@ -7433,7 +7416,7 @@ func rewriteValueRISCV64_OpRISCV64SLTU(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLTU x (MOVDconst [val]))
- // cond: val >= -2048 && val <= 2047
+ // cond: is12Bit(val)
// result: (SLTIU [val] x)
for {
x := v_0
@@ -7441,7 +7424,7 @@ func rewriteValueRISCV64_OpRISCV64SLTU(v *Value) bool {
break
}
val := auxIntToInt64(v_1.AuxInt)
- if !(val >= -2048 && val <= 2047) {
+ if !(is12Bit(val)) {
break
}
v.reset(OpRISCV64SLTIU)
@@ -7555,7 +7538,7 @@ func rewriteValueRISCV64_OpRISCV64SRA(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRA x (MOVDconst [val]))
- // result: (SRAI [int64(val&63)] x)
+ // result: (SRAI [val&63] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7563,7 +7546,7 @@ func rewriteValueRISCV64_OpRISCV64SRA(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64SRAI)
- v.AuxInt = int64ToAuxInt(int64(val & 63))
+ v.AuxInt = int64ToAuxInt(val & 63)
v.AddArg(x)
return true
}
@@ -7572,11 +7555,10 @@ func rewriteValueRISCV64_OpRISCV64SRA(v *Value) bool {
func rewriteValueRISCV64_OpRISCV64SRAI(v *Value) bool {
v_0 := v.Args[0]
b := v.Block
- // match: (SRAI <t> [x] (MOVWreg y))
+ // match: (SRAI [x] (MOVWreg y))
// cond: x >= 0 && x <= 31
- // result: (SRAIW <t> [int64(x)] y)
+ // result: (SRAIW [x] y)
for {
- t := v.Type
x := auxIntToInt64(v.AuxInt)
if v_0.Op != OpRISCV64MOVWreg {
break
@@ -7586,8 +7568,7 @@ func rewriteValueRISCV64_OpRISCV64SRAI(v *Value) bool {
break
}
v.reset(OpRISCV64SRAIW)
- v.Type = t
- v.AuxInt = int64ToAuxInt(int64(x))
+ v.AuxInt = int64ToAuxInt(x)
v.AddArg(y)
return true
}
@@ -7633,7 +7614,7 @@ func rewriteValueRISCV64_OpRISCV64SRAI(v *Value) bool {
v.AddArg(v0)
return true
}
- // match: (SRAI <t> [x] (MOVWreg y))
+ // match: (SRAI [x] (MOVWreg y))
// cond: x >= 32
// result: (SRAIW [31] y)
for {
@@ -7668,7 +7649,7 @@ func rewriteValueRISCV64_OpRISCV64SRAW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRAW x (MOVDconst [val]))
- // result: (SRAIW [int64(val&31)] x)
+ // result: (SRAIW [val&31] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7676,7 +7657,7 @@ func rewriteValueRISCV64_OpRISCV64SRAW(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64SRAIW)
- v.AuxInt = int64ToAuxInt(int64(val & 31))
+ v.AuxInt = int64ToAuxInt(val & 31)
v.AddArg(x)
return true
}
@@ -7686,7 +7667,7 @@ func rewriteValueRISCV64_OpRISCV64SRL(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRL x (MOVDconst [val]))
- // result: (SRLI [int64(val&63)] x)
+ // result: (SRLI [val&63] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7694,7 +7675,7 @@ func rewriteValueRISCV64_OpRISCV64SRL(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64SRLI)
- v.AuxInt = int64ToAuxInt(int64(val & 63))
+ v.AuxInt = int64ToAuxInt(val & 63)
v.AddArg(x)
return true
}
@@ -7702,11 +7683,10 @@ func rewriteValueRISCV64_OpRISCV64SRL(v *Value) bool {
}
func rewriteValueRISCV64_OpRISCV64SRLI(v *Value) bool {
v_0 := v.Args[0]
- // match: (SRLI <t> [x] (MOVWUreg y))
+ // match: (SRLI [x] (MOVWUreg y))
// cond: x >= 0 && x <= 31
- // result: (SRLIW <t> [int64(x)] y)
+ // result: (SRLIW [x] y)
for {
- t := v.Type
x := auxIntToInt64(v.AuxInt)
if v_0.Op != OpRISCV64MOVWUreg {
break
@@ -7716,16 +7696,14 @@ func rewriteValueRISCV64_OpRISCV64SRLI(v *Value) bool {
break
}
v.reset(OpRISCV64SRLIW)
- v.Type = t
- v.AuxInt = int64ToAuxInt(int64(x))
+ v.AuxInt = int64ToAuxInt(x)
v.AddArg(y)
return true
}
- // match: (SRLI <t> [x] (MOVBUreg y))
+ // match: (SRLI [x] (MOVBUreg y))
// cond: x >= 8
- // result: (MOVDconst <t> [0])
+ // result: (MOVDconst [0])
for {
- t := v.Type
x := auxIntToInt64(v.AuxInt)
if v_0.Op != OpRISCV64MOVBUreg {
break
@@ -7734,15 +7712,13 @@ func rewriteValueRISCV64_OpRISCV64SRLI(v *Value) bool {
break
}
v.reset(OpRISCV64MOVDconst)
- v.Type = t
v.AuxInt = int64ToAuxInt(0)
return true
}
- // match: (SRLI <t> [x] (MOVHUreg y))
+ // match: (SRLI [x] (MOVHUreg y))
// cond: x >= 16
- // result: (MOVDconst <t> [0])
+ // result: (MOVDconst [0])
for {
- t := v.Type
x := auxIntToInt64(v.AuxInt)
if v_0.Op != OpRISCV64MOVHUreg {
break
@@ -7751,15 +7727,13 @@ func rewriteValueRISCV64_OpRISCV64SRLI(v *Value) bool {
break
}
v.reset(OpRISCV64MOVDconst)
- v.Type = t
v.AuxInt = int64ToAuxInt(0)
return true
}
- // match: (SRLI <t> [x] (MOVWUreg y))
+ // match: (SRLI [x] (MOVWUreg y))
// cond: x >= 32
- // result: (MOVDconst <t> [0])
+ // result: (MOVDconst [0])
for {
- t := v.Type
x := auxIntToInt64(v.AuxInt)
if v_0.Op != OpRISCV64MOVWUreg {
break
@@ -7768,7 +7742,6 @@ func rewriteValueRISCV64_OpRISCV64SRLI(v *Value) bool {
break
}
v.reset(OpRISCV64MOVDconst)
- v.Type = t
v.AuxInt = int64ToAuxInt(0)
return true
}
@@ -7790,7 +7763,7 @@ func rewriteValueRISCV64_OpRISCV64SRLW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRLW x (MOVDconst [val]))
- // result: (SRLIW [int64(val&31)] x)
+ // result: (SRLIW [val&31] x)
for {
x := v_0
if v_1.Op != OpRISCV64MOVDconst {
@@ -7798,7 +7771,7 @@ func rewriteValueRISCV64_OpRISCV64SRLW(v *Value) bool {
}
val := auxIntToInt64(v_1.AuxInt)
v.reset(OpRISCV64SRLIW)
- v.AuxInt = int64ToAuxInt(int64(val & 31))
+ v.AuxInt = int64ToAuxInt(val & 31)
v.AddArg(x)
return true
}
diff --git a/src/cmd/compile/internal/ssa/rewritedec.go b/src/cmd/compile/internal/ssa/rewritedec.go
index 16d0269210..c45034ead0 100644
--- a/src/cmd/compile/internal/ssa/rewritedec.go
+++ b/src/cmd/compile/internal/ssa/rewritedec.go
@@ -279,11 +279,20 @@ func rewriteValuedec_OpIData(v *Value) bool {
func rewriteValuedec_OpIMake(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- // match: (IMake _typ (StructMake val))
+ // match: (IMake _typ (StructMake ___))
+ // result: imakeOfStructMake(v)
+ for {
+ if v_1.Op != OpStructMake {
+ break
+ }
+ v.copyOf(imakeOfStructMake(v))
+ return true
+ }
+ // match: (IMake _typ (ArrayMake1 val))
// result: (IMake _typ val)
for {
_typ := v_0
- if v_1.Op != OpStructMake || len(v_1.Args) != 1 {
+ if v_1.Op != OpArrayMake1 {
break
}
val := v_1.Args[0]
@@ -839,17 +848,47 @@ func rewriteValuedec_OpStructMake(v *Value) bool {
func rewriteValuedec_OpStructSelect(v *Value) bool {
v_0 := v.Args[0]
b := v.Block
- // match: (StructSelect [0] (IData x))
+ // match: (StructSelect (IData x))
+ // cond: v.Type.Size() > 0
// result: (IData x)
for {
- if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpIData {
+ if v_0.Op != OpIData {
break
}
x := v_0.Args[0]
+ if !(v.Type.Size() > 0) {
+ break
+ }
v.reset(OpIData)
v.AddArg(x)
return true
}
+ // match: (StructSelect (IData x))
+ // cond: v.Type.Size() == 0 && v.Type.IsStruct()
+ // result: (StructMake)
+ for {
+ if v_0.Op != OpIData {
+ break
+ }
+ if !(v.Type.Size() == 0 && v.Type.IsStruct()) {
+ break
+ }
+ v.reset(OpStructMake)
+ return true
+ }
+ // match: (StructSelect (IData x))
+ // cond: v.Type.Size() == 0 && v.Type.IsArray()
+ // result: (ArrayMake0)
+ for {
+ if v_0.Op != OpIData {
+ break
+ }
+ if !(v.Type.Size() == 0 && v.Type.IsArray()) {
+ break
+ }
+ v.reset(OpArrayMake0)
+ return true
+ }
// match: (StructSelect [i] x:(StructMake ___))
// result: x.Args[i]
for {
@@ -861,13 +900,10 @@ func rewriteValuedec_OpStructSelect(v *Value) bool {
v.copyOf(x.Args[i])
return true
}
- // match: (StructSelect [0] x)
+ // match: (StructSelect x)
// cond: x.Type.IsPtrShaped()
// result: x
for {
- if auxIntToInt64(v.AuxInt) != 0 {
- break
- }
x := v_0
if !(x.Type.IsPtrShaped()) {
break
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 5b5494f43a..5c183fc2a6 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -5332,6 +5332,182 @@ func rewriteValuegeneric_OpAndB(v *Value) bool {
}
break
}
+ // match: (AndB (Neq64 x cv:(Const64 [c])) (Neq64 x (Const64 [d])))
+ // cond: c|d == c && oneBit(c^d)
+ // result: (Neq64 (Or64 <x.Type> x (Const64 <x.Type> [c^d])) cv)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpNeq64 {
+ continue
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 {
+ x := v_0_0
+ cv := v_0_1
+ if cv.Op != OpConst64 {
+ continue
+ }
+ c := auxIntToInt64(cv.AuxInt)
+ if v_1.Op != OpNeq64 {
+ continue
+ }
+ _ = v_1.Args[1]
+ v_1_0 := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ for _i2 := 0; _i2 <= 1; _i2, v_1_0, v_1_1 = _i2+1, v_1_1, v_1_0 {
+ if x != v_1_0 || v_1_1.Op != OpConst64 {
+ continue
+ }
+ d := auxIntToInt64(v_1_1.AuxInt)
+ if !(c|d == c && oneBit(c^d)) {
+ continue
+ }
+ v.reset(OpNeq64)
+ v0 := b.NewValue0(v.Pos, OpOr64, x.Type)
+ v1 := b.NewValue0(v.Pos, OpConst64, x.Type)
+ v1.AuxInt = int64ToAuxInt(c ^ d)
+ v0.AddArg2(x, v1)
+ v.AddArg2(v0, cv)
+ return true
+ }
+ }
+ }
+ break
+ }
+ // match: (AndB (Neq32 x cv:(Const32 [c])) (Neq32 x (Const32 [d])))
+ // cond: c|d == c && oneBit(c^d)
+ // result: (Neq32 (Or32 <x.Type> x (Const32 <x.Type> [c^d])) cv)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpNeq32 {
+ continue
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 {
+ x := v_0_0
+ cv := v_0_1
+ if cv.Op != OpConst32 {
+ continue
+ }
+ c := auxIntToInt32(cv.AuxInt)
+ if v_1.Op != OpNeq32 {
+ continue
+ }
+ _ = v_1.Args[1]
+ v_1_0 := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ for _i2 := 0; _i2 <= 1; _i2, v_1_0, v_1_1 = _i2+1, v_1_1, v_1_0 {
+ if x != v_1_0 || v_1_1.Op != OpConst32 {
+ continue
+ }
+ d := auxIntToInt32(v_1_1.AuxInt)
+ if !(c|d == c && oneBit(c^d)) {
+ continue
+ }
+ v.reset(OpNeq32)
+ v0 := b.NewValue0(v.Pos, OpOr32, x.Type)
+ v1 := b.NewValue0(v.Pos, OpConst32, x.Type)
+ v1.AuxInt = int32ToAuxInt(c ^ d)
+ v0.AddArg2(x, v1)
+ v.AddArg2(v0, cv)
+ return true
+ }
+ }
+ }
+ break
+ }
+ // match: (AndB (Neq16 x cv:(Const16 [c])) (Neq16 x (Const16 [d])))
+ // cond: c|d == c && oneBit(c^d)
+ // result: (Neq16 (Or16 <x.Type> x (Const16 <x.Type> [c^d])) cv)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpNeq16 {
+ continue
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 {
+ x := v_0_0
+ cv := v_0_1
+ if cv.Op != OpConst16 {
+ continue
+ }
+ c := auxIntToInt16(cv.AuxInt)
+ if v_1.Op != OpNeq16 {
+ continue
+ }
+ _ = v_1.Args[1]
+ v_1_0 := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ for _i2 := 0; _i2 <= 1; _i2, v_1_0, v_1_1 = _i2+1, v_1_1, v_1_0 {
+ if x != v_1_0 || v_1_1.Op != OpConst16 {
+ continue
+ }
+ d := auxIntToInt16(v_1_1.AuxInt)
+ if !(c|d == c && oneBit(c^d)) {
+ continue
+ }
+ v.reset(OpNeq16)
+ v0 := b.NewValue0(v.Pos, OpOr16, x.Type)
+ v1 := b.NewValue0(v.Pos, OpConst16, x.Type)
+ v1.AuxInt = int16ToAuxInt(c ^ d)
+ v0.AddArg2(x, v1)
+ v.AddArg2(v0, cv)
+ return true
+ }
+ }
+ }
+ break
+ }
+ // match: (AndB (Neq8 x cv:(Const8 [c])) (Neq8 x (Const8 [d])))
+ // cond: c|d == c && oneBit(c^d)
+ // result: (Neq8 (Or8 <x.Type> x (Const8 <x.Type> [c^d])) cv)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpNeq8 {
+ continue
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 {
+ x := v_0_0
+ cv := v_0_1
+ if cv.Op != OpConst8 {
+ continue
+ }
+ c := auxIntToInt8(cv.AuxInt)
+ if v_1.Op != OpNeq8 {
+ continue
+ }
+ _ = v_1.Args[1]
+ v_1_0 := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ for _i2 := 0; _i2 <= 1; _i2, v_1_0, v_1_1 = _i2+1, v_1_1, v_1_0 {
+ if x != v_1_0 || v_1_1.Op != OpConst8 {
+ continue
+ }
+ d := auxIntToInt8(v_1_1.AuxInt)
+ if !(c|d == c && oneBit(c^d)) {
+ continue
+ }
+ v.reset(OpNeq8)
+ v0 := b.NewValue0(v.Pos, OpOr8, x.Type)
+ v1 := b.NewValue0(v.Pos, OpConst8, x.Type)
+ v1.AuxInt = int8ToAuxInt(c ^ d)
+ v0.AddArg2(x, v1)
+ v.AddArg2(v0, cv)
+ return true
+ }
+ }
+ }
+ break
+ }
return false
}
func rewriteValuegeneric_OpArraySelect(v *Value) bool {
@@ -8809,16 +8985,13 @@ func rewriteValuegeneric_OpFloor(v *Value) bool {
func rewriteValuegeneric_OpIMake(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- // match: (IMake _typ (StructMake val))
- // result: (IMake _typ val)
+ // match: (IMake _typ (StructMake ___))
+ // result: imakeOfStructMake(v)
for {
- _typ := v_0
- if v_1.Op != OpStructMake || len(v_1.Args) != 1 {
+ if v_1.Op != OpStructMake {
break
}
- val := v_1.Args[0]
- v.reset(OpIMake)
- v.AddArg2(_typ, val)
+ v.copyOf(imakeOfStructMake(v))
return true
}
// match: (IMake _typ (ArrayMake1 val))
@@ -16610,6 +16783,45 @@ func rewriteValuegeneric_OpMul16(v *Value) bool {
}
break
}
+ // match: (Mul16 (Const16 <t> [c]) (Neg16 x))
+ // result: (Mul16 x (Const16 <t> [-c]))
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpConst16 {
+ continue
+ }
+ t := v_0.Type
+ c := auxIntToInt16(v_0.AuxInt)
+ if v_1.Op != OpNeg16 {
+ continue
+ }
+ x := v_1.Args[0]
+ v.reset(OpMul16)
+ v0 := b.NewValue0(v.Pos, OpConst16, t)
+ v0.AuxInt = int16ToAuxInt(-c)
+ v.AddArg2(x, v0)
+ return true
+ }
+ break
+ }
+ // match: (Mul16 (Neg16 x) (Neg16 y))
+ // result: (Mul16 x y)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpNeg16 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpNeg16 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpMul16)
+ v.AddArg2(x, y)
+ return true
+ }
+ break
+ }
// match: (Mul16 (Const16 <t> [c]) (Add16 <t> (Const16 <t> [d]) x))
// cond: !isPowerOfTwo(c)
// result: (Add16 (Const16 <t> [c*d]) (Mul16 <t> (Const16 <t> [c]) x))
@@ -16821,6 +17033,45 @@ func rewriteValuegeneric_OpMul32(v *Value) bool {
}
break
}
+ // match: (Mul32 (Const32 <t> [c]) (Neg32 x))
+ // result: (Mul32 x (Const32 <t> [-c]))
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpConst32 {
+ continue
+ }
+ t := v_0.Type
+ c := auxIntToInt32(v_0.AuxInt)
+ if v_1.Op != OpNeg32 {
+ continue
+ }
+ x := v_1.Args[0]
+ v.reset(OpMul32)
+ v0 := b.NewValue0(v.Pos, OpConst32, t)
+ v0.AuxInt = int32ToAuxInt(-c)
+ v.AddArg2(x, v0)
+ return true
+ }
+ break
+ }
+ // match: (Mul32 (Neg32 x) (Neg32 y))
+ // result: (Mul32 x y)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpNeg32 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpNeg32 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpMul32)
+ v.AddArg2(x, y)
+ return true
+ }
+ break
+ }
// match: (Mul32 (Const32 <t> [c]) (Add32 <t> (Const32 <t> [d]) x))
// cond: !isPowerOfTwo(c)
// result: (Add32 (Const32 <t> [c*d]) (Mul32 <t> (Const32 <t> [c]) x))
@@ -17193,6 +17444,45 @@ func rewriteValuegeneric_OpMul64(v *Value) bool {
}
break
}
+ // match: (Mul64 (Const64 <t> [c]) (Neg64 x))
+ // result: (Mul64 x (Const64 <t> [-c]))
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpConst64 {
+ continue
+ }
+ t := v_0.Type
+ c := auxIntToInt64(v_0.AuxInt)
+ if v_1.Op != OpNeg64 {
+ continue
+ }
+ x := v_1.Args[0]
+ v.reset(OpMul64)
+ v0 := b.NewValue0(v.Pos, OpConst64, t)
+ v0.AuxInt = int64ToAuxInt(-c)
+ v.AddArg2(x, v0)
+ return true
+ }
+ break
+ }
+ // match: (Mul64 (Neg64 x) (Neg64 y))
+ // result: (Mul64 x y)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpNeg64 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpNeg64 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpMul64)
+ v.AddArg2(x, y)
+ return true
+ }
+ break
+ }
// match: (Mul64 (Const64 <t> [c]) (Add64 <t> (Const64 <t> [d]) x))
// cond: !isPowerOfTwo(c)
// result: (Add64 (Const64 <t> [c*d]) (Mul64 <t> (Const64 <t> [c]) x))
@@ -17565,6 +17855,45 @@ func rewriteValuegeneric_OpMul8(v *Value) bool {
}
break
}
+ // match: (Mul8 (Const8 <t> [c]) (Neg8 x))
+ // result: (Mul8 x (Const8 <t> [-c]))
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpConst8 {
+ continue
+ }
+ t := v_0.Type
+ c := auxIntToInt8(v_0.AuxInt)
+ if v_1.Op != OpNeg8 {
+ continue
+ }
+ x := v_1.Args[0]
+ v.reset(OpMul8)
+ v0 := b.NewValue0(v.Pos, OpConst8, t)
+ v0.AuxInt = int8ToAuxInt(-c)
+ v.AddArg2(x, v0)
+ return true
+ }
+ break
+ }
+ // match: (Mul8 (Neg8 x) (Neg8 y))
+ // result: (Mul8 x y)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpNeg8 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpNeg8 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpMul8)
+ v.AddArg2(x, y)
+ return true
+ }
+ break
+ }
// match: (Mul8 (Const8 <t> [c]) (Add8 <t> (Const8 <t> [d]) x))
// cond: !isPowerOfTwo(c)
// result: (Add8 (Const8 <t> [c*d]) (Mul8 <t> (Const8 <t> [c]) x))
@@ -23242,6 +23571,182 @@ func rewriteValuegeneric_OpOrB(v *Value) bool {
}
break
}
+ // match: (OrB (Eq64 x cv:(Const64 [c])) (Eq64 x (Const64 [d])))
+ // cond: c|d == c && oneBit(c^d)
+ // result: (Eq64 (Or64 <x.Type> x (Const64 <x.Type> [c^d])) cv)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpEq64 {
+ continue
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 {
+ x := v_0_0
+ cv := v_0_1
+ if cv.Op != OpConst64 {
+ continue
+ }
+ c := auxIntToInt64(cv.AuxInt)
+ if v_1.Op != OpEq64 {
+ continue
+ }
+ _ = v_1.Args[1]
+ v_1_0 := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ for _i2 := 0; _i2 <= 1; _i2, v_1_0, v_1_1 = _i2+1, v_1_1, v_1_0 {
+ if x != v_1_0 || v_1_1.Op != OpConst64 {
+ continue
+ }
+ d := auxIntToInt64(v_1_1.AuxInt)
+ if !(c|d == c && oneBit(c^d)) {
+ continue
+ }
+ v.reset(OpEq64)
+ v0 := b.NewValue0(v.Pos, OpOr64, x.Type)
+ v1 := b.NewValue0(v.Pos, OpConst64, x.Type)
+ v1.AuxInt = int64ToAuxInt(c ^ d)
+ v0.AddArg2(x, v1)
+ v.AddArg2(v0, cv)
+ return true
+ }
+ }
+ }
+ break
+ }
+ // match: (OrB (Eq32 x cv:(Const32 [c])) (Eq32 x (Const32 [d])))
+ // cond: c|d == c && oneBit(c^d)
+ // result: (Eq32 (Or32 <x.Type> x (Const32 <x.Type> [c^d])) cv)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpEq32 {
+ continue
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 {
+ x := v_0_0
+ cv := v_0_1
+ if cv.Op != OpConst32 {
+ continue
+ }
+ c := auxIntToInt32(cv.AuxInt)
+ if v_1.Op != OpEq32 {
+ continue
+ }
+ _ = v_1.Args[1]
+ v_1_0 := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ for _i2 := 0; _i2 <= 1; _i2, v_1_0, v_1_1 = _i2+1, v_1_1, v_1_0 {
+ if x != v_1_0 || v_1_1.Op != OpConst32 {
+ continue
+ }
+ d := auxIntToInt32(v_1_1.AuxInt)
+ if !(c|d == c && oneBit(c^d)) {
+ continue
+ }
+ v.reset(OpEq32)
+ v0 := b.NewValue0(v.Pos, OpOr32, x.Type)
+ v1 := b.NewValue0(v.Pos, OpConst32, x.Type)
+ v1.AuxInt = int32ToAuxInt(c ^ d)
+ v0.AddArg2(x, v1)
+ v.AddArg2(v0, cv)
+ return true
+ }
+ }
+ }
+ break
+ }
+ // match: (OrB (Eq16 x cv:(Const16 [c])) (Eq16 x (Const16 [d])))
+ // cond: c|d == c && oneBit(c^d)
+ // result: (Eq16 (Or16 <x.Type> x (Const16 <x.Type> [c^d])) cv)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpEq16 {
+ continue
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 {
+ x := v_0_0
+ cv := v_0_1
+ if cv.Op != OpConst16 {
+ continue
+ }
+ c := auxIntToInt16(cv.AuxInt)
+ if v_1.Op != OpEq16 {
+ continue
+ }
+ _ = v_1.Args[1]
+ v_1_0 := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ for _i2 := 0; _i2 <= 1; _i2, v_1_0, v_1_1 = _i2+1, v_1_1, v_1_0 {
+ if x != v_1_0 || v_1_1.Op != OpConst16 {
+ continue
+ }
+ d := auxIntToInt16(v_1_1.AuxInt)
+ if !(c|d == c && oneBit(c^d)) {
+ continue
+ }
+ v.reset(OpEq16)
+ v0 := b.NewValue0(v.Pos, OpOr16, x.Type)
+ v1 := b.NewValue0(v.Pos, OpConst16, x.Type)
+ v1.AuxInt = int16ToAuxInt(c ^ d)
+ v0.AddArg2(x, v1)
+ v.AddArg2(v0, cv)
+ return true
+ }
+ }
+ }
+ break
+ }
+ // match: (OrB (Eq8 x cv:(Const8 [c])) (Eq8 x (Const8 [d])))
+ // cond: c|d == c && oneBit(c^d)
+ // result: (Eq8 (Or8 <x.Type> x (Const8 <x.Type> [c^d])) cv)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpEq8 {
+ continue
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 {
+ x := v_0_0
+ cv := v_0_1
+ if cv.Op != OpConst8 {
+ continue
+ }
+ c := auxIntToInt8(cv.AuxInt)
+ if v_1.Op != OpEq8 {
+ continue
+ }
+ _ = v_1.Args[1]
+ v_1_0 := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ for _i2 := 0; _i2 <= 1; _i2, v_1_0, v_1_1 = _i2+1, v_1_1, v_1_0 {
+ if x != v_1_0 || v_1_1.Op != OpConst8 {
+ continue
+ }
+ d := auxIntToInt8(v_1_1.AuxInt)
+ if !(c|d == c && oneBit(c^d)) {
+ continue
+ }
+ v.reset(OpEq8)
+ v0 := b.NewValue0(v.Pos, OpOr8, x.Type)
+ v1 := b.NewValue0(v.Pos, OpConst8, x.Type)
+ v1.AuxInt = int8ToAuxInt(c ^ d)
+ v0.AddArg2(x, v1)
+ v.AddArg2(v0, cv)
+ return true
+ }
+ }
+ }
+ break
+ }
// match: (OrB (Neq64F x x) (Less64F x y:(Const64F [c])))
// result: (Not (Leq64F y x))
for {
@@ -31601,17 +32106,47 @@ func rewriteValuegeneric_OpStructSelect(v *Value) bool {
v0.AddArg2(v1, mem)
return true
}
- // match: (StructSelect [0] (IData x))
+ // match: (StructSelect (IData x))
+ // cond: v.Type.Size() > 0
// result: (IData x)
for {
- if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpIData {
+ if v_0.Op != OpIData {
break
}
x := v_0.Args[0]
+ if !(v.Type.Size() > 0) {
+ break
+ }
v.reset(OpIData)
v.AddArg(x)
return true
}
+ // match: (StructSelect (IData x))
+ // cond: v.Type.Size() == 0 && v.Type.IsStruct()
+ // result: (StructMake)
+ for {
+ if v_0.Op != OpIData {
+ break
+ }
+ if !(v.Type.Size() == 0 && v.Type.IsStruct()) {
+ break
+ }
+ v.reset(OpStructMake)
+ return true
+ }
+ // match: (StructSelect (IData x))
+ // cond: v.Type.Size() == 0 && v.Type.IsArray()
+ // result: (ArrayMake0)
+ for {
+ if v_0.Op != OpIData {
+ break
+ }
+ if !(v.Type.Size() == 0 && v.Type.IsArray()) {
+ break
+ }
+ v.reset(OpArrayMake0)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpSub16(v *Value) bool {
diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index e854cd9895..e59451c773 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -124,6 +124,11 @@ func InitConfig() {
ir.Syms.GCWriteBarrier[7] = typecheck.LookupRuntimeFunc("gcWriteBarrier8")
ir.Syms.Goschedguarded = typecheck.LookupRuntimeFunc("goschedguarded")
ir.Syms.Growslice = typecheck.LookupRuntimeFunc("growslice")
+ ir.Syms.GrowsliceBuf = typecheck.LookupRuntimeFunc("growsliceBuf")
+ ir.Syms.MoveSlice = typecheck.LookupRuntimeFunc("moveSlice")
+ ir.Syms.MoveSliceNoScan = typecheck.LookupRuntimeFunc("moveSliceNoScan")
+ ir.Syms.MoveSliceNoCap = typecheck.LookupRuntimeFunc("moveSliceNoCap")
+ ir.Syms.MoveSliceNoCapNoScan = typecheck.LookupRuntimeFunc("moveSliceNoCapNoScan")
ir.Syms.InterfaceSwitch = typecheck.LookupRuntimeFunc("interfaceSwitch")
for i := 1; i < len(ir.Syms.MallocGCSmallNoScan); i++ {
ir.Syms.MallocGCSmallNoScan[i] = typecheck.LookupRuntimeFunc(fmt.Sprintf("mallocgcSmallNoScanSC%d", i))
@@ -1096,6 +1101,23 @@ type state struct {
// Block starting position, indexed by block id.
blockStarts []src.XPos
+
+ // Information for stack allocation. Indexed by the first argument
+ // to an append call. Normally a slice-typed variable, but not always.
+ backingStores map[ir.Node]*backingStoreInfo
+}
+
+type backingStoreInfo struct {
+ // Size of backing store array (in elements)
+ K int64
+ // Stack-allocated backing store variable.
+ store *ir.Name
+ // Dynamic boolean variable marking the fact that we used this backing store.
+ used *ir.Name
+ // Have we used this variable statically yet? This is just a hint
+ // to avoid checking the dynamic variable if the answer is obvious.
+ // (usedStatic == true implies used == true)
+ usedStatic bool
}
type funcLine struct {
@@ -3683,6 +3705,9 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
case ir.OAPPEND:
return s.append(n.(*ir.CallExpr), false)
+ case ir.OMOVE2HEAP:
+ return s.move2heap(n.(*ir.MoveToHeapExpr))
+
case ir.OMIN, ir.OMAX:
return s.minMax(n.(*ir.CallExpr))
@@ -3744,6 +3769,68 @@ func (s *state) resultAddrOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.
return addr
}
+// Get backing store information for an append call.
+func (s *state) getBackingStoreInfoForAppend(n *ir.CallExpr) *backingStoreInfo {
+ if n.Esc() != ir.EscNone {
+ return nil
+ }
+ return s.getBackingStoreInfo(n.Args[0])
+}
+func (s *state) getBackingStoreInfo(n ir.Node) *backingStoreInfo {
+ t := n.Type()
+ et := t.Elem()
+ maxStackSize := int64(base.Debug.VariableMakeThreshold)
+ if et.Size() == 0 || et.Size() > maxStackSize {
+ return nil
+ }
+ if base.Flag.N != 0 {
+ return nil
+ }
+ if !base.VariableMakeHash.MatchPos(n.Pos(), nil) {
+ return nil
+ }
+ i := s.backingStores[n]
+ if i != nil {
+ return i
+ }
+
+ // Build type of backing store.
+ K := maxStackSize / et.Size() // rounds down
+ KT := types.NewArray(et, K)
+ KT.SetNoalg(true)
+ types.CalcArraySize(KT)
+ // Align more than naturally for the type KT. See issue 73199.
+ align := types.NewArray(types.Types[types.TUINTPTR], 0)
+ types.CalcArraySize(align)
+ storeTyp := types.NewStruct([]*types.Field{
+ {Sym: types.BlankSym, Type: align},
+ {Sym: types.BlankSym, Type: KT},
+ })
+ storeTyp.SetNoalg(true)
+ types.CalcStructSize(storeTyp)
+
+ // Make backing store variable.
+ backingStore := typecheck.TempAt(n.Pos(), s.curfn, storeTyp)
+ backingStore.SetAddrtaken(true)
+
+ // Make "used" boolean.
+ used := typecheck.TempAt(n.Pos(), s.curfn, types.Types[types.TBOOL])
+ if s.curBlock == s.f.Entry {
+ s.vars[used] = s.constBool(false)
+ } else {
+ // initialize this variable at end of entry block
+ s.defvars[s.f.Entry.ID][used] = s.constBool(false)
+ }
+
+ // Initialize an info structure.
+ if s.backingStores == nil {
+ s.backingStores = map[ir.Node]*backingStoreInfo{}
+ }
+ i = &backingStoreInfo{K: K, store: backingStore, used: used, usedStatic: false}
+ s.backingStores[n] = i
+ return i
+}
+
// append converts an OAPPEND node to SSA.
// If inplace is false, it converts the OAPPEND expression n to an ssa.Value,
// adds it to s, and returns the Value.
@@ -3834,9 +3921,29 @@ func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
// A stack-allocated backing store could be used at every
// append that qualifies, but we limit it in some cases to
// avoid wasted code and stack space.
- // TODO: handle ... append case.
- maxStackSize := int64(base.Debug.VariableMakeThreshold)
- if !inplace && n.Esc() == ir.EscNone && et.Size() > 0 && et.Size() <= maxStackSize && base.Flag.N == 0 && base.VariableMakeHash.MatchPos(n.Pos(), nil) && !s.appendTargets[sn] {
+ //
+ // Note that we have two different strategies.
+ // 1. The standard strategy is just to allocate the full
+ // backing store at the first append.
+ // 2. An alternate strategy is used when
+ // a. The backing store eventually escapes via move2heap
+ // and b. The capacity is used somehow
+ // In this case, we don't want to just allocate
+ // the full buffer at the first append, because when
+ // we move2heap the buffer to the heap when it escapes,
+ // we might end up wasting memory because we can't
+ // change the capacity.
+ // So in this case we use growsliceBuf to reuse the buffer
+ // and walk one step up the size class ladder each time.
+ //
+ // TODO: handle ... append case? Currently we handle only
+ // a fixed number of appended elements.
+ var info *backingStoreInfo
+ if !inplace {
+ info = s.getBackingStoreInfoForAppend(n)
+ }
+
+ if !inplace && info != nil && !n.UseBuf && !info.usedStatic {
// if l <= K {
// if !used {
// if oldLen == 0 {
@@ -3860,43 +3967,19 @@ func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
// It is ok to do it more often, but it is probably helpful only for
// the first instance. TODO: this could use more tuning. Using ir.Node
// as the key works for *ir.Name instances but probably nothing else.
- if s.appendTargets == nil {
- s.appendTargets = map[ir.Node]bool{}
- }
- s.appendTargets[sn] = true
-
- K := maxStackSize / et.Size() // rounds down
- KT := types.NewArray(et, K)
- KT.SetNoalg(true)
- types.CalcArraySize(KT)
- // Align more than naturally for the type KT. See issue 73199.
- align := types.NewArray(types.Types[types.TUINTPTR], 0)
- types.CalcArraySize(align)
- storeTyp := types.NewStruct([]*types.Field{
- {Sym: types.BlankSym, Type: align},
- {Sym: types.BlankSym, Type: KT},
- })
- storeTyp.SetNoalg(true)
- types.CalcStructSize(storeTyp)
+ info.usedStatic = true
+ // TODO: unset usedStatic somehow?
usedTestBlock := s.f.NewBlock(ssa.BlockPlain)
oldLenTestBlock := s.f.NewBlock(ssa.BlockPlain)
bodyBlock := s.f.NewBlock(ssa.BlockPlain)
growSlice := s.f.NewBlock(ssa.BlockPlain)
-
- // Make "used" boolean.
- tBool := types.Types[types.TBOOL]
- used := typecheck.TempAt(n.Pos(), s.curfn, tBool)
- s.defvars[s.f.Entry.ID][used] = s.constBool(false) // initialize this variable at fn entry
-
- // Make backing store variable.
tInt := types.Types[types.TINT]
- backingStore := typecheck.TempAt(n.Pos(), s.curfn, storeTyp)
- backingStore.SetAddrtaken(true)
+ tBool := types.Types[types.TBOOL]
// if l <= K
s.startBlock(grow)
- kTest := s.newValue2(s.ssaOp(ir.OLE, tInt), tBool, l, s.constInt(tInt, K))
+ kTest := s.newValue2(s.ssaOp(ir.OLE, tInt), tBool, l, s.constInt(tInt, info.K))
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(kTest)
@@ -3906,7 +3989,7 @@ func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
// if !used
s.startBlock(usedTestBlock)
- usedTest := s.newValue1(ssa.OpNot, tBool, s.expr(used))
+ usedTest := s.newValue1(ssa.OpNot, tBool, s.expr(info.used))
b = s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(usedTest)
@@ -3927,18 +4010,18 @@ func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
// var store struct { _ [0]uintptr; arr [K]T }
s.startBlock(bodyBlock)
if et.HasPointers() {
- s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, backingStore, s.mem())
+ s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, info.store, s.mem())
}
- addr := s.addr(backingStore)
- s.zero(storeTyp, addr)
+ addr := s.addr(info.store)
+ s.zero(info.store.Type(), addr)
// s = store.arr[:l:K]
s.vars[ptrVar] = addr
s.vars[lenVar] = l // nargs would also be ok because of the oldLen==0 test.
- s.vars[capVar] = s.constInt(tInt, K)
+ s.vars[capVar] = s.constInt(tInt, info.K)
// used = true
- s.assign(used, s.constBool(true), false, 0)
+ s.assign(info.used, s.constBool(true), false, 0)
b = s.endBlock()
b.AddEdgeTo(assign)
@@ -3949,7 +4032,25 @@ func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
// Call growslice
s.startBlock(grow)
taddr := s.expr(n.Fun)
- r := s.rtcall(ir.Syms.Growslice, true, []*types.Type{n.Type()}, p, l, c, nargs, taddr)
+ var r []*ssa.Value
+ if info != nil && n.UseBuf {
+ // Use stack-allocated buffer as backing store, if we can.
+ if et.HasPointers() && !info.usedStatic {
+ // Initialize in the function header. Not the best place,
+ // but it makes sure we don't scan this area before it is
+ // initialized.
+ mem := s.defvars[s.f.Entry.ID][memVar]
+ mem = s.f.Entry.NewValue1A(n.Pos(), ssa.OpVarDef, types.TypeMem, info.store, mem)
+ addr := s.f.Entry.NewValue2A(n.Pos(), ssa.OpLocalAddr, types.NewPtr(info.store.Type()), info.store, s.sp, mem)
+ mem = s.f.Entry.NewValue2I(n.Pos(), ssa.OpZero, types.TypeMem, info.store.Type().Size(), addr, mem)
+ mem.Aux = info.store.Type()
+ s.defvars[s.f.Entry.ID][memVar] = mem
+ info.usedStatic = true
+ }
+ r = s.rtcall(ir.Syms.GrowsliceBuf, true, []*types.Type{n.Type()}, p, l, c, nargs, taddr, s.addr(info.store), s.constInt(types.Types[types.TINT], info.K))
+ } else {
+ r = s.rtcall(ir.Syms.Growslice, true, []*types.Type{n.Type()}, p, l, c, nargs, taddr)
+ }
// Decompose output slice
p = s.newValue1(ssa.OpSlicePtr, pt, r[0])
@@ -4036,6 +4137,95 @@ func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
}
+func (s *state) move2heap(n *ir.MoveToHeapExpr) *ssa.Value {
+ // s := n.Slice
+ // if s.ptr points to current stack frame {
+ // s2 := make([]T, s.len, s.cap)
+ // copy(s2[:cap], s[:cap])
+ // s = s2
+ // }
+ // return s
+
+ slice := s.expr(n.Slice)
+ et := slice.Type.Elem()
+ pt := types.NewPtr(et)
+
+ info := s.getBackingStoreInfo(n)
+ if info == nil {
+ // Backing store will never be stack allocated, so
+ // move2heap is a no-op.
+ return slice
+ }
+
+ // Decomposse input slice.
+ p := s.newValue1(ssa.OpSlicePtr, pt, slice)
+ l := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
+ c := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], slice)
+
+ moveBlock := s.f.NewBlock(ssa.BlockPlain)
+ mergeBlock := s.f.NewBlock(ssa.BlockPlain)
+
+ s.vars[ptrVar] = p
+ s.vars[lenVar] = l
+ s.vars[capVar] = c
+
+ // Decide if we need to move the slice backing store.
+ // It needs to be moved if it is currently on the stack.
+ sub := ssa.OpSub64
+ less := ssa.OpLess64U
+ if s.config.PtrSize == 4 {
+ sub = ssa.OpSub32
+ less = ssa.OpLess32U
+ }
+ callerSP := s.newValue1(ssa.OpGetCallerSP, types.Types[types.TUINTPTR], s.mem())
+ frameSize := s.newValue2(sub, types.Types[types.TUINTPTR], callerSP, s.sp)
+ pInt := s.newValue2(ssa.OpConvert, types.Types[types.TUINTPTR], p, s.mem())
+ off := s.newValue2(sub, types.Types[types.TUINTPTR], pInt, s.sp)
+ cond := s.newValue2(less, types.Types[types.TBOOL], off, frameSize)
+
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.Likely = ssa.BranchUnlikely // fast path is to not have to call into runtime
+ b.SetControl(cond)
+ b.AddEdgeTo(moveBlock)
+ b.AddEdgeTo(mergeBlock)
+
+ // Move the slice to heap
+ s.startBlock(moveBlock)
+ var newSlice *ssa.Value
+ if et.HasPointers() {
+ typ := s.expr(n.RType)
+ if n.PreserveCapacity {
+ newSlice = s.rtcall(ir.Syms.MoveSlice, true, []*types.Type{slice.Type}, typ, p, l, c)[0]
+ } else {
+ newSlice = s.rtcall(ir.Syms.MoveSliceNoCap, true, []*types.Type{slice.Type}, typ, p, l)[0]
+ }
+ } else {
+ elemSize := s.constInt(types.Types[types.TUINTPTR], et.Size())
+ if n.PreserveCapacity {
+ newSlice = s.rtcall(ir.Syms.MoveSliceNoScan, true, []*types.Type{slice.Type}, elemSize, p, l, c)[0]
+ } else {
+ newSlice = s.rtcall(ir.Syms.MoveSliceNoCapNoScan, true, []*types.Type{slice.Type}, elemSize, p, l)[0]
+ }
+ }
+ // Decompose output slice
+ s.vars[ptrVar] = s.newValue1(ssa.OpSlicePtr, pt, newSlice)
+ s.vars[lenVar] = s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], newSlice)
+ s.vars[capVar] = s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], newSlice)
+ b = s.endBlock()
+ b.AddEdgeTo(mergeBlock)
+
+ // Merge fast path (no moving) and slow path (moved)
+ s.startBlock(mergeBlock)
+ p = s.variable(ptrVar, pt) // generates phi for ptr
+ l = s.variable(lenVar, types.Types[types.TINT]) // generates phi for len
+ c = s.variable(capVar, types.Types[types.TINT]) // generates phi for cap
+ delete(s.vars, ptrVar)
+ delete(s.vars, lenVar)
+ delete(s.vars, capVar)
+ return s.newValue3(ssa.OpSliceMake, slice.Type, p, l, c)
+}
+
// minMax converts an OMIN/OMAX builtin call into SSA.
func (s *state) minMax(n *ir.CallExpr) *ssa.Value {
// The OMIN/OMAX builtin is variadic, but its semantics are
diff --git a/src/cmd/compile/internal/test/testdata/arith_test.go b/src/cmd/compile/internal/test/testdata/arith_test.go
index 8984cd3e26..34ac73c068 100644
--- a/src/cmd/compile/internal/test/testdata/arith_test.go
+++ b/src/cmd/compile/internal/test/testdata/arith_test.go
@@ -445,6 +445,19 @@ func testBitwiseRshU_ssa(a uint32, b, c uint32) uint32 {
}
//go:noinline
+func orLt_ssa(x int) bool {
+ y := x - x
+ return (x | 2) < y
+}
+
+// test riscv64 SLTI rules
+func testSetIfLessThan(t *testing.T) {
+ if want, got := true, orLt_ssa(-7); got != want {
+ t.Errorf("orLt_ssa(-7) = %t want %t", got, want)
+ }
+}
+
+//go:noinline
func testShiftCX_ssa() int {
v1 := uint8(3)
v4 := (v1 * v1) ^ v1 | v1 - v1 - v1&v1 ^ uint8(3+2) + v1*1>>0 - v1 | 1 | v1<<(2*3|0-0*0^1)
@@ -977,6 +990,7 @@ func TestArithmetic(t *testing.T) {
testRegallocCVSpill(t)
testSubqToNegq(t)
testBitwiseLogic(t)
+ testSetIfLessThan(t)
testOcom(t)
testLrot(t)
testShiftCX(t)
diff --git a/src/cmd/compile/internal/typecheck/_builtin/runtime.go b/src/cmd/compile/internal/typecheck/_builtin/runtime.go
index 3c9707252e..3e2324b528 100644
--- a/src/cmd/compile/internal/typecheck/_builtin/runtime.go
+++ b/src/cmd/compile/internal/typecheck/_builtin/runtime.go
@@ -195,6 +195,7 @@ func makeslice(typ *byte, len int, cap int) unsafe.Pointer
func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer
func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
func growslice(oldPtr *any, newLen, oldCap, num int, et *byte) (ary []any)
+func growsliceBuf(oldPtr *any, newLen, oldCap, num int, et *byte, buf *any, bufLen int) (ary []any)
func unsafeslicecheckptr(typ *byte, ptr unsafe.Pointer, len int64)
func panicunsafeslicelen()
func panicunsafeslicenilptr()
@@ -202,6 +203,11 @@ func unsafestringcheckptr(ptr unsafe.Pointer, len int64)
func panicunsafestringlen()
func panicunsafestringnilptr()
+func moveSlice(typ *byte, old *byte, len, cap int) (*byte, int, int)
+func moveSliceNoScan(elemSize uintptr, old *byte, len, cap int) (*byte, int, int)
+func moveSliceNoCap(typ *byte, old *byte, len int) (*byte, int, int)
+func moveSliceNoCapNoScan(elemSize uintptr, old *byte, len int) (*byte, int, int)
+
func memmove(to *any, frm *any, length uintptr)
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
func memclrHasPointers(ptr unsafe.Pointer, n uintptr)
diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go
index eea7fd7d05..537de2cbe9 100644
--- a/src/cmd/compile/internal/typecheck/builtin.go
+++ b/src/cmd/compile/internal/typecheck/builtin.go
@@ -160,80 +160,85 @@ var runtimeDecls = [...]struct {
{"makeslice64", funcTag, 124},
{"makeslicecopy", funcTag, 125},
{"growslice", funcTag, 127},
- {"unsafeslicecheckptr", funcTag, 128},
+ {"growsliceBuf", funcTag, 128},
+ {"unsafeslicecheckptr", funcTag, 129},
{"panicunsafeslicelen", funcTag, 9},
{"panicunsafeslicenilptr", funcTag, 9},
- {"unsafestringcheckptr", funcTag, 129},
+ {"unsafestringcheckptr", funcTag, 130},
{"panicunsafestringlen", funcTag, 9},
{"panicunsafestringnilptr", funcTag, 9},
- {"memmove", funcTag, 130},
- {"memclrNoHeapPointers", funcTag, 131},
- {"memclrHasPointers", funcTag, 131},
- {"memequal", funcTag, 132},
- {"memequal0", funcTag, 133},
- {"memequal8", funcTag, 133},
- {"memequal16", funcTag, 133},
- {"memequal32", funcTag, 133},
- {"memequal64", funcTag, 133},
- {"memequal128", funcTag, 133},
- {"f32equal", funcTag, 134},
- {"f64equal", funcTag, 134},
- {"c64equal", funcTag, 134},
- {"c128equal", funcTag, 134},
- {"strequal", funcTag, 134},
- {"interequal", funcTag, 134},
- {"nilinterequal", funcTag, 134},
- {"memhash", funcTag, 135},
- {"memhash0", funcTag, 136},
- {"memhash8", funcTag, 136},
- {"memhash16", funcTag, 136},
- {"memhash32", funcTag, 136},
- {"memhash64", funcTag, 136},
- {"memhash128", funcTag, 136},
- {"f32hash", funcTag, 137},
- {"f64hash", funcTag, 137},
- {"c64hash", funcTag, 137},
- {"c128hash", funcTag, 137},
- {"strhash", funcTag, 137},
- {"interhash", funcTag, 137},
- {"nilinterhash", funcTag, 137},
- {"int64div", funcTag, 138},
- {"uint64div", funcTag, 139},
- {"int64mod", funcTag, 138},
- {"uint64mod", funcTag, 139},
- {"float64toint64", funcTag, 140},
- {"float64touint64", funcTag, 141},
- {"float64touint32", funcTag, 142},
- {"int64tofloat64", funcTag, 143},
- {"int64tofloat32", funcTag, 144},
- {"uint64tofloat64", funcTag, 145},
- {"uint64tofloat32", funcTag, 146},
- {"uint32tofloat64", funcTag, 147},
- {"complex128div", funcTag, 148},
+ {"moveSlice", funcTag, 131},
+ {"moveSliceNoScan", funcTag, 132},
+ {"moveSliceNoCap", funcTag, 133},
+ {"moveSliceNoCapNoScan", funcTag, 134},
+ {"memmove", funcTag, 135},
+ {"memclrNoHeapPointers", funcTag, 136},
+ {"memclrHasPointers", funcTag, 136},
+ {"memequal", funcTag, 137},
+ {"memequal0", funcTag, 138},
+ {"memequal8", funcTag, 138},
+ {"memequal16", funcTag, 138},
+ {"memequal32", funcTag, 138},
+ {"memequal64", funcTag, 138},
+ {"memequal128", funcTag, 138},
+ {"f32equal", funcTag, 139},
+ {"f64equal", funcTag, 139},
+ {"c64equal", funcTag, 139},
+ {"c128equal", funcTag, 139},
+ {"strequal", funcTag, 139},
+ {"interequal", funcTag, 139},
+ {"nilinterequal", funcTag, 139},
+ {"memhash", funcTag, 140},
+ {"memhash0", funcTag, 141},
+ {"memhash8", funcTag, 141},
+ {"memhash16", funcTag, 141},
+ {"memhash32", funcTag, 141},
+ {"memhash64", funcTag, 141},
+ {"memhash128", funcTag, 141},
+ {"f32hash", funcTag, 142},
+ {"f64hash", funcTag, 142},
+ {"c64hash", funcTag, 142},
+ {"c128hash", funcTag, 142},
+ {"strhash", funcTag, 142},
+ {"interhash", funcTag, 142},
+ {"nilinterhash", funcTag, 142},
+ {"int64div", funcTag, 143},
+ {"uint64div", funcTag, 144},
+ {"int64mod", funcTag, 143},
+ {"uint64mod", funcTag, 144},
+ {"float64toint64", funcTag, 145},
+ {"float64touint64", funcTag, 146},
+ {"float64touint32", funcTag, 147},
+ {"int64tofloat64", funcTag, 148},
+ {"int64tofloat32", funcTag, 149},
+ {"uint64tofloat64", funcTag, 150},
+ {"uint64tofloat32", funcTag, 151},
+ {"uint32tofloat64", funcTag, 152},
+ {"complex128div", funcTag, 153},
{"racefuncenter", funcTag, 33},
{"racefuncexit", funcTag, 9},
{"raceread", funcTag, 33},
{"racewrite", funcTag, 33},
- {"racereadrange", funcTag, 149},
- {"racewriterange", funcTag, 149},
- {"msanread", funcTag, 149},
- {"msanwrite", funcTag, 149},
- {"msanmove", funcTag, 150},
- {"asanread", funcTag, 149},
- {"asanwrite", funcTag, 149},
- {"checkptrAlignment", funcTag, 151},
- {"checkptrArithmetic", funcTag, 153},
- {"libfuzzerTraceCmp1", funcTag, 154},
- {"libfuzzerTraceCmp2", funcTag, 155},
- {"libfuzzerTraceCmp4", funcTag, 156},
- {"libfuzzerTraceCmp8", funcTag, 157},
- {"libfuzzerTraceConstCmp1", funcTag, 154},
- {"libfuzzerTraceConstCmp2", funcTag, 155},
- {"libfuzzerTraceConstCmp4", funcTag, 156},
- {"libfuzzerTraceConstCmp8", funcTag, 157},
- {"libfuzzerHookStrCmp", funcTag, 158},
- {"libfuzzerHookEqualFold", funcTag, 158},
- {"addCovMeta", funcTag, 160},
+ {"racereadrange", funcTag, 154},
+ {"racewriterange", funcTag, 154},
+ {"msanread", funcTag, 154},
+ {"msanwrite", funcTag, 154},
+ {"msanmove", funcTag, 155},
+ {"asanread", funcTag, 154},
+ {"asanwrite", funcTag, 154},
+ {"checkptrAlignment", funcTag, 156},
+ {"checkptrArithmetic", funcTag, 158},
+ {"libfuzzerTraceCmp1", funcTag, 159},
+ {"libfuzzerTraceCmp2", funcTag, 160},
+ {"libfuzzerTraceCmp4", funcTag, 161},
+ {"libfuzzerTraceCmp8", funcTag, 162},
+ {"libfuzzerTraceConstCmp1", funcTag, 159},
+ {"libfuzzerTraceConstCmp2", funcTag, 160},
+ {"libfuzzerTraceConstCmp4", funcTag, 161},
+ {"libfuzzerTraceConstCmp8", funcTag, 162},
+ {"libfuzzerHookStrCmp", funcTag, 163},
+ {"libfuzzerHookEqualFold", funcTag, 163},
+ {"addCovMeta", funcTag, 165},
{"x86HasAVX", varTag, 6},
{"x86HasFMA", varTag, 6},
{"x86HasPOPCNT", varTag, 6},
@@ -244,11 +249,11 @@ var runtimeDecls = [...]struct {
{"loong64HasLAM_BH", varTag, 6},
{"loong64HasLSX", varTag, 6},
{"riscv64HasZbb", varTag, 6},
- {"asanregisterglobals", funcTag, 131},
+ {"asanregisterglobals", funcTag, 136},
}
func runtimeTypes() []*types.Type {
- var typs [161]*types.Type
+ var typs [166]*types.Type
typs[0] = types.ByteType
typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[types.TANY]
@@ -377,39 +382,44 @@ func runtimeTypes() []*types.Type {
typs[125] = newSig(params(typs[1], typs[13], typs[13], typs[7]), params(typs[7]))
typs[126] = types.NewSlice(typs[2])
typs[127] = newSig(params(typs[3], typs[13], typs[13], typs[13], typs[1]), params(typs[126]))
- typs[128] = newSig(params(typs[1], typs[7], typs[22]), nil)
- typs[129] = newSig(params(typs[7], typs[22]), nil)
- typs[130] = newSig(params(typs[3], typs[3], typs[5]), nil)
- typs[131] = newSig(params(typs[7], typs[5]), nil)
- typs[132] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
- typs[133] = newSig(params(typs[3], typs[3]), params(typs[6]))
- typs[134] = newSig(params(typs[7], typs[7]), params(typs[6]))
- typs[135] = newSig(params(typs[3], typs[5], typs[5]), params(typs[5]))
- typs[136] = newSig(params(typs[7], typs[5]), params(typs[5]))
- typs[137] = newSig(params(typs[3], typs[5]), params(typs[5]))
- typs[138] = newSig(params(typs[22], typs[22]), params(typs[22]))
- typs[139] = newSig(params(typs[24], typs[24]), params(typs[24]))
- typs[140] = newSig(params(typs[18]), params(typs[22]))
- typs[141] = newSig(params(typs[18]), params(typs[24]))
- typs[142] = newSig(params(typs[18]), params(typs[67]))
- typs[143] = newSig(params(typs[22]), params(typs[18]))
- typs[144] = newSig(params(typs[22]), params(typs[20]))
- typs[145] = newSig(params(typs[24]), params(typs[18]))
- typs[146] = newSig(params(typs[24]), params(typs[20]))
- typs[147] = newSig(params(typs[67]), params(typs[18]))
- typs[148] = newSig(params(typs[26], typs[26]), params(typs[26]))
- typs[149] = newSig(params(typs[5], typs[5]), nil)
- typs[150] = newSig(params(typs[5], typs[5], typs[5]), nil)
- typs[151] = newSig(params(typs[7], typs[1], typs[5]), nil)
- typs[152] = types.NewSlice(typs[7])
- typs[153] = newSig(params(typs[7], typs[152]), nil)
- typs[154] = newSig(params(typs[71], typs[71], typs[15]), nil)
- typs[155] = newSig(params(typs[65], typs[65], typs[15]), nil)
- typs[156] = newSig(params(typs[67], typs[67], typs[15]), nil)
- typs[157] = newSig(params(typs[24], typs[24], typs[15]), nil)
- typs[158] = newSig(params(typs[30], typs[30], typs[15]), nil)
- typs[159] = types.NewArray(typs[0], 16)
- typs[160] = newSig(params(typs[7], typs[67], typs[159], typs[30], typs[13], typs[71], typs[71]), params(typs[67]))
+ typs[128] = newSig(params(typs[3], typs[13], typs[13], typs[13], typs[1], typs[3], typs[13]), params(typs[126]))
+ typs[129] = newSig(params(typs[1], typs[7], typs[22]), nil)
+ typs[130] = newSig(params(typs[7], typs[22]), nil)
+ typs[131] = newSig(params(typs[1], typs[1], typs[13], typs[13]), params(typs[1], typs[13], typs[13]))
+ typs[132] = newSig(params(typs[5], typs[1], typs[13], typs[13]), params(typs[1], typs[13], typs[13]))
+ typs[133] = newSig(params(typs[1], typs[1], typs[13]), params(typs[1], typs[13], typs[13]))
+ typs[134] = newSig(params(typs[5], typs[1], typs[13]), params(typs[1], typs[13], typs[13]))
+ typs[135] = newSig(params(typs[3], typs[3], typs[5]), nil)
+ typs[136] = newSig(params(typs[7], typs[5]), nil)
+ typs[137] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
+ typs[138] = newSig(params(typs[3], typs[3]), params(typs[6]))
+ typs[139] = newSig(params(typs[7], typs[7]), params(typs[6]))
+ typs[140] = newSig(params(typs[3], typs[5], typs[5]), params(typs[5]))
+ typs[141] = newSig(params(typs[7], typs[5]), params(typs[5]))
+ typs[142] = newSig(params(typs[3], typs[5]), params(typs[5]))
+ typs[143] = newSig(params(typs[22], typs[22]), params(typs[22]))
+ typs[144] = newSig(params(typs[24], typs[24]), params(typs[24]))
+ typs[145] = newSig(params(typs[18]), params(typs[22]))
+ typs[146] = newSig(params(typs[18]), params(typs[24]))
+ typs[147] = newSig(params(typs[18]), params(typs[67]))
+ typs[148] = newSig(params(typs[22]), params(typs[18]))
+ typs[149] = newSig(params(typs[22]), params(typs[20]))
+ typs[150] = newSig(params(typs[24]), params(typs[18]))
+ typs[151] = newSig(params(typs[24]), params(typs[20]))
+ typs[152] = newSig(params(typs[67]), params(typs[18]))
+ typs[153] = newSig(params(typs[26], typs[26]), params(typs[26]))
+ typs[154] = newSig(params(typs[5], typs[5]), nil)
+ typs[155] = newSig(params(typs[5], typs[5], typs[5]), nil)
+ typs[156] = newSig(params(typs[7], typs[1], typs[5]), nil)
+ typs[157] = types.NewSlice(typs[7])
+ typs[158] = newSig(params(typs[7], typs[157]), nil)
+ typs[159] = newSig(params(typs[71], typs[71], typs[15]), nil)
+ typs[160] = newSig(params(typs[65], typs[65], typs[15]), nil)
+ typs[161] = newSig(params(typs[67], typs[67], typs[15]), nil)
+ typs[162] = newSig(params(typs[24], typs[24], typs[15]), nil)
+ typs[163] = newSig(params(typs[30], typs[30], typs[15]), nil)
+ typs[164] = types.NewArray(typs[0], 16)
+ typs[165] = newSig(params(typs[7], typs[67], typs[164], typs[30], typs[13], typs[71], typs[71]), params(typs[67]))
return typs[:]
}
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index e8aca90081..6663c49dd8 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -1842,26 +1842,7 @@ func IsReflexive(t *Type) bool {
// Can this type be stored directly in an interface word?
// Yes, if the representation is a single pointer.
func IsDirectIface(t *Type) bool {
- switch t.Kind() {
- case TPTR:
- // Pointers to notinheap types must be stored indirectly. See issue 42076.
- return !t.Elem().NotInHeap()
- case TCHAN,
- TMAP,
- TFUNC,
- TUNSAFEPTR:
- return true
-
- case TARRAY:
- // Array of 1 direct iface type can be direct.
- return t.NumElem() == 1 && IsDirectIface(t.Elem())
-
- case TSTRUCT:
- // Struct with 1 field of direct iface type can be direct.
- return t.NumFields() == 1 && IsDirectIface(t.Field(0).Type)
- }
-
- return false
+ return t.Size() == int64(PtrSize) && PtrDataSize(t) == int64(PtrSize)
}
// IsInterfaceMethod reports whether (field) m is
diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go
index 25cda4f73d..42218b4caf 100644
--- a/src/cmd/compile/internal/types2/check.go
+++ b/src/cmd/compile/internal/types2/check.go
@@ -171,12 +171,13 @@ type Checker struct {
usedPkgNames map[*PkgName]bool // set of used package names
mono monoGraph // graph for detecting non-monomorphizable instantiation loops
- firstErr error // first error encountered
- methods map[*TypeName][]*Func // maps package scope type names to associated non-blank (non-interface) methods
- untyped map[syntax.Expr]exprInfo // map of expressions without final type
- delayed []action // stack of delayed action segments; segments are processed in FIFO order
- objPath []Object // path of object dependencies during type inference (for cycle reporting)
- cleaners []cleaner // list of types that may need a final cleanup at the end of type-checking
+ firstErr error // first error encountered
+ methods map[*TypeName][]*Func // maps package scope type names to associated non-blank (non-interface) methods
+ untyped map[syntax.Expr]exprInfo // map of expressions without final type
+ delayed []action // stack of delayed action segments; segments are processed in FIFO order
+ objPath []Object // path of object dependencies during type-checking (for cycle reporting)
+ objPathIdx map[Object]int // map of object to object path index during type-checking (for cycle reporting)
+ cleaners []cleaner // list of types that may need a final cleanup at the end of type-checking
// environment within which the current object is type-checked (valid only
// for the duration of type-checking a specific object)
@@ -248,19 +249,22 @@ func (check *Checker) later(f func()) *action {
return &check.delayed[i]
}
-// push pushes obj onto the object path and returns its index in the path.
-func (check *Checker) push(obj Object) int {
+// push pushes obj onto the object path and records its index in the path index map.
+func (check *Checker) push(obj Object) {
+ if check.objPathIdx == nil {
+ check.objPathIdx = make(map[Object]int)
+ }
+ check.objPathIdx[obj] = len(check.objPath)
check.objPath = append(check.objPath, obj)
- return len(check.objPath) - 1
}
-// pop pops and returns the topmost object from the object path.
-func (check *Checker) pop() Object {
+// pop pops an object from the object path and removes it from the path index map.
+func (check *Checker) pop() {
i := len(check.objPath) - 1
obj := check.objPath[i]
- check.objPath[i] = nil
+ check.objPath[i] = nil // help the garbage collector
check.objPath = check.objPath[:i]
- return obj
+ delete(check.objPathIdx, obj)
}
type cleaner interface {
@@ -319,6 +323,7 @@ func (check *Checker) initFiles(files []*syntax.File) {
check.untyped = nil
check.delayed = nil
check.objPath = nil
+ check.objPathIdx = nil
check.cleaners = nil
// We must initialize usedVars and usedPkgNames both here and in NewChecker,
diff --git a/src/cmd/compile/internal/types2/cycles.go b/src/cmd/compile/internal/types2/cycles.go
index fa739a2b84..b916219c97 100644
--- a/src/cmd/compile/internal/types2/cycles.go
+++ b/src/cmd/compile/internal/types2/cycles.go
@@ -54,7 +54,6 @@ func (check *Checker) directCycle(tname *TypeName, pathIdx map[*TypeName]int) {
// tname is marked grey - we have a cycle on the path beginning at start.
// Mark tname as invalid.
tname.setType(Typ[Invalid])
- tname.setColor(black)
// collect type names on cycle
var cycle []Object
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go
index 91d2492a53..5cb52fdbe4 100644
--- a/src/cmd/compile/internal/types2/decl.go
+++ b/src/cmd/compile/internal/types2/decl.go
@@ -62,114 +62,77 @@ func (check *Checker) objDecl(obj Object, def *TypeName) {
if check.indent == 0 {
fmt.Println() // empty line between top-level objects for readability
}
- check.trace(obj.Pos(), "-- checking %s (%s, objPath = %s)", obj, obj.color(), pathString(check.objPath))
+ check.trace(obj.Pos(), "-- checking %s (objPath = %s)", obj, pathString(check.objPath))
check.indent++
defer func() {
check.indent--
- check.trace(obj.Pos(), "=> %s (%s)", obj, obj.color())
+ check.trace(obj.Pos(), "=> %s", obj)
}()
}
- // Checking the declaration of obj means inferring its type
- // (and possibly its value, for constants).
- // An object's type (and thus the object) may be in one of
- // three states which are expressed by colors:
+ // Checking the declaration of an object means determining its type
+ // (and also its value for constants). An object (and thus its type)
+ // may be in 1 of 3 states:
//
- // - an object whose type is not yet known is painted white (initial color)
- // - an object whose type is in the process of being inferred is painted grey
- // - an object whose type is fully inferred is painted black
+ // - not in Checker.objPathIdx and type == nil : type is not yet known (white)
+ // - in Checker.objPathIdx : type is pending (grey)
+ // - not in Checker.objPathIdx and type != nil : type is known (black)
//
- // During type inference, an object's color changes from white to grey
- // to black (pre-declared objects are painted black from the start).
- // A black object (i.e., its type) can only depend on (refer to) other black
- // ones. White and grey objects may depend on white and black objects.
- // A dependency on a grey object indicates a cycle which may or may not be
- // valid.
+ // During type-checking, an object changes from white to grey to black.
+ // Predeclared objects start as black (their type is known without checking).
//
- // When objects turn grey, they are pushed on the object path (a stack);
- // they are popped again when they turn black. Thus, if a grey object (a
- // cycle) is encountered, it is on the object path, and all the objects
- // it depends on are the remaining objects on that path. Color encoding
- // is such that the color value of a grey object indicates the index of
- // that object in the object path.
-
- // During type-checking, white objects may be assigned a type without
- // traversing through objDecl; e.g., when initializing constants and
- // variables. Update the colors of those objects here (rather than
- // everywhere where we set the type) to satisfy the color invariants.
- if obj.color() == white && obj.Type() != nil {
- obj.setColor(black)
- return
- }
-
- switch obj.color() {
- case white:
- assert(obj.Type() == nil)
- // All color values other than white and black are considered grey.
- // Because black and white are < grey, all values >= grey are grey.
- // Use those values to encode the object's index into the object path.
- obj.setColor(grey + color(check.push(obj)))
- defer func() {
- check.pop().setColor(black)
- }()
-
- case black:
- assert(obj.Type() != nil)
- return
-
- default:
- // Color values other than white or black are considered grey.
- fallthrough
+ // A black object may only depend on (refer to) to other black objects. White
+ // and grey objects may depend on white or black objects. A dependency on a
+ // grey object indicates a (possibly invalid) cycle.
+ //
+ // When an object is marked grey, it is pushed onto the object path (a stack)
+ // and its index in the path is recorded in the path index map. It is popped
+ // and removed from the map when its type is determined (and marked black).
- case grey:
- // We have a (possibly invalid) cycle.
- // In the existing code, this is marked by a non-nil type
- // for the object except for constants and variables whose
- // type may be non-nil (known), or nil if it depends on the
- // not-yet known initialization value.
- // In the former case, set the type to Typ[Invalid] because
- // we have an initialization cycle. The cycle error will be
- // reported later, when determining initialization order.
- // TODO(gri) Report cycle here and simplify initialization
- // order code.
+ // If this object is grey, we have a (possibly invalid) cycle. This is signaled
+ // by a non-nil type for the object, except for constants and variables whose
+ // type may be non-nil (known), or nil if it depends on a not-yet known
+ // initialization value.
+ //
+ // In the former case, set the type to Typ[Invalid] because we have an
+ // initialization cycle. The cycle error will be reported later, when
+ // determining initialization order.
+ //
+ // TODO(gri) Report cycle here and simplify initialization order code.
+ if _, ok := check.objPathIdx[obj]; ok {
switch obj := obj.(type) {
- case *Const:
- if !check.validCycle(obj) || obj.typ == nil {
- obj.typ = Typ[Invalid]
- }
-
- case *Var:
- if !check.validCycle(obj) || obj.typ == nil {
- obj.typ = Typ[Invalid]
+ case *Const, *Var:
+ if !check.validCycle(obj) || obj.Type() == nil {
+ obj.setType(Typ[Invalid])
}
-
case *TypeName:
if !check.validCycle(obj) {
- // break cycle
- // (without this, calling underlying()
- // below may lead to an endless loop
- // if we have a cycle for a defined
- // (*Named) type)
- obj.typ = Typ[Invalid]
+ obj.setType(Typ[Invalid])
}
-
case *Func:
if !check.validCycle(obj) {
- // Don't set obj.typ to Typ[Invalid] here
- // because plenty of code type-asserts that
- // functions have a *Signature type. Grey
- // functions have their type set to an empty
- // signature which makes it impossible to
+ // Don't set type to Typ[Invalid]; plenty of code asserts that
+ // functions have a *Signature type. Instead, leave the type
+ // as an empty signature, which makes it impossible to
// initialize a variable with the function.
}
-
default:
panic("unreachable")
}
+
assert(obj.Type() != nil)
return
}
+ if obj.Type() != nil { // black, meaning it's already type-checked
+ return
+ }
+
+ // white, meaning it must be type-checked
+
+ check.push(obj)
+ defer check.pop()
+
d := check.objMap[obj]
if d == nil {
check.dump("%v: %s should have been declared", obj.Pos(), obj)
@@ -221,8 +184,8 @@ func (check *Checker) validCycle(obj Object) (valid bool) {
}
// Count cycle objects.
- assert(obj.color() >= grey)
- start := obj.color() - grey // index of obj in objPath
+ start, found := check.objPathIdx[obj]
+ assert(found)
cycle := check.objPath[start:]
tparCycle := false // if set, the cycle is through a type parameter list
nval := 0 // number of (constant or variable) values in the cycle
@@ -532,11 +495,16 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *TypeN
check.collectTypeParams(&alias.tparams, tdecl.TParamList)
}
- rhs = check.definedType(tdecl.Type, obj)
+ rhs = check.declaredType(tdecl.Type, obj)
assert(rhs != nil)
-
alias.fromRHS = rhs
- unalias(alias) // populate alias.actual
+
+ // spec: In an alias declaration the given type cannot be a type parameter declared in the same declaration."
+ // (see also go.dev/issue/75884, go.dev/issue/#75885)
+ if tpar, ok := rhs.(*TypeParam); ok && alias.tparams != nil && slices.Index(alias.tparams.list(), tpar) >= 0 {
+ check.error(tdecl.Type, MisplacedTypeParam, "cannot use type parameter declared in alias declaration as RHS")
+ alias.fromRHS = Typ[Invalid]
+ }
} else {
if !versionErr && tparam0 != nil {
check.error(tdecl, UnsupportedFeature, "generic type alias requires GODEBUG=gotypesalias=1 or unset")
@@ -576,7 +544,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *TypeN
check.collectTypeParams(&named.tparams, tdecl.TParamList)
}
- rhs = check.definedType(tdecl.Type, obj)
+ rhs = check.declaredType(tdecl.Type, obj)
assert(rhs != nil)
named.fromRHS = rhs
@@ -764,17 +732,8 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
sig := new(Signature)
obj.typ = sig // guard against cycles
- // Avoid cycle error when referring to method while type-checking the signature.
- // This avoids a nuisance in the best case (non-parameterized receiver type) and
- // since the method is not a type, we get an error. If we have a parameterized
- // receiver type, instantiating the receiver type leads to the instantiation of
- // its methods, and we don't want a cycle error in that case.
- // TODO(gri) review if this is correct and/or whether we still need this?
- saved := obj.color_
- obj.color_ = black
fdecl := decl.fdecl
check.funcType(sig, fdecl.Recv, fdecl.TParamList, fdecl.Type)
- obj.color_ = saved
// Set the scope's extent to the complete "func (...) { ... }"
// so that Scope.Innermost works correctly.
@@ -921,10 +880,9 @@ func (check *Checker) declStmt(list []syntax.Decl) {
// the innermost containing block."
scopePos := s.Name.Pos()
check.declare(check.scope, s.Name, obj, scopePos)
- // mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
- obj.setColor(grey + color(check.push(obj)))
+ check.push(obj) // mark as grey
check.typeDecl(obj, s, nil)
- check.pop().setColor(black)
+ check.pop()
default:
check.errorf(s, InvalidSyntaxTree, "unknown syntax.Decl node %T", s)
diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go
index ce129dbf59..dd2d415790 100644
--- a/src/cmd/compile/internal/types2/object.go
+++ b/src/cmd/compile/internal/types2/object.go
@@ -42,18 +42,12 @@ type Object interface {
// 0 for all other objects (including objects in file scopes).
order() uint32
- // color returns the object's color.
- color() color
-
// setType sets the type of the object.
setType(Type)
// setOrder sets the order number of the object. It must be > 0.
setOrder(uint32)
- // setColor sets the object's color. It must not be white.
- setColor(color color)
-
// setParent sets the parent scope of the object.
setParent(*Scope)
@@ -102,41 +96,9 @@ type object struct {
name string
typ Type
order_ uint32
- color_ color
scopePos_ syntax.Pos
}
-// color encodes the color of an object (see Checker.objDecl for details).
-type color uint32
-
-// An object may be painted in one of three colors.
-// Color values other than white or black are considered grey.
-const (
- white color = iota
- black
- grey // must be > white and black
-)
-
-func (c color) String() string {
- switch c {
- case white:
- return "white"
- case black:
- return "black"
- default:
- return "grey"
- }
-}
-
-// colorFor returns the (initial) color for an object depending on
-// whether its type t is known or not.
-func colorFor(t Type) color {
- if t != nil {
- return black
- }
- return white
-}
-
// Parent returns the scope in which the object is declared.
// The result is nil for methods and struct fields.
func (obj *object) Parent() *Scope { return obj.parent }
@@ -164,13 +126,11 @@ func (obj *object) Id() string { return Id(obj.pkg, obj.name) }
func (obj *object) String() string { panic("abstract") }
func (obj *object) order() uint32 { return obj.order_ }
-func (obj *object) color() color { return obj.color_ }
func (obj *object) scopePos() syntax.Pos { return obj.scopePos_ }
func (obj *object) setParent(parent *Scope) { obj.parent = parent }
func (obj *object) setType(typ Type) { obj.typ = typ }
func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = order }
-func (obj *object) setColor(color color) { assert(color != white); obj.color_ = color }
func (obj *object) setScopePos(pos syntax.Pos) { obj.scopePos_ = pos }
func (obj *object) sameId(pkg *Package, name string, foldCase bool) bool {
@@ -247,7 +207,7 @@ type PkgName struct {
// NewPkgName returns a new PkgName object representing an imported package.
// The remaining arguments set the attributes found with all Objects.
func NewPkgName(pos syntax.Pos, pkg *Package, name string, imported *Package) *PkgName {
- return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, nopos}, imported}
+ return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, nopos}, imported}
}
// Imported returns the package that was imported.
@@ -263,7 +223,7 @@ type Const struct {
// NewConst returns a new constant with value val.
// The remaining arguments set the attributes found with all Objects.
func NewConst(pos syntax.Pos, pkg *Package, name string, typ Type, val constant.Value) *Const {
- return &Const{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, val}
+ return &Const{object{nil, pos, pkg, name, typ, 0, nopos}, val}
}
// Val returns the constant's value.
@@ -288,7 +248,7 @@ type TypeName struct {
// argument for NewNamed, which will set the TypeName's type as a side-
// effect.
func NewTypeName(pos syntax.Pos, pkg *Package, name string, typ Type) *TypeName {
- return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}}
+ return &TypeName{object{nil, pos, pkg, name, typ, 0, nopos}}
}
// NewTypeNameLazy returns a new defined type like NewTypeName, but it
@@ -402,7 +362,7 @@ func NewField(pos syntax.Pos, pkg *Package, name string, typ Type, embedded bool
// newVar returns a new variable.
// The arguments set the attributes found with all Objects.
func newVar(kind VarKind, pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
- return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, kind: kind}
+ return &Var{object: object{nil, pos, pkg, name, typ, 0, nopos}, kind: kind}
}
// Anonymous reports whether the variable is an embedded field.
@@ -452,7 +412,7 @@ func NewFunc(pos syntax.Pos, pkg *Package, name string, sig *Signature) *Func {
// as this would violate object.{Type,color} invariants.
// TODO(adonovan): propose to disallow NewFunc with nil *Signature.
}
- return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, false, nil}
+ return &Func{object{nil, pos, pkg, name, typ, 0, nopos}, false, nil}
}
// Signature returns the signature (type) of the function or method.
@@ -534,7 +494,7 @@ type Label struct {
// NewLabel returns a new label.
func NewLabel(pos syntax.Pos, pkg *Package, name string) *Label {
- return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid], color_: black}, false}
+ return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid]}, false}
}
// A Builtin represents a built-in function.
@@ -545,7 +505,7 @@ type Builtin struct {
}
func newBuiltin(id builtinId) *Builtin {
- return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid], color_: black}, id}
+ return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid]}, id}
}
// Nil represents the predeclared value nil.
diff --git a/src/cmd/compile/internal/types2/scope.go b/src/cmd/compile/internal/types2/scope.go
index 566184df73..10c624be2e 100644
--- a/src/cmd/compile/internal/types2/scope.go
+++ b/src/cmd/compile/internal/types2/scope.go
@@ -217,10 +217,8 @@ func (*lazyObject) Exported() bool { panic("unreachable") }
func (*lazyObject) Id() string { panic("unreachable") }
func (*lazyObject) String() string { panic("unreachable") }
func (*lazyObject) order() uint32 { panic("unreachable") }
-func (*lazyObject) color() color { panic("unreachable") }
func (*lazyObject) setType(Type) { panic("unreachable") }
func (*lazyObject) setOrder(uint32) { panic("unreachable") }
-func (*lazyObject) setColor(color color) { panic("unreachable") }
func (*lazyObject) setParent(*Scope) { panic("unreachable") }
func (*lazyObject) sameId(*Package, string, bool) bool { panic("unreachable") }
func (*lazyObject) scopePos() syntax.Pos { panic("unreachable") }
diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go
index 092e82318a..f206c12fc3 100644
--- a/src/cmd/compile/internal/types2/sizeof_test.go
+++ b/src/cmd/compile/internal/types2/sizeof_test.go
@@ -36,14 +36,14 @@ func TestSizeof(t *testing.T) {
{term{}, 12, 24},
// Objects
- {PkgName{}, 60, 96},
- {Const{}, 64, 104},
- {TypeName{}, 56, 88},
- {Var{}, 64, 104},
- {Func{}, 64, 104},
- {Label{}, 60, 96},
- {Builtin{}, 60, 96},
- {Nil{}, 56, 88},
+ {PkgName{}, 56, 96},
+ {Const{}, 60, 104},
+ {TypeName{}, 52, 88},
+ {Var{}, 60, 104},
+ {Func{}, 60, 104},
+ {Label{}, 56, 96},
+ {Builtin{}, 56, 96},
+ {Nil{}, 52, 88},
// Misc
{Scope{}, 60, 104},
diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go
index 8601ce6277..303f782ac4 100644
--- a/src/cmd/compile/internal/types2/typexpr.go
+++ b/src/cmd/compile/internal/types2/typexpr.go
@@ -16,7 +16,7 @@ import (
// ident type-checks identifier e and initializes x with the value or type of e.
// If an error occurred, x.mode is set to invalid.
-// For the meaning of def, see Checker.definedType, below.
+// For the meaning of def, see Checker.declaredType, below.
// If wantType is set, the identifier e is expected to denote a type.
func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType bool) {
x.mode = invalid
@@ -149,14 +149,14 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
// typ type-checks the type expression e and returns its type, or Typ[Invalid].
// The type must not be an (uninstantiated) generic type.
func (check *Checker) typ(e syntax.Expr) Type {
- return check.definedType(e, nil)
+ return check.declaredType(e, nil)
}
// varType type-checks the type expression e and returns its type, or Typ[Invalid].
// The type must not be an (uninstantiated) generic type and it must not be a
// constraint interface.
func (check *Checker) varType(e syntax.Expr) Type {
- typ := check.definedType(e, nil)
+ typ := check.declaredType(e, nil)
check.validVarType(e, typ)
return typ
}
@@ -187,11 +187,11 @@ func (check *Checker) validVarType(e syntax.Expr, typ Type) {
}).describef(e, "check var type %s", typ)
}
-// definedType is like typ but also accepts a type name def.
-// If def != nil, e is the type specification for the type named def, declared
-// in a type declaration, and def.typ.underlying will be set to the type of e
-// before any components of e are type-checked.
-func (check *Checker) definedType(e syntax.Expr, def *TypeName) Type {
+// declaredType is like typ but also accepts a type name def.
+// If def != nil, e is the type specification for the [Alias] or [Named] type
+// named def, and def.typ.fromRHS will be set to the [Type] of e immediately
+// after its creation.
+func (check *Checker) declaredType(e syntax.Expr, def *TypeName) Type {
typ := check.typInternal(e, def)
assert(isTyped(typ))
if isGeneric(typ) {
@@ -230,7 +230,7 @@ func goTypeName(typ Type) string {
}
// typInternal drives type checking of types.
-// Must only be called by definedType or genericType.
+// Must only be called by declaredType or genericType.
func (check *Checker) typInternal(e0 syntax.Expr, def *TypeName) (T Type) {
if check.conf.Trace {
check.trace(e0.Pos(), "-- type %s", e0)
@@ -296,7 +296,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *TypeName) (T Type) {
case *syntax.ParenExpr:
// Generic types must be instantiated before they can be used in any form.
// Consequently, generic types cannot be parenthesized.
- return check.definedType(e.X, def)
+ return check.declaredType(e.X, def)
case *syntax.ArrayType:
typ := new(Array)
diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go
index 332cd174f9..1ecef97d51 100644
--- a/src/cmd/compile/internal/types2/universe.go
+++ b/src/cmd/compile/internal/types2/universe.go
@@ -98,7 +98,6 @@ func defPredeclaredTypes() {
// interface.
{
universeAnyNoAlias = NewTypeName(nopos, nil, "any", &Interface{complete: true, tset: &topTypeSet})
- universeAnyNoAlias.setColor(black)
// ensure that the any TypeName reports a consistent Parent, after
// hijacking Universe.Lookup with gotypesalias=0.
universeAnyNoAlias.setParent(Universe)
@@ -107,7 +106,6 @@ func defPredeclaredTypes() {
// into the Universe, but we lean toward the future and insert the Alias
// representation.
universeAnyAlias = NewTypeName(nopos, nil, "any", nil)
- universeAnyAlias.setColor(black)
_ = NewAlias(universeAnyAlias, universeAnyNoAlias.Type().Underlying()) // Link TypeName and Alias
def(universeAnyAlias)
}
@@ -115,7 +113,6 @@ func defPredeclaredTypes() {
// type error interface{ Error() string }
{
obj := NewTypeName(nopos, nil, "error", nil)
- obj.setColor(black)
typ := (*Checker)(nil).newNamed(obj, nil, nil)
// error.Error() string
@@ -136,7 +133,6 @@ func defPredeclaredTypes() {
// type comparable interface{} // marked as comparable
{
obj := NewTypeName(nopos, nil, "comparable", nil)
- obj.setColor(black)
typ := (*Checker)(nil).newNamed(obj, nil, nil)
// interface{} // marked as comparable
@@ -165,7 +161,7 @@ func defPredeclaredConsts() {
}
func defPredeclaredNil() {
- def(&Nil{object{name: "nil", typ: Typ[UntypedNil], color_: black}})
+ def(&Nil{object{name: "nil", typ: Typ[UntypedNil]}})
}
// A builtinId is the id of a builtin function.
@@ -289,7 +285,7 @@ func init() {
// a scope. Objects with exported names are inserted in the unsafe package
// scope; other objects are inserted in the universe scope.
func def(obj Object) {
- assert(obj.color() == black)
+ assert(obj.Type() != nil)
name := obj.Name()
if strings.Contains(name, " ") {
return // nothing to do
diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index 989ae0a1db..2794671c73 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -351,6 +351,11 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
case ir.OMETHVALUE:
return walkMethodValue(n.(*ir.SelectorExpr), init)
+
+ case ir.OMOVE2HEAP:
+ n := n.(*ir.MoveToHeapExpr)
+ n.Slice = walkExpr(n.Slice, init)
+ return n
}
// No return! Each case must return (or panic),
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
index 42d510c34f..090b2c943f 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -6,12 +6,12 @@ require (
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5
golang.org/x/arch v0.22.1-0.20251016010524-fea4a9ec4938
golang.org/x/build v0.0.0-20250806225920-b7c66c047964
- golang.org/x/mod v0.29.0
- golang.org/x/sync v0.17.0
- golang.org/x/sys v0.37.0
- golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8
+ golang.org/x/mod v0.30.1-0.20251114215501-3f03020ad526
+ golang.org/x/sync v0.18.0
+ golang.org/x/sys v0.38.0
+ golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54
golang.org/x/term v0.34.0
- golang.org/x/tools v0.38.1-0.20251015192825-7d9453ccc0f5
+ golang.org/x/tools v0.39.1-0.20251114194111-59ff18ce4883
)
require (
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
index 0a09e6e401..e4955f224b 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -10,19 +10,19 @@ golang.org/x/arch v0.22.1-0.20251016010524-fea4a9ec4938 h1:VJ182b/ajNehMFRltVfCh
golang.org/x/arch v0.22.1-0.20251016010524-fea4a9ec4938/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/build v0.0.0-20250806225920-b7c66c047964 h1:yRs1K51GKq7hsIO+YHJ8LsslrvwFceNPIv0tYjpcBd0=
golang.org/x/build v0.0.0-20250806225920-b7c66c047964/go.mod h1:i9Vx7+aOQUpYJRxSO+OpRStVBCVL/9ccI51xblWm5WY=
-golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
-golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
-golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
-golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
-golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
-golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
+golang.org/x/mod v0.30.1-0.20251114215501-3f03020ad526 h1:LPpBM4CGUFMC47OqgAr2YIUxEUjH1Ur+D3KR/1LiuuQ=
+golang.org/x/mod v0.30.1-0.20251114215501-3f03020ad526/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
+golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
+golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
+golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=
+golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
-golang.org/x/tools v0.38.1-0.20251015192825-7d9453ccc0f5 h1:cz7f45KGWAtyIrz6bm45Gc+lw8beIxBSW3EQh4Bwbg4=
-golang.org/x/tools v0.38.1-0.20251015192825-7d9453ccc0f5/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
+golang.org/x/tools v0.39.1-0.20251114194111-59ff18ce4883 h1:aeO0AW8d+a+5+hNQx9f4J5egD89zftrY2x42KGQjLzI=
+golang.org/x/tools v0.39.1-0.20251114194111-59ff18ce4883/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
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/go/internal/cache/hash.go b/src/cmd/go/internal/cache/hash.go
index 4f79c31500..27d275644a 100644
--- a/src/cmd/go/internal/cache/hash.go
+++ b/src/cmd/go/internal/cache/hash.go
@@ -51,6 +51,9 @@ func stripExperiment(version string) string {
if i := strings.Index(version, " X:"); i >= 0 {
return version[:i]
}
+ if i := strings.Index(version, "-X:"); i >= 0 {
+ return version[:i]
+ }
return version
}
diff --git a/src/cmd/go/internal/vcweb/script.go b/src/cmd/go/internal/vcweb/script.go
index 0856c40677..8fa00b2775 100644
--- a/src/cmd/go/internal/vcweb/script.go
+++ b/src/cmd/go/internal/vcweb/script.go
@@ -44,7 +44,7 @@ func newScriptEngine() *script.Engine {
return script.OnceCondition(summary, func() (bool, error) { return f(), nil })
}
add("bzr", lazyBool("the 'bzr' executable exists and provides the standard CLI", hasWorkingBzr))
- add("git-min-vers", script.PrefixCondition("<suffix> indicates a minimum git version", hasAtLeastGitVersion))
+ add("git-sha256", script.OnceCondition("the local 'git' version is recent enough to support sha256 object/commit hashes", gitSupportsSHA256))
interrupt := func(cmd *exec.Cmd) error { return cmd.Process.Signal(os.Interrupt) }
gracePeriod := 30 * time.Second // arbitrary
@@ -412,10 +412,14 @@ func gitVersion() (string, error) {
return "v" + string(matches[1]), nil
}
-func hasAtLeastGitVersion(s *script.State, minVers string) (bool, error) {
+func hasAtLeastGitVersion(minVers string) (bool, error) {
gitVers, gitVersErr := gitVersion()
if gitVersErr != nil {
return false, gitVersErr
}
return semver.Compare(minVers, gitVers) <= 0, nil
}
+
+func gitSupportsSHA256() (bool, error) {
+ return hasAtLeastGitVersion("v2.29")
+}
diff --git a/src/cmd/go/scriptconds_test.go b/src/cmd/go/scriptconds_test.go
index c87c60ad33..4d7a9ac54b 100644
--- a/src/cmd/go/scriptconds_test.go
+++ b/src/cmd/go/scriptconds_test.go
@@ -44,7 +44,7 @@ func scriptConditions(t *testing.T) map[string]script.Cond {
add("case-sensitive", script.OnceCondition("$WORK filesystem is case-sensitive", isCaseSensitive))
add("cc", script.PrefixCondition("go env CC = <suffix> (ignoring the go/env file)", ccIs))
add("git", lazyBool("the 'git' executable exists and provides the standard CLI", hasWorkingGit))
- add("git-min-vers", script.PrefixCondition("<suffix> indicates a minimum git version", hasAtLeastGitVersion))
+ add("git-sha256", script.OnceCondition("the local 'git' version is recent enough to support sha256 object/commit hashes", gitSupportsSHA256))
add("net", script.PrefixCondition("can connect to external network host <suffix>", hasNet))
add("trimpath", script.OnceCondition("test binary was built with -trimpath", isTrimpath))
@@ -171,7 +171,7 @@ func gitVersion() (string, error) {
return "v" + string(matches[1]), nil
}
-func hasAtLeastGitVersion(s *script.State, minVers string) (bool, error) {
+func hasAtLeastGitVersion(minVers string) (bool, error) {
gitVers, gitVersErr := gitVersion()
if gitVersErr != nil {
return false, gitVersErr
@@ -179,6 +179,10 @@ func hasAtLeastGitVersion(s *script.State, minVers string) (bool, error) {
return semver.Compare(minVers, gitVers) <= 0, nil
}
+func gitSupportsSHA256() (bool, error) {
+ return hasAtLeastGitVersion("v2.29")
+}
+
func hasWorkingBzr() bool {
bzr, err := exec.LookPath("bzr")
if err != nil {
diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README
index d4f4c47af7..2b5ab6948b 100644
--- a/src/cmd/go/testdata/script/README
+++ b/src/cmd/go/testdata/script/README
@@ -399,8 +399,8 @@ The available conditions are:
GOOS/GOARCH supports -fuzz with instrumentation
[git]
the 'git' executable exists and provides the standard CLI
-[git-min-vers:*]
- <suffix> indicates a minimum git version
+[git-sha256]
+ the local 'git' version is recent enough to support sha256 object/commit hashes
[go-builder]
GO_BUILDER_NAME is non-empty
[link]
diff --git a/src/cmd/go/testdata/script/build_git_sha256_go_get_branch.txt b/src/cmd/go/testdata/script/build_git_sha256_go_get_branch.txt
index 0773e08ea5..1e71e25f11 100644
--- a/src/cmd/go/testdata/script/build_git_sha256_go_get_branch.txt
+++ b/src/cmd/go/testdata/script/build_git_sha256_go_get_branch.txt
@@ -1,6 +1,6 @@
[short] skip
[!git] skip
-[!git-min-vers:v2.29] skip
+[!git-sha256] skip
env GOPRIVATE=vcs-test.golang.org
diff --git a/src/cmd/go/testdata/script/build_git_sha256_moddep.txt b/src/cmd/go/testdata/script/build_git_sha256_moddep.txt
index 21a296bd3d..7048e8f2e4 100644
--- a/src/cmd/go/testdata/script/build_git_sha256_moddep.txt
+++ b/src/cmd/go/testdata/script/build_git_sha256_moddep.txt
@@ -1,6 +1,6 @@
[short] skip
[!git] skip
-[!git-min-vers:v2.29] skip
+[!git-sha256] skip
env GOPRIVATE=vcs-test.golang.org
diff --git a/src/cmd/go/testdata/script/mod_download_git_bareRepository_sha256.txt b/src/cmd/go/testdata/script/mod_download_git_bareRepository_sha256.txt
index df772f5c4b..2f391e200e 100644
--- a/src/cmd/go/testdata/script/mod_download_git_bareRepository_sha256.txt
+++ b/src/cmd/go/testdata/script/mod_download_git_bareRepository_sha256.txt
@@ -1,6 +1,6 @@
[short] skip
[!git] skip
-[!git-min-vers:v2.29] skip
+[!git-sha256] skip
# This is a git sha256-mode copy of mod_download_git_bareRepository
diff --git a/src/cmd/go/testdata/script/mod_get_direct.txt b/src/cmd/go/testdata/script/mod_get_direct.txt
index 02b10ab6fd..2c89576446 100644
--- a/src/cmd/go/testdata/script/mod_get_direct.txt
+++ b/src/cmd/go/testdata/script/mod_get_direct.txt
@@ -2,14 +2,14 @@
# 'GOPROXY=direct go get golang.org/x/tools/gopls@master' did not correctly
# resolve the pseudo-version for its dependency on golang.org/x/tools.
-[!net:cloud.google.com] skip
+[short] skip
[!git] skip
env GO111MODULE=on
env GOPROXY=direct
env GOSUMDB=off
-go list -m cloud.google.com/go@main
+go list -m vcs-test.golang.org/git/tagtests.git@master
! stdout 'v0.0.0-'
-- go.mod --
diff --git a/src/cmd/go/testdata/vcstest/git/gitrepo-sha256.txt b/src/cmd/go/testdata/vcstest/git/gitrepo-sha256.txt
index 15068a249e..a08e2949d3 100644
--- a/src/cmd/go/testdata/vcstest/git/gitrepo-sha256.txt
+++ b/src/cmd/go/testdata/vcstest/git/gitrepo-sha256.txt
@@ -1,4 +1,4 @@
-[!git-min-vers:v2.29] skip
+[!git-sha256] skip
handle git
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 85dca33d27..c70c1d9438 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -1153,36 +1153,37 @@ type Func interface {
// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.
type Link struct {
- Headtype objabi.HeadType
- Arch *LinkArch
- Debugasm int
- Debugvlog bool
- Debugpcln string
- Flag_shared bool
- Flag_dynlink bool
- Flag_linkshared bool
- Flag_optimize bool
- Flag_locationlists bool
- Flag_noRefName bool // do not include referenced symbol names in object file
- Retpoline bool // emit use of retpoline stubs for indirect jmp/call
- Flag_maymorestack string // If not "", call this function before stack checks
- Bso *bufio.Writer
- Pathname string
- Pkgpath string // the current package's import path
- hashmu sync.Mutex // protects hash, funchash
- hash map[string]*LSym // name -> sym mapping
- funchash map[string]*LSym // name -> sym mapping for ABIInternal syms
- statichash map[string]*LSym // name -> sym mapping for static syms
- PosTable src.PosTable
- InlTree InlTree // global inlining tree used by gc/inl.go
- DwFixups *DwarfFixupTable
- DwTextCount int
- Imports []goobj.ImportedPkg
- DiagFunc func(string, ...any)
- DiagFlush func()
- DebugInfo func(ctxt *Link, fn *LSym, info *LSym, curfn Func) ([]dwarf.Scope, dwarf.InlCalls)
- GenAbstractFunc func(fn *LSym)
- Errors int
+ Headtype objabi.HeadType
+ Arch *LinkArch
+ CompressInstructions bool // use compressed instructions where possible (if supported by architecture)
+ Debugasm int
+ Debugvlog bool
+ Debugpcln string
+ Flag_shared bool
+ Flag_dynlink bool
+ Flag_linkshared bool
+ Flag_optimize bool
+ Flag_locationlists bool
+ Flag_noRefName bool // do not include referenced symbol names in object file
+ Retpoline bool // emit use of retpoline stubs for indirect jmp/call
+ Flag_maymorestack string // If not "", call this function before stack checks
+ Bso *bufio.Writer
+ Pathname string
+ Pkgpath string // the current package's import path
+ hashmu sync.Mutex // protects hash, funchash
+ hash map[string]*LSym // name -> sym mapping
+ funchash map[string]*LSym // name -> sym mapping for ABIInternal syms
+ statichash map[string]*LSym // name -> sym mapping for static syms
+ PosTable src.PosTable
+ InlTree InlTree // global inlining tree used by gc/inl.go
+ DwFixups *DwarfFixupTable
+ DwTextCount int
+ Imports []goobj.ImportedPkg
+ DiagFunc func(string, ...any)
+ DiagFlush func()
+ DebugInfo func(ctxt *Link, fn *LSym, info *LSym, curfn Func) ([]dwarf.Scope, dwarf.InlCalls)
+ GenAbstractFunc func(fn *LSym)
+ Errors int
InParallel bool // parallel backend phase in effect
UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges
diff --git a/src/cmd/internal/obj/loong64/a.out.go b/src/cmd/internal/obj/loong64/a.out.go
index 73f145df14..5b8bffc9f1 100644
--- a/src/cmd/internal/obj/loong64/a.out.go
+++ b/src/cmd/internal/obj/loong64/a.out.go
@@ -589,6 +589,10 @@ const (
AORN
AANDN
+ // 2.2.1.12
+ AMULWVW
+ AMULWVWU
+
// 2.2.7. Atomic Memory Access Instructions
AAMSWAPB
AAMSWAPH
diff --git a/src/cmd/internal/obj/loong64/anames.go b/src/cmd/internal/obj/loong64/anames.go
index ab85c52a21..1749b43bf6 100644
--- a/src/cmd/internal/obj/loong64/anames.go
+++ b/src/cmd/internal/obj/loong64/anames.go
@@ -131,6 +131,8 @@ var Anames = []string{
"ALSLV",
"ORN",
"ANDN",
+ "MULWVW",
+ "MULWVWU",
"AMSWAPB",
"AMSWAPH",
"AMSWAPW",
diff --git a/src/cmd/internal/obj/loong64/asm.go b/src/cmd/internal/obj/loong64/asm.go
index 38b075d77e..b35e49a1b6 100644
--- a/src/cmd/internal/obj/loong64/asm.go
+++ b/src/cmd/internal/obj/loong64/asm.go
@@ -1503,6 +1503,8 @@ func buildop(ctxt *obj.Link) {
opset(AREMU, r0)
opset(ADIV, r0)
opset(ADIVU, r0)
+ opset(AMULWVW, r0)
+ opset(AMULWVWU, r0)
case AMULV:
opset(AMULVU, r0)
@@ -3230,6 +3232,10 @@ func (c *ctxt0) oprrr(a obj.As) uint32 {
return 0x3c << 15 // mulh.d
case AMULHVU:
return 0x3d << 15 // mulhu.d
+ case AMULWVW:
+ return 0x3e << 15 // mulw.d.w
+ case AMULWVWU:
+ return 0x3f << 15 // mulw.d.wu
case ADIV:
return 0x40 << 15 // div.w
case ADIVU:
diff --git a/src/cmd/internal/obj/riscv/asm_test.go b/src/cmd/internal/obj/riscv/asm_test.go
index f40e57fa64..5b50d1533a 100644
--- a/src/cmd/internal/obj/riscv/asm_test.go
+++ b/src/cmd/internal/obj/riscv/asm_test.go
@@ -11,8 +11,8 @@ import (
"os"
"os/exec"
"path/filepath"
+ "regexp"
"runtime"
- "strings"
"testing"
)
@@ -48,10 +48,10 @@ func genLargeBranch(buf *bytes.Buffer) {
fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
fmt.Fprintln(buf, "BEQ X0, X0, label")
for i := 0; i < 1<<19; i++ {
- fmt.Fprintln(buf, "ADD $0, X0, X0")
+ fmt.Fprintln(buf, "ADD $0, X5, X0")
}
fmt.Fprintln(buf, "label:")
- fmt.Fprintln(buf, "ADD $0, X0, X0")
+ fmt.Fprintln(buf, "ADD $0, X5, X0")
}
// TestLargeCall generates a large function (>1MB of text) with a call to
@@ -112,11 +112,11 @@ func genLargeCall(buf *bytes.Buffer) {
fmt.Fprintln(buf, "TEXT ·x(SB),0,$0-0")
fmt.Fprintln(buf, "CALL ·y(SB)")
for i := 0; i < 1<<19; i++ {
- fmt.Fprintln(buf, "ADD $0, X0, X0")
+ fmt.Fprintln(buf, "ADD $0, X5, X0")
}
fmt.Fprintln(buf, "RET")
fmt.Fprintln(buf, "TEXT ·y(SB),0,$0-0")
- fmt.Fprintln(buf, "ADD $0, X0, X0")
+ fmt.Fprintln(buf, "ADD $0, X5, X0")
fmt.Fprintln(buf, "RET")
}
@@ -301,9 +301,9 @@ TEXT _stub(SB),$0-0
// FENCE
// NOP
// FENCE
- // RET
- want := "0f 00 f0 0f 13 00 00 00 0f 00 f0 0f 67 80 00 00"
- if !strings.Contains(string(out), want) {
+ // RET (CJALR or JALR)
+ want := regexp.MustCompile("0x0000 0f 00 f0 0f 13 00 00 00 0f 00 f0 0f (82 80|67 80 00 00) ")
+ if !want.Match(out) {
t.Errorf("PCALIGN test failed - got %s\nwant %s", out, want)
}
}
diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go
index 60174a0b3a..a91395dd38 100644
--- a/src/cmd/internal/obj/riscv/cpu.go
+++ b/src/cmd/internal/obj/riscv/cpu.go
@@ -326,6 +326,9 @@ const (
NEED_GOT_PCREL_ITYPE_RELOC
)
+const NEED_RELOC = NEED_JAL_RELOC | NEED_CALL_RELOC | NEED_PCREL_ITYPE_RELOC |
+ NEED_PCREL_STYPE_RELOC | NEED_GOT_PCREL_ITYPE_RELOC
+
// RISC-V mnemonics, as defined in the "opcodes" and "opcodes-pseudo" files
// at https://github.com/riscv/riscv-opcodes.
//
diff --git a/src/cmd/internal/obj/riscv/doc.go b/src/cmd/internal/obj/riscv/doc.go
new file mode 100644
index 0000000000..365bedd299
--- /dev/null
+++ b/src/cmd/internal/obj/riscv/doc.go
@@ -0,0 +1,297 @@
+// Copyright 2025 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 riscv implements the riscv64 assembler.
+
+# Register naming
+
+The integer registers are named X0 through to X31, however X4 must be accessed
+through its RISC-V ABI name, TP, and X27, which holds a pointer to the Go
+routine structure, must be referred to as g. Additionally, when building in
+shared mode, X3 is unavailable and must be accessed via its RISC-V ABI name,
+GP.
+
+The floating-point registers are named F0 through to F31.
+
+The vector registers are named V0 through to V31.
+
+Both integer and floating-point registers can be referred to by their RISC-V
+ABI names, e.g., A0 or FT0, with the exception that X27 cannot be referred to
+by its RISC-V ABI name, S11. It must be referred to as g.
+
+Some of the integer registers are used by the Go runtime and assembler - X26 is
+the closure pointer, X27 points to the Go routine structure and X31 is a
+temporary register used by the Go assembler. Use of X31 should be avoided in
+hand written assembly code as its value could be altered by the instruction
+sequences emitted by the assembler.
+
+# Instruction naming
+
+Many RISC-V instructions contain one or more suffixes in their names. In the
+[RISC-V ISA Manual] these suffixes are separated from themselves and the
+name of the instruction mnemonic with a dot ('.'). In the Go assembler, the
+separators are omitted and the suffixes are written in upper case.
+
+Example:
+
+ FMVWX <=> fmv.w.x
+
+# Rounding modes
+
+The Go toolchain does not set the FCSR register and requires the desired
+rounding mode to be explicitly encoded within floating-point instructions.
+The syntax the Go assembler uses to specify the rounding modes differs
+from the syntax in the RISC-V specifications. In the [RISC-V ISA Manual]
+the rounding mode is given as an extra operand at the end of an
+assembly language instruction. In the Go assembler, the rounding modes are
+converted to uppercase and follow the instruction mnemonic from which they
+are separated with a dot ('.').
+
+Example:
+
+ FCVTLUS.RNE F0, X5 <=> fcvt.lu.s x5, f0, rne
+
+RTZ is assumed if the rounding mode is omitted.
+
+# RISC-V extensions
+
+By default the Go compiler targets the [rva20u64] profile. This profile mandates
+all the general RISC-V instructions, allowing Go to use integer, multiplication,
+division, floating-point and atomic instructions without having to
+perform compile time or runtime checks to verify that their use is appropriate
+for the target hardware. All widely available riscv64 devices support at least
+[rva20u64]. The Go toolchain can be instructed to target later RISC-V profiles,
+including, [rva22u64] and [rva23u64], via the GORISCV64 environment variable.
+Instructions that are provided by newer profiles cannot typically be used in
+handwritten assembly code without compile time guards (or runtime checks)
+that ensure they are hardware supported.
+
+The file asm_riscv64.h defines macros for each RISC-V extension that is enabled
+by setting the GORISCV64 environment variable to a value other than [rva20u64].
+For example, if GORISCV64=rva22u64 the macros hasZba, hasZbb and hasZbs will be
+defined. If GORISCV64=rva23u64 hasV will be defined in addition to hasZba,
+hasZbb and hasZbs. These macros can be used to determine whether it's safe
+to use an instruction in hand-written assembly.
+
+It is not always necessary to include asm_riscv64.h and use #ifdefs in your
+code to safely take advantage of instructions present in the [rva22u64]
+profile. In some cases the assembler can generate [rva20u64] compatible code
+even when an [rva22u64] instruction is used in an assembly source file. When
+GORISCV64=rva20u64 the assembler will synthesize certain [rva22u64]
+instructions, e.g., ANDN, using multiple [rva20u64] instructions. Instructions
+such as ANDN can then be freely used in assembly code without checking to see
+whether the instruction is supported by the target profile. When building a
+source file containing the ANDN instruction with GORISCV64=rva22u64 the
+assembler will emit the Zbb ANDN instruction directly. When building the same
+source file with GORISCV64=rva20u64 the assembler will emit multiple [rva20u64]
+instructions to synthesize ANDN.
+
+The assembler will also use [rva22u64] instructions to implement the zero and
+sign extension instructions, e.g., MOVB and MOVHU, when GORISCV64=rva22u64 or
+greater.
+
+The instructions not implemented in the default profile ([rva20u64]) that can
+be safely used in assembly code without compile time checks are:
+
+ - ANDN
+ - MAX
+ - MAXU
+ - MIN
+ - MINU
+ - MOVB
+ - MOVH
+ - MOVHU
+ - MOVWU
+ - ORN
+ - ROL
+ - ROLW
+ - ROR
+ - RORI
+ - RORIW
+ - RORW
+ - XNOR
+
+# Operand ordering
+
+The ordering used for instruction operands in the Go assembler differs from the
+ordering defined in the [RISC-V ISA Manual].
+
+1. R-Type instructions
+
+R-Type instructions are written in the reverse order to that given in the
+[RISC-V ISA Manual], with the register order being rs2, rs1, rd.
+
+Examples:
+
+ ADD X10, X11, X12 <=> add x12, x11, x10
+ FADDD F10, F11, F12 <=> fadd.d f12, f11, f10
+
+2. I-Type arithmetic instructions
+
+I-Type arithmetic instructions (not loads, fences, ebreak, ecall) use the same
+ordering as the R-Type instructions, typically, imm12, rs1, rd.
+
+Examples:
+
+ ADDI $1, X11, X12 <=> add x12, x11, 1
+ SLTI $1, X11, X12 <=> slti x12, x11, 1
+
+3. Loads and Stores
+
+Load instructions are written with the source operand (whether it be a register
+or a memory address), first followed by the destination operand.
+
+Examples:
+
+ MOV 16(X2), X10 <=> ld x10, 16(x2)
+ MOV X10, (X2) <=> sd x10, 0(x2)
+
+4. Branch instructions
+
+The branch instructions use the same operand ordering as is given in the
+[RISC-V ISA Manual], e.g., rs1, rs2, label.
+
+Example:
+
+ BLT X12, X23, loop1 <=> blt x12, x23, loop1
+
+BLT X12, X23, label will jump to label if X12 < X23. Note this is not the
+same ordering as is used for the SLT instructions.
+
+5. FMA instructions
+
+The Go assembler uses a different ordering for the RISC-V FMA operands to
+the ordering given in the [RISC-V ISA Manual]. The operands are rotated one
+place to the left, so that the destination operand comes last.
+
+Example:
+
+ FMADDS F1, F2, F3, F4 <=> fmadd.s f4, f1, f2, f3
+
+6. AMO instructions
+
+The ordering used for the AMO operations is rs2, rs1, rd, i.e., the operands
+as specified in the [RISC-V ISA Manual] are rotated one place to the left.
+
+Example:
+
+ AMOSWAPW X5, (X6), X7 <=> amoswap.w x7, x5, (x6)
+
+7. Vector instructions
+
+The VSETVLI instruction uses the same symbolic names as the [RISC-V ISA Manual]
+to represent the components of vtype, with the exception
+that they are written in upper case. The ordering of the operands in the Go
+assembler differs from the [RISC-V ISA Manual] in that the operands are
+rotated one place to the left so that the destination register, the register
+that holds the new vl, is the last operand.
+
+Example:
+
+ VSETVLI X10, E8, M1, TU, MU, X12 <=> vsetvli x12, x10, e8, m1, tu, mu
+
+Vector load and store instructions follow the pattern set by scalar loads and
+stores, i.e., the source is always the first operand and the destination the
+last. However, the ordering of the operands of these instructions is
+complicated by the optional mask register and, in some cases, the use of an
+additional stride or index register. In the Go assembler the index and stride
+registers appear as the second operand in indexed or strided loads and stores,
+while the mask register, if present, is always the penultimate operand.
+
+Examples:
+
+ VLE8V (X10), V3 <=> vle8.v v3, (x10)
+ VSE8V V3, (X10) <=> vse8.v v3, (x10)
+ VLE8V (X10), V0, V3 <=> vle8.v v3, (x10), v0.t
+ VSE8V V3, V0, (X10) <=> vse8.v v3, (x10), v0.t
+ VLSE8V (X10), X11, V3 <=> vlse8.v v3, (x10), x11
+ VSSE8V V3, X11, (X10) <=> vsse8.v v3, (x10), x11
+ VLSE8V (X10), X11, V0, V3 <=> vlse8.v v3, (x10), x11, v0.t
+ VSSE8V V3, X11, V0, (X10) <=> vsse8.v v3, (x10), x11, v0.t
+ VLUXEI8V (X10), V2, V3 <=> vluxei8.v v3, (x10), v2
+ VSUXEI8V V3, V2, (X10) <=> vsuxei8.v v3, (x10), v2
+ VLUXEI8V (X10), V2, V0, V3 <=> vluxei8.v v3, (x10), v2, v0.t
+ VSUXEI8V V3, V2, V0, (X10) <=> vsuxei8.v v3, (x10), v2, v0.t
+ VL1RE8V (X10), V3 <=> vl1re8.v v3, (x10)
+ VS1RV V3, (X11) <=> vs1r.v v3, (x11)
+
+The ordering of operands for two and three argument vector arithmetic instructions is
+reversed in the Go assembler.
+
+Examples:
+
+ VMVVV V2, V3 <=> vmv.v.v v3, v2
+ VADDVV V1, V2, V3 <=> vadd.vv v3, v2, v1
+ VADDVX X10, V2, V3 <=> vadd.vx v3, v2, x10
+ VMADCVI $15, V2, V3 <=> vmadc.vi v3, v2, 15
+
+The mask register, when specified, is always the penultimate operand in a vector
+arithmetic instruction, appearing before the destination register.
+
+Examples:
+
+ VANDVV V1, V2, V0, V3 <=> vand.vv v3, v2, v1, v0.t
+
+# Ternary instructions
+
+The Go assembler allows the second operand to be omitted from most ternary
+instructions if it matches the third (destination) operand.
+
+Examples:
+
+ ADD X10, X12, X12 <=> ADD X10, X12
+ ANDI $3, X12, X12 <=> ANDI $3, X12
+
+The use of this abbreviated syntax is encouraged.
+
+# Ordering of atomic instructions
+
+It is not possible to specify the ordering bits in the FENCE, LR, SC or AMO
+instructions. The FENCE instruction is always emitted as a full fence, the
+acquire and release bits are always set for the AMO instructions, the acquire
+bit is always set for the LR instructions while the release bit is set for
+the SC instructions.
+
+# Immediate operands
+
+In many cases, where an R-Type instruction has a corresponding I-Type
+instruction, the R-Type mnemonic can be used in place of the I-Type mnemonic.
+The assembler assumes that the immediate form of the instruction was intended
+when the first operand is given as an immediate value rather than a register.
+
+Example:
+
+ AND $3, X12, X13 <=> ANDI $3, X12, X13
+
+# Integer constant materialization
+
+The MOV instruction can be used to set a register to the value of any 64 bit
+constant literal. The way this is achieved by the assembler varies depending
+on the value of the constant. Where possible the assembler will synthesize the
+constant using one or more RISC-V arithmetic instructions. If it is unable
+to easily materialize the constant it will load the 64 bit literal from memory.
+
+A 32 bit constant literal can be specified as an argument to ADDI, ANDI, ORI and
+XORI. If the specified literal does not fit into 12 bits the assembler will
+generate extra instructions to synthesize it.
+
+Integer constants provided as operands to all other instructions must fit into
+the number of bits allowed by the instructions' encodings for immediate values.
+Otherwise, an error will be generated.
+
+# Floating point constant materialization
+
+The MOVF and MOVD instructions can be used to set a register to the value
+of any 32 bit or 64 bit floating point constant literal, respectively. Unless
+the constant literal is 0.0, MOVF and MOVD will be encoded as FLW and FLD
+instructions that load the constant from a location within the program's
+binary.
+
+[RISC-V ISA Manual]: https://github.com/riscv/riscv-isa-manual
+[rva20u64]: https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc#51-rva20u64-profile
+[rva22u64]: https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc#rva22u64-profile
+[rva23u64]: https://github.com/riscv/riscv-profiles/blob/main/src/rva23-profile.adoc#rva23u64-profile
+*/
+package riscv
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 3deab34d31..043be17c07 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -414,10 +414,10 @@ func containsCall(sym *obj.LSym) bool {
// setPCs sets the Pc field in all instructions reachable from p.
// It uses pc as the initial value and returns the next available pc.
-func setPCs(p *obj.Prog, pc int64) int64 {
+func setPCs(p *obj.Prog, pc int64, compress bool) int64 {
for ; p != nil; p = p.Link {
p.Pc = pc
- for _, ins := range instructionsForProg(p) {
+ for _, ins := range instructionsForProg(p, compress) {
pc += int64(ins.length())
}
@@ -671,7 +671,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// a fixed point will be reached). No attempt to handle functions > 2GiB.
for {
big, rescan := false, false
- maxPC := setPCs(cursym.Func().Text, 0)
+ maxPC := setPCs(cursym.Func().Text, 0, ctxt.CompressInstructions)
if maxPC+maxTrampSize > (1 << 20) {
big = true
}
@@ -801,7 +801,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// Validate all instructions - this provides nice error messages.
for p := cursym.Func().Text; p != nil; p = p.Link {
- for _, ins := range instructionsForProg(p) {
+ for _, ins := range instructionsForProg(p, ctxt.CompressInstructions) {
ins.validate(ctxt)
}
}
@@ -1141,6 +1141,14 @@ func wantImmU(ctxt *obj.Link, ins *instruction, imm int64, nbits uint) {
}
}
+func isScaledImmI(imm int64, nbits uint, scale int64) bool {
+ return immFits(imm, nbits, true) == nil && imm%scale == 0
+}
+
+func isScaledImmU(imm int64, nbits uint, scale int64) bool {
+ return immFits(imm, nbits, false) == nil && imm%scale == 0
+}
+
func wantScaledImm(ctxt *obj.Link, ins *instruction, imm int64, nbits uint, scale int64, signed bool) {
if err := immFits(imm, nbits, signed); err != nil {
ctxt.Diag("%v: %v", ins, err)
@@ -1180,6 +1188,10 @@ func wantIntReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) {
wantReg(ctxt, ins, pos, "integer", r, REG_X0, REG_X31)
}
+func isIntPrimeReg(r uint32) bool {
+ return r >= REG_X8 && r <= REG_X15
+}
+
// wantIntPrimeReg checks that r is an integer register that can be used
// in a prime register field of a compressed instruction.
func wantIntPrimeReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) {
@@ -1191,6 +1203,10 @@ func wantFloatReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) {
wantReg(ctxt, ins, pos, "float", r, REG_F0, REG_F31)
}
+func isFloatPrimeReg(r uint32) bool {
+ return r >= REG_F8 && r <= REG_F15
+}
+
// wantFloatPrimeReg checks that r is an floating-point register that can
// be used in a prime register field of a compressed instruction.
func wantFloatPrimeReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) {
@@ -3515,6 +3531,147 @@ func (ins *instruction) usesRegTmp() bool {
return ins.rd == REG_TMP || ins.rs1 == REG_TMP || ins.rs2 == REG_TMP
}
+func (ins *instruction) compress() {
+ switch ins.as {
+ case ALW:
+ if ins.rd != REG_X0 && ins.rs1 == REG_SP && isScaledImmU(ins.imm, 8, 4) {
+ ins.as, ins.rs1, ins.rs2 = ACLWSP, obj.REG_NONE, ins.rs1
+ } else if isIntPrimeReg(ins.rd) && isIntPrimeReg(ins.rs1) && isScaledImmU(ins.imm, 7, 4) {
+ ins.as = ACLW
+ }
+
+ case ALD:
+ if ins.rs1 == REG_SP && ins.rd != REG_X0 && isScaledImmU(ins.imm, 9, 8) {
+ ins.as, ins.rs1, ins.rs2 = ACLDSP, obj.REG_NONE, ins.rs1
+ } else if isIntPrimeReg(ins.rd) && isIntPrimeReg(ins.rs1) && isScaledImmU(ins.imm, 8, 8) {
+ ins.as = ACLD
+ }
+
+ case AFLD:
+ if ins.rs1 == REG_SP && isScaledImmU(ins.imm, 9, 8) {
+ ins.as, ins.rs1, ins.rs2 = ACFLDSP, obj.REG_NONE, ins.rs1
+ } else if isFloatPrimeReg(ins.rd) && isIntPrimeReg(ins.rs1) && isScaledImmU(ins.imm, 8, 8) {
+ ins.as = ACFLD
+ }
+
+ case ASW:
+ if ins.rd == REG_SP && isScaledImmU(ins.imm, 8, 4) {
+ ins.as, ins.rs1, ins.rs2 = ACSWSP, obj.REG_NONE, ins.rs1
+ } else if isIntPrimeReg(ins.rd) && isIntPrimeReg(ins.rs1) && isScaledImmU(ins.imm, 7, 4) {
+ ins.as, ins.rd, ins.rs1, ins.rs2 = ACSW, obj.REG_NONE, ins.rd, ins.rs1
+ }
+
+ case ASD:
+ if ins.rd == REG_SP && isScaledImmU(ins.imm, 9, 8) {
+ ins.as, ins.rs1, ins.rs2 = ACSDSP, obj.REG_NONE, ins.rs1
+ } else if isIntPrimeReg(ins.rd) && isIntPrimeReg(ins.rs1) && isScaledImmU(ins.imm, 8, 8) {
+ ins.as, ins.rd, ins.rs1, ins.rs2 = ACSD, obj.REG_NONE, ins.rd, ins.rs1
+ }
+
+ case AFSD:
+ if ins.rd == REG_SP && isScaledImmU(ins.imm, 9, 8) {
+ ins.as, ins.rs1, ins.rs2 = ACFSDSP, obj.REG_NONE, ins.rs1
+ } else if isIntPrimeReg(ins.rd) && isFloatPrimeReg(ins.rs1) && isScaledImmU(ins.imm, 8, 8) {
+ ins.as, ins.rd, ins.rs1, ins.rs2 = ACFSD, obj.REG_NONE, ins.rd, ins.rs1
+ }
+
+ case AADDI:
+ if ins.rd == REG_SP && ins.rs1 == REG_SP && ins.imm != 0 && isScaledImmI(ins.imm, 10, 16) {
+ ins.as = ACADDI16SP
+ } else if ins.rd != REG_X0 && ins.rd == ins.rs1 && ins.imm != 0 && immIFits(ins.imm, 6) == nil {
+ ins.as = ACADDI
+ } else if isIntPrimeReg(ins.rd) && ins.rs1 == REG_SP && ins.imm != 0 && isScaledImmU(ins.imm, 10, 4) {
+ ins.as = ACADDI4SPN
+ } else if ins.rd != REG_X0 && ins.rs1 == REG_X0 && immIFits(ins.imm, 6) == nil {
+ ins.as, ins.rs1 = ACLI, obj.REG_NONE
+ } else if ins.rd != REG_X0 && ins.rs1 != REG_X0 && ins.imm == 0 {
+ ins.as, ins.rs1, ins.rs2 = ACMV, obj.REG_NONE, ins.rs1
+ } else if ins.rd == REG_X0 && ins.rs1 == REG_X0 && ins.imm == 0 {
+ ins.as, ins.rs1 = ACNOP, ins.rd
+ }
+
+ case AADDIW:
+ if ins.rd == ins.rs1 && immIFits(ins.imm, 6) == nil {
+ ins.as = ACADDIW
+ }
+
+ case ALUI:
+ if ins.rd != REG_X0 && ins.rd != REG_SP && ins.imm != 0 && immIFits(ins.imm, 6) == nil {
+ ins.as = ACLUI
+ }
+
+ case ASLLI:
+ if ins.rd != REG_X0 && ins.rd == ins.rs1 && ins.imm != 0 {
+ ins.as = ACSLLI
+ }
+
+ case ASRLI:
+ if isIntPrimeReg(ins.rd) && ins.rd == ins.rs1 && ins.imm != 0 {
+ ins.as = ACSRLI
+ }
+
+ case ASRAI:
+ if isIntPrimeReg(ins.rd) && ins.rd == ins.rs1 && ins.imm != 0 {
+ ins.as = ACSRAI
+ }
+
+ case AANDI:
+ if isIntPrimeReg(ins.rd) && ins.rd == ins.rs1 && immIFits(ins.imm, 6) == nil {
+ ins.as = ACANDI
+ }
+
+ case AADD:
+ if ins.rd != REG_X0 && ins.rd == ins.rs1 && ins.rs2 != REG_X0 {
+ ins.as = ACADD
+ } else if ins.rd != REG_X0 && ins.rd == ins.rs2 && ins.rs1 != REG_X0 {
+ ins.as, ins.rs1, ins.rs2 = ACADD, ins.rs2, ins.rs1
+ } else if ins.rd != REG_X0 && ins.rs1 == REG_X0 && ins.rs2 != REG_X0 {
+ ins.as = ACMV
+ }
+
+ case AADDW:
+ if isIntPrimeReg(ins.rd) && ins.rd == ins.rs1 && isIntPrimeReg(ins.rs2) {
+ ins.as = ACADDW
+ } else if isIntPrimeReg(ins.rd) && isIntPrimeReg(ins.rs1) && ins.rd == ins.rs2 {
+ ins.as, ins.rs1, ins.rs2 = ACADDW, ins.rs2, ins.rs1
+ }
+
+ case ASUB:
+ if isIntPrimeReg(ins.rd) && ins.rd == ins.rs1 && isIntPrimeReg(ins.rs2) {
+ ins.as = ACSUB
+ }
+
+ case ASUBW:
+ if isIntPrimeReg(ins.rd) && ins.rd == ins.rs1 && isIntPrimeReg(ins.rs2) {
+ ins.as = ACSUBW
+ }
+
+ case AAND:
+ if isIntPrimeReg(ins.rd) && ins.rd == ins.rs1 && isIntPrimeReg(ins.rs2) {
+ ins.as = ACAND
+ } else if isIntPrimeReg(ins.rd) && isIntPrimeReg(ins.rs1) && ins.rd == ins.rs2 {
+ ins.as, ins.rs1, ins.rs2 = ACAND, ins.rs2, ins.rs1
+ }
+
+ case AOR:
+ if isIntPrimeReg(ins.rd) && ins.rd == ins.rs1 && isIntPrimeReg(ins.rs2) {
+ ins.as = ACOR
+ } else if isIntPrimeReg(ins.rd) && isIntPrimeReg(ins.rs1) && ins.rd == ins.rs2 {
+ ins.as, ins.rs1, ins.rs2 = ACOR, ins.rs2, ins.rs1
+ }
+
+ case AXOR:
+ if isIntPrimeReg(ins.rd) && ins.rd == ins.rs1 && isIntPrimeReg(ins.rs2) {
+ ins.as = ACXOR
+ } else if isIntPrimeReg(ins.rd) && isIntPrimeReg(ins.rs1) && ins.rd == ins.rs2 {
+ ins.as, ins.rs1, ins.rs2 = ACXOR, ins.rs2, ins.rs1
+ }
+
+ case AEBREAK:
+ ins.as, ins.rd, ins.rs1 = ACEBREAK, obj.REG_NONE, obj.REG_NONE
+ }
+}
+
// instructionForProg returns the default *obj.Prog to instruction mapping.
func instructionForProg(p *obj.Prog) *instruction {
ins := &instruction{
@@ -4057,7 +4214,7 @@ func instructionsForMinMax(p *obj.Prog, ins *instruction) []*instruction {
}
// instructionsForProg returns the machine instructions for an *obj.Prog.
-func instructionsForProg(p *obj.Prog) []*instruction {
+func instructionsForProg(p *obj.Prog, compress bool) []*instruction {
ins := instructionForProg(p)
inss := []*instruction{ins}
@@ -4710,6 +4867,15 @@ func instructionsForProg(p *obj.Prog) []*instruction {
ins.rs1, ins.rs2 = obj.REG_NONE, REG_V0
}
+ // Only compress instructions when there is no relocation, since
+ // relocation relies on knowledge about the exact instructions that
+ // are in use.
+ if compress && p.Mark&NEED_RELOC == 0 {
+ for _, ins := range inss {
+ ins.compress()
+ }
+ }
+
for _, ins := range inss {
ins.p = p
}
@@ -4799,15 +4965,22 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
v := pcAlignPadLength(p.Pc, alignedValue)
offset := p.Pc
for ; v >= 4; v -= 4 {
- // NOP
- cursym.WriteBytes(ctxt, offset, []byte{0x13, 0, 0, 0})
+ // NOP (ADDI $0, X0, X0)
+ cursym.WriteBytes(ctxt, offset, []byte{0x13, 0x00, 0x00, 0x00})
offset += 4
}
+ if v == 2 {
+ // CNOP
+ cursym.WriteBytes(ctxt, offset, []byte{0x01, 0x00})
+ offset += 2
+ } else if v != 0 {
+ ctxt.Diag("bad PCALIGN pad length")
+ }
continue
}
offset := p.Pc
- for _, ins := range instructionsForProg(p) {
+ for _, ins := range instructionsForProg(p, ctxt.CompressInstructions) {
if ic, err := ins.encode(); err == nil {
cursym.WriteInt(ctxt, offset, ins.length(), int64(ic))
offset += int64(ins.length())
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 9c8e5e96f8..ed41d81388 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -423,8 +423,12 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
q.From.Reg = reg
}
}
- if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
- ctxt.Diag("don't know how to handle %v with -dynlink", p)
+ from3 := p.GetFrom3()
+ for i := range p.RestArgs {
+ a := &p.RestArgs[i].Addr
+ if a != from3 && a.Name == obj.NAME_EXTERN && !a.Sym.Local() {
+ ctxt.Diag("don't know how to handle %v with -dynlink", p)
+ }
}
var source *obj.Addr
// MOVx sym, Ry becomes $MOV sym@GOT, R15; MOVx (R15), Ry
@@ -434,9 +438,17 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
}
+ if from3 != nil && from3.Name == obj.NAME_EXTERN && !from3.Sym.Local() {
+ ctxt.Diag("cannot handle NAME_EXTERN on multiple operands in %v with -dynlink", p)
+ }
source = &p.From
} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
+ if from3 != nil && from3.Name == obj.NAME_EXTERN && !from3.Sym.Local() {
+ ctxt.Diag("cannot handle NAME_EXTERN on multiple operands in %v with -dynlink", p)
+ }
source = &p.To
+ } else if from3 != nil && from3.Name == obj.NAME_EXTERN && !from3.Sym.Local() {
+ source = from3
} else {
return
}
@@ -501,9 +513,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p2.As = p.As
p2.From = p.From
p2.To = p.To
- if from3 := p.GetFrom3(); from3 != nil {
- p2.AddRestSource(*from3)
- }
+ p2.RestArgs = p.RestArgs
if p.From.Name == obj.NAME_EXTERN {
p2.From.Reg = reg
p2.From.Name = obj.NAME_NONE
@@ -512,6 +522,11 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p2.To.Reg = reg
p2.To.Name = obj.NAME_NONE
p2.To.Sym = nil
+ } else if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
+ from3 = p2.GetFrom3()
+ from3.Reg = reg
+ from3.Name = obj.NAME_NONE
+ from3.Sym = nil
} else {
return
}
diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go
index 3c92a6bbf2..14b1cde22b 100644
--- a/src/cmd/internal/sys/arch.go
+++ b/src/cmd/internal/sys/arch.go
@@ -236,7 +236,7 @@ var ArchRISCV64 = &Arch{
ByteOrder: binary.LittleEndian,
PtrSize: 8,
RegSize: 8,
- MinLC: 4,
+ MinLC: 2,
Alignment: 8, // riscv unaligned loads work, but are really slow (trap + simulated by OS)
CanMergeLoads: false,
HasLR: true,
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 31de34aff4..9bab73e7b7 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -2507,19 +2507,19 @@ func dwarfcompress(ctxt *Link) {
var prevSect *sym.Section
for _, si := range dwarfp {
for _, s := range si.syms {
- ldr.SetSymValue(s, int64(pos))
sect := ldr.SymSect(s)
if sect != prevSect {
+ if ctxt.IsWindows() {
+ pos = uint64(Rnd(int64(pos), PEFILEALIGN))
+ }
sect.Vaddr = pos
prevSect = sect
}
+ ldr.SetSymValue(s, int64(pos))
if ldr.SubSym(s) != 0 {
log.Fatalf("%s: unexpected sub-symbols", ldr.SymName(s))
}
pos += uint64(ldr.SymSize(s))
- if ctxt.IsWindows() {
- pos = uint64(Rnd(int64(pos), PEFILEALIGN))
- }
}
}
Segdwarf.Length = pos - Segdwarf.Vaddr
diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go
index 9a27ac8c76..64b86f3a0b 100644
--- a/src/cmd/link/internal/ld/ld_test.go
+++ b/src/cmd/link/internal/ld/ld_test.go
@@ -387,7 +387,7 @@ func TestRISCVTrampolines(t *testing.T) {
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "TEXT a(SB),$0-0\n")
for i := 0; i < 1<<17; i++ {
- fmt.Fprintf(buf, "\tADD $0, X0, X0\n")
+ fmt.Fprintf(buf, "\tADD $0, X5, X0\n")
}
fmt.Fprintf(buf, "\tCALL b(SB)\n")
fmt.Fprintf(buf, "\tRET\n")
@@ -398,7 +398,7 @@ func TestRISCVTrampolines(t *testing.T) {
fmt.Fprintf(buf, "\tRET\n")
fmt.Fprintf(buf, "TEXT ·d(SB),0,$0-0\n")
for i := 0; i < 1<<17; i++ {
- fmt.Fprintf(buf, "\tADD $0, X0, X0\n")
+ fmt.Fprintf(buf, "\tADD $0, X5, X0\n")
}
fmt.Fprintf(buf, "\tCALL a(SB)\n")
fmt.Fprintf(buf, "\tCALL c(SB)\n")
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index d913953944..a4b3a0422f 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -188,7 +188,11 @@ func Main(arch *sys.Arch, theArch Arch) {
buildVersion := buildcfg.Version
if goexperiment := buildcfg.Experiment.String(); goexperiment != "" {
- buildVersion += " X:" + goexperiment
+ sep := " "
+ if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953.
+ sep = "-"
+ }
+ buildVersion += sep + "X:" + goexperiment
}
addstrdata1(ctxt, "runtime.buildVersion="+buildVersion)
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 2d386c0c65..9ab55643f6 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -2464,10 +2464,11 @@ var blockedLinknames = map[string][]string{
// Experimental features
"runtime.goroutineLeakGC": {"runtime/pprof"},
"runtime.goroutineleakcount": {"runtime/pprof"},
+ "runtime.freegc": {}, // disallow all packages
// Others
"net.newWindowsFile": {"net"}, // pushed from os
"testing/synctest.testingSynctestTest": {"testing/synctest"}, // pushed from testing
- "runtime.addmoduledata": {}, // disallow all package
+ "runtime.addmoduledata": {}, // disallow all packages
}
// check if a linkname reference to symbol s from pkg is allowed
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index 31822d21f3..6ab1246c81 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -1616,6 +1616,7 @@ func TestCheckLinkname(t *testing.T) {
// pull linkname of a builtin symbol is not ok
{"builtin.go", false},
{"addmoduledata.go", false},
+ {"freegc.go", false},
// legacy bad linkname is ok, for now
{"fastrand.go", true},
{"badlinkname.go", true},
diff --git a/src/cmd/link/testdata/linkname/freegc.go b/src/cmd/link/testdata/linkname/freegc.go
new file mode 100644
index 0000000000..390063f8e9
--- /dev/null
+++ b/src/cmd/link/testdata/linkname/freegc.go
@@ -0,0 +1,18 @@
+// Copyright 2025 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.
+
+// Linkname runtime.freegc is not allowed.
+
+package main
+
+import (
+ _ "unsafe"
+)
+
+//go:linkname freegc runtime.freegc
+func freegc()
+
+func main() {
+ freegc()
+}
diff --git a/src/cmd/trace/procgen.go b/src/cmd/trace/procgen.go
index 060e62fe04..fc0a00e7ce 100644
--- a/src/cmd/trace/procgen.go
+++ b/src/cmd/trace/procgen.go
@@ -143,6 +143,13 @@ func (g *procGenerator) ProcTransition(ctx *traceContext, ev *trace.Event) {
viewerEv := traceviewer.InstantEvent{
Resource: uint64(proc),
Stack: ctx.Stack(viewerFrames(ev.Stack())),
+
+ // Annotate with the thread and proc. The proc is redundant, but this is to
+ // stay consistent with the thread view, where it's useful information.
+ Arg: format.SchedCtxArg{
+ ProcID: uint64(st.Resource.Proc()),
+ ThreadID: uint64(ev.Thread()),
+ },
}
from, to := st.Proc()
@@ -156,7 +163,6 @@ func (g *procGenerator) ProcTransition(ctx *traceContext, ev *trace.Event) {
start = ctx.startTime
}
viewerEv.Name = "proc start"
- viewerEv.Arg = format.ThreadIDArg{ThreadID: uint64(ev.Thread())}
viewerEv.Ts = ctx.elapsed(start)
ctx.IncThreadStateCount(ctx.elapsed(start), traceviewer.ThreadStateRunning, 1)
}
diff --git a/src/cmd/trace/threadgen.go b/src/cmd/trace/threadgen.go
index c2e2c86f6c..7f9e7a72f0 100644
--- a/src/cmd/trace/threadgen.go
+++ b/src/cmd/trace/threadgen.go
@@ -138,14 +138,17 @@ func (g *threadGenerator) ProcTransition(ctx *traceContext, ev *trace.Event) {
}
}
- type procArg struct {
- Proc uint64 `json:"proc,omitempty"`
- }
st := ev.StateTransition()
viewerEv := traceviewer.InstantEvent{
Resource: uint64(ev.Thread()),
Stack: ctx.Stack(viewerFrames(ev.Stack())),
- Arg: procArg{Proc: uint64(st.Resource.Proc())},
+
+ // Annotate with the thread and proc. The thread is redundant, but this is to
+ // stay consistent with the proc view.
+ Arg: format.SchedCtxArg{
+ ProcID: uint64(st.Resource.Proc()),
+ ThreadID: uint64(ev.Thread()),
+ },
}
from, to := st.Proc()
@@ -159,7 +162,6 @@ func (g *threadGenerator) ProcTransition(ctx *traceContext, ev *trace.Event) {
start = ctx.startTime
}
viewerEv.Name = "proc start"
- viewerEv.Arg = format.ThreadIDArg{ThreadID: uint64(ev.Thread())}
viewerEv.Ts = ctx.elapsed(start)
// TODO(mknyszek): We don't have a state machine for threads, so approximate
// running threads with running Ps.
diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/print.go b/src/cmd/vendor/golang.org/x/mod/modfile/print.go
index 2a0123d4b9..48dbd82aec 100644
--- a/src/cmd/vendor/golang.org/x/mod/modfile/print.go
+++ b/src/cmd/vendor/golang.org/x/mod/modfile/print.go
@@ -33,7 +33,7 @@ type printer struct {
}
// printf prints to the buffer.
-func (p *printer) printf(format string, args ...interface{}) {
+func (p *printer) printf(format string, args ...any) {
fmt.Fprintf(p, format, args...)
}
diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/read.go b/src/cmd/vendor/golang.org/x/mod/modfile/read.go
index 2d7486804f..504a2f1df6 100644
--- a/src/cmd/vendor/golang.org/x/mod/modfile/read.go
+++ b/src/cmd/vendor/golang.org/x/mod/modfile/read.go
@@ -94,7 +94,7 @@ func (x *FileSyntax) Span() (start, end Position) {
// line, the new line is added at the end of the block containing hint,
// extracting hint into a new block if it is not yet in one.
//
-// If the hint is non-nil buts its first token does not match,
+// If the hint is non-nil but its first token does not match,
// the new line is added after the block containing hint
// (or hint itself, if not in a block).
//
@@ -600,7 +600,7 @@ func (in *input) readToken() {
// Checked all punctuation. Must be identifier token.
if c := in.peekRune(); !isIdent(c) {
- in.Error(fmt.Sprintf("unexpected input character %#q", c))
+ in.Error(fmt.Sprintf("unexpected input character %#q", rune(c)))
}
// Scan over identifier.
diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go
index a86ee4fd82..c5b8305de7 100644
--- a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go
+++ b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go
@@ -368,7 +368,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
Err: err,
})
}
- errorf := func(format string, args ...interface{}) {
+ errorf := func(format string, args ...any) {
wrapError(fmt.Errorf(format, args...))
}
@@ -574,7 +574,7 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V
Err: err,
}
}
- errorf := func(format string, args ...interface{}) *Error {
+ errorf := func(format string, args ...any) *Error {
return wrapError(fmt.Errorf(format, args...))
}
@@ -685,7 +685,7 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string,
Err: err,
})
}
- errorf := func(format string, args ...interface{}) {
+ errorf := func(format string, args ...any) {
wrapError(fmt.Errorf(format, args...))
}
@@ -1594,7 +1594,7 @@ func (f *File) AddRetract(vi VersionInterval, rationale string) error {
r.Syntax = f.Syntax.addLine(nil, "retract", "[", AutoQuote(vi.Low), ",", AutoQuote(vi.High), "]")
}
if rationale != "" {
- for _, line := range strings.Split(rationale, "\n") {
+ for line := range strings.SplitSeq(rationale, "\n") {
com := Comment{Token: "// " + line}
r.Syntax.Comment().Before = append(r.Syntax.Comment().Before, com)
}
diff --git a/src/cmd/vendor/golang.org/x/mod/module/module.go b/src/cmd/vendor/golang.org/x/mod/module/module.go
index 16e1aa7ab4..739c13f48f 100644
--- a/src/cmd/vendor/golang.org/x/mod/module/module.go
+++ b/src/cmd/vendor/golang.org/x/mod/module/module.go
@@ -261,7 +261,7 @@ func modPathOK(r rune) bool {
// importPathOK reports whether r can appear in a package import path element.
//
-// Import paths are intermediate between module paths and file paths: we allow
+// Import paths are intermediate between module paths and file paths: we
// disallow characters that would be confusing or ambiguous as arguments to
// 'go get' (such as '@' and ' ' ), but allow certain characters that are
// otherwise-unambiguous on the command line and historically used for some
@@ -802,8 +802,8 @@ func MatchPrefixPatterns(globs, target string) bool {
for globs != "" {
// Extract next non-empty glob in comma-separated list.
var glob string
- if i := strings.Index(globs, ","); i >= 0 {
- glob, globs = globs[:i], globs[i+1:]
+ if before, after, ok := strings.Cut(globs, ","); ok {
+ glob, globs = before, after
} else {
glob, globs = globs, ""
}
diff --git a/src/cmd/vendor/golang.org/x/mod/semver/semver.go b/src/cmd/vendor/golang.org/x/mod/semver/semver.go
index 628f8fd687..824b282c83 100644
--- a/src/cmd/vendor/golang.org/x/mod/semver/semver.go
+++ b/src/cmd/vendor/golang.org/x/mod/semver/semver.go
@@ -45,8 +45,8 @@ func IsValid(v string) bool {
// Canonical returns the canonical formatting of the semantic version v.
// It fills in any missing .MINOR or .PATCH and discards build metadata.
-// Two semantic versions compare equal only if their canonical formattings
-// are identical strings.
+// Two semantic versions compare equal only if their canonical formatting
+// is an identical string.
// The canonical invalid semantic version is the empty string.
func Canonical(v string) string {
p, ok := parse(v)
diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/cache.go b/src/cmd/vendor/golang.org/x/mod/sumdb/cache.go
index 629e591f42..749a80dfa4 100644
--- a/src/cmd/vendor/golang.org/x/mod/sumdb/cache.go
+++ b/src/cmd/vendor/golang.org/x/mod/sumdb/cache.go
@@ -20,13 +20,13 @@ type parCache struct {
type cacheEntry struct {
done uint32
mu sync.Mutex
- result interface{}
+ result any
}
// Do calls the function f if and only if Do is being called for the first time with this key.
// No call to Do with a given key returns until the one call to f returns.
// Do returns the value returned by the one call to f.
-func (c *parCache) Do(key interface{}, f func() interface{}) interface{} {
+func (c *parCache) Do(key any, f func() any) any {
entryIface, ok := c.m.Load(key)
if !ok {
entryIface, _ = c.m.LoadOrStore(key, new(cacheEntry))
@@ -46,7 +46,7 @@ func (c *parCache) Do(key interface{}, f func() interface{}) interface{} {
// Get returns the cached result associated with key.
// It returns nil if there is no such result.
// If the result for key is being computed, Get does not wait for the computation to finish.
-func (c *parCache) Get(key interface{}) interface{} {
+func (c *parCache) Get(key any) any {
entryIface, ok := c.m.Load(key)
if !ok {
return nil
diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/client.go b/src/cmd/vendor/golang.org/x/mod/sumdb/client.go
index 04dbdfe46a..f926eda1bb 100644
--- a/src/cmd/vendor/golang.org/x/mod/sumdb/client.go
+++ b/src/cmd/vendor/golang.org/x/mod/sumdb/client.go
@@ -244,7 +244,7 @@ func (c *Client) Lookup(path, vers string) (lines []string, err error) {
data []byte
err error
}
- result := c.record.Do(file, func() interface{} {
+ result := c.record.Do(file, func() any {
// Try the on-disk cache, or else get from web.
writeCache := false
data, err := c.ops.ReadCache(file)
@@ -284,7 +284,7 @@ func (c *Client) Lookup(path, vers string) (lines []string, err error) {
// (with or without /go.mod).
prefix := path + " " + vers + " "
var hashes []string
- for _, line := range strings.Split(string(result.data), "\n") {
+ for line := range strings.SplitSeq(string(result.data), "\n") {
if strings.HasPrefix(line, prefix) {
hashes = append(hashes, line)
}
@@ -552,7 +552,7 @@ func (c *Client) readTile(tile tlog.Tile) ([]byte, error) {
err error
}
- result := c.tileCache.Do(tile, func() interface{} {
+ result := c.tileCache.Do(tile, func() any {
// Try the requested tile in on-disk cache.
data, err := c.ops.ReadCache(c.tileCacheKey(tile))
if err == nil {
diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go b/src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go
index db9865c317..8b2b25278d 100644
--- a/src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go
+++ b/src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go
@@ -240,8 +240,8 @@ func isValidName(name string) bool {
// NewVerifier construct a new [Verifier] from an encoded verifier key.
func NewVerifier(vkey string) (Verifier, error) {
- name, vkey := chop(vkey, "+")
- hash16, key64 := chop(vkey, "+")
+ name, vkey, _ := strings.Cut(vkey, "+")
+ hash16, key64, _ := strings.Cut(vkey, "+")
hash, err1 := strconv.ParseUint(hash16, 16, 32)
key, err2 := base64.StdEncoding.DecodeString(key64)
if len(hash16) != 8 || err1 != nil || err2 != nil || !isValidName(name) || len(key) == 0 {
@@ -276,12 +276,8 @@ func NewVerifier(vkey string) (Verifier, error) {
// chop chops s at the first instance of sep, if any,
// and returns the text before and after sep.
// If sep is not present, chop returns before is s and after is empty.
-func chop(s, sep string) (before, after string) {
- i := strings.Index(s, sep)
- if i < 0 {
- return s, ""
- }
- return s[:i], s[i+len(sep):]
+func chop(s, sep string) (before, after string, ok bool) {
+ return strings.Cut(s, sep)
}
// verifier is a trivial Verifier implementation.
@@ -297,10 +293,10 @@ func (v *verifier) Verify(msg, sig []byte) bool { return v.verify(msg, sig) }
// NewSigner constructs a new [Signer] from an encoded signer key.
func NewSigner(skey string) (Signer, error) {
- priv1, skey := chop(skey, "+")
- priv2, skey := chop(skey, "+")
- name, skey := chop(skey, "+")
- hash16, key64 := chop(skey, "+")
+ priv1, skey, _ := strings.Cut(skey, "+")
+ priv2, skey, _ := strings.Cut(skey, "+")
+ name, skey, _ := strings.Cut(skey, "+")
+ hash16, key64, _ := strings.Cut(skey, "+")
hash, err1 := strconv.ParseUint(hash16, 16, 32)
key, err2 := base64.StdEncoding.DecodeString(key64)
if priv1 != "PRIVATE" || priv2 != "KEY" || len(hash16) != 8 || err1 != nil || err2 != nil || !isValidName(name) || len(key) == 0 {
@@ -557,7 +553,7 @@ func Open(msg []byte, known Verifiers) (*Note, error) {
return nil, errMalformedNote
}
line = line[len(sigPrefix):]
- name, b64 := chop(string(line), " ")
+ name, b64, _ := chop(string(line), " ")
sig, err := base64.StdEncoding.DecodeString(b64)
if err != nil || !isValidName(name) || b64 == "" || len(sig) < 5 {
return nil, errMalformedNote
diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/server.go b/src/cmd/vendor/golang.org/x/mod/sumdb/server.go
index 216a2562c2..2433c939d7 100644
--- a/src/cmd/vendor/golang.org/x/mod/sumdb/server.go
+++ b/src/cmd/vendor/golang.org/x/mod/sumdb/server.go
@@ -76,8 +76,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, "invalid module@version syntax", http.StatusBadRequest)
return
}
- i := strings.Index(mod, "@")
- escPath, escVers := mod[:i], mod[i+1:]
+ escPath, escVers, _ := strings.Cut(mod, "@")
path, err := module.UnescapePath(escPath)
if err != nil {
reportError(w, err)
diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/test.go b/src/cmd/vendor/golang.org/x/mod/sumdb/test.go
index fb772452d9..0868bef5fc 100644
--- a/src/cmd/vendor/golang.org/x/mod/sumdb/test.go
+++ b/src/cmd/vendor/golang.org/x/mod/sumdb/test.go
@@ -66,7 +66,7 @@ func (s *TestServer) ReadRecords(ctx context.Context, id, n int64) ([][]byte, er
defer s.mu.Unlock()
var list [][]byte
- for i := int64(0); i < n; i++ {
+ for i := range n {
if id+i >= int64(len(s.records)) {
return nil, fmt.Errorf("missing records")
}
diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/note.go b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/note.go
index fc6d5fa0a3..1ea765a54f 100644
--- a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/note.go
+++ b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/note.go
@@ -35,7 +35,7 @@ type Tree struct {
// A future backwards-incompatible encoding would use a different
// first line (for example, "go.sum database tree v2").
func FormatTree(tree Tree) []byte {
- return []byte(fmt.Sprintf("go.sum database tree\n%d\n%s\n", tree.N, tree.Hash))
+ return fmt.Appendf(nil, "go.sum database tree\n%d\n%s\n", tree.N, tree.Hash)
}
var errMalformedTree = errors.New("malformed tree note")
@@ -87,7 +87,7 @@ func FormatRecord(id int64, text []byte) (msg []byte, err error) {
if !isValidRecordText(text) {
return nil, errMalformedRecord
}
- msg = []byte(fmt.Sprintf("%d\n", id))
+ msg = fmt.Appendf(nil, "%d\n", id)
msg = append(msg, text...)
msg = append(msg, '\n')
return msg, nil
diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go
index f7ea753832..480b5eff5a 100644
--- a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go
+++ b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go
@@ -194,7 +194,7 @@ func StoredHashesForRecordHash(n int64, h Hash, r HashReader) ([]Hash, error) {
// and consumes a hash from an adjacent subtree.
m := int(bits.TrailingZeros64(uint64(n + 1)))
indexes := make([]int64, m)
- for i := 0; i < m; i++ {
+ for i := range m {
// We arrange indexes in sorted order.
// Note that n>>i is always odd.
indexes[m-1-i] = StoredHashIndex(i, n>>uint(i)-1)
@@ -210,7 +210,7 @@ func StoredHashesForRecordHash(n int64, h Hash, r HashReader) ([]Hash, error) {
}
// Build new hashes.
- for i := 0; i < m; i++ {
+ for i := range m {
h = NodeHash(old[m-1-i], h)
hashes = append(hashes, h)
}
diff --git a/src/cmd/vendor/golang.org/x/mod/zip/zip.go b/src/cmd/vendor/golang.org/x/mod/zip/zip.go
index 3673db4997..48363ceb72 100644
--- a/src/cmd/vendor/golang.org/x/mod/zip/zip.go
+++ b/src/cmd/vendor/golang.org/x/mod/zip/zip.go
@@ -780,7 +780,7 @@ func (fi dataFileInfo) Size() int64 { return int64(len(fi.f.data)) }
func (fi dataFileInfo) Mode() os.FileMode { return 0644 }
func (fi dataFileInfo) ModTime() time.Time { return time.Time{} }
func (fi dataFileInfo) IsDir() bool { return false }
-func (fi dataFileInfo) Sys() interface{} { return nil }
+func (fi dataFileInfo) Sys() any { return nil }
// isVendoredPackage attempts to report whether the given filename is contained
// in a package whose import path contains (but does not end with) the component
diff --git a/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go b/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go
index 1d8cffae8c..2f45dbc86e 100644
--- a/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go
+++ b/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package errgroup provides synchronization, error propagation, and Context
-// cancelation for groups of goroutines working on subtasks of a common task.
+// cancellation for groups of goroutines working on subtasks of a common task.
//
// [errgroup.Group] is related to [sync.WaitGroup] but adds handling of tasks
// returning errors.
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh b/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh
index d1c8b2640e..42517077c4 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -226,6 +226,7 @@ struct ltchars {
#include <linux/cryptouser.h>
#include <linux/devlink.h>
#include <linux/dm-ioctl.h>
+#include <linux/elf.h>
#include <linux/errqueue.h>
#include <linux/ethtool_netlink.h>
#include <linux/falloc.h>
@@ -529,6 +530,7 @@ ccflags="$@"
$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ ||
$2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ ||
$2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ ||
+ $2 ~ /^(DT|EI|ELF|EV|NN|NT|PF|SHF|SHN|SHT|STB|STT|VER)_/ ||
$2 ~ /^O?XTABS$/ ||
$2 ~ /^TC[IO](ON|OFF)$/ ||
$2 ~ /^IN_/ ||
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go
index 9439af961d..06c0eea6fb 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -2643,3 +2643,9 @@ func SchedGetAttr(pid int, flags uint) (*SchedAttr, error) {
//sys Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint) (err error)
//sys Mseal(b []byte, flags uint) (err error)
+
+//sys setMemPolicy(mode int, mask *CPUSet, size int) (err error) = SYS_SET_MEMPOLICY
+
+func SetMemPolicy(mode int, mask *CPUSet) error {
+ return setMemPolicy(mode, mask, _CPU_SETSIZE)
+}
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go
index b6db27d937..d0a75da572 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -853,20 +853,86 @@ const (
DM_VERSION_MAJOR = 0x4
DM_VERSION_MINOR = 0x32
DM_VERSION_PATCHLEVEL = 0x0
+ DT_ADDRRNGHI = 0x6ffffeff
+ DT_ADDRRNGLO = 0x6ffffe00
DT_BLK = 0x6
DT_CHR = 0x2
+ DT_DEBUG = 0x15
DT_DIR = 0x4
+ DT_ENCODING = 0x20
DT_FIFO = 0x1
+ DT_FINI = 0xd
+ DT_FLAGS_1 = 0x6ffffffb
+ DT_GNU_HASH = 0x6ffffef5
+ DT_HASH = 0x4
+ DT_HIOS = 0x6ffff000
+ DT_HIPROC = 0x7fffffff
+ DT_INIT = 0xc
+ DT_JMPREL = 0x17
DT_LNK = 0xa
+ DT_LOOS = 0x6000000d
+ DT_LOPROC = 0x70000000
+ DT_NEEDED = 0x1
+ DT_NULL = 0x0
+ DT_PLTGOT = 0x3
+ DT_PLTREL = 0x14
+ DT_PLTRELSZ = 0x2
DT_REG = 0x8
+ DT_REL = 0x11
+ DT_RELA = 0x7
+ DT_RELACOUNT = 0x6ffffff9
+ DT_RELAENT = 0x9
+ DT_RELASZ = 0x8
+ DT_RELCOUNT = 0x6ffffffa
+ DT_RELENT = 0x13
+ DT_RELSZ = 0x12
+ DT_RPATH = 0xf
DT_SOCK = 0xc
+ DT_SONAME = 0xe
+ DT_STRSZ = 0xa
+ DT_STRTAB = 0x5
+ DT_SYMBOLIC = 0x10
+ DT_SYMENT = 0xb
+ DT_SYMTAB = 0x6
+ DT_TEXTREL = 0x16
DT_UNKNOWN = 0x0
+ DT_VALRNGHI = 0x6ffffdff
+ DT_VALRNGLO = 0x6ffffd00
+ DT_VERDEF = 0x6ffffffc
+ DT_VERDEFNUM = 0x6ffffffd
+ DT_VERNEED = 0x6ffffffe
+ DT_VERNEEDNUM = 0x6fffffff
+ DT_VERSYM = 0x6ffffff0
DT_WHT = 0xe
ECHO = 0x8
ECRYPTFS_SUPER_MAGIC = 0xf15f
EFD_SEMAPHORE = 0x1
EFIVARFS_MAGIC = 0xde5e81e4
EFS_SUPER_MAGIC = 0x414a53
+ EI_CLASS = 0x4
+ EI_DATA = 0x5
+ EI_MAG0 = 0x0
+ EI_MAG1 = 0x1
+ EI_MAG2 = 0x2
+ EI_MAG3 = 0x3
+ EI_NIDENT = 0x10
+ EI_OSABI = 0x7
+ EI_PAD = 0x8
+ EI_VERSION = 0x6
+ ELFCLASS32 = 0x1
+ ELFCLASS64 = 0x2
+ ELFCLASSNONE = 0x0
+ ELFCLASSNUM = 0x3
+ ELFDATA2LSB = 0x1
+ ELFDATA2MSB = 0x2
+ ELFDATANONE = 0x0
+ ELFMAG = "\177ELF"
+ ELFMAG0 = 0x7f
+ ELFMAG1 = 'E'
+ ELFMAG2 = 'L'
+ ELFMAG3 = 'F'
+ ELFOSABI_LINUX = 0x3
+ ELFOSABI_NONE = 0x0
EM_386 = 0x3
EM_486 = 0x6
EM_68K = 0x4
@@ -1152,14 +1218,24 @@ const (
ETH_P_WCCP = 0x883e
ETH_P_X25 = 0x805
ETH_P_XDSA = 0xf8
+ ET_CORE = 0x4
+ ET_DYN = 0x3
+ ET_EXEC = 0x2
+ ET_HIPROC = 0xffff
+ ET_LOPROC = 0xff00
+ ET_NONE = 0x0
+ ET_REL = 0x1
EV_ABS = 0x3
EV_CNT = 0x20
+ EV_CURRENT = 0x1
EV_FF = 0x15
EV_FF_STATUS = 0x17
EV_KEY = 0x1
EV_LED = 0x11
EV_MAX = 0x1f
EV_MSC = 0x4
+ EV_NONE = 0x0
+ EV_NUM = 0x2
EV_PWR = 0x16
EV_REL = 0x2
EV_REP = 0x14
@@ -2276,7 +2352,167 @@ const (
NLM_F_REPLACE = 0x100
NLM_F_REQUEST = 0x1
NLM_F_ROOT = 0x100
+ NN_386_IOPERM = "LINUX"
+ NN_386_TLS = "LINUX"
+ NN_ARC_V2 = "LINUX"
+ NN_ARM_FPMR = "LINUX"
+ NN_ARM_GCS = "LINUX"
+ NN_ARM_HW_BREAK = "LINUX"
+ NN_ARM_HW_WATCH = "LINUX"
+ NN_ARM_PACA_KEYS = "LINUX"
+ NN_ARM_PACG_KEYS = "LINUX"
+ NN_ARM_PAC_ENABLED_KEYS = "LINUX"
+ NN_ARM_PAC_MASK = "LINUX"
+ NN_ARM_POE = "LINUX"
+ NN_ARM_SSVE = "LINUX"
+ NN_ARM_SVE = "LINUX"
+ NN_ARM_SYSTEM_CALL = "LINUX"
+ NN_ARM_TAGGED_ADDR_CTRL = "LINUX"
+ NN_ARM_TLS = "LINUX"
+ NN_ARM_VFP = "LINUX"
+ NN_ARM_ZA = "LINUX"
+ NN_ARM_ZT = "LINUX"
+ NN_AUXV = "CORE"
+ NN_FILE = "CORE"
+ NN_GNU_PROPERTY_TYPE_0 = "GNU"
+ NN_LOONGARCH_CPUCFG = "LINUX"
+ NN_LOONGARCH_CSR = "LINUX"
+ NN_LOONGARCH_HW_BREAK = "LINUX"
+ NN_LOONGARCH_HW_WATCH = "LINUX"
+ NN_LOONGARCH_LASX = "LINUX"
+ NN_LOONGARCH_LBT = "LINUX"
+ NN_LOONGARCH_LSX = "LINUX"
+ NN_MIPS_DSP = "LINUX"
+ NN_MIPS_FP_MODE = "LINUX"
+ NN_MIPS_MSA = "LINUX"
+ NN_PPC_DEXCR = "LINUX"
+ NN_PPC_DSCR = "LINUX"
+ NN_PPC_EBB = "LINUX"
+ NN_PPC_HASHKEYR = "LINUX"
+ NN_PPC_PKEY = "LINUX"
+ NN_PPC_PMU = "LINUX"
+ NN_PPC_PPR = "LINUX"
+ NN_PPC_SPE = "LINUX"
+ NN_PPC_TAR = "LINUX"
+ NN_PPC_TM_CDSCR = "LINUX"
+ NN_PPC_TM_CFPR = "LINUX"
+ NN_PPC_TM_CGPR = "LINUX"
+ NN_PPC_TM_CPPR = "LINUX"
+ NN_PPC_TM_CTAR = "LINUX"
+ NN_PPC_TM_CVMX = "LINUX"
+ NN_PPC_TM_CVSX = "LINUX"
+ NN_PPC_TM_SPR = "LINUX"
+ NN_PPC_VMX = "LINUX"
+ NN_PPC_VSX = "LINUX"
+ NN_PRFPREG = "CORE"
+ NN_PRPSINFO = "CORE"
+ NN_PRSTATUS = "CORE"
+ NN_PRXFPREG = "LINUX"
+ NN_RISCV_CSR = "LINUX"
+ NN_RISCV_TAGGED_ADDR_CTRL = "LINUX"
+ NN_RISCV_VECTOR = "LINUX"
+ NN_S390_CTRS = "LINUX"
+ NN_S390_GS_BC = "LINUX"
+ NN_S390_GS_CB = "LINUX"
+ NN_S390_HIGH_GPRS = "LINUX"
+ NN_S390_LAST_BREAK = "LINUX"
+ NN_S390_PREFIX = "LINUX"
+ NN_S390_PV_CPU_DATA = "LINUX"
+ NN_S390_RI_CB = "LINUX"
+ NN_S390_SYSTEM_CALL = "LINUX"
+ NN_S390_TDB = "LINUX"
+ NN_S390_TIMER = "LINUX"
+ NN_S390_TODCMP = "LINUX"
+ NN_S390_TODPREG = "LINUX"
+ NN_S390_VXRS_HIGH = "LINUX"
+ NN_S390_VXRS_LOW = "LINUX"
+ NN_SIGINFO = "CORE"
+ NN_TASKSTRUCT = "CORE"
+ NN_VMCOREDD = "LINUX"
+ NN_X86_SHSTK = "LINUX"
+ NN_X86_XSAVE_LAYOUT = "LINUX"
+ NN_X86_XSTATE = "LINUX"
NSFS_MAGIC = 0x6e736673
+ NT_386_IOPERM = 0x201
+ NT_386_TLS = 0x200
+ NT_ARC_V2 = 0x600
+ NT_ARM_FPMR = 0x40e
+ NT_ARM_GCS = 0x410
+ NT_ARM_HW_BREAK = 0x402
+ NT_ARM_HW_WATCH = 0x403
+ NT_ARM_PACA_KEYS = 0x407
+ NT_ARM_PACG_KEYS = 0x408
+ NT_ARM_PAC_ENABLED_KEYS = 0x40a
+ NT_ARM_PAC_MASK = 0x406
+ NT_ARM_POE = 0x40f
+ NT_ARM_SSVE = 0x40b
+ NT_ARM_SVE = 0x405
+ NT_ARM_SYSTEM_CALL = 0x404
+ NT_ARM_TAGGED_ADDR_CTRL = 0x409
+ NT_ARM_TLS = 0x401
+ NT_ARM_VFP = 0x400
+ NT_ARM_ZA = 0x40c
+ NT_ARM_ZT = 0x40d
+ NT_AUXV = 0x6
+ NT_FILE = 0x46494c45
+ NT_GNU_PROPERTY_TYPE_0 = 0x5
+ NT_LOONGARCH_CPUCFG = 0xa00
+ NT_LOONGARCH_CSR = 0xa01
+ NT_LOONGARCH_HW_BREAK = 0xa05
+ NT_LOONGARCH_HW_WATCH = 0xa06
+ NT_LOONGARCH_LASX = 0xa03
+ NT_LOONGARCH_LBT = 0xa04
+ NT_LOONGARCH_LSX = 0xa02
+ NT_MIPS_DSP = 0x800
+ NT_MIPS_FP_MODE = 0x801
+ NT_MIPS_MSA = 0x802
+ NT_PPC_DEXCR = 0x111
+ NT_PPC_DSCR = 0x105
+ NT_PPC_EBB = 0x106
+ NT_PPC_HASHKEYR = 0x112
+ NT_PPC_PKEY = 0x110
+ NT_PPC_PMU = 0x107
+ NT_PPC_PPR = 0x104
+ NT_PPC_SPE = 0x101
+ NT_PPC_TAR = 0x103
+ NT_PPC_TM_CDSCR = 0x10f
+ NT_PPC_TM_CFPR = 0x109
+ NT_PPC_TM_CGPR = 0x108
+ NT_PPC_TM_CPPR = 0x10e
+ NT_PPC_TM_CTAR = 0x10d
+ NT_PPC_TM_CVMX = 0x10a
+ NT_PPC_TM_CVSX = 0x10b
+ NT_PPC_TM_SPR = 0x10c
+ NT_PPC_VMX = 0x100
+ NT_PPC_VSX = 0x102
+ NT_PRFPREG = 0x2
+ NT_PRPSINFO = 0x3
+ NT_PRSTATUS = 0x1
+ NT_PRXFPREG = 0x46e62b7f
+ NT_RISCV_CSR = 0x900
+ NT_RISCV_TAGGED_ADDR_CTRL = 0x902
+ NT_RISCV_VECTOR = 0x901
+ NT_S390_CTRS = 0x304
+ NT_S390_GS_BC = 0x30c
+ NT_S390_GS_CB = 0x30b
+ NT_S390_HIGH_GPRS = 0x300
+ NT_S390_LAST_BREAK = 0x306
+ NT_S390_PREFIX = 0x305
+ NT_S390_PV_CPU_DATA = 0x30e
+ NT_S390_RI_CB = 0x30d
+ NT_S390_SYSTEM_CALL = 0x307
+ NT_S390_TDB = 0x308
+ NT_S390_TIMER = 0x301
+ NT_S390_TODCMP = 0x302
+ NT_S390_TODPREG = 0x303
+ NT_S390_VXRS_HIGH = 0x30a
+ NT_S390_VXRS_LOW = 0x309
+ NT_SIGINFO = 0x53494749
+ NT_TASKSTRUCT = 0x4
+ NT_VMCOREDD = 0x700
+ NT_X86_SHSTK = 0x204
+ NT_X86_XSAVE_LAYOUT = 0x205
+ NT_X86_XSTATE = 0x202
OCFS2_SUPER_MAGIC = 0x7461636f
OCRNL = 0x8
OFDEL = 0x80
@@ -2463,6 +2699,59 @@ const (
PERF_RECORD_MISC_USER = 0x2
PERF_SAMPLE_BRANCH_PLM_ALL = 0x7
PERF_SAMPLE_WEIGHT_TYPE = 0x1004000
+ PF_ALG = 0x26
+ PF_APPLETALK = 0x5
+ PF_ASH = 0x12
+ PF_ATMPVC = 0x8
+ PF_ATMSVC = 0x14
+ PF_AX25 = 0x3
+ PF_BLUETOOTH = 0x1f
+ PF_BRIDGE = 0x7
+ PF_CAIF = 0x25
+ PF_CAN = 0x1d
+ PF_DECnet = 0xc
+ PF_ECONET = 0x13
+ PF_FILE = 0x1
+ PF_IB = 0x1b
+ PF_IEEE802154 = 0x24
+ PF_INET = 0x2
+ PF_INET6 = 0xa
+ PF_IPX = 0x4
+ PF_IRDA = 0x17
+ PF_ISDN = 0x22
+ PF_IUCV = 0x20
+ PF_KCM = 0x29
+ PF_KEY = 0xf
+ PF_LLC = 0x1a
+ PF_LOCAL = 0x1
+ PF_MAX = 0x2e
+ PF_MCTP = 0x2d
+ PF_MPLS = 0x1c
+ PF_NETBEUI = 0xd
+ PF_NETLINK = 0x10
+ PF_NETROM = 0x6
+ PF_NFC = 0x27
+ PF_PACKET = 0x11
+ PF_PHONET = 0x23
+ PF_PPPOX = 0x18
+ PF_QIPCRTR = 0x2a
+ PF_R = 0x4
+ PF_RDS = 0x15
+ PF_ROSE = 0xb
+ PF_ROUTE = 0x10
+ PF_RXRPC = 0x21
+ PF_SECURITY = 0xe
+ PF_SMC = 0x2b
+ PF_SNA = 0x16
+ PF_TIPC = 0x1e
+ PF_UNIX = 0x1
+ PF_UNSPEC = 0x0
+ PF_VSOCK = 0x28
+ PF_W = 0x2
+ PF_WANPIPE = 0x19
+ PF_X = 0x1
+ PF_X25 = 0x9
+ PF_XDP = 0x2c
PID_FS_MAGIC = 0x50494446
PIPEFS_MAGIC = 0x50495045
PPPIOCGNPMODE = 0xc008744c
@@ -2758,6 +3047,23 @@ const (
PTRACE_SYSCALL_INFO_NONE = 0x0
PTRACE_SYSCALL_INFO_SECCOMP = 0x3
PTRACE_TRACEME = 0x0
+ PT_AARCH64_MEMTAG_MTE = 0x70000002
+ PT_DYNAMIC = 0x2
+ PT_GNU_EH_FRAME = 0x6474e550
+ PT_GNU_PROPERTY = 0x6474e553
+ PT_GNU_RELRO = 0x6474e552
+ PT_GNU_STACK = 0x6474e551
+ PT_HIOS = 0x6fffffff
+ PT_HIPROC = 0x7fffffff
+ PT_INTERP = 0x3
+ PT_LOAD = 0x1
+ PT_LOOS = 0x60000000
+ PT_LOPROC = 0x70000000
+ PT_NOTE = 0x4
+ PT_NULL = 0x0
+ PT_PHDR = 0x6
+ PT_SHLIB = 0x5
+ PT_TLS = 0x7
P_ALL = 0x0
P_PGID = 0x2
P_PID = 0x1
@@ -3091,6 +3397,47 @@ const (
SEEK_MAX = 0x4
SEEK_SET = 0x0
SELINUX_MAGIC = 0xf97cff8c
+ SHF_ALLOC = 0x2
+ SHF_EXCLUDE = 0x8000000
+ SHF_EXECINSTR = 0x4
+ SHF_GROUP = 0x200
+ SHF_INFO_LINK = 0x40
+ SHF_LINK_ORDER = 0x80
+ SHF_MASKOS = 0xff00000
+ SHF_MASKPROC = 0xf0000000
+ SHF_MERGE = 0x10
+ SHF_ORDERED = 0x4000000
+ SHF_OS_NONCONFORMING = 0x100
+ SHF_RELA_LIVEPATCH = 0x100000
+ SHF_RO_AFTER_INIT = 0x200000
+ SHF_STRINGS = 0x20
+ SHF_TLS = 0x400
+ SHF_WRITE = 0x1
+ SHN_ABS = 0xfff1
+ SHN_COMMON = 0xfff2
+ SHN_HIPROC = 0xff1f
+ SHN_HIRESERVE = 0xffff
+ SHN_LIVEPATCH = 0xff20
+ SHN_LOPROC = 0xff00
+ SHN_LORESERVE = 0xff00
+ SHN_UNDEF = 0x0
+ SHT_DYNAMIC = 0x6
+ SHT_DYNSYM = 0xb
+ SHT_HASH = 0x5
+ SHT_HIPROC = 0x7fffffff
+ SHT_HIUSER = 0xffffffff
+ SHT_LOPROC = 0x70000000
+ SHT_LOUSER = 0x80000000
+ SHT_NOBITS = 0x8
+ SHT_NOTE = 0x7
+ SHT_NULL = 0x0
+ SHT_NUM = 0xc
+ SHT_PROGBITS = 0x1
+ SHT_REL = 0x9
+ SHT_RELA = 0x4
+ SHT_SHLIB = 0xa
+ SHT_STRTAB = 0x3
+ SHT_SYMTAB = 0x2
SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
@@ -3317,6 +3664,16 @@ const (
STATX_UID = 0x8
STATX_WRITE_ATOMIC = 0x10000
STATX__RESERVED = 0x80000000
+ STB_GLOBAL = 0x1
+ STB_LOCAL = 0x0
+ STB_WEAK = 0x2
+ STT_COMMON = 0x5
+ STT_FILE = 0x4
+ STT_FUNC = 0x2
+ STT_NOTYPE = 0x0
+ STT_OBJECT = 0x1
+ STT_SECTION = 0x3
+ STT_TLS = 0x6
SYNC_FILE_RANGE_WAIT_AFTER = 0x4
SYNC_FILE_RANGE_WAIT_BEFORE = 0x1
SYNC_FILE_RANGE_WRITE = 0x2
@@ -3553,6 +3910,8 @@ const (
UTIME_OMIT = 0x3ffffffe
V9FS_MAGIC = 0x1021997
VERASE = 0x2
+ VER_FLG_BASE = 0x1
+ VER_FLG_WEAK = 0x2
VINTR = 0x0
VKILL = 0x3
VLNEXT = 0xf
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go
index 5cc1e8eb2f..8935d10a31 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go
@@ -2238,3 +2238,13 @@ func Mseal(b []byte, flags uint) (err error) {
}
return
}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setMemPolicy(mode int, mask *CPUSet, size int) (err error) {
+ _, _, e1 := Syscall(SYS_SET_MEMPOLICY, uintptr(mode), uintptr(unsafe.Pointer(mask)), uintptr(size))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
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 944e75a11c..c1a4670171 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
@@ -3590,6 +3590,8 @@ type Nhmsg struct {
Flags uint32
}
+const SizeofNhmsg = 0x8
+
type NexthopGrp struct {
Id uint32
Weight uint8
@@ -3597,6 +3599,8 @@ type NexthopGrp struct {
Resvd2 uint16
}
+const SizeofNexthopGrp = 0x8
+
const (
NHA_UNSPEC = 0x0
NHA_ID = 0x1
@@ -6332,3 +6336,30 @@ type SockDiagReq struct {
}
const RTM_NEWNVLAN = 0x70
+
+const (
+ MPOL_BIND = 0x2
+ MPOL_DEFAULT = 0x0
+ MPOL_F_ADDR = 0x2
+ MPOL_F_MEMS_ALLOWED = 0x4
+ MPOL_F_MOF = 0x8
+ MPOL_F_MORON = 0x10
+ MPOL_F_NODE = 0x1
+ MPOL_F_NUMA_BALANCING = 0x2000
+ MPOL_F_RELATIVE_NODES = 0x4000
+ MPOL_F_SHARED = 0x1
+ MPOL_F_STATIC_NODES = 0x8000
+ MPOL_INTERLEAVE = 0x3
+ MPOL_LOCAL = 0x4
+ MPOL_MAX = 0x7
+ MPOL_MF_INTERNAL = 0x10
+ MPOL_MF_LAZY = 0x8
+ MPOL_MF_MOVE_ALL = 0x4
+ MPOL_MF_MOVE = 0x2
+ MPOL_MF_STRICT = 0x1
+ MPOL_MF_VALID = 0x7
+ MPOL_MODE_FLAGS = 0xe000
+ MPOL_PREFERRED = 0x1
+ MPOL_PREFERRED_MANY = 0x5
+ MPOL_WEIGHTED_INTERLEAVE = 0x6
+)
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 bd51337306..69439df2a4 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
@@ -892,8 +892,12 @@ const socket_error = uintptr(^uint32(0))
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
//sys getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcode error) = iphlpapi.GetBestInterfaceEx
//sys GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) = iphlpapi.GetIfEntry2Ex
+//sys GetIpForwardEntry2(row *MibIpForwardRow2) (errcode error) = iphlpapi.GetIpForwardEntry2
+//sys GetIpForwardTable2(family uint16, table **MibIpForwardTable2) (errcode error) = iphlpapi.GetIpForwardTable2
//sys GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) = iphlpapi.GetUnicastIpAddressEntry
+//sys FreeMibTable(memory unsafe.Pointer) = iphlpapi.FreeMibTable
//sys NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyIpInterfaceChange
+//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
@@ -916,6 +920,17 @@ type RawSockaddrInet6 struct {
Scope_id uint32
}
+// RawSockaddrInet is a union that contains an IPv4, an IPv6 address, or an address family. See
+// https://learn.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-sockaddr_inet.
+//
+// A [*RawSockaddrInet] may be converted to a [*RawSockaddrInet4] or [*RawSockaddrInet6] using
+// unsafe, depending on the address family.
+type RawSockaddrInet struct {
+ Family uint16
+ Port uint16
+ Data [6]uint32
+}
+
type RawSockaddr struct {
Family uint16
Data [14]int8
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 358be3c7f5..6e4f50eb48 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
@@ -2320,6 +2320,82 @@ type MibIfRow2 struct {
OutQLen uint64
}
+// IP_ADDRESS_PREFIX stores an IP address prefix. See
+// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-ip_address_prefix.
+type IpAddressPrefix struct {
+ Prefix RawSockaddrInet
+ PrefixLength uint8
+}
+
+// NL_ROUTE_ORIGIN enumeration from nldef.h or
+// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_route_origin.
+const (
+ NlroManual = 0
+ NlroWellKnown = 1
+ NlroDHCP = 2
+ NlroRouterAdvertisement = 3
+ Nlro6to4 = 4
+)
+
+// NL_ROUTE_ORIGIN enumeration from nldef.h or
+// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_route_protocol.
+const (
+ MIB_IPPROTO_OTHER = 1
+ MIB_IPPROTO_LOCAL = 2
+ MIB_IPPROTO_NETMGMT = 3
+ MIB_IPPROTO_ICMP = 4
+ MIB_IPPROTO_EGP = 5
+ MIB_IPPROTO_GGP = 6
+ MIB_IPPROTO_HELLO = 7
+ MIB_IPPROTO_RIP = 8
+ MIB_IPPROTO_IS_IS = 9
+ MIB_IPPROTO_ES_IS = 10
+ MIB_IPPROTO_CISCO = 11
+ MIB_IPPROTO_BBN = 12
+ MIB_IPPROTO_OSPF = 13
+ MIB_IPPROTO_BGP = 14
+ MIB_IPPROTO_IDPR = 15
+ MIB_IPPROTO_EIGRP = 16
+ MIB_IPPROTO_DVMRP = 17
+ MIB_IPPROTO_RPL = 18
+ MIB_IPPROTO_DHCP = 19
+ MIB_IPPROTO_NT_AUTOSTATIC = 10002
+ MIB_IPPROTO_NT_STATIC = 10006
+ MIB_IPPROTO_NT_STATIC_NON_DOD = 10007
+)
+
+// MIB_IPFORWARD_ROW2 stores information about an IP route entry. See
+// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipforward_row2.
+type MibIpForwardRow2 struct {
+ InterfaceLuid uint64
+ InterfaceIndex uint32
+ DestinationPrefix IpAddressPrefix
+ NextHop RawSockaddrInet
+ SitePrefixLength uint8
+ ValidLifetime uint32
+ PreferredLifetime uint32
+ Metric uint32
+ Protocol uint32
+ Loopback uint8
+ AutoconfigureAddress uint8
+ Publish uint8
+ Immortal uint8
+ Age uint32
+ Origin uint32
+}
+
+// MIB_IPFORWARD_TABLE2 contains a table of IP route entries. See
+// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipforward_table2.
+type MibIpForwardTable2 struct {
+ NumEntries uint32
+ Table [1]MibIpForwardRow2
+}
+
+// Rows returns the IP route entries in the table.
+func (t *MibIpForwardTable2) Rows() []MibIpForwardRow2 {
+ return unsafe.Slice(&t.Table[0], t.NumEntries)
+}
+
// MIB_UNICASTIPADDRESS_ROW stores information about a unicast IP address. See
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_unicastipaddress_row.
type MibUnicastIpAddressRow struct {
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 426151a019..f25b7308a1 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
@@ -182,13 +182,17 @@ var (
procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute")
procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
procCancelMibChangeNotify2 = modiphlpapi.NewProc("CancelMibChangeNotify2")
+ procFreeMibTable = modiphlpapi.NewProc("FreeMibTable")
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
procGetBestInterfaceEx = modiphlpapi.NewProc("GetBestInterfaceEx")
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
procGetIfEntry2Ex = modiphlpapi.NewProc("GetIfEntry2Ex")
+ procGetIpForwardEntry2 = modiphlpapi.NewProc("GetIpForwardEntry2")
+ procGetIpForwardTable2 = modiphlpapi.NewProc("GetIpForwardTable2")
procGetUnicastIpAddressEntry = modiphlpapi.NewProc("GetUnicastIpAddressEntry")
procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange")
+ procNotifyRouteChange2 = modiphlpapi.NewProc("NotifyRouteChange2")
procNotifyUnicastIpAddressChange = modiphlpapi.NewProc("NotifyUnicastIpAddressChange")
procAddDllDirectory = modkernel32.NewProc("AddDllDirectory")
procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject")
@@ -1624,6 +1628,11 @@ func CancelMibChangeNotify2(notificationHandle Handle) (errcode error) {
return
}
+func FreeMibTable(memory unsafe.Pointer) {
+ syscall.SyscallN(procFreeMibTable.Addr(), uintptr(memory))
+ return
+}
+
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
r0, _, _ := syscall.SyscallN(procGetAdaptersAddresses.Addr(), uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)))
if r0 != 0 {
@@ -1664,6 +1673,22 @@ func GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) {
return
}
+func GetIpForwardEntry2(row *MibIpForwardRow2) (errcode error) {
+ r0, _, _ := syscall.SyscallN(procGetIpForwardEntry2.Addr(), uintptr(unsafe.Pointer(row)))
+ if r0 != 0 {
+ errcode = syscall.Errno(r0)
+ }
+ return
+}
+
+func GetIpForwardTable2(family uint16, table **MibIpForwardTable2) (errcode error) {
+ r0, _, _ := syscall.SyscallN(procGetIpForwardTable2.Addr(), uintptr(family), uintptr(unsafe.Pointer(table)))
+ if r0 != 0 {
+ errcode = syscall.Errno(r0)
+ }
+ return
+}
+
func GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) {
r0, _, _ := syscall.SyscallN(procGetUnicastIpAddressEntry.Addr(), uintptr(unsafe.Pointer(row)))
if r0 != 0 {
@@ -1684,6 +1709,18 @@ func NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsa
return
}
+func NotifyRouteChange2(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
+ var _p0 uint32
+ if initialNotification {
+ _p0 = 1
+ }
+ r0, _, _ := syscall.SyscallN(procNotifyRouteChange2.Addr(), uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)))
+ if r0 != 0 {
+ errcode = syscall.Errno(r0)
+ }
+ return
+}
+
func NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
var _p0 uint32
if initialNotification {
diff --git a/src/cmd/vendor/golang.org/x/telemetry/codereview.cfg b/src/cmd/vendor/golang.org/x/telemetry/codereview.cfg
new file mode 100644
index 0000000000..3f8b14b64e
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/telemetry/codereview.cfg
@@ -0,0 +1 @@
+issuerepo: golang/go
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go
index f6118bec64..527540c62c 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go
@@ -33,8 +33,9 @@ type Diagnostic struct {
URL string
// SuggestedFixes is an optional list of fixes to address the
- // problem described by the diagnostic. Each one represents
- // an alternative strategy; at most one may be applied.
+ // problem described by the diagnostic. Each one represents an
+ // alternative strategy, and should have a distinct and
+ // descriptive message; at most one may be applied.
//
// Fixes for different diagnostics should be treated as
// independent changes to the same baseline file state,
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 ffc4169083..c7637df00a 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
@@ -13,22 +13,20 @@ import (
"encoding/json"
"flag"
"fmt"
- "go/token"
"io"
"log"
"os"
"strconv"
- "strings"
"golang.org/x/tools/go/analysis"
)
// flags common to all {single,multi,unit}checkers.
var (
- JSON = false // -json
- Context = -1 // -c=N: if N>0, display offending line plus N lines of context
- Fix bool // -fix
- diffFlag bool // -diff (changes [ApplyFixes] behavior)
+ JSON = false // -json
+ Context = -1 // -c=N: if N>0, display offending line plus N lines of context
+ Fix bool // -fix
+ Diff bool // -diff
)
// Parse creates a flag for each of the analyzer's flags,
@@ -78,7 +76,7 @@ func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer {
flag.BoolVar(&JSON, "json", JSON, "emit JSON output")
flag.IntVar(&Context, "c", Context, `display offending line with this many lines of context`)
flag.BoolVar(&Fix, "fix", false, "apply all suggested fixes")
- flag.BoolVar(&diffFlag, "diff", false, "with -fix, don't update the files, but print a unified diff")
+ flag.BoolVar(&Diff, "diff", false, "with -fix, don't update the files, but print a unified diff")
// Add shims for legacy vet flags to enable existing
// scripts that run vet to continue to work.
@@ -310,150 +308,3 @@ var vetLegacyFlags = map[string]string{
"unusedfuncs": "unusedresult.funcs",
"unusedstringmethods": "unusedresult.stringmethods",
}
-
-// ---- output helpers common to all drivers ----
-//
-// These functions should not depend on global state (flags)!
-// Really they belong in a different package.
-
-// TODO(adonovan): don't accept an io.Writer if we don't report errors.
-// Either accept a bytes.Buffer (infallible), or return a []byte.
-
-// PrintPlain prints a diagnostic in plain text form.
-// If contextLines is nonnegative, it also prints the
-// offending line plus this many lines of context.
-func PrintPlain(out io.Writer, fset *token.FileSet, contextLines int, diag analysis.Diagnostic) {
- print := func(pos, end token.Pos, message string) {
- posn := fset.Position(pos)
- fmt.Fprintf(out, "%s: %s\n", posn, message)
-
- // show offending line plus N lines of context.
- if contextLines >= 0 {
- end := fset.Position(end)
- if !end.IsValid() {
- end = posn
- }
- // TODO(adonovan): highlight the portion of the line indicated
- // by pos...end using ASCII art, terminal colors, etc?
- data, _ := os.ReadFile(posn.Filename)
- lines := strings.Split(string(data), "\n")
- for i := posn.Line - contextLines; i <= end.Line+contextLines; i++ {
- if 1 <= i && i <= len(lines) {
- fmt.Fprintf(out, "%d\t%s\n", i, lines[i-1])
- }
- }
- }
- }
-
- print(diag.Pos, diag.End, diag.Message)
- for _, rel := range diag.Related {
- print(rel.Pos, rel.End, "\t"+rel.Message)
- }
-}
-
-// A JSONTree is a mapping from package ID to analysis name to result.
-// Each result is either a jsonError or a list of JSONDiagnostic.
-type JSONTree map[string]map[string]any
-
-// A TextEdit describes the replacement of a portion of a file.
-// Start and End are zero-based half-open indices into the original byte
-// sequence of the file, and New is the new text.
-type JSONTextEdit struct {
- Filename string `json:"filename"`
- Start int `json:"start"`
- End int `json:"end"`
- New string `json:"new"`
-}
-
-// A JSONSuggestedFix describes an edit that should be applied as a whole or not
-// at all. It might contain multiple TextEdits/text_edits if the SuggestedFix
-// consists of multiple non-contiguous edits.
-type JSONSuggestedFix struct {
- Message string `json:"message"`
- Edits []JSONTextEdit `json:"edits"`
-}
-
-// A JSONDiagnostic describes the JSON schema of an analysis.Diagnostic.
-//
-// TODO(matloob): include End position if present.
-type JSONDiagnostic struct {
- Category string `json:"category,omitempty"`
- Posn string `json:"posn"` // e.g. "file.go:line:column"
- Message string `json:"message"`
- SuggestedFixes []JSONSuggestedFix `json:"suggested_fixes,omitempty"`
- Related []JSONRelatedInformation `json:"related,omitempty"`
-}
-
-// A JSONRelated describes a secondary position and message related to
-// a primary diagnostic.
-//
-// TODO(adonovan): include End position if present.
-type JSONRelatedInformation struct {
- Posn string `json:"posn"` // e.g. "file.go:line:column"
- Message string `json:"message"`
-}
-
-// Add adds the result of analysis 'name' on package 'id'.
-// The result is either a list of diagnostics or an error.
-func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.Diagnostic, err error) {
- var v any
- if err != nil {
- type jsonError struct {
- Err string `json:"error"`
- }
- v = jsonError{err.Error()}
- } else if len(diags) > 0 {
- diagnostics := make([]JSONDiagnostic, 0, len(diags))
- for _, f := range diags {
- var fixes []JSONSuggestedFix
- for _, fix := range f.SuggestedFixes {
- var edits []JSONTextEdit
- for _, edit := range fix.TextEdits {
- edits = append(edits, JSONTextEdit{
- Filename: fset.Position(edit.Pos).Filename,
- Start: fset.Position(edit.Pos).Offset,
- End: fset.Position(edit.End).Offset,
- New: string(edit.NewText),
- })
- }
- fixes = append(fixes, JSONSuggestedFix{
- Message: fix.Message,
- Edits: edits,
- })
- }
- var related []JSONRelatedInformation
- for _, r := range f.Related {
- related = append(related, JSONRelatedInformation{
- Posn: fset.Position(r.Pos).String(),
- Message: r.Message,
- })
- }
- jdiag := JSONDiagnostic{
- Category: f.Category,
- Posn: fset.Position(f.Pos).String(),
- Message: f.Message,
- SuggestedFixes: fixes,
- Related: related,
- }
- diagnostics = append(diagnostics, jdiag)
- }
- v = diagnostics
- }
- if v != nil {
- m, ok := tree[id]
- if !ok {
- m = make(map[string]any)
- tree[id] = m
- }
- m[name] = v
- }
-}
-
-func (tree JSONTree) Print(out io.Writer) error {
- data, err := json.MarshalIndent(tree, "", "\t")
- if err != nil {
- log.Panicf("internal error: JSON marshaling failed: %v", err)
- }
- _, err = fmt.Fprintf(out, "%s\n", data)
- return err
-}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
index b4e91edce3..8ccf982d23 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
@@ -15,7 +15,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
)
//go:embed doc.go
@@ -23,7 +23,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "appends",
- Doc: analysisinternal.MustExtractDoc(doc, "appends"),
+ Doc: analyzerutil.MustExtractDoc(doc, "appends"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/appends",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
index e9c0879844..ba9ca38a81 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
@@ -19,7 +19,7 @@ import (
"strings"
"golang.org/x/tools/go/analysis"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
)
const Doc = "report mismatches between assembly files and Go declarations"
@@ -175,7 +175,7 @@ func run(pass *analysis.Pass) (any, error) {
Files:
for _, fname := range sfiles {
- content, tf, err := analysisinternal.ReadFile(pass, fname)
+ content, tf, err := analyzerutil.ReadFile(pass, fname)
if err != nil {
return nil, err
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
index 8080aed020..69734df825 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
@@ -18,7 +18,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
+ "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"
@@ -29,7 +29,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "assign",
- Doc: analysisinternal.MustExtractDoc(doc, "assign"),
+ Doc: analyzerutil.MustExtractDoc(doc, "assign"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/assign",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
index 9faa3f67c1..c6ab7ff7a2 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
@@ -13,7 +13,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -23,7 +23,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "atomic",
- Doc: analysisinternal.MustExtractDoc(doc, "atomic"),
+ Doc: analyzerutil.MustExtractDoc(doc, "atomic"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomic",
Requires: []*analysis.Analyzer{inspect.Analyzer},
RunDespiteErrors: true,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go
index 7dd4f249e2..d0b28e5b84 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go
@@ -14,7 +14,7 @@ import (
"unicode"
"golang.org/x/tools/go/analysis"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
)
const Doc = "check //go:build and // +build directives"
@@ -86,7 +86,7 @@ func checkOtherFile(pass *analysis.Pass, filename string) error {
// We cannot use the Go parser, since this may not be a Go source file.
// Read the raw bytes instead.
- content, tf, err := analysisinternal.ReadFile(pass, filename)
+ content, tf, err := analyzerutil.ReadFile(pass, filename)
if err != nil {
return err
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
index bf1202b92b..54b8062cc0 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
@@ -350,8 +350,8 @@ func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool {
case *types.Array:
return typeOKForCgoCall(t.Elem(), m)
case *types.Struct:
- for i := 0; i < t.NumFields(); i++ {
- if !typeOKForCgoCall(t.Field(i).Type(), m) {
+ for field := range t.Fields() {
+ if !typeOKForCgoCall(field.Type(), m) {
return false
}
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
index 4190cc5900..208602f486 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
@@ -328,8 +328,8 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ
ttyp, ok := typ.Underlying().(*types.Tuple)
if ok {
- for i := 0; i < ttyp.Len(); i++ {
- subpath := lockPath(tpkg, ttyp.At(i).Type(), seen)
+ for v := range ttyp.Variables() {
+ subpath := lockPath(tpkg, v.Type(), seen)
if subpath != nil {
return append(subpath, typ.String())
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go
index 951aaed00f..d6c2586e73 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go
@@ -16,9 +16,12 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/analysis/passes/internal/ctrlflowinternal"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/cfg"
"golang.org/x/tools/go/types/typeutil"
+ "golang.org/x/tools/internal/cfginternal"
+ "golang.org/x/tools/internal/typesinternal"
)
var Analyzer = &analysis.Analyzer{
@@ -26,7 +29,7 @@ var Analyzer = &analysis.Analyzer{
Doc: "build a control-flow graph",
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ctrlflow",
Run: run,
- ResultType: reflect.TypeOf(new(CFGs)),
+ ResultType: reflect.TypeFor[*CFGs](),
FactTypes: []analysis.Fact{new(noReturn)},
Requires: []*analysis.Analyzer{inspect.Analyzer},
}
@@ -44,7 +47,20 @@ type CFGs struct {
defs map[*ast.Ident]types.Object // from Pass.TypesInfo.Defs
funcDecls map[*types.Func]*declInfo
funcLits map[*ast.FuncLit]*litInfo
- pass *analysis.Pass // transient; nil after construction
+ noReturn map[*types.Func]bool // functions lacking a reachable return statement
+ pass *analysis.Pass // transient; nil after construction
+}
+
+// TODO(adonovan): add (*CFGs).NoReturn to public API.
+func (c *CFGs) isNoReturn(fn *types.Func) bool {
+ return c.noReturn[fn]
+}
+
+func init() {
+ // Expose the hidden method to callers in x/tools.
+ ctrlflowinternal.NoReturn = func(c any, fn *types.Func) bool {
+ return c.(*CFGs).isNoReturn(fn)
+ }
}
// CFGs has two maps: funcDecls for named functions and funcLits for
@@ -54,15 +70,14 @@ type CFGs struct {
// *types.Func but not the other way.
type declInfo struct {
- decl *ast.FuncDecl
- cfg *cfg.CFG // iff decl.Body != nil
- started bool // to break cycles
- noReturn bool
+ decl *ast.FuncDecl
+ cfg *cfg.CFG // iff decl.Body != nil
+ started bool // to break cycles
}
type litInfo struct {
cfg *cfg.CFG
- noReturn bool
+ noReturn bool // (currently unused)
}
// FuncDecl returns the control-flow graph for a named function.
@@ -118,6 +133,7 @@ func run(pass *analysis.Pass) (any, error) {
defs: pass.TypesInfo.Defs,
funcDecls: funcDecls,
funcLits: funcLits,
+ noReturn: make(map[*types.Func]bool),
pass: pass,
}
@@ -138,7 +154,7 @@ func run(pass *analysis.Pass) (any, error) {
li := funcLits[lit]
if li.cfg == nil {
li.cfg = cfg.New(lit.Body, c.callMayReturn)
- if !hasReachableReturn(li.cfg) {
+ if cfginternal.IsNoReturn(li.cfg) {
li.noReturn = true
}
}
@@ -158,27 +174,28 @@ func (c *CFGs) buildDecl(fn *types.Func, di *declInfo) {
// The buildDecl call tree thus resembles the static call graph.
// We mark each node when we start working on it to break cycles.
- if !di.started { // break cycle
- di.started = true
+ if di.started {
+ return // break cycle
+ }
+ di.started = true
- if isIntrinsicNoReturn(fn) {
- di.noReturn = true
- }
- if di.decl.Body != nil {
- di.cfg = cfg.New(di.decl.Body, c.callMayReturn)
- if !hasReachableReturn(di.cfg) {
- di.noReturn = true
- }
- }
- if di.noReturn {
- c.pass.ExportObjectFact(fn, new(noReturn))
- }
+ noreturn := isIntrinsicNoReturn(fn)
- // debugging
- if false {
- log.Printf("CFG for %s:\n%s (noreturn=%t)\n", fn, di.cfg.Format(c.pass.Fset), di.noReturn)
+ if di.decl.Body != nil {
+ di.cfg = cfg.New(di.decl.Body, c.callMayReturn)
+ if cfginternal.IsNoReturn(di.cfg) {
+ noreturn = true
}
}
+ if noreturn {
+ c.pass.ExportObjectFact(fn, new(noReturn))
+ c.noReturn[fn] = true
+ }
+
+ // debugging
+ if false {
+ log.Printf("CFG for %s:\n%s (noreturn=%t)\n", fn, di.cfg.Format(c.pass.Fset), noreturn)
+ }
}
// callMayReturn reports whether the called function may return.
@@ -201,31 +218,26 @@ func (c *CFGs) callMayReturn(call *ast.CallExpr) (r bool) {
// Function or method declared in this package?
if di, ok := c.funcDecls[fn]; ok {
c.buildDecl(fn, di)
- return !di.noReturn
+ return !c.noReturn[fn]
}
// Not declared in this package.
// Is there a fact from another package?
- return !c.pass.ImportObjectFact(fn, new(noReturn))
+ if c.pass.ImportObjectFact(fn, new(noReturn)) {
+ c.noReturn[fn] = true
+ return false
+ }
+
+ return true
}
var panicBuiltin = types.Universe.Lookup("panic").(*types.Builtin)
-func hasReachableReturn(g *cfg.CFG) bool {
- for _, b := range g.Blocks {
- if b.Live && b.Return() != nil {
- return true
- }
- }
- return false
-}
-
// isIntrinsicNoReturn reports whether a function intrinsically never
// returns because it stops execution of the calling thread.
// It is the base case in the recursion.
func isIntrinsicNoReturn(fn *types.Func) bool {
// Add functions here as the need arises, but don't allocate memory.
- path, name := fn.Pkg().Path(), fn.Name()
- return path == "syscall" && (name == "Exit" || name == "ExitProcess" || name == "ExitThread") ||
- path == "runtime" && name == "Goexit"
+ return typesinternal.IsFunctionNamed(fn, "syscall", "Exit", "ExitProcess", "ExitThread") ||
+ typesinternal.IsFunctionNamed(fn, "runtime", "Goexit")
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
index 3069ee9fec..af93407cae 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
@@ -12,7 +12,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -23,7 +23,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "defers",
Requires: []*analysis.Analyzer{inspect.Analyzer},
- Doc: analysisinternal.MustExtractDoc(doc, "defers"),
+ Doc: analyzerutil.MustExtractDoc(doc, "defers"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/defers",
Run: run,
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go
index c84d25842e..5fa28861e5 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go
@@ -14,7 +14,7 @@ import (
"unicode/utf8"
"golang.org/x/tools/go/analysis"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
)
const Doc = `check Go toolchain directives such as //go:debug
@@ -86,7 +86,7 @@ func checkGoFile(pass *analysis.Pass, f *ast.File) {
func checkOtherFile(pass *analysis.Pass, filename string) error {
// We cannot use the Go parser, since is not a Go source file.
// Read the raw bytes instead.
- content, tf, err := analysisinternal.ReadFile(pass, filename)
+ content, tf, err := analyzerutil.ReadFile(pass, filename)
if err != nil {
return err
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
index b3df99929d..f1465f7343 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
@@ -12,7 +12,7 @@ import (
"go/types"
"golang.org/x/tools/go/analysis"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go
index 809095d40a..a7d558103a 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go
@@ -13,7 +13,7 @@ import (
"unicode"
"golang.org/x/tools/go/analysis"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
)
const Doc = "report assembly that clobbers the frame pointer before saving it"
@@ -98,7 +98,7 @@ func run(pass *analysis.Pass) (any, error) {
}
for _, fname := range sfiles {
- content, tf, err := analysisinternal.ReadFile(pass, fname)
+ content, tf, err := analyzerutil.ReadFile(pass, fname)
if err != nil {
return nil, err
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/hostport/hostport.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/hostport/hostport.go
index 07f154963e..d41a0e4cbf 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/hostport/hostport.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/hostport/hostport.go
@@ -17,7 +17,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/types/typeutil"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go
index a6dcf1cf8e..da0acbd8e2 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go
@@ -12,7 +12,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typeparams"
)
@@ -21,7 +21,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "ifaceassert",
- Doc: analysisinternal.MustExtractDoc(doc, "ifaceassert"),
+ Doc: analyzerutil.MustExtractDoc(doc, "ifaceassert"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ifaceassert",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/gofix.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go
index 629d5d8526..1b3cb108c6 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/gofix.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go
@@ -20,9 +20,10 @@ import (
"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/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/diff"
+ "golang.org/x/tools/internal/moreiters"
"golang.org/x/tools/internal/packagepath"
"golang.org/x/tools/internal/refactor"
"golang.org/x/tools/internal/refactor/inline"
@@ -34,7 +35,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "inline",
- Doc: analysisinternal.MustExtractDoc(doc, "inline"),
+ Doc: analyzerutil.MustExtractDoc(doc, "inline"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/inline",
Run: run,
FactTypes: []analysis.Fact{
@@ -132,8 +133,6 @@ func (a *analyzer) HandleConst(nameIdent, rhsIdent *ast.Ident) {
// inline inlines each static call to an inlinable function
// and each reference to an inlinable constant or type alias.
-//
-// TODO(adonovan): handle multiple diffs that each add the same import.
func (a *analyzer) inline() {
for cur := range a.root.Preorder((*ast.CallExpr)(nil), (*ast.Ident)(nil)) {
switch n := cur.Node().(type) {
@@ -167,6 +166,10 @@ func (a *analyzer) inlineCall(call *ast.CallExpr, cur inspector.Cursor) {
return // nope
}
+ if a.withinTestOf(cur, fn) {
+ return // don't inline a function from within its own test
+ }
+
// Inline the call.
content, err := a.readFile(call)
if err != nil {
@@ -229,6 +232,44 @@ func (a *analyzer) inlineCall(call *ast.CallExpr, cur inspector.Cursor) {
}
}
+// withinTestOf reports whether cur is within a dedicated test
+// function for the inlinable target function.
+// A call within its dedicated test should not be inlined.
+func (a *analyzer) withinTestOf(cur inspector.Cursor, target *types.Func) bool {
+ curFuncDecl, ok := moreiters.First(cur.Enclosing((*ast.FuncDecl)(nil)))
+ if !ok {
+ return false // not in a function
+ }
+ funcDecl := curFuncDecl.Node().(*ast.FuncDecl)
+ if funcDecl.Recv != nil {
+ return false // not a test func
+ }
+ if strings.TrimSuffix(a.pass.Pkg.Path(), "_test") != target.Pkg().Path() {
+ return false // different package
+ }
+ if !strings.HasSuffix(a.pass.Fset.File(funcDecl.Pos()).Name(), "_test.go") {
+ return false // not a test file
+ }
+
+ // Computed expected SYMBOL portion of "TestSYMBOL_comment"
+ // for the target symbol.
+ symbol := target.Name()
+ if recv := target.Signature().Recv(); recv != nil {
+ _, named := typesinternal.ReceiverNamed(recv)
+ symbol = named.Obj().Name() + "_" + symbol
+ }
+
+ // TODO(adonovan): use a proper Test function parser.
+ fname := funcDecl.Name.Name
+ for _, pre := range []string{"Test", "Example", "Bench"} {
+ if fname == pre+symbol || strings.HasPrefix(fname, pre+symbol+"_") {
+ return true
+ }
+ }
+
+ return false
+}
+
// If tn is the TypeName of an inlinable alias, suggest inlining its use at cur.
func (a *analyzer) inlineAlias(tn *types.TypeName, curId inspector.Cursor) {
inalias, ok := a.inlinableAliases[tn]
@@ -375,8 +416,8 @@ func typenames(t types.Type) []*types.TypeName {
visit(t.Key())
visit(t.Elem())
case *types.Struct:
- for i := range t.NumFields() {
- visit(t.Field(i).Type())
+ for field := range t.Fields() {
+ visit(field.Type())
}
case *types.Signature:
// Ignore the receiver: although it may be present, it has no meaning
@@ -389,11 +430,11 @@ func typenames(t types.Type) []*types.TypeName {
visit(t.Params())
visit(t.Results())
case *types.Interface:
- for i := range t.NumEmbeddeds() {
- visit(t.EmbeddedType(i))
+ for etyp := range t.EmbeddedTypes() {
+ visit(etyp)
}
- for i := range t.NumExplicitMethods() {
- visit(t.ExplicitMethod(i).Type())
+ for method := range t.ExplicitMethods() {
+ visit(method.Type())
}
case *types.Tuple:
for v := range t.Variables() {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
index ee1972f56d..aae5d255f9 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
@@ -41,7 +41,7 @@ var Analyzer = &analysis.Analyzer{
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/inspect",
Run: run,
RunDespiteErrors: true,
- ResultType: reflect.TypeOf(new(inspector.Inspector)),
+ ResultType: reflect.TypeFor[*inspector.Inspector](),
}
func run(pass *analysis.Pass) (any, error) {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/ctrlflowinternal/ctrlflowinternal.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/ctrlflowinternal/ctrlflowinternal.go
new file mode 100644
index 0000000000..ee7a37228e
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/ctrlflowinternal/ctrlflowinternal.go
@@ -0,0 +1,17 @@
+// Copyright 2025 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 ctrlflowinternal exposes internals of ctrlflow.
+// It cannot actually depend on symbols from ctrlflow.
+package ctrlflowinternal
+
+import "go/types"
+
+// NoReturn exposes the (*ctrlflow.CFGs).NoReturn method to the buildssa analyzer.
+//
+// You must link [golang.org/x/tools/go/analysis/passes/ctrlflow] into your
+// application for it to be non-nil.
+var NoReturn = func(cfgs any, fn *types.Func) bool {
+ panic("x/tools/go/analysis/passes/ctrlflow is not linked into this application")
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
index 868226328f..41b19d7933 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
@@ -13,7 +13,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typesinternal"
"golang.org/x/tools/internal/versions"
)
@@ -23,7 +23,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "loopclosure",
- Doc: analysisinternal.MustExtractDoc(doc, "loopclosure"),
+ Doc: analyzerutil.MustExtractDoc(doc, "loopclosure"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/loopclosure",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
@@ -55,8 +55,8 @@ func run(pass *analysis.Pass) (any, error) {
switch n := n.(type) {
case *ast.File:
// Only traverse the file if its goversion is strictly before go1.22.
- goversion := versions.FileVersion(pass.TypesInfo, n)
- return versions.Before(goversion, versions.Go1_22)
+ return !analyzerutil.FileUsesGoVersion(pass, n, versions.Go1_22)
+
case *ast.RangeStmt:
body = n.Body
addVar(n.Key)
@@ -308,12 +308,11 @@ func parallelSubtest(info *types.Info, call *ast.CallExpr) []ast.Stmt {
if !ok {
continue
}
- expr := exprStmt.X
- if isMethodCall(info, expr, "testing", "T", "Parallel") {
- call, _ := expr.(*ast.CallExpr)
- if call == nil {
- continue
- }
+ call, ok := exprStmt.X.(*ast.CallExpr)
+ if !ok {
+ continue
+ }
+ if isMethodCall(info, call, "testing", "T", "Parallel") {
x, _ := call.Fun.(*ast.SelectorExpr)
if x == nil {
continue
@@ -347,26 +346,6 @@ func unlabel(stmt ast.Stmt) (ast.Stmt, bool) {
}
}
-// isMethodCall reports whether expr is a method call of
-// <pkgPath>.<typeName>.<method>.
-func isMethodCall(info *types.Info, expr ast.Expr, pkgPath, typeName, method string) bool {
- call, ok := expr.(*ast.CallExpr)
- if !ok {
- return false
- }
-
- // Check that we are calling a method <method>
- f := typeutil.StaticCallee(info, call)
- if f == nil || f.Name() != method {
- return false
- }
- recv := f.Type().(*types.Signature).Recv()
- if recv == nil {
- return false
- }
-
- // Check that the receiver is a <pkgPath>.<typeName> or
- // *<pkgPath>.<typeName>.
- _, named := typesinternal.ReceiverNamed(recv)
- return typesinternal.IsTypeNamed(named, pkgPath, typeName)
+func isMethodCall(info *types.Info, call *ast.CallExpr, pkgPath, typeName, method string) bool {
+ return typesinternal.IsMethodNamed(typeutil.Callee(info, call), pkgPath, typeName, method)
}
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 dfaecf51e2..28a5f6cd93 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
@@ -15,7 +15,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/cfg"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -25,7 +25,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "lostcancel",
- Doc: analysisinternal.MustExtractDoc(doc, "lostcancel"),
+ Doc: analyzerutil.MustExtractDoc(doc, "lostcancel"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/lostcancel",
Run: run,
Requires: []*analysis.Analyzer{
@@ -316,8 +316,8 @@ outer:
}
func tupleContains(tuple *types.Tuple, v *types.Var) bool {
- for i := 0; i < tuple.Len(); i++ {
- if tuple.At(i) == v {
+ for v0 := range tuple.Variables() {
+ if v0 == v {
return true
}
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/any.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/any.go
index 05999f8f2b..579ab865da 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/any.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/any.go
@@ -9,29 +9,21 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
- "golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
+ "golang.org/x/tools/internal/versions"
)
var AnyAnalyzer = &analysis.Analyzer{
- Name: "any",
- Doc: analysisinternal.MustExtractDoc(doc, "any"),
- Requires: []*analysis.Analyzer{
- generated.Analyzer,
- inspect.Analyzer,
- },
- Run: runAny,
- URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#any",
+ Name: "any",
+ Doc: analyzerutil.MustExtractDoc(doc, "any"),
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: runAny,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#any",
}
// The any pass replaces interface{} with go1.18's 'any'.
func runAny(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
-
- for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.18") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_18) {
for curIface := range curFile.Preorder((*ast.InterfaceType)(nil)) {
iface := curIface.Node().(*ast.InterfaceType)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/bloop.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/bloop.go
index eb1ac170c6..ad45d74478 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/bloop.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/bloop.go
@@ -15,20 +15,19 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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"
)
var BLoopAnalyzer = &analysis.Analyzer{
Name: "bloop",
- Doc: analysisinternal.MustExtractDoc(doc, "bloop"),
+ Doc: analyzerutil.MustExtractDoc(doc, "bloop"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -45,16 +44,13 @@ var BLoopAnalyzer = &analysis.Analyzer{
// for i := 0; i < b.N; i++ {} => for b.Loop() {}
// for range b.N {}
func bloop(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
if !typesinternal.Imports(pass.Pkg, "testing") {
return nil, nil
}
var (
- inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
- info = pass.TypesInfo
+ index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
+ info = pass.TypesInfo
)
// edits computes the text edits for a matched for/range loop
@@ -102,7 +98,7 @@ func bloop(pass *analysis.Pass) (any, error) {
(*ast.ForStmt)(nil),
(*ast.RangeStmt)(nil),
}
- for curFile := range filesUsing(inspect, info, "go1.24") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_24) {
for curLoop := range curFile.Preorder(loops...) {
switch n := curLoop.Node().(type) {
case *ast.ForStmt:
@@ -189,6 +185,7 @@ func enclosingFunc(c inspector.Cursor) (inspector.Cursor, bool) {
// 2. The only b.N loop in that benchmark function
// - b.Loop() can only be called once per benchmark execution
// - Multiple calls result in "B.Loop called with timer stopped" error
+// - Multiple loops may have complex interdependencies that are hard to analyze
func usesBenchmarkNOnce(c inspector.Cursor, info *types.Info) bool {
// Find the enclosing benchmark function
curFunc, ok := enclosingFunc(c)
@@ -205,17 +202,14 @@ func usesBenchmarkNOnce(c inspector.Cursor, info *types.Info) bool {
return false
}
- // Count b.N references in this benchmark function
+ // Count all b.N references in this benchmark function (including nested functions)
bnRefCount := 0
- filter := []ast.Node{(*ast.SelectorExpr)(nil), (*ast.FuncLit)(nil)}
+ filter := []ast.Node{(*ast.SelectorExpr)(nil)}
curFunc.Inspect(filter, func(cur inspector.Cursor) bool {
- switch n := cur.Node().(type) {
- case *ast.FuncLit:
- return false // don't descend into nested function literals
- case *ast.SelectorExpr:
- if n.Sel.Name == "N" && typesinternal.IsPointerToNamed(info.TypeOf(n.X), "testing", "B") {
- bnRefCount++
- }
+ sel := cur.Node().(*ast.SelectorExpr)
+ if sel.Sel.Name == "N" &&
+ typesinternal.IsPointerToNamed(info.TypeOf(sel.X), "testing", "B") {
+ bnRefCount++
}
return true
})
@@ -240,7 +234,7 @@ func isIncrementLoop(info *types.Info, loop *ast.ForStmt) *types.Var {
if assign, ok := loop.Init.(*ast.AssignStmt); ok &&
assign.Tok == token.DEFINE &&
len(assign.Rhs) == 1 &&
- isZeroIntLiteral(info, assign.Rhs[0]) &&
+ isZeroIntConst(info, assign.Rhs[0]) &&
is[*ast.IncDecStmt](loop.Post) &&
loop.Post.(*ast.IncDecStmt).Tok == token.INC &&
astutil.EqualSyntax(loop.Post.(*ast.IncDecStmt).X, assign.Lhs[0]) {
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 bc143d7a6d..7469002f56 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
@@ -176,8 +176,12 @@ This analyzer finds declarations of functions of this form:
and suggests a fix to turn them into inlinable wrappers around
go1.26's built-in new(expr) function:
+ //go:fix inline
func varOf(x int) *int { return new(x) }
+(The directive comment causes the 'inline' analyzer to suggest
+that calls to such functions are inlined.)
+
In addition, this analyzer suggests a fix for each call
to one of the functions before it is transformed, so that
@@ -187,9 +191,9 @@ is replaced by:
use(new(123))
-(Wrapper functions such as varOf are common when working with Go
+Wrapper functions such as varOf are common when working with Go
serialization packages such as for JSON or protobuf, where pointers
-are often used to express optionality.)
+are often used to express optionality.
# Analyzer omitzero
@@ -327,6 +331,44 @@ iterator offered by the same data type:
where x is one of various well-known types in the standard library.
+# Analyzer stringscut
+
+stringscut: replace strings.Index etc. with strings.Cut
+
+This analyzer replaces certain patterns of use of [strings.Index] and string slicing by [strings.Cut], added in go1.18.
+
+For example:
+
+ idx := strings.Index(s, substr)
+ if idx >= 0 {
+ return s[:idx]
+ }
+
+is replaced by:
+
+ before, _, ok := strings.Cut(s, substr)
+ if ok {
+ return before
+ }
+
+And:
+
+ idx := strings.Index(s, substr)
+ if idx >= 0 {
+ return
+ }
+
+is replaced by:
+
+ found := strings.Contains(s, substr)
+ if found {
+ return
+ }
+
+It also handles variants using [strings.IndexByte] instead of Index, or the bytes package instead of strings.
+
+Fixes are offered only in cases in which there are no potential modifications of the idx, s, or substr expressions between their definition and use.
+
# Analyzer stringscutprefix
stringscutprefix: replace HasPrefix/TrimPrefix with CutPrefix
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 b6387ad840..d9a922f846 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
@@ -14,21 +14,21 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/ast/edge"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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 errorsastypeAnalyzer = &analysis.Analyzer{
Name: "errorsastype",
- Doc: analysisinternal.MustExtractDoc(doc, "errorsastype"),
+ Doc: analyzerutil.MustExtractDoc(doc, "errorsastype"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#errorsastype",
- Requires: []*analysis.Analyzer{generated.Analyzer, typeindexanalyzer.Analyzer},
+ Requires: []*analysis.Analyzer{typeindexanalyzer.Analyzer},
Run: errorsastype,
}
@@ -78,8 +78,6 @@ func init() {
//
// - if errors.As(err, myerr) && othercond { ... }
func errorsastype(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
var (
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
info = pass.TypesInfo
@@ -97,7 +95,7 @@ func errorsastype(pass *analysis.Pass) (any, error) {
}
file := astutil.EnclosingFile(curDeclStmt)
- if !fileUses(info, file, "go1.26") {
+ if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_26) {
continue // errors.AsType is too new
}
@@ -127,6 +125,8 @@ 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
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 f2e5360542..389f703466 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
@@ -13,18 +13,17 @@ import (
"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/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
)
var FmtAppendfAnalyzer = &analysis.Analyzer{
Name: "fmtappendf",
- Doc: analysisinternal.MustExtractDoc(doc, "fmtappendf"),
+ Doc: analyzerutil.MustExtractDoc(doc, "fmtappendf"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -35,8 +34,6 @@ var FmtAppendfAnalyzer = &analysis.Analyzer{
// The fmtappend function replaces []byte(fmt.Sprintf(...)) by
// fmt.Appendf(nil, ...), and similarly for Sprint, Sprintln.
func fmtappendf(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
index := pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
for _, fn := range []types.Object{
index.Object("fmt", "Sprintf"),
@@ -50,7 +47,7 @@ func fmtappendf(pass *analysis.Pass) (any, error) {
conv := curCall.Parent().Node().(*ast.CallExpr)
tv := pass.TypesInfo.Types[conv.Fun]
if tv.IsType() && types.Identical(tv.Type, byteSliceType) &&
- fileUses(pass.TypesInfo, astutil.EnclosingFile(curCall), "go1.19") {
+ analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(curCall), versions.Go1_19) {
// Have: []byte(fmt.SprintX(...))
// Find "Sprint" identifier.
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/forvar.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/forvar.go
index 76e3a8a73c..67f60acaaf 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/forvar.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/forvar.go
@@ -10,22 +10,18 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
- "golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/refactor"
+ "golang.org/x/tools/internal/versions"
)
var ForVarAnalyzer = &analysis.Analyzer{
- Name: "forvar",
- Doc: analysisinternal.MustExtractDoc(doc, "forvar"),
- Requires: []*analysis.Analyzer{
- generated.Analyzer,
- inspect.Analyzer,
- },
- Run: forvar,
- URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#forvar",
+ Name: "forvar",
+ Doc: analyzerutil.MustExtractDoc(doc, "forvar"),
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: forvar,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#forvar",
}
// forvar offers to fix unnecessary copying of a for variable
@@ -39,54 +35,77 @@ var ForVarAnalyzer = &analysis.Analyzer{
// where the two idents are the same,
// and the ident is defined (:=) as a variable in the for statement.
// (Note that this 'fix' does not work for three clause loops
-// because the Go specification says "The variable used by each subsequent iteration
+// because the Go specfilesUsingGoVersionsays "The variable used by each subsequent iteration
// is declared implicitly before executing the post statement and initialized to the
// value of the previous iteration's variable at that moment.")
+//
+// Variant: same thing in an IfStmt.Init, when the IfStmt is the sole
+// loop body statement:
+//
+// for _, x := range foo {
+// if x := x; cond { ... }
+// }
+//
+// (The restriction is necessary to avoid potential problems arising
+// from merging two distinct variables.)
+//
+// This analyzer is synergistic with stditerators,
+// which may create redundant "x := x" statements.
func forvar(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.22") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_22) {
for curLoop := range curFile.Preorder((*ast.RangeStmt)(nil)) {
loop := curLoop.Node().(*ast.RangeStmt)
if loop.Tok != token.DEFINE {
continue
}
- isLoopVarRedecl := func(assign *ast.AssignStmt) bool {
- for i, lhs := range assign.Lhs {
- if !(astutil.EqualSyntax(lhs, assign.Rhs[i]) &&
- (astutil.EqualSyntax(lhs, loop.Key) || astutil.EqualSyntax(lhs, loop.Value))) {
- return false
+ isLoopVarRedecl := func(stmt ast.Stmt) bool {
+ if assign, ok := stmt.(*ast.AssignStmt); ok &&
+ assign.Tok == token.DEFINE &&
+ len(assign.Lhs) == len(assign.Rhs) {
+
+ for i, lhs := range assign.Lhs {
+ if !(astutil.EqualSyntax(lhs, assign.Rhs[i]) &&
+ (astutil.EqualSyntax(lhs, loop.Key) ||
+ astutil.EqualSyntax(lhs, loop.Value))) {
+ return false
+ }
}
+ return true
}
- return true
+ return false
}
// Have: for k, v := range x { stmts }
//
// Delete the prefix of stmts that are
// of the form k := k; v := v; k, v := k, v; v, k := v, k.
for _, stmt := range loop.Body.List {
- if assign, ok := stmt.(*ast.AssignStmt); ok &&
- assign.Tok == token.DEFINE &&
- len(assign.Lhs) == len(assign.Rhs) &&
- isLoopVarRedecl(assign) {
-
- curStmt, _ := curLoop.FindNode(stmt)
- edits := refactor.DeleteStmt(pass.Fset.File(stmt.Pos()), curStmt)
- if len(edits) > 0 {
- pass.Report(analysis.Diagnostic{
- Pos: stmt.Pos(),
- End: stmt.End(),
- Message: "copying variable is unneeded",
- SuggestedFixes: []analysis.SuggestedFix{{
- Message: "Remove unneeded redeclaration",
- TextEdits: edits,
- }},
- })
- }
+ if isLoopVarRedecl(stmt) {
+ // { x := x; ... }
+ // ------
+ } else if ifstmt, ok := stmt.(*ast.IfStmt); ok &&
+ ifstmt.Init != nil &&
+ len(loop.Body.List) == 1 && // must be sole statement in loop body
+ isLoopVarRedecl(ifstmt.Init) {
+ // if x := x; cond {
+ // ------
+ stmt = ifstmt.Init
} else {
break // stop at first other statement
}
+
+ curStmt, _ := curLoop.FindNode(stmt)
+ edits := refactor.DeleteStmt(pass.Fset.File(stmt.Pos()), curStmt)
+ if len(edits) > 0 {
+ pass.Report(analysis.Diagnostic{
+ Pos: stmt.Pos(),
+ End: stmt.End(),
+ Message: "copying variable is unneeded",
+ SuggestedFixes: []analysis.SuggestedFix{{
+ Message: "Remove unneeded redeclaration",
+ TextEdits: edits,
+ }},
+ })
+ }
}
}
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/maps.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/maps.go
index 3072cf6f51..2352c8b608 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/maps.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/maps.go
@@ -15,23 +15,20 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/refactor"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal"
+ "golang.org/x/tools/internal/versions"
)
var MapsLoopAnalyzer = &analysis.Analyzer{
- Name: "mapsloop",
- Doc: analysisinternal.MustExtractDoc(doc, "mapsloop"),
- Requires: []*analysis.Analyzer{
- generated.Analyzer,
- inspect.Analyzer,
- },
- Run: mapsloop,
- URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#mapsloop",
+ Name: "mapsloop",
+ Doc: analyzerutil.MustExtractDoc(doc, "mapsloop"),
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: mapsloop,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#mapsloop",
}
// The mapsloop pass offers to simplify a loop of map insertions:
@@ -55,8 +52,6 @@ var MapsLoopAnalyzer = &analysis.Analyzer{
// m = make(M)
// m = M{}
func mapsloop(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
// Skip the analyzer in packages where its
// fixes would create an import cycle.
if within(pass, "maps", "bytes", "runtime") {
@@ -223,8 +218,7 @@ func mapsloop(pass *analysis.Pass) (any, error) {
}
// Find all range loops around m[k] = v.
- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.23") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_23) {
file := curFile.Node().(*ast.File)
for curRange := range curFile.Preorder((*ast.RangeStmt)(nil)) {
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 7ebf837375..23a0977f21 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
@@ -15,19 +15,18 @@ import (
"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/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/typeparams"
"golang.org/x/tools/internal/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
)
var MinMaxAnalyzer = &analysis.Analyzer{
Name: "minmax",
- Doc: analysisinternal.MustExtractDoc(doc, "minmax"),
+ Doc: analyzerutil.MustExtractDoc(doc, "minmax"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -56,8 +55,6 @@ var MinMaxAnalyzer = &analysis.Analyzer{
// - "x := a" or "x = a" or "var x = a" in pattern 2
// - "x < b" or "a < b" in pattern 2
func minmax(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
// Check for user-defined min/max functions that can be removed
checkUserDefinedMinMax(pass)
@@ -201,8 +198,7 @@ func minmax(pass *analysis.Pass) (any, error) {
// Find all "if a < b { lhs = rhs }" statements.
info := pass.TypesInfo
- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- for curFile := range filesUsing(inspect, info, "go1.21") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_21) {
astFile := curFile.Node().(*ast.File)
for curIfStmt := range curFile.Preorder((*ast.IfStmt)(nil)) {
ifStmt := curIfStmt.Node().(*ast.IfStmt)
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 df23fc23c8..013ce79d6c 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
@@ -16,15 +16,15 @@ import (
"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/internal/analysisinternal/generated"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/moreiters"
"golang.org/x/tools/internal/packagepath"
"golang.org/x/tools/internal/stdlib"
"golang.org/x/tools/internal/typesinternal"
- "golang.org/x/tools/internal/versions"
)
//go:embed doc.go
@@ -48,6 +48,7 @@ var Suite = []*analysis.Analyzer{
// SlicesDeleteAnalyzer, // not nil-preserving!
SlicesSortAnalyzer,
stditeratorsAnalyzer,
+ stringscutAnalyzer,
StringsCutPrefixAnalyzer,
StringsSeqAnalyzer,
StringsBuilderAnalyzer,
@@ -57,18 +58,6 @@ var Suite = []*analysis.Analyzer{
// -- helpers --
-// skipGenerated decorates pass.Report to suppress diagnostics in generated files.
-func skipGenerated(pass *analysis.Pass) {
- report := pass.Report
- pass.Report = func(diag analysis.Diagnostic) {
- generated := pass.ResultOf[generated.Analyzer].(*generated.Result)
- if generated.IsGenerated(diag.Pos) {
- return // skip
- }
- report(diag)
- }
-}
-
// formatExprs formats a comma-separated list of expressions.
func formatExprs(fset *token.FileSet, exprs []ast.Expr) string {
var buf strings.Builder
@@ -81,8 +70,8 @@ func formatExprs(fset *token.FileSet, exprs []ast.Expr) string {
return buf.String()
}
-// isZeroIntLiteral reports whether e is an integer whose value is 0.
-func isZeroIntLiteral(info *types.Info, e ast.Expr) bool {
+// isZeroIntConst reports whether e is an integer whose value is 0.
+func isZeroIntConst(info *types.Info, e ast.Expr) bool {
return isIntLiteral(info, e, 0)
}
@@ -91,36 +80,28 @@ func isIntLiteral(info *types.Info, e ast.Expr, n int64) bool {
return info.Types[e].Value == constant.MakeInt64(n)
}
-// filesUsing returns a cursor for each *ast.File in the inspector
+// filesUsingGoVersion returns a cursor for each *ast.File in the inspector
// that uses at least the specified version of Go (e.g. "go1.24").
//
+// The pass's analyzer must require [inspect.Analyzer].
+//
// TODO(adonovan): opt: eliminate this function, instead following the
-// approach of [fmtappendf], which uses typeindex and [fileUses].
-// See "Tip" at [fileUses] for motivation.
-func filesUsing(inspect *inspector.Inspector, info *types.Info, version string) iter.Seq[inspector.Cursor] {
+// approach of [fmtappendf], which uses typeindex and
+// [analyzerutil.FileUsesGoVersion]; see "Tip" documented at the
+// latter function for motivation.
+func filesUsingGoVersion(pass *analysis.Pass, version string) iter.Seq[inspector.Cursor] {
+ inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+
return func(yield func(inspector.Cursor) bool) {
for curFile := range inspect.Root().Children() {
file := curFile.Node().(*ast.File)
- if !versions.Before(info.FileVersions[file], version) && !yield(curFile) {
+ if analyzerutil.FileUsesGoVersion(pass, file, version) && !yield(curFile) {
break
}
}
}
}
-// fileUses reports whether the specified file uses at least the
-// specified version of Go (e.g. "go1.24").
-//
-// 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
-// operation is not free, yet is not a highly selective filter: the
-// fraction of files that pass most version checks is high and
-// increases over time.
-func fileUses(info *types.Info, file *ast.File, version string) bool {
- return !versions.Before(info.FileVersions[file], version)
-}
-
// within reports whether the current pass is analyzing one of the
// specified standard packages or their dependencies.
func within(pass *analysis.Pass, pkgs ...string) bool {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/newexpr.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/newexpr.go
index b8893244d5..6cb75f247c 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/newexpr.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/newexpr.go
@@ -17,13 +17,14 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
+ "golang.org/x/tools/internal/versions"
)
var NewExprAnalyzer = &analysis.Analyzer{
Name: "newexpr",
- Doc: analysisinternal.MustExtractDoc(doc, "newexpr"),
+ Doc: analyzerutil.MustExtractDoc(doc, "newexpr"),
URL: "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/modernize#newexpr",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
@@ -60,7 +61,7 @@ func run(pass *analysis.Pass) (any, error) {
// Check file version.
file := astutil.EnclosingFile(curFuncDecl)
- if !fileUses(info, file, "go1.26") {
+ if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_26) {
continue // new(expr) not available in this file
}
@@ -87,25 +88,18 @@ func run(pass *analysis.Pass) (any, error) {
}
}
- // Disabled until we resolve https://go.dev/issue/75726
- // (Go version skew between caller and callee in inliner.)
- // TODO(adonovan): fix and reenable.
+ // Add a //go:fix inline annotation, if not already present.
//
- // Also, restore these lines to our section of doc.go:
- // //go:fix inline
- // ...
- // (The directive comment causes the inline analyzer to suggest
- // that calls to such functions are inlined.)
- if false {
- // Add a //go:fix inline annotation, if not already present.
- // TODO(adonovan): use ast.ParseDirective when go1.26 is assured.
- if !strings.Contains(decl.Doc.Text(), "go:fix inline") {
- edits = append(edits, analysis.TextEdit{
- Pos: decl.Pos(),
- End: decl.Pos(),
- NewText: []byte("//go:fix inline\n"),
- })
- }
+ // The inliner will not inline a newer callee body into an
+ // older Go file; see https://go.dev/issue/75726.
+ //
+ // TODO(adonovan): use ast.ParseDirective when go1.26 is assured.
+ if !strings.Contains(decl.Doc.Text(), "go:fix inline") {
+ edits = append(edits, analysis.TextEdit{
+ Pos: decl.Pos(),
+ End: decl.Pos(),
+ NewText: []byte("//go:fix inline\n"),
+ })
}
if len(edits) > 0 {
@@ -140,7 +134,7 @@ func run(pass *analysis.Pass) (any, error) {
// Check file version.
file := astutil.EnclosingFile(curCall)
- if !fileUses(info, file, "go1.26") {
+ if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_26) {
continue // new(expr) not available in this file
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/omitzero.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/omitzero.go
index bd309cf9d5..4a05d64f42 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/omitzero.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/omitzero.go
@@ -12,21 +12,17 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
- "golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
+ "golang.org/x/tools/internal/versions"
)
var OmitZeroAnalyzer = &analysis.Analyzer{
- Name: "omitzero",
- Doc: analysisinternal.MustExtractDoc(doc, "omitzero"),
- Requires: []*analysis.Analyzer{
- generated.Analyzer,
- inspect.Analyzer,
- },
- Run: omitzero,
- URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#omitzero",
+ Name: "omitzero",
+ Doc: analyzerutil.MustExtractDoc(doc, "omitzero"),
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: omitzero,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#omitzero",
}
func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Field) {
@@ -48,25 +44,20 @@ func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Fi
// No omitempty in json tag
return
}
- omitEmptyPos, omitEmptyEnd, err := astutil.RangeInStringLiteral(curField.Tag, match[2], match[3])
+ omitEmpty, err := astutil.RangeInStringLiteral(curField.Tag, match[2], match[3])
if err != nil {
return
}
- removePos, removeEnd := omitEmptyPos, omitEmptyEnd
+ var remove analysis.Range = omitEmpty
jsonTag := reflect.StructTag(tagconv).Get("json")
if jsonTag == ",omitempty" {
// Remove the entire struct tag if json is the only package used
if match[1]-match[0] == len(tagconv) {
- removePos = curField.Tag.Pos()
- removeEnd = curField.Tag.End()
+ remove = curField.Tag
} else {
// Remove the json tag if omitempty is the only field
- removePos, err = astutil.PosInStringLiteral(curField.Tag, match[0])
- if err != nil {
- return
- }
- removeEnd, err = astutil.PosInStringLiteral(curField.Tag, match[1])
+ remove, err = astutil.RangeInStringLiteral(curField.Tag, match[0], match[1])
if err != nil {
return
}
@@ -81,8 +72,8 @@ func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Fi
Message: "Remove redundant omitempty tag",
TextEdits: []analysis.TextEdit{
{
- Pos: removePos,
- End: removeEnd,
+ Pos: remove.Pos(),
+ End: remove.End(),
},
},
},
@@ -90,8 +81,8 @@ func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Fi
Message: "Replace omitempty with omitzero (behavior change)",
TextEdits: []analysis.TextEdit{
{
- Pos: omitEmptyPos,
- End: omitEmptyEnd,
+ Pos: omitEmpty.Pos(),
+ End: omitEmpty.End(),
NewText: []byte(",omitzero"),
},
},
@@ -100,18 +91,14 @@ func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Fi
}
// The omitzero pass searches for instances of "omitempty" in a json field tag on a
-// struct. Since "omitempty" does not have any effect when applied to a struct field,
+// struct. Since "omitfilesUsingGoVersions not have any effect when applied to a struct field,
// it suggests either deleting "omitempty" or replacing it with "omitzero", which
// correctly excludes structs from a json encoding.
func omitzero(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- info := pass.TypesInfo
- for curFile := range filesUsing(inspect, info, "go1.24") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_24) {
for curStruct := range curFile.Preorder((*ast.StructType)(nil)) {
for _, curField := range curStruct.Node().(*ast.StructType).Fields.List {
- checkOmitEmptyField(pass, info, curField)
+ checkOmitEmptyField(pass, pass.TypesInfo, curField)
}
}
}
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 e8af8074ff..57b502ab80 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
@@ -10,13 +10,14 @@ import (
"strings"
"golang.org/x/tools/go/analysis"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/goplsexport"
+ "golang.org/x/tools/internal/versions"
)
var plusBuildAnalyzer = &analysis.Analyzer{
Name: "plusbuild",
- Doc: analysisinternal.MustExtractDoc(doc, "plusbuild"),
+ Doc: analyzerutil.MustExtractDoc(doc, "plusbuild"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#plusbuild",
Run: plusbuild,
}
@@ -28,7 +29,7 @@ func init() {
func plusbuild(pass *analysis.Pass) (any, error) {
check := func(f *ast.File) {
- if !fileUses(pass.TypesInfo, f, "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 adc840f11d..6b1edf38b3 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
@@ -15,19 +15,18 @@ import (
"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/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/typesinternal"
"golang.org/x/tools/internal/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
)
var RangeIntAnalyzer = &analysis.Analyzer{
Name: "rangeint",
- Doc: analysisinternal.MustExtractDoc(doc, "rangeint"),
+ Doc: analyzerutil.MustExtractDoc(doc, "rangeint"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -66,21 +65,19 @@ var RangeIntAnalyzer = &analysis.Analyzer{
// - a constant; or
// - len(s), where s has the above properties.
func rangeint(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
+ var (
+ info = pass.TypesInfo
+ typeindex = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
+ )
- info := pass.TypesInfo
-
- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- typeindex := pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
-
- for curFile := range filesUsing(inspect, info, "go1.22") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_22) {
nextLoop:
for curLoop := range curFile.Preorder((*ast.ForStmt)(nil)) {
loop := curLoop.Node().(*ast.ForStmt)
if init, ok := loop.Init.(*ast.AssignStmt); ok &&
isSimpleAssign(init) &&
is[*ast.Ident](init.Lhs[0]) &&
- isZeroIntLiteral(info, init.Rhs[0]) {
+ isZeroIntConst(info, init.Rhs[0]) {
// Have: for i = 0; ... (or i := 0)
index := init.Lhs[0].(*ast.Ident)
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 c9b0fa42ee..0fc781813f 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
@@ -14,9 +14,8 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/edge"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/refactor"
"golang.org/x/tools/internal/typesinternal"
@@ -26,9 +25,8 @@ import (
var ReflectTypeForAnalyzer = &analysis.Analyzer{
Name: "reflecttypefor",
- Doc: analysisinternal.MustExtractDoc(doc, "reflecttypefor"),
+ Doc: analyzerutil.MustExtractDoc(doc, "reflecttypefor"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -37,8 +35,6 @@ var ReflectTypeForAnalyzer = &analysis.Analyzer{
}
func reflecttypefor(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
var (
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
info = pass.TypesInfo
@@ -89,7 +85,7 @@ func reflecttypefor(pass *analysis.Pass) (any, error) {
}
file := astutil.EnclosingFile(curCall)
- if versions.Before(info.FileVersions[file], "go1.22") {
+ if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_22) {
continue // TypeFor requires go1.22
}
tokFile := pass.Fset.File(file.Pos())
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slices.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slices.go
index 032f874df1..960a46644b 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slices.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slices.go
@@ -13,25 +13,21 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
- "golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
+ "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"
+ "golang.org/x/tools/internal/versions"
)
// Warning: this analyzer is not safe to enable by default.
var AppendClippedAnalyzer = &analysis.Analyzer{
- Name: "appendclipped",
- Doc: analysisinternal.MustExtractDoc(doc, "appendclipped"),
- Requires: []*analysis.Analyzer{
- generated.Analyzer,
- inspect.Analyzer,
- },
- Run: appendclipped,
- URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#appendclipped",
+ Name: "appendclipped",
+ Doc: analyzerutil.MustExtractDoc(doc, "appendclipped"),
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: appendclipped,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#appendclipped",
}
// The appendclipped pass offers to simplify a tower of append calls:
@@ -59,8 +55,6 @@ var AppendClippedAnalyzer = &analysis.Analyzer{
// The fix does not always preserve nilness the of base slice when the
// addends (a, b, c) are all empty (see #73557).
func appendclipped(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
// Skip the analyzer in packages where its
// fixes would create an import cycle.
if within(pass, "slices", "bytes", "runtime") {
@@ -205,8 +199,7 @@ func appendclipped(pass *analysis.Pass) (any, error) {
skip := make(map[*ast.CallExpr]bool)
// Visit calls of form append(x, y...).
- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- for curFile := range filesUsing(inspect, info, "go1.21") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_21) {
file := curFile.Node().(*ast.File)
for curCall := range curFile.Preorder((*ast.CallExpr)(nil)) {
@@ -266,7 +259,7 @@ func clippedSlice(info *types.Info, e ast.Expr) (res ast.Expr, empty bool) {
// x[:0:0], x[:len(x):len(x)], x[:k:k]
if e.Slice3 && e.High != nil && e.Max != nil && astutil.EqualSyntax(e.High, e.Max) { // x[:k:k]
res = e
- empty = isZeroIntLiteral(info, e.High) // x[:0:0]
+ empty = isZeroIntConst(info, e.High) // x[:0:0]
if call, ok := e.High.(*ast.CallExpr); ok &&
typeutil.Callee(info, call) == builtinLen &&
astutil.EqualSyntax(call.Args[0], e.X) {
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 b3c2e562c9..3b32685266 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
@@ -14,20 +14,19 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/refactor"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
)
var SlicesContainsAnalyzer = &analysis.Analyzer{
Name: "slicescontains",
- Doc: analysisinternal.MustExtractDoc(doc, "slicescontains"),
+ Doc: analyzerutil.MustExtractDoc(doc, "slicescontains"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -66,8 +65,6 @@ var SlicesContainsAnalyzer = &analysis.Analyzer{
// TODO(adonovan): Add a check that needle/predicate expression from
// if-statement has no effects. Now the program behavior may change.
func slicescontains(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
// Skip the analyzer in packages where its
// fixes would create an import cycle.
if within(pass, "slices", "runtime") {
@@ -75,9 +72,8 @@ func slicescontains(pass *analysis.Pass) (any, error) {
}
var (
- inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
- info = pass.TypesInfo
+ index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
+ info = pass.TypesInfo
)
// check is called for each RangeStmt of this form:
@@ -312,7 +308,7 @@ func slicescontains(pass *analysis.Pass) (any, error) {
// Special case:
// prev="lhs = false" body={ lhs = true; break }
- // => lhs = slices.Contains(...) (or negation)
+ // => lhs = slices.Contains(...) (or its negation)
if assign, ok := body.List[0].(*ast.AssignStmt); ok &&
len(body.List) == 2 &&
assign.Tok == token.ASSIGN &&
@@ -320,13 +316,12 @@ func slicescontains(pass *analysis.Pass) (any, error) {
len(assign.Rhs) == 1 {
// Have: body={ lhs = rhs; break }
-
if prevAssign, ok := prevStmt.(*ast.AssignStmt); ok &&
len(prevAssign.Lhs) == 1 &&
len(prevAssign.Rhs) == 1 &&
astutil.EqualSyntax(prevAssign.Lhs[0], assign.Lhs[0]) &&
- is[*ast.Ident](assign.Rhs[0]) &&
- info.Uses[assign.Rhs[0].(*ast.Ident)] == builtinTrue {
+ isTrueOrFalse(info, assign.Rhs[0]) ==
+ -isTrueOrFalse(info, prevAssign.Rhs[0]) {
// Have:
// lhs = false
@@ -336,15 +331,14 @@ func slicescontains(pass *analysis.Pass) (any, error) {
//
// TODO(adonovan):
// - support "var lhs bool = false" and variants.
- // - support negation.
- // Both these variants seem quite significant.
// - allow the break to be omitted.
+ neg := cond(isTrueOrFalse(info, assign.Rhs[0]) < 0, "!", "")
report([]analysis.TextEdit{
- // Replace "rhs" of previous assignment by slices.Contains(...)
+ // Replace "rhs" of previous assignment by [!]slices.Contains(...)
{
Pos: prevAssign.Rhs[0].Pos(),
End: prevAssign.Rhs[0].End(),
- NewText: []byte(contains),
+ NewText: []byte(neg + contains),
},
// Delete the loop and preceding space.
{
@@ -388,7 +382,7 @@ func slicescontains(pass *analysis.Pass) (any, error) {
}
}
- for curFile := range filesUsing(inspect, info, "go1.21") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_21) {
file := curFile.Node().(*ast.File)
for curRange := range curFile.Preorder((*ast.RangeStmt)(nil)) {
@@ -420,13 +414,19 @@ func slicescontains(pass *analysis.Pass) (any, error) {
// isReturnTrueOrFalse returns nonzero if stmt returns true (+1) or false (-1).
func isReturnTrueOrFalse(info *types.Info, stmt ast.Stmt) int {
if ret, ok := stmt.(*ast.ReturnStmt); ok && len(ret.Results) == 1 {
- if id, ok := ret.Results[0].(*ast.Ident); ok {
- switch info.Uses[id] {
- case builtinTrue:
- return +1
- case builtinFalse:
- return -1
- }
+ return isTrueOrFalse(info, ret.Results[0])
+ }
+ return 0
+}
+
+// isTrueOrFalse returns nonzero if expr is literally true (+1) or false (-1).
+func isTrueOrFalse(info *types.Info, expr ast.Expr) int {
+ if id, ok := expr.(*ast.Ident); ok {
+ switch info.Uses[id] {
+ case builtinTrue:
+ return +1
+ case builtinFalse:
+ return -1
}
}
return 0
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesdelete.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesdelete.go
index b3e063db0f..7b3aa875c0 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesdelete.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesdelete.go
@@ -12,24 +12,20 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
- "golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
+ "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"
+ "golang.org/x/tools/internal/versions"
)
// Warning: this analyzer is not safe to enable by default (not nil-preserving).
var SlicesDeleteAnalyzer = &analysis.Analyzer{
- Name: "slicesdelete",
- Doc: analysisinternal.MustExtractDoc(doc, "slicesdelete"),
- Requires: []*analysis.Analyzer{
- generated.Analyzer,
- inspect.Analyzer,
- },
- Run: slicesdelete,
- URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#slicesdelete",
+ Name: "slicesdelete",
+ Doc: analyzerutil.MustExtractDoc(doc, "slicesdelete"),
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: slicesdelete,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#slicesdelete",
}
// The slicesdelete pass attempts to replace instances of append(s[:i], s[i+k:]...)
@@ -37,15 +33,12 @@ var SlicesDeleteAnalyzer = &analysis.Analyzer{
// Other variations that will also have suggested replacements include:
// append(s[:i-1], s[i:]...) and append(s[:i+k1], s[i+k2:]) where k2 > k1.
func slicesdelete(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
// Skip the analyzer in packages where its
// fixes would create an import cycle.
if within(pass, "slices", "runtime") {
return nil, nil
}
- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
info := pass.TypesInfo
report := func(file *ast.File, call *ast.CallExpr, slice1, slice2 *ast.SliceExpr) {
insert := func(pos token.Pos, text string) analysis.TextEdit {
@@ -55,7 +48,7 @@ func slicesdelete(pass *analysis.Pass) (any, error) {
return types.Identical(types.Default(info.TypeOf(e)), builtinInt.Type())
}
isIntShadowed := func() bool {
- scope := pass.TypesInfo.Scopes[file].Innermost(call.Lparen)
+ scope := info.Scopes[file].Innermost(call.Lparen)
if _, obj := scope.LookupParent("int", call.Lparen); obj != builtinInt {
return true // int type is shadowed
}
@@ -130,7 +123,7 @@ func slicesdelete(pass *analysis.Pass) (any, error) {
}},
})
}
- for curFile := range filesUsing(inspect, info, "go1.21") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_21) {
file := curFile.Node().(*ast.File)
for curCall := range curFile.Preorder((*ast.CallExpr)(nil)) {
call := curCall.Node().(*ast.CallExpr)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/sortslice.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/sortslice.go
index 66af16d1f6..e22b8c55f5 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/sortslice.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/sortslice.go
@@ -11,20 +11,19 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/refactor"
"golang.org/x/tools/internal/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
)
// (Not to be confused with go/analysis/passes/sortslice.)
var SlicesSortAnalyzer = &analysis.Analyzer{
Name: "slicessort",
- Doc: analysisinternal.MustExtractDoc(doc, "slicessort"),
+ Doc: analyzerutil.MustExtractDoc(doc, "slicessort"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -52,8 +51,6 @@ var SlicesSortAnalyzer = &analysis.Analyzer{
// - sort.Sort(x) where x has a named slice type whose Less method is the natural order.
// -> sort.Slice(x)
func slicessort(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
// Skip the analyzer in packages where its
// fixes would create an import cycle.
if within(pass, "slices", "sort", "runtime") {
@@ -87,7 +84,7 @@ func slicessort(pass *analysis.Pass) (any, error) {
}
file := astutil.EnclosingFile(curCall)
if isIndex(compare.X, i) && isIndex(compare.Y, j) &&
- fileUses(info, file, "go1.21") {
+ analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_21) {
// Have: sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
prefix, importEdits := refactor.AddImport(
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 20817520e1..cc59580671 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
@@ -14,9 +14,8 @@ import (
"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/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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"
@@ -26,9 +25,8 @@ import (
var stditeratorsAnalyzer = &analysis.Analyzer{
Name: "stditerators",
- Doc: analysisinternal.MustExtractDoc(doc, "stditerators"),
+ Doc: analyzerutil.MustExtractDoc(doc, "stditerators"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
typeindexanalyzer.Analyzer,
},
Run: stditerators,
@@ -89,8 +87,6 @@ var stditeratorsTable = [...]struct {
// iterator for that reason? We don't want to go fix to
// undo optimizations. Do we need a suppression mechanism?
func stditerators(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
var (
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
info = pass.TypesInfo
@@ -116,6 +112,10 @@ func stditerators(pass *analysis.Pass) (any, error) {
//
// for ... { e := x.At(i); use(e) }
//
+ // or
+ //
+ // for ... { if e := x.At(i); cond { use(e) } }
+ //
// then chooseName prefers the name e and additionally
// returns the var's symbol. We'll transform this to:
//
@@ -124,10 +124,11 @@ func stditerators(pass *analysis.Pass) (any, error) {
// which leaves a redundant assignment that a
// subsequent 'forvar' pass will eliminate.
chooseName := func(curBody inspector.Cursor, x ast.Expr, i *types.Var) (string, *types.Var) {
- // Is body { elem := x.At(i); ... } ?
- body := curBody.Node().(*ast.BlockStmt)
- if len(body.List) > 0 {
- if assign, ok := body.List[0].(*ast.AssignStmt); ok &&
+
+ // isVarAssign reports whether stmt has the form v := x.At(i)
+ // and returns the variable if so.
+ isVarAssign := func(stmt ast.Stmt) *types.Var {
+ if assign, ok := stmt.(*ast.AssignStmt); ok &&
assign.Tok == token.DEFINE &&
len(assign.Lhs) == 1 &&
len(assign.Rhs) == 1 &&
@@ -138,15 +139,47 @@ func stditerators(pass *analysis.Pass) (any, error) {
astutil.EqualSyntax(ast.Unparen(call.Fun).(*ast.SelectorExpr).X, x) &&
is[*ast.Ident](call.Args[0]) &&
info.Uses[call.Args[0].(*ast.Ident)] == i {
- // Have: { elem := x.At(i); ... }
+ // Have: elem := x.At(i)
id := assign.Lhs[0].(*ast.Ident)
- return id.Name, info.Defs[id].(*types.Var)
+ return info.Defs[id].(*types.Var)
+ }
+ }
+ return nil
+ }
+
+ body := curBody.Node().(*ast.BlockStmt)
+ if len(body.List) > 0 {
+ // Is body { elem := x.At(i); ... } ?
+ if v := isVarAssign(body.List[0]); v != nil {
+ return v.Name(), v
+ }
+
+ // Or { if elem := x.At(i); cond { ... } } ?
+ if ifstmt, ok := body.List[0].(*ast.IfStmt); ok && ifstmt.Init != nil {
+ if v := isVarAssign(ifstmt.Init); v != nil {
+ return v.Name(), v
}
}
}
loop := curBody.Parent().Node()
- return refactor.FreshName(info.Scopes[loop], loop.Pos(), row.elemname), nil
+
+ // 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
+ }
+ }
+ }
+ return name, nil
}
// Process each call of x.Len().
@@ -191,7 +224,7 @@ func stditerators(pass *analysis.Pass) (any, error) {
}
// Have: for i := 0; i < x.Len(); i++ { ... }.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- rng = analysisinternal.Range(loop.For, loop.Post.End())
+ rng = astutil.RangeOf(loop.For, loop.Post.End())
indexVar = v
curBody = curFor.ChildAt(edge.ForStmt_Body, -1)
elem, elemVar = chooseName(curBody, lenSel.X, indexVar)
@@ -234,7 +267,7 @@ func stditerators(pass *analysis.Pass) (any, error) {
// Have: for i := range x.Len() { ... }
// ~~~~~~~~~~~~~
- rng = analysisinternal.Range(loop.Range, loop.X.End())
+ rng = astutil.RangeOf(loop.Range, loop.X.End())
indexVar = info.Defs[id].(*types.Var)
curBody = curRange.ChildAt(edge.RangeStmt_Body, -1)
elem, elemVar = chooseName(curBody, lenSel.X, indexVar)
@@ -313,7 +346,7 @@ func stditerators(pass *analysis.Pass) (any, error) {
// may be somewhat expensive.)
if v, ok := methodGoVersion(row.pkgpath, row.typename, row.itermethod); !ok {
panic("no version found")
- } else if file := astutil.EnclosingFile(curLenCall); !fileUses(info, file, v.String()) {
+ } else if !analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(curLenCall), v.String()) {
continue nextCall
}
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 56d0ba73cc..56c5d0e3b3 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
@@ -15,9 +15,8 @@ import (
"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/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/refactor"
"golang.org/x/tools/internal/typesinternal"
@@ -26,9 +25,8 @@ import (
var StringsBuilderAnalyzer = &analysis.Analyzer{
Name: "stringsbuilder",
- Doc: analysisinternal.MustExtractDoc(doc, "stringsbuilder"),
+ Doc: analyzerutil.MustExtractDoc(doc, "stringsbuilder"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -38,8 +36,6 @@ var StringsBuilderAnalyzer = &analysis.Analyzer{
// stringsbuilder replaces string += string in a loop by strings.Builder.
func stringsbuilder(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
// Skip the analyzer in packages where its
// fixes would create an import cycle.
if within(pass, "strings", "runtime") {
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
new file mode 100644
index 0000000000..521c264c51
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go
@@ -0,0 +1,580 @@
+// Copyright 2025 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/constant"
+ "go/token"
+ "go/types"
+ "iter"
+ "strconv"
+
+ "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 stringscutAnalyzer = &analysis.Analyzer{
+ Name: "stringscut",
+ Doc: analyzerutil.MustExtractDoc(doc, "stringscut"),
+ Requires: []*analysis.Analyzer{
+ inspect.Analyzer,
+ typeindexanalyzer.Analyzer,
+ },
+ Run: stringscut,
+ URL: "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/modernize#stringscut",
+}
+
+func init() {
+ // Export to gopls until this is a published modernizer.
+ goplsexport.StringsCutModernizer = stringscutAnalyzer
+}
+
+// stringscut offers a fix to replace an occurrence of strings.Index{,Byte} with
+// strings.{Cut,Contains}, and similar fixes for functions in the bytes package.
+// Consider some candidate for replacement i := strings.Index(s, substr).
+// The following must hold for a replacement to occur:
+//
+// 1. All instances of i and s must be in one of these forms.
+// Binary expressions:
+// (a): establishing that i < 0: e.g.: i < 0, 0 > i, i == -1, -1 == i
+// (b): establishing that i > -1: e.g.: i >= 0, 0 <= i, i == 0, 0 == i
+//
+// Slice expressions:
+// a: s[:i], s[0:i]
+// b: s[i+len(substr):], s[len(substr) + i:], s[i + const], s[k + i] (where k = len(substr))
+//
+// 2. There can be no uses of s, substr, or i where they are
+// potentially modified (i.e. in assignments, or function calls with unknown side
+// effects).
+//
+// Then, the replacement involves the following substitutions:
+//
+// 1. Replace "i := strings.Index(s, substr)" with "before, after, ok := strings.Cut(s, substr)"
+//
+// 2. Replace instances of binary expressions (a) with !ok and binary expressions (b) with ok.
+//
+// 3. Replace slice expressions (a) with "before" and slice expressions (b) with after.
+//
+// 4. The assignments to before, after, and ok may use the blank identifier "_" if they are unused.
+//
+// For example:
+//
+// i := strings.Index(s, substr)
+// if i >= 0 {
+// use(s[:i], s[i+len(substr):])
+// }
+//
+// Would become:
+//
+// before, after, ok := strings.Cut(s, substr)
+// if ok {
+// use(before, after)
+// }
+//
+// If the condition involving `i` establishes that i > -1, then we replace it with
+// `if ok“. Variants listed above include i >= 0, i > 0, and i == 0.
+// If the condition is negated (e.g. establishes `i < 0`), we use `if !ok` instead.
+// If the slices of `s` match `s[:i]` or `s[i+len(substr):]` or their variants listed above,
+// then we replace them with before and after.
+//
+// When the index `i` is used only to check for the presence of the substring or byte slice,
+// the suggested fix uses Contains() instead of Cut.
+//
+// For example:
+//
+// i := strings.Index(s, substr)
+// if i >= 0 {
+// return
+// }
+//
+// Would become:
+//
+// found := strings.Contains(s, substr)
+// if found {
+// return
+// }
+func stringscut(pass *analysis.Pass) (any, error) {
+ var (
+ index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
+ info = pass.TypesInfo
+
+ stringsIndex = index.Object("strings", "Index")
+ stringsIndexByte = index.Object("strings", "IndexByte")
+ bytesIndex = index.Object("bytes", "Index")
+ bytesIndexByte = index.Object("bytes", "IndexByte")
+ )
+
+ for _, obj := range []types.Object{
+ stringsIndex,
+ stringsIndexByte,
+ bytesIndex,
+ bytesIndexByte,
+ } {
+ // (obj may be nil)
+ nextcall:
+ for curCall := range index.Calls(obj) {
+ // Check file version.
+ if !analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(curCall), versions.Go1_18) {
+ continue // strings.Index not available in this file
+ }
+ indexCall := curCall.Node().(*ast.CallExpr) // the call to strings.Index, etc.
+ obj := typeutil.Callee(info, indexCall)
+ if obj == nil {
+ continue
+ }
+
+ var iIdent *ast.Ident // defining identifier of i var
+ switch ek, idx := curCall.ParentEdge(); ek {
+ case edge.ValueSpec_Values:
+ // Have: var i = strings.Index(...)
+ curName := curCall.Parent().ChildAt(edge.ValueSpec_Names, idx)
+ iIdent = curName.Node().(*ast.Ident)
+ case edge.AssignStmt_Rhs:
+ // Have: i := strings.Index(...)
+ // (Must be i's definition.)
+ curLhs := curCall.Parent().ChildAt(edge.AssignStmt_Lhs, idx)
+ iIdent, _ = curLhs.Node().(*ast.Ident) // may be nil
+ }
+
+ if iIdent == nil {
+ continue
+ }
+ // Inv: iIdent is i's definition. The following would be skipped: 'var i int; i = strings.Index(...)'
+ // Get uses of i.
+ iObj := info.ObjectOf(iIdent)
+ if iObj == nil {
+ continue
+ }
+
+ var (
+ s = indexCall.Args[0]
+ substr = indexCall.Args[1]
+ )
+
+ // Check that there are no statements that alter the value of s
+ // or substr after the call to Index().
+ if !indexArgValid(info, index, s, indexCall.Pos()) ||
+ !indexArgValid(info, index, substr, indexCall.Pos()) {
+ continue nextcall
+ }
+
+ // Next, examine all uses of i. If the only uses are of the
+ // forms mentioned above (e.g. i < 0, i >= 0, s[:i] and s[i +
+ // 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.
+ lessZero, greaterNegOne, beforeSlice, afterSlice := checkIdxUses(pass.TypesInfo, index.Uses(iObj), s, substr)
+
+ // 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.
+ if lessZero == nil && greaterNegOne == nil && beforeSlice == nil && afterSlice == nil {
+ continue
+ }
+
+ // If the only uses are ok and !ok, don't suggest a Cut() fix - these should be using Contains()
+ isContains := (len(lessZero) > 0 || len(greaterNegOne) > 0) && len(beforeSlice) == 0 && len(afterSlice) == 0
+
+ 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()
+ )
+
+ // If there will be no uses of ok, before, or after, use the
+ // blank identifier instead.
+ if len(lessZero) == 0 && len(greaterNegOne) == 0 {
+ okVarName = "_"
+ }
+ if len(beforeSlice) == 0 {
+ beforeVarName = "_"
+ }
+ if len(afterSlice) == 0 {
+ afterVarName = "_"
+ }
+
+ var edits []analysis.TextEdit
+ replace := func(exprs []ast.Expr, new string) {
+ for _, expr := range exprs {
+ edits = append(edits, analysis.TextEdit{
+ Pos: expr.Pos(),
+ End: expr.End(),
+ NewText: []byte(new),
+ })
+ }
+ }
+ // Get the ident for the call to strings.Index, which could just be
+ // "Index" if the strings package is dot imported.
+ indexCallId := typesinternal.UsedIdent(info, indexCall.Fun)
+ replacedFunc := "Cut"
+ if isContains {
+ replacedFunc = "Contains"
+ replace(lessZero, "!"+foundVarName) // idx < 0 -> !found
+ replace(greaterNegOne, foundVarName) // idx > -1 -> found
+
+ // Replace the assignment with found, and replace the call to
+ // Index or IndexByte with a call to Contains.
+ // i := strings.Index (...)
+ // ----- --------
+ // found := strings.Contains(...)
+ edits = append(edits, analysis.TextEdit{
+ Pos: iIdent.Pos(),
+ End: iIdent.End(),
+ NewText: []byte(foundVarName),
+ }, analysis.TextEdit{
+ Pos: indexCallId.Pos(),
+ End: indexCallId.End(),
+ NewText: []byte("Contains"),
+ })
+ } else {
+ replace(lessZero, "!"+okVarName) // idx < 0 -> !ok
+ replace(greaterNegOne, okVarName) // idx > -1 -> ok
+ replace(beforeSlice, beforeVarName) // s[:idx] -> before
+ replace(afterSlice, afterVarName) // s[idx+k:] -> after
+
+ // Replace the assignment with before, after, ok, and replace
+ // the call to Index or IndexByte with a call to Cut.
+ // i := strings.Index(...)
+ // ----------------- -----
+ // before, after, ok := strings.Cut (...)
+ edits = append(edits, analysis.TextEdit{
+ Pos: iIdent.Pos(),
+ End: iIdent.End(),
+ NewText: fmt.Appendf(nil, "%s, %s, %s", beforeVarName, afterVarName, okVarName),
+ }, analysis.TextEdit{
+ Pos: indexCallId.Pos(),
+ End: indexCallId.End(),
+ NewText: []byte("Cut"),
+ })
+ }
+
+ // Calls to IndexByte have a byte as their second arg, which
+ // must be converted to a string or []byte to be a valid arg for Cut/Contains.
+ if obj.Name() == "IndexByte" {
+ switch obj.Pkg().Name() {
+ case "strings":
+ searchByteVal := info.Types[substr].Value
+ if searchByteVal == nil {
+ // substr is a variable, e.g. substr := byte('b')
+ // use string(substr)
+ edits = append(edits, []analysis.TextEdit{
+ {
+ Pos: substr.Pos(),
+ NewText: []byte("string("),
+ },
+ {
+ Pos: substr.End(),
+ NewText: []byte(")"),
+ },
+ }...)
+ } else {
+ // substr is a byte constant
+ val, _ := constant.Int64Val(searchByteVal) // inv: must be a valid byte
+ // strings.Cut/Contains requires a string, so convert byte literal to string literal; e.g. 'a' -> "a", 55 -> "7"
+ edits = append(edits, analysis.TextEdit{
+ Pos: substr.Pos(),
+ End: substr.End(),
+ NewText: strconv.AppendQuote(nil, string(byte(val))),
+ })
+ }
+ case "bytes":
+ // bytes.Cut/Contains requires a []byte, so wrap substr in a []byte{}
+ edits = append(edits, []analysis.TextEdit{
+ {
+ Pos: substr.Pos(),
+ NewText: []byte("[]byte{"),
+ },
+ {
+ Pos: substr.End(),
+ NewText: []byte("}"),
+ },
+ }...)
+ }
+ }
+ pass.Report(analysis.Diagnostic{
+ Pos: indexCall.Fun.Pos(),
+ End: indexCall.Fun.End(),
+ Message: fmt.Sprintf("%s.%s can be simplified using %s.%s",
+ obj.Pkg().Name(), obj.Name(), obj.Pkg().Name(), replacedFunc),
+ Category: "stringscut",
+ SuggestedFixes: []analysis.SuggestedFix{{
+ Message: fmt.Sprintf("Simplify %s.%s call using %s.%s", obj.Pkg().Name(), obj.Name(), obj.Pkg().Name(), replacedFunc),
+ TextEdits: edits,
+ }},
+ })
+ }
+ }
+
+ return nil, nil
+}
+
+// indexArgValid reports whether expr is a valid strings.Index(_, _) arg
+// for the transformation. An arg is valid iff it is:
+// - constant;
+// - a local variable with no modifying uses after the Index() call; or
+// - []byte(x) where x is also valid by this definition.
+// All other expressions are assumed not referentially transparent,
+// so we cannot be sure that all uses are safe to replace.
+func indexArgValid(info *types.Info, index *typeindex.Index, expr ast.Expr, afterPos token.Pos) bool {
+ tv := info.Types[expr]
+ if tv.Value != nil {
+ return true // constant
+ }
+ switch expr := expr.(type) {
+ case *ast.CallExpr:
+ return types.Identical(tv.Type, byteSliceType) &&
+ indexArgValid(info, index, expr.Args[0], afterPos) // check s in []byte(s)
+ case *ast.Ident:
+ sObj := info.Uses[expr]
+ sUses := index.Uses(sObj)
+ return !hasModifyingUses(info, sUses, afterPos)
+ default:
+ // For now, skip instances where s or substr are not
+ // identifers, basic lits, or call expressions of the form
+ // []byte(s).
+ // TODO(mkalil): Handle s and substr being expressions like ptr.field[i].
+ // From adonovan: We'd need to analyze s and substr to see
+ // whether they are referentially transparent, and if not,
+ // analyze all code between declaration and use and see if
+ // there are statements or expressions with potential side
+ // effects.
+ return false
+ }
+}
+
+// checkIdxUses inspects the uses of i to make sure they match certain criteria that
+// allows us to suggest a modernization. If all uses of i, s and substr match
+// one of the following four valid formats, it returns a list of occurrences for
+// each format. If any of the uses do not match one of the formats, return nil
+// for all values, since we should not offer a replacement.
+// 1. lessZero - a condition involving i establishing that i is negative (e.g. i < 0, 0 > i, i == -1, -1 == i)
+// 2. greaterNegOne - a condition involving i establishing that i is non-negative (e.g. i >= 0, 0 <= i, i == 0, 0 == i)
+// 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) (lessZero, greaterNegOne, beforeSlice, afterSlice []ast.Expr) {
+ use := func(cur inspector.Cursor) bool {
+ ek, _ := cur.ParentEdge()
+ n := cur.Parent().Node()
+ switch ek {
+ case edge.BinaryExpr_X, edge.BinaryExpr_Y:
+ check := n.(*ast.BinaryExpr)
+ switch checkIdxComparison(info, check) {
+ case -1:
+ lessZero = append(lessZero, check)
+ return true
+ case 1:
+ greaterNegOne = append(greaterNegOne, check)
+ return true
+ }
+ // Check does not establish that i < 0 or i > -1.
+ // Might be part of an outer slice expression like s[i + k]
+ // which requires a different check.
+ // Check that the thing being sliced is s and that the slice
+ // doesn't have a max index.
+ if slice, ok := cur.Parent().Parent().Node().(*ast.SliceExpr); ok &&
+ sameObject(info, s, slice.X) &&
+ slice.Max == nil {
+ if isBeforeSlice(info, ek, slice) {
+ beforeSlice = append(beforeSlice, slice)
+ return true
+ } else if isAfterSlice(info, ek, slice, substr) {
+ afterSlice = append(afterSlice, slice)
+ return true
+ }
+ }
+ case edge.SliceExpr_Low, edge.SliceExpr_High:
+ slice := n.(*ast.SliceExpr)
+ // 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) {
+ beforeSlice = append(beforeSlice, slice)
+ return true
+ } else if isAfterSlice(info, ek, slice, substr) {
+ afterSlice = append(afterSlice, slice)
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ for curIdent := range uses {
+ if !use(curIdent) {
+ return nil, nil, nil, nil
+ }
+ }
+ return lessZero, greaterNegOne, beforeSlice, afterSlice
+}
+
+// hasModifyingUses reports whether any of the uses involve potential
+// modifications. Uses involving assignments before the "afterPos" won't be
+// considered.
+func hasModifyingUses(info *types.Info, uses iter.Seq[inspector.Cursor], afterPos token.Pos) bool {
+ for curUse := range uses {
+ ek, _ := curUse.ParentEdge()
+ if ek == edge.AssignStmt_Lhs {
+ if curUse.Node().Pos() <= afterPos {
+ continue
+ }
+ assign := curUse.Parent().Node().(*ast.AssignStmt)
+ if sameObject(info, assign.Lhs[0], curUse.Node().(*ast.Ident)) {
+ // Modifying use because we are reassigning the value of the object.
+ return true
+ }
+ } else if ek == edge.UnaryExpr_X &&
+ curUse.Parent().Node().(*ast.UnaryExpr).Op == token.AND {
+ // Modifying use because we might be passing the object by reference (an explicit &).
+ // We can ignore the case where we have a method call on the expression (which
+ // has an implicit &) because we know the type of s and substr are strings
+ // which cannot have methods on them.
+ return true
+ }
+ }
+ return false
+}
+
+// checkIdxComparison reports whether the check establishes that i is negative
+// or non-negative. It returns -1 in the first case, 1 in the second, and 0 if
+// we can confirm neither condition. We assume that a check passed to
+// checkIdxComparison has i as one of its operands.
+func checkIdxComparison(info *types.Info, check *ast.BinaryExpr) int {
+ // Check establishes that i is negative.
+ // e.g.: i < 0, 0 > i, i == -1, -1 == i
+ if check.Op == token.LSS && (isNegativeConst(info, check.Y) || isZeroIntConst(info, check.Y)) || //i < (0 or neg)
+ check.Op == token.GTR && (isNegativeConst(info, check.X) || isZeroIntConst(info, check.X)) || // (0 or neg) > i
+ check.Op == token.LEQ && (isNegativeConst(info, check.Y)) || //i <= (neg)
+ check.Op == token.GEQ && (isNegativeConst(info, check.X)) || // (neg) >= i
+ check.Op == token.EQL &&
+ (isNegativeConst(info, check.X) || isNegativeConst(info, check.Y)) { // i == neg; neg == i
+ return -1
+ }
+ // Check establishes that i is non-negative.
+ // e.g.: i >= 0, 0 <= i, i == 0, 0 == i
+ if check.Op == token.GTR && (isNonNegativeConst(info, check.Y) || isIntLiteral(info, check.Y, -1)) || // i > (non-neg or -1)
+ check.Op == token.LSS && (isNonNegativeConst(info, check.X) || isIntLiteral(info, check.X, -1)) || // (non-neg or -1) < i
+ check.Op == token.GEQ && isNonNegativeConst(info, check.Y) || // i >= (non-neg)
+ check.Op == token.LEQ && isNonNegativeConst(info, check.X) || // (non-neg) <= i
+ check.Op == token.EQL &&
+ (isNonNegativeConst(info, check.X) || isNonNegativeConst(info, check.Y)) { // i == non-neg; non-neg == i
+ return 1
+ }
+ return 0
+}
+
+// isNegativeConst returns true if the expr is a const int with value < zero.
+func isNegativeConst(info *types.Info, expr ast.Expr) bool {
+ if tv, ok := info.Types[expr]; ok && tv.Value != nil && tv.Value.Kind() == constant.Int {
+ if v, ok := constant.Int64Val(tv.Value); ok {
+ return v < 0
+ }
+ }
+ return false
+}
+
+// isNoneNegativeConst returns true if the expr is a const int with value >= zero.
+func isNonNegativeConst(info *types.Info, expr ast.Expr) bool {
+ if tv, ok := info.Types[expr]; ok && tv.Value != nil && tv.Value.Kind() == constant.Int {
+ if v, ok := constant.Int64Val(tv.Value); ok {
+ return v >= 0
+ }
+ }
+ return false
+}
+
+// isBeforeSlice reports whether the SliceExpr is of the form s[:i] or s[0:i].
+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
+ }
+
+ // Handle len([]byte(substr))
+ if is[*ast.CallExpr](substr) {
+ call := substr.(*ast.CallExpr)
+ 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))
+ 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
+ }
+ }
+
+ switch ek {
+ case edge.BinaryExpr_X:
+ kVal := info.Types[lowExpr.Y].Value
+ if kVal == nil {
+ // i + len(substr)
+ return lowExpr.Op == token.ADD && isLenCall(lowExpr.Y)
+ } else {
+ // i + k
+ kInt, ok := constant.Int64Val(kVal)
+ return ok && substrLen == int(kInt)
+ }
+ case edge.BinaryExpr_Y:
+ kVal := info.Types[lowExpr.X].Value
+ if kVal == nil {
+ // len(substr) + i
+ return lowExpr.Op == token.ADD && isLenCall(lowExpr.X)
+ } else {
+ // k + i
+ kInt, ok := constant.Int64Val(kVal)
+ return ok && substrLen == int(kInt)
+ }
+ }
+ 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 {
+ if ident2, ok := expr2.(*ast.Ident); ok {
+ uses1, ok1 := info.Uses[ident1]
+ uses2, ok2 := info.Uses[ident2]
+ return ok1 && ok2 && uses1 == uses2
+ }
+ }
+ return false
+}
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 9e76f953ed..7dc11308dd 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
@@ -12,22 +12,20 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
- "golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/refactor"
"golang.org/x/tools/internal/typesinternal"
"golang.org/x/tools/internal/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
)
var StringsCutPrefixAnalyzer = &analysis.Analyzer{
Name: "stringscutprefix",
- Doc: analysisinternal.MustExtractDoc(doc, "stringscutprefix"),
+ Doc: analyzerutil.MustExtractDoc(doc, "stringscutprefix"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -56,12 +54,9 @@ var StringsCutPrefixAnalyzer = &analysis.Analyzer{
// Variants:
// - bytes.HasPrefix/HasSuffix usage as pattern 1.
func stringscutprefix(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
var (
- inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
- info = pass.TypesInfo
+ index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
+ info = pass.TypesInfo
stringsTrimPrefix = index.Object("strings", "TrimPrefix")
bytesTrimPrefix = index.Object("bytes", "TrimPrefix")
@@ -72,7 +67,7 @@ func stringscutprefix(pass *analysis.Pass) (any, error) {
return nil, nil
}
- for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.20") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_20) {
for curIfStmt := range curFile.Preorder((*ast.IfStmt)(nil)) {
ifStmt := curIfStmt.Node().(*ast.IfStmt)
@@ -206,6 +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")
// Have one of:
// if rest := TrimPrefix(s, prefix); rest != s { (ditto Suffix)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsseq.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsseq.go
index ef2b546364..d02a53230f 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsseq.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsseq.go
@@ -13,19 +13,17 @@ import (
"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/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
+ typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
"golang.org/x/tools/internal/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
)
var StringsSeqAnalyzer = &analysis.Analyzer{
Name: "stringsseq",
- Doc: analysisinternal.MustExtractDoc(doc, "stringsseq"),
+ Doc: analyzerutil.MustExtractDoc(doc, "stringsseq"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -48,12 +46,9 @@ var StringsSeqAnalyzer = &analysis.Analyzer{
// - bytes.SplitSeq
// - bytes.FieldsSeq
func stringsseq(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
var (
- inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
- info = pass.TypesInfo
+ index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
+ info = pass.TypesInfo
stringsSplit = index.Object("strings", "Split")
stringsFields = index.Object("strings", "Fields")
@@ -64,7 +59,7 @@ func stringsseq(pass *analysis.Pass) (any, error) {
return nil, nil
}
- for curFile := range filesUsing(inspect, info, "go1.24") {
+ for curFile := range filesUsingGoVersion(pass, versions.Go1_24) {
for curRange := range curFile.Preorder((*ast.RangeStmt)(nil)) {
rng := curRange.Node().(*ast.RangeStmt)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/testingcontext.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/testingcontext.go
index 558cf142dd..939330521c 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/testingcontext.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/testingcontext.go
@@ -17,19 +17,18 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/edge"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/typesinternal"
"golang.org/x/tools/internal/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
)
var TestingContextAnalyzer = &analysis.Analyzer{
Name: "testingcontext",
- Doc: analysisinternal.MustExtractDoc(doc, "testingcontext"),
+ Doc: analyzerutil.MustExtractDoc(doc, "testingcontext"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -56,8 +55,6 @@ var TestingContextAnalyzer = &analysis.Analyzer{
// - the call is within a test or subtest function
// - the relevant testing.{T,B,F} is named and not shadowed at the call
func testingContext(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
var (
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
info = pass.TypesInfo
@@ -137,7 +134,7 @@ calls:
testObj = isTestFn(info, n)
}
}
- if testObj != nil && fileUses(info, astutil.EnclosingFile(cur), "go1.24") {
+ if testObj != nil && analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(cur), versions.Go1_24) {
// Have a test function. Check that we can resolve the relevant
// testing.{T,B,F} at the current position.
if _, obj := lhs[0].Parent().LookupParent(testObj.Name(), lhs[0].Pos()); obj == testObj {
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/waitgroup.go
index b890f334ba..19564c69b6 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/waitgroup.go
@@ -14,19 +14,18 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/analysisinternal/generated"
- typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "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/refactor"
"golang.org/x/tools/internal/typesinternal/typeindex"
+ "golang.org/x/tools/internal/versions"
)
var WaitGroupAnalyzer = &analysis.Analyzer{
Name: "waitgroup",
- Doc: analysisinternal.MustExtractDoc(doc, "waitgroup"),
+ Doc: analyzerutil.MustExtractDoc(doc, "waitgroup"),
Requires: []*analysis.Analyzer{
- generated.Analyzer,
inspect.Analyzer,
typeindexanalyzer.Analyzer,
},
@@ -61,8 +60,6 @@ var WaitGroupAnalyzer = &analysis.Analyzer{
// other effects, or blocked, or if WaitGroup.Go propagated panics
// from child to parent goroutine, the argument would be different.)
func waitgroup(pass *analysis.Pass) (any, error) {
- skipGenerated(pass)
-
var (
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
info = pass.TypesInfo
@@ -128,7 +125,7 @@ func waitgroup(pass *analysis.Pass) (any, error) {
}
file := astutil.EnclosingFile(curAddCall)
- if !fileUses(info, file, "go1.25") {
+ if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_25) {
continue
}
tokFile := pass.Fset.File(file.Pos())
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go
index 2b5a7c8037..6b37295187 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go
@@ -15,7 +15,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -24,7 +24,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "nilfunc",
- Doc: analysisinternal.MustExtractDoc(doc, "nilfunc"),
+ Doc: analyzerutil.MustExtractDoc(doc, "nilfunc"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilfunc",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
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 910ffe70d7..1eac2589bf 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
@@ -21,7 +21,7 @@ import (
"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/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/fmtstr"
"golang.org/x/tools/internal/typeparams"
@@ -38,7 +38,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "printf",
- Doc: analysisinternal.MustExtractDoc(doc, "printf"),
+ Doc: analyzerutil.MustExtractDoc(doc, "printf"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/printf",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
@@ -612,7 +612,7 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C
// breaking existing tests and CI scripts.
if idx == len(call.Args)-1 &&
fileVersion != "" && // fail open
- versions.AtLeast(fileVersion, "go1.24") {
+ versions.AtLeast(fileVersion, versions.Go1_24) {
pass.Report(analysis.Diagnostic{
Pos: formatArg.Pos(),
@@ -662,7 +662,7 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C
anyIndex = true
}
rng := opRange(formatArg, op)
- if !okPrintfArg(pass, call, rng, &maxArgIndex, firstArg, name, op) {
+ if !okPrintfArg(pass, fileVersion, call, rng, &maxArgIndex, firstArg, name, op) {
// One error per format is enough.
return
}
@@ -694,9 +694,9 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C
// such as the position of the %v substring of "...%v...".
func opRange(formatArg ast.Expr, op *fmtstr.Operation) analysis.Range {
if lit, ok := formatArg.(*ast.BasicLit); ok {
- start, end, err := astutil.RangeInStringLiteral(lit, op.Range.Start, op.Range.End)
+ rng, err := astutil.RangeInStringLiteral(lit, op.Range.Start, op.Range.End)
if err == nil {
- return analysisinternal.Range(start, end) // position of "%v"
+ return rng // position of "%v"
}
}
return formatArg // entire format string
@@ -707,6 +707,7 @@ type printfArgType int
const (
argBool printfArgType = 1 << iota
+ argByte
argInt
argRune
argString
@@ -751,7 +752,7 @@ var printVerbs = []printVerb{
{'o', sharpNumFlag, argInt | argPointer},
{'O', sharpNumFlag, argInt | argPointer},
{'p', "-#", argPointer},
- {'q', " -+.0#", argRune | argInt | argString},
+ {'q', " -+.0#", argRune | argInt | argString}, // note: when analyzing go1.26 code, argInt => argByte
{'s', " -+.0", argString},
{'t', "-", argBool},
{'T', "-", anyType},
@@ -765,7 +766,7 @@ var printVerbs = []printVerb{
// okPrintfArg compares the operation to the arguments actually present,
// reporting any discrepancies it can discern, maxArgIndex was the index of the highest used index.
// If the final argument is ellipsissed, there's little it can do for that.
-func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, rng analysis.Range, maxArgIndex *int, firstArg int, name string, operation *fmtstr.Operation) (ok bool) {
+func okPrintfArg(pass *analysis.Pass, fileVersion string, call *ast.CallExpr, rng analysis.Range, maxArgIndex *int, firstArg int, name string, operation *fmtstr.Operation) (ok bool) {
verb := operation.Verb.Verb
var v printVerb
found := false
@@ -777,6 +778,13 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, rng analysis.Range, ma
}
}
+ // When analyzing go1.26 code, rune and byte are the only %q integers (#72850).
+ if verb == 'q' &&
+ fileVersion != "" && // fail open
+ versions.AtLeast(fileVersion, versions.Go1_26) {
+ v.typ = argRune | argByte | argString
+ }
+
// Could verb's arg implement fmt.Formatter?
// Skip check for the %w verb, which requires an error.
formatter := false
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go
index f7e50f98a9..2cc5c23f12 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go
@@ -204,8 +204,7 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
case *types.Struct:
// report whether all the elements of the struct match the expected type. For
// instance, with "%d" all the elements must be printable with the "%d" format.
- for i := 0; i < typ.NumFields(); i++ {
- typf := typ.Field(i)
+ for typf := range typ.Fields() {
if !m.match(typf.Type(), false) {
return false
}
@@ -228,14 +227,20 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
types.Bool:
return m.t&argBool != 0
+ case types.Byte:
+ return m.t&(argInt|argByte) != 0
+
+ case types.Rune, types.UntypedRune:
+ return m.t&(argInt|argRune) != 0
+
case types.UntypedInt,
types.Int,
types.Int8,
types.Int16,
- types.Int32,
+ // see case Rune for int32
types.Int64,
types.Uint,
- types.Uint8,
+ // see case Byte for uint8
types.Uint16,
types.Uint32,
types.Uint64,
@@ -259,9 +264,6 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
case types.UnsafePointer:
return m.t&(argPointer|argInt) != 0
- case types.UntypedRune:
- return m.t&(argInt|argRune) != 0
-
case types.UntypedNil:
return false
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go
index 934f3913c2..174c27109e 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go
@@ -19,7 +19,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -29,7 +29,7 @@ var doc string
// Analyzer describes sigchanyzer analysis function detector.
var Analyzer = &analysis.Analyzer{
Name: "sigchanyzer",
- Doc: analysisinternal.MustExtractDoc(doc, "sigchanyzer"),
+ Doc: analyzerutil.MustExtractDoc(doc, "sigchanyzer"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/sigchanyzer",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
index 2cb91c7329..4afbe04684 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
@@ -19,7 +19,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -29,7 +29,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "slog",
- Doc: analysisinternal.MustExtractDoc(doc, "slog"),
+ Doc: analyzerutil.MustExtractDoc(doc, "slog"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/slog",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
@@ -168,7 +168,7 @@ func isAttr(t types.Type) bool {
// "slog.Logger.With" (instead of "(*log/slog.Logger).With")
func shortName(fn *types.Func) string {
var r string
- if recv := fn.Type().(*types.Signature).Recv(); recv != nil {
+ if recv := fn.Signature().Recv(); recv != nil {
if _, named := typesinternal.ReceiverNamed(recv); named != nil {
r = named.Obj().Name()
} else {
@@ -188,7 +188,7 @@ func kvFuncSkipArgs(fn *types.Func) (int, bool) {
return 0, false
}
var recvName string // by default a slog package function
- if recv := fn.Type().(*types.Signature).Recv(); recv != nil {
+ if recv := fn.Signature().Recv(); recv != nil {
_, named := typesinternal.ReceiverNamed(recv)
if named == nil {
return 0, false // anon struct/interface
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
index ca303ae5c1..b68385b242 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
@@ -13,7 +13,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
)
//go:embed doc.go
@@ -21,7 +21,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "stdmethods",
- Doc: analysisinternal.MustExtractDoc(doc, "stdmethods"),
+ Doc: analyzerutil.MustExtractDoc(doc, "stdmethods"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stdmethods",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
@@ -131,12 +131,12 @@ func canonicalMethod(pass *analysis.Pass, id *ast.Ident) {
}
// Do the =s (if any) all match?
- if !matchParams(pass, expect.args, args, "=") || !matchParams(pass, expect.results, results, "=") {
+ if !matchParams(expect.args, args, "=") || !matchParams(expect.results, results, "=") {
return
}
// Everything must match.
- if !matchParams(pass, expect.args, args, "") || !matchParams(pass, expect.results, results, "") {
+ if !matchParams(expect.args, args, "") || !matchParams(expect.results, results, "") {
expectFmt := id.Name + "(" + argjoin(expect.args) + ")"
if len(expect.results) == 1 {
expectFmt += " " + argjoin(expect.results)
@@ -168,7 +168,7 @@ func argjoin(x []string) string {
}
// Does each type in expect with the given prefix match the corresponding type in actual?
-func matchParams(pass *analysis.Pass, expect []string, actual *types.Tuple, prefix string) bool {
+func matchParams(expect []string, actual *types.Tuple, prefix string) bool {
for i, x := range expect {
if !strings.HasPrefix(x, prefix) {
continue
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
index 19c72d2cf9..0cbae68898 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
@@ -14,7 +14,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/refactor"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal"
@@ -25,7 +25,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "stringintconv",
- Doc: analysisinternal.MustExtractDoc(doc, "stringintconv"),
+ Doc: analyzerutil.MustExtractDoc(doc, "stringintconv"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stringintconv",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go
index eba4e56bb0..e38c266afe 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go
@@ -15,7 +15,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -30,7 +30,7 @@ func init() {
var Analyzer = &analysis.Analyzer{
Name: "testinggoroutine",
- Doc: analysisinternal.MustExtractDoc(doc, "testinggoroutine"),
+ Doc: analyzerutil.MustExtractDoc(doc, "testinggoroutine"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/testinggoroutine",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go
index db2e5f76d1..4b68a789cf 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go
@@ -36,7 +36,7 @@ func localFunctionDecls(info *types.Info, files []*ast.File) func(*types.Func) *
// isMethodNamed returns true if f is a method defined
// in package with the path pkgPath with a name in names.
//
-// (Unlike [analysisinternal.IsMethodNamed], it ignores the receiver type name.)
+// (Unlike [analysis.IsMethodNamed], it ignores the receiver type name.)
func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool {
if f == nil {
return false
@@ -44,7 +44,7 @@ func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool {
if f.Pkg() == nil || f.Pkg().Path() != pkgPath {
return false
}
- if f.Type().(*types.Signature).Recv() == nil {
+ if f.Signature().Recv() == nil {
return false
}
return slices.Contains(names, f.Name())
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
index a0ed5ab14e..1f33df8403 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
@@ -15,7 +15,8 @@ import (
"unicode/utf8"
"golang.org/x/tools/go/analysis"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -24,7 +25,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "tests",
- Doc: analysisinternal.MustExtractDoc(doc, "tests"),
+ Doc: analyzerutil.MustExtractDoc(doc, "tests"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/tests",
Run: run,
}
@@ -464,7 +465,7 @@ func checkTest(pass *analysis.Pass, fn *ast.FuncDecl, prefix string) {
if tparams := fn.Type.TypeParams; tparams != nil && len(tparams.List) > 0 {
// Note: cmd/go/internal/load also errors about TestXXX and BenchmarkXXX functions with type parameters.
// We have currently decided to also warn before compilation/package loading. This can help users in IDEs.
- pass.ReportRangef(analysisinternal.Range(tparams.Opening, tparams.Closing),
+ pass.ReportRangef(astutil.RangeOf(tparams.Opening, tparams.Closing),
"%s has type parameters: it will not be run by go test as a %sXXX function",
fn.Name.Name, prefix)
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
index 45b6822c17..8353c1efa9 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
@@ -18,7 +18,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -30,7 +30,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "timeformat",
- Doc: analysisinternal.MustExtractDoc(doc, "timeformat"),
+ Doc: analyzerutil.MustExtractDoc(doc, "timeformat"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/timeformat",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
@@ -39,7 +39,7 @@ var Analyzer = &analysis.Analyzer{
func run(pass *analysis.Pass) (any, error) {
// Note: (time.Time).Format is a method and can be a typeutil.Callee
// without directly importing "time". So we cannot just skip this package
- // when !analysisinternal.Imports(pass.Pkg, "time").
+ // when !analysis.Imports(pass.Pkg, "time").
// TODO(taking): Consider using a prepass to collect typeutil.Callees.
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
index 4de48c8393..38eb0b1063 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
@@ -13,7 +13,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -22,7 +22,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "unmarshal",
- Doc: analysisinternal.MustExtractDoc(doc, "unmarshal"),
+ Doc: analyzerutil.MustExtractDoc(doc, "unmarshal"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unmarshal",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
@@ -39,7 +39,7 @@ func run(pass *analysis.Pass) (any, error) {
// Note: (*"encoding/json".Decoder).Decode, (* "encoding/gob".Decoder).Decode
// and (* "encoding/xml".Decoder).Decode are methods and can be a typeutil.Callee
// without directly importing their packages. So we cannot just skip this package
- // when !analysisinternal.Imports(pass.Pkg, "encoding/...").
+ // when !analysis.Imports(pass.Pkg, "encoding/...").
// TODO(taking): Consider using a prepass to collect typeutil.Callees.
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
@@ -57,7 +57,7 @@ func run(pass *analysis.Pass) (any, error) {
// Classify the callee (without allocating memory).
argidx := -1
- recv := fn.Type().(*types.Signature).Recv()
+ recv := fn.Signature().Recv()
if fn.Name() == "Unmarshal" && recv == nil {
// "encoding/json".Unmarshal
// "encoding/xml".Unmarshal
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go
index 668a335299..532f38fe91 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go
@@ -15,7 +15,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/refactor"
)
@@ -24,7 +24,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "unreachable",
- Doc: analysisinternal.MustExtractDoc(doc, "unreachable"),
+ Doc: analyzerutil.MustExtractDoc(doc, "unreachable"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unreachable",
Requires: []*analysis.Analyzer{inspect.Analyzer},
RunDespiteErrors: true,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
index 24ff723390..ce785725e3 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
@@ -15,7 +15,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -24,7 +24,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "unsafeptr",
- Doc: analysisinternal.MustExtractDoc(doc, "unsafeptr"),
+ Doc: analyzerutil.MustExtractDoc(doc, "unsafeptr"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unsafeptr",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
index 57ad4f0769..bd32d58690 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
@@ -25,7 +25,8 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
+ "golang.org/x/tools/internal/astutil"
)
//go:embed doc.go
@@ -33,7 +34,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "unusedresult",
- Doc: analysisinternal.MustExtractDoc(doc, "unusedresult"),
+ Doc: analyzerutil.MustExtractDoc(doc, "unusedresult"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedresult",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
@@ -149,11 +150,11 @@ func run(pass *analysis.Pass) (any, error) {
if !ok {
return // e.g. var or builtin
}
- if sig := fn.Type().(*types.Signature); sig.Recv() != nil {
+ if sig := fn.Signature(); sig.Recv() != nil {
// method (e.g. foo.String())
if types.Identical(sig, sigNoArgsStringResult) {
if stringMethods[fn.Name()] {
- pass.ReportRangef(analysisinternal.Range(call.Pos(), call.Lparen),
+ pass.ReportRangef(astutil.RangeOf(call.Pos(), call.Lparen),
"result of (%s).%s call not used",
sig.Recv().Type(), fn.Name())
}
@@ -161,7 +162,7 @@ func run(pass *analysis.Pass) (any, error) {
} else {
// package-level function (e.g. fmt.Errorf)
if pkgFuncs[[2]string{fn.Pkg().Path(), fn.Name()}] {
- pass.ReportRangef(analysisinternal.Range(call.Pos(), call.Lparen),
+ pass.ReportRangef(astutil.RangeOf(call.Pos(), call.Lparen),
"result of %s.%s call not used",
fn.Pkg().Path(), fn.Name())
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go
index 88e4cc8677..c2e20521e9 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go
@@ -15,7 +15,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/analyzerutil"
"golang.org/x/tools/internal/typesinternal"
)
@@ -24,7 +24,7 @@ var doc string
var Analyzer = &analysis.Analyzer{
Name: "waitgroup",
- Doc: analysisinternal.MustExtractDoc(doc, "waitgroup"),
+ Doc: analyzerutil.MustExtractDoc(doc, "waitgroup"),
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/waitgroup",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
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 b407bc7791..0180a341e5 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
@@ -49,7 +49,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/internal/analysisflags"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/internal/analysis/driverutil"
"golang.org/x/tools/internal/facts"
)
@@ -183,16 +183,18 @@ func processResults(fset *token.FileSet, id string, results []result) (exit int)
// but apply all fixes from the root actions.
// Convert results to form needed by ApplyFixes.
- fixActions := make([]analysisflags.FixAction, len(results))
+ fixActions := make([]driverutil.FixAction, len(results))
for i, res := range results {
- fixActions[i] = analysisflags.FixAction{
+ fixActions[i] = driverutil.FixAction{
Name: res.a.Name,
+ Pkg: res.pkg,
+ Files: res.files,
FileSet: fset,
- ReadFileFunc: os.ReadFile,
+ ReadFileFunc: os.ReadFile, // TODO(adonovan): respect overlays
Diagnostics: res.diagnostics,
}
}
- if err := analysisflags.ApplyFixes(fixActions, false); err != nil {
+ if err := driverutil.ApplyFixes(fixActions, analysisflags.Diff, false); err != nil {
// Fail when applying fixes failed.
log.Print(err)
exit = 1
@@ -209,7 +211,7 @@ func processResults(fset *token.FileSet, id string, results []result) (exit int)
if analysisflags.JSON {
// JSON output
- tree := make(analysisflags.JSONTree)
+ tree := make(driverutil.JSONTree)
for _, res := range results {
tree.Add(fset, id, res.a.Name, res.diagnostics, res.err)
}
@@ -225,7 +227,7 @@ func processResults(fset *token.FileSet, id string, results []result) (exit int)
}
for _, res := range results {
for _, diag := range res.diagnostics {
- analysisflags.PrintPlain(os.Stderr, fset, analysisflags.Context, diag)
+ driverutil.PrintPlain(os.Stderr, fset, analysisflags.Context, diag)
exit = 1
}
}
@@ -428,7 +430,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
ResultOf: inputs,
Report: func(d analysis.Diagnostic) {
// Unitchecker doesn't apply fixes, but it does report them in the JSON output.
- if err := analysisinternal.ValidateFixes(fset, a, d.SuggestedFixes); err != nil {
+ if err := driverutil.ValidateFixes(fset, a, d.SuggestedFixes); err != nil {
// Since we have diagnostics, the exit code will be nonzero,
// so logging these errors is sufficient.
log.Println(err)
@@ -444,14 +446,14 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
AllPackageFacts: func() []analysis.PackageFact { return facts.AllPackageFacts(factFilter) },
Module: module,
}
- pass.ReadFile = analysisinternal.CheckedReadFile(pass, os.ReadFile)
+ pass.ReadFile = driverutil.CheckedReadFile(pass, os.ReadFile)
t0 := time.Now()
act.result, act.err = a.Run(pass)
if act.err == nil { // resolve URLs on diagnostics.
for i := range act.diagnostics {
- if url, uerr := analysisflags.ResolveURL(a, act.diagnostics[i]); uerr == nil {
+ if url, uerr := driverutil.ResolveURL(a, act.diagnostics[i]); uerr == nil {
act.diagnostics[i].URL = url
} else {
act.err = uerr // keep the last error
@@ -482,9 +484,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
results := make([]result, len(analyzers))
for i, a := range analyzers {
act := actions[a]
- results[i].a = a
- results[i].err = act.err
- results[i].diagnostics = act.diagnostics
+ results[i] = result{pkg, files, a, act.diagnostics, act.err}
}
data := facts.Encode()
@@ -499,6 +499,8 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
}
type result struct {
+ pkg *types.Package
+ files []*ast.File
a *analysis.Analyzer
diagnostics []analysis.Diagnostic
err error
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 7e72d3c284..fc9bbc714c 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
@@ -467,7 +467,9 @@ func (c Cursor) FindByPos(start, end token.Pos) (Cursor, bool) {
// This algorithm could be implemented using c.Inspect,
// but it is about 2.5x slower.
- best := int32(-1) // push index of latest (=innermost) node containing range
+ // best is the push-index of the latest (=innermost) node containing range.
+ // (Beware: latest is not always innermost because FuncDecl.{Name,Type} overlap.)
+ best := int32(-1)
for i, limit := c.indices(); i < limit; i++ {
ev := events[i]
if ev.index > i { // push?
@@ -481,6 +483,19 @@ func (c Cursor) FindByPos(start, end token.Pos) (Cursor, bool) {
continue
}
} else {
+ // Edge case: FuncDecl.Name and .Type overlap:
+ // Don't update best from Name to FuncDecl.Type.
+ //
+ // The condition can be read as:
+ // - n is FuncType
+ // - n.parent is FuncDecl
+ // - best is strictly beneath the FuncDecl
+ if ev.typ == 1<<nFuncType &&
+ events[ev.parent].typ == 1<<nFuncDecl &&
+ best > ev.parent {
+ continue
+ }
+
nodeEnd = n.End()
if n.Pos() > start {
break // disjoint, after; stop
diff --git a/src/cmd/vendor/golang.org/x/tools/go/cfg/builder.go b/src/cmd/vendor/golang.org/x/tools/go/cfg/builder.go
index ac4d63c400..f16cd42309 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/cfg/builder.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/cfg/builder.go
@@ -13,7 +13,7 @@ import (
)
type builder struct {
- cfg *CFG
+ blocks []*Block
mayReturn func(*ast.CallExpr) bool
current *Block
lblocks map[string]*lblock // labeled blocks
@@ -32,12 +32,18 @@ start:
*ast.SendStmt,
*ast.IncDecStmt,
*ast.GoStmt,
- *ast.DeferStmt,
*ast.EmptyStmt,
*ast.AssignStmt:
// No effect on control flow.
b.add(s)
+ case *ast.DeferStmt:
+ b.add(s)
+ // Assume conservatively that this behaves like:
+ // defer func() { recover() }
+ // so any subsequent panic may act like a return.
+ b.current.returns = true
+
case *ast.ExprStmt:
b.add(s)
if call, ok := s.X.(*ast.CallExpr); ok && !b.mayReturn(call) {
@@ -64,6 +70,7 @@ start:
goto start // effectively: tailcall stmt(g, s.Stmt, label)
case *ast.ReturnStmt:
+ b.current.returns = true
b.add(s)
b.current = b.newBlock(KindUnreachable, s)
@@ -483,14 +490,13 @@ func (b *builder) labeledBlock(label *ast.Ident, stmt *ast.LabeledStmt) *lblock
// It does not automatically become the current block.
// comment is an optional string for more readable debugging output.
func (b *builder) newBlock(kind BlockKind, stmt ast.Stmt) *Block {
- g := b.cfg
block := &Block{
- Index: int32(len(g.Blocks)),
+ Index: int32(len(b.blocks)),
Kind: kind,
Stmt: stmt,
}
block.Succs = block.succs2[:0]
- g.Blocks = append(g.Blocks, block)
+ b.blocks = append(b.blocks, block)
return block
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/cfg/cfg.go b/src/cmd/vendor/golang.org/x/tools/go/cfg/cfg.go
index 29a39f698c..38aba77c29 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/cfg/cfg.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/cfg/cfg.go
@@ -47,13 +47,16 @@ import (
"go/ast"
"go/format"
"go/token"
+
+ "golang.org/x/tools/internal/cfginternal"
)
// A CFG represents the control-flow graph of a single function.
//
// The entry point is Blocks[0]; there may be multiple return blocks.
type CFG struct {
- Blocks []*Block // block[0] is entry; order otherwise undefined
+ Blocks []*Block // block[0] is entry; order otherwise undefined
+ noreturn bool // function body lacks a reachable return statement
}
// A Block represents a basic block: a list of statements and
@@ -67,12 +70,13 @@ type CFG struct {
// an [ast.Expr], Succs[0] is the successor if the condition is true, and
// Succs[1] is the successor if the condition is false.
type Block struct {
- Nodes []ast.Node // statements, expressions, and ValueSpecs
- Succs []*Block // successor nodes in the graph
- Index int32 // index within CFG.Blocks
- Live bool // block is reachable from entry
- Kind BlockKind // block kind
- Stmt ast.Stmt // statement that gave rise to this block (see BlockKind for details)
+ Nodes []ast.Node // statements, expressions, and ValueSpecs
+ Succs []*Block // successor nodes in the graph
+ Index int32 // index within CFG.Blocks
+ Live bool // block is reachable from entry
+ returns bool // block contains return or defer (which may recover and return)
+ Kind BlockKind // block kind
+ Stmt ast.Stmt // statement that gave rise to this block (see BlockKind for details)
succs2 [2]*Block // underlying array for Succs
}
@@ -141,14 +145,14 @@ func (kind BlockKind) String() string {
func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG {
b := builder{
mayReturn: mayReturn,
- cfg: new(CFG),
}
b.current = b.newBlock(KindBody, body)
b.stmt(body)
- // Compute liveness (reachability from entry point), breadth-first.
- q := make([]*Block, 0, len(b.cfg.Blocks))
- q = append(q, b.cfg.Blocks[0]) // entry point
+ // Compute liveness (reachability from entry point),
+ // breadth-first, marking Block.Live flags.
+ q := make([]*Block, 0, len(b.blocks))
+ q = append(q, b.blocks[0]) // entry point
for len(q) > 0 {
b := q[len(q)-1]
q = q[:len(q)-1]
@@ -162,12 +166,30 @@ func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG {
// Does control fall off the end of the function's body?
// Make implicit return explicit.
if b.current != nil && b.current.Live {
+ b.current.returns = true
b.add(&ast.ReturnStmt{
Return: body.End() - 1,
})
}
- return b.cfg
+ // Is any return (or defer+recover) block reachable?
+ noreturn := true
+ for _, bl := range b.blocks {
+ if bl.Live && bl.returns {
+ noreturn = false
+ break
+ }
+ }
+
+ return &CFG{Blocks: b.blocks, noreturn: noreturn}
+}
+
+// isNoReturn reports whether the function has no reachable return.
+// TODO(adonovan): add (*CFG).NoReturn to public API.
+func isNoReturn(_cfg any) bool { return _cfg.(*CFG).noreturn }
+
+func init() {
+ cfginternal.IsNoReturn = isNoReturn // expose to ctrlflow analyzer
}
func (b *Block) String() string {
@@ -187,6 +209,14 @@ func (b *Block) comment(fset *token.FileSet) string {
//
// When control falls off the end of the function, the ReturnStmt is synthetic
// and its [ast.Node.End] position may be beyond the end of the file.
+//
+// A function that contains no return statement (explicit or implied)
+// may yet return normally, and may even return a nonzero value. For example:
+//
+// func() (res any) {
+// defer func() { res = recover() }()
+// panic(123)
+// }
func (b *Block) Return() (ret *ast.ReturnStmt) {
if len(b.Nodes) > 0 {
ret, _ = b.Nodes[len(b.Nodes)-1].(*ast.ReturnStmt)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
index 6c0c74968f..6646bf5508 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
@@ -249,7 +249,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
case *types.Func:
// A func, if not package-level, must be a method.
- if recv := obj.Type().(*types.Signature).Recv(); recv == nil {
+ if recv := obj.Signature().Recv(); recv == nil {
return "", fmt.Errorf("func is not a method: %v", obj)
}
@@ -405,7 +405,7 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
return "", false
}
- _, named := typesinternal.ReceiverNamed(meth.Type().(*types.Signature).Recv())
+ _, named := typesinternal.ReceiverNamed(meth.Signature().Recv())
if named == nil {
return "", false
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go b/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go
index f035a0b6be..36624572a6 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go
@@ -304,8 +304,7 @@ func (h hasher) hash(t types.Type) uint32 {
case *types.Named:
hash := h.hashTypeName(t.Obj())
targs := t.TypeArgs()
- for i := 0; i < targs.Len(); i++ {
- targ := targs.At(i)
+ for targ := range targs.Types() {
hash += 2 * h.hash(targ)
}
return hash
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/doc.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/doc.go
new file mode 100644
index 0000000000..74a2a1c815
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/doc.go
@@ -0,0 +1,6 @@
+// Copyright 2025 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 analyzerutil provides implementation helpers for analyzers.
+package analyzerutil
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/extractdoc.go
index c6cdf5997e..772a0300da 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/extractdoc.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package analysisinternal
+package analyzerutil
import (
"fmt"
@@ -35,7 +35,7 @@ import (
//
// var Analyzer = &analysis.Analyzer{
// Name: "halting",
-// Doc: analysisinternal.MustExtractDoc(doc, "halting"),
+// Doc: analyzerutil.MustExtractDoc(doc, "halting"),
// ...
// }
func MustExtractDoc(content, name string) string {
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/readfile.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/readfile.go
new file mode 100644
index 0000000000..ecc30cae04
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/readfile.go
@@ -0,0 +1,30 @@
+// Copyright 2025 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 analyzerutil
+
+// This file defines helpers for calling [analysis.Pass.ReadFile].
+
+import (
+ "go/token"
+ "os"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// ReadFile reads a file and adds it to the FileSet in pass
+// so that we can report errors against it using lineStart.
+func ReadFile(pass *analysis.Pass, filename string) ([]byte, *token.File, error) {
+ readFile := pass.ReadFile
+ if readFile == nil {
+ readFile = os.ReadFile
+ }
+ content, err := readFile(filename)
+ if err != nil {
+ return nil, nil, err
+ }
+ tf := pass.Fset.AddFile(filename, -1, len(content))
+ tf.SetLinesForContent(content)
+ return content, tf, nil
+}
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
new file mode 100644
index 0000000000..0b9bcc37b6
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/version.go
@@ -0,0 +1,42 @@
+// Copyright 2025 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 analyzerutil
+
+import (
+ "go/ast"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/internal/packagepath"
+ "golang.org/x/tools/internal/stdlib"
+ "golang.org/x/tools/internal/versions"
+)
+
+// FileUsesGoVersion reports whether the specified file may use features of the
+// specified version of Go (e.g. "go1.24").
+//
+// 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
+// operation is not free, yet is not a highly selective filter: the
+// 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]
+
+ // Standard packages that are part of toolchain bootstrapping
+ // are not considered to use a version of Go later than the
+ // current bootstrap toolchain version.
+ // The bootstrap rule does not cover tests,
+ // and some tests (e.g. debug/elf/file_test.go) rely on this.
+ pkgpath := pass.Pkg.Path()
+ if packagepath.IsStdPackage(pkgpath) &&
+ stdlib.IsBootstrapPackage(pkgpath) && // (excludes "*_test" external test packages)
+ !strings.HasSuffix(pass.Fset.File(file.Pos()).Name(), "_test.go") { // (excludes all tests)
+ fileVersion = stdlib.BootstrapVersion.String() // package must bootstrap
+ }
+
+ return !versions.Before(fileVersion, version)
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/fix.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/fix.go
index 43a456a457..ef06cf9bde 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/fix.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/fix.go
@@ -2,37 +2,48 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package analysisflags
+// Package driverutil defines implementation helper functions for
+// analysis drivers such as unitchecker, {single,multi}checker, and
+// analysistest.
+package driverutil
// This file defines the -fix logic common to unitchecker and
// {single,multi}checker.
import (
+ "bytes"
"fmt"
- "go/format"
+ "go/ast"
+ "go/parser"
+ "go/printer"
"go/token"
+ "go/types"
"log"
"maps"
"os"
"sort"
+ "strconv"
"golang.org/x/tools/go/analysis"
- "golang.org/x/tools/internal/analysisinternal"
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/internal/astutil/free"
"golang.org/x/tools/internal/diff"
)
// FixAction abstracts a checker action (running one analyzer on one
// package) for the purposes of applying its diagnostics' fixes.
type FixAction struct {
- Name string // e.g. "analyzer@package"
+ Name string // e.g. "analyzer@package"
+ Pkg *types.Package // (for import removal)
+ Files []*ast.File
FileSet *token.FileSet
- ReadFileFunc analysisinternal.ReadFileFunc
+ ReadFileFunc ReadFileFunc
Diagnostics []analysis.Diagnostic
}
// ApplyFixes attempts to apply the first suggested fix associated
// with each diagnostic reported by the specified actions.
-// All fixes must have been validated by [analysisinternal.ValidateFixes].
+// All fixes must have been validated by [ValidateFixes].
//
// Each fix is treated as an independent change; fixes are merged in
// an arbitrary deterministic order as if by a three-way diff tool
@@ -58,15 +69,15 @@ type FixAction struct {
// composition of the two fixes is semantically correct. Coalescing
// identical edits is appropriate for imports, but not for, say,
// increments to a counter variable; the correct resolution in that
-// case might be to increment it twice. Or consider two fixes that
-// each delete the penultimate reference to an import or local
-// variable: each fix is sound individually, and they may be textually
-// distant from each other, but when both are applied, the program is
-// no longer valid because it has an unreferenced import or local
-// variable.
-// TODO(adonovan): investigate replacing the final "gofmt" step with a
-// formatter that applies the unused-import deletion logic of
-// "goimports".
+// case might be to increment it twice.
+//
+// Or consider two fixes that each delete the penultimate reference to
+// a local variable: each fix is sound individually, and they may be
+// textually distant from each other, but when both are applied, the
+// program is no longer valid because it has an unreferenced local
+// variable. (ApplyFixes solves the analogous problem for imports by
+// eliminating imports whose name is unreferenced in the remainder of
+// the fixed file.)
//
// Merging depends on both the order of fixes and they order of edits
// within them. For example, if three fixes add import "a" twice and
@@ -80,12 +91,15 @@ type FixAction struct {
// applyFixes returns success if all fixes are valid, could be cleanly
// merged, and the corresponding files were successfully updated.
//
-// If the -diff flag was set, instead of updating the files it display the final
-// patch composed of all the cleanly merged fixes.
+// If printDiff (from the -diff flag) is set, instead of updating the
+// files it display the final patch composed of all the cleanly merged
+// fixes.
//
// TODO(adonovan): handle file-system level aliases such as symbolic
// links using robustio.FileID.
-func ApplyFixes(actions []FixAction, verbose bool) error {
+func ApplyFixes(actions []FixAction, printDiff, verbose bool) error {
+ generated := make(map[*token.File]bool)
+
// Select fixes to apply.
//
// If there are several for a given Diagnostic, choose the first.
@@ -96,6 +110,15 @@ func ApplyFixes(actions []FixAction, verbose bool) error {
}
var fixes []*fixact
for _, act := range actions {
+ for _, file := range act.Files {
+ tokFile := act.FileSet.File(file.FileStart)
+ // Memoize, since there may be many actions
+ // for the same package (list of files).
+ if _, seen := generated[tokFile]; !seen {
+ generated[tokFile] = ast.IsGenerated(file)
+ }
+ }
+
for _, diag := range act.Diagnostics {
for i := range diag.SuggestedFixes {
fix := &diag.SuggestedFixes[i]
@@ -119,7 +142,7 @@ func ApplyFixes(actions []FixAction, verbose bool) error {
// packages are not disjoint, due to test variants, so this
// would not really address the issue.)
baselineContent := make(map[string][]byte)
- getBaseline := func(readFile analysisinternal.ReadFileFunc, filename string) ([]byte, error) {
+ getBaseline := func(readFile ReadFileFunc, filename string) ([]byte, error) {
content, ok := baselineContent[filename]
if !ok {
var err error
@@ -134,16 +157,32 @@ func ApplyFixes(actions []FixAction, verbose bool) error {
// Apply each fix, updating the current state
// only if the entire fix can be cleanly merged.
- accumulatedEdits := make(map[string][]diff.Edit)
- goodFixes := 0
+ var (
+ accumulatedEdits = make(map[string][]diff.Edit)
+ filePkgs = make(map[string]*types.Package) // maps each file to an arbitrary package that includes it
+
+ goodFixes = 0 // number of fixes cleanly applied
+ skippedFixes = 0 // number of fixes skipped (because e.g. edits a generated file)
+ )
fixloop:
for _, fixact := range fixes {
+ // Skip a fix if any of its edits touch a generated file.
+ for _, edit := range fixact.fix.TextEdits {
+ file := fixact.act.FileSet.File(edit.Pos)
+ if generated[file] {
+ skippedFixes++
+ continue fixloop
+ }
+ }
+
// Convert analysis.TextEdits to diff.Edits, grouped by file.
// Precondition: a prior call to validateFix succeeded.
fileEdits := make(map[string][]diff.Edit)
for _, edit := range fixact.fix.TextEdits {
file := fixact.act.FileSet.File(edit.Pos)
+ filePkgs[file.Name()] = fixact.act.Pkg
+
baseline, err := getBaseline(fixact.act.ReadFileFunc, file.Name())
if err != nil {
log.Printf("skipping fix to file %s: %v", file.Name(), err)
@@ -191,7 +230,7 @@ fixloop:
log.Printf("%s: fix %s applied", fixact.act.Name, fixact.fix.Message)
}
}
- badFixes := len(fixes) - goodFixes
+ badFixes := len(fixes) - goodFixes - skippedFixes // number of fixes that could not be applied
// Show diff or update files to final state.
var files []string
@@ -214,11 +253,11 @@ fixloop:
}
// Attempt to format each file.
- if formatted, err := format.Source(final); err == nil {
+ if formatted, err := FormatSourceRemoveImports(filePkgs[file], final); err == nil {
final = formatted
}
- if diffFlag {
+ if printDiff {
// Since we formatted the file, we need to recompute the diff.
unified := diff.Unified(file+" (old)", file+" (new)", string(baseline), string(final))
// TODO(adonovan): abstract the I/O.
@@ -262,23 +301,149 @@ fixloop:
// These numbers are potentially misleading:
// The denominator includes duplicate conflicting fixes due to
// common files in packages "p" and "p [p.test]", which may
- // have been fixed fixed and won't appear in the re-run.
+ // have been fixed and won't appear in the re-run.
// TODO(adonovan): eliminate identical fixes as an initial
// filtering step.
//
// TODO(adonovan): should we log that n files were updated in case of total victory?
if badFixes > 0 || filesUpdated < totalFiles {
- if diffFlag {
- return fmt.Errorf("%d of %d fixes skipped (e.g. due to conflicts)", badFixes, len(fixes))
+ if printDiff {
+ return fmt.Errorf("%d of %s skipped (e.g. due to conflicts)",
+ badFixes,
+ plural(len(fixes), "fix", "fixes"))
} else {
- return fmt.Errorf("applied %d of %d fixes; %d files updated. (Re-run the command to apply more.)",
- goodFixes, len(fixes), filesUpdated)
+ return fmt.Errorf("applied %d of %s; %s updated. (Re-run the command to apply more.)",
+ goodFixes,
+ plural(len(fixes), "fix", "fixes"),
+ plural(filesUpdated, "file", "files"))
}
}
if verbose {
- log.Printf("applied %d fixes, updated %d files", len(fixes), filesUpdated)
+ if skippedFixes > 0 {
+ log.Printf("skipped %s that would edit generated files",
+ plural(skippedFixes, "fix", "fixes"))
+ }
+ log.Printf("applied %s, updated %s",
+ plural(len(fixes), "fix", "fixes"),
+ plural(filesUpdated, "file", "files"))
}
return nil
}
+
+// FormatSourceRemoveImports is a variant of [format.Source] that
+// removes imports that became redundant when fixes were applied.
+//
+// Import removal is necessarily heuristic since we do not have type
+// information for the fixed file and thus cannot accurately tell
+// whether k is among the free names of T{k: 0}, which requires
+// knowledge of whether T is a struct type.
+func FormatSourceRemoveImports(pkg *types.Package, src []byte) ([]byte, error) {
+ // This function was reduced from the "strict entire file"
+ // path through [format.Source].
+
+ fset := token.NewFileSet()
+ file, err := parser.ParseFile(fset, "fixed.go", src, parser.ParseComments|parser.SkipObjectResolution)
+ if err != nil {
+ return nil, err
+ }
+
+ ast.SortImports(fset, file)
+
+ removeUnneededImports(fset, pkg, file)
+
+ // printerNormalizeNumbers means to canonicalize number literal prefixes
+ // and exponents while printing. See https://golang.org/doc/go1.13#gofmt.
+ //
+ // This value is defined in go/printer specifically for go/format and cmd/gofmt.
+ const printerNormalizeNumbers = 1 << 30
+ cfg := &printer.Config{
+ Mode: printer.UseSpaces | printer.TabIndent | printerNormalizeNumbers,
+ Tabwidth: 8,
+ }
+ var buf bytes.Buffer
+ if err := cfg.Fprint(&buf, fset, file); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// removeUnneededImports removes import specs that are not referenced
+// within the fixed file. It uses [free.Names] to heuristically
+// approximate the set of imported names needed by the body of the
+// file based only on syntax.
+//
+// pkg provides type information about the unmodified package, in
+// 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.
+ // (We'll need this to interpret non-renaming imports.)
+ packageNames := make(map[string]string)
+ for _, imp := range pkg.Imports() {
+ packageNames[imp.Path()] = imp.Name()
+ }
+
+ // Compute the set of free names of the file,
+ // ignoring its import decls.
+ freenames := make(map[string]bool)
+ for _, decl := range file.Decls {
+ if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
+ continue // skip import
+ }
+
+ // TODO(adonovan): we could do better than includeComplitIdents=false
+ // since we have type information about the unmodified package,
+ // which is a good source of heuristics.
+ const includeComplitIdents = false
+ maps.Copy(freenames, free.Names(decl, includeComplitIdents))
+ }
+
+ // Check whether each import's declared name is free (referenced) by the file.
+ var deletions []func()
+ for _, spec := range file.Imports {
+ path, err := strconv.Unquote(spec.Path.Value)
+ if err != nil {
+ continue // malformed import; ignore
+ }
+ explicit := "" // explicit PkgName, if any
+ if spec.Name != nil {
+ explicit = spec.Name.Name
+ }
+ name := explicit // effective PkgName
+ if name == "" {
+ // Non-renaming import: use package's default name.
+ name = packageNames[path]
+ }
+ switch name {
+ case "":
+ continue // assume it's a new import
+ case ".":
+ continue // dot imports are tricky
+ case "_":
+ continue // keep blank imports
+ }
+ if !freenames[name] {
+ // Import's effective name is not free in (not used by) the file.
+ // Enqueue it for deletion after the loop.
+ deletions = append(deletions, func() {
+ astutil.DeleteNamedImport(fset, file, explicit, path)
+ })
+ }
+ }
+
+ // Apply the deletions.
+ for _, del := range deletions {
+ del()
+ }
+}
+
+// plural returns "n nouns", selecting the plural form as approriate.
+func plural(n int, singular, plural string) string {
+ if n == 1 {
+ return "1 " + singular
+ } else {
+ return fmt.Sprintf("%d %s", n, plural)
+ }
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/print.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/print.go
new file mode 100644
index 0000000000..7fc42a5ef7
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/print.go
@@ -0,0 +1,161 @@
+// Copyright 2025 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 driverutil
+
+// This file defined output helpers common to all drivers.
+
+import (
+ "encoding/json"
+ "fmt"
+ "go/token"
+ "io"
+ "log"
+ "os"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// TODO(adonovan): don't accept an io.Writer if we don't report errors.
+// Either accept a bytes.Buffer (infallible), or return a []byte.
+
+// PrintPlain prints a diagnostic in plain text form.
+// If contextLines is nonnegative, it also prints the
+// offending line plus this many lines of context.
+func PrintPlain(out io.Writer, fset *token.FileSet, contextLines int, diag analysis.Diagnostic) {
+ print := func(pos, end token.Pos, message string) {
+ posn := fset.Position(pos)
+ fmt.Fprintf(out, "%s: %s\n", posn, message)
+
+ // show offending line plus N lines of context.
+ if contextLines >= 0 {
+ end := fset.Position(end)
+ if !end.IsValid() {
+ end = posn
+ }
+ // TODO(adonovan): highlight the portion of the line indicated
+ // by pos...end using ASCII art, terminal colors, etc?
+ data, _ := os.ReadFile(posn.Filename)
+ lines := strings.Split(string(data), "\n")
+ for i := posn.Line - contextLines; i <= end.Line+contextLines; i++ {
+ if 1 <= i && i <= len(lines) {
+ fmt.Fprintf(out, "%d\t%s\n", i, lines[i-1])
+ }
+ }
+ }
+ }
+
+ print(diag.Pos, diag.End, diag.Message)
+ for _, rel := range diag.Related {
+ print(rel.Pos, rel.End, "\t"+rel.Message)
+ }
+}
+
+// A JSONTree is a mapping from package ID to analysis name to result.
+// Each result is either a jsonError or a list of JSONDiagnostic.
+type JSONTree map[string]map[string]any
+
+// A TextEdit describes the replacement of a portion of a file.
+// Start and End are zero-based half-open indices into the original byte
+// sequence of the file, and New is the new text.
+type JSONTextEdit struct {
+ Filename string `json:"filename"`
+ Start int `json:"start"`
+ End int `json:"end"`
+ New string `json:"new"`
+}
+
+// A JSONSuggestedFix describes an edit that should be applied as a whole or not
+// at all. It might contain multiple TextEdits/text_edits if the SuggestedFix
+// consists of multiple non-contiguous edits.
+type JSONSuggestedFix struct {
+ Message string `json:"message"`
+ Edits []JSONTextEdit `json:"edits"`
+}
+
+// A JSONDiagnostic describes the JSON schema of an analysis.Diagnostic.
+//
+// TODO(matloob): include End position if present.
+type JSONDiagnostic struct {
+ Category string `json:"category,omitempty"`
+ Posn string `json:"posn"` // e.g. "file.go:line:column"
+ Message string `json:"message"`
+ SuggestedFixes []JSONSuggestedFix `json:"suggested_fixes,omitempty"`
+ Related []JSONRelatedInformation `json:"related,omitempty"`
+}
+
+// A JSONRelated describes a secondary position and message related to
+// a primary diagnostic.
+//
+// TODO(adonovan): include End position if present.
+type JSONRelatedInformation struct {
+ Posn string `json:"posn"` // e.g. "file.go:line:column"
+ Message string `json:"message"`
+}
+
+// Add adds the result of analysis 'name' on package 'id'.
+// The result is either a list of diagnostics or an error.
+func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.Diagnostic, err error) {
+ var v any
+ if err != nil {
+ type jsonError struct {
+ Err string `json:"error"`
+ }
+ v = jsonError{err.Error()}
+ } else if len(diags) > 0 {
+ diagnostics := make([]JSONDiagnostic, 0, len(diags))
+ for _, f := range diags {
+ var fixes []JSONSuggestedFix
+ for _, fix := range f.SuggestedFixes {
+ var edits []JSONTextEdit
+ for _, edit := range fix.TextEdits {
+ edits = append(edits, JSONTextEdit{
+ Filename: fset.Position(edit.Pos).Filename,
+ Start: fset.Position(edit.Pos).Offset,
+ End: fset.Position(edit.End).Offset,
+ New: string(edit.NewText),
+ })
+ }
+ fixes = append(fixes, JSONSuggestedFix{
+ Message: fix.Message,
+ Edits: edits,
+ })
+ }
+ var related []JSONRelatedInformation
+ for _, r := range f.Related {
+ related = append(related, JSONRelatedInformation{
+ Posn: fset.Position(r.Pos).String(),
+ Message: r.Message,
+ })
+ }
+ jdiag := JSONDiagnostic{
+ Category: f.Category,
+ Posn: fset.Position(f.Pos).String(),
+ Message: f.Message,
+ SuggestedFixes: fixes,
+ Related: related,
+ }
+ diagnostics = append(diagnostics, jdiag)
+ }
+ v = diagnostics
+ }
+ if v != nil {
+ m, ok := tree[id]
+ if !ok {
+ m = make(map[string]any)
+ tree[id] = m
+ }
+ m[name] = v
+ }
+}
+
+func (tree JSONTree) Print(out io.Writer) error {
+ data, err := json.MarshalIndent(tree, "", "\t")
+ if err != nil {
+ log.Panicf("internal error: JSON marshaling failed: %v", err)
+ }
+ _, err = fmt.Fprintf(out, "%s\n", data)
+ return err
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/readfile.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/readfile.go
new file mode 100644
index 0000000000..dc1d54dd8b
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/readfile.go
@@ -0,0 +1,43 @@
+// Copyright 2020 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 driverutil
+
+// This file defines helpers for implementing [analysis.Pass.ReadFile].
+
+import (
+ "fmt"
+ "slices"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// A ReadFileFunc is a function that returns the
+// contents of a file, such as [os.ReadFile].
+type ReadFileFunc = func(filename string) ([]byte, error)
+
+// CheckedReadFile returns a wrapper around a Pass.ReadFile
+// function that performs the appropriate checks.
+func CheckedReadFile(pass *analysis.Pass, readFile ReadFileFunc) ReadFileFunc {
+ return func(filename string) ([]byte, error) {
+ if err := CheckReadable(pass, filename); err != nil {
+ return nil, err
+ }
+ return readFile(filename)
+ }
+}
+
+// CheckReadable enforces the access policy defined by the ReadFile field of [analysis.Pass].
+func CheckReadable(pass *analysis.Pass, filename string) error {
+ if slices.Contains(pass.OtherFiles, filename) ||
+ slices.Contains(pass.IgnoredFiles, filename) {
+ return nil
+ }
+ for _, f := range pass.Files {
+ if pass.Fset.File(f.FileStart).Name() == filename {
+ return nil
+ }
+ }
+ return fmt.Errorf("Pass.ReadFile: %s is not among OtherFiles, IgnoredFiles, or names of Files", filename)
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/url.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/url.go
index 26a917a991..93b3ecfd49 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/url.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/url.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package analysisflags
+package driverutil
import (
"fmt"
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/validatefix.go
index 970d7507f0..7efc4197d6 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/validatefix.go
@@ -1,71 +1,20 @@
-// Copyright 2020 The Go Authors. All rights reserved.
+// Copyright 2025 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 analysisinternal provides helper functions for use in both
-// the analysis drivers in go/analysis and gopls, and in various
-// analyzers.
-//
-// TODO(adonovan): this is not ideal as it may lead to unnecessary
-// dependencies between drivers and analyzers. Split into analyzerlib
-// and driverlib?
-package analysisinternal
+package driverutil
+
+// This file defines the validation of SuggestedFixes.
import (
"cmp"
"fmt"
"go/token"
- "os"
"slices"
"golang.org/x/tools/go/analysis"
)
-// ReadFile reads a file and adds it to the FileSet in pass
-// so that we can report errors against it using lineStart.
-func ReadFile(pass *analysis.Pass, filename string) ([]byte, *token.File, error) {
- readFile := pass.ReadFile
- if readFile == nil {
- readFile = os.ReadFile
- }
- content, err := readFile(filename)
- if err != nil {
- return nil, nil, err
- }
- tf := pass.Fset.AddFile(filename, -1, len(content))
- tf.SetLinesForContent(content)
- return content, tf, nil
-}
-
-// A ReadFileFunc is a function that returns the
-// contents of a file, such as [os.ReadFile].
-type ReadFileFunc = func(filename string) ([]byte, error)
-
-// CheckedReadFile returns a wrapper around a Pass.ReadFile
-// function that performs the appropriate checks.
-func CheckedReadFile(pass *analysis.Pass, readFile ReadFileFunc) ReadFileFunc {
- return func(filename string) ([]byte, error) {
- if err := CheckReadable(pass, filename); err != nil {
- return nil, err
- }
- return readFile(filename)
- }
-}
-
-// CheckReadable enforces the access policy defined by the ReadFile field of [analysis.Pass].
-func CheckReadable(pass *analysis.Pass, filename string) error {
- if slices.Contains(pass.OtherFiles, filename) ||
- slices.Contains(pass.IgnoredFiles, filename) {
- return nil
- }
- for _, f := range pass.Files {
- if pass.Fset.File(f.FileStart).Name() == filename {
- return nil
- }
- }
- return fmt.Errorf("Pass.ReadFile: %s is not among OtherFiles, IgnoredFiles, or names of Files", filename)
-}
-
// ValidateFixes validates the set of fixes for a single diagnostic.
// Any error indicates a bug in the originating analyzer.
//
@@ -167,14 +116,3 @@ func validateFix(fset *token.FileSet, fix *analysis.SuggestedFix) error {
return nil
}
-
-// Range returns an [analysis.Range] for the specified start and end positions.
-func Range(pos, end token.Pos) analysis.Range {
- return tokenRange{pos, end}
-}
-
-// tokenRange is an implementation of the [analysis.Range] interface.
-type tokenRange struct{ StartPos, EndPos token.Pos }
-
-func (r tokenRange) Pos() token.Pos { return r.StartPos }
-func (r tokenRange) End() token.Pos { return r.EndPos }
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/typeindex/typeindex.go b/src/cmd/vendor/golang.org/x/tools/internal/analysis/typeindex/typeindex.go
index bba21c6ea0..41146d9abb 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/typeindex/typeindex.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/analysis/typeindex/typeindex.go
@@ -22,12 +22,12 @@ import (
var Analyzer = &analysis.Analyzer{
Name: "typeindex",
Doc: "indexes of type information for later passes",
- URL: "https://pkg.go.dev/golang.org/x/tools/internal/analysisinternal/typeindex",
+ URL: "https://pkg.go.dev/golang.org/x/tools/internal/analysis/typeindex",
Run: func(pass *analysis.Pass) (any, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
return typeindex.New(inspect, pass.Pkg, pass.TypesInfo), nil
},
RunDespiteErrors: true,
Requires: []*analysis.Analyzer{inspect.Analyzer},
- ResultType: reflect.TypeOf(new(typeindex.Index)),
+ ResultType: reflect.TypeFor[*typeindex.Index](),
}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/generated/generated.go b/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/generated/generated.go
deleted file mode 100644
index 13e1b69021..0000000000
--- a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/generated/generated.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2025 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 generated defines an analyzer whose result makes it
-// convenient to skip diagnostics within generated files.
-package generated
-
-import (
- "go/ast"
- "go/token"
- "reflect"
-
- "golang.org/x/tools/go/analysis"
-)
-
-var Analyzer = &analysis.Analyzer{
- Name: "generated",
- Doc: "detect which Go files are generated",
- URL: "https://pkg.go.dev/golang.org/x/tools/internal/analysisinternal/generated",
- ResultType: reflect.TypeFor[*Result](),
- Run: func(pass *analysis.Pass) (any, error) {
- set := make(map[*token.File]bool)
- for _, file := range pass.Files {
- if ast.IsGenerated(file) {
- set[pass.Fset.File(file.FileStart)] = true
- }
- }
- return &Result{fset: pass.Fset, generatedFiles: set}, nil
- },
-}
-
-type Result struct {
- fset *token.FileSet
- generatedFiles map[*token.File]bool
-}
-
-// IsGenerated reports whether the position is within a generated file.
-func (r *Result) IsGenerated(pos token.Pos) bool {
- return r.generatedFiles[r.fset.File(pos)]
-}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/free.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/free/free.go
index e3cf313a8a..2c4d2c4e52 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/free.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/free/free.go
@@ -2,18 +2,22 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Copied, with considerable changes, from go/parser/resolver.go
-// at af53bd2c03.
-
-package inline
+// Package free defines utilities for computing the free variables of
+// a syntax tree without type information. This is inherently
+// heuristic because of the T{f: x} ambiguity, in which f may or may
+// not be a lexical reference depending on whether T is a struct type.
+package free
import (
"go/ast"
"go/token"
)
-// freeishNames computes an approximation to the free names of the AST
-// at node n based solely on syntax, inserting values into the map.
+// Copied, with considerable changes, from go/parser/resolver.go
+// at af53bd2c03.
+
+// Names computes an approximation to the set of free names of the AST
+// at node n based solely on syntax.
//
// In the absence of composite literals, the set of free names is exact. Composite
// literals introduce an ambiguity that can only be resolved with type information:
@@ -26,15 +30,22 @@ import (
// a struct type, so freeishNames underapproximates: the resulting set
// may omit names that are free lexical references.
//
+// TODO(adonovan): includeComplitIdents is a crude hammer: the caller
+// may have partial or heuristic information about whether a given T
+// is struct type. Replace includeComplitIdents with a hook to query
+// the caller.
+//
// The code is based on go/parser.resolveFile, but heavily simplified. Crucial
// differences are:
// - Instead of resolving names to their objects, this function merely records
// whether they are free.
// - Labels are ignored: they do not refer to values.
-// - This is never called on FuncDecls or ImportSpecs, so the function
-// panics if it sees one.
-func freeishNames(free map[string]bool, n ast.Node, includeComplitIdents bool) {
- v := &freeVisitor{free: free, includeComplitIdents: includeComplitIdents}
+// - This is never called on ImportSpecs, so the function panics if it sees one.
+func Names(n ast.Node, includeComplitIdents bool) map[string]bool {
+ v := &freeVisitor{
+ free: make(map[string]bool),
+ includeComplitIdents: includeComplitIdents,
+ }
// Begin with a scope, even though n might not be a form that establishes a scope.
// For example, n might be:
// x := ...
@@ -42,7 +53,10 @@ func freeishNames(free map[string]bool, n ast.Node, includeComplitIdents bool) {
v.openScope()
ast.Walk(v, n)
v.closeScope()
- assert(v.scope == nil, "unbalanced scopes")
+ if v.scope != nil {
+ panic("unbalanced scopes")
+ }
+ return v.free
}
// A freeVisitor holds state for a free-name analysis.
@@ -73,12 +87,12 @@ func (v *freeVisitor) Visit(n ast.Node) ast.Visitor {
// Expressions.
case *ast.Ident:
- v.resolve(n)
+ v.use(n)
case *ast.FuncLit:
v.openScope()
defer v.closeScope()
- v.walkFuncType(n.Type)
+ v.walkFuncType(nil, n.Type)
v.walkBody(n.Body)
case *ast.SelectorExpr:
@@ -93,7 +107,7 @@ func (v *freeVisitor) Visit(n ast.Node) ast.Visitor {
case *ast.FuncType:
v.openScope()
defer v.closeScope()
- v.walkFuncType(n)
+ v.walkFuncType(nil, n)
case *ast.CompositeLit:
v.walk(n.Type)
@@ -107,7 +121,7 @@ func (v *freeVisitor) Visit(n ast.Node) ast.Visitor {
if v.includeComplitIdents {
// Over-approximate by treating both cases as potentially
// free names.
- v.resolve(ident)
+ v.use(ident)
} else {
// Under-approximate by ignoring potentially free names.
}
@@ -135,13 +149,11 @@ func (v *freeVisitor) Visit(n ast.Node) ast.Visitor {
}
case *ast.LabeledStmt:
- // ignore labels
- // TODO(jba): consider labels?
+ // Ignore labels.
v.walk(n.Stmt)
case *ast.BranchStmt:
// Ignore labels.
- // TODO(jba): consider labels?
case *ast.BlockStmt:
v.openScope()
@@ -170,13 +182,11 @@ func (v *freeVisitor) Visit(n ast.Node) ast.Visitor {
v.walkBody(n.Body)
case *ast.TypeSwitchStmt:
+ v.openScope()
+ defer v.closeScope()
if n.Init != nil {
- v.openScope()
- defer v.closeScope()
v.walk(n.Init)
}
- v.openScope()
- defer v.closeScope()
v.walk(n.Assign)
// We can use walkBody here because we don't track label scopes.
v.walkBody(n.Body)
@@ -225,11 +235,10 @@ func (v *freeVisitor) Visit(n ast.Node) ast.Visitor {
for _, spec := range n.Specs {
spec := spec.(*ast.ValueSpec)
walkSlice(v, spec.Values)
- if spec.Type != nil {
- v.walk(spec.Type)
- }
+ v.walk(spec.Type)
v.declare(spec.Names...)
}
+
case token.TYPE:
for _, spec := range n.Specs {
spec := spec.(*ast.TypeSpec)
@@ -250,7 +259,14 @@ func (v *freeVisitor) Visit(n ast.Node) ast.Visitor {
}
case *ast.FuncDecl:
- panic("encountered top-level function declaration in free analysis")
+ if n.Recv == nil && n.Name.Name != "init" { // package-level function
+ v.declare(n.Name)
+ }
+ v.openScope()
+ defer v.closeScope()
+ v.walkTypeParams(n.Type.TypeParams)
+ v.walkFuncType(n.Recv, n.Type)
+ v.walkBody(n.Body)
default:
return v
@@ -259,67 +275,90 @@ func (v *freeVisitor) Visit(n ast.Node) ast.Visitor {
return nil
}
-func (r *freeVisitor) openScope() {
- r.scope = &scope{map[string]bool{}, r.scope}
+func (v *freeVisitor) openScope() {
+ v.scope = &scope{map[string]bool{}, v.scope}
}
-func (r *freeVisitor) closeScope() {
- r.scope = r.scope.outer
+func (v *freeVisitor) closeScope() {
+ v.scope = v.scope.outer
}
-func (r *freeVisitor) walk(n ast.Node) {
+func (v *freeVisitor) walk(n ast.Node) {
if n != nil {
- ast.Walk(r, n)
+ ast.Walk(v, n)
}
}
-// walkFuncType walks a function type. It is used for explicit
-// function types, like this:
-//
-// type RunFunc func(context.Context) error
-//
-// and function literals, like this:
-//
-// func(a, b int) int { return a + b}
-//
-// neither of which have type parameters.
-// Function declarations do involve type parameters, but we don't
-// handle them.
-func (r *freeVisitor) walkFuncType(typ *ast.FuncType) {
- // The order here doesn't really matter, because names in
- // a field list cannot appear in types.
- // (The situation is different for type parameters, for which
- // see [freeVisitor.walkTypeParams].)
- r.resolveFieldList(typ.Params)
- r.resolveFieldList(typ.Results)
- r.declareFieldList(typ.Params)
- r.declareFieldList(typ.Results)
+func (v *freeVisitor) walkFuncType(recv *ast.FieldList, typ *ast.FuncType) {
+ // First use field types...
+ v.walkRecvFieldType(recv)
+ v.walkFieldTypes(typ.Params)
+ v.walkFieldTypes(typ.Results)
+
+ // ...then declare field names.
+ v.declareFieldNames(recv)
+ v.declareFieldNames(typ.Params)
+ v.declareFieldNames(typ.Results)
+}
+
+// A receiver field is not like a param or result field because
+// "func (recv R[T]) method()" uses R but declares T.
+func (v *freeVisitor) walkRecvFieldType(list *ast.FieldList) {
+ if list == nil {
+ return
+ }
+ for _, f := range list.List { // valid => len=1
+ typ := f.Type
+ if ptr, ok := typ.(*ast.StarExpr); ok {
+ typ = ptr.X
+ }
+
+ // Analyze receiver type as Base[Index, ...]
+ var (
+ base ast.Expr
+ indices []ast.Expr
+ )
+ switch typ := typ.(type) {
+ case *ast.IndexExpr: // B[T]
+ base, indices = typ.X, []ast.Expr{typ.Index}
+ case *ast.IndexListExpr: // B[K, V]
+ base, indices = typ.X, typ.Indices
+ default: // B
+ base = typ
+ }
+ for _, expr := range indices {
+ if id, ok := expr.(*ast.Ident); ok {
+ v.declare(id)
+ }
+ }
+ v.walk(base)
+ }
}
// walkTypeParams is like walkFieldList, but declares type parameters eagerly so
// that they may be resolved in the constraint expressions held in the field
// Type.
-func (r *freeVisitor) walkTypeParams(list *ast.FieldList) {
- r.declareFieldList(list)
- r.resolveFieldList(list)
+func (v *freeVisitor) walkTypeParams(list *ast.FieldList) {
+ v.declareFieldNames(list)
+ v.walkFieldTypes(list) // constraints
}
-func (r *freeVisitor) walkBody(body *ast.BlockStmt) {
+func (v *freeVisitor) walkBody(body *ast.BlockStmt) {
if body == nil {
return
}
- walkSlice(r, body.List)
+ walkSlice(v, body.List)
}
-func (r *freeVisitor) walkFieldList(list *ast.FieldList) {
+func (v *freeVisitor) walkFieldList(list *ast.FieldList) {
if list == nil {
return
}
- r.resolveFieldList(list) // .Type may contain references
- r.declareFieldList(list) // .Names declares names
+ v.walkFieldTypes(list) // .Type may contain references
+ v.declareFieldNames(list) // .Names declares names
}
-func (r *freeVisitor) shortVarDecl(lhs []ast.Expr) {
+func (v *freeVisitor) shortVarDecl(lhs []ast.Expr) {
// Go spec: A short variable declaration may redeclare variables provided
// they were originally declared in the same block with the same type, and
// at least one of the non-blank variables is new.
@@ -330,7 +369,7 @@ func (r *freeVisitor) shortVarDecl(lhs []ast.Expr) {
// In a well-formed program each expr must be an identifier,
// but be forgiving.
if id, ok := x.(*ast.Ident); ok {
- r.declare(id)
+ v.declare(id)
}
}
}
@@ -341,42 +380,39 @@ func walkSlice[S ~[]E, E ast.Node](r *freeVisitor, list S) {
}
}
-// resolveFieldList resolves the types of the fields in list.
-// The companion method declareFieldList declares the names of the fields.
-func (r *freeVisitor) resolveFieldList(list *ast.FieldList) {
- if list == nil {
- return
- }
- for _, f := range list.List {
- r.walk(f.Type)
+// walkFieldTypes resolves the types of the walkFieldTypes in list.
+// The companion method declareFieldList declares the names of the walkFieldTypes.
+func (v *freeVisitor) walkFieldTypes(list *ast.FieldList) {
+ if list != nil {
+ for _, f := range list.List {
+ v.walk(f.Type)
+ }
}
}
-// declareFieldList declares the names of the fields in list.
+// declareFieldNames declares the names of the fields in list.
// (Names in a FieldList always establish new bindings.)
// The companion method resolveFieldList resolves the types of the fields.
-func (r *freeVisitor) declareFieldList(list *ast.FieldList) {
- if list == nil {
- return
- }
- for _, f := range list.List {
- r.declare(f.Names...)
+func (v *freeVisitor) declareFieldNames(list *ast.FieldList) {
+ if list != nil {
+ for _, f := range list.List {
+ v.declare(f.Names...)
+ }
}
}
-// resolve marks ident as free if it is not in scope.
-// TODO(jba): rename: no resolution is happening.
-func (r *freeVisitor) resolve(ident *ast.Ident) {
- if s := ident.Name; s != "_" && !r.scope.defined(s) {
- r.free[s] = true
+// use marks ident as free if it is not in scope.
+func (v *freeVisitor) use(ident *ast.Ident) {
+ if s := ident.Name; s != "_" && !v.scope.defined(s) {
+ v.free[s] = true
}
}
// declare adds each non-blank ident to the current scope.
-func (r *freeVisitor) declare(idents ...*ast.Ident) {
+func (v *freeVisitor) declare(idents ...*ast.Ident) {
for _, id := range idents {
if id.Name != "_" {
- r.scope.names[id.Name] = true
+ v.scope.names[id.Name] = true
}
}
}
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 849d45d853..ce1e7de882 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
@@ -14,16 +14,16 @@ import (
// RangeInStringLiteral calculates the positional range within a string literal
// corresponding to the specified start and end byte offsets within the logical string.
-func RangeInStringLiteral(lit *ast.BasicLit, start, end int) (token.Pos, token.Pos, error) {
+func RangeInStringLiteral(lit *ast.BasicLit, start, end int) (Range, error) {
startPos, err := PosInStringLiteral(lit, start)
if err != nil {
- return 0, 0, fmt.Errorf("start: %v", err)
+ return Range{}, fmt.Errorf("start: %v", err)
}
endPos, err := PosInStringLiteral(lit, end)
if err != nil {
- return 0, 0, fmt.Errorf("end: %v", err)
+ return Range{}, fmt.Errorf("end: %v", err)
}
- return startPos, endPos, nil
+ return Range{startPos, endPos}, nil
}
// PosInStringLiteral returns the position within a string literal
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 a1c0983504..7a02fca21e 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
@@ -5,6 +5,7 @@
package astutil
import (
+ "fmt"
"go/ast"
"go/printer"
"go/token"
@@ -50,28 +51,26 @@ func PreorderStack(root ast.Node, stack []ast.Node, f func(n ast.Node, stack []a
}
// NodeContains reports whether the Pos/End range of node n encloses
-// the given position pos.
+// the given range.
//
// It is inclusive of both end points, to allow hovering (etc) when
// the cursor is immediately after a node.
//
-// For unfortunate historical reasons, the Pos/End extent of an
-// ast.File runs from the start of its package declaration---excluding
-// copyright comments, build tags, and package documentation---to the
-// end of its last declaration, excluding any trailing comments. So,
-// as a special case, if n is an [ast.File], NodeContains uses
-// n.FileStart <= pos && pos <= n.FileEnd to report whether the
-// position lies anywhere within the file.
+// Like [NodeRange], it treats the range of an [ast.File] as the
+// file's complete extent.
//
// Precondition: n must not be nil.
-func NodeContains(n ast.Node, pos token.Pos) bool {
- var start, end token.Pos
- if file, ok := n.(*ast.File); ok {
- start, end = file.FileStart, file.FileEnd // entire file
- } else {
- start, end = n.Pos(), n.End()
- }
- return start <= pos && pos <= end
+func NodeContains(n ast.Node, rng Range) bool {
+ return NodeRange(n).Contains(rng)
+}
+
+// NodeContainPos reports whether the Pos/End range of node n encloses
+// the given pos.
+//
+// Like [NodeRange], it treats the range of an [ast.File] as the
+// file's complete extent.
+func NodeContainsPos(n ast.Node, pos token.Pos) bool {
+ return NodeRange(n).ContainsPos(pos)
}
// IsChildOf reports whether cur.ParentEdge is ek.
@@ -117,3 +116,118 @@ func Format(fset *token.FileSet, n ast.Node) string {
printer.Fprint(&buf, fset, n) // ignore errors
return buf.String()
}
+
+// -- Range --
+
+// Range is a Pos interval.
+// It implements [analysis.Range] and [ast.Node].
+type Range struct{ Start, EndPos token.Pos }
+
+// RangeOf constructs a Range.
+//
+// RangeOf exists to pacify the "unkeyed literal" (composites) vet
+// check. It would be nice if there were a way for a type to add
+// itself to the allowlist.
+func RangeOf(start, end token.Pos) Range { return Range{start, end} }
+
+// NodeRange returns the extent of node n as a Range.
+//
+// For unfortunate historical reasons, the Pos/End extent of an
+// ast.File runs from the start of its package declaration---excluding
+// copyright comments, build tags, and package documentation---to the
+// end of its last declaration, excluding any trailing comments. So,
+// as a special case, if n is an [ast.File], NodeContains uses
+// n.FileStart <= pos && pos <= n.FileEnd to report whether the
+// position lies anywhere within the file.
+func NodeRange(n ast.Node) Range {
+ if file, ok := n.(*ast.File); ok {
+ return Range{file.FileStart, file.FileEnd} // entire file
+ }
+ return Range{n.Pos(), n.End()}
+}
+
+func (r Range) Pos() token.Pos { return r.Start }
+func (r Range) End() token.Pos { return r.EndPos }
+
+// ContainsPos reports whether the range (inclusive of both end points)
+// includes the specified position.
+func (r Range) ContainsPos(pos token.Pos) bool {
+ return r.Contains(RangeOf(pos, pos))
+}
+
+// Contains reports whether the range (inclusive of both end points)
+// includes the specified range.
+func (r Range) Contains(rng Range) bool {
+ return r.Start <= rng.Start && rng.EndPos <= r.EndPos
+}
+
+// IsValid reports whether the range is valid.
+func (r Range) IsValid() bool { return r.Start.IsValid() && r.Start <= r.EndPos }
+
+// --
+
+// Select returns the syntax nodes identified by a user's text
+// selection. It returns three nodes: the innermost node that wholly
+// encloses the selection; and the first and last nodes that are
+// wholly enclosed by the selection.
+//
+// For example, given this selection:
+//
+// { f(); g(); /* comment */ }
+// ~~~~~~~~~~~
+//
+// Select returns the enclosing BlockStmt, the f() CallExpr, and the g() CallExpr.
+//
+// Callers that require exactly one syntax tree (e.g. just f() or just
+// g()) should check that the returned start and end nodes are
+// identical.
+//
+// This function is intended to be called early in the handling of a
+// user's request, since it is tolerant of sloppy selection including
+// extraneous whitespace and comments. Use it in new code instead of
+// PathEnclosingInterval. When the exact extent of a node is known,
+// use [Cursor.FindByPos] instead.
+func Select(curFile inspector.Cursor, start, end token.Pos) (_enclosing, _start, _end inspector.Cursor, _ error) {
+ curEnclosing, ok := curFile.FindByPos(start, end)
+ if !ok {
+ return noCursor, noCursor, noCursor, fmt.Errorf("invalid selection")
+ }
+
+ // Find the first and last node wholly within the (start, end) range.
+ // We'll narrow the effective selection to them, to exclude whitespace.
+ // (This matches the functionality of PathEnclosingInterval.)
+ var curStart, curEnd inspector.Cursor
+ rng := RangeOf(start, end)
+ for cur := range curEnclosing.Preorder() {
+ if rng.Contains(NodeRange(cur.Node())) {
+ // The start node has the least Pos.
+ if !CursorValid(curStart) {
+ curStart = cur
+ }
+ // The end node has the greatest End.
+ // End positions do not change monotonically,
+ // so we must compute the max.
+ if !CursorValid(curEnd) ||
+ cur.Node().End() > curEnd.Node().End() {
+ curEnd = cur
+ }
+ }
+ }
+ if !CursorValid(curStart) {
+ return noCursor, noCursor, noCursor, fmt.Errorf("no syntax selected")
+ }
+ 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].
+//
+// 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
+}
+
+var noCursor inspector.Cursor
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/cfginternal/cfginternal.go b/src/cmd/vendor/golang.org/x/tools/internal/cfginternal/cfginternal.go
new file mode 100644
index 0000000000..a9b6236f4d
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/tools/internal/cfginternal/cfginternal.go
@@ -0,0 +1,16 @@
+// Copyright 2025 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 cfginternal exposes internals of go/cfg.
+// It cannot actually depend on symbols from go/cfg.
+package cfginternal
+
+// IsNoReturn exposes (*cfg.CFG).noReturn to the ctrlflow analyzer.
+// TODO(adonovan): add CFG.NoReturn to the public API.
+//
+// You must link [golang.org/x/tools/go/cfg] into your application for
+// this function to be non-nil.
+var IsNoReturn = func(cfg any) bool {
+ panic("golang.org/x/tools/go/cfg not linked into application")
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/diff/lcs/old.go b/src/cmd/vendor/golang.org/x/tools/internal/diff/lcs/old.go
index 7b7c5cc677..5acc68e1db 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/diff/lcs/old.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/diff/lcs/old.go
@@ -16,10 +16,6 @@ type Diff struct {
ReplStart, ReplEnd int // offset of replacement text in B
}
-// DiffStrings returns the differences between two strings.
-// It does not respect rune boundaries.
-func DiffStrings(a, b string) []Diff { return diff(stringSeqs{a, b}) }
-
// DiffBytes returns the differences between two byte sequences.
// It does not respect rune boundaries.
func DiffBytes(a, b []byte) []Diff { return diff(bytesSeqs{a, b}) }
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/facts/imports.go b/src/cmd/vendor/golang.org/x/tools/internal/facts/imports.go
index cc9383e800..324010b475 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/facts/imports.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/facts/imports.go
@@ -53,8 +53,8 @@ func importMap(imports []*types.Package) map[string]*types.Package {
case typesinternal.NamedOrAlias: // *types.{Named,Alias}
// Add the type arguments if this is an instance.
if targs := T.TypeArgs(); targs.Len() > 0 {
- for i := 0; i < targs.Len(); i++ {
- addType(targs.At(i))
+ for t := range targs.Types() {
+ addType(t)
}
}
@@ -70,8 +70,8 @@ func importMap(imports []*types.Package) map[string]*types.Package {
// common aspects
addObj(T.Obj())
if tparams := T.TypeParams(); tparams.Len() > 0 {
- for i := 0; i < tparams.Len(); i++ {
- addType(tparams.At(i))
+ for tparam := range tparams.TypeParams() {
+ addType(tparam)
}
}
@@ -81,8 +81,8 @@ func importMap(imports []*types.Package) map[string]*types.Package {
addType(aliases.Rhs(T))
case *types.Named:
addType(T.Underlying())
- for i := 0; i < T.NumMethods(); i++ {
- addObj(T.Method(i))
+ for method := range T.Methods() {
+ addObj(method)
}
}
}
@@ -101,28 +101,28 @@ func importMap(imports []*types.Package) map[string]*types.Package {
addType(T.Params())
addType(T.Results())
if tparams := T.TypeParams(); tparams != nil {
- for i := 0; i < tparams.Len(); i++ {
- addType(tparams.At(i))
+ for tparam := range tparams.TypeParams() {
+ addType(tparam)
}
}
case *types.Struct:
- for i := 0; i < T.NumFields(); i++ {
- addObj(T.Field(i))
+ for field := range T.Fields() {
+ addObj(field)
}
case *types.Tuple:
- for i := 0; i < T.Len(); i++ {
- addObj(T.At(i))
+ for v := range T.Variables() {
+ addObj(v)
}
case *types.Interface:
- for i := 0; i < T.NumMethods(); i++ {
- addObj(T.Method(i))
+ for method := range T.Methods() {
+ addObj(method)
}
- for i := 0; i < T.NumEmbeddeds(); i++ {
- addType(T.EmbeddedType(i)) // walk Embedded for implicits
+ for etyp := range T.EmbeddedTypes() {
+ addType(etyp) // walk Embedded for implicits
}
case *types.Union:
- for i := 0; i < T.Len(); i++ {
- addType(T.Term(i).Type())
+ for term := range T.Terms() {
+ addType(term.Type())
}
case *types.TypeParam:
if !typs[T] {
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 2764a97fc7..bca4d8a0b0 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
@@ -12,4 +12,5 @@ var (
ErrorsAsTypeModernizer *analysis.Analyzer // = modernize.errorsastypeAnalyzer
StdIteratorsModernizer *analysis.Analyzer // = modernize.stditeratorsAnalyzer
PlusBuildModernizer *analysis.Analyzer // = modernize.plusbuildAnalyzer
+ StringsCutModernizer *analysis.Analyzer // = modernize.stringscutAnalyzer
)
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 6df01d8ef9..9b96b1dbf1 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
@@ -331,109 +331,192 @@ func DeleteDecl(tokFile *token.File, curDecl inspector.Cursor) []analysis.TextEd
}
}
+// find leftmost Pos bigger than start and rightmost less than end
+func filterPos(nds []*ast.Comment, start, end token.Pos) (token.Pos, token.Pos, bool) {
+ l, r := end, token.NoPos
+ ok := false
+ for _, n := range nds {
+ if n.Pos() > start && n.Pos() < l {
+ l = n.Pos()
+ ok = true
+ }
+ if n.End() <= end && n.End() > r {
+ r = n.End()
+ ok = true
+ }
+ }
+ return l, r, ok
+}
+
// DeleteStmt returns the edits to remove the [ast.Stmt] identified by
-// curStmt, if it is contained within a BlockStmt, CaseClause,
-// CommClause, or is the STMT in switch STMT; ... {...}. It returns nil otherwise.
-func DeleteStmt(tokFile *token.File, curStmt inspector.Cursor) []analysis.TextEdit {
- stmt := curStmt.Node().(ast.Stmt)
- // if the stmt is on a line by itself delete the whole line
- // otherwise just delete the statement.
+// curStmt if it recognizes the context. It returns nil otherwise.
+// TODO(pjw, adonovan): it should not return nil, it should return an error
+//
+// DeleteStmt is called with just the AST so it has trouble deciding if
+// a comment is associated with the statement to be deleted. For instance,
+//
+// for /*A*/ init()/*B*/;/*C/cond()/*D/;/*E*/post() /*F*/ { /*G*/}
+//
+// comment B and C are indistinguishable, as are D and E. That is, as the
+// AST does not say where the semicolons are, B and C could go either
+// with the init() or the cond(), so cannot be removed safely. The same
+// is true for D, E, and the post(). (And there are other similar cases.)
+// But the other comments can be removed as they are unambiguously
+// associated with the statement being deleted. In particular,
+// it removes whole lines like
+//
+// stmt // comment
+func DeleteStmt(file *token.File, curStmt inspector.Cursor) []analysis.TextEdit {
+ // if the stmt is on a line by itself, or a range of lines, delete the whole thing
+ // including comments. Except for the heads of switches, type
+ // switches, and for-statements that's the usual case. Complexity occurs where
+ // there are multiple statements on the same line, and adjacent comments.
+
+ // In that case we remove some adjacent comments:
+ // In me()/*A*/;b(), comment A cannot be removed, because the ast
+ // is indistinguishable from me();/*A*/b()
+ // and the same for cases like switch me()/*A*/; x.(type) {
- // this logic would be a lot simpler with the file contents, and somewhat simpler
- // if the cursors included the comments.
+ // this would be more precise with the file contents, or if the ast
+ // contained the location of semicolons
+ var (
+ stmt = curStmt.Node().(ast.Stmt)
+ tokFile = file
+ lineOf = tokFile.Line
+ stmtStartLine = lineOf(stmt.Pos())
+ stmtEndLine = lineOf(stmt.End())
- lineOf := tokFile.Line
- stmtStartLine, stmtEndLine := lineOf(stmt.Pos()), lineOf(stmt.End())
+ leftSyntax, rightSyntax token.Pos // pieces of parent node on stmt{Start,End}Line
+ leftComments, rightComments []*ast.Comment // comments before/after stmt on the same line
+ )
- var from, to token.Pos
- // bounds of adjacent syntax/comments on same line, if any
- limits := func(left, right token.Pos) {
+ // remember the Pos that are on the same line as stmt
+ use := func(left, right token.Pos) {
if lineOf(left) == stmtStartLine {
- from = left
+ leftSyntax = left
}
if lineOf(right) == stmtEndLine {
- to = right
+ rightSyntax = right
}
}
- // TODO(pjw): there are other places a statement might be removed:
- // IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
- // (removing the blocks requires more rewriting than this routine would do)
- // CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
- // (removing the stmt requires more rewriting, and it's unclear what the user means)
- switch parent := curStmt.Parent().Node().(type) {
- case *ast.SwitchStmt:
- limits(parent.Switch, parent.Body.Lbrace)
- case *ast.TypeSwitchStmt:
- limits(parent.Switch, parent.Body.Lbrace)
- if parent.Assign == stmt {
- return nil // don't let the user break the type switch
+
+ // find the comments, if any, on the same line
+Big:
+ for _, cg := range astutil.EnclosingFile(curStmt).Comments {
+ for _, co := range cg.List {
+ if lineOf(co.End()) < stmtStartLine {
+ continue
+ } else if lineOf(co.Pos()) > stmtEndLine {
+ break Big // no more are possible
+ }
+ if lineOf(co.End()) == stmtStartLine && co.End() <= stmt.Pos() {
+ // comment is before the statement
+ leftComments = append(leftComments, co)
+ } else if lineOf(co.Pos()) == stmtEndLine && co.Pos() >= stmt.End() {
+ // comment is after the statement
+ rightComments = append(rightComments, co)
+ }
}
+ }
+
+ // find any other syntax on the same line
+ var (
+ leftStmt, rightStmt token.Pos // end/start positions of sibling statements in a []Stmt list
+ inStmtList = false
+ curParent = curStmt.Parent()
+ )
+ switch parent := curParent.Node().(type) {
case *ast.BlockStmt:
- limits(parent.Lbrace, parent.Rbrace)
+ use(parent.Lbrace, parent.Rbrace)
+ inStmtList = true
+ case *ast.CaseClause:
+ use(parent.Colon, curStmt.Parent().Parent().Node().(*ast.BlockStmt).Rbrace)
+ inStmtList = true
case *ast.CommClause:
- limits(parent.Colon, curStmt.Parent().Parent().Node().(*ast.BlockStmt).Rbrace)
if parent.Comm == stmt {
return nil // maybe the user meant to remove the entire CommClause?
}
- case *ast.CaseClause:
- limits(parent.Colon, curStmt.Parent().Parent().Node().(*ast.BlockStmt).Rbrace)
+ use(parent.Colon, curStmt.Parent().Parent().Node().(*ast.BlockStmt).Rbrace)
+ inStmtList = true
case *ast.ForStmt:
- limits(parent.For, parent.Body.Lbrace)
-
+ use(parent.For, parent.Body.Lbrace)
+ // special handling, as init;cond;post BlockStmt is not a statment list
+ if parent.Init != nil && parent.Cond != nil && stmt == parent.Init && lineOf(parent.Cond.Pos()) == lineOf(stmt.End()) {
+ rightStmt = parent.Cond.Pos()
+ } else if parent.Post != nil && parent.Cond != nil && stmt == parent.Post && lineOf(parent.Cond.End()) == lineOf(stmt.Pos()) {
+ leftStmt = parent.Cond.End()
+ }
+ case *ast.IfStmt:
+ switch stmt {
+ case parent.Init:
+ use(parent.If, parent.Body.Lbrace)
+ case parent.Else:
+ // stmt is the {...} in "if cond {} else {...}" and removing
+ // it would require removing the 'else' keyword, but the ast
+ // does not contain its position.
+ return nil
+ }
+ case *ast.SwitchStmt:
+ use(parent.Switch, parent.Body.Lbrace)
+ case *ast.TypeSwitchStmt:
+ if stmt == parent.Assign {
+ return nil // don't remove .(type)
+ }
+ use(parent.Switch, parent.Body.Lbrace)
default:
return nil // not one of ours
}
- if prev, found := curStmt.PrevSibling(); found && lineOf(prev.Node().End()) == stmtStartLine {
- from = prev.Node().End() // preceding statement ends on same line
- }
- if next, found := curStmt.NextSibling(); found && lineOf(next.Node().Pos()) == stmtEndLine {
- to = next.Node().Pos() // following statement begins on same line
- }
- // and now for the comments
-Outer:
- for _, cg := range astutil.EnclosingFile(curStmt).Comments {
- for _, co := range cg.List {
- if lineOf(co.End()) < stmtStartLine {
- continue
- } else if lineOf(co.Pos()) > stmtEndLine {
- break Outer // no more are possible
- }
- if lineOf(co.End()) == stmtStartLine && co.End() < stmt.Pos() {
- if !from.IsValid() || co.End() > from {
- from = co.End()
- continue // maybe there are more
- }
- }
- if lineOf(co.Pos()) == stmtEndLine && co.Pos() > stmt.End() {
- if !to.IsValid() || co.Pos() < to {
- to = co.Pos()
- continue // maybe there are more
- }
+ if inStmtList {
+ // find the siblings, if any, on the same line
+ if prev, found := curStmt.PrevSibling(); found && lineOf(prev.Node().End()) == stmtStartLine {
+ if _, ok := prev.Node().(ast.Stmt); ok {
+ leftStmt = prev.Node().End() // preceding statement ends on same line
}
}
+ if next, found := curStmt.NextSibling(); found && lineOf(next.Node().Pos()) == stmtEndLine {
+ rightStmt = next.Node().Pos() // following statement begins on same line
+ }
}
- // if either from or to is valid, just remove the statement
- // otherwise remove the line
- edit := analysis.TextEdit{Pos: stmt.Pos(), End: stmt.End()}
- if from.IsValid() || to.IsValid() {
- // remove just the statement.
- // we can't tell if there is a ; or whitespace right after the statement
- // ideally we'd like to remove the former and leave the latter
- // (if gofmt has run, there likely won't be a ;)
- // In type switches we know there's a semicolon somewhere after the statement,
- // but the extra work for this special case is not worth it, as gofmt will fix it.
- return []analysis.TextEdit{edit}
- }
- // remove the whole line
- for lineOf(edit.Pos) == stmtStartLine {
- edit.Pos--
+
+ // compute the left and right limits of the edit
+ var leftEdit, rightEdit token.Pos
+ if leftStmt.IsValid() {
+ leftEdit = stmt.Pos() // can't remove preceding comments: a()/*A*/; me()
+ } else if leftSyntax.IsValid() {
+ // remove intervening leftComments
+ if a, _, ok := filterPos(leftComments, leftSyntax, stmt.Pos()); ok {
+ leftEdit = a
+ } else {
+ leftEdit = stmt.Pos()
+ }
+ } else { // remove whole line
+ for leftEdit = stmt.Pos(); lineOf(leftEdit) == stmtStartLine; leftEdit-- {
+ }
+ if leftEdit < stmt.Pos() {
+ leftEdit++ // beginning of line
+ }
}
- edit.Pos++ // get back tostmtStartLine
- for lineOf(edit.End) == stmtEndLine {
- edit.End++
+ if rightStmt.IsValid() {
+ rightEdit = stmt.End() // can't remove following comments
+ } else if rightSyntax.IsValid() {
+ // remove intervening rightComments
+ if _, b, ok := filterPos(rightComments, stmt.End(), rightSyntax); ok {
+ rightEdit = b
+ } else {
+ rightEdit = stmt.End()
+ }
+ } else { // remove whole line
+ fend := token.Pos(file.Base()) + token.Pos(file.Size())
+ for rightEdit = stmt.End(); fend >= rightEdit && lineOf(rightEdit) == stmtEndLine; rightEdit++ {
+ }
+ // don't remove \n if there was other stuff earlier
+ if leftSyntax.IsValid() || leftStmt.IsValid() {
+ rightEdit--
+ }
}
- return []analysis.TextEdit{edit}
+
+ return []analysis.TextEdit{{Pos: leftEdit, End: rightEdit}}
}
// DeleteUnusedVars computes the edits required to delete the
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 b46340c66a..ce5beb2724 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
@@ -36,6 +36,7 @@ type gobCallee struct {
// results of type analysis (does not reach go/types data structures)
PkgPath string // package path of declaring package
Name string // user-friendly name for error messages
+ GoVersion string // version of Go effective in callee file
Unexported []string // names of free objects that are unexported
FreeRefs []freeRef // locations of references to free objects
FreeObjs []object // descriptions of free objects
@@ -114,6 +115,24 @@ func AnalyzeCallee(logf func(string, ...any), fset *token.FileSet, pkg *types.Pa
return nil, fmt.Errorf("cannot inline function %s as it has no body", name)
}
+ // Record the file's Go goVersion so that we don't
+ // inline newer code into file using an older dialect.
+ //
+ // Using the file version is overly conservative.
+ // A more precise solution would be for the type checker to
+ // record which language features the callee actually needs;
+ // see https://go.dev/issue/75726.
+ //
+ // We don't have the ast.File handy, so instead of a
+ // lookup we must scan the entire FileVersions map.
+ var goVersion string
+ for file, v := range info.FileVersions {
+ if file.Pos() < decl.Pos() && decl.Pos() < file.End() {
+ goVersion = v
+ break
+ }
+ }
+
// Record the location of all free references in the FuncDecl.
// (Parameters are not free by this definition.)
var (
@@ -342,6 +361,7 @@ func AnalyzeCallee(logf func(string, ...any), fset *token.FileSet, pkg *types.Pa
Content: content,
PkgPath: pkg.Path(),
Name: name,
+ GoVersion: goVersion,
Unexported: unexported,
FreeObjs: freeObjs,
FreeRefs: freeRefs,
@@ -421,11 +441,11 @@ func analyzeParams(logf func(string, ...any), fset *token.FileSet, info *types.I
if sig.Recv() != nil {
params = append(params, newParamInfo(sig.Recv(), false))
}
- for i := 0; i < sig.Params().Len(); i++ {
- params = append(params, newParamInfo(sig.Params().At(i), false))
+ for v := range sig.Params().Variables() {
+ params = append(params, newParamInfo(v, false))
}
- for i := 0; i < sig.Results().Len(); i++ {
- results = append(results, newParamInfo(sig.Results().At(i), true))
+ for v := range sig.Results().Variables() {
+ results = append(results, newParamInfo(v, true))
}
}
@@ -497,8 +517,8 @@ func analyzeTypeParams(_ logger, fset *token.FileSet, info *types.Info, decl *as
paramInfos := make(map[*types.TypeName]*paramInfo)
var params []*paramInfo
collect := func(tpl *types.TypeParamList) {
- for i := range tpl.Len() {
- typeName := tpl.At(i).Obj()
+ for tparam := range tpl.TypeParams() {
+ typeName := tparam.Obj()
info := &paramInfo{Name: typeName.Name()}
params = append(params, info)
paramInfos[typeName] = info
@@ -639,8 +659,7 @@ func analyzeAssignment(info *types.Info, stack []ast.Node) (assignable, ifaceAss
return true, types.IsInterface(under.Elem()), false
case *types.Struct: // Struct{k: expr}
if id, _ := kv.Key.(*ast.Ident); id != nil {
- for fi := range under.NumFields() {
- field := under.Field(fi)
+ for field := range under.Fields() {
if info.Uses[id] == field {
return true, types.IsInterface(field.Type()), false
}
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 2443504da7..03ef0714e0 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
@@ -24,9 +24,11 @@ import (
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/types/typeutil"
internalastutil "golang.org/x/tools/internal/astutil"
+ "golang.org/x/tools/internal/astutil/free"
"golang.org/x/tools/internal/packagepath"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal"
+ "golang.org/x/tools/internal/versions"
)
// A Caller describes the function call and its enclosing context.
@@ -424,12 +426,35 @@ func newImportState(logf func(string, ...any), caller *Caller, callee *gobCallee
// For simplicity we ignore existing dot imports, so that a qualified
// identifier (QI) in the callee is always represented by a QI in the caller,
// allowing us to treat a QI like a selection on a package name.
- is := &importState{
+ ist := &importState{
logf: logf,
caller: caller,
importMap: make(map[string][]string),
}
+ // Build an index of used-once PkgNames.
+ type pkgNameUse struct {
+ count int
+ id *ast.Ident // an arbitrary use
+ }
+ pkgNameUses := make(map[*types.PkgName]pkgNameUse)
+ for id, obj := range caller.Info.Uses {
+ if pkgname, ok := obj.(*types.PkgName); ok {
+ u := pkgNameUses[pkgname]
+ u.id = id
+ u.count++
+ pkgNameUses[pkgname] = u
+ }
+ }
+ // soleUse returns the ident that refers to pkgname, if there is exactly one.
+ soleUse := func(pkgname *types.PkgName) *ast.Ident {
+ u := pkgNameUses[pkgname]
+ if u.count == 1 {
+ return u.id
+ }
+ return nil
+ }
+
for _, imp := range caller.File.Imports {
if pkgName, ok := importedPkgName(caller.Info, imp); ok &&
pkgName.Name() != "." &&
@@ -448,7 +473,7 @@ func newImportState(logf func(string, ...any), caller *Caller, callee *gobCallee
// need this import. Doing so eagerly simplifies the resulting logic.
needed := true
sel, ok := ast.Unparen(caller.Call.Fun).(*ast.SelectorExpr)
- if ok && soleUse(caller.Info, pkgName) == sel.X {
+ if ok && soleUse(pkgName) == sel.X {
needed = false // no longer needed by caller
// Check to see if any of the inlined free objects need this package.
for _, obj := range callee.FreeObjs {
@@ -463,13 +488,13 @@ func newImportState(logf func(string, ...any), caller *Caller, callee *gobCallee
// return value holds these.
if needed {
path := pkgName.Imported().Path()
- is.importMap[path] = append(is.importMap[path], pkgName.Name())
+ ist.importMap[path] = append(ist.importMap[path], pkgName.Name())
} else {
- is.oldImports = append(is.oldImports, oldImport{pkgName: pkgName, spec: imp})
+ ist.oldImports = append(ist.oldImports, oldImport{pkgName: pkgName, spec: imp})
}
}
}
- return is
+ return ist
}
// importName finds an existing import name to use in a particular shadowing
@@ -575,9 +600,8 @@ func (i *importState) localName(pkgPath, pkgName string, shadow shadowMap) strin
// Since they are not relevant to removing unused imports, we instruct
// freeishNames to omit composite-literal keys that are identifiers.
func trimNewImports(newImports []newImport, new ast.Node) []newImport {
- free := map[string]bool{}
const omitComplitIdents = false
- freeishNames(free, new, omitComplitIdents)
+ free := free.Names(new, omitComplitIdents)
var res []newImport
for _, ni := range newImports {
if free[ni.pkgName] {
@@ -677,6 +701,15 @@ func (st *state) inlineCall() (*inlineCallResult, error) {
callee.Name, callee.Unexported[0])
}
+ // Reject cross-file inlining if callee requires a newer dialect of Go (#75726).
+ // (Versions default to types.Config.GoVersion, which is unset in many tests,
+ // though should be populated by an analysis driver.)
+ callerGoVersion := caller.Info.FileVersions[caller.File]
+ if callerGoVersion != "" && callee.GoVersion != "" && versions.Before(callerGoVersion, callee.GoVersion) {
+ return nil, fmt.Errorf("cannot inline call to %s (declared using %s) into a file using %s",
+ callee.Name, callee.GoVersion, callerGoVersion)
+ }
+
// -- analyze callee's free references in caller context --
// Compute syntax path enclosing Call, innermost first (Path[0]=Call),
@@ -2019,7 +2052,7 @@ func checkFalconConstraints(logf logger, params []*parameter, args []*argument,
pkg.Scope().Insert(types.NewTypeName(token.NoPos, pkg, typ.Name, types.Typ[typ.Kind]))
}
- // Declared constants and variables for for parameters.
+ // Declared constants and variables for parameters.
nconst := 0
for i, param := range params {
name := param.info.Name
@@ -2388,14 +2421,13 @@ func createBindingDecl(logf logger, caller *Caller, args []*argument, calleeDecl
// (caller syntax), so we can use type info.
// But Type is the untyped callee syntax,
// so we have to use a syntax-only algorithm.
- free := make(map[string]bool)
+ const includeComplitIdents = true
+ free := free.Names(spec.Type, includeComplitIdents)
for _, value := range spec.Values {
for name := range freeVars(caller.Info, value) {
free[name] = true
}
}
- const includeComplitIdents = true
- freeishNames(free, spec.Type, includeComplitIdents)
for name := range free {
if names[name] {
logf("binding decl would shadow free name %q", name)
@@ -3456,7 +3488,7 @@ func (st *state) assignStmts(callerStmt *ast.AssignStmt, returnOperands []ast.Ex
assert(callIdx == -1, "malformed (duplicative) AST")
callIdx = i
for j, returnOperand := range returnOperands {
- freeishNames(freeNames, returnOperand, includeComplitIdents)
+ maps.Copy(freeNames, free.Names(returnOperand, includeComplitIdents))
rhs = append(rhs, returnOperand)
if resultInfo[j]&nonTrivialResult != 0 {
nonTrivial[i+j] = true
@@ -3469,7 +3501,7 @@ func (st *state) assignStmts(callerStmt *ast.AssignStmt, returnOperands []ast.Ex
// We must clone before clearing positions, since e came from the caller.
expr = internalastutil.CloneNode(expr)
clearPositions(expr)
- freeishNames(freeNames, expr, includeComplitIdents)
+ maps.Copy(freeNames, free.Names(expr, includeComplitIdents))
rhs = append(rhs, expr)
}
}
@@ -3727,18 +3759,4 @@ func hasNonTrivialReturn(returnInfo [][]returnOperandFlags) bool {
return false
}
-// soleUse returns the ident that refers to obj, if there is exactly one.
-func soleUse(info *types.Info, obj types.Object) (sole *ast.Ident) {
- // This is not efficient, but it is called infrequently.
- for id, obj2 := range info.Uses {
- if obj2 == obj {
- if sole != nil {
- return nil // not unique
- }
- sole = id
- }
- }
- return sole
-}
-
type unit struct{} // for representing sets as maps
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/util.go b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/util.go
index 205e5b6aad..5f895cce57 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/util.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/util.go
@@ -97,6 +97,7 @@ func checkInfoFields(info *types.Info) {
assert(info.Selections != nil, "types.Info.Selections is nil")
assert(info.Types != nil, "types.Info.Types is nil")
assert(info.Uses != nil, "types.Info.Uses is nil")
+ assert(info.FileVersions != nil, "types.Info.FileVersions is nil")
}
// intersects reports whether the maps' key sets intersect.
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 27b9750896..26bc079808 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,6 +17,11 @@ 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.
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/stdlib/deps.go b/src/cmd/vendor/golang.org/x/tools/internal/stdlib/deps.go
index 96ad6c5821..581784da43 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/stdlib/deps.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/stdlib/deps.go
@@ -12,354 +12,508 @@ type pkginfo struct {
}
var deps = [...]pkginfo{
- {"archive/tar", "\x03k\x03E;\x01\n\x01$\x01\x01\x02\x05\b\x02\x01\x02\x02\f"},
- {"archive/zip", "\x02\x04a\a\x03\x12\x021;\x01+\x05\x01\x0f\x03\x02\x0e\x04"},
- {"bufio", "\x03k\x83\x01D\x14"},
- {"bytes", "n*Y\x03\fG\x02\x02"},
+ {"archive/tar", "\x03n\x03E<\x01\n\x01$\x01\x01\x02\x05\b\x02\x01\x02\x02\f"},
+ {"archive/zip", "\x02\x04d\a\x03\x12\x021<\x01+\x05\x01\x0f\x03\x02\x0e\x04"},
+ {"bufio", "\x03n\x84\x01D\x14"},
+ {"bytes", "q*Z\x03\fG\x02\x02"},
{"cmp", ""},
- {"compress/bzip2", "\x02\x02\xed\x01A"},
- {"compress/flate", "\x02l\x03\x80\x01\f\x033\x01\x03"},
- {"compress/gzip", "\x02\x04a\a\x03\x14lT"},
- {"compress/lzw", "\x02l\x03\x80\x01"},
- {"compress/zlib", "\x02\x04a\a\x03\x12\x01m"},
- {"container/heap", "\xb3\x02"},
+ {"compress/bzip2", "\x02\x02\xf1\x01A"},
+ {"compress/flate", "\x02o\x03\x81\x01\f\x033\x01\x03"},
+ {"compress/gzip", "\x02\x04d\a\x03\x14mT"},
+ {"compress/lzw", "\x02o\x03\x81\x01"},
+ {"compress/zlib", "\x02\x04d\a\x03\x12\x01n"},
+ {"container/heap", "\xb7\x02"},
{"container/list", ""},
{"container/ring", ""},
- {"context", "n\\m\x01\r"},
- {"crypto", "\x83\x01nC"},
- {"crypto/aes", "\x10\n\a\x93\x02"},
- {"crypto/cipher", "\x03\x1e\x01\x01\x1e\x11\x1c+X"},
- {"crypto/des", "\x10\x13\x1e-+\x9b\x01\x03"},
- {"crypto/dsa", "A\x04)\x83\x01\r"},
- {"crypto/ecdh", "\x03\v\f\x0e\x04\x15\x04\r\x1c\x83\x01"},
- {"crypto/ecdsa", "\x0e\x05\x03\x04\x01\x0e\a\v\x05\x01\x04\f\x01\x1c\x83\x01\r\x05K\x01"},
- {"crypto/ed25519", "\x0e\x1c\x11\x06\n\a\x1c\x83\x01C"},
- {"crypto/elliptic", "0>\x83\x01\r9"},
- {"crypto/fips140", " \x05"},
- {"crypto/hkdf", "-\x13\x01-\x15"},
- {"crypto/hmac", "\x1a\x14\x12\x01\x111"},
- {"crypto/internal/boring", "\x0e\x02\rf"},
- {"crypto/internal/boring/bbig", "\x1a\xe4\x01M"},
- {"crypto/internal/boring/bcache", "\xb8\x02\x13"},
+ {"context", "q[o\x01\r"},
+ {"crypto", "\x86\x01oC"},
+ {"crypto/aes", "\x10\n\t\x95\x02"},
+ {"crypto/cipher", "\x03 \x01\x01\x1f\x11\x1c+Y"},
+ {"crypto/des", "\x10\x15\x1f-+\x9c\x01\x03"},
+ {"crypto/dsa", "D\x04)\x84\x01\r"},
+ {"crypto/ecdh", "\x03\v\f\x10\x04\x16\x04\r\x1c\x84\x01"},
+ {"crypto/ecdsa", "\x0e\x05\x03\x04\x01\x10\a\v\x06\x01\x04\f\x01\x1c\x84\x01\r\x05K\x01"},
+ {"crypto/ed25519", "\x0e\x1e\x11\a\n\a\x1c\x84\x01C"},
+ {"crypto/elliptic", "2?\x84\x01\r9"},
+ {"crypto/fips140", "\"\x05"},
+ {"crypto/hkdf", "/\x14\x01-\x15"},
+ {"crypto/hmac", "\x1a\x16\x13\x01\x111"},
+ {"crypto/internal/boring", "\x0e\x02\ri"},
+ {"crypto/internal/boring/bbig", "\x1a\xe8\x01M"},
+ {"crypto/internal/boring/bcache", "\xbc\x02\x13"},
{"crypto/internal/boring/sig", ""},
- {"crypto/internal/cryptotest", "\x03\r\n\x06$\x0e\x19\x06\x12\x12 \x04\a\t\x16\x01\x11\x11\x1b\x01\a\x05\b\x03\x05\v"},
- {"crypto/internal/entropy", "F"},
- {"crypto/internal/fips140", "?/\x15\xa7\x01\v\x16"},
- {"crypto/internal/fips140/aes", "\x03\x1d\x03\x02\x13\x05\x01\x01\x05*\x92\x014"},
- {"crypto/internal/fips140/aes/gcm", " \x01\x02\x02\x02\x11\x05\x01\x06*\x8f\x01"},
- {"crypto/internal/fips140/alias", "\xcb\x02"},
- {"crypto/internal/fips140/bigmod", "%\x18\x01\x06*\x92\x01"},
- {"crypto/internal/fips140/check", " \x0e\x06\t\x02\xb2\x01Z"},
- {"crypto/internal/fips140/check/checktest", "%\x85\x02!"},
- {"crypto/internal/fips140/drbg", "\x03\x1c\x01\x01\x04\x13\x05\b\x01(\x83\x01\x0f7"},
- {"crypto/internal/fips140/ecdh", "\x03\x1d\x05\x02\t\r1\x83\x01\x0f7"},
- {"crypto/internal/fips140/ecdsa", "\x03\x1d\x04\x01\x02\a\x02\x068\x15nF"},
- {"crypto/internal/fips140/ed25519", "\x03\x1d\x05\x02\x04\v8\xc6\x01\x03"},
- {"crypto/internal/fips140/edwards25519", "%\a\f\x051\x92\x017"},
- {"crypto/internal/fips140/edwards25519/field", "%\x13\x051\x92\x01"},
- {"crypto/internal/fips140/hkdf", "\x03\x1d\x05\t\x06:\x15"},
- {"crypto/internal/fips140/hmac", "\x03\x1d\x14\x01\x018\x15"},
- {"crypto/internal/fips140/mlkem", "\x03\x1d\x05\x02\x0e\x03\x051"},
- {"crypto/internal/fips140/nistec", "%\f\a\x051\x92\x01*\r\x14"},
- {"crypto/internal/fips140/nistec/fiat", "%\x136\x92\x01"},
- {"crypto/internal/fips140/pbkdf2", "\x03\x1d\x05\t\x06:\x15"},
- {"crypto/internal/fips140/rsa", "\x03\x1d\x04\x01\x02\r\x01\x01\x026\x15nF"},
- {"crypto/internal/fips140/sha256", "\x03\x1d\x1d\x01\x06*\x15}"},
- {"crypto/internal/fips140/sha3", "\x03\x1d\x18\x05\x010\x92\x01K"},
- {"crypto/internal/fips140/sha512", "\x03\x1d\x1d\x01\x06*\x15}"},
- {"crypto/internal/fips140/ssh", "%^"},
- {"crypto/internal/fips140/subtle", "#\x1a\xc3\x01"},
- {"crypto/internal/fips140/tls12", "\x03\x1d\x05\t\x06\x028\x15"},
- {"crypto/internal/fips140/tls13", "\x03\x1d\x05\b\a\t1\x15"},
- {"crypto/internal/fips140cache", "\xaa\x02\r&"},
+ {"crypto/internal/constanttime", ""},
+ {"crypto/internal/cryptotest", "\x03\r\n\b%\x0e\x19\x06\x12\x12 \x04\x06\t\x18\x01\x11\x11\x1b\x01\a\x05\b\x03\x05\v"},
+ {"crypto/internal/entropy", "I"},
+ {"crypto/internal/entropy/v1.0.0", "B/\x93\x018\x13"},
+ {"crypto/internal/fips140", "A0\xbd\x01\v\x16"},
+ {"crypto/internal/fips140/aes", "\x03\x1f\x03\x02\x13\x05\x01\x01\x06*\x93\x014"},
+ {"crypto/internal/fips140/aes/gcm", "\"\x01\x02\x02\x02\x11\x05\x01\a*\x90\x01"},
+ {"crypto/internal/fips140/alias", "\xcf\x02"},
+ {"crypto/internal/fips140/bigmod", "'\x18\x01\a*\x93\x01"},
+ {"crypto/internal/fips140/check", "\"\x0e\x06\t\x02\xb4\x01Z"},
+ {"crypto/internal/fips140/check/checktest", "'\x87\x02!"},
+ {"crypto/internal/fips140/drbg", "\x03\x1e\x01\x01\x04\x13\x05\t\x01(\x84\x01\x0f7\x01"},
+ {"crypto/internal/fips140/ecdh", "\x03\x1f\x05\x02\t\r2\x84\x01\x0f7"},
+ {"crypto/internal/fips140/ecdsa", "\x03\x1f\x04\x01\x02\a\x02\x069\x15oF"},
+ {"crypto/internal/fips140/ed25519", "\x03\x1f\x05\x02\x04\v9\xc7\x01\x03"},
+ {"crypto/internal/fips140/edwards25519", "\x1e\t\a\x112\x93\x017"},
+ {"crypto/internal/fips140/edwards25519/field", "'\x13\x052\x93\x01"},
+ {"crypto/internal/fips140/hkdf", "\x03\x1f\x05\t\x06;\x15"},
+ {"crypto/internal/fips140/hmac", "\x03\x1f\x14\x01\x019\x15"},
+ {"crypto/internal/fips140/mlkem", "\x03\x1f\x05\x02\x0e\x03\x052\xca\x01"},
+ {"crypto/internal/fips140/nistec", "\x1e\t\f\f2\x93\x01*\r\x14"},
+ {"crypto/internal/fips140/nistec/fiat", "'\x137\x93\x01"},
+ {"crypto/internal/fips140/pbkdf2", "\x03\x1f\x05\t\x06;\x15"},
+ {"crypto/internal/fips140/rsa", "\x03\x1b\x04\x04\x01\x02\r\x01\x01\x027\x15oF"},
+ {"crypto/internal/fips140/sha256", "\x03\x1f\x1d\x01\a*\x15~"},
+ {"crypto/internal/fips140/sha3", "\x03\x1f\x18\x05\x011\x93\x01K"},
+ {"crypto/internal/fips140/sha512", "\x03\x1f\x1d\x01\a*\x15~"},
+ {"crypto/internal/fips140/ssh", "'_"},
+ {"crypto/internal/fips140/subtle", "\x1e\a\x1a\xc5\x01"},
+ {"crypto/internal/fips140/tls12", "\x03\x1f\x05\t\x06\x029\x15"},
+ {"crypto/internal/fips140/tls13", "\x03\x1f\x05\b\a\t2\x15"},
+ {"crypto/internal/fips140cache", "\xae\x02\r&"},
{"crypto/internal/fips140deps", ""},
- {"crypto/internal/fips140deps/byteorder", "\x99\x01"},
- {"crypto/internal/fips140deps/cpu", "\xae\x01\a"},
- {"crypto/internal/fips140deps/godebug", "\xb6\x01"},
- {"crypto/internal/fips140hash", "5\x1b3\xc8\x01"},
- {"crypto/internal/fips140only", "'\r\x01\x01M3;"},
+ {"crypto/internal/fips140deps/byteorder", "\x9c\x01"},
+ {"crypto/internal/fips140deps/cpu", "\xb1\x01\a"},
+ {"crypto/internal/fips140deps/godebug", "\xb9\x01"},
+ {"crypto/internal/fips140deps/time", "\xc9\x02"},
+ {"crypto/internal/fips140hash", "7\x1c3\xc9\x01"},
+ {"crypto/internal/fips140only", ")\r\x01\x01N3<"},
{"crypto/internal/fips140test", ""},
- {"crypto/internal/hpke", "\x0e\x01\x01\x03\x053#+gM"},
- {"crypto/internal/impl", "\xb5\x02"},
- {"crypto/internal/randutil", "\xf1\x01\x12"},
- {"crypto/internal/sysrand", "nn! \r\r\x01\x01\f\x06"},
- {"crypto/internal/sysrand/internal/seccomp", "n"},
- {"crypto/md5", "\x0e3-\x15\x16g"},
- {"crypto/mlkem", "/"},
- {"crypto/pbkdf2", "2\x0e\x01-\x15"},
- {"crypto/rand", "\x1a\x06\a\x1a\x04\x01(\x83\x01\rM"},
- {"crypto/rc4", "#\x1e-\xc6\x01"},
- {"crypto/rsa", "\x0e\f\x01\t\x0f\r\x01\x04\x06\a\x1c\x03\x123;\f\x01"},
- {"crypto/sha1", "\x0e\f'\x03*\x15\x16\x15R"},
- {"crypto/sha256", "\x0e\f\x1aO"},
- {"crypto/sha3", "\x0e'N\xc8\x01"},
- {"crypto/sha512", "\x0e\f\x1cM"},
- {"crypto/subtle", "8\x9b\x01W"},
- {"crypto/tls", "\x03\b\x02\x01\x01\x01\x01\x02\x01\x01\x01\x02\x01\x01\a\x01\r\n\x01\t\x05\x03\x01\x01\x01\x01\x02\x01\x02\x01\x17\x02\x03\x12\x16\x15\b;\x16\x16\r\b\x01\x01\x01\x02\x01\r\x06\x02\x01\x0f"},
- {"crypto/tls/internal/fips140tls", "\x17\xa1\x02"},
- {"crypto/x509", "\x03\v\x01\x01\x01\x01\x01\x01\x01\x012\x05\x01\x01\x02\x05\x0e\x06\x02\x02\x03E\x038\x01\x02\b\x01\x01\x02\a\x10\x05\x01\x06\x02\x05\n\x01\x02\x0e\x02\x01\x01\x02\x03\x01"},
- {"crypto/x509/pkix", "d\x06\a\x8d\x01G"},
- {"database/sql", "\x03\nK\x16\x03\x80\x01\v\a\"\x05\b\x02\x03\x01\r\x02\x02\x02"},
- {"database/sql/driver", "\ra\x03\xb4\x01\x0f\x11"},
- {"debug/buildinfo", "\x03X\x02\x01\x01\b\a\x03e\x19\x02\x01+\x0f\x1f"},
- {"debug/dwarf", "\x03d\a\x03\x80\x011\x11\x01\x01"},
- {"debug/elf", "\x03\x06Q\r\a\x03e\x1a\x01,\x17\x01\x16"},
- {"debug/gosym", "\x03d\n\xc2\x01\x01\x01\x02"},
- {"debug/macho", "\x03\x06Q\r\ne\x1b,\x17\x01"},
- {"debug/pe", "\x03\x06Q\r\a\x03e\x1b,\x17\x01\x16"},
- {"debug/plan9obj", "g\a\x03e\x1b,"},
- {"embed", "n*@\x19\x01S"},
+ {"crypto/internal/hpke", "\x0e\x01\x01\x03\x056#+hM"},
+ {"crypto/internal/impl", "\xb9\x02"},
+ {"crypto/internal/randutil", "\xf5\x01\x12"},
+ {"crypto/internal/sysrand", "qo! \r\r\x01\x01\f\x06"},
+ {"crypto/internal/sysrand/internal/seccomp", "q"},
+ {"crypto/md5", "\x0e6-\x15\x16h"},
+ {"crypto/mlkem", "1"},
+ {"crypto/pbkdf2", "4\x0f\x01-\x15"},
+ {"crypto/rand", "\x1a\b\a\x1b\x04\x01(\x84\x01\rM"},
+ {"crypto/rc4", "%\x1f-\xc7\x01"},
+ {"crypto/rsa", "\x0e\f\x01\v\x0f\x0e\x01\x04\x06\a\x1c\x03\x123<\f\x01"},
+ {"crypto/sha1", "\x0e\f*\x03*\x15\x16\x15S"},
+ {"crypto/sha256", "\x0e\f\x1cP"},
+ {"crypto/sha3", "\x0e)O\xc9\x01"},
+ {"crypto/sha512", "\x0e\f\x1eN"},
+ {"crypto/subtle", "\x1e\x1c\x9c\x01X"},
+ {"crypto/tls", "\x03\b\x02\x01\x01\x01\x01\x02\x01\x01\x01\x02\x01\x01\t\x01\r\n\x01\n\x05\x03\x01\x01\x01\x01\x02\x01\x02\x01\x17\x02\x03\x12\x16\x15\b<\x16\x16\r\b\x01\x01\x01\x02\x01\r\x06\x02\x01\x0f"},
+ {"crypto/tls/internal/fips140tls", "\x17\xa5\x02"},
+ {"crypto/x509", "\x03\v\x01\x01\x01\x01\x01\x01\x01\x015\x05\x01\x01\x02\x05\x0e\x06\x02\x02\x03E\x039\x01\x02\b\x01\x01\x02\a\x10\x05\x01\x06\x02\x05\b\x02\x01\x02\x0e\x02\x01\x01\x02\x03\x01"},
+ {"crypto/x509/pkix", "g\x06\a\x8e\x01G"},
+ {"database/sql", "\x03\nN\x16\x03\x81\x01\v\a\"\x05\b\x02\x03\x01\r\x02\x02\x02"},
+ {"database/sql/driver", "\rd\x03\xb5\x01\x0f\x11"},
+ {"debug/buildinfo", "\x03[\x02\x01\x01\b\a\x03e\x1a\x02\x01+\x0f\x1f"},
+ {"debug/dwarf", "\x03g\a\x03\x81\x011\x11\x01\x01"},
+ {"debug/elf", "\x03\x06T\r\a\x03e\x1b\x01\f \x17\x01\x16"},
+ {"debug/gosym", "\x03g\n\xc3\x01\x01\x01\x02"},
+ {"debug/macho", "\x03\x06T\r\ne\x1c,\x17\x01"},
+ {"debug/pe", "\x03\x06T\r\a\x03e\x1c,\x17\x01\x16"},
+ {"debug/plan9obj", "j\a\x03e\x1c,"},
+ {"embed", "q*A\x19\x01S"},
{"embed/internal/embedtest", ""},
{"encoding", ""},
- {"encoding/ascii85", "\xf1\x01C"},
- {"encoding/asn1", "\x03k\x03\x8c\x01\x01'\r\x02\x01\x10\x03\x01"},
- {"encoding/base32", "\xf1\x01A\x02"},
- {"encoding/base64", "\x99\x01XA\x02"},
- {"encoding/binary", "n\x83\x01\f(\r\x05"},
- {"encoding/csv", "\x02\x01k\x03\x80\x01D\x12\x02"},
- {"encoding/gob", "\x02`\x05\a\x03e\x1b\v\x01\x03\x1d\b\x12\x01\x0f\x02"},
- {"encoding/hex", "n\x03\x80\x01A\x03"},
- {"encoding/json", "\x03\x01^\x04\b\x03\x80\x01\f(\r\x02\x01\x02\x10\x01\x01\x02"},
- {"encoding/pem", "\x03c\b\x83\x01A\x03"},
- {"encoding/xml", "\x02\x01_\f\x03\x80\x014\x05\n\x01\x02\x10\x02"},
- {"errors", "\xca\x01\x81\x01"},
- {"expvar", "kK?\b\v\x15\r\b\x02\x03\x01\x11"},
- {"flag", "b\f\x03\x80\x01,\b\x05\b\x02\x01\x10"},
- {"fmt", "nE>\f \b\r\x02\x03\x12"},
- {"go/ast", "\x03\x01m\x0e\x01q\x03)\b\r\x02\x01"},
- {"go/build", "\x02\x01k\x03\x01\x02\x02\a\x02\x01\x17\x1f\x04\x02\t\x19\x13\x01+\x01\x04\x01\a\b\x02\x01\x12\x02\x02"},
- {"go/build/constraint", "n\xc6\x01\x01\x12\x02"},
- {"go/constant", "q\x0f}\x01\x024\x01\x02\x12"},
- {"go/doc", "\x04m\x01\x05\t>31\x10\x02\x01\x12\x02"},
- {"go/doc/comment", "\x03n\xc1\x01\x01\x01\x01\x12\x02"},
- {"go/format", "\x03n\x01\v\x01\x02qD"},
- {"go/importer", "s\a\x01\x01\x04\x01p9"},
- {"go/internal/gccgoimporter", "\x02\x01X\x13\x03\x04\v\x01n\x02,\x01\x05\x11\x01\f\b"},
- {"go/internal/gcimporter", "\x02o\x0f\x010\x05\x0e-,\x15\x03\x02"},
- {"go/internal/srcimporter", "q\x01\x01\n\x03\x01p,\x01\x05\x12\x02\x14"},
- {"go/parser", "\x03k\x03\x01\x02\v\x01q\x01+\x06\x12"},
- {"go/printer", "q\x01\x02\x03\tq\f \x15\x02\x01\x02\v\x05\x02"},
- {"go/scanner", "\x03n\x0fq2\x10\x01\x13\x02"},
- {"go/token", "\x04m\x83\x01>\x02\x03\x01\x0f\x02"},
- {"go/types", "\x03\x01\x06d\x03\x01\x03\b\x03\x02\x15\x1f\x061\x04\x03\t \x06\a\b\x01\x01\x01\x02\x01\x0f\x02\x02"},
- {"go/version", "\xbb\x01z"},
- {"hash", "\xf1\x01"},
- {"hash/adler32", "n\x15\x16"},
- {"hash/crc32", "n\x15\x16\x15\x89\x01\x01\x13"},
- {"hash/crc64", "n\x15\x16\x9e\x01"},
- {"hash/fnv", "n\x15\x16g"},
- {"hash/maphash", "\x83\x01\x11!\x03\x93\x01"},
- {"html", "\xb5\x02\x02\x12"},
- {"html/template", "\x03h\x06\x18-;\x01\n!\x05\x01\x02\x03\f\x01\x02\f\x01\x03\x02"},
- {"image", "\x02l\x1ee\x0f4\x03\x01"},
+ {"encoding/ascii85", "\xf5\x01C"},
+ {"encoding/asn1", "\x03n\x03e(\x01'\r\x02\x01\x10\x03\x01"},
+ {"encoding/base32", "\xf5\x01A\x02"},
+ {"encoding/base64", "\x9c\x01YA\x02"},
+ {"encoding/binary", "q\x84\x01\f(\r\x05"},
+ {"encoding/csv", "\x02\x01n\x03\x81\x01D\x12\x02"},
+ {"encoding/gob", "\x02c\x05\a\x03e\x1c\v\x01\x03\x1d\b\x12\x01\x0f\x02"},
+ {"encoding/hex", "q\x03\x81\x01A\x03"},
+ {"encoding/json", "\x03\x01a\x04\b\x03\x81\x01\f(\r\x02\x01\x02\x10\x01\x01\x02"},
+ {"encoding/pem", "\x03f\b\x84\x01A\x03"},
+ {"encoding/xml", "\x02\x01b\f\x03\x81\x014\x05\n\x01\x02\x10\x02"},
+ {"errors", "\xcc\x01\x83\x01"},
+ {"expvar", "nK@\b\v\x15\r\b\x02\x03\x01\x11"},
+ {"flag", "e\f\x03\x81\x01,\b\x05\b\x02\x01\x10"},
+ {"fmt", "qE&\x19\f \b\r\x02\x03\x12"},
+ {"go/ast", "\x03\x01p\x0e\x01r\x03)\b\r\x02\x01\x12\x02"},
+ {"go/build", "\x02\x01n\x03\x01\x02\x02\a\x02\x01\x17\x1f\x04\x02\b\x1b\x13\x01+\x01\x04\x01\a\b\x02\x01\x12\x02\x02"},
+ {"go/build/constraint", "q\xc7\x01\x01\x12\x02"},
+ {"go/constant", "t\x0f~\x01\x024\x01\x02\x12"},
+ {"go/doc", "\x04p\x01\x05\t=51\x10\x02\x01\x12\x02"},
+ {"go/doc/comment", "\x03q\xc2\x01\x01\x01\x01\x12\x02"},
+ {"go/format", "\x03q\x01\v\x01\x02rD"},
+ {"go/importer", "v\a\x01\x01\x04\x01q9"},
+ {"go/internal/gccgoimporter", "\x02\x01[\x13\x03\x04\v\x01o\x02,\x01\x05\x11\x01\f\b"},
+ {"go/internal/gcimporter", "\x02r\x0f\x010\x05\r/,\x15\x03\x02"},
+ {"go/internal/srcimporter", "t\x01\x01\n\x03\x01q,\x01\x05\x12\x02\x14"},
+ {"go/parser", "\x03n\x03\x01\x02\v\x01r\x01+\x06\x12"},
+ {"go/printer", "t\x01\x02\x03\tr\f \x15\x02\x01\x02\v\x05\x02"},
+ {"go/scanner", "\x03q\x0fr2\x10\x01\x13\x02"},
+ {"go/token", "\x04p\x84\x01>\x02\x03\x01\x0f\x02"},
+ {"go/types", "\x03\x01\x06g\x03\x01\x03\b\x03\x024\x062\x04\x03\t \x06\a\b\x01\x01\x01\x02\x01\x0f\x02\x02"},
+ {"go/version", "\xbe\x01{"},
+ {"hash", "\xf5\x01"},
+ {"hash/adler32", "q\x15\x16"},
+ {"hash/crc32", "q\x15\x16\x15\x8a\x01\x01\x13"},
+ {"hash/crc64", "q\x15\x16\x9f\x01"},
+ {"hash/fnv", "q\x15\x16h"},
+ {"hash/maphash", "\x86\x01\x11<|"},
+ {"html", "\xb9\x02\x02\x12"},
+ {"html/template", "\x03k\x06\x18-<\x01\n!\x05\x01\x02\x03\f\x01\x02\f\x01\x03\x02"},
+ {"image", "\x02o\x1ef\x0f4\x03\x01"},
{"image/color", ""},
- {"image/color/palette", "\x8c\x01"},
- {"image/draw", "\x8b\x01\x01\x04"},
- {"image/gif", "\x02\x01\x05f\x03\x1a\x01\x01\x01\vX"},
- {"image/internal/imageutil", "\x8b\x01"},
- {"image/jpeg", "\x02l\x1d\x01\x04a"},
- {"image/png", "\x02\a^\n\x12\x02\x06\x01eC"},
- {"index/suffixarray", "\x03d\a\x83\x01\f+\n\x01"},
- {"internal/abi", "\xb5\x01\x96\x01"},
- {"internal/asan", "\xcb\x02"},
- {"internal/bisect", "\xaa\x02\r\x01"},
- {"internal/buildcfg", "qGe\x06\x02\x05\n\x01"},
- {"internal/bytealg", "\xae\x01\x9d\x01"},
+ {"image/color/palette", "\x8f\x01"},
+ {"image/draw", "\x8e\x01\x01\x04"},
+ {"image/gif", "\x02\x01\x05i\x03\x1a\x01\x01\x01\vY"},
+ {"image/internal/imageutil", "\x8e\x01"},
+ {"image/jpeg", "\x02o\x1d\x01\x04b"},
+ {"image/png", "\x02\aa\n\x12\x02\x06\x01fC"},
+ {"index/suffixarray", "\x03g\a\x84\x01\f+\n\x01"},
+ {"internal/abi", "\xb8\x01\x97\x01"},
+ {"internal/asan", "\xcf\x02"},
+ {"internal/bisect", "\xae\x02\r\x01"},
+ {"internal/buildcfg", "tGf\x06\x02\x05\n\x01"},
+ {"internal/bytealg", "\xb1\x01\x9e\x01"},
{"internal/byteorder", ""},
{"internal/cfg", ""},
- {"internal/cgrouptest", "q[Q\x06\x0f\x02\x01\x04\x01"},
- {"internal/chacha8rand", "\x99\x01\x15\a\x96\x01"},
+ {"internal/cgrouptest", "tZS\x06\x0f\x02\x01\x04\x01"},
+ {"internal/chacha8rand", "\x9c\x01\x15\a\x97\x01"},
{"internal/copyright", ""},
{"internal/coverage", ""},
{"internal/coverage/calloc", ""},
- {"internal/coverage/cfile", "k\x06\x16\x17\x01\x02\x01\x01\x01\x01\x01\x01\x01#\x02$,\x06\a\n\x01\x03\r\x06"},
- {"internal/coverage/cformat", "\x04m-\x04O\v6\x01\x02\r"},
- {"internal/coverage/cmerge", "q-_"},
- {"internal/coverage/decodecounter", "g\n-\v\x02F,\x17\x17"},
- {"internal/coverage/decodemeta", "\x02e\n\x16\x17\v\x02F,"},
- {"internal/coverage/encodecounter", "\x02e\n-\f\x01\x02D\v!\x15"},
- {"internal/coverage/encodemeta", "\x02\x01d\n\x12\x04\x17\r\x02D,."},
- {"internal/coverage/pods", "\x04m-\x7f\x06\x05\n\x02\x01"},
- {"internal/coverage/rtcov", "\xcb\x02"},
- {"internal/coverage/slicereader", "g\n\x80\x01Z"},
- {"internal/coverage/slicewriter", "q\x80\x01"},
- {"internal/coverage/stringtab", "q8\x04D"},
+ {"internal/coverage/cfile", "n\x06\x16\x17\x01\x02\x01\x01\x01\x01\x01\x01\x01\"\x02&,\x06\a\n\x01\x03\r\x06"},
+ {"internal/coverage/cformat", "\x04p-\x04P\v6\x01\x02\r"},
+ {"internal/coverage/cmerge", "t-`"},
+ {"internal/coverage/decodecounter", "j\n-\v\x02G,\x17\x17"},
+ {"internal/coverage/decodemeta", "\x02h\n\x16\x17\v\x02G,"},
+ {"internal/coverage/encodecounter", "\x02h\n-\f\x01\x02E\v!\x15"},
+ {"internal/coverage/encodemeta", "\x02\x01g\n\x12\x04\x17\r\x02E,."},
+ {"internal/coverage/pods", "\x04p-\x80\x01\x06\x05\n\x02\x01"},
+ {"internal/coverage/rtcov", "\xcf\x02"},
+ {"internal/coverage/slicereader", "j\n\x81\x01Z"},
+ {"internal/coverage/slicewriter", "t\x81\x01"},
+ {"internal/coverage/stringtab", "t8\x04E"},
{"internal/coverage/test", ""},
{"internal/coverage/uleb128", ""},
- {"internal/cpu", "\xcb\x02"},
- {"internal/dag", "\x04m\xc1\x01\x03"},
- {"internal/diff", "\x03n\xc2\x01\x02"},
- {"internal/exportdata", "\x02\x01k\x03\x02c\x1b,\x01\x05\x11\x01\x02"},
- {"internal/filepathlite", "n*@\x1a@"},
- {"internal/fmtsort", "\x04\xa1\x02\r"},
- {"internal/fuzz", "\x03\nB\x18\x04\x03\x03\x01\v\x036;\f\x03\x1d\x01\x05\x02\x05\n\x01\x02\x01\x01\f\x04\x02"},
+ {"internal/cpu", "\xcf\x02"},
+ {"internal/dag", "\x04p\xc2\x01\x03"},
+ {"internal/diff", "\x03q\xc3\x01\x02"},
+ {"internal/exportdata", "\x02\x01n\x03\x02c\x1c,\x01\x05\x11\x01\x02"},
+ {"internal/filepathlite", "q*A\x1a@"},
+ {"internal/fmtsort", "\x04\xa5\x02\r"},
+ {"internal/fuzz", "\x03\nE\x18\x04\x03\x03\x01\v\x036<\f\x03\x1d\x01\x05\x02\x05\n\x01\x02\x01\x01\f\x04\x02"},
{"internal/goarch", ""},
- {"internal/godebug", "\x96\x01!\x80\x01\x01\x13"},
+ {"internal/godebug", "\x99\x01!\x81\x01\x01\x13"},
{"internal/godebugs", ""},
{"internal/goexperiment", ""},
{"internal/goos", ""},
- {"internal/goroot", "\x9d\x02\x01\x05\x12\x02"},
+ {"internal/goroot", "\xa1\x02\x01\x05\x12\x02"},
{"internal/gover", "\x04"},
{"internal/goversion", ""},
- {"internal/itoa", ""},
- {"internal/lazyregexp", "\x9d\x02\v\r\x02"},
- {"internal/lazytemplate", "\xf1\x01,\x18\x02\f"},
- {"internal/msan", "\xcb\x02"},
+ {"internal/lazyregexp", "\xa1\x02\v\r\x02"},
+ {"internal/lazytemplate", "\xf5\x01,\x18\x02\f"},
+ {"internal/msan", "\xcf\x02"},
{"internal/nettrace", ""},
- {"internal/obscuretestdata", "f\x8b\x01,"},
- {"internal/oserror", "n"},
- {"internal/pkgbits", "\x03L\x18\a\x03\x04\vq\r\x1f\r\n\x01"},
+ {"internal/obscuretestdata", "i\x8c\x01,"},
+ {"internal/oserror", "q"},
+ {"internal/pkgbits", "\x03O\x18\a\x03\x04\vr\r\x1f\r\n\x01"},
{"internal/platform", ""},
- {"internal/poll", "nO\x1f\x159\r\x01\x01\f\x06"},
- {"internal/profile", "\x03\x04g\x03\x80\x017\v\x01\x01\x10"},
+ {"internal/poll", "qj\x05\x159\r\x01\x01\f\x06"},
+ {"internal/profile", "\x03\x04j\x03\x81\x017\n\x01\x01\x01\x10"},
{"internal/profilerecord", ""},
- {"internal/race", "\x94\x01\xb7\x01"},
- {"internal/reflectlite", "\x94\x01!9<!"},
- {"internal/runtime/atomic", "\xb5\x01\x96\x01"},
- {"internal/runtime/cgroup", "\x98\x01:\x02w"},
- {"internal/runtime/exithook", "\xcb\x01\x80\x01"},
- {"internal/runtime/gc", "\xb5\x01"},
- {"internal/runtime/maps", "\x94\x01\x01 \v\t\a\x03x"},
- {"internal/runtime/math", "\xb5\x01"},
+ {"internal/race", "\x97\x01\xb8\x01"},
+ {"internal/reflectlite", "\x97\x01!:<!"},
+ {"internal/runtime/atomic", "\xb8\x01\x97\x01"},
+ {"internal/runtime/cgroup", "\x9b\x01<\x04t"},
+ {"internal/runtime/exithook", "\xcd\x01\x82\x01"},
+ {"internal/runtime/gc", "\xb8\x01"},
+ {"internal/runtime/gc/internal/gen", "\n`\n\x17j\x04\v\x1d\b\x10\x02"},
+ {"internal/runtime/gc/scan", "\xb1\x01\a\x18\x06y"},
+ {"internal/runtime/maps", "\x97\x01\x01 \n\t\t\x02y"},
+ {"internal/runtime/math", "\xb8\x01"},
{"internal/runtime/startlinetest", ""},
- {"internal/runtime/strconv", "\xd0\x01"},
- {"internal/runtime/sys", "\xb5\x01\x04"},
- {"internal/runtime/syscall", "\xb5\x01\x96\x01"},
+ {"internal/runtime/sys", "\xb8\x01\x04"},
+ {"internal/runtime/syscall/linux", "\xb8\x01\x97\x01"},
{"internal/runtime/wasitest", ""},
- {"internal/saferio", "\xf1\x01Z"},
- {"internal/singleflight", "\xb7\x02"},
- {"internal/stringslite", "\x98\x01\xb3\x01"},
- {"internal/sync", "\x94\x01!\x14o\x13"},
- {"internal/synctest", "\x94\x01\xb7\x01"},
- {"internal/syscall/execenv", "\xb9\x02"},
- {"internal/syscall/unix", "\xaa\x02\x0e\x01\x12"},
- {"internal/sysinfo", "\x02\x01\xab\x01C,\x18\x02"},
+ {"internal/saferio", "\xf5\x01Z"},
+ {"internal/singleflight", "\xbb\x02"},
+ {"internal/strconv", "\x84\x02K"},
+ {"internal/stringslite", "\x9b\x01\xb4\x01"},
+ {"internal/sync", "\x97\x01!\x13q\x13"},
+ {"internal/synctest", "\x97\x01\xb8\x01"},
+ {"internal/syscall/execenv", "\xbd\x02"},
+ {"internal/syscall/unix", "\xae\x02\x0e\x01\x12"},
+ {"internal/sysinfo", "\x02\x01\xae\x01D,\x18\x02"},
{"internal/syslist", ""},
- {"internal/testenv", "\x03\na\x02\x01)\x1b\x10-+\x01\x05\a\n\x01\x02\x02\x01\v"},
- {"internal/testhash", "\x03\x80\x01n\x118\v"},
- {"internal/testlog", "\xb7\x02\x01\x13"},
- {"internal/testpty", "n\x03\xac\x01"},
- {"internal/trace", "\x02\x01\x01\x06]\a\x03t\x03\x03\x06\x03\t5\x01\x01\x01\x10\x06"},
- {"internal/trace/internal/testgen", "\x03d\nr\x03\x02\x03\x011\v\r\x10"},
- {"internal/trace/internal/tracev1", "\x03\x01c\a\x03z\x06\f5\x01"},
- {"internal/trace/raw", "\x02e\nw\x03\x06C\x01\x12"},
- {"internal/trace/testtrace", "\x02\x01k\x03r\x03\x05\x01\x057\n\x02\x01"},
+ {"internal/testenv", "\x03\nd\x02\x01)\x1b\x0f/+\x01\x05\a\n\x01\x02\x02\x01\v"},
+ {"internal/testhash", "\x03\x83\x01o\x118\v"},
+ {"internal/testlog", "\xbb\x02\x01\x13"},
+ {"internal/testpty", "q\x03\xad\x01"},
+ {"internal/trace", "\x02\x01\x01\x06`\a\x03u\x03\x03\x06\x03\t5\x01\x01\x01\x10\x06"},
+ {"internal/trace/internal/testgen", "\x03g\ns\x03\x02\x03\x011\v\r\x10"},
+ {"internal/trace/internal/tracev1", "\x03\x01f\a\x03{\x06\f5\x01"},
+ {"internal/trace/raw", "\x02h\nx\x03\x06C\x01\x12"},
+ {"internal/trace/testtrace", "\x02\x01n\x03o\x04\x03\x05\x01\x05,\v\x02\b\x02\x01\x05"},
{"internal/trace/tracev2", ""},
- {"internal/trace/traceviewer", "\x02^\v\x06\x19=\x1c\a\a\x04\b\v\x15\x01\x05\a\n\x01\x02\x0e"},
+ {"internal/trace/traceviewer", "\x02a\v\x06\x19<\x1e\a\a\x04\b\v\x15\x01\x05\a\n\x01\x02\x0e"},
{"internal/trace/traceviewer/format", ""},
- {"internal/trace/version", "qw\t"},
- {"internal/txtar", "\x03n\xac\x01\x18"},
- {"internal/types/errors", "\xb4\x02"},
- {"internal/unsafeheader", "\xcb\x02"},
- {"internal/xcoff", "Z\r\a\x03e\x1b,\x17\x01"},
- {"internal/zstd", "g\a\x03\x80\x01\x0f"},
- {"io", "n\xc9\x01"},
- {"io/fs", "n*+.1\x10\x13\x04"},
- {"io/ioutil", "\xf1\x01\x01+\x15\x03"},
- {"iter", "\xc9\x01a!"},
- {"log", "q\x80\x01\x05'\r\r\x01\r"},
+ {"internal/trace/version", "tx\t"},
+ {"internal/txtar", "\x03q\xad\x01\x18"},
+ {"internal/types/errors", "\xb8\x02"},
+ {"internal/unsafeheader", "\xcf\x02"},
+ {"internal/xcoff", "]\r\a\x03e\x1c,\x17\x01"},
+ {"internal/zstd", "j\a\x03\x81\x01\x0f"},
+ {"io", "q\xca\x01"},
+ {"io/fs", "q**01\x10\x13\x04"},
+ {"io/ioutil", "\xf5\x01\x01+\x15\x03"},
+ {"iter", "\xcb\x01c!"},
+ {"log", "t\x81\x01\x05'\r\r\x01\r"},
{"log/internal", ""},
- {"log/slog", "\x03\nU\t\x03\x03\x80\x01\x04\x01\x02\x02\x03(\x05\b\x02\x01\x02\x01\r\x02\x02\x02"},
+ {"log/slog", "\x03\nX\t\x03\x03\x81\x01\x04\x01\x02\x02\x03(\x05\b\x02\x01\x02\x01\r\x02\x02\x02"},
{"log/slog/internal", ""},
- {"log/slog/internal/benchmarks", "\ra\x03\x80\x01\x06\x03:\x11"},
- {"log/slog/internal/buffer", "\xb7\x02"},
- {"log/syslog", "n\x03\x84\x01\x12\x16\x18\x02\x0e"},
- {"maps", "\xf4\x01W"},
- {"math", "\xae\x01RK"},
- {"math/big", "\x03k\x03(\x15C\f\x03\x020\x02\x01\x02\x14"},
- {"math/big/internal/asmgen", "\x03\x01m\x8f\x012\x03"},
- {"math/bits", "\xcb\x02"},
- {"math/cmplx", "\xfd\x01\x03"},
- {"math/rand", "\xb6\x01G:\x01\x13"},
- {"math/rand/v2", "n+\x03a\x03K"},
- {"mime", "\x02\x01c\b\x03\x80\x01\v!\x15\x03\x02\x10\x02"},
- {"mime/multipart", "\x02\x01H#\x03E;\v\x01\a\x02\x15\x02\x06\x0f\x02\x01\x16"},
- {"mime/quotedprintable", "\x02\x01n\x80\x01"},
- {"net", "\x04\ta*\x1e\a\x04\x05\x11\x01\x04\x15\x01%\x06\r\b\x05\x01\x01\f\x06\a"},
- {"net/http", "\x02\x01\x04\x04\x02>\b\x13\x01\a\x03E;\x01\x03\a\x01\x03\x02\x02\x01\x02\x06\x02\x01\x01\n\x01\x01\x05\x01\x02\x05\b\x01\x01\x01\x02\x01\r\x02\x02\x02\b\x01\x01\x01"},
- {"net/http/cgi", "\x02Q\x1b\x03\x80\x01\x04\a\v\x01\x13\x01\x01\x01\x04\x01\x05\x02\b\x02\x01\x10\x0e"},
- {"net/http/cookiejar", "\x04j\x03\x96\x01\x01\b\f\x16\x03\x02\x0e\x04"},
- {"net/http/fcgi", "\x02\x01\nZ\a\x03\x80\x01\x16\x01\x01\x14\x18\x02\x0e"},
- {"net/http/httptest", "\x02\x01\nF\x02\x1b\x01\x80\x01\x04\x12\x01\n\t\x02\x17\x01\x02\x0e\x0e"},
- {"net/http/httptrace", "\rFnF\x14\n "},
- {"net/http/httputil", "\x02\x01\na\x03\x80\x01\x04\x0f\x03\x01\x05\x02\x01\v\x01\x19\x02\x0e\x0e"},
- {"net/http/internal", "\x02\x01k\x03\x80\x01"},
- {"net/http/internal/ascii", "\xb5\x02\x12"},
- {"net/http/internal/httpcommon", "\ra\x03\x9c\x01\x0e\x01\x17\x01\x01\x02\x1c\x02"},
- {"net/http/internal/testcert", "\xb5\x02"},
- {"net/http/pprof", "\x02\x01\nd\x18-\x11*\x04\x13\x14\x01\r\x04\x03\x01\x02\x01\x10"},
+ {"log/slog/internal/benchmarks", "\rd\x03\x81\x01\x06\x03:\x11"},
+ {"log/slog/internal/buffer", "\xbb\x02"},
+ {"log/syslog", "q\x03\x85\x01\x12\x16\x18\x02\x0e"},
+ {"maps", "\xf8\x01W"},
+ {"math", "\xb1\x01SK"},
+ {"math/big", "\x03n\x03(\x15D\f\x03\x020\x02\x01\x02\x14"},
+ {"math/big/internal/asmgen", "\x03\x01p\x90\x012\x03"},
+ {"math/bits", "\xcf\x02"},
+ {"math/cmplx", "\x81\x02\x03"},
+ {"math/rand", "\xb9\x01H:\x01\x13"},
+ {"math/rand/v2", "q+\x03b\x03K"},
+ {"mime", "\x02\x01f\b\x03\x81\x01\v!\x15\x03\x02\x10\x02"},
+ {"mime/multipart", "\x02\x01K#\x03E<\v\x01\a\x02\x15\x02\x06\x0f\x02\x01\x16"},
+ {"mime/quotedprintable", "\x02\x01q\x81\x01"},
+ {"net", "\x04\td*\x1e\n\x05\x12\x01\x01\x04\x15\x01%\x06\r\b\x05\x01\x01\f\x06\a"},
+ {"net/http", "\x02\x01\x03\x01\x04\x02A\b\x13\x01\a\x03E<\x01\x03\a\x01\x03\x02\x02\x01\x02\x06\x02\x01\x01\n\x01\x01\x05\x01\x02\x05\b\x01\x01\x01\x02\x01\r\x02\x02\x02\b\x01\x01\x01"},
+ {"net/http/cgi", "\x02T\x1b\x03\x81\x01\x04\a\v\x01\x13\x01\x01\x01\x04\x01\x05\x02\b\x02\x01\x10\x0e"},
+ {"net/http/cookiejar", "\x04m\x03\x97\x01\x01\b\f\x16\x03\x02\x0e\x04"},
+ {"net/http/fcgi", "\x02\x01\n]\a\x03\x81\x01\x16\x01\x01\x14\x18\x02\x0e"},
+ {"net/http/httptest", "\x02\x01\nI\x02\x1b\x01\x81\x01\x04\x12\x01\n\t\x02\x17\x01\x02\x0e\x0e"},
+ {"net/http/httptrace", "\rImH\x14\n "},
+ {"net/http/httputil", "\x02\x01\nd\x03\x81\x01\x04\x0f\x03\x01\x05\x02\x01\v\x01\x19\x02\x0e\x0e"},
+ {"net/http/internal", "\x02\x01n\x03\x81\x01"},
+ {"net/http/internal/ascii", "\xb9\x02\x12"},
+ {"net/http/internal/httpcommon", "\rd\x03\x9d\x01\x0e\x01\x17\x01\x01\x02\x1c\x02"},
+ {"net/http/internal/testcert", "\xb9\x02"},
+ {"net/http/pprof", "\x02\x01\ng\x18-\x02\x0e,\x04\x13\x14\x01\r\x04\x03\x01\x02\x01\x10"},
{"net/internal/cgotest", ""},
- {"net/internal/socktest", "q\xc6\x01\x02"},
- {"net/mail", "\x02l\x03\x80\x01\x04\x0f\x03\x14\x1a\x02\x0e\x04"},
- {"net/netip", "\x04j*\x01$@\x034\x16"},
- {"net/rpc", "\x02g\x05\x03\x0f\ng\x04\x12\x01\x1d\r\x03\x02"},
- {"net/rpc/jsonrpc", "k\x03\x03\x80\x01\x16\x11\x1f"},
- {"net/smtp", "\x19/\v\x13\b\x03\x80\x01\x16\x14\x1a"},
- {"net/textproto", "\x02\x01k\x03\x80\x01\f\n-\x01\x02\x14"},
- {"net/url", "n\x03\x8b\x01&\x10\x02\x01\x16"},
- {"os", "n*\x01\x19\x03\b\t\x12\x03\x01\x05\x10\x018\b\x05\x01\x01\f\x06"},
- {"os/exec", "\x03\naH%\x01\x15\x01+\x06\a\n\x01\x04\f"},
- {"os/exec/internal/fdtest", "\xb9\x02"},
- {"os/signal", "\r\x90\x02\x15\x05\x02"},
- {"os/user", "\x02\x01k\x03\x80\x01,\r\n\x01\x02"},
- {"path", "n*\xb1\x01"},
- {"path/filepath", "n*\x1a@+\r\b\x03\x04\x10"},
- {"plugin", "n"},
- {"reflect", "n&\x04\x1d\b\f\x06\x04\x1b\x06\t-\n\x03\x10\x02\x02"},
+ {"net/internal/socktest", "t\xc7\x01\x02"},
+ {"net/mail", "\x02o\x03\x81\x01\x04\x0f\x03\x14\x1a\x02\x0e\x04"},
+ {"net/netip", "\x04m*\x01e\x034\x16"},
+ {"net/rpc", "\x02j\x05\x03\x0f\nh\x04\x12\x01\x1d\r\x03\x02"},
+ {"net/rpc/jsonrpc", "n\x03\x03\x81\x01\x16\x11\x1f"},
+ {"net/smtp", "\x192\v\x13\b\x03\x81\x01\x16\x14\x1a"},
+ {"net/textproto", "\x02\x01n\x03\x81\x01\f\n-\x01\x02\x14"},
+ {"net/url", "q\x03\xa7\x01\v\x10\x02\x01\x16"},
+ {"os", "q*\x01\x19\x03\x10\x13\x01\x03\x01\x05\x10\x018\b\x05\x01\x01\f\x06"},
+ {"os/exec", "\x03\ndH&\x01\x15\x01+\x06\a\n\x01\x04\f"},
+ {"os/exec/internal/fdtest", "\xbd\x02"},
+ {"os/signal", "\r\x94\x02\x15\x05\x02"},
+ {"os/user", "\x02\x01n\x03\x81\x01,\r\n\x01\x02"},
+ {"path", "q*\xb2\x01"},
+ {"path/filepath", "q*\x1aA+\r\b\x03\x04\x10"},
+ {"plugin", "q"},
+ {"reflect", "q&\x04\x1d\x13\b\x03\x05\x17\x06\t-\n\x03\x10\x02\x02"},
{"reflect/internal/example1", ""},
{"reflect/internal/example2", ""},
- {"regexp", "\x03\xee\x018\t\x02\x01\x02\x10\x02"},
- {"regexp/syntax", "\xb2\x02\x01\x01\x01\x02\x10\x02"},
- {"runtime", "\x94\x01\x04\x01\x03\f\x06\a\x02\x01\x01\x0f\x03\x01\x01\x01\x01\x01\x02\x01\x01\x04\x10c"},
- {"runtime/coverage", "\xa0\x01Q"},
- {"runtime/debug", "qUW\r\b\x02\x01\x10\x06"},
- {"runtime/metrics", "\xb7\x01F-!"},
- {"runtime/pprof", "\x02\x01\x01\x03\x06Z\a\x03#4)\f \r\b\x01\x01\x01\x02\x02\t\x03\x06"},
- {"runtime/race", "\xb0\x02"},
+ {"regexp", "\x03\xf2\x018\t\x02\x01\x02\x10\x02"},
+ {"regexp/syntax", "\xb6\x02\x01\x01\x01\x02\x10\x02"},
+ {"runtime", "\x97\x01\x04\x01\x03\f\x06\a\x02\x01\x01\x0e\x03\x01\x01\x01\x02\x01\x01\x02\x01\x04\x01\x10c"},
+ {"runtime/coverage", "\xa3\x01R"},
+ {"runtime/debug", "tTY\r\b\x02\x01\x10\x06"},
+ {"runtime/metrics", "\xba\x01G-!"},
+ {"runtime/pprof", "\x02\x01\x01\x03\x06]\a\x03#$\x0f+\f \r\b\x01\x01\x01\x02\x02\t\x03\x06"},
+ {"runtime/race", "\xb4\x02"},
{"runtime/race/internal/amd64v1", ""},
- {"runtime/trace", "\ra\x03w\t9\b\x05\x01\r\x06"},
- {"slices", "\x04\xf0\x01\fK"},
- {"sort", "\xca\x0162"},
- {"strconv", "n*@%\x03I"},
- {"strings", "n&\x04@\x19\x03\f7\x10\x02\x02"},
+ {"runtime/trace", "\rd\x03x\t9\b\x05\x01\r\x06"},
+ {"slices", "\x04\xf4\x01\fK"},
+ {"sort", "\xcc\x0182"},
+ {"strconv", "q*@\x01q"},
+ {"strings", "q&\x04A\x19\x03\f7\x10\x02\x02"},
{"structs", ""},
- {"sync", "\xc9\x01\x10\x01P\x0e\x13"},
- {"sync/atomic", "\xcb\x02"},
- {"syscall", "n'\x03\x01\x1c\b\x03\x03\x06\vV\b\x05\x01\x13"},
- {"testing", "\x03\na\x02\x01X\x14\x14\f\x05\x1b\x06\x02\x05\x02\x05\x01\x02\x01\x02\x01\r\x02\x02\x02"},
- {"testing/fstest", "n\x03\x80\x01\x01\n&\x10\x03\b\b"},
- {"testing/internal/testdeps", "\x02\v\xa7\x01-\x10,\x03\x05\x03\x06\a\x02\x0e"},
- {"testing/iotest", "\x03k\x03\x80\x01\x04"},
- {"testing/quick", "p\x01\x8c\x01\x05#\x10\x10"},
- {"testing/slogtest", "\ra\x03\x86\x01.\x05\x10\v"},
- {"testing/synctest", "\xda\x01`\x11"},
- {"text/scanner", "\x03n\x80\x01,*\x02"},
- {"text/tabwriter", "q\x80\x01X"},
- {"text/template", "n\x03B>\x01\n \x01\x05\x01\x02\x05\v\x02\r\x03\x02"},
- {"text/template/parse", "\x03n\xb9\x01\n\x01\x12\x02"},
- {"time", "n*\x1e\"(*\r\x02\x12"},
- {"time/tzdata", "n\xcb\x01\x12"},
+ {"sync", "\xcb\x01\x12\x01P\x0e\x13"},
+ {"sync/atomic", "\xcf\x02"},
+ {"syscall", "q'\x03\x01\x1c\n\x03\x06\f\x04S\b\x05\x01\x13"},
+ {"testing", "\x03\nd\x02\x01W\x16\x14\f\x05\x1b\x06\x02\x05\x02\x05\x01\x02\x01\x02\x01\r\x02\x04"},
+ {"testing/fstest", "q\x03\x81\x01\x01\n&\x10\x03\b\b"},
+ {"testing/internal/testdeps", "\x02\v\xaa\x01.\x10,\x03\x05\x03\x06\a\x02\x0e"},
+ {"testing/iotest", "\x03n\x03\x81\x01\x04"},
+ {"testing/quick", "s\x01\x8d\x01\x05#\x10\x10"},
+ {"testing/slogtest", "\rd\x03\x87\x01.\x05\x10\v"},
+ {"testing/synctest", "\xde\x01`\x11"},
+ {"text/scanner", "\x03q\x81\x01,*\x02"},
+ {"text/tabwriter", "t\x81\x01X"},
+ {"text/template", "q\x03B?\x01\n \x01\x05\x01\x02\x05\v\x02\r\x03\x02"},
+ {"text/template/parse", "\x03q\xba\x01\n\x01\x12\x02"},
+ {"time", "q*\x1e#(*\r\x02\x12"},
+ {"time/tzdata", "q\xcc\x01\x12"},
{"unicode", ""},
{"unicode/utf16", ""},
{"unicode/utf8", ""},
- {"unique", "\x94\x01!#\x01Q\r\x01\x13\x12"},
+ {"unique", "\x97\x01!$\x01Q\r\x01\x13\x12"},
{"unsafe", ""},
- {"vendor/golang.org/x/crypto/chacha20", "\x10W\a\x92\x01*&"},
- {"vendor/golang.org/x/crypto/chacha20poly1305", "\x10W\a\xde\x01\x04\x01\a"},
- {"vendor/golang.org/x/crypto/cryptobyte", "d\n\x03\x8d\x01' \n"},
+ {"vendor/golang.org/x/crypto/chacha20", "\x10Z\a\x93\x01*&"},
+ {"vendor/golang.org/x/crypto/chacha20poly1305", "\x10Z\a\xdf\x01\x04\x01\a"},
+ {"vendor/golang.org/x/crypto/cryptobyte", "g\n\x03\x8e\x01' \n"},
{"vendor/golang.org/x/crypto/cryptobyte/asn1", ""},
- {"vendor/golang.org/x/crypto/internal/alias", "\xcb\x02"},
- {"vendor/golang.org/x/crypto/internal/poly1305", "R\x15\x99\x01"},
- {"vendor/golang.org/x/net/dns/dnsmessage", "n"},
- {"vendor/golang.org/x/net/http/httpguts", "\x87\x02\x14\x1a\x14\r"},
- {"vendor/golang.org/x/net/http/httpproxy", "n\x03\x96\x01\x10\x05\x01\x18\x14\r"},
- {"vendor/golang.org/x/net/http2/hpack", "\x03k\x03\x80\x01F"},
- {"vendor/golang.org/x/net/idna", "q\x8c\x018\x14\x10\x02\x01"},
- {"vendor/golang.org/x/net/nettest", "\x03d\a\x03\x80\x01\x11\x05\x16\x01\f\n\x01\x02\x02\x01\v"},
- {"vendor/golang.org/x/sys/cpu", "\x9d\x02\r\n\x01\x16"},
- {"vendor/golang.org/x/text/secure/bidirule", "n\xdb\x01\x11\x01"},
- {"vendor/golang.org/x/text/transform", "\x03k\x83\x01X"},
- {"vendor/golang.org/x/text/unicode/bidi", "\x03\bf\x84\x01>\x16"},
- {"vendor/golang.org/x/text/unicode/norm", "g\n\x80\x01F\x12\x11"},
- {"weak", "\x94\x01\x96\x01!"},
+ {"vendor/golang.org/x/crypto/internal/alias", "\xcf\x02"},
+ {"vendor/golang.org/x/crypto/internal/poly1305", "U\x15\x9a\x01"},
+ {"vendor/golang.org/x/net/dns/dnsmessage", "q"},
+ {"vendor/golang.org/x/net/http/httpguts", "\x8b\x02\x14\x1a\x14\r"},
+ {"vendor/golang.org/x/net/http/httpproxy", "q\x03\x97\x01\x10\x05\x01\x18\x14\r"},
+ {"vendor/golang.org/x/net/http2/hpack", "\x03n\x03\x81\x01F"},
+ {"vendor/golang.org/x/net/idna", "t\x8d\x018\x14\x10\x02\x01"},
+ {"vendor/golang.org/x/net/nettest", "\x03g\a\x03\x81\x01\x11\x05\x16\x01\f\n\x01\x02\x02\x01\v"},
+ {"vendor/golang.org/x/sys/cpu", "\xa1\x02\r\n\x01\x16"},
+ {"vendor/golang.org/x/text/secure/bidirule", "q\xdc\x01\x11\x01"},
+ {"vendor/golang.org/x/text/transform", "\x03n\x84\x01X"},
+ {"vendor/golang.org/x/text/unicode/bidi", "\x03\bi\x85\x01>\x16"},
+ {"vendor/golang.org/x/text/unicode/norm", "j\n\x81\x01F\x12\x11"},
+ {"weak", "\x97\x01\x97\x01!"},
}
+
+// bootstrap is the list of bootstrap packages extracted from cmd/dist.
+var bootstrap = map[string]bool{
+ "cmp": true,
+ "cmd/asm": true,
+ "cmd/asm/internal/arch": true,
+ "cmd/asm/internal/asm": true,
+ "cmd/asm/internal/flags": true,
+ "cmd/asm/internal/lex": true,
+ "cmd/cgo": true,
+ "cmd/compile": true,
+ "cmd/compile/internal/abi": true,
+ "cmd/compile/internal/abt": true,
+ "cmd/compile/internal/amd64": true,
+ "cmd/compile/internal/arm": true,
+ "cmd/compile/internal/arm64": true,
+ "cmd/compile/internal/base": true,
+ "cmd/compile/internal/bitvec": true,
+ "cmd/compile/internal/compare": true,
+ "cmd/compile/internal/coverage": true,
+ "cmd/compile/internal/deadlocals": true,
+ "cmd/compile/internal/devirtualize": true,
+ "cmd/compile/internal/dwarfgen": true,
+ "cmd/compile/internal/escape": true,
+ "cmd/compile/internal/gc": true,
+ "cmd/compile/internal/importer": true,
+ "cmd/compile/internal/inline": true,
+ "cmd/compile/internal/inline/inlheur": true,
+ "cmd/compile/internal/inline/interleaved": true,
+ "cmd/compile/internal/ir": true,
+ "cmd/compile/internal/liveness": true,
+ "cmd/compile/internal/logopt": true,
+ "cmd/compile/internal/loong64": true,
+ "cmd/compile/internal/loopvar": true,
+ "cmd/compile/internal/mips": true,
+ "cmd/compile/internal/mips64": true,
+ "cmd/compile/internal/noder": true,
+ "cmd/compile/internal/objw": true,
+ "cmd/compile/internal/pgoir": true,
+ "cmd/compile/internal/pkginit": true,
+ "cmd/compile/internal/ppc64": true,
+ "cmd/compile/internal/rangefunc": true,
+ "cmd/compile/internal/reflectdata": true,
+ "cmd/compile/internal/riscv64": true,
+ "cmd/compile/internal/rttype": true,
+ "cmd/compile/internal/s390x": true,
+ "cmd/compile/internal/ssa": true,
+ "cmd/compile/internal/ssagen": true,
+ "cmd/compile/internal/staticdata": true,
+ "cmd/compile/internal/staticinit": true,
+ "cmd/compile/internal/syntax": true,
+ "cmd/compile/internal/test": true,
+ "cmd/compile/internal/typebits": true,
+ "cmd/compile/internal/typecheck": true,
+ "cmd/compile/internal/types": true,
+ "cmd/compile/internal/types2": true,
+ "cmd/compile/internal/walk": true,
+ "cmd/compile/internal/wasm": true,
+ "cmd/compile/internal/x86": true,
+ "cmd/internal/archive": true,
+ "cmd/internal/bio": true,
+ "cmd/internal/codesign": true,
+ "cmd/internal/dwarf": true,
+ "cmd/internal/edit": true,
+ "cmd/internal/gcprog": true,
+ "cmd/internal/goobj": true,
+ "cmd/internal/hash": true,
+ "cmd/internal/macho": true,
+ "cmd/internal/obj": true,
+ "cmd/internal/obj/arm": true,
+ "cmd/internal/obj/arm64": true,
+ "cmd/internal/obj/loong64": true,
+ "cmd/internal/obj/mips": true,
+ "cmd/internal/obj/ppc64": true,
+ "cmd/internal/obj/riscv": true,
+ "cmd/internal/obj/s390x": true,
+ "cmd/internal/obj/wasm": true,
+ "cmd/internal/obj/x86": true,
+ "cmd/internal/objabi": true,
+ "cmd/internal/par": true,
+ "cmd/internal/pgo": true,
+ "cmd/internal/pkgpath": true,
+ "cmd/internal/quoted": true,
+ "cmd/internal/src": true,
+ "cmd/internal/sys": true,
+ "cmd/internal/telemetry": true,
+ "cmd/internal/telemetry/counter": true,
+ "cmd/link": true,
+ "cmd/link/internal/amd64": true,
+ "cmd/link/internal/arm": true,
+ "cmd/link/internal/arm64": true,
+ "cmd/link/internal/benchmark": true,
+ "cmd/link/internal/dwtest": true,
+ "cmd/link/internal/ld": true,
+ "cmd/link/internal/loadelf": true,
+ "cmd/link/internal/loader": true,
+ "cmd/link/internal/loadmacho": true,
+ "cmd/link/internal/loadpe": true,
+ "cmd/link/internal/loadxcoff": true,
+ "cmd/link/internal/loong64": true,
+ "cmd/link/internal/mips": true,
+ "cmd/link/internal/mips64": true,
+ "cmd/link/internal/ppc64": true,
+ "cmd/link/internal/riscv64": true,
+ "cmd/link/internal/s390x": true,
+ "cmd/link/internal/sym": true,
+ "cmd/link/internal/wasm": true,
+ "cmd/link/internal/x86": true,
+ "compress/flate": true,
+ "compress/zlib": true,
+ "container/heap": true,
+ "debug/dwarf": true,
+ "debug/elf": true,
+ "debug/macho": true,
+ "debug/pe": true,
+ "go/build/constraint": true,
+ "go/constant": true,
+ "go/version": true,
+ "internal/abi": true,
+ "internal/coverage": true,
+ "cmd/internal/cov/covcmd": true,
+ "internal/bisect": true,
+ "internal/buildcfg": true,
+ "internal/exportdata": true,
+ "internal/goarch": true,
+ "internal/godebugs": true,
+ "internal/goexperiment": true,
+ "internal/goroot": true,
+ "internal/gover": true,
+ "internal/goversion": true,
+ "internal/lazyregexp": true,
+ "internal/pkgbits": true,
+ "internal/platform": true,
+ "internal/profile": true,
+ "internal/race": true,
+ "internal/runtime/gc": true,
+ "internal/saferio": true,
+ "internal/syscall/unix": true,
+ "internal/types/errors": true,
+ "internal/unsafeheader": true,
+ "internal/xcoff": true,
+ "internal/zstd": true,
+ "math/bits": true,
+ "sort": true,
+}
+
+// BootstrapVersion is the minor version of Go used during toolchain
+// bootstrapping. Packages for which [IsBootstrapPackage] must not use
+// features of Go newer than this version.
+const BootstrapVersion = Version(24) // go1.24.6
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/stdlib/import.go b/src/cmd/vendor/golang.org/x/tools/internal/stdlib/import.go
index f6909878a8..8ecc672b8b 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/stdlib/import.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/stdlib/import.go
@@ -87,3 +87,11 @@ func find(pkg string) (int, bool) {
return strings.Compare(p.name, n)
})
}
+
+// IsBootstrapPackage reports whether pkg is one of the low-level
+// packages in the Go distribution that must compile with the older
+// language version specified by [BootstrapVersion] during toolchain
+// bootstrapping; see golang.org/s/go15bootstrap.
+func IsBootstrapPackage(pkg string) bool {
+ return bootstrap[pkg]
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go b/src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go
index c1faa50d36..362f23c436 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go
@@ -225,6 +225,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*Buffer).Grow", Method, 1, ""},
{"(*Buffer).Len", Method, 0, ""},
{"(*Buffer).Next", Method, 0, ""},
+ {"(*Buffer).Peek", Method, 26, ""},
{"(*Buffer).Read", Method, 0, ""},
{"(*Buffer).ReadByte", Method, 0, ""},
{"(*Buffer).ReadBytes", Method, 0, ""},
@@ -1628,6 +1629,7 @@ var PackageSymbols = map[string][]Symbol{
{"ResultNoRows", Var, 0, ""},
{"Rows", Type, 0, ""},
{"RowsAffected", Type, 0, ""},
+ {"RowsColumnScanner", Type, 26, ""},
{"RowsColumnTypeDatabaseTypeName", Type, 8, ""},
{"RowsColumnTypeLength", Type, 8, ""},
{"RowsColumnTypeNullable", Type, 8, ""},
@@ -4953,6 +4955,7 @@ var PackageSymbols = map[string][]Symbol{
},
"errors": {
{"As", Func, 13, "func(err error, target any) bool"},
+ {"AsType", Func, 26, "func[E error](err error) (E, bool)"},
{"ErrUnsupported", Var, 21, ""},
{"Is", Func, 13, "func(err error, target error) bool"},
{"Join", Func, 20, "func(errs ...error) error"},
@@ -5090,7 +5093,7 @@ var PackageSymbols = map[string][]Symbol{
{"Append", Func, 19, "func(b []byte, a ...any) []byte"},
{"Appendf", Func, 19, "func(b []byte, format string, a ...any) []byte"},
{"Appendln", Func, 19, "func(b []byte, a ...any) []byte"},
- {"Errorf", Func, 0, "func(format string, a ...any) error"},
+ {"Errorf", Func, 0, "func(format string, a ...any) (err error)"},
{"FormatString", Func, 20, "func(state State, verb rune) string"},
{"Formatter", Type, 0, ""},
{"Fprint", Func, 0, "func(w io.Writer, a ...any) (n int, err error)"},
@@ -5155,6 +5158,9 @@ var PackageSymbols = map[string][]Symbol{
{"(*DeclStmt).Pos", Method, 0, ""},
{"(*DeferStmt).End", Method, 0, ""},
{"(*DeferStmt).Pos", Method, 0, ""},
+ {"(*Directive).End", Method, 26, ""},
+ {"(*Directive).ParseArgs", Method, 26, ""},
+ {"(*Directive).Pos", Method, 26, ""},
{"(*Ellipsis).End", Method, 0, ""},
{"(*Ellipsis).Pos", Method, 0, ""},
{"(*EmptyStmt).End", Method, 0, ""},
@@ -5320,6 +5326,15 @@ var PackageSymbols = map[string][]Symbol{
{"DeferStmt", Type, 0, ""},
{"DeferStmt.Call", Field, 0, ""},
{"DeferStmt.Defer", Field, 0, ""},
+ {"Directive", Type, 26, ""},
+ {"Directive.Args", Field, 26, ""},
+ {"Directive.ArgsPos", Field, 26, ""},
+ {"Directive.Name", Field, 26, ""},
+ {"Directive.Slash", Field, 26, ""},
+ {"Directive.Tool", Field, 26, ""},
+ {"DirectiveArg", Type, 26, ""},
+ {"DirectiveArg.Arg", Field, 26, ""},
+ {"DirectiveArg.Pos", Field, 26, ""},
{"Ellipsis", Type, 0, ""},
{"Ellipsis.Ellipsis", Field, 0, ""},
{"Ellipsis.Elt", Field, 0, ""},
@@ -5469,6 +5484,7 @@ var PackageSymbols = map[string][]Symbol{
{"ParenExpr.Lparen", Field, 0, ""},
{"ParenExpr.Rparen", Field, 0, ""},
{"ParenExpr.X", Field, 0, ""},
+ {"ParseDirective", Func, 26, "func(pos token.Pos, c string) (Directive, bool)"},
{"Pkg", Const, 0, ""},
{"Preorder", Func, 23, "func(root Node) iter.Seq[Node]"},
{"PreorderStack", Func, 25, "func(root Node, stack []Node, f func(n Node, stack []Node) bool)"},
@@ -7271,6 +7287,10 @@ var PackageSymbols = map[string][]Symbol{
{"(*Logger).WarnContext", Method, 21, ""},
{"(*Logger).With", Method, 21, ""},
{"(*Logger).WithGroup", Method, 21, ""},
+ {"(*MultiHandler).Enabled", Method, 26, ""},
+ {"(*MultiHandler).Handle", Method, 26, ""},
+ {"(*MultiHandler).WithAttrs", Method, 26, ""},
+ {"(*MultiHandler).WithGroup", Method, 26, ""},
{"(*Record).Add", Method, 21, ""},
{"(*Record).AddAttrs", Method, 21, ""},
{"(*TextHandler).Enabled", Method, 21, ""},
@@ -7358,9 +7378,11 @@ var PackageSymbols = map[string][]Symbol{
{"LogValuer", Type, 21, ""},
{"Logger", Type, 21, ""},
{"MessageKey", Const, 21, ""},
+ {"MultiHandler", Type, 26, ""},
{"New", Func, 21, "func(h Handler) *Logger"},
{"NewJSONHandler", Func, 21, "func(w io.Writer, opts *HandlerOptions) *JSONHandler"},
{"NewLogLogger", Func, 21, "func(h Handler, level Level) *log.Logger"},
+ {"NewMultiHandler", Func, 26, "func(handlers ...Handler) *MultiHandler"},
{"NewRecord", Func, 21, "func(t time.Time, level Level, msg string, pc uintptr) Record"},
{"NewTextHandler", Func, 21, "func(w io.Writer, opts *HandlerOptions) *TextHandler"},
{"Record", Type, 21, ""},
@@ -7515,7 +7537,7 @@ var PackageSymbols = map[string][]Symbol{
{"MinInt64", Const, 0, ""},
{"MinInt8", Const, 0, ""},
{"Mod", Func, 0, "func(x float64, y float64) float64"},
- {"Modf", Func, 0, "func(f float64) (int float64, frac float64)"},
+ {"Modf", Func, 0, "func(f float64) (integer float64, fractional float64)"},
{"NaN", Func, 0, "func() float64"},
{"Nextafter", Func, 0, "func(x float64, y float64) (r float64)"},
{"Nextafter32", Func, 4, "func(x float32, y float32) (r float32)"},
@@ -7972,6 +7994,10 @@ var PackageSymbols = map[string][]Symbol{
{"(*DNSError).Unwrap", Method, 23, ""},
{"(*Dialer).Dial", Method, 1, ""},
{"(*Dialer).DialContext", Method, 7, ""},
+ {"(*Dialer).DialIP", Method, 26, ""},
+ {"(*Dialer).DialTCP", Method, 26, ""},
+ {"(*Dialer).DialUDP", Method, 26, ""},
+ {"(*Dialer).DialUnix", Method, 26, ""},
{"(*Dialer).MultipathTCP", Method, 21, ""},
{"(*Dialer).SetMultipathTCP", Method, 21, ""},
{"(*IP).UnmarshalText", Method, 2, ""},
@@ -8457,6 +8483,7 @@ var PackageSymbols = map[string][]Symbol{
{"HTTP2Config.PermitProhibitedCipherSuites", Field, 24, ""},
{"HTTP2Config.PingTimeout", Field, 24, ""},
{"HTTP2Config.SendPingTimeout", Field, 24, ""},
+ {"HTTP2Config.StrictMaxConcurrentRequests", Field, 26, ""},
{"HTTP2Config.WriteByteTimeout", Field, 24, ""},
{"Handle", Func, 0, "func(pattern string, handler Handler)"},
{"HandleFunc", Func, 0, "func(pattern string, handler func(ResponseWriter, *Request))"},
@@ -8904,6 +8931,7 @@ var PackageSymbols = map[string][]Symbol{
{"(Prefix).AppendText", Method, 24, ""},
{"(Prefix).AppendTo", Method, 18, ""},
{"(Prefix).Bits", Method, 18, ""},
+ {"(Prefix).Compare", Method, 26, ""},
{"(Prefix).Contains", Method, 18, ""},
{"(Prefix).IsSingleIP", Method, 18, ""},
{"(Prefix).IsValid", Method, 18, ""},
@@ -9177,6 +9205,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*Process).Release", Method, 0, ""},
{"(*Process).Signal", Method, 0, ""},
{"(*Process).Wait", Method, 0, ""},
+ {"(*Process).WithHandle", Method, 26, ""},
{"(*ProcessState).ExitCode", Method, 12, ""},
{"(*ProcessState).Exited", Method, 0, ""},
{"(*ProcessState).Pid", Method, 0, ""},
@@ -9234,6 +9263,7 @@ var PackageSymbols = map[string][]Symbol{
{"ErrExist", Var, 0, ""},
{"ErrInvalid", Var, 0, ""},
{"ErrNoDeadline", Var, 10, ""},
+ {"ErrNoHandle", Var, 26, ""},
{"ErrNotExist", Var, 0, ""},
{"ErrPermission", Var, 0, ""},
{"ErrProcessDone", Var, 16, ""},
@@ -9461,7 +9491,7 @@ var PackageSymbols = map[string][]Symbol{
{"ListSeparator", Const, 0, ""},
{"Localize", Func, 23, "func(path string) (string, error)"},
{"Match", Func, 0, "func(pattern string, name string) (matched bool, err error)"},
- {"Rel", Func, 0, "func(basepath string, targpath string) (string, error)"},
+ {"Rel", Func, 0, "func(basePath string, targPath string) (string, error)"},
{"Separator", Const, 0, ""},
{"SkipAll", Var, 20, ""},
{"SkipDir", Var, 0, ""},
@@ -9932,7 +9962,7 @@ var PackageSymbols = map[string][]Symbol{
{"PanicNilError", Type, 21, ""},
{"Pinner", Type, 21, ""},
{"ReadMemStats", Func, 0, "func(m *MemStats)"},
- {"ReadTrace", Func, 5, "func() []byte"},
+ {"ReadTrace", Func, 5, "func() (buf []byte)"},
{"SetBlockProfileRate", Func, 1, "func(rate int)"},
{"SetCPUProfileRate", Func, 0, "func(hz int)"},
{"SetCgoTraceback", Func, 7, "func(version int, traceback unsafe.Pointer, context unsafe.Pointer, symbolizer unsafe.Pointer)"},
@@ -16679,6 +16709,7 @@ var PackageSymbols = map[string][]Symbol{
{"ValueOf", Func, 0, ""},
},
"testing": {
+ {"(*B).ArtifactDir", Method, 26, ""},
{"(*B).Attr", Method, 25, ""},
{"(*B).Chdir", Method, 24, ""},
{"(*B).Cleanup", Method, 14, ""},
@@ -16713,6 +16744,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*B).StopTimer", Method, 0, ""},
{"(*B).TempDir", Method, 15, ""},
{"(*F).Add", Method, 18, ""},
+ {"(*F).ArtifactDir", Method, 26, ""},
{"(*F).Attr", Method, 25, ""},
{"(*F).Chdir", Method, 24, ""},
{"(*F).Cleanup", Method, 18, ""},
@@ -16738,6 +16770,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*F).TempDir", Method, 18, ""},
{"(*M).Run", Method, 4, ""},
{"(*PB).Next", Method, 3, ""},
+ {"(*T).ArtifactDir", Method, 26, ""},
{"(*T).Attr", Method, 25, ""},
{"(*T).Chdir", Method, 24, ""},
{"(*T).Cleanup", Method, 14, ""},
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/normalize.go
index f49802b8ef..8d13f12147 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/normalize.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/normalize.go
@@ -160,8 +160,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
// The term set of an interface is the intersection of the term sets of its
// embedded types.
tset.terms = allTermlist
- for i := 0; i < u.NumEmbeddeds(); i++ {
- embedded := u.EmbeddedType(i)
+ for embedded := range u.EmbeddedTypes() {
if _, ok := embedded.Underlying().(*types.TypeParam); ok {
return nil, fmt.Errorf("invalid embedded type %T", embedded)
}
@@ -174,8 +173,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
case *types.Union:
// The term set of a union is the union of term sets of its terms.
tset.terms = nil
- for i := 0; i < u.Len(); i++ {
- t := u.Term(i)
+ for t := range u.Terms() {
var terms termlist
switch t.Type().Underlying().(type) {
case *types.Interface:
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/element.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/element.go
index 4957f02164..5fe4d8abcb 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/element.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/element.go
@@ -35,8 +35,8 @@ func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T type
// Recursion over signatures of each method.
tmset := msets.MethodSet(T)
- for i := 0; i < tmset.Len(); i++ {
- sig := tmset.At(i).Type().(*types.Signature)
+ for method := range tmset.Methods() {
+ sig := method.Type().(*types.Signature)
// It is tempting to call visit(sig, false)
// but, as noted in golang.org/cl/65450043,
// the Signature.Recv field is ignored by
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/isnamed.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/isnamed.go
index f2affec4fb..e0d63c46c6 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/isnamed.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/isnamed.go
@@ -48,7 +48,7 @@ func IsFunctionNamed(obj types.Object, pkgPath string, names ...string) bool {
return ok &&
IsPackageLevel(obj) &&
f.Pkg().Path() == pkgPath &&
- f.Type().(*types.Signature).Recv() == nil &&
+ f.Signature().Recv() == nil &&
slices.Contains(names, f.Name())
}
@@ -60,7 +60,7 @@ func IsFunctionNamed(obj types.Object, pkgPath string, names ...string) bool {
// which is important for the performance of syntax matching.
func IsMethodNamed(obj types.Object, pkgPath string, typeName string, names ...string) bool {
if fn, ok := obj.(*types.Func); ok {
- if recv := fn.Type().(*types.Signature).Recv(); recv != nil {
+ if recv := fn.Signature().Recv(); recv != nil {
_, T := ReceiverNamed(recv)
return T != nil &&
IsTypeNamed(T, pkgPath, typeName) &&
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go
index 64f47919f0..4e2756fc49 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go
@@ -19,7 +19,7 @@ import (
// TODO(adonovan): this function ignores the effect of shadowing. It
// should accept a [token.Pos] and a [types.Info] and compute only the
// set of imports that are not shadowed at that point, analogous to
-// [analysisinternal.AddImport]. It could also compute (as a side
+// [analysis.AddImport]. It could also compute (as a side
// effect) the set of additional imports required to ensure that there
// is an accessible import for each necessary package, making it
// converge even more closely with AddImport.
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
index 453bba2ad5..d612a71029 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
@@ -258,12 +258,12 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
case *types.Signature:
var params []*ast.Field
- for i := 0; i < t.Params().Len(); i++ {
+ for v := range t.Params().Variables() {
params = append(params, &ast.Field{
- Type: TypeExpr(t.Params().At(i).Type(), qual),
+ Type: TypeExpr(v.Type(), qual),
Names: []*ast.Ident{
{
- Name: t.Params().At(i).Name(),
+ Name: v.Name(),
},
},
})
@@ -273,9 +273,9 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
last.Type = &ast.Ellipsis{Elt: last.Type.(*ast.ArrayType).Elt}
}
var returns []*ast.Field
- for i := 0; i < t.Results().Len(); i++ {
+ for v := range t.Results().Variables() {
returns = append(returns, &ast.Field{
- Type: TypeExpr(t.Results().At(i).Type(), qual),
+ Type: TypeExpr(v.Type(), qual),
})
}
return &ast.FuncType{
@@ -315,8 +315,8 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
if hasTypeArgs, ok := t.(interface{ TypeArgs() *types.TypeList }); ok {
if typeArgs := hasTypeArgs.TypeArgs(); typeArgs != nil && typeArgs.Len() > 0 {
var indices []ast.Expr
- for i := range typeArgs.Len() {
- indices = append(indices, TypeExpr(typeArgs.At(i), qual))
+ for t0 := range typeArgs.Types() {
+ indices = append(indices, TypeExpr(t0, qual))
}
expr = &ast.IndexListExpr{
X: expr,
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/versions/features.go b/src/cmd/vendor/golang.org/x/tools/internal/versions/features.go
index b53f178616..a5f4e3252c 100644
--- a/src/cmd/vendor/golang.org/x/tools/internal/versions/features.go
+++ b/src/cmd/vendor/golang.org/x/tools/internal/versions/features.go
@@ -7,13 +7,17 @@ package versions
// This file contains predicates for working with file versions to
// decide when a tool should consider a language feature enabled.
-// GoVersions that features in x/tools can be gated to.
+// named constants, to avoid misspelling
const (
Go1_18 = "go1.18"
Go1_19 = "go1.19"
Go1_20 = "go1.20"
Go1_21 = "go1.21"
Go1_22 = "go1.22"
+ Go1_23 = "go1.23"
+ Go1_24 = "go1.24"
+ Go1_25 = "go1.25"
+ Go1_26 = "go1.26"
)
// Future is an invalid unknown Go version sometime in the future.
diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt
index e92804a90d..80b23723bc 100644
--- a/src/cmd/vendor/modules.txt
+++ b/src/cmd/vendor/modules.txt
@@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm
# golang.org/x/build v0.0.0-20250806225920-b7c66c047964
## explicit; go 1.23.0
golang.org/x/build/relnote
-# golang.org/x/mod v0.29.0
+# golang.org/x/mod v0.30.1-0.20251114215501-3f03020ad526
## explicit; go 1.24.0
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
@@ -39,16 +39,16 @@ 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.17.0
+# golang.org/x/sync v0.18.0
## explicit; go 1.24.0
golang.org/x/sync/errgroup
golang.org/x/sync/semaphore
-# golang.org/x/sys v0.37.0
+# golang.org/x/sys v0.38.0
## explicit; go 1.24.0
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8
+# golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54
## explicit; go 1.24.0
golang.org/x/telemetry
golang.org/x/telemetry/counter
@@ -73,7 +73,7 @@ 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.38.1-0.20251015192825-7d9453ccc0f5
+# golang.org/x/tools v0.39.1-0.20251114194111-59ff18ce4883
## explicit; go 1.24.0
golang.org/x/tools/cmd/bisect
golang.org/x/tools/cover
@@ -98,6 +98,7 @@ golang.org/x/tools/go/analysis/passes/httpresponse
golang.org/x/tools/go/analysis/passes/ifaceassert
golang.org/x/tools/go/analysis/passes/inline
golang.org/x/tools/go/analysis/passes/inspect
+golang.org/x/tools/go/analysis/passes/internal/ctrlflowinternal
golang.org/x/tools/go/analysis/passes/internal/gofixdirective
golang.org/x/tools/go/analysis/passes/loopclosure
golang.org/x/tools/go/analysis/passes/lostcancel
@@ -127,11 +128,13 @@ golang.org/x/tools/go/cfg
golang.org/x/tools/go/types/objectpath
golang.org/x/tools/go/types/typeutil
golang.org/x/tools/internal/aliases
-golang.org/x/tools/internal/analysisinternal
-golang.org/x/tools/internal/analysisinternal/generated
-golang.org/x/tools/internal/analysisinternal/typeindex
+golang.org/x/tools/internal/analysis/analyzerutil
+golang.org/x/tools/internal/analysis/driverutil
+golang.org/x/tools/internal/analysis/typeindex
golang.org/x/tools/internal/astutil
+golang.org/x/tools/internal/astutil/free
golang.org/x/tools/internal/bisect
+golang.org/x/tools/internal/cfginternal
golang.org/x/tools/internal/diff
golang.org/x/tools/internal/diff/lcs
golang.org/x/tools/internal/facts
diff --git a/src/cmd/vet/testdata/print/print.go b/src/cmd/vet/testdata/print/print.go
index 3761da420b..9145c12fb8 100644
--- a/src/cmd/vet/testdata/print/print.go
+++ b/src/cmd/vet/testdata/print/print.go
@@ -75,7 +75,7 @@ func PrintfTests() {
fmt.Printf("%b %b %b %b", 3e9, x, fslice, c)
fmt.Printf("%o %o", 3, i)
fmt.Printf("%p", p)
- fmt.Printf("%q %q %q %q", 3, i, 'x', r)
+ fmt.Printf("%q %q %q", rune(3), 'x', r)
fmt.Printf("%s %s %s", "hi", s, []byte{65})
fmt.Printf("%t %t", true, b)
fmt.Printf("%T %T", 3, i)