From c2dcde178dcaff1c50cc1992eda46995053a8f32 Mon Sep 17 00:00:00 2001 From: Mauri de Souza Meneguzzo Date: Fri, 12 Jun 2026 23:35:09 +0000 Subject: [PATCH 01/16] cmd/compile: add align128 compiler marker for 128-bit struct alignment Add an align128 sentinel type to sync/atomic and internal/runtime/atomic, analogous to align64. Embedding `_ align128` in a struct causes the compiler to enforce 16-byte alignment on the containing struct. This is required for 128-bit atomic operations (CMPXCHG16B on amd64, CASP on arm64), which require a 16-byte-aligned memory operand. A struct containing two uint64 fields has natural alignment of 8 bytes, so it may otherwise be placed at a non-16-byte-aligned offset within a larger struct, causing faults or incorrect behavior. No test: align128 is unexported in sync/atomic, and testing it in internal would create cyclic dependencies with reflect. For #61236. Change-Id: Iab0502776141aed309457b462f2fdb60ec0d5245 GitHub-Last-Rev: 8cf379404d04c1fbe2b011975d5932eb9d9225da GitHub-Pull-Request: golang/go#79991 Reviewed-on: https://go-review.googlesource.com/c/go/+/790320 Reviewed-by: Robert Griesemer LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Keith Randall Reviewed-by: Dmitri Shuralyov --- src/cmd/compile/internal/types/size.go | 5 ++++- src/cmd/compile/internal/types2/gcsizes.go | 10 +++++++++ src/cmd/compile/internal/types2/sizes.go | 26 ++++++++++++++++++++-- src/go/types/gcsizes.go | 10 +++++++++ src/go/types/generate_test.go | 4 ++-- src/go/types/sizes.go | 26 ++++++++++++++++++++-- src/internal/runtime/atomic/types.go | 5 +++++ src/sync/atomic/type.go | 5 +++++ 8 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index c52ce6e8c4170d..d30a29e564ae0c 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -68,7 +68,7 @@ var defercalc int // RoundUp rounds o to a multiple of r, r is a power of 2. func RoundUp(o int64, r int64) int64 { - if r < 1 || r > 8 || r&(r-1) != 0 { + if r < 1 || r > 16 || r&(r-1) != 0 { base.Fatalf("Round %d", r) } return (o + r - 1) &^ (r - 1) @@ -492,6 +492,9 @@ func CalcStructSize(t *Type) { case sym.Name == "align64" && isAtomicStdPkg(sym.Pkg): maxAlign = 8 + case sym.Name == "align128" && isAtomicStdPkg(sym.Pkg): + maxAlign = 16 + case buildcfg.Experiment.SIMD && (sym.Pkg.Path == "simd/archsimd") && len(t.Fields()) >= 1: // This gates the experiment -- without it, no user-visible types can be "simd". // The SSA-visible SIMD types remain. diff --git a/src/cmd/compile/internal/types2/gcsizes.go b/src/cmd/compile/internal/types2/gcsizes.go index 54e8ea23c173c5..41fc5e936c659b 100644 --- a/src/cmd/compile/internal/types2/gcsizes.go +++ b/src/cmd/compile/internal/types2/gcsizes.go @@ -32,6 +32,16 @@ func (s *gcSizes) Alignof(T Type) (result int64) { // cmd/compile/internal/types/size.go:calcStructOffset return 8 } + if len(t.fields) == 0 && IsSyncAtomicAlign128(T) { + // Special case: sync/atomic.align128 is an + // empty struct we recognize as a signal that + // the struct it contains must be + // 128-bit-aligned. + // + // This logic is equivalent to the logic in + // cmd/compile/internal/types/size.go:calcStructOffset + return 16 + } // spec: "For a variable x of struct type: unsafe.Alignof(x) // is the largest of the values unsafe.Alignof(x.f) for each diff --git a/src/cmd/compile/internal/types2/sizes.go b/src/cmd/compile/internal/types2/sizes.go index 534ecfba35ced7..215e5d5fef3ce7 100644 --- a/src/cmd/compile/internal/types2/sizes.go +++ b/src/cmd/compile/internal/types2/sizes.go @@ -70,6 +70,16 @@ func (s *StdSizes) Alignof(T Type) (result int64) { // cmd/compile/internal/types/size.go:calcStructOffset return 8 } + if len(t.fields) == 0 && IsSyncAtomicAlign128(T) { + // Special case: sync/atomic.align128 is an + // empty struct we recognize as a signal that + // the struct it contains must be + // 128-bit-aligned. + // + // This logic is equivalent to the logic in + // cmd/compile/internal/types/size.go:calcStructOffset + return 16 + } // spec: "For a variable x of struct type: unsafe.Alignof(x) // is the largest of the values unsafe.Alignof(x.f) for each @@ -123,6 +133,18 @@ func IsSyncAtomicAlign64(T Type) bool { obj.Pkg().Path() == "internal/runtime/atomic") } +func IsSyncAtomicAlign128(T Type) bool { + named := asNamed(T) + if named == nil { + return false + } + obj := named.Obj() + return obj.Name() == "align128" && + obj.Pkg() != nil && + (obj.Pkg().Path() == "sync/atomic" || + obj.Pkg().Path() == "internal/runtime/atomic") +} + func (s *StdSizes) Offsetsof(fields []*Var) []int64 { offsets := make([]int64, len(fields)) var offs int64 @@ -332,9 +354,9 @@ func (conf *Config) sizeof(T Type) int64 { } // align returns the smallest y >= x such that y % a == 0. -// a must be within 1 and 8 and it must be a power of 2. +// a must be within 1 and 16 and it must be a power of 2. // The result may be negative due to overflow. func align(x, a int64) int64 { - assert(x >= 0 && 1 <= a && a <= 8 && a&(a-1) == 0) + assert(x >= 0 && 1 <= a && a <= 16 && a&(a-1) == 0) return (x + a - 1) &^ (a - 1) } diff --git a/src/go/types/gcsizes.go b/src/go/types/gcsizes.go index adc350a6c2d001..d181e41707133f 100644 --- a/src/go/types/gcsizes.go +++ b/src/go/types/gcsizes.go @@ -35,6 +35,16 @@ func (s *gcSizes) Alignof(T Type) (result int64) { // cmd/compile/internal/types/size.go:calcStructOffset return 8 } + if len(t.fields) == 0 && _IsSyncAtomicAlign128(T) { + // Special case: sync/atomic.align128 is an + // empty struct we recognize as a signal that + // the struct it contains must be + // 128-bit-aligned. + // + // This logic is equivalent to the logic in + // cmd/compile/internal/types/size.go:calcStructOffset + return 16 + } // spec: "For a variable x of struct type: unsafe.Alignof(x) // is the largest of the values unsafe.Alignof(x.f) for each diff --git a/src/go/types/generate_test.go b/src/go/types/generate_test.go index d1ffd99a85152d..7a4e053b7b01fb 100644 --- a/src/go/types/generate_test.go +++ b/src/go/types/generate_test.go @@ -138,7 +138,7 @@ var filemap = map[string]action{ "errors_test.go": func(f *ast.File) { renameIdents(f, "nopos->noposn") }, "errsupport.go": nil, "gccgosizes.go": nil, - "gcsizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") }, + "gcsizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64", "IsSyncAtomicAlign128->_IsSyncAtomicAlign128") }, "hilbert_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`) }, "infer.go": func(f *ast.File) { fixTokenPos(f); fixInferSig(f) }, "initorder.go": nil, @@ -193,7 +193,7 @@ var filemap = map[string]action{ }, "scope.go": func(f *ast.File) { fixTokenPos(f); renameIdents(f, "InsertLazy->_InsertLazy") }, "selection.go": nil, - "sizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") }, + "sizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64", "IsSyncAtomicAlign128->_IsSyncAtomicAlign128") }, "slice.go": nil, "subst.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") }, "termlist.go": nil, diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go index e2ff047bc859c3..abe3f129259d0d 100644 --- a/src/go/types/sizes.go +++ b/src/go/types/sizes.go @@ -73,6 +73,16 @@ func (s *StdSizes) Alignof(T Type) (result int64) { // cmd/compile/internal/types/size.go:calcStructOffset return 8 } + if len(t.fields) == 0 && _IsSyncAtomicAlign128(T) { + // Special case: sync/atomic.align128 is an + // empty struct we recognize as a signal that + // the struct it contains must be + // 128-bit-aligned. + // + // This logic is equivalent to the logic in + // cmd/compile/internal/types/size.go:calcStructOffset + return 16 + } // spec: "For a variable x of struct type: unsafe.Alignof(x) // is the largest of the values unsafe.Alignof(x.f) for each @@ -126,6 +136,18 @@ func _IsSyncAtomicAlign64(T Type) bool { obj.Pkg().Path() == "internal/runtime/atomic") } +func _IsSyncAtomicAlign128(T Type) bool { + named := asNamed(T) + if named == nil { + return false + } + obj := named.Obj() + return obj.Name() == "align128" && + obj.Pkg() != nil && + (obj.Pkg().Path() == "sync/atomic" || + obj.Pkg().Path() == "internal/runtime/atomic") +} + func (s *StdSizes) Offsetsof(fields []*Var) []int64 { offsets := make([]int64, len(fields)) var offs int64 @@ -335,9 +357,9 @@ func (conf *Config) sizeof(T Type) int64 { } // align returns the smallest y >= x such that y % a == 0. -// a must be within 1 and 8 and it must be a power of 2. +// a must be within 1 and 16 and it must be a power of 2. // The result may be negative due to overflow. func align(x, a int64) int64 { - assert(x >= 0 && 1 <= a && a <= 8 && a&(a-1) == 0) + assert(x >= 0 && 1 <= a && a <= 16 && a&(a-1) == 0) return (x + a - 1) &^ (a - 1) } diff --git a/src/internal/runtime/atomic/types.go b/src/internal/runtime/atomic/types.go index 287742fee5ce50..4832fd8f4285fc 100644 --- a/src/internal/runtime/atomic/types.go +++ b/src/internal/runtime/atomic/types.go @@ -585,3 +585,8 @@ func (*noCopy) Unlock() {} // This struct is recognized by a special case in the compiler // and will not work if copied to any other package. type align64 struct{} + +// align128 may be added to structs that must be 128-bit aligned. +// This struct is recognized by a special case in the compiler +// and will not work if copied to any other package. +type align128 struct{} diff --git a/src/sync/atomic/type.go b/src/sync/atomic/type.go index 4a74150b41bace..5088d44b89e3f2 100644 --- a/src/sync/atomic/type.go +++ b/src/sync/atomic/type.go @@ -252,3 +252,8 @@ func (*noCopy) Unlock() {} // This struct is recognized by a special case in the compiler // and will not work if copied to any other package. type align64 struct{} + +// align128 may be added to structs that must be 128-bit aligned. +// This struct is recognized by a special case in the compiler +// and will not work if copied to any other package. +type align128 struct{} From fb355d8a3c2fd04fc84841b121f3266b36b864bf Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Tue, 14 Jul 2026 13:45:06 -0400 Subject: [PATCH 02/16] cmd/compile: rewrite x*y-z to fused multiply subtract for GOAMD64=v3 This is done similarly to in CL 646335. Fixes #80278 Change-Id: Idc0abb682797b9f4e23842b332428a486a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/799984 Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Michael Matloob Reviewed-by: Jorropo LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/cmd/compile/internal/amd64/ssa.go | 2 +- src/cmd/compile/internal/ssa/_gen/AMD64.rules | 1 + src/cmd/compile/internal/ssa/_gen/AMD64Ops.go | 3 ++ src/cmd/compile/internal/ssa/opGen.go | 34 +++++++++++++++++++ src/cmd/compile/internal/ssa/rewriteAMD64.go | 34 +++++++++++++++++++ test/codegen/floats.go | 2 ++ 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 4dadede1b1c72e..0c2890a7cfb0c2 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -226,7 +226,7 @@ func getgFromTLS(s *ssagen.State, r int16) { func ssaGenValue(s *ssagen.State, v *ssa.Value) { switch v.Op { - case ssa.OpAMD64VFMADD231SD, ssa.OpAMD64VFMADD231SS: + case ssa.OpAMD64VFMADD231SD, ssa.OpAMD64VFMADD231SS, ssa.OpAMD64VFMSUB231SD, ssa.OpAMD64VFMSUB231SS: p := s.Prog(v.Op.Asm()) p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[2].Reg()} p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()} diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index bb6732d57dfcf3..2dd2816f9b4bf4 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -1502,6 +1502,7 @@ // Detect FMA (ADDS(S|D) (MULS(S|D) x y) z) && buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v) => (VFMADD231S(S|D) z x y) +(SUBS(S|D) (MULS(S|D) x y) z) && buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v) => (VFMSUB231S(S|D) z x y) // Redirect stores to use the other register set. (MOVQstore [off] {sym} ptr (MOVQf2i val) mem) => (MOVSDstore [off] {sym} ptr val mem) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go index 14882015053700..9951089d72febe 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go @@ -808,6 +808,9 @@ func init() { // arg0 + arg1*arg2, with no intermediate rounding. {name: "VFMADD231SS", argLength: 3, reg: fp31, resultInArg0: true, asm: "VFMADD231SS"}, {name: "VFMADD231SD", argLength: 3, reg: fp31, resultInArg0: true, asm: "VFMADD231SD"}, + // arg1*arg2 - arg0, with no intermediate rounding. + {name: "VFMSUB231SS", argLength: 3, reg: fp31, resultInArg0: true, asm: "VFMSUB231SS"}, + {name: "VFMSUB231SD", argLength: 3, reg: fp31, resultInArg0: true, asm: "VFMSUB231SD"}, // Note that these operations don't exactly match the semantics of Go's // builtin min. In particular, these aren't commutative, because on various diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index f79a83c13ca6d1..3b61b6e5809880 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -933,6 +933,8 @@ const ( OpAMD64LoweredRound64F OpAMD64VFMADD231SS OpAMD64VFMADD231SD + OpAMD64VFMSUB231SS + OpAMD64VFMSUB231SD OpAMD64MINSD OpAMD64MINSS OpAMD64SBBQcarrymask @@ -17799,6 +17801,38 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "VFMSUB231SS", + argLen: 3, + resultInArg0: true, + asm: x86.AVFMSUB231SS, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + {1, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + {2, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + outputs: []outputInfo{ + {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + }, + }, + { + name: "VFMSUB231SD", + argLen: 3, + resultInArg0: true, + asm: x86.AVFMSUB231SD, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + {1, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + {2, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + outputs: []outputInfo{ + {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + }, + }, { name: "MINSD", argLen: 2, diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 303db4728f8c12..b92489ee4ed9a1 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -40666,6 +40666,23 @@ func rewriteValueAMD64_OpAMD64SUBSD(v *Value) bool { v.AddArg3(x, ptr, mem) return true } + // match: (SUBSD (MULSD x y) z) + // cond: buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v) + // result: (VFMSUB231SD z x y) + for { + if v_0.Op != OpAMD64MULSD { + break + } + y := v_0.Args[1] + x := v_0.Args[0] + z := v_1 + if !(buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v)) { + break + } + v.reset(OpAMD64VFMSUB231SD) + v.AddArg3(z, x, y) + return true + } return false } func rewriteValueAMD64_OpAMD64SUBSDload(v *Value) bool { @@ -40766,6 +40783,23 @@ func rewriteValueAMD64_OpAMD64SUBSS(v *Value) bool { v.AddArg3(x, ptr, mem) return true } + // match: (SUBSS (MULSS x y) z) + // cond: buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v) + // result: (VFMSUB231SS z x y) + for { + if v_0.Op != OpAMD64MULSS { + break + } + y := v_0.Args[1] + x := v_0.Args[0] + z := v_1 + if !(buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v)) { + break + } + v.reset(OpAMD64VFMSUB231SS) + v.AddArg3(z, x, y) + return true + } return false } func rewriteValueAMD64_OpAMD64SUBSSload(v *Value) bool { diff --git a/test/codegen/floats.go b/test/codegen/floats.go index 09ef4276ab07e4..29d85421b43171 100644 --- a/test/codegen/floats.go +++ b/test/codegen/floats.go @@ -89,6 +89,7 @@ func FusedSub32_a(x, y, z float32) float32 { // ppc64x:"FMSUBS " // riscv64:"FMSUBS " // loong64:"FMSUBF " + // amd64/v3:"VFMSUB231SS " return x*y - z } @@ -114,6 +115,7 @@ func FusedSub64_a(x, y, z float64) float64 { // ppc64x:"FMSUB " // riscv64:"FMSUBD " // loong64:"FMSUBD " + // amd64/v3:"VFMSUB231SD " return x*y - z } From ce608609c113e602ceda1eb7e091bf1488daf762 Mon Sep 17 00:00:00 2001 From: Mauri de Souza Meneguzzo Date: Thu, 16 Jul 2026 13:47:42 +0000 Subject: [PATCH 03/16] internal/bytealg: use NEON for compare_arm64.s large-input path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the scalar chunk loop with a 64-byte/iter NEON loop. For inputs >= 64 bytes, each iteration loads and compares 64 bytes from both sides using NEON. The compare results are reduced to a single byte; zero indicates a mismatch. On mismatch, both pointers are rewound by 64 bytes and the existing scalar chunk16 path locates the first differing byte pair and produces the lexicographic result. This fallback is taken at most once. Inputs < 64 bytes continue to use the existing scalar chunk16 and tail paths unchanged. This brings the overall structure closer to equal_arm64.s. goos: darwin goarch: arm64 pkg: bytes cpu: Apple M3 Pro │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ CompareBytesBigUnaligned/offset=1-11 26.55µ ± 1% 19.21µ ± 1% -27.63% (p=0.000 n=10) CompareBytesBigUnaligned/offset=2-11 26.83µ ± 3% 19.11µ ± 1% -28.78% (p=0.000 n=10) CompareBytesBigUnaligned/offset=3-11 26.59µ ± 1% 19.28µ ± 2% -27.50% (p=0.000 n=10) CompareBytesBigUnaligned/offset=4-11 26.49µ ± 1% 19.11µ ± 1% -27.84% (p=0.000 n=10) CompareBytesBigUnaligned/offset=5-11 27.04µ ± 3% 19.05µ ± 1% -29.54% (p=0.000 n=10) CompareBytesBigUnaligned/offset=6-11 27.12µ ± 1% 18.92µ ± 1% -30.24% (p=0.000 n=10) CompareBytesBigUnaligned/offset=7-11 27.00µ ± 0% 18.90µ ± 0% -30.01% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=0-11 26.56µ ± 1% 18.01µ ± 1% -32.20% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=1-11 27.27µ ± 1% 19.43µ ± 0% -28.77% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=2-11 26.83µ ± 2% 18.68µ ± 1% -30.38% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=3-11 27.24µ ± 0% 19.45µ ± 0% -28.62% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=4-11 27.07µ ± 1% 18.67µ ± 1% -31.03% (p=0.000 n=7+10) geomean 26.88µ 10.82µ -29.39% │ old.txt │ new.txt │ │ B/s │ B/s vs base │ CompareBytesBigUnaligned/offset=1-11 36.78Gi ± 1% 50.82Gi ± 1% +38.18% (p=0.000 n=10) CompareBytesBigUnaligned/offset=2-11 36.40Gi ± 3% 51.11Gi ± 1% +40.41% (p=0.000 n=10) CompareBytesBigUnaligned/offset=3-11 36.73Gi ± 1% 50.66Gi ± 2% +37.93% (p=0.000 n=10) CompareBytesBigUnaligned/offset=4-11 36.87Gi ± 1% 51.09Gi ± 1% +38.59% (p=0.000 n=10) CompareBytesBigUnaligned/offset=5-11 36.12Gi ± 3% 51.27Gi ± 1% +41.92% (p=0.000 n=10) CompareBytesBigUnaligned/offset=6-11 36.00Gi ± 1% 51.61Gi ± 1% +43.35% (p=0.000 n=10) CompareBytesBigUnaligned/offset=7-11 36.17Gi ± 0% 51.68Gi ± 0% +42.88% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=0-11 36.77Gi ± 1% 54.23Gi ± 1% +47.48% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=1-11 35.81Gi ± 1% 50.27Gi ± 0% +40.39% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=2-11 36.40Gi ± 2% 52.29Gi ± 1% +43.64% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=3-11 35.85Gi ± 0% 50.22Gi ± 0% +40.09% (p=0.000 n=10) CompareBytesBigBothUnaligned/offset=4-11 36.07Gi ± 1% 52.30Gi ± 1% +45.00% (p=0.000 n=7+10) geomean 36.33Gi 90.30Gi +41.63% Change-Id: I4ce9a26f7d434eb4f6447d8a5cbebee5d0901753 GitHub-Last-Rev: 1bf14dc111f1a848cce2193af0f17170b1dc7e73 GitHub-Pull-Request: golang/go#79800 Reviewed-on: https://go-review.googlesource.com/c/go/+/786560 Auto-Submit: Keith Randall Reviewed-by: Michael Pratt LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Keith Randall Reviewed-by: Keith Randall --- src/internal/bytealg/compare_arm64.s | 74 +++++++++++++++++----------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/src/internal/bytealg/compare_arm64.s b/src/internal/bytealg/compare_arm64.s index 852a535779b985..71f41fe349dd81 100644 --- a/src/internal/bytealg/compare_arm64.s +++ b/src/internal/bytealg/compare_arm64.s @@ -31,7 +31,7 @@ TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40 // // On exit: // R0 is the result -// R4, R5, R6, R8, R9 and R10 are clobbered +// R4, R5, R6, R8, R9, R10 and V0-V11 are clobbered TEXT cmpbody<>(SB),NOSPLIT|NOFRAME,$0-0 CMP R0, R2 BEQ samebytes // same starting pointers; compare lengths @@ -39,38 +39,48 @@ TEXT cmpbody<>(SB),NOSPLIT|NOFRAME,$0-0 CSEL LT, R3, R1, R6 // R6 is min(R1, R3) CBZ R6, samebytes - BIC $0x1f, R6, R10 - CBZ R10, chunk16 // length < 32, try single chunk16 - ADD R0, R10 // end of chunk32 - // length >= 32 -chunk32_loop: - LDP.P 16(R0), (R4, R8) - LDP.P 16(R2), (R5, R9) - CMP R4, R5 - BNE cmp - CMP R8, R9 - BNE cmpnext - LDP.P 16(R0), (R4, R8) - LDP.P 16(R2), (R5, R9) - CMP R4, R5 - BNE cmp - CMP R8, R9 - BNE cmpnext + BIC $0x3f, R6, R10 + CBZ R10, less_than_64 // length < 64, use scalar path + ADD R0, R10 // end of 64-byte chunks + + // Process 64 bytes per iteration using NEON. + // Compare 4x16-byte chunks and reduce the result to a single byte. + // On mismatch, rewind and fall back to the scalar path. + PCALIGN $16 +chunk64_loop: + VLD1.P (R0), [V0.D2, V1.D2, V2.D2, V3.D2] + VLD1.P (R2), [V4.D2, V5.D2, V6.D2, V7.D2] + VCMEQ V0.B16, V4.B16, V8.B16 + VCMEQ V1.B16, V5.B16, V9.B16 + VCMEQ V2.B16, V6.B16, V10.B16 + VCMEQ V3.B16, V7.B16, V11.B16 + VAND V8.B16, V9.B16, V8.B16 + VAND V10.B16, V11.B16, V10.B16 + VAND V8.B16, V10.B16, V8.B16 + VUMINV V8.B16, V8 + VMOV V8.B[0], R4 + CBZ R4, neon_mismatch CMP R10, R0 - BNE chunk32_loop - AND $0x1f, R6, R6 // remaining 0-31 bytes + BNE chunk64_loop + + AND $0x3f, R6, R6 // remaining 0-63 bytes CBZ R6, samebytes - // handle remaining 0-31 bytes: one possible 16-byte chunk then tail - TBZ $4, R6, small_direct -chunk16: - TBZ $4, R6, small // length < 16 + +less_than_64: + // Scalar 16-byte loop for up to 63 bytes, then byte-level tail. + BIC $0xf, R6, R10 + CBZ R10, small // length < 16 + ADD R0, R10 + PCALIGN $16 +chunk16_loop: LDP.P 16(R0), (R4, R8) LDP.P 16(R2), (R5, R9) CMP R4, R5 BNE cmp CMP R8, R9 BNE cmpnext -small_direct: + CMP R10, R0 + BNE chunk16_loop AND $0xf, R6, R6 CBZ R6, samebytes SUBS $8, R6 @@ -82,6 +92,8 @@ small_direct: BNE cmp SUB $8, R6 // compare last 8 bytes + // tail always reads the final 8-byte window at R0+R6. R6 may be + // negative here, overlapping already-verified bytes, which is harmless. tail: MOVD (R0)(R6), R4 MOVD (R2)(R6), R5 @@ -95,6 +107,15 @@ ret: MOVD $1, R0 CNEG HI, R0, R0 RET + +neon_mismatch: + // A mismatch was found in the last 64-byte NEON chunk. Rewind both + // pointers and let the scalar path locate the first differing byte. + SUB $64, R0 + SUB $64, R2 + MOVD $64, R6 + B less_than_64 + small: TBZ $3, R6, lt_8 MOVD (R0), R4 @@ -103,9 +124,6 @@ small: BNE cmp SUBS $8, R6 BEQ samebytes - ADD $8, R0 - ADD $8, R2 - SUB $8, R6 B tail lt_8: TBZ $2, R6, lt_4 From c25263921018fe83cad7916a3bebef020ce9875a Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 16 Jul 2026 20:59:09 +0700 Subject: [PATCH 04/16] cmd/compile: fix broken 386 softfloat builder CL 782461 added new test for avoiding temporary on non-softfloat system. However, the test was set to be run unconditionally, thus it would be failed on softfloat builders. Fixing this by moving the test to be run under cmd/internal/testdir, so it's possible to exclude unwanted softfloat platforms. While at it, also tighten the test to ensure there would be temporary if the compiler is forced to emit softfloat code. Updates #28698 Fixes #80422 Cq-Include-Trybots: luci.golang.try:gotip-linux-386-softfloat Change-Id: I5f7b3a19fe36d070d819d58cc29d43e4b44bb1fe Reviewed-on: https://go-review.googlesource.com/c/go/+/801560 Auto-Submit: Cuong Manh Le Reviewed-by: Keith Randall Reviewed-by: Michael Pratt LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Keith Randall --- .../compile/testdata/script/issue28698.txt | 15 ---- test/fixedbugs/issue28698.go | 80 +++++++++++++++++++ 2 files changed, 80 insertions(+), 15 deletions(-) delete mode 100644 src/cmd/compile/testdata/script/issue28698.txt create mode 100644 test/fixedbugs/issue28698.go diff --git a/src/cmd/compile/testdata/script/issue28698.txt b/src/cmd/compile/testdata/script/issue28698.txt deleted file mode 100644 index 87b39bd0c1e71b..00000000000000 --- a/src/cmd/compile/testdata/script/issue28698.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Float division does not require a temporary when preparing call arguments. - -go tool compile -W p.go -stdout 'DIV float64' -! stdout 'autotmp_.*float64' - --- p.go -- -package p - -//go:noinline -func sink(i int, f float64) {} - -func div(i int, x, y float64) { - sink(i, x/y) -} diff --git a/test/fixedbugs/issue28698.go b/test/fixedbugs/issue28698.go new file mode 100644 index 00000000000000..b76ebe36cc0af7 --- /dev/null +++ b/test/fixedbugs/issue28698.go @@ -0,0 +1,80 @@ +// run + +//go:build !js && !wasip1 + +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +const src = `package p + +//go:noinline +func sink(i int, f float64) {} + +func div(i int, x, y float64) { + sink(i, x/y) +} +` + +func isSoftFloat(s string) bool { + for _, v := range strings.Split(s, ",") { + if v == "softfloat" { + return true + } + } + return false +} + +func main() { + for _, env := range []string{"GO386", "GOMIPS", "GOMIPS64", "GOARM"} { + if isSoftFloat(os.Getenv(env)) { + return + } + } + + dir, err := os.MkdirTemp("", "issue28698") + if err != nil { + panic(err) + } + defer os.RemoveAll(dir) + + fn := filepath.Join(dir, "p.go") + if err := os.WriteFile(fn, []byte(src), 0644); err != nil { + panic(err) + } + + // Float division does not require a temporary when preparing call arguments. + cmd := exec.Command("go", "tool", "compile", "-W", fn) + out, err := cmd.CombinedOutput() + if err != nil { + panic(err) + } + + if bytes.Contains(out, []byte(".autotmp_")) { + fmt.Println(string(out)) + panic("unexpected autotmp") + } + + // Forcing softfloat should still emit temporary. + cmd = exec.Command("go", "tool", "compile", "-W", "-d=softfloat", fn) + out, err = cmd.CombinedOutput() + if err != nil { + panic(err) + } + + if !bytes.Contains(out, []byte(".autotmp_")) { + fmt.Println(string(out)) + panic("no autotmp") + } +} From a28f0001b7b5bd4062e399746a2a8c1ffd284ec8 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 16 Jul 2026 15:39:19 +1000 Subject: [PATCH 05/16] cmd/go/testdata/script/build_cwd_newline.txt: update go list output CL 787320 changed go list -compiled -x -f '{{.CompiledGoFiles}}' . output. But the CL did not changed build_cwd_newline.txt test because it is only running when CGO_ENABLED=0. Adjust the test. Updates #75238 Change-Id: I675abd19ef8fc75e0a8367ef937b202e8ba768ca Reviewed-on: https://go-review.googlesource.com/c/go/+/801420 Reviewed-by: Michael Pratt Auto-Submit: Michael Pratt Reviewed-by: Sean Liao Reviewed-by: David Chase Reviewed-by: Quim Muntal LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/cmd/go/testdata/script/build_cwd_newline.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/testdata/script/build_cwd_newline.txt b/src/cmd/go/testdata/script/build_cwd_newline.txt index 91cb57fa49e821..08570b5282e373 100644 --- a/src/cmd/go/testdata/script/build_cwd_newline.txt +++ b/src/cmd/go/testdata/script/build_cwd_newline.txt @@ -36,7 +36,7 @@ stderr 'package example: invalid package directory .*uh-oh' stderr 'package command-line-arguments: invalid package directory .*uh-oh' go list -compiled -e -f '{{with .CompiledGoFiles}}{{.}}{{end}}' . -! stdout . +[!cgo] stdout '[main_nocgo.go]' ! stderr . ! exists obj_ From 73aaa406fb563026da2e8457897efaf7f97a62b1 Mon Sep 17 00:00:00 2001 From: Julian Zhu Date: Thu, 4 Dec 2025 01:39:52 +0800 Subject: [PATCH 06/16] crypto/internal/fips140/subtle: re-add assembly implementation of xorBytes for mipsx This CL reapplies CL 666275 , and fixes the previous implementation's unaligned access and panic on mipsx. Updates #74998 Change-Id: I26cd3fdeb54419407bdc0a2f9616924e2e825bc3 Reviewed-on: https://go-review.googlesource.com/c/go/+/696076 Reviewed-by: Keith Randall LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Keith Randall Reviewed-by: Dmitri Shuralyov --- .../internal/fips140/subtle/xor_generic.go | 2 +- .../internal/fips140/subtle/xor_mipsx.go | 61 ++++++ .../internal/fips140/subtle/xor_mipsx.s | 188 ++++++++++++++++++ 3 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 src/crypto/internal/fips140/subtle/xor_mipsx.go create mode 100644 src/crypto/internal/fips140/subtle/xor_mipsx.s diff --git a/src/crypto/internal/fips140/subtle/xor_generic.go b/src/crypto/internal/fips140/subtle/xor_generic.go index 0b31eec60197d3..8d2e222ecb599a 100644 --- a/src/crypto/internal/fips140/subtle/xor_generic.go +++ b/src/crypto/internal/fips140/subtle/xor_generic.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. -//go:build (!amd64 && !arm64 && !loong64 && !ppc64 && !ppc64le && !riscv64) || purego +//go:build (!amd64 && !arm64 && !loong64 && !mips && !mipsle && !ppc64 && !ppc64le && !riscv64) || purego package subtle diff --git a/src/crypto/internal/fips140/subtle/xor_mipsx.go b/src/crypto/internal/fips140/subtle/xor_mipsx.go new file mode 100644 index 00000000000000..95e69dc3e3a551 --- /dev/null +++ b/src/crypto/internal/fips140/subtle/xor_mipsx.go @@ -0,0 +1,61 @@ +// 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. + +//go:build (mips || mipsle) && !purego + +package subtle + +import ( + "unsafe" +) + +const wordSize = unsafe.Sizeof(uintptr(0)) + +// dst,a,b,n, all be wordSize aligned, and n must be > 0 and a multiple of wordSize +// +//go:noescape +func xorBytesAligned(dst, a, b *byte, n int) + +func xorBytes(dstb, xb, yb *byte, n int) { + xp := uintptr(unsafe.Pointer(xb)) % wordSize + yp := uintptr(unsafe.Pointer(yb)) % wordSize + dp := uintptr(unsafe.Pointer(dstb)) % wordSize + if xp != yp || xp != dp { + dst := unsafe.Slice(dstb, n) + x := unsafe.Slice(xb, n) + y := unsafe.Slice(yb, n) + xorLoop(dst, x, y) + return + } + for (uintptr(unsafe.Pointer(dstb))%wordSize) != 0 && n > 0 { + *dstb = *xb ^ *yb + dstb = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(dstb)) + 1)) + xb = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(xb)) + 1)) + yb = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(yb)) + 1)) + n-- + } + alignedN := n & -int(wordSize) + if alignedN > 0 { + xorBytesAligned(dstb, xb, yb, alignedN) + dstb = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(dstb)) + uintptr(alignedN))) + xb = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(xb)) + uintptr(alignedN))) + yb = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(yb)) + uintptr(alignedN))) + n -= alignedN + } + for n > 0 { + *dstb = *xb ^ *yb + dstb = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(dstb)) + 1)) + xb = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(xb)) + 1)) + yb = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(yb)) + 1)) + n-- + } +} + +func xorLoop[T byte | uintptr](dst, x, y []T) { + x = x[:len(dst)] // remove bounds check in loop + y = y[:len(dst)] // remove bounds check in loop + for i := range dst { + dst[i] = x[i] ^ y[i] + } +} diff --git a/src/crypto/internal/fips140/subtle/xor_mipsx.s b/src/crypto/internal/fips140/subtle/xor_mipsx.s new file mode 100644 index 00000000000000..f65b9718cb6b91 --- /dev/null +++ b/src/crypto/internal/fips140/subtle/xor_mipsx.s @@ -0,0 +1,188 @@ +// 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. + +//go:build (mips || mipsle) && !purego + +#include "textflag.h" + +// func xorBytesAligned(dst, a, b *byte, n int) +TEXT ·xorBytesAligned(SB), NOSPLIT|NOFRAME, $0 + MOVW dst+0(FP), R1 + MOVW a+4(FP), R2 + MOVW b+8(FP), R3 + MOVW n+12(FP), R4 + + SGTU $64, R4, R5 // R5 = 1 if (64 > R4) + BNE R5, xor_32_check +xor_64: + MOVW (R2), R6 + MOVW 4(R2), R7 + MOVW 8(R2), R8 + MOVW 12(R2), R9 + MOVW (R3), R10 + MOVW 4(R3), R11 + MOVW 8(R3), R12 + MOVW 12(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVW R10, (R1) + MOVW R11, 4(R1) + MOVW R12, 8(R1) + MOVW R13, 12(R1) + MOVW 16(R2), R6 + MOVW 20(R2), R7 + MOVW 24(R2), R8 + MOVW 28(R2), R9 + MOVW 16(R3), R10 + MOVW 20(R3), R11 + MOVW 24(R3), R12 + MOVW 28(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVW R10, 16(R1) + MOVW R11, 20(R1) + MOVW R12, 24(R1) + MOVW R13, 28(R1) + MOVW 32(R2), R6 + MOVW 36(R2), R7 + MOVW 40(R2), R8 + MOVW 44(R2), R9 + MOVW 32(R3), R10 + MOVW 36(R3), R11 + MOVW 40(R3), R12 + MOVW 44(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVW R10, 32(R1) + MOVW R11, 36(R1) + MOVW R12, 40(R1) + MOVW R13, 44(R1) + MOVW 48(R2), R6 + MOVW 52(R2), R7 + MOVW 56(R2), R8 + MOVW 60(R2), R9 + MOVW 48(R3), R10 + MOVW 52(R3), R11 + MOVW 56(R3), R12 + MOVW 60(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVW R10, 48(R1) + MOVW R11, 52(R1) + MOVW R12, 56(R1) + MOVW R13, 60(R1) + ADD $64, R2 + ADD $64, R3 + ADD $64, R1 + SUB $64, R4 + SGTU $64, R4, R5 + BEQ R5, xor_64 + BEQ R4, end + +xor_32_check: + SGTU $32, R4, R5 + BNE R5, xor_16_check +xor_32: + MOVW (R2), R6 + MOVW 4(R2), R7 + MOVW 8(R2), R8 + MOVW 12(R2), R9 + MOVW (R3), R10 + MOVW 4(R3), R11 + MOVW 8(R3), R12 + MOVW 12(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVW R10, (R1) + MOVW R11, 4(R1) + MOVW R12, 8(R1) + MOVW R13, 12(R1) + MOVW 16(R2), R6 + MOVW 20(R2), R7 + MOVW 24(R2), R8 + MOVW 28(R2), R9 + MOVW 16(R3), R10 + MOVW 20(R3), R11 + MOVW 24(R3), R12 + MOVW 28(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVW R10, 16(R1) + MOVW R11, 20(R1) + MOVW R12, 24(R1) + MOVW R13, 28(R1) + ADD $32, R2 + ADD $32, R3 + ADD $32, R1 + SUB $32, R4 + BEQ R4, end + +xor_16_check: + SGTU $16, R4, R5 + BNE R5, xor_8_check +xor_16: + MOVW (R2), R6 + MOVW 4(R2), R7 + MOVW 8(R2), R8 + MOVW 12(R2), R9 + MOVW (R3), R10 + MOVW 4(R3), R11 + MOVW 8(R3), R12 + MOVW 12(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVW R10, (R1) + MOVW R11, 4(R1) + MOVW R12, 8(R1) + MOVW R13, 12(R1) + ADD $16, R2 + ADD $16, R3 + ADD $16, R1 + SUB $16, R4 + BEQ R4, end + +xor_8_check: + SGTU $8, R4, R5 + BNE R5, xor_4 +xor_8: + MOVW (R2), R6 + MOVW 4(R2), R7 + MOVW (R3), R8 + MOVW 4(R3), R9 + XOR R6, R8 + XOR R7, R9 + MOVW R8, (R1) + MOVW R9, 4(R1) + ADD $8, R1 + ADD $8, R2 + ADD $8, R3 + SUB $8, R4 + BEQ R4, end + +xor_4: + MOVW (R2), R6 + MOVW (R3), R7 + XOR R6, R7 + MOVW R7, (R1) + ADD $4, R2 + ADD $4, R3 + ADD $4, R1 + SUB $4, R4 + +end: + RET From 1ad6b283d410fb05be4ba63aaacb25b560d23839 Mon Sep 17 00:00:00 2001 From: Julian Zhu Date: Thu, 4 Dec 2025 01:51:55 +0800 Subject: [PATCH 07/16] crypto/internal/fips140/subtle: re-add assembly implementation of xorBytes for mips64x This CL reapplies CL 666255 , and fixes the previous implementation's unaligned access and panic on mips64x. Updates #74998 Change-Id: I8e58d25ba5f11520bfbe6e515d378c805bd5984f Reviewed-on: https://go-review.googlesource.com/c/go/+/696075 Reviewed-by: Keith Randall Reviewed-by: Keith Randall LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Dmitri Shuralyov --- .../internal/fips140/subtle/xor_generic.go | 2 +- .../internal/fips140/subtle/xor_mips64x.s | 117 ++++++++++++++++++ .../internal/fips140/subtle/xor_mipsx.go | 2 +- 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 src/crypto/internal/fips140/subtle/xor_mips64x.s diff --git a/src/crypto/internal/fips140/subtle/xor_generic.go b/src/crypto/internal/fips140/subtle/xor_generic.go index 8d2e222ecb599a..ed484bc630e98d 100644 --- a/src/crypto/internal/fips140/subtle/xor_generic.go +++ b/src/crypto/internal/fips140/subtle/xor_generic.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. -//go:build (!amd64 && !arm64 && !loong64 && !mips && !mipsle && !ppc64 && !ppc64le && !riscv64) || purego +//go:build (!amd64 && !arm64 && !loong64 && !mips && !mipsle && !mips64 && !mips64le && !ppc64 && !ppc64le && !riscv64) || purego package subtle diff --git a/src/crypto/internal/fips140/subtle/xor_mips64x.s b/src/crypto/internal/fips140/subtle/xor_mips64x.s new file mode 100644 index 00000000000000..c9224150a9668e --- /dev/null +++ b/src/crypto/internal/fips140/subtle/xor_mips64x.s @@ -0,0 +1,117 @@ +// 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. + +// mips64 version of xor.go +// derived from xor_riscv64.s + +//go:build (mips64 || mips64le) && !purego + +#include "textflag.h" + +// func xorBytes(dst, a, b *byte, n int) +TEXT ·xorBytesAligned(SB), NOSPLIT|NOFRAME, $0 + MOVV dst+0(FP), R1 + MOVV a+8(FP), R2 + MOVV b+16(FP), R3 + MOVV n+24(FP), R4 + + SGTU $64, R4, R5 // R5 = 1 if (64 > R4) + BNE R5, xor_32_check +xor_64: + MOVV (R2), R6 + MOVV 8(R2), R7 + MOVV 16(R2), R8 + MOVV 24(R2), R9 + MOVV (R3), R10 + MOVV 8(R3), R11 + MOVV 16(R3), R12 + MOVV 24(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVV R10, (R1) + MOVV R11, 8(R1) + MOVV R12, 16(R1) + MOVV R13, 24(R1) + MOVV 32(R2), R6 + MOVV 40(R2), R7 + MOVV 48(R2), R8 + MOVV 56(R2), R9 + MOVV 32(R3), R10 + MOVV 40(R3), R11 + MOVV 48(R3), R12 + MOVV 56(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVV R10, 32(R1) + MOVV R11, 40(R1) + MOVV R12, 48(R1) + MOVV R13, 56(R1) + ADDV $64, R2 + ADDV $64, R3 + ADDV $64, R1 + SUBV $64, R4 + SGTU $64, R4, R5 + BEQ R5, xor_64 + BEQ R4, end + +xor_32_check: + SGTU $32, R4, R5 + BNE R5, xor_16_check +xor_32: + MOVV (R2), R6 + MOVV 8(R2), R7 + MOVV 16(R2), R8 + MOVV 24(R2), R9 + MOVV (R3), R10 + MOVV 8(R3), R11 + MOVV 16(R3), R12 + MOVV 24(R3), R13 + XOR R6, R10 + XOR R7, R11 + XOR R8, R12 + XOR R9, R13 + MOVV R10, (R1) + MOVV R11, 8(R1) + MOVV R12, 16(R1) + MOVV R13, 24(R1) + ADDV $32, R2 + ADDV $32, R3 + ADDV $32, R1 + SUBV $32, R4 + BEQ R4, end + +xor_16_check: + SGTU $16, R4, R5 + BNE R5, xor_8 +xor_16: + MOVV (R2), R6 + MOVV 8(R2), R7 + MOVV (R3), R8 + MOVV 8(R3), R9 + XOR R6, R8 + XOR R7, R9 + MOVV R8, (R1) + MOVV R9, 8(R1) + ADDV $16, R2 + ADDV $16, R3 + ADDV $16, R1 + SUBV $16, R4 + BEQ R4, end + +xor_8: + MOVV (R2), R6 + MOVV (R3), R7 + XOR R6, R7 + MOVV R7, (R1) + ADDV $8, R1 + ADDV $8, R2 + ADDV $8, R3 + SUBV $8, R4 + +end: + RET diff --git a/src/crypto/internal/fips140/subtle/xor_mipsx.go b/src/crypto/internal/fips140/subtle/xor_mipsx.go index 95e69dc3e3a551..197fe634e0e9d9 100644 --- a/src/crypto/internal/fips140/subtle/xor_mipsx.go +++ b/src/crypto/internal/fips140/subtle/xor_mipsx.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. -//go:build (mips || mipsle) && !purego +//go:build (mips || mipsle || mips64 || mips64le) && !purego package subtle From 297d5911b5df9395580a512dbd0eefdaefbea723 Mon Sep 17 00:00:00 2001 From: "Nicholas S. Husin" Date: Wed, 15 Jul 2026 13:34:22 -0400 Subject: [PATCH 08/16] all: update vendored dependencies The Go 1.28 development tree has opened. This is a time to update all golang.org/x/... module versions that contribute packages to the std and cmd modules in the standard library to latest master versions. For #36905. [git-generate] go install golang.org/x/build/cmd/updatestd@latest go install golang.org/x/tools/cmd/bundle@latest updatestd -goroot=$(pwd) -branch=master Change-Id: I11731202ff1ede6ed905c667b5bbd7546a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/801060 Reviewed-by: Nicholas Husin Reviewed-by: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov Auto-Submit: Nicholas Husin LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Michael Matloob Reviewed-by: Michael Matloob --- src/cmd/go.mod | 20 +- src/cmd/go.sum | 36 +-- src/cmd/go/internal/doc/pkgsite.go | 2 +- .../x/arch/loong64/loong64asm/inst.go | 20 ++ .../golang.org/x/build/relnote/relnote.go | 10 + .../vendor/golang.org/x/mod/modfile/read.go | 2 +- .../vendor/golang.org/x/mod/modfile/rule.go | 6 +- .../vendor/golang.org/x/mod/sumdb/client.go | 2 +- .../golang.org/x/mod/sumdb/note/note.go | 2 +- .../golang.org/x/mod/sumdb/tlog/tile.go | 2 +- .../golang.org/x/mod/sumdb/tlog/tlog.go | 4 +- src/cmd/vendor/golang.org/x/mod/zip/zip.go | 4 +- .../golang.org/x/sync/errgroup/errgroup.go | 2 +- .../golang.org/x/sync/semaphore/semaphore.go | 27 +- .../golang.org/x/sys/unix/syscall_linux.go | 1 + .../x/sys/unix/syscall_linux_386.go | 1 - .../x/sys/unix/syscall_linux_amd64.go | 1 - .../x/sys/unix/syscall_linux_arm.go | 1 - .../x/sys/unix/syscall_linux_arm64.go | 1 - .../x/sys/unix/syscall_linux_loong64.go | 1 - .../x/sys/unix/syscall_linux_mips64x.go | 1 - .../x/sys/unix/syscall_linux_mipsx.go | 1 - .../x/sys/unix/syscall_linux_ppc.go | 1 - .../x/sys/unix/syscall_linux_ppc64x.go | 1 - .../x/sys/unix/syscall_linux_riscv64.go | 1 - .../x/sys/unix/syscall_linux_s390x.go | 1 - .../x/sys/unix/syscall_linux_sparc64.go | 1 - .../golang.org/x/sys/unix/zerrors_linux.go | 8 +- .../golang.org/x/sys/unix/zsyscall_linux.go | 17 ++ .../x/sys/unix/zsyscall_linux_386.go | 17 -- .../x/sys/unix/zsyscall_linux_amd64.go | 17 -- .../x/sys/unix/zsyscall_linux_arm.go | 17 -- .../x/sys/unix/zsyscall_linux_arm64.go | 17 -- .../x/sys/unix/zsyscall_linux_loong64.go | 17 -- .../x/sys/unix/zsyscall_linux_mips.go | 17 -- .../x/sys/unix/zsyscall_linux_mips64.go | 17 -- .../x/sys/unix/zsyscall_linux_mips64le.go | 17 -- .../x/sys/unix/zsyscall_linux_mipsle.go | 17 -- .../x/sys/unix/zsyscall_linux_ppc.go | 17 -- .../x/sys/unix/zsyscall_linux_ppc64.go | 17 -- .../x/sys/unix/zsyscall_linux_ppc64le.go | 17 -- .../x/sys/unix/zsyscall_linux_riscv64.go | 17 -- .../x/sys/unix/zsyscall_linux_s390x.go | 17 -- .../x/sys/unix/zsyscall_linux_sparc64.go | 17 -- .../golang.org/x/sys/unix/ztypes_linux.go | 76 ++++++ .../golang.org/x/sys/unix/ztypes_linux_386.go | 4 + .../x/sys/unix/ztypes_linux_amd64.go | 4 + .../golang.org/x/sys/unix/ztypes_linux_arm.go | 4 + .../x/sys/unix/ztypes_linux_arm64.go | 4 + .../x/sys/unix/ztypes_linux_loong64.go | 4 + .../x/sys/unix/ztypes_linux_mips.go | 4 + .../x/sys/unix/ztypes_linux_mips64.go | 4 + .../x/sys/unix/ztypes_linux_mips64le.go | 4 + .../x/sys/unix/ztypes_linux_mipsle.go | 4 + .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 4 + .../x/sys/unix/ztypes_linux_ppc64.go | 4 + .../x/sys/unix/ztypes_linux_ppc64le.go | 4 + .../x/sys/unix/ztypes_linux_riscv64.go | 4 + .../x/sys/unix/ztypes_linux_s390x.go | 4 + .../x/sys/unix/ztypes_linux_sparc64.go | 4 + .../x/sys/windows/security_windows.go | 36 +++ .../x/sys/windows/syscall_windows.go | 8 +- .../golang.org/x/sys/windows/types_windows.go | 1 + .../internal/crashmonitor/monitor.go | 85 +++++-- .../vendor/golang.org/x/text/cases/context.go | 2 +- src/cmd/vendor/golang.org/x/text/cases/map.go | 4 +- .../x/text/unicode/norm/forminfo.go | 9 +- .../golang.org/x/text/unicode/norm/iter.go | 8 +- .../x/text/unicode/norm/normalize.go | 20 +- .../go/analysis/passes/directive/directive.go | 10 +- .../x/tools/go/analysis/passes/inline/doc.go | 37 ++- .../tools/go/analysis/passes/inline/inline.go | 56 ++-- .../tools/go/analysis/passes/modernize/doc.go | 28 ++ .../go/analysis/passes/modernize/embedlit.go | 49 ++-- .../analysis/passes/modernize/errorsastype.go | 12 +- .../passes/modernize/importcomment.go | 69 +++++ .../go/analysis/passes/modernize/modernize.go | 19 +- .../go/analysis/passes/modernize/newexpr.go | 3 +- .../passes/modernize/reflecttypeassert.go | 118 +++++++++ .../passes/modernize/slicesbackward.go | 7 +- .../analysis/passes/modernize/unsafefuncs.go | 7 +- .../analysis/passes/modernize/waitgroupgo.go | 44 +++- .../x/tools/go/analysis/suite/vet/vet.go | 2 + .../x/tools/go/types/objectpath/objectpath.go | 9 +- .../x/tools/go/types/typeutil/callee.go | 61 +---- .../x/tools/internal/astutil/comment.go | 27 +- .../x/tools/internal/goplsexport/export.go | 20 -- .../x/tools/internal/refactor/imports.go | 33 ++- .../tools/internal/refactor/inline/inline.go | 70 ++--- .../internal/typesinternal/classify_call.go | 74 +++++- .../x/tools/internal/typesinternal/element.go | 22 +- .../x/tools/internal/typesinternal/types.go | 28 ++ .../tools/internal/typesinternal/zerovalue.go | 16 +- .../x/tools/refactor/satisfy/find.go | 176 ++++++++----- src/cmd/vendor/modules.txt | 19 +- src/go.mod | 10 +- src/go.sum | 16 +- .../golang.org/x/net/dns/dnsmessage/svcb.go | 33 ++- src/vendor/golang.org/x/net/idna/idna.go | 6 +- .../golang.org/x/net/internal/http3/body.go | 35 +-- .../golang.org/x/net/internal/http3/conn.go | 12 +- .../golang.org/x/net/internal/http3/gzip.go | 125 +++++++++ .../golang.org/x/net/internal/http3/qpack.go | 37 ++- .../x/net/internal/http3/qpack_static.go | 2 +- .../x/net/internal/http3/roundtrip.go | 39 ++- .../golang.org/x/net/internal/http3/server.go | 233 +++++++++++++---- .../golang.org/x/net/internal/http3/stream.go | 240 +++++++++++++++--- .../x/net/internal/http3/transport.go | 77 +++++- src/vendor/golang.org/x/net/quic/conn_flow.go | 2 +- src/vendor/golang.org/x/net/quic/conn_send.go | 2 +- .../x/net/quic/packet_protection.go | 2 +- src/vendor/golang.org/x/net/quic/stream.go | 2 +- src/vendor/golang.org/x/sys/cpu/parse.go | 62 +++-- .../x/text/unicode/norm/forminfo.go | 9 +- .../golang.org/x/text/unicode/norm/iter.go | 8 +- .../x/text/unicode/norm/normalize.go | 20 +- src/vendor/modules.txt | 8 +- 117 files changed, 1853 insertions(+), 884 deletions(-) create mode 100644 src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/importcomment.go create mode 100644 src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflecttypeassert.go delete mode 100644 src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go create mode 100644 src/vendor/golang.org/x/net/internal/http3/gzip.go diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 9aa7c87ac0e0cf..72d17b6d37c14b 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -1,21 +1,21 @@ module cmd -go 1.27 +go 1.28 require ( github.com/google/pprof v0.0.0-20260507013755-92041b743c96 - golang.org/x/arch v0.27.1-0.20260521044007-9c1a596a2c97 - golang.org/x/build v0.0.0-20260522210304-d55d0041b921 - golang.org/x/mod v0.36.1-0.20260520130633-087f6515dd3b - golang.org/x/sync v0.20.0 - golang.org/x/sys v0.45.0 - golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2 - golang.org/x/term v0.43.0 - golang.org/x/tools v0.45.1-0.20260714184632-28657d66a087 + golang.org/x/arch v0.29.0 + golang.org/x/build v0.0.0-20260715183034-a43f90886f2e + golang.org/x/mod v0.38.0 + golang.org/x/sync v0.22.0 + golang.org/x/sys v0.47.0 + golang.org/x/telemetry v0.0.0-20260716142750-dad6939de390 + golang.org/x/term v0.45.0 + golang.org/x/tools v0.48.1-0.20260715233119-591dfa620de7 ) require ( github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b // indirect - golang.org/x/text v0.37.0 // indirect + golang.org/x/text v0.40.0 // indirect rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef // indirect ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 9c6aa59dc288d6..97bbb0b963d9ce 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -6,23 +6,23 @@ github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b h1:ogbOPx8 github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -golang.org/x/arch v0.27.1-0.20260521044007-9c1a596a2c97 h1:OEbDVxixMxnrAI3whhcFkCb0rPrEHwxeSSUMdN0V414= -golang.org/x/arch v0.27.1-0.20260521044007-9c1a596a2c97/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= -golang.org/x/build v0.0.0-20260522210304-d55d0041b921 h1:94de7eCg8UQyP1wZw1ap2Y6rUGCmlKFSmffASSuprtk= -golang.org/x/build v0.0.0-20260522210304-d55d0041b921/go.mod h1:fBHxr1BrGapBTKSXEIQF99Z70AVWGYjAYKtf4FahAkA= -golang.org/x/mod v0.36.1-0.20260520130633-087f6515dd3b h1:/ZgX0SqMKZLpu1t6t3AEb2XROCzL71ILKLDWzDOZEUM= -golang.org/x/mod v0.36.1-0.20260520130633-087f6515dd3b/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2 h1:2EucmYlcIsc8Y6aLj+kX90Y00hmjqLNlw935kc13R2k= -golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2/go.mod h1:Eqhaxk/wZsWEH8CRxLwj6xzEJbz7k1EFGqx7nyCoabE= -golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= -golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= -golang.org/x/tools v0.45.1-0.20260714184632-28657d66a087 h1:OBacbO7Pun0pcIzRzkngMhqkKWPEgHQP6EZmltKDw4o= -golang.org/x/tools v0.45.1-0.20260714184632-28657d66a087/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/arch v0.29.0 h1:8sSET5wB0+exBm0FGmOtdHMqjlRdV2DRD3/IV6OZgho= +golang.org/x/arch v0.29.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= +golang.org/x/build v0.0.0-20260715183034-a43f90886f2e h1:oiywBusyGRO3p0N3a5ZP8BNETgAI/hGUxM7DQ1i0zcg= +golang.org/x/build v0.0.0-20260715183034-a43f90886f2e/go.mod h1:N2hm5dC0KLJLeV/d8HEFtLyibAwArsLhfcrbRNuWgwY= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20260716142750-dad6939de390 h1:L+U/4uCEJDjouVIvfchGv2nt7M9eB+uN4okfRiVRb6g= +golang.org/x/telemetry v0.0.0-20260716142750-dad6939de390/go.mod h1:LV7u5Oco+Z/g6XI7PqN+EUUUGGkEcmB1uj2ceI0fOVg= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= +golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= +golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/tools v0.48.1-0.20260715233119-591dfa620de7 h1:8VRsH4u6JnfFxX1nbu77Txl4Ry0er8QKCryK72kHAGc= +golang.org/x/tools v0.48.1-0.20260715233119-591dfa620de7/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= 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/doc/pkgsite.go b/src/cmd/go/internal/doc/pkgsite.go index bb006607824e8d..fba75f3bc6206e 100644 --- a/src/cmd/go/internal/doc/pkgsite.go +++ b/src/cmd/go/internal/doc/pkgsite.go @@ -32,7 +32,7 @@ import ( // To make that process easier, the exact name and file location of this constant are known // to the [golang.org/x/build/cmd/updatestd] command. If this constant needs to be renamed // or moved to another .go file, update that code too. -const pkgsiteCmdInternalDocVersion = "v0.0.0-20260605201217-deb78785c3ce" +const pkgsiteCmdInternalDocVersion = "v0.0.0-20260716130756-7a55b7dd9a2a" // pickUnusedPort finds an unused port by trying to listen on port 0 // and letting the OS pick a port, then closing that connection and diff --git a/src/cmd/vendor/golang.org/x/arch/loong64/loong64asm/inst.go b/src/cmd/vendor/golang.org/x/arch/loong64/loong64asm/inst.go index 362d73baf5c97b..ad97323f5cd003 100644 --- a/src/cmd/vendor/golang.org/x/arch/loong64/loong64asm/inst.go +++ b/src/cmd/vendor/golang.org/x/arch/loong64/loong64asm/inst.go @@ -63,6 +63,26 @@ func (i Inst) String() string { op = "bgez" args = append(args[:1], args[2:]...) } + + case RDTIMEH_W: + // rdtimeh.w rd, zero => rdcntvh.w rd + if i.Args[1].(Reg) == R0 && i.Args[0].(Reg) != R0 { + op = "rdcntvh.w" + args = args[:1] + } + + case RDTIMEL_W: + // rdtimel.w zero, rj => rdcntid.w rj + if i.Args[0].(Reg) == R0 && i.Args[1].(Reg) != R0 { + op = "rdcntid.w" + args = args[1:] + } + + // rdtimel.w rd, zero => rdcntvl.w rd + if i.Args[0].(Reg) != R0 && i.Args[1].(Reg) == R0 { + op = "rdcntvl.w" + args = args[:1] + } } if len(args) == 0 { diff --git a/src/cmd/vendor/golang.org/x/build/relnote/relnote.go b/src/cmd/vendor/golang.org/x/build/relnote/relnote.go index eeb12ce9e3ea28..8e87f82d32b3b5 100644 --- a/src/cmd/vendor/golang.org/x/build/relnote/relnote.go +++ b/src/cmd/vendor/golang.org/x/build/relnote/relnote.go @@ -144,6 +144,16 @@ func Merge(fsys fs.FS) (*md.Document, error) { // of a file acts as a blank line. lastLine := lastBlock(doc).Pos().EndLine delta := lastLine + 2 - newdoc.Blocks[0].Pos().StartLine + if pkg != "" { + // For stdlib minor changes, include the file name as a comment, as + // it often contains the issue number which is helpful. + comment := &md.HTMLBlock{ + Position: md.Position{StartLine: lastLine + 2, EndLine: lastLine + 2}, + Text: []string{""}, + } + delta++ + doc.Blocks = append(doc.Blocks, comment) + } for _, b := range newdoc.Blocks { addLines(b, delta) } 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 5b528c718e2f6b..9e35e1ac51f3eb 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/read.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/read.go @@ -924,7 +924,7 @@ var ( moduleStr = []byte("module") ) -// ModulePath returns the module path from the gomod file text. +// ModulePath returns the module path from the go.mod file text. // If it cannot find a module path, it returns an empty string. // It is tolerant of unrelated problems in the go.mod file. func ModulePath(mod []byte) string { 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 9ab203b5622981..20ba825d294032 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go @@ -1477,7 +1477,7 @@ func (f *File) setRequireSeparateIndirect(req []*Require, simplify bool) { // Delete requirements we don't want anymore. // Update versions and indirect comments on requirements we want to keep. // If a requirement is in last{Direct,Indirect}Block with the wrong - // indirect marking after this, or if the requirement is in an single + // indirect marking after this, or if the requirement is in a single // uncommented mixed block (oneFlatUncommentedBlock), move it to the // correct block. // @@ -1537,7 +1537,7 @@ func (f *File) DropRequire(path string) error { return nil } -// AddExclude adds a exclude statement to the mod file. Errors if the provided +// AddExclude adds an exclude statement to the mod file. Errors if the provided // version is not a canonical version string func (f *File) AddExclude(path, vers string) error { if err := checkCanonicalVersion(path, vers); err != nil { @@ -1708,7 +1708,7 @@ func (f *File) AddIgnore(path string) error { return nil } -// DropIgnore removes a ignore directive with the given path. +// DropIgnore removes an ignore directive with the given path. // It does nothing if no such ignore directive exists. func (f *File) DropIgnore(path string) error { for _, t := range f.Ignore { 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 f926eda1bb8b22..47533a843d6345 100644 --- a/src/cmd/vendor/golang.org/x/mod/sumdb/client.go +++ b/src/cmd/vendor/golang.org/x/mod/sumdb/client.go @@ -460,7 +460,7 @@ func (c *Client) checkTrees(older tlog.Tree, olderNote []byte, newer tlog.Tree, // on the continued availability of the misbehaving server. // Preparing this data only reuses the tiled hashes needed for // tlog.TreeHash(older.N, thr) above, so assuming thr is caching tiles, - // there are no new access to the server here, and these operations cannot fail. + // there are no new accesses to the server here, and these operations cannot fail. fmt.Fprintf(&buf, "proof of misbehavior:\n\t%v", h) if p, err := tlog.ProveTree(newer.N, older.N, thr); err != nil { fmt.Fprintf(&buf, "\tinternal error: %v\n", err) 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 c95777f5e855a0..a41a0e56b0e15f 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 @@ -238,7 +238,7 @@ func isValidName(name string) bool { return name != "" && utf8.ValidString(name) && strings.IndexFunc(name, unicode.IsSpace) < 0 && !strings.Contains(name, "+") } -// NewVerifier construct a new [Verifier] from an encoded verifier key. +// NewVerifier constructs a new [Verifier] from an encoded verifier key. func NewVerifier(vkey string) (Verifier, error) { name, vkey, _ := strings.Cut(vkey, "+") hash16, key64, _ := strings.Cut(vkey, "+") diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tile.go b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tile.go index 37771c53101a3d..153f41c979915d 100644 --- a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tile.go +++ b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tile.go @@ -22,7 +22,7 @@ import ( // of the form tile/H/L/NNN[.p/W]. // The .p/W suffix is present only for partial tiles, meaning W < 2**H. // The NNN element is an encoding of N into 3-digit path elements. -// All but the last path element begins with an "x". +// All but the last path element begin with an "x". // For example, // Tile{H: 3, L: 4, N: 1234067, W: 1}'s path // is tile/3/4/x001/x234/067.p/1, and 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 480b5eff5afe89..cbfca875f95835 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 @@ -34,7 +34,7 @@ func (h Hash) MarshalJSON() ([]byte, error) { return []byte(`"` + h.String() + `"`), nil } -// UnmarshalJSON unmarshals a hash from JSON string containing the a base64-encoded hash. +// UnmarshalJSON unmarshals a hash from a JSON string containing a base64-encoded hash. func (h *Hash) UnmarshalJSON(data []byte) error { if len(data) != 1+44+1 || data[0] != '"' || data[len(data)-2] != '=' || data[len(data)-1] != '"' { return errors.New("cannot decode hash") @@ -246,7 +246,7 @@ var emptyHash = Hash{ // TreeHash computes the hash for the root of the tree with n records, // using the HashReader to obtain previously stored hashes // (those returned by StoredHashes during the writes of those n records). -// TreeHash makes a single call to ReadHash requesting at most 1 + log₂ n hashes. +// TreeHash makes a single call to ReadHashes requesting at most 1 + log₂ n hashes. func TreeHash(n int64, r HashReader) (Hash, error) { if n == 0 { return emptyHash, nil 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 48363ceb722d7a..ddab4c328d7b3b 100644 --- a/src/cmd/vendor/golang.org/x/mod/zip/zip.go +++ b/src/cmd/vendor/golang.org/x/mod/zip/zip.go @@ -668,7 +668,7 @@ func filesInGitRepo(dir, rev, subdir string) ([]File, error) { // techniques like git ls-files, but this approach most closely matches what // the Go command does, which is beneficial. // - // Note: some of this code copied from https://go.googlesource.com/go/+/refs/tags/go1.16.5/src/cmd/go/internal/modfetch/codehost/git.go#826. + // Note: some of this code is copied from https://go.googlesource.com/go/+/refs/tags/go1.16.5/src/cmd/go/internal/modfetch/codehost/git.go#826. cmd := exec.Command("git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", rev) if subdir != "" { cmd.Args = append(cmd.Args, subdir) @@ -710,7 +710,7 @@ func filesInGitRepo(dir, rev, subdir string) ([]File, error) { } if !haveLICENSE && subdir != "" { - // Note: this method of extracting the license from the root copied from + // Note: this method of extracting the license from the root is copied from // https://go.googlesource.com/go/+/refs/tags/go1.20.4/src/cmd/go/internal/modfetch/coderepo.go#1118 // https://go.googlesource.com/go/+/refs/tags/go1.20.4/src/cmd/go/internal/modfetch/codehost/git.go#657 cmd := exec.Command("git", "cat-file", "blob", rev+":LICENSE") 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 f69fd754685a44..c261a8ebbddb18 100644 --- a/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -109,7 +109,7 @@ func (g *Group) TryGo(f func() error) bool { if g.sem != nil { select { case g.sem <- token{}: - // Note: this allows barging iff channels in general allow barging. + // Note: this allows barging if and only if channels in general allow barging. default: return false } diff --git a/src/cmd/vendor/golang.org/x/sync/semaphore/semaphore.go b/src/cmd/vendor/golang.org/x/sync/semaphore/semaphore.go index b618162aab648f..96a035aedeb6ab 100644 --- a/src/cmd/vendor/golang.org/x/sync/semaphore/semaphore.go +++ b/src/cmd/vendor/golang.org/x/sync/semaphore/semaphore.go @@ -24,7 +24,7 @@ func NewWeighted(n int64) *Weighted { } // Weighted provides a way to bound concurrent access to a resource. -// The callers can request access with a given weight. +// The callers can request access with a given non-negative weight. type Weighted struct { size int64 cur int64 @@ -32,10 +32,13 @@ type Weighted struct { waiters list.List } -// Acquire acquires the semaphore with a weight of n, blocking until resources +// Acquire acquires the semaphore with a non-negative weight of n, blocking until resources // are available or ctx is done. On success, returns nil. On failure, returns // ctx.Err() and leaves the semaphore unchanged. func (s *Weighted) Acquire(ctx context.Context, n int64) error { + if n < 0 { + panic("semaphore: n < 0") + } done := ctx.Done() s.mu.Lock() @@ -83,7 +86,7 @@ func (s *Weighted) Acquire(ctx context.Context, n int64) error { default: isFront := s.waiters.Front() == elem s.waiters.Remove(elem) - // If we're at the front and there're extra tokens left, notify other waiters. + // If we're at the front and there are extra tokens left, notify other waiters. if isFront && s.size > s.cur { s.notifyWaiters() } @@ -106,9 +109,12 @@ func (s *Weighted) Acquire(ctx context.Context, n int64) error { } } -// TryAcquire acquires the semaphore with a weight of n without blocking. +// TryAcquire acquires the semaphore with a non-negative weight of n without blocking. // On success, returns true. On failure, returns false and leaves the semaphore unchanged. func (s *Weighted) TryAcquire(n int64) bool { + if n < 0 { + panic("semaphore: n < 0") + } s.mu.Lock() success := s.size-s.cur >= n && s.waiters.Len() == 0 if success { @@ -118,8 +124,11 @@ func (s *Weighted) TryAcquire(n int64) bool { return success } -// Release releases the semaphore with a weight of n. +// Release releases the semaphore with a non-negative weight of n. func (s *Weighted) Release(n int64) { + if n < 0 { + panic("semaphore: n < 0") + } s.mu.Lock() s.cur -= n if s.cur < 0 { @@ -139,15 +148,15 @@ func (s *Weighted) notifyWaiters() { w := next.Value.(waiter) if s.size-s.cur < w.n { - // Not enough tokens for the next waiter. We could keep going (to try to + // Not enough tokens for the next waiter. We could keep going (to try to // find a waiter with a smaller request), but under load that could cause // starvation for large requests; instead, we leave all remaining waiters // blocked. // // Consider a semaphore used as a read-write lock, with N tokens, N - // readers, and one writer. Each reader can Acquire(1) to obtain a read - // lock. The writer can Acquire(N) to obtain a write lock, excluding all - // of the readers. If we allow the readers to jump ahead in the queue, + // readers, and one writer. Each reader can Acquire(1) to obtain a read + // lock. The writer can Acquire(N) to obtain a write lock, excluding all + // of the readers. If we allow the readers to jump ahead in the queue, // the writer will starve — there is always one token available for every // reader. break 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 ce4d7ab1ed8a42..21e2bfa398b93a 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 @@ -1874,6 +1874,7 @@ func Dup2(oldfd, newfd int) error { //sys Dup3(oldfd int, newfd int, flags int) (err error) //sysnb EpollCreate1(flag int) (fd int, err error) //sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT //sys Eventfd(initval uint, flags int) (fd int, err error) = SYS_EVENTFD2 //sys Exit(code int) = SYS_EXIT_GROUP //sys Fallocate(fd int, mode uint32, off int64, len int64) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_386.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_386.go index 506dafa7b4c6b1..210d545c93778c 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_386.go @@ -20,7 +20,6 @@ func setTimeval(sec, usec int64) Timeval { // 64-bit file system and 32-bit uid calls // (386 default is 32-bit file system and 16-bit uid). -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64 //sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32 //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go index d557cf8de3f236..a9a52f231996d9 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go @@ -6,7 +6,6 @@ package unix -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm.go index ecf92bfa2a39b3..54474c20feef0c 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm.go @@ -44,7 +44,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { // 64-bit file system and 32-bit uid calls // (16-bit uid calls are not always supported in newer kernels) -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32 //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 //sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go index 173738077b6d68..e9f30db97d4e61 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go @@ -8,7 +8,6 @@ package unix import "unsafe" -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go index a3fd1d0b802fd7..6f09ca200ad92d 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go @@ -8,7 +8,6 @@ package unix import "unsafe" -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstatfs(fd int, buf *Statfs_t) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go index 70963a95abf343..ca3b56597d7943 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go @@ -6,7 +6,6 @@ package unix -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstatfs(fd int, buf *Statfs_t) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go index c218ebd2801606..54ba667b1b2c7e 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go @@ -13,7 +13,6 @@ import ( func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go index e6c48500ca9444..ce462859024812 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go @@ -11,7 +11,6 @@ import ( "unsafe" ) -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 //sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go index 7286a9aa882b0d..33f7af38043d2d 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go @@ -6,7 +6,6 @@ package unix -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go index fc5543c5ffb458..c658871e307282 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go @@ -8,7 +8,6 @@ package unix import "unsafe" -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go index 66f31210d083fa..2c8587691b4d93 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go @@ -10,7 +10,6 @@ import ( "unsafe" ) -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go index 11d1f169866553..4964119af8fa43 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go @@ -6,7 +6,6 @@ package unix -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) 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 9d72a6b73a9367..5bb51d7ae1e3e5 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 @@ -1359,6 +1359,7 @@ const ( FAN_UNLIMITED_MARKS = 0x20 FAN_UNLIMITED_QUEUE = 0x10 FD_CLOEXEC = 0x1 + FD_PIDFS_ROOT = -0x2712 FD_SETSIZE = 0x400 FF0 = 0x0 FIB_RULE_DEV_DETACHED = 0x8 @@ -1970,6 +1971,8 @@ const ( MADV_DONTNEED = 0x4 MADV_DONTNEED_LOCKED = 0x18 MADV_FREE = 0x8 + MADV_GUARD_INSTALL = 0x66 + MADV_GUARD_REMOVE = 0x67 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 MADV_KEEPONFORK = 0x13 @@ -2114,7 +2117,7 @@ const ( MS_NOSEC = 0x10000000 MS_NOSUID = 0x2 MS_NOSYMFOLLOW = 0x100 - MS_NOUSER = -0x80000000 + MS_NOUSER = 0x80000000 MS_POSIXACL = 0x10000 MS_PRIVATE = 0x40000 MS_RDONLY = 0x1 @@ -3786,6 +3789,9 @@ const ( TCPOPT_TIMESTAMP = 0x8 TCPOPT_TSTAMP_HDR = 0x101080a TCPOPT_WINDOW = 0x3 + TCP_AO_KEYF_EXCLUDE_OPT = 0x2 + TCP_AO_KEYF_IFINDEX = 0x1 + TCP_AO_MAXKEYLEN = 0x50 TCP_CC_INFO = 0x1a TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd 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 80f40e40135783..5788c2a58d3705 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 @@ -700,6 +700,23 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Eventfd(initval uint, flags int) (fd int, err error) { r0, _, e1 := Syscall(SYS_EVENTFD2, uintptr(initval), uintptr(flags), 0) fd = int(r0) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go index 4def3e9fcb0d67..254f33988f0c7d 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64_64, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice)) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go index fef2bc8ba9c900..27c05db1acb296 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go index a9fd76a884119c..840d85bfc3ecc7 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go @@ -213,23 +213,6 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go index 4600650280aa87..fe414498b4046d 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go index c8987d2646504f..eb358ce05a0190 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go index 921f4306110659..c437622f14f3ec 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset>>32), uintptr(offset), uintptr(length>>32), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go index 44f067829c4dd1..bc4ca255820cc2 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go index e7fa0abf0d1964..5051435ce7e364 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go index 8c5125675e8385..33aa5418a4fca5 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go index 7392fd45e4333d..3bef8ef1d25150 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go index 41180434e60950..fc1bd4e2c45d51 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go index 40c6ce7ae5439b..d78fe7dabe9e6c 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go index 2cfe34adb12358..76dcf87d01c4f3 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go index 61e6f070971bfb..2cf020f2baa9f1 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go index 834b84204283a1..527637623d1aa5 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go @@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go index d11d5b96a49da4..526a0d5f434eb6 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 @@ -6397,3 +6397,79 @@ const ( MPOL_PREFERRED_MANY = 0x5 MPOL_WEIGHTED_INTERLEAVE = 0x6 ) + +const ( + GPIO_V2_GET_LINEINFO_IOCTL = 0xc100b405 + GPIO_V2_GET_LINE_IOCTL = 0xc250b407 + GPIO_V2_LINE_GET_VALUES_IOCTL = 0xc010b40e + GPIO_V2_LINE_SET_VALUES_IOCTL = 0xc010b40f + GPIO_V2_GET_LINEINFO_WATCH_IOCTL = 0xc100b406 + GPIO_GET_LINEINFO_UNWATCH_IOCTL = 0xc004b40c +) +const ( + GPIO_V2_LINE_ATTR_ID_FLAGS = 0x1 + GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES = 0x2 + GPIO_V2_LINE_ATTR_ID_DEBOUNCE = 0x3 + GPIO_V2_LINE_CHANGED_REQUESTED = 0x1 + GPIO_V2_LINE_CHANGED_RELEASED = 0x2 + GPIO_V2_LINE_CHANGED_CONFIG = 0x3 + GPIO_V2_LINE_EVENT_RISING_EDGE = 0x1 + GPIO_V2_LINE_EVENT_FALLING_EDGE = 0x2 +) + +type GPIOChipInfo struct { + Name [32]byte + Label [32]byte + Lines uint32 +} +type GPIOV2LineValues struct { + Bits uint64 + Mask uint64 +} +type GPIOV2LineAttribute struct { + Id uint32 + _ uint32 + Flags uint64 +} +type GPIOV2LineConfigAttribute struct { + Attr GPIOV2LineAttribute + Mask uint64 +} +type GPIOV2LineConfig struct { + Flags uint64 + Num_attrs uint32 + _ [5]uint32 + Attrs [10]GPIOV2LineConfigAttribute +} +type GPIOV2LineRequest struct { + Offsets [64]uint32 + Consumer [32]byte + Config GPIOV2LineConfig + Num_lines uint32 + Event_buffer_size uint32 + _ [5]uint32 + Fd int32 +} +type GPIOV2LineInfo struct { + Name [32]byte + Consumer [32]byte + Offset uint32 + Num_attrs uint32 + Flags uint64 + Attrs [10]GPIOV2LineAttribute + _ [4]uint32 +} +type GPIOV2LineInfoChanged struct { + Info GPIOV2LineInfo + Timestamp_ns uint64 + Event_type uint32 + _ [5]uint32 +} +type GPIOV2LineEvent struct { + Timestamp_ns uint64 + Id uint32 + Offset uint32 + Seqno uint32 + Line_seqno uint32 + _ [6]uint32 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index 97ef790deb2c9a..aede1de7f2e92b 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -711,3 +711,7 @@ type SysvShmDesc struct { _ uint32 _ uint32 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x8044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index 90b50da680f5ee..bb3bc4dc2c4ab2 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -725,3 +725,7 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x8044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index acda136851008c..1fdf4c5175c81b 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -705,3 +705,7 @@ type SysvShmDesc struct { _ uint32 _ uint32 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x8044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index ef7a99e1f9dc98..063e6f0b41e21e 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -704,3 +704,7 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x8044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go index 966063dfc132bd..9cf836c708f6a8 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go @@ -705,3 +705,7 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x8044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go index dc53b20b7433a1..1d222fcb312242 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -710,3 +710,7 @@ type SysvShmDesc struct { Ctime_high uint16 _ uint16 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x4044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index 9ad0aa8c31e798..912cc4ab63b3e2 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -707,3 +707,7 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x4044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index 29d55493d557c3..1e358ef34f2801 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -707,3 +707,7 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x4044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go index a4d9e158488cdb..df59f32f5e480e 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -710,3 +710,7 @@ type SysvShmDesc struct { Ctime_high uint16 _ uint16 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x4044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go index f8a2977716299f..29355aa0bfeff6 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go @@ -718,3 +718,7 @@ type SysvShmDesc struct { _ uint32 _ [4]byte } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x4044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index 4158d6c4eeeeea..c6083a15d7d9f8 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -713,3 +713,7 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x4044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index 1035af49f78581..6321cc76266701 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -713,3 +713,7 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x4044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index 2297125d3c7b3b..b44f402feb68c4 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -792,3 +792,7 @@ const ( RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE = 0x6 RISCV_HWPROBE_WHICH_CPUS = 0x1 ) + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x8044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index 8481e9bd98d2c5..b22c795a646dd3 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -727,3 +727,7 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x8044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go index a6828a031046bb..0b18075b53e364 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go @@ -708,3 +708,7 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +const ( + GPIO_GET_CHIPINFO_IOCTL = 0x4044b401 +) diff --git a/src/cmd/vendor/golang.org/x/sys/windows/security_windows.go b/src/cmd/vendor/golang.org/x/sys/windows/security_windows.go index 6c955cea158fa9..783621561ea27e 100644 --- a/src/cmd/vendor/golang.org/x/sys/windows/security_windows.go +++ b/src/cmd/vendor/golang.org/x/sys/windows/security_windows.go @@ -1109,17 +1109,53 @@ const ( ) // This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions. +// +// Go pointers stored in a TrusteeValue must be pinned using [runtime.Pinner] +// for the lifetime of the TrusteeValue. type TrusteeValue uintptr +// TrusteeValueFromString is unsafe and should not be used. +// +// It returns a uintptr containing a reference to newly-allocated memory +// which will be freed by the garbage collector. +// There is no way for the caller to safely reference this memory. +// +// To create a [TrusteeValue] from a string, use: +// +// p, err := windows.UTF16PtrFromString(s) +// if err != nil { +// // handle error +// } +// +// // Pin the string for as long as it is used. +// var pinner runtime.Pinner +// pinner.Pin(p) +// defer pinner.Unpin() +// +// tv := TrusteeValue(unsafe.Pointer(p)) +// +// Deprecated: TrusteeValueFromString is unsafe and should not be used. func TrusteeValueFromString(str string) TrusteeValue { return TrusteeValue(unsafe.Pointer(StringToUTF16Ptr(str))) } + +// TrusteeValueFromSID returns a [TrusteeValue] referencing sid. +// +// The caller must pin sid using a [runtime.Pinner] for the lifetime of the TrusteeValue. func TrusteeValueFromSID(sid *SID) TrusteeValue { return TrusteeValue(unsafe.Pointer(sid)) } + +// TrusteeValueFromObjectsAndSid returns a [TrusteeValue] referencing objectsAndSid. +// +// The caller must pin objectsAndSid using a [runtime.Pinner] for the lifetime of the TrusteeValue. func TrusteeValueFromObjectsAndSid(objectsAndSid *OBJECTS_AND_SID) TrusteeValue { return TrusteeValue(unsafe.Pointer(objectsAndSid)) } + +// TrusteeValueFromObjectsAndName returns a [TrusteeValue] referencing objectsAndName. +// +// The caller must pin objectsAndName using a [runtime.Pinner] for the lifetime of the TrusteeValue. func TrusteeValueFromObjectsAndName(objectsAndName *OBJECTS_AND_NAME) TrusteeValue { return TrusteeValue(unsafe.Pointer(objectsAndName)) } 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 9755bca9fd39df..e6966b4c32766f 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 @@ -1728,11 +1728,15 @@ func (s *NTUnicodeString) String() string { // the more common *uint16 string type. func NewNTString(s string) (*NTString, error) { var nts NTString - s8, err := BytePtrFromString(s) + s8, err := ByteSliceFromString(s) if err != nil { return nil, err } - RtlInitString(&nts, s8) + // The source string plus its terminating NUL must fit within MAX_USHORT. + if len(s8) > MAX_USHORT { + return nil, syscall.EINVAL + } + RtlInitString(&nts, &s8[0]) return &nts, nil } 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 d2574a73ee00a6..75a50b3165ee23 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 @@ -169,6 +169,7 @@ const ( FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192 FORMAT_MESSAGE_MAX_WIDTH_MASK = 255 + MAX_USHORT = 0xffff MAX_PATH = 260 MAX_LONG_PATH = 32768 diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go b/src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go index ac22f68c34ccf1..f6e6c7035685bd 100644 --- a/src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go +++ b/src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go @@ -202,19 +202,26 @@ func parseStackPCs(crash string) ([]uintptr, error) { return strconv.ParseUint(pcstr, 0, 64) // 0 => allow 0x prefix } + type goroutine struct { + id uint64 + pcs []uintptr + system bool // stack starts with runtime.systemstack_switch + } + var ( - pcs []uintptr + glist []*goroutine parentSentinel uint64 childSentinel = sentinel() - on = false // are we in the first running goroutine? lines = strings.Split(crash, "\n") - symLine = true // within a goroutine, every other line is a symbol or file/line/pc location, starting with symbol. - currSymbol string - prevSymbol string // symbol of the most recent previous frame with a PC. + + // Parsing state for the current goroutine. + g *goroutine + symLine = true // a symbol (not a filename) is expected on this line + currSymbol string + prevSymbol string ) - for i := 0; i < len(lines); i++ { - line := lines[i] + for _, line := range lines { // Read sentinel value. if parentSentinel == 0 && strings.HasPrefix(line, "sentinel ") { _, err := fmt.Sscanf(line, "sentinel %x", &parentSentinel) @@ -224,27 +231,37 @@ func parseStackPCs(crash string) ([]uintptr, error) { continue } - // Search for "goroutine GID [STATUS]" - if !on { - if strings.HasPrefix(line, "goroutine ") && - strings.Contains(line, " [running]:") { - on = true - - if parentSentinel == 0 { - return nil, fmt.Errorf("no sentinel value in crash report") + // Check for a "goroutine GID [STATUS]" header. + if strings.HasPrefix(line, "goroutine ") { + if parentSentinel == 0 { + return nil, fmt.Errorf("no sentinel value in crash report") + } + isG0 := strings.HasPrefix(line, "goroutine 0 ") + isRunning := strings.Contains(line, " [running]:") + if isG0 || isRunning { + var id uint64 + if parts := strings.Fields(line); len(parts) > 1 { + id, _ = strconv.ParseUint(parts[1], 10, 64) } + g = &goroutine{id: id} + glist = append(glist, g) + symLine = true + currSymbol = "" + prevSymbol = "" + } else { + g = nil } continue } - // A blank line marks end of a goroutine stack. - if line == "" { - break + if g == nil { + continue } - // Skip the final "created by SYMBOL in goroutine GID" part. - if strings.HasPrefix(line, "created by ") { - break + // A blank line or "created by " marks the end of the goroutine stack. + if line == "" || strings.HasPrefix(line, "created by ") { + g = nil + continue } // Expect a pair of lines: @@ -316,7 +333,10 @@ func parseStackPCs(crash string) ([]uintptr, error) { pc++ } - pcs = append(pcs, uintptr(pc)) + if len(g.pcs) == 0 && currSymbol == "runtime.systemstack_switch" { + g.system = true + } + g.pcs = append(g.pcs, uintptr(pc)) // Done with this frame. Next line is a new frame. prevSymbol = currSymbol @@ -324,5 +344,24 @@ func parseStackPCs(crash string) ([]uintptr, error) { symLine = true } } - return pcs, nil + + if len(glist) == 0 { + return nil, nil + } + + // The first goroutine in the dump is the one that crashed. + firstG := glist[0] + + // If the first goroutine is g0 (the system stack), we want to find the user + // goroutine that called it, which will start with systemstack_switch. + if firstG.id == 0 { + for _, g := range glist[1:] { + if g.system && len(g.pcs) > 0 { + // Stitch the g0 stack and user stack (skipping systemstack_switch). + return append(firstG.pcs, g.pcs[1:]...), nil + } + } + } + + return firstG.pcs, nil } diff --git a/src/cmd/vendor/golang.org/x/text/cases/context.go b/src/cmd/vendor/golang.org/x/text/cases/context.go index e9aa9e1936fa2c..a28f45d7bf1f76 100644 --- a/src/cmd/vendor/golang.org/x/text/cases/context.go +++ b/src/cmd/vendor/golang.org/x/text/cases/context.go @@ -249,7 +249,7 @@ func upper(c *context) bool { return c.copy() } -// isUpper writes the isUppercase version of the current rune to dst. +// isUpper reports whether the current rune is in upper case. func isUpper(c *context) bool { ct := c.caseType() if c.info&hasMappingMask == 0 || ct == cUpper { diff --git a/src/cmd/vendor/golang.org/x/text/cases/map.go b/src/cmd/vendor/golang.org/x/text/cases/map.go index 0f7c6a14bb73c5..51a683092f2dd8 100644 --- a/src/cmd/vendor/golang.org/x/text/cases/map.go +++ b/src/cmd/vendor/golang.org/x/text/cases/map.go @@ -774,7 +774,7 @@ func nlTitle(c *context) bool { // From CLDR: // # Special titlecasing for Dutch initial "ij". // ::Any-Title(); - // # Fix up Ij at the beginning of a "word" (per Any-Title, notUAX #29) + // # Fix up Ij at the beginning of a "word" (per Any-Title, not UAX #29) // [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ; if c.src[c.pSrc] != 'I' && c.src[c.pSrc] != 'i' { return title(c) @@ -794,7 +794,7 @@ func nlTitleSpan(c *context) bool { // From CLDR: // # Special titlecasing for Dutch initial "ij". // ::Any-Title(); - // # Fix up Ij at the beginning of a "word" (per Any-Title, notUAX #29) + // # Fix up Ij at the beginning of a "word" (per Any-Title, not UAX #29) // [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ; if c.src[c.pSrc] != 'I' { return isTitle(c) diff --git a/src/cmd/vendor/golang.org/x/text/unicode/norm/forminfo.go b/src/cmd/vendor/golang.org/x/text/unicode/norm/forminfo.go index f3a234e5f53eaf..b3cf5d9bdee236 100644 --- a/src/cmd/vendor/golang.org/x/text/unicode/norm/forminfo.go +++ b/src/cmd/vendor/golang.org/x/text/unicode/norm/forminfo.go @@ -121,8 +121,12 @@ func (p Properties) BoundaryAfter() bool { // // When all 6 bits are zero, the character is inert, meaning it is never // influenced by normalization. +// +// We set flags to 0x80 (high bit 7 unused in quick check data) to indicate an invalid rune. type qcInfo uint8 +func (p Properties) isInvalid() bool { return p.flags == 0x80 } + func (p Properties) isYesC() bool { return p.flags&0x10 == 0 } func (p Properties) isYesD() bool { return p.flags&0x4 == 0 } @@ -247,6 +251,9 @@ func (f Form) PropertiesString(s string) Properties { // to a Properties. See the comment at the top of the file // for more information on the format. func compInfo(v uint16, sz int) Properties { + if sz == 0 { + return Properties{flags: 0x80, size: 1} + } if v == 0 { return Properties{size: uint8(sz)} } else if v >= 0x8000 { @@ -254,7 +261,7 @@ func compInfo(v uint16, sz int) Properties { size: uint8(sz), ccc: uint8(v), tccc: uint8(v), - flags: qcInfo(v >> 8), + flags: qcInfo(v>>8) & 0x3f, } if p.ccc > 0 || p.combinesBackward() { p.nLead = uint8(p.flags & 0x3) diff --git a/src/cmd/vendor/golang.org/x/text/unicode/norm/iter.go b/src/cmd/vendor/golang.org/x/text/unicode/norm/iter.go index 417c6b26894da4..3cc059224d9d9e 100644 --- a/src/cmd/vendor/golang.org/x/text/unicode/norm/iter.go +++ b/src/cmd/vendor/golang.org/x/text/unicode/norm/iter.go @@ -376,16 +376,12 @@ func nextComposed(i *Iter) []byte { goto doNorm } prevCC = i.info.tccc - sz := int(i.info.size) - if sz == 0 { - sz = 1 // illegal rune: copy byte-by-byte - } - p := outp + sz + p := outp + int(i.info.size) if p > len(i.buf) { break } outp = p - i.p += sz + i.p += int(i.info.size) if i.p >= i.rb.nsrc { i.setDone() break diff --git a/src/cmd/vendor/golang.org/x/text/unicode/norm/normalize.go b/src/cmd/vendor/golang.org/x/text/unicode/norm/normalize.go index 4747ad07a839c1..60b1511caa2bad 100644 --- a/src/cmd/vendor/golang.org/x/text/unicode/norm/normalize.go +++ b/src/cmd/vendor/golang.org/x/text/unicode/norm/normalize.go @@ -148,7 +148,7 @@ func (f Form) IsNormalString(s string) bool { // patched buffer and whether the decomposition is still in progress. func patchTail(rb *reorderBuffer) bool { info, p := lastRuneStart(&rb.f, rb.out) - if p == -1 || info.size == 0 { + if p == -1 || info.isInvalid() { return true } end := p + int(info.size) @@ -225,7 +225,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte { } fd := &rb.f if doMerge { - var info Properties + info := Properties{flags: 0x80, size: 1} // invalid rune if p < n { info = fd.info(src, p) if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 { @@ -235,7 +235,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte { p = decomposeSegment(rb, p, true) } } - if info.size == 0 { + if info.isInvalid() { rb.doFlush() // Append incomplete UTF-8 encoding. return src.appendSlice(rb.out, p, n) @@ -314,7 +314,7 @@ func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) continue } info := f.info(src, i) - if info.size == 0 { + if info.isInvalid() { if atEOF { // include incomplete runes return n, true @@ -379,7 +379,7 @@ func (f Form) firstBoundary(src input, nsrc int) int { // CGJ insertion points correctly. Luckily it doesn't have to. for { info := fd.info(src, i) - if info.size == 0 { + if info.isInvalid() { return -1 } if s := ss.next(info); s != ssSuccess { @@ -424,7 +424,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int { } fd := formTable[f] info := fd.info(src, 0) - if info.size == 0 { + if info.isInvalid() { if atEOF { return 1 } @@ -435,7 +435,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int { for i := int(info.size); i < nsrc; i += int(info.size) { info = fd.info(src, i) - if info.size == 0 { + if info.isInvalid() { if atEOF { return i } @@ -465,7 +465,7 @@ func lastBoundary(fd *formInfo, b []byte) int { if p == -1 { return -1 } - if info.size == 0 { // ends with incomplete rune + if info.isInvalid() { // ends with incomplete rune if p == 0 { // starts with incomplete rune return -1 } @@ -504,7 +504,7 @@ func lastBoundary(fd *formInfo, b []byte) int { func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { // Force one character to be consumed. info := rb.f.info(rb.src, sp) - if info.size == 0 { + if info.isInvalid() { return 0 } if s := rb.ss.next(info); s == ssStarter { @@ -528,7 +528,7 @@ func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { break } info = rb.f.info(rb.src, sp) - if info.size == 0 { + if info.isInvalid() { if !atEOF { return int(iShortSrc) } 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 5fa28861e549e6..c8619fa33161a3 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 @@ -139,7 +139,7 @@ func (check *checker) nonGoFile(pos token.Pos, fullText string) { inStar = false continue } - line, inStar = stringsCutPrefix(line, "/*") + line, inStar = strings.CutPrefix(line, "/*") if !inStar { break } @@ -194,11 +194,3 @@ func (check *checker) comment(pos token.Pos, line string) { } } } - -// Go 1.20 strings.CutPrefix. -func stringsCutPrefix(s, prefix string) (after string, found bool) { - if !strings.HasPrefix(s, prefix) { - return s, false - } - return s[len(prefix):], true -} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/doc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/doc.go index 8b817a702900ba..fea596b9eed862 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/doc.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/doc.go @@ -10,7 +10,12 @@ and uses of constants marked with a "//go:fix inline" directive. inline: apply fixes based on 'go:fix inline' comment directives -The inline analyzer inlines functions and constants that are marked for inlining. +The inline analyzer inlines functions, constants, and type aliases +that are marked for inlining. + +Use this command to apply (just) inline fixes en masse: + + $ go fix -inline ./... ## Functions @@ -61,12 +66,6 @@ inliner machinery is capable of replacing f by a function literal, func(){...}(). However, the inline analyzer discards all such "literalizations" unconditionally, again on grounds of style.) -A call to a function F from its dedicated test (TestF) is not inlined, -since the purpose of the test is to exercise F itself, even when -it's a deprecated function to which other calls should be inlined. -This is not true for type aliases; see https://go.dev/issue/79271. -See further discussion in https://go.dev/issue/79272. - ## Constants Given a constant that is marked for inlining, like this one: @@ -96,14 +95,30 @@ or before a group, applying to every constant in the group: //go:fix inline const ( Ptr = Pointer - Val = Value + Val = Value ) -The proposal https://go.dev/issue/32816 introduces the "//go:fix inline" directives. +## Type aliases + +Similar to named constants, a type alias can also be marked for inlining: + + //go:fix inline + type A = newpkg.A + +The analyzer will replace all references to the annotated type +(A) by the type on the right-hand side of the declaration (newpkg.A). + +## Tests -You can use this command to apply inline fixes en masse: +A use of a function, named constant, or type alias X from its +dedicated test (TestX), is not inlined, since the purpose of the test +is to exercise X itself, even if it is deprecated and other uses of it +should be inlined. +This applies to benchmarks and examples too, and follows the usual +conventions of test function naming. - $ go run golang.org/x/tools/go/analysis/passes/inline/cmd/inline@latest -fix ./... +Similarly, if the symbol X is declared in a file named foo.go, any use +of it within a file named foo_test.go will also not be inlined. # Analyzer gofixdirective diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go index 890f4adf6ed5f2..d16e0d0b63c431 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go @@ -150,11 +150,11 @@ func (a *analyzer) inline() { a.inlineCall(n, cur) case *ast.Ident: - switch t := a.pass.TypesInfo.Uses[n].(type) { + switch obj := a.pass.TypesInfo.Uses[n].(type) { case *types.TypeName: - a.inlineAlias(t, cur) + a.inlineAlias(obj, cur) case *types.Const: - a.inlineConst(t, cur) + a.inlineConst(obj, cur) } } } @@ -252,11 +252,22 @@ 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. +// withinTestOf reports whether curUse is within a dedicated test +// function for the inlinable target symbol. // 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))) +func (a *analyzer) withinTestOf(curUse inspector.Cursor, target types.Object) bool { + // x_test.go -> x + useFileBase, isTest := strings.CutSuffix(a.pass.Fset.File(curUse.Node().Pos()).Name(), "_test.go") + if !isTest { + return false // not a test file + } + + // Suppress fixes for uses in x_test.go of target symbol defined in x.go (#79272). + if useFileBase == strings.TrimSuffix(a.pass.Fset.File(target.Pos()).Name(), ".go") { + return true + } + + curFuncDecl, ok := moreiters.First(curUse.Enclosing((*ast.FuncDecl)(nil))) if !ok { return false // not in a function } @@ -267,23 +278,22 @@ func (a *analyzer) withinTestOf(cur inspector.Cursor, target *types.Func) bool { 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. + // Computed expected SYMBOL portion of "ExampleSYMBOL_comment" + // for the target symbol. (Strictly, this convention applies + // only to Example functions.) + // TODO(adonovan): use a proper Test function parser. symbol := target.Name() - if recv := target.Signature().Recv(); recv != nil { - _, named := typesinternal.ReceiverNamed(recv) - symbol = named.Obj().Name() + "_" + symbol + if fn, ok := target.(*types.Func); ok { + if recv := fn.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"} { + for _, pre := range []string{"Test", "Example", "Bench", "Fuzz"} { if fname == pre+symbol || strings.HasPrefix(fname, pre+symbol+"_") { - return true + return true // use of X within TestX } } @@ -304,6 +314,10 @@ func (a *analyzer) inlineAlias(tn *types.TypeName, curId inspector.Cursor) { return // nope } + if a.withinTestOf(curId, tn) { + return // don't inline a type alias from within its own test + } + alias := tn.Type().(*types.Alias) // Remember the names of the alias's type params. When we check for shadowing // later, we'll ignore these because they won't appear in the replacement text. @@ -508,6 +522,10 @@ func (a *analyzer) inlineConst(con *types.Const, cur inspector.Cursor) { return // nope } + if a.withinTestOf(cur, con) { + return // don't inline a type alias from within its own test + } + // If n is qualified by a package identifier, we'll need the full selector expression. curFile := astutil.EnclosingFile(cur) n := cur.Node().(*ast.Ident) 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 260dd50908c2e7..bf83de38163b9c 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 @@ -182,6 +182,19 @@ unnecessary `x := x` statement. This fix only applies to `range` loops. +# Analyzer importcomment + +importcomment: remove obsolete comments specifying canonical import path + +The importcomment analyzer removes comments specifying the canonical +import path, such as + + package foo // import "example.com/foo" + +The go command enforced these comments in GOPATH mode via "go get", but +ignores them in module mode, so they are obsolete once the package +belongs to a module. The fix removes the comment. + # Analyzer mapsloop mapsloop: replace explicit loops over maps with calls to maps package @@ -331,6 +344,21 @@ No fix is offered in cases when the runtime type is dynamic, such as: or when the operand has potential side effects. +# Analyzer reflecttypeassert + +reflecttypeassert: replace v.Interface().(T) with reflect.TypeAssert[T](v) + +This analyzer suggests fixes to replace two-valued type assertions on +the result of (reflect.Value).Interface with reflect.TypeAssert, +introduced in go1.25, which avoids the intermediate allocation of an +interface value, for example: + + x, ok := v.Interface().(string) -> x, ok := reflect.TypeAssert[string](v) + +No fix is offered for single-valued assertions, since they panic when +the assertion fails whereas reflect.TypeAssert does not. Nor is a fix +offered for a type switch. + # Analyzer slicesbackward slicesbackward: replace backward loops over slices with slices.Backward diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/embedlit.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/embedlit.go index da883d67c983dd..4061758f85f43d 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/embedlit.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/embedlit.go @@ -84,14 +84,12 @@ func embedlitUnnest(pass *analysis.Pass, info *types.Info, curLit inspector.Curs // Can't promote an unkeyed field; would result in a syntax error. if kv, ok := elt.(*ast.KeyValueExpr); ok { if innerLit := isEmbeddedFieldLit(info, compLitType, kv); innerLit != nil { + // Inv: len(innerLit.Elts) > 0. We skip empty struct literals. // Emit edits to delete the unnecessary embedded field type specifier // and its closing brace. - closingPos := innerLit.Rbrace - if len(innerLit.Elts) > 0 { - // Delete any inner trailing commas or white space. Extra trailing commas - // would result in invalid code. - closingPos = innerLit.Elts[len(innerLit.Elts)-1].End() - } + // Delete any inner trailing commas or white space. Extra trailing commas + // would result in invalid code. + closingPos := innerLit.Elts[len(innerLit.Elts)-1].End() file := astutil.EnclosingFile(curLit) // Enable modernizer only for Go1.27. if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_27) { @@ -132,11 +130,11 @@ func embedlitUnnest(pass *analysis.Pass, info *types.Info, curLit inspector.Curs } // We can safely delete the entire line if the key value expression is - // on a different line than the previous element, and the closing - // brace of the inner literal is on a different line than its opening - // brace. + // alone on its line: it starts on a new line relative to the previous + // element (prevLine < curLine), and the first element of the inner + // literal starts on a subsequent line. if prevLine < curLine && curLine < tokFile.LineCount() && // (1-based) - lineOf(innerLit.Lbrace) < lineOf(innerLit.Rbrace) { + lineOf(innerLit.Elts[0].Pos()) > curLine { lineStart := tokFile.LineStart(curLine) nextLineStart := tokFile.LineStart(curLine + 1) // Check that there are no comments on the line we are going to delete. @@ -211,15 +209,25 @@ func embedlitCombine(pass *analysis.Pass, index *typeindex.Index, info *types.In case edge.AssignStmt_Rhs: assign := curLit.Parent().Node().(*ast.AssignStmt) // TODO(mkalil): Handle lhs forms that aren't idents, i.e. x.y[i] = T{...}. - if id, ok := assign.Lhs[curLit.ParentEdgeIndex()].(*ast.Ident); ok { + // TODO(mkalil): Handle multi-assignments like t1, t2 := A{}, B{} + if len(assign.Lhs) != 1 { + return nil + } + if id, ok := assign.Lhs[0].(*ast.Ident); ok { lhs = id curStmt = curLit.Parent() } case edge.ValueSpec_Values: spec := curLit.Parent().Node().(*ast.ValueSpec) - lhs = spec.Names[curLit.ParentEdgeIndex()] + // TODO(mkalil): Handle multi-declarations like var (x = A{}; y = B{}) or var x, y = ... + if len(spec.Names) != 1 { + return nil + } + lhs = spec.Names[0] if decl, ok := moreiters.First(curLit.Enclosing((*ast.DeclStmt)(nil))); ok { - curStmt = decl + if gdecl, ok := decl.Node().(*ast.DeclStmt).Decl.(*ast.GenDecl); ok && len(gdecl.Specs) == 1 { + curStmt = decl + } } default: return nil @@ -233,7 +241,8 @@ func embedlitCombine(pass *analysis.Pass, index *typeindex.Index, info *types.In tObj = info.ObjectOf(lhs) // Marks the contiguous block of embedded field assign statements that will // be moved into the struct initialization. - firstStmt, lastStmt inspector.Cursor + firstStmt, lastStmt inspector.Cursor + hasEmbeddedSelection bool ) stmtloop: for { @@ -264,6 +273,15 @@ stmtloop: if obj != tObj { break } + // The selection is from an embedded field if it directly + // assigns an embedded struct field (t.B = B{...}) or if + // the length of the index path is greater than one. + seln := info.Selections[sel] + if v, ok := seln.Obj().(*types.Var); ok && v.Embedded() || + len(seln.Index()) > 1 { + hasEmbeddedSelection = true + } + rhsCur := curStmt.ChildAt(edge.AssignStmt_Rhs, 0) if uses(index, rhsCur, tObj) { break @@ -286,7 +304,8 @@ stmtloop: lastStmt = curStmt } - if !firstStmt.Valid() { + if !firstStmt.Valid() || !hasEmbeddedSelection { + // We should not suggest a fix if none of the selections are from embedded fields. return nil } 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 f52f202e22def9..618e180cf4a6aa 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 @@ -32,7 +32,7 @@ var ErrorsAsTypeAnalyzer = &analysis.Analyzer{ Run: errorsastype, } -// errorsastype offers a fix to replace error.As with the newer +// errorsastype offers a fix to replace errors.As with the newer // errors.AsType[T] following this pattern: // // var myerr *MyErr @@ -228,11 +228,19 @@ func canUseErrorsAsType(info *types.Info, index *typeindex.Index, curCall inspec len(curDecl.Node().(*ast.GenDecl).Specs) != 1 { return // not a simple "var v T" decl } + if curDecl.ParentEdgeKind() != edge.DeclStmt_Decl { + return // package-level var, not a local declaration statement + } + // AsType requires that its type argument implements error. + // Reject if v does not implement error. + if !types.AssignableTo(v.Type(), errorType) { + return + } // Have: // var v *MyErr // ... // if errors.As(err, &v) { ... } // with no uses of v outside the IfStmt. - return v, curDecl.Parent(), curIfStmt // curDecl.Parent() is a DeclStmt + return v, curDecl.Parent(), curIfStmt } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/importcomment.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/importcomment.go new file mode 100644 index 00000000000000..15387835eed967 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/importcomment.go @@ -0,0 +1,69 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modernize + +import ( + "strings" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/internal/analysis/analyzerutil" +) + +var importCommentAnalyzer = &analysis.Analyzer{ + Name: "importcomment", + Doc: analyzerutil.MustExtractDoc(doc, "importcomment"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#importcomment", + Run: importcomment, +} + +func importcomment(pass *analysis.Pass) (any, error) { + // Import path comments are ignored in module mode. + if pass.Module == nil { + return nil, nil + } + + for _, file := range pass.Files { + // An import comment follows the package name on the same line. + pkgEnd := file.Name.End() + pkgLine := pass.Fset.Position(pkgEnd).Line + for _, c := range file.Comments { + if len(c.List) != 1 { + continue + } + if c.Pos() < pkgEnd { + continue + } + commentLine := pass.Fset.Position(c.Pos()).Line + if commentLine > pkgLine { + break // comments are sorted; the rest are on later lines + } + // Have: package p // comment + if !isImportComment(c.Text()) { + continue + } + pass.Report(analysis.Diagnostic{ + Pos: c.Pos(), + End: c.End(), + Message: "canonical import path comment is ignored in module mode", + SuggestedFixes: []analysis.SuggestedFix{{ + Message: "Remove obsolete import path comment", + TextEdits: []analysis.TextEdit{{ + Pos: pkgEnd, // deletes the preceding space too + End: c.End(), + }}, + }}, + }) + } + } + + return nil, nil +} + +// isImportComment reports whether text, a comment's content with its +// markers removed, is a canonical import path comment, import "path". +func isImportComment(text string) bool { + text = strings.TrimSpace(text) + return strings.HasPrefix(text, `import "`) && strings.HasSuffix(text, `"`) +} 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 80491273b5d5f9..755c0d64c7f9d7 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 @@ -35,22 +35,20 @@ var doc string var Suite = []*analysis.Analyzer{ AnyAnalyzer, AtomicTypesAnalyzer, - // AppendClippedAnalyzer, // not nil-preserving! - // BLoopAnalyzer, // may skew benchmark results, see golang/go#74967 EmbedLitAnalyzer, ErrorsAsTypeAnalyzer, - // FmtAppendfAnalyzer, // makes code less clear, see golang/go#77581 ForVarAnalyzer, + importCommentAnalyzer, // awaiting public symbol MapsLoopAnalyzer, MinMaxAnalyzer, NewExprAnalyzer, OmitZeroAnalyzer, PlusBuildAnalyzer, RangeIntAnalyzer, + reflectTypeAssertAnalyzer, // awaiting public symbol ReflectTypeForAnalyzer, - slicesBackwardAnalyzer, + slicesBackwardAnalyzer, // awaiting public symbol SlicesContainsAnalyzer, - // SlicesDeleteAnalyzer, // not nil-preserving! SlicesSortAnalyzer, StdIteratorsAnalyzer, StringsCutAnalyzer, @@ -58,8 +56,15 @@ var Suite = []*analysis.Analyzer{ StringsSeqAnalyzer, StringsBuilderAnalyzer, TestingContextAnalyzer, - unsafeFuncsAnalyzer, + unsafeFuncsAnalyzer, // awaiting public symbol WaitGroupGoAnalyzer, + + // Not included: + // + // AppendClippedAnalyzer, // not nil-preserving + // BLoopAnalyzer, // may skew benchmark results, see golang/go#74967 + // FmtAppendfAnalyzer, // makes code less clear, see golang/go#77581 + // SlicesDeleteAnalyzer, // not nil-preserving } // -- helpers -- @@ -132,10 +137,12 @@ var ( builtinMake = types.Universe.Lookup("make") builtinNew = types.Universe.Lookup("new") builtinNil = types.Universe.Lookup("nil") + builtinRecover = types.Universe.Lookup("recover") builtinString = types.Universe.Lookup("string") builtinTrue = types.Universe.Lookup("true") byteSliceType = types.NewSlice(types.Typ[types.Byte]) omitemptyRegex = regexp.MustCompile(`(?:^json| json):"[^"]*(,omitempty)(?:"|,[^"]*")\s?`) + errorType = types.Universe.Lookup("error").Type() ) // lookup returns the symbol denoted by name at the position of the cursor. 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 c99d9c24de9de2..15d52d12dbc17f 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 @@ -53,7 +53,8 @@ func run(pass *analysis.Pass) (any, error) { if sig.Results().Len() == 1 && is[*types.Pointer](sig.Results().At(0).Type()) && // => no iface conversion sig.Params().Len() == 1 && - sig.Params().At(0) == v { + sig.Params().At(0) == v && + !sig.Variadic() { // we can't safely transform a variadic function call, so skip them // Export a fact for each one. pass.ExportObjectFact(fn, &newLike{}) diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflecttypeassert.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflecttypeassert.go new file mode 100644 index 00000000000000..f9c120785cda0c --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflecttypeassert.go @@ -0,0 +1,118 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modernize + +import ( + "go/ast" + "go/token" + + "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/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 reflectTypeAssertAnalyzer = &analysis.Analyzer{ + Name: "reflecttypeassert", + Doc: analyzerutil.MustExtractDoc(doc, "reflecttypeassert"), + Requires: []*analysis.Analyzer{ + inspect.Analyzer, + typeindexanalyzer.Analyzer, + }, + Run: reflecttypeassert, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#reflecttypeassert", +} + +func reflecttypeassert(pass *analysis.Pass) (any, error) { + var ( + index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index) + info = pass.TypesInfo + + valueInterface = index.Selection("reflect", "Value", "Interface") + ) + + for curCall := range index.Calls(valueInterface) { + call := curCall.Node().(*ast.CallExpr) + // Have: v.Interface() + + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + continue // method expression reflect.Value.Interface(v) + } + + // TypeAssert's argument must be a reflect.Value; a pointer + // receiver would need an explicit dereference in the rewrite. + if !typesinternal.IsTypeNamed(info.TypeOf(sel.X), "reflect", "Value") { + continue + } + + // The call must be the operand of a type assertion + // (not a type switch, whose Type field is nil). + curOperand := astutil.UnparenEnclosingCursor(curCall) + if curOperand.ParentEdgeKind() != edge.TypeAssertExpr_X { + continue + } + curAssert := curOperand.Parent() + assert := curAssert.Node().(*ast.TypeAssertExpr) + if assert.Type == nil { + continue // type switch + } + + // The assertion must be the sole RHS of a two-valued + // assignment, x, ok := v.Interface().(T), so that the + // rewrite preserves the "commaOK" semantics; a single-valued + // assertion panics on failure whereas TypeAssert does not. + curRhs := astutil.UnparenEnclosingCursor(curAssert) + if curRhs.ParentEdgeKind() != edge.AssignStmt_Rhs { + continue + } + assign := curRhs.Parent().Node().(*ast.AssignStmt) + if len(assign.Lhs) != 2 || len(assign.Rhs) != 1 || + (assign.Tok != token.ASSIGN && assign.Tok != token.DEFINE) { + continue + } + + file := astutil.EnclosingFile(curCall) + if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_25) { + continue // TypeAssert requires go1.25 + } + + prefix, importEdits := refactor.AddImport(info, file, "reflect", "reflect", "TypeAssert", assert.Pos()) + + tstr := astutil.Format(pass.Fset, assert.Type) + pass.Report(analysis.Diagnostic{ + Pos: assert.Pos(), + End: assert.End(), + Message: "Interface().(" + tstr + ") can be simplified using reflect.TypeAssert", + SuggestedFixes: []analysis.SuggestedFix{{ + // v.Interface().(T) -> reflect.TypeAssert[T](v) + Message: "Replace Interface().(" + tstr + ") by reflect.TypeAssert[" + tstr + "]", + // Edit around sel.X instead of reformatting it, so its + // comments and spacing are preserved; only the type, + // which must move, is reformatted. + TextEdits: append(importEdits, + analysis.TextEdit{ + Pos: assert.Pos(), + End: sel.X.Pos(), + NewText: []byte(prefix + "TypeAssert[" + tstr + "]("), + }, + analysis.TextEdit{ + Pos: sel.X.End(), + End: assert.End(), + NewText: []byte(")"), + }, + ), + }}, + }) + } + + return nil, nil +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesbackward.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesbackward.go index 305b5e5b149141..02cd30a25809e4 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesbackward.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesbackward.go @@ -18,12 +18,12 @@ import ( "golang.org/x/tools/internal/analysis/analyzerutil" typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex" "golang.org/x/tools/internal/astutil" - "golang.org/x/tools/internal/goplsexport" "golang.org/x/tools/internal/refactor" "golang.org/x/tools/internal/typesinternal/typeindex" "golang.org/x/tools/internal/versions" ) +// TODO(adonovan): needs a proposal for a public symbol. var slicesBackwardAnalyzer = &analysis.Analyzer{ Name: "slicesbackward", Doc: analyzerutil.MustExtractDoc(doc, "slicesbackward"), @@ -35,11 +35,6 @@ var slicesBackwardAnalyzer = &analysis.Analyzer{ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#slicesbackward", } -func init() { - // Export to gopls until this is a published modernizer. - goplsexport.SlicesBackwardModernizer = slicesBackwardAnalyzer -} - // slicesbackward offers a fix to replace a manually-written backward loop: // // for i := len(s) - 1; i >= 0; i-- { diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go index 91c2f378ea89b7..34c135ca61e367 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go @@ -16,7 +16,6 @@ import ( "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/internal/analysis/analyzerutil" "golang.org/x/tools/internal/astutil" - "golang.org/x/tools/internal/goplsexport" "golang.org/x/tools/internal/refactor" "golang.org/x/tools/internal/typesinternal" "golang.org/x/tools/internal/versions" @@ -29,6 +28,7 @@ import ( // func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType // func SliceData(slice []ArbitraryType) *ArbitraryType +// TODO(adonovan): needs a proposal for a public symbol. var unsafeFuncsAnalyzer = &analysis.Analyzer{ Name: "unsafefuncs", Doc: analyzerutil.MustExtractDoc(doc, "unsafefuncs"), @@ -37,11 +37,6 @@ var unsafeFuncsAnalyzer = &analysis.Analyzer{ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#unsafefuncs", } -func init() { - // Export to gopls until this is a published modernizer. - goplsexport.UnsafeFuncsModernizer = unsafeFuncsAnalyzer -} - func unsafefuncs(pass *analysis.Pass) (any, error) { // Short circuit if the package doesn't use unsafe. // (In theory one could use some imported alias of unsafe.Pointer, diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroupgo.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroupgo.go index 9af2d3bdc74a16..570cd8f9f9e07e 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroupgo.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroupgo.go @@ -9,6 +9,7 @@ import ( "fmt" "go/ast" "go/printer" + "go/types" "slices" "golang.org/x/tools/go/analysis" @@ -112,7 +113,7 @@ func waitgroup(pass *analysis.Pass) (any, error) { astutil.EqualSyntax(ast.Unparen(deferStmt.Call.Fun).(*ast.SelectorExpr).X, addCallRecv) { doneStmt = deferStmt // "defer wg.Done()" - } else if lastStmt, ok := list[len(list)-1].(*ast.ExprStmt); ok { + } else if lastStmt, ok := list[len(list)-1].(*ast.ExprStmt); ok && cannotRecover(lit.Body, info) { if doneCall, ok := lastStmt.X.(*ast.CallExpr); ok && typeutil.Callee(info, doneCall) == syncWaitGroupDone && astutil.EqualSyntax(ast.Unparen(doneCall.Fun).(*ast.SelectorExpr).X, addCallRecv) { @@ -175,3 +176,44 @@ func waitgroup(pass *analysis.Pass) (any, error) { } return nil, nil } + +// cannotRecover reports whether no panic arising in body can be +// recovered. It conservatively treats a defer of anything but a +// recover-free function literal (e.g. a named function) as able to recover. +func cannotRecover(body *ast.BlockStmt, info *types.Info) bool { + res := true + ast.Inspect(body, func(n ast.Node) bool { + switch n := n.(type) { + case *ast.DeferStmt: + lit, ok := ast.Unparen(n.Call.Fun).(*ast.FuncLit) + if !ok || containsRecover(lit.Body, info) { + res = false + } + // Each defer is fully handled here; don't descend into it. + return false + case *ast.FuncLit: + // Defers in nested functions cannot recover panics from this body. + return false + } + return true + }) + return res +} + +func containsRecover(body *ast.BlockStmt, info *types.Info) bool { + found := false + ast.Inspect(body, func(n ast.Node) bool { + switch n := n.(type) { + case *ast.CallExpr: + if typeutil.Callee(info, n) == builtinRecover { + found = true + return false + } + case *ast.FuncLit: + // Recover calls in nested functions cannot recover panics from body. + return false + } + return true + }) + return found +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/suite/vet/vet.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/suite/vet/vet.go index 73e7a27d843f03..b85ee656c5f735 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/suite/vet/vet.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/suite/vet/vet.go @@ -78,10 +78,12 @@ var Suite = []*analysis.Analyzer{ lostcancel.Analyzer, nilfunc.Analyzer, printf.Analyzer, + // scannererr.Analyzer, // TODO(adonovan): add to go vet for 1.28 after the freeze (#17747) // shadow.Analyzer omitted: too noisy shift.Analyzer, sigchanyzer.Analyzer, slog.Analyzer, + // sqlrowserr.Analyzer, // TODO(adonovan): add to go vet for 1.28 after the freeze (#17747) stdmethods.Analyzer, stdversion.Analyzer, stringintconv.Analyzer, 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 0d6d0bced0fae9..9c7401c9ba51f5 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 @@ -30,6 +30,7 @@ import ( "slices" "strconv" "strings" + "sync" "golang.org/x/tools/internal/typesinternal" ) @@ -126,7 +127,8 @@ func For(obj types.Object) (Path, error) { // An Encoder amortizes the cost of encoding the paths of multiple objects. // The zero value of an Encoder is ready to use. type Encoder struct { - pkgIndex map[*types.Package]*pkgIndex + pkgIndexMu sync.Mutex + pkgIndex map[*types.Package]*pkgIndex } // A traversal encapsulates the state of a single traversal of the object/type graph. @@ -191,6 +193,8 @@ type pkgIndex struct { // For returns the path to an object relative to its package, // or an error if the object is not accessible from the package's Scope. // +// For is safe for concurrent use. +// // The For function guarantees to return a path only for the following objects: // - package-level types // - exported package-level non-types @@ -320,6 +324,9 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { panic(obj) } + enc.pkgIndexMu.Lock() + defer enc.pkgIndexMu.Unlock() + // 4. Search the object/type graph for the path to // the var (field/param/result) or method. ix, ok := enc.pkgIndex[pkg] diff --git a/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/callee.go b/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/callee.go index 3d24a8c63711b5..b64a8f454951a8 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/callee.go +++ b/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/callee.go @@ -7,7 +7,8 @@ package typeutil import ( "go/ast" "go/types" - _ "unsafe" // for linkname + + "golang.org/x/tools/internal/typesinternal" ) // Callee returns the named target of a function call, if any: @@ -19,14 +20,7 @@ import ( // Note: for calls of instantiated functions and methods, Callee returns // the corresponding generic function or method on the generic type. func Callee(info *types.Info, call *ast.CallExpr) types.Object { - obj := info.Uses[usedIdent(info, call.Fun)] - if obj == nil { - return nil - } - if _, ok := obj.(*types.TypeName); ok { - return nil - } - return obj + return typesinternal.Callee(info, call) } // StaticCallee returns the target (function or method) of a static function @@ -35,52 +29,5 @@ func Callee(info *types.Info, call *ast.CallExpr) types.Object { // Note: for calls of instantiated functions and methods, StaticCallee returns // the corresponding generic function or method on the generic type. func StaticCallee(info *types.Info, call *ast.CallExpr) *types.Func { - obj := info.Uses[usedIdent(info, call.Fun)] - fn, _ := obj.(*types.Func) - if fn == nil || interfaceMethod(fn) { - return nil - } - return fn -} - -// usedIdent is the implementation of [internal/typesinternal.UsedIdent]. -// It returns the identifier associated with e. -// See typesinternal.UsedIdent for a fuller description. -// This function should live in typesinternal, but cannot because it would -// create an import cycle. -// -//go:linkname usedIdent golang.org/x/tools/go/types/typeutil.usedIdent -func usedIdent(info *types.Info, e ast.Expr) *ast.Ident { - if info.Types == nil || info.Uses == nil { - panic("one of info.Types or info.Uses is nil; both must be populated") - } - // Look through type instantiation if necessary. - switch d := ast.Unparen(e).(type) { - case *ast.IndexExpr: - if info.Types[d.Index].IsType() { - e = d.X - } - case *ast.IndexListExpr: - e = d.X - } - - switch e := ast.Unparen(e).(type) { - // info.Uses always has the object we want, even for selector expressions. - // We don't need info.Selections. - // See go/types/recording.go:recordSelection. - case *ast.Ident: - return e - case *ast.SelectorExpr: - return e.Sel - } - return nil -} - -// interfaceMethod reports whether its argument is a method of an interface. -// This function should live in typesinternal, but cannot because it would create an import cycle. -// -//go:linkname interfaceMethod golang.org/x/tools/go/types/typeutil.interfaceMethod -func interfaceMethod(f *types.Func) bool { - recv := f.Signature().Recv() - return recv != nil && types.IsInterface(recv.Type()) + return typesinternal.StaticCallee(info, call) } diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go index 40a347214b5a38..db9e68b0da0084 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go @@ -13,11 +13,17 @@ import ( ) // Deprecation returns the paragraph of the doc comment that starts with the -// conventional "Deprecation: " marker, as defined by -// https://go.dev/wiki/Deprecated, or "" if the documented symbol is not -// deprecated. +// conventional "Deprecation: " marker, or the end of a single-line comment +// with the deprecation marker, as defined by https://go.dev/wiki/Deprecated. +// Returns "" if the documented symbol is not deprecated. +// +// Deprecation(nil) returns the empty string. func Deprecation(doc *ast.CommentGroup) string { - for p := range strings.SplitSeq(doc.Text(), "\n\n") { + // doc.Text() is newline-terminated. For legacy reasons, this function will + // return as newline-terminated if is the last segment of the CommentGroup + // but not if it is a paragraph in the middle of the CommentGroup. + docText := doc.Text() + for p := range strings.SplitSeq(docText, "\n\n") { // There is still some ambiguity for deprecation message. This function // only returns the paragraph introduced by "Deprecated: ". More // information related to the deprecation may follow in additional @@ -27,6 +33,19 @@ func Deprecation(doc *ast.CommentGroup) string { return p } } + + // We also want to support deprecation markers in line comments. Not all + // call sites know whether they have a line comment or the type of AST node + // the comment is associated with; so to best match line deprecations, + // the CommentGroup must meet these criteria: + // * The doc.Text() is a single line. + // * The comment uses the "// ..." format. + if doc == nil || len(doc.List) != 1 || !strings.HasPrefix(doc.List[0].Text, "//") { + return "" + } + if i := strings.Index(docText, "Deprecated: "); i != -1 { + return docText[i:] + } return "" } 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 deleted file mode 100644 index 414c9cb03ef22e..00000000000000 --- a/src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go +++ /dev/null @@ -1,20 +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 goplsexport provides various backdoors to not-yet-published -// parts of x/tools that are needed by gopls. -package goplsexport - -import "golang.org/x/tools/go/analysis" - -var ( - ErrorsAsTypeModernizer *analysis.Analyzer // = modernize.errorsastypeAnalyzer - SlicesBackwardModernizer *analysis.Analyzer // = modernize.slicesbackwardAnalyzer - StdIteratorsModernizer *analysis.Analyzer // = modernize.stditeratorsAnalyzer - PlusBuildModernizer *analysis.Analyzer // = modernize.plusbuildAnalyzer - StringsCutModernizer *analysis.Analyzer // = modernize.stringscutAnalyzer - UnsafeFuncsModernizer *analysis.Analyzer // = modernize.unsafeFuncsAnalyzer - AtomicTypesModernizer *analysis.Analyzer // = modernize.atomicTypesAnalyzer - EmbedLitModernizer *analysis.Analyzer // = modernize.embedLitAnalyzer -) diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/imports.go b/src/cmd/vendor/golang.org/x/tools/internal/refactor/imports.go index e1860ab0659880..5ce70aee837d3a 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/imports.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/refactor/imports.go @@ -99,19 +99,28 @@ func AddImportEdits(file *ast.File, name, pkgpath string) []Edit { } // Create a new import declaration either before the first existing - // declaration (which must exist), including its comments; or - // inside the declaration, if it is an import group. - decl0 := file.Decls[0] - before := decl0.Pos() - switch decl0 := decl0.(type) { - case *ast.GenDecl: - if decl0.Doc != nil { - before = decl0.Doc.Pos() - } - case *ast.FuncDecl: - if decl0.Doc != nil { - before = decl0.Doc.Pos() + // declaration (if it exists), including its comments; or at the end of the + // file (if there are no decls); or inside the declaration, if it is an + // import group. + var ( + before token.Pos + decl0 ast.Decl + ) + if len(file.Decls) > 0 { + decl0 = file.Decls[0] + before = decl0.Pos() + switch decl0 := decl0.(type) { + case *ast.GenDecl: + if decl0.Doc != nil { + before = decl0.Doc.Pos() + } + case *ast.FuncDecl: + if decl0.Doc != nil { + before = decl0.Doc.Pos() + } } + } else { + before = file.FileEnd } var pos token.Pos if gd, ok := decl0.(*ast.GenDecl); ok && gd.Tok == token.IMPORT && gd.Rparen.IsValid() { 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 cf4c587176e5cd..b329ab6f5da36a 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 @@ -768,12 +768,18 @@ func (st *state) inlineCall() (*inlineCallResult, error) { } } - typeArgs := st.typeArguments(caller.Call) - if len(typeArgs) != len(callee.TypeParams) { - return nil, fmt.Errorf("cannot inline: type parameter inference is not yet supported") - } - if err := substituteTypeParams(logf, callee.TypeParams, typeArgs, params, replaceCalleeID); err != nil { - return nil, err + // Substitute type parameters in calleeDecl AST with type arguments from the + // call, and synchronize the parameter metadata. + { + typeArgs := st.typeArguments(caller.Call) + if len(typeArgs) != len(callee.TypeParams) { + return nil, fmt.Errorf("cannot inline: type parameter inference is not yet supported") + } + if err := substituteTypeParams(logf, callee.TypeParams, typeArgs, replaceCalleeID); err != nil { + return nil, err + } + // Synchronize the parameters' type pointers with the mutated calleeDecl. + syncParamFieldTypes(calleeDecl, params) } // Log effective arguments. @@ -1506,9 +1512,9 @@ type parameter struct { // variadic elimination, and may be unpacked into variadic calls. type replacer = func(offset int, repl ast.Expr, unpackVariadic bool) -// substituteTypeParams replaces type parameters in the callee with the corresponding type arguments -// from the call. -func substituteTypeParams(logf logger, typeParams []*paramInfo, typeArgs []*argument, params []*parameter, replace replacer) error { +// substituteTypeParams replaces type parameters in the callee with the +// corresponding type arguments from the call. +func substituteTypeParams(logf logger, typeParams []*paramInfo, typeArgs []*argument, replace replacer) error { assert(len(typeParams) == len(typeArgs), "mismatched number of type params/args") for i, paramInfo := range typeParams { arg := typeArgs[i] @@ -1522,31 +1528,37 @@ func substituteTypeParams(logf logger, typeParams []*paramInfo, typeArgs []*argu for _, ref := range paramInfo.Refs { replace(ref.Offset, internalastutil.CloneNode(arg.expr), false) } - // Also replace parameter field types. - // TODO(jba): find a way to do this that is not so slow and clumsy. - // Ideally, we'd walk each p.fieldType once, replacing all type params together. - for _, p := range params { - if id, ok := p.fieldType.(*ast.Ident); ok && id.Name == paramInfo.Name { - p.fieldType = arg.expr - } else { - for _, id := range identsNamed(p.fieldType, paramInfo.Name) { - replaceNode(p.fieldType, id, arg.expr) - } - } - } } return nil } -func identsNamed(n ast.Node, name string) []*ast.Ident { - var ids []*ast.Ident - ast.Inspect(n, func(n ast.Node) bool { - if id, ok := n.(*ast.Ident); ok && id.Name == name { - ids = append(ids, id) +// syncParamFieldTypes synchronizes the fieldType of each parameter in params +// with the mutated calleeDecl AST. This is necessary because substituteTypeParams +// mutates the calleeDecl AST, replacing type nodes, but params still references +// the original (now outdated) type nodes. +func syncParamFieldTypes(calleeDecl *ast.FuncDecl, params []*parameter) { + var i int + setFieldType := func(t ast.Expr) { + assert(i < len(params), "mismatched parameter count") + params[i].fieldType = t + i++ + } + + if calleeDecl.Recv != nil && len(calleeDecl.Recv.List) > 0 { + setFieldType(calleeDecl.Recv.List[0].Type) + } + if calleeDecl.Type.Params != nil { + for _, field := range calleeDecl.Type.Params.List { + if field.Names == nil { + setFieldType(field.Type) + } else { + for range field.Names { + setFieldType(field.Type) + } + } } - return true - }) - return ids + } + assert(i == len(params), "mismatched parameter count") } // substitute implements parameter elimination by substitution. diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/classify_call.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/classify_call.go index 7ebe9768bc3e7a..14f616ff5aa017 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/classify_call.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/classify_call.go @@ -8,7 +8,6 @@ import ( "fmt" "go/ast" "go/types" - _ "unsafe" // for go:linkname hack ) // CallKind describes the function position of an [*ast.CallExpr]. @@ -72,11 +71,15 @@ func ClassifyCall(info *types.Info, call *ast.CallExpr) CallKind { if tv.IsBuiltin() { return CallBuiltin } - obj := info.Uses[UsedIdent(info, call.Fun)] + id := UsedIdent(info, call.Fun) + if id == nil { + return CallDynamic + } + obj := info.Uses[id] // Classify the call by the type of the object, if any. switch obj := obj.(type) { case *types.Func: - if interfaceMethod(obj) { + if isInterfaceMethod(obj) { return CallInterface } return CallStatic @@ -127,11 +130,66 @@ func ClassifyCall(info *types.Info, call *ast.CallExpr) CallKind { // Note: if e is an instantiated function or method, UsedIdent returns // the corresponding generic function or method on the generic type. func UsedIdent(info *types.Info, e ast.Expr) *ast.Ident { - return usedIdent(info, e) + if info.Types == nil || info.Uses == nil { + panic("one of info.Types or info.Uses is nil; both must be populated") + } + // Look through type instantiation if necessary. + switch d := ast.Unparen(e).(type) { + case *ast.IndexExpr: + if info.Types[d.Index].IsType() { + e = d.X + } + case *ast.IndexListExpr: + e = d.X + } + + switch e := ast.Unparen(e).(type) { + // info.Uses always has the object we want, even for selector expressions. + // We don't need info.Selections. + // See go/types/recording.go:recordSelection. + case *ast.Ident: + return e + case *ast.SelectorExpr: + return e.Sel + } + return nil } -//go:linkname usedIdent golang.org/x/tools/go/types/typeutil.usedIdent -func usedIdent(info *types.Info, e ast.Expr) *ast.Ident +// See [golang.org/x/tools/go/types/typeutil.Callee]. +func Callee(info *types.Info, call *ast.CallExpr) types.Object { + id := UsedIdent(info, call.Fun) + if id == nil { + return nil + } + obj := info.Uses[id] + if obj == nil { + return nil + } + if _, ok := obj.(*types.TypeName); ok { + return nil + } + return obj +} + +// See [golang.org/x/tools/go/types/typeutil.StaticCallee]. +func StaticCallee(info *types.Info, call *ast.CallExpr) *types.Func { + id := UsedIdent(info, call.Fun) + if id == nil { + return nil + } + obj := info.Uses[id] + if obj == nil { + return nil + } + fn, _ := obj.(*types.Func) + if fn == nil || isInterfaceMethod(fn) { + return nil + } + return fn +} -//go:linkname interfaceMethod golang.org/x/tools/go/types/typeutil.interfaceMethod -func interfaceMethod(f *types.Func) bool +// isInterfaceMethod reports whether its argument is a method of an interface. +func isInterfaceMethod(f *types.Func) bool { + recv := f.Signature().Recv() + return recv != nil && types.IsInterface(recv.Type()) +} 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 89eeea165333eb..6e0613c4af8270 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 @@ -7,8 +7,6 @@ package typesinternal import ( "fmt" "go/types" - - "golang.org/x/tools/go/types/typeutil" ) // ForEachElement calls f for type T and each type reachable from its @@ -16,25 +14,25 @@ import ( // type constructors; in addition, for each named type N, the type *N // is added to the result as it may have additional methods. // -// The caller must provide an initially empty set used to de-duplicate -// identical types, potentially across multiple calls to ForEachElement. -// (Its final value holds all the elements seen, matching the arguments -// passed to f.) +// The result of f indicates whether the caller has seen this type +// already, so we can prune the traversal. // // TODO(adonovan): share/harmonize with go/callgraph/rta. -func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T types.Type, f func(types.Type)) { +// +// methodSetOf abstracts (*typeutil.MethodSetCache).MethodSet, +// avoiding an import cycle. +func ForEachElement(methodSetOf func(types.Type) *types.MethodSet, T types.Type, f func(types.Type) bool) { var visit func(T types.Type, skip bool) visit = func(T types.Type, skip bool) { if !skip { - if seen, _ := rtypes.Set(T, true).(bool); seen { - return // de-dup + // notify caller of element type + if f(T) { + return // duplicate; prune descent } - - f(T) // notify caller of new element type } // Recursion over signatures of each method. - tmset := msets.MethodSet(T) + tmset := methodSetOf(T) for method := range tmset.Methods() { sig := method.Type().(*types.Signature) if sig.TypeParams() != nil { diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go index 6582cc81f5affd..d2c0b4c5ff23b3 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go @@ -22,6 +22,7 @@ import ( "go/ast" "go/token" "go/types" + "iter" "reflect" "golang.org/x/tools/go/ast/inspector" @@ -242,3 +243,30 @@ func ObjectKind(obj types.Object) string { } return "unknown symbol" } + +// ImplicitFieldSelections returns the sequence of implicit embedded fields +// traversed by the given selection. It skips the final leaf field or method. +// The boolean component indicates whether the traversal traversed a pointer. +func ImplicitFieldSelections(seln types.Selection) iter.Seq2[*types.Var, bool] { + return func(yield func(*types.Var, bool) bool) { + var ( + t = seln.Recv() + indices = seln.Index() + ) + for _, idx := range indices[:len(indices)-1] { + ptr, isPtr := t.Underlying().(*types.Pointer) + if isPtr { + t = ptr.Elem() + } + structType, ok := t.Underlying().(*types.Struct) + if !ok { + break + } + field := structType.Field(idx) + if !yield(field, isPtr) { + break + } + t = field.Type() + } + } +} 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 d612a7102971b0..706ad33ef89acf 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 @@ -259,13 +259,13 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr { case *types.Signature: var params []*ast.Field for v := range t.Params().Variables() { + var names []*ast.Ident + if v.Name() != "" { + names = []*ast.Ident{ast.NewIdent(v.Name())} + } params = append(params, &ast.Field{ - Type: TypeExpr(v.Type(), qual), - Names: []*ast.Ident{ - { - Name: v.Name(), - }, - }, + Type: TypeExpr(v.Type(), qual), + Names: names, }) } if t.Variadic() { @@ -328,10 +328,10 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr { return expr case *types.Struct: - return ast.NewIdent(t.String()) + return ast.NewIdent(types.TypeString(t, qual)) case *types.Interface: - return ast.NewIdent(t.String()) + return ast.NewIdent(types.TypeString(t, qual)) case *types.Union: if t.Len() == 0 { diff --git a/src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go b/src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go index 3d21ce6d26e812..720ecc17d7e9c1 100644 --- a/src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go +++ b/src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go @@ -8,8 +8,13 @@ // interface, and this fact is necessary for the package to be // well-typed. // -// It requires well-typed inputs. -package satisfy // import "golang.org/x/tools/refactor/satisfy" +// It requires well-typed inputs, and may panic otherwise. +// +// This package reimplements parts of the type checker. See +// https://go.dev/issue/70638 for a proposal to expose the the work +// already done by the type checker, which would make this package +// redundant. +package satisfy // NOTES: // @@ -40,6 +45,7 @@ import ( "go/ast" "go/token" "go/types" + "iter" "golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/internal/typeparams" @@ -127,13 +133,16 @@ func (f *Finder) exprN(e ast.Expr) types.Type { case *ast.CallExpr: // x, err := f(args) - sig := typeparams.CoreType(f.expr(e.Fun)).(*types.Signature) - f.call(sig, e.Args) + if sig := hasUnderlyingTermOf[*types.Signature](f.expr(e.Fun)); sig != nil { + f.call(sig, e.Args) + } case *ast.IndexExpr: // y, ok := x[i] x := f.expr(e.X) - f.assign(f.expr(e.Index), typeparams.CoreType(x).(*types.Map).Key()) + if m := hasUnderlyingTermOf[*types.Map](x); m != nil { + f.assign(f.expr(e.Index), m.Key()) + } case *ast.TypeAssertExpr: // y, ok := x.(T) @@ -216,16 +225,19 @@ func (f *Finder) builtin(obj *types.Builtin, sig *types.Signature, args []ast.Ex f.expr(args[1]) } else { // append(x, y, z) - tElem := typeparams.CoreType(s).(*types.Slice).Elem() - for _, arg := range args[1:] { - f.assign(tElem, f.expr(arg)) + if s := hasUnderlyingTermOf[*types.Slice](s); s != nil { + for _, arg := range args[1:] { + f.assign(s.Elem(), f.expr(arg)) + } } } case "delete": m := f.expr(args[0]) k := f.expr(args[1]) - f.assign(typeparams.CoreType(m).(*types.Map).Key(), k) + if m := hasUnderlyingTermOf[*types.Map](m); m != nil { + f.assign(m.Key(), k) + } default: // ordinary call @@ -357,38 +369,37 @@ func (f *Finder) expr(e ast.Expr) types.Type { f.sig = saved case *ast.CompositeLit: - switch T := typeparams.CoreType(typeparams.Deref(tv.Type)).(type) { - case *types.Struct: - for i, elem := range e.Elts { - if kv, ok := elem.(*ast.KeyValueExpr); ok { - f.assign(f.info.Uses[kv.Key.(*ast.Ident)].Type(), f.expr(kv.Value)) - } else { - f.assign(T.Field(i).Type(), f.expr(elem)) + for term := range terms(typeparams.Deref(tv.Type)) { + switch T := term.Underlying().(type) { + case *types.Struct: + for i, elem := range e.Elts { + if kv, ok := elem.(*ast.KeyValueExpr); ok { + f.assign(f.info.Uses[kv.Key.(*ast.Ident)].Type(), f.expr(kv.Value)) + } else { + f.assign(T.Field(i).Type(), f.expr(elem)) + } } - } - case *types.Map: - for _, elem := range e.Elts { - elem := elem.(*ast.KeyValueExpr) - f.assign(T.Key(), f.expr(elem.Key)) - f.assign(T.Elem(), f.expr(elem.Value)) - } + case *types.Map: + for _, elem := range e.Elts { + elem := elem.(*ast.KeyValueExpr) + f.assign(T.Key(), f.expr(elem.Key)) + f.assign(T.Elem(), f.expr(elem.Value)) + } - case *types.Array, *types.Slice: - tElem := T.(interface { - Elem() types.Type - }).Elem() - for _, elem := range e.Elts { - if kv, ok := elem.(*ast.KeyValueExpr); ok { - // ignore the key - f.assign(tElem, f.expr(kv.Value)) - } else { - f.assign(tElem, f.expr(elem)) + case *types.Array, *types.Slice: + tElem := T.(interface{ Elem() types.Type }).Elem() + for _, elem := range e.Elts { + if kv, ok := elem.(*ast.KeyValueExpr); ok { + // ignore the key + f.assign(tElem, f.expr(kv.Value)) + } else { + f.assign(tElem, f.expr(elem)) + } } + default: + panic(fmt.Sprintf("unexpected composite literal type %T: %v", tv.Type, tv.Type.String())) } - - default: - panic(fmt.Sprintf("unexpected composite literal type %T: %v", tv.Type, tv.Type.String())) } case *ast.ParenExpr: @@ -411,8 +422,8 @@ func (f *Finder) expr(e ast.Expr) types.Type { // x[i] or m[k] -- index or lookup operation x := f.expr(e.X) i := f.expr(e.Index) - if ux, ok := typeparams.CoreType(x).(*types.Map); ok { - f.assign(ux.Key(), i) + if m := hasUnderlyingTermOf[*types.Map](x); m != nil { + f.assign(m.Key(), i) } } @@ -464,7 +475,9 @@ func (f *Finder) expr(e ast.Expr) types.Type { } // ordinary call - f.call(typeparams.CoreType(f.expr(e.Fun)).(*types.Signature), e.Args) + if sig := hasUnderlyingTermOf[*types.Signature](f.expr(e.Fun)); sig != nil { + f.call(sig, e.Args) + } } case *ast.StarExpr: @@ -524,7 +537,9 @@ func (f *Finder) stmt(s ast.Stmt) { case *ast.SendStmt: ch := f.expr(s.Chan) val := f.expr(s.Value) - f.assign(typeparams.CoreType(ch).(*types.Chan).Elem(), val) + if c := hasUnderlyingTermOf[*types.Chan](ch); c != nil { + f.assign(c.Elem(), val) + } case *ast.IncDecStmt: f.expr(s.X) @@ -671,36 +686,36 @@ func (f *Finder) stmt(s ast.Stmt) { if s.Tok == token.ASSIGN { if s.Key != nil { k := f.expr(s.Key) - var xelem types.Type // Keys of array, *array, slice, string aren't interesting // since the RHS key type is just an int. - switch ux := typeparams.CoreType(x).(type) { - case *types.Chan: - xelem = ux.Elem() - case *types.Map: - xelem = ux.Key() - } - if xelem != nil { - f.assign(k, xelem) + for term := range terms(x) { + switch term := term.Underlying().(type) { + case *types.Chan: + f.assign(k, term.Elem()) + case *types.Map: + f.assign(k, term.Key()) + } } } if s.Value != nil { val := f.expr(s.Value) - var xelem types.Type // Values of type strings aren't interesting because // the RHS value type is just a rune. - switch ux := typeparams.CoreType(x).(type) { - case *types.Array: - xelem = ux.Elem() - case *types.Map: - xelem = ux.Elem() - case *types.Pointer: // *array - xelem = typeparams.CoreType(typeparams.Deref(ux)).(*types.Array).Elem() - case *types.Slice: - xelem = ux.Elem() - } - if xelem != nil { - f.assign(val, xelem) + for term := range terms(x) { + switch term := term.Underlying().(type) { + case *types.Pointer: + for term := range terms(term.Elem()) { + if array, ok := term.Underlying().(*types.Array); ok { + f.assign(val, array.Elem()) + } + } + case *types.Array: + f.assign(val, term.Elem()) + case *types.Map: + f.assign(val, term.Elem()) + case *types.Slice: + f.assign(val, term.Elem()) + } } } } @@ -726,3 +741,40 @@ func instance(info *types.Info, expr ast.Expr) bool { _, ok := info.Instances[id] return ok } + +// -- type-set helpers -- + +// hasUnderlyingTermOf reports whether terms(t) contains a +// term whose underlying type has top-level type constructor T +// (e.g. *types.Map for a map). +// If so, it returns an arbitrary one. +// Otherwise it returns the zero value (nil). +// +// This arbitrariness would be a hazard if this function were +// published more widely, but in this package it is used only for +// structural operations (indexing, etc) that require the relevant +// component types to be identical across all terms in the operand's +// type set. +func hasUnderlyingTermOf[T types.Type](t types.Type) T { + for term := range terms(t) { + if under, ok := term.Underlying().(T); ok { + return under + } + } + return *new(T) // e.g. (*types.Map)(nil) +} + +// terms returns the sequence of terms in the type set of t. +// The boolean reports whether the term has a tilde. +// TODO(adonovan): replace with solution to go.dev/issue/61013. +func terms(t types.Type) iter.Seq2[types.Type, bool] { + return func(yield func(types.Type, bool) bool) { + if terms, err := typeparams.NormalTerms(t); err == nil { + for _, term := range terms { + if !yield(term.Type(), term.Tilde()) { + break + } + } + } + } +} diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 6e513d8a5f175e..e543d18b3bb23d 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -16,7 +16,7 @@ github.com/google/pprof/third_party/svgpan # github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b ## explicit; go 1.13 github.com/ianlancetaylor/demangle -# golang.org/x/arch v0.27.1-0.20260521044007-9c1a596a2c97 +# golang.org/x/arch v0.29.0 ## explicit; go 1.25.0 golang.org/x/arch/arm/armasm golang.org/x/arch/arm64/arm64asm @@ -25,10 +25,10 @@ golang.org/x/arch/ppc64/ppc64asm golang.org/x/arch/riscv64/riscv64asm golang.org/x/arch/s390x/s390xasm golang.org/x/arch/x86/x86asm -# golang.org/x/build v0.0.0-20260522210304-d55d0041b921 +# golang.org/x/build v0.0.0-20260715183034-a43f90886f2e ## explicit; go 1.25.0 golang.org/x/build/relnote -# golang.org/x/mod v0.36.1-0.20260520130633-087f6515dd3b +# golang.org/x/mod v0.38.0 ## explicit; go 1.25.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.20.0 +# golang.org/x/sync v0.22.0 ## explicit; go 1.25.0 golang.org/x/sync/errgroup golang.org/x/sync/semaphore -# golang.org/x/sys v0.45.0 +# golang.org/x/sys v0.47.0 ## explicit; go 1.25.0 golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2 +# golang.org/x/telemetry v0.0.0-20260716142750-dad6939de390 ## explicit; go 1.25.0 golang.org/x/telemetry golang.org/x/telemetry/counter @@ -60,10 +60,10 @@ golang.org/x/telemetry/internal/crashmonitor golang.org/x/telemetry/internal/mmap golang.org/x/telemetry/internal/telemetry golang.org/x/telemetry/internal/upload -# golang.org/x/term v0.43.0 +# golang.org/x/term v0.45.0 ## explicit; go 1.25.0 golang.org/x/term -# golang.org/x/text v0.37.0 +# golang.org/x/text v0.40.0 ## explicit; go 1.25.0 golang.org/x/text/cases golang.org/x/text/internal @@ -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.45.1-0.20260714184632-28657d66a087 +# golang.org/x/tools v0.48.1-0.20260715233119-591dfa620de7 ## explicit; go 1.25.0 golang.org/x/tools/cmd/bisect golang.org/x/tools/cover @@ -138,7 +138,6 @@ golang.org/x/tools/internal/diff golang.org/x/tools/internal/diff/lcs golang.org/x/tools/internal/facts golang.org/x/tools/internal/fmtstr -golang.org/x/tools/internal/goplsexport golang.org/x/tools/internal/moreiters golang.org/x/tools/internal/packagepath golang.org/x/tools/internal/refactor diff --git a/src/go.mod b/src/go.mod index bb6abc93792f39..31cff08cfb0658 100644 --- a/src/go.mod +++ b/src/go.mod @@ -1,13 +1,13 @@ module std -go 1.27 +go 1.28 require ( - golang.org/x/crypto v0.52.1-0.20260526024921-9beb694f9766 - golang.org/x/net v0.55.1-0.20260526154343-657eb1317b5d + golang.org/x/crypto v0.54.1-0.20260714033321-10b54ffa51b1 + golang.org/x/net v0.57.1-0.20260714001123-e7e2eb826435 ) require ( - golang.org/x/sys v0.45.0 // indirect - golang.org/x/text v0.37.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/text v0.40.0 // indirect ) diff --git a/src/go.sum b/src/go.sum index ab34844da17757..829e8fbf4b3026 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,8 +1,8 @@ -golang.org/x/crypto v0.52.1-0.20260526024921-9beb694f9766 h1:ABD+jVg0H4Hwu2sGcUtKeb3T8mlS+jS3uWrkTAPcXjs= -golang.org/x/crypto v0.52.1-0.20260526024921-9beb694f9766/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= -golang.org/x/net v0.55.1-0.20260526154343-657eb1317b5d h1:G6GZDsxGyGK2SxMEqnPJfBWRKGCNpWheup5btZYkYpw= -golang.org/x/net v0.55.1-0.20260526154343-657eb1317b5d/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/crypto v0.54.1-0.20260714033321-10b54ffa51b1 h1:vGPAn+SBeT/HVkWqXTwgapJgtGQJztG0WR0OTuHzMAI= +golang.org/x/crypto v0.54.1-0.20260714033321-10b54ffa51b1/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/net v0.57.1-0.20260714001123-e7e2eb826435 h1:F2VkyVpi+/NElkyxEdnKyWzMLTGeSpJBbLgHJKS1rJ0= +golang.org/x/net v0.57.1-0.20260714001123-e7e2eb826435/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= +golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= diff --git a/src/vendor/golang.org/x/net/dns/dnsmessage/svcb.go b/src/vendor/golang.org/x/net/dns/dnsmessage/svcb.go index 4840516a7f88e5..977d91eadc0e32 100644 --- a/src/vendor/golang.org/x/net/dns/dnsmessage/svcb.go +++ b/src/vendor/golang.org/x/net/dns/dnsmessage/svcb.go @@ -168,9 +168,8 @@ func (r *SVCBResource) pack(msg []byte, _ map[string]uint16, _ int) ([]byte, err if err != nil { return oldMsg, &nestedError{"SVCBResource.Target", err} } - var previousKey SVCParamKey for i, param := range r.Params { - if i > 0 && param.Key <= previousKey { + if i > 0 && param.Key <= r.Params[i-1].Key { return oldMsg, &nestedError{"SVCBResource.Params", errParamOutOfOrder} } if len(param.Value) > (1<<16)-1 { @@ -189,6 +188,10 @@ func unpackSVCBResource(msg []byte, off int, length uint16) (SVCBResource, error paramsOff := off bodyEnd := off + int(length) + if bodyEnd > len(msg) { + return SVCBResource{}, errResourceLen + } + var err error if r.Priority, paramsOff, err = unpackUint16(msg, paramsOff); err != nil { return SVCBResource{}, &nestedError{"Priority", err} @@ -205,7 +208,7 @@ func unpackSVCBResource(msg []byte, off int, length uint16) (SVCBResource, error off = paramsOff var previousKey uint16 for off < bodyEnd { - var key, len uint16 + var key, size uint16 if key, off, err = unpackUint16(msg, off); err != nil { return SVCBResource{}, &nestedError{"Params key", err} } @@ -214,14 +217,15 @@ func unpackSVCBResource(msg []byte, off int, length uint16) (SVCBResource, error // consider the RR malformed if the SvcParamKeys are not in strictly increasing numeric order return SVCBResource{}, &nestedError{"Params", errParamOutOfOrder} } - if len, off, err = unpackUint16(msg, off); err != nil { + if size, off, err = unpackUint16(msg, off); err != nil { return SVCBResource{}, &nestedError{"Params value length", err} } - if off+int(len) > bodyEnd { + if off+int(size) > bodyEnd { return SVCBResource{}, errResourceLen } - totalValueLen += len - off += int(len) + previousKey = key + totalValueLen += size + off += int(size) n++ } if off != bodyEnd { @@ -236,20 +240,23 @@ func unpackSVCBResource(msg []byte, off int, length uint16) (SVCBResource, error off = paramsOff for i := 0; i < n; i++ { p := &r.Params[i] - var key, len uint16 + var key, size uint16 if key, off, err = unpackUint16(msg, off); err != nil { return SVCBResource{}, &nestedError{"param key", err} } p.Key = SVCParamKey(key) - if len, off, err = unpackUint16(msg, off); err != nil { + if size, off, err = unpackUint16(msg, off); err != nil { return SVCBResource{}, &nestedError{"param length", err} } - if copy(valuesBuf, msg[off:off+int(len)]) != int(len) { + if len(msg[off:]) < int(size) { + return SVCBResource{}, &nestedError{"param value", errCalcLen} + } + if copy(valuesBuf, msg[off:][:int(size)]) != int(size) { return SVCBResource{}, &nestedError{"param value", errCalcLen} } - p.Value = valuesBuf[:len:len] - valuesBuf = valuesBuf[len:] - off += int(len) + p.Value = valuesBuf[:size:size] + valuesBuf = valuesBuf[size:] + off += int(size) } return r, nil diff --git a/src/vendor/golang.org/x/net/idna/idna.go b/src/vendor/golang.org/x/net/idna/idna.go index 22767125bf3e88..e2f28fed489d7b 100644 --- a/src/vendor/golang.org/x/net/idna/idna.go +++ b/src/vendor/golang.org/x/net/idna/idna.go @@ -400,7 +400,11 @@ func (p *Profile) process(s string, toASCII bool) (string, error) { // Spec says keep the old label. continue } - if unicode16 && err == nil && len(u) > 0 && isASCII(u) { + if err == nil && len(u) > 0 && isASCII(u) { + // UTS 43 pre-revision 33 doesn't classify a xn-- label + // which contains only ASCII characters as an error, + // but that's a specification bug and a security issue. + // Always return an error in this case. err = punyError(enc) } isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight diff --git a/src/vendor/golang.org/x/net/internal/http3/body.go b/src/vendor/golang.org/x/net/internal/http3/body.go index 169417c858630b..c80bc75bfd5a63 100644 --- a/src/vendor/golang.org/x/net/internal/http3/body.go +++ b/src/vendor/golang.org/x/net/internal/http3/body.go @@ -108,8 +108,8 @@ func (w *bodyWriter) Close() error { w.st.writeVarint(int64(len(encTrailer))) w.st.Write(encTrailer) } - if w.st != nil && w.st.stream != nil { - w.st.stream.CloseWrite() + if w.st != nil { + w.st.CloseWrite() } return nil } @@ -121,15 +121,14 @@ type bodyReader struct { mu sync.Mutex remain int64 err error - // If not nil, the body contains an "Expect: 100-continue" header, and - // send100Continue should be called when Read is invoked for the first - // time. - send100Continue func() // A map where the key represents the trailer header names we expect. If // there is a HEADERS frame after reading DATA frames to EOF, the value of - // the headers will be written here, provided that the name of the header - // exists in the map already. - trailer http.Header + // the headers will be written here. Keys in the map are assumed to be + // canonicalized. + // If filterTrailer is true, headers that are not already in the map will + // be ignored; otherwise, all headers will be added to the map. + trailer http.Header + filterTrailer bool } func (r *bodyReader) Read(p []byte) (n int, err error) { @@ -138,10 +137,6 @@ func (r *bodyReader) Read(p []byte) (n int, err error) { // Use a mutex here to provide the same behavior. r.mu.Lock() defer r.mu.Unlock() - if r.send100Continue != nil { - r.send100Continue() - r.send100Continue = nil - } if r.err != nil { return 0, r.err } @@ -188,8 +183,16 @@ func (r *bodyReader) Read(p []byte) (n int, err error) { } var dec qpackDecoder if err := dec.decode(r.st, func(_ indexType, name, value string) error { + if r.trailer == nil { + return nil + } + if !validWireHeaderFieldName(name) || !httpguts.ValidHeaderFieldValue(value) { + return nil + } name = textproto.CanonicalMIMEHeaderKey(textproto.TrimString(name)) - if _, ok := r.trailer[name]; ok { + if !r.filterTrailer { + r.trailer.Add(name, value) + } else if _, ok := r.trailer[name]; ok { r.trailer.Add(name, value) } return nil @@ -222,9 +225,11 @@ func (r *bodyReader) Read(p []byte) (n int, err error) { func (r *bodyReader) Close() error { // Unlike the HTTP/1 and HTTP/2 body readers (at the time of this comment being written), // calling Close concurrently with Read will interrupt the read. - r.st.stream.CloseRead() + r.st.CloseRead() // Make sure that any data that has already been written to bodyReader // cannot be read after it has been closed. + r.mu.Lock() + defer r.mu.Unlock() r.err = net.ErrClosed r.remain = 0 return nil diff --git a/src/vendor/golang.org/x/net/internal/http3/conn.go b/src/vendor/golang.org/x/net/internal/http3/conn.go index 6a3c962b41b685..a90464e4fe73ae 100644 --- a/src/vendor/golang.org/x/net/internal/http3/conn.go +++ b/src/vendor/golang.org/x/net/internal/http3/conn.go @@ -99,14 +99,14 @@ func (c *genericConn) handleStreamError(st *stream, h streamHandler, err error) case *connectionError: h.abort(err) case nil: - st.stream.CloseRead() - st.stream.CloseWrite() + st.CloseRead() + st.CloseWrite() case *streamError: - st.stream.CloseRead() - st.stream.Reset(uint64(err.code)) + st.CloseRead() + st.Reset(uint64(err.code)) default: - st.stream.CloseRead() - st.stream.Reset(uint64(errH3InternalError)) + st.CloseRead() + st.Reset(uint64(errH3InternalError)) } } diff --git a/src/vendor/golang.org/x/net/internal/http3/gzip.go b/src/vendor/golang.org/x/net/internal/http3/gzip.go new file mode 100644 index 00000000000000..8854f2b511cf25 --- /dev/null +++ b/src/vendor/golang.org/x/net/internal/http3/gzip.go @@ -0,0 +1,125 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package http3 + +import ( + "compress/flate" + "compress/gzip" + "errors" + "io" + "io/fs" + "sync" +) + +var errConcurrentReadOnResBody = errors.New("http3: concurrent read on response body") + +// gzipReader wraps a response body so it can lazily +// get gzip.Reader from the pool on the first call to Read. +// After Close is called it puts gzip.Reader to the pool immediately +// if there is no Read in progress or later when Read completes. +type gzipReader struct { + body io.ReadCloser // underlying Response.Body + mu sync.Mutex // guards zr and zerr + zr *gzip.Reader // stores gzip reader from the pool between reads + zerr error // sticky gzip reader init error or sentinel value to detect concurrent read and read after close +} + +type eofReader struct{} + +func (eofReader) Read([]byte) (int, error) { return 0, io.EOF } +func (eofReader) ReadByte() (byte, error) { return 0, io.EOF } + +var gzipPool = sync.Pool{New: func() any { return new(gzip.Reader) }} + +// gzipPoolGet gets a gzip.Reader from the pool and resets it to read from r. +func gzipPoolGet(r io.Reader) (*gzip.Reader, error) { + zr := gzipPool.Get().(*gzip.Reader) + if err := zr.Reset(r); err != nil { + gzipPoolPut(zr) + return nil, err + } + return zr, nil +} + +// gzipPoolPut puts a gzip.Reader back into the pool. +func gzipPoolPut(zr *gzip.Reader) { + // Reset will allocate bufio.Reader if we pass it anything + // other than a flate.Reader, so ensure that it's getting one. + var r flate.Reader = eofReader{} + zr.Reset(r) + gzipPool.Put(zr) +} + +// acquire returns a gzip.Reader for reading response body. +// The reader must be released after use. +func (gz *gzipReader) acquire() (*gzip.Reader, error) { + gz.mu.Lock() + defer gz.mu.Unlock() + if gz.zerr != nil { + return nil, gz.zerr + } + if gz.zr == nil { + // gzipPoolGet might block indefinitely since it reads the gzip header. + // Therefore, drop mu temporarily when using gzipPoolGet. + // We set zerr to errConcurrentReadOnResBody to prevent concurrent read + // even when mu is temporarily dropped. + gz.zerr = errConcurrentReadOnResBody + gz.mu.Unlock() + zr, err := gzipPoolGet(gz.body) + gz.mu.Lock() + // Guard against Close being called while gzipPoolGet is running. + if gz.zerr != errConcurrentReadOnResBody { + if zr != nil { + gzipPoolPut(zr) + } + return nil, gz.zerr + } + gz.zr, gz.zerr = zr, err + if gz.zerr != nil { + return nil, gz.zerr + } + } + ret := gz.zr + gz.zr, gz.zerr = nil, errConcurrentReadOnResBody + return ret, nil +} + +// release returns the gzip.Reader to the pool if Close was called during Read. +func (gz *gzipReader) release(zr *gzip.Reader) { + gz.mu.Lock() + defer gz.mu.Unlock() + if gz.zerr == errConcurrentReadOnResBody { + gz.zr, gz.zerr = zr, nil + } else { // fs.ErrClosed + gzipPoolPut(zr) + } +} + +// close returns the gzip.Reader to the pool immediately or +// signals release to do so after Read completes. +func (gz *gzipReader) close() { + gz.mu.Lock() + defer gz.mu.Unlock() + if gz.zerr == nil && gz.zr != nil { + gzipPoolPut(gz.zr) + gz.zr = nil + } + gz.zerr = fs.ErrClosed +} + +func (gz *gzipReader) Read(p []byte) (n int, err error) { + zr, err := gz.acquire() + if err != nil { + return 0, err + } + defer gz.release(zr) + + return zr.Read(p) +} + +func (gz *gzipReader) Close() error { + gz.close() + + return gz.body.Close() +} diff --git a/src/vendor/golang.org/x/net/internal/http3/qpack.go b/src/vendor/golang.org/x/net/internal/http3/qpack.go index e400d83e014887..423b5aae2491bd 100644 --- a/src/vendor/golang.org/x/net/internal/http3/qpack.go +++ b/src/vendor/golang.org/x/net/internal/http3/qpack.go @@ -5,8 +5,10 @@ package http3 import ( + "encoding/binary" "errors" "io" + "math" "golang.org/x/net/http/httpguts" "golang.org/x/net/http2/hpack" @@ -225,25 +227,19 @@ func (st *stream) readPrefixedInt(prefixLen uint8) (firstByte byte, v int64, err // readPrefixedIntWithByte reads an RFC 7541 prefixed integer from st. // The first byte has already been read from the stream. -func (st *stream) readPrefixedIntWithByte(firstByte byte, prefixLen uint8) (v int64, err error) { +func (st *stream) readPrefixedIntWithByte(firstByte byte, prefixLen uint8) (int64, error) { prefixMask := (byte(1) << prefixLen) - 1 - v = int64(firstByte & prefixMask) - if v != int64(prefixMask) { - return v, nil + if v := firstByte & prefixMask; v != prefixMask { + return int64(v), nil } - m := 0 - for { - b, err := st.ReadByte() - if err != nil { - return 0, errQPACKDecompressionFailed - } - v += int64(b&127) << m - m += 7 - if b&128 == 0 { - break - } + v, err := binary.ReadUvarint(st) + if err != nil { + return 0, errQPACKDecompressionFailed } - return v, err + if v > math.MaxInt64-uint64(prefixMask) { + return 0, errQPACKDecompressionFailed + } + return int64(v + uint64(prefixMask)), nil } // appendPrefixedInt appends an RFC 7541 prefixed integer to b. @@ -258,11 +254,7 @@ func appendPrefixedInt(b []byte, firstByte byte, prefixLen uint8, i int64) []byt } b = append(b, firstByte|byte(prefixMask)) u -= prefixMask - for u >= 128 { - b = append(b, 0x80|byte(u&0x7f)) - u >>= 7 - } - return append(b, byte(u)) + return binary.AppendUvarint(b, u) } // String literal encoding from RFC 7541, section 5.2 @@ -291,6 +283,9 @@ func (st *stream) readPrefixedStringWithByte(firstByte byte, prefixLen uint8) (s if err != nil { return "", errQPACKDecompressionFailed } + if st.lim >= 0 && size > st.lim { + return "", errQPACKDecompressionFailed + } hbit := byte(1) << prefixLen isHuffman := firstByte&hbit != 0 diff --git a/src/vendor/golang.org/x/net/internal/http3/qpack_static.go b/src/vendor/golang.org/x/net/internal/http3/qpack_static.go index 6c0b51c5e67ae0..395554cd7c8cb3 100644 --- a/src/vendor/golang.org/x/net/internal/http3/qpack_static.go +++ b/src/vendor/golang.org/x/net/internal/http3/qpack_static.go @@ -13,7 +13,7 @@ type tableEntry struct { // staticTableEntry returns the static table entry with the given index. func staticTableEntry(index int64) (tableEntry, error) { - if index >= int64(len(staticTableEntries)) { + if index < 0 || index >= int64(len(staticTableEntries)) { return tableEntry{}, errQPACKDecompressionFailed } return staticTableEntries[index], nil diff --git a/src/vendor/golang.org/x/net/internal/http3/roundtrip.go b/src/vendor/golang.org/x/net/internal/http3/roundtrip.go index edf5f1330b912e..c5aab72b2d5d67 100644 --- a/src/vendor/golang.org/x/net/internal/http3/roundtrip.go +++ b/src/vendor/golang.org/x/net/internal/http3/roundtrip.go @@ -11,6 +11,7 @@ import ( "net/http/httptrace" "net/textproto" "strconv" + "strings" "sync" "golang.org/x/net/http/httpguts" @@ -41,15 +42,21 @@ type roundTripState struct { func (rt *roundTripState) abort(err error) error { rt.errOnce.Do(func() { rt.err = err + + rt.cc.mu.Lock() + rt.cc.active-- + rt.cc.mu.Unlock() + rt.cc.maybeCallStateHook() + switch e := err.(type) { case *connectionError: rt.cc.abort(e) case *streamError: - rt.st.stream.CloseRead() - rt.st.stream.Reset(uint64(e.code)) + rt.st.CloseRead() + rt.st.Reset(uint64(e.code)) default: - rt.st.stream.CloseRead() - rt.st.stream.Reset(uint64(errH3NoError)) + rt.st.CloseRead() + rt.st.Reset(uint64(errH3NoError)) } }) return rt.err @@ -88,9 +95,20 @@ func (rt *roundTripState) maybeCallWait100Continue() { // RoundTrip sends a request on the connection. func (cc *clientConn) RoundTrip(req *http.Request) (_ *http.Response, err error) { + cc.mu.Lock() + if cc.reserved > 0 { + cc.reserved-- + } + cc.active++ + cc.mu.Unlock() + // Each request gets its own QUIC stream. st, err := newConnStream(req.Context(), cc.qconn, streamTypeRequest) if err != nil { + cc.mu.Lock() + cc.active-- + cc.mu.Unlock() + cc.maybeCallStateHook() return nil, err } rt := &roundTripState{ @@ -112,6 +130,7 @@ func (cc *clientConn) RoundTrip(req *http.Request) (_ *http.Response, err error) st.stream.SetReadContext(req.Context()) st.stream.SetWriteContext(req.Context()) + addedGzip := httpcommon.IsRequestGzip(req.Method, req.Header, cc.tr.tr1.DisableCompression) headers := cc.enc.encode(func(yield func(itype indexType, name, value string)) { _, err = httpcommon.EncodeHeaders(req.Context(), httpcommon.EncodeHeadersParam{ Request: httpcommon.Request{ @@ -122,7 +141,7 @@ func (cc *clientConn) RoundTrip(req *http.Request) (_ *http.Response, err error) Trailer: req.Trailer, ActualContentLength: actualContentLength(req), }, - AddGzipHeader: false, // TODO: add when appropriate + AddGzipHeader: addedGzip, PeerMaxHeaderListSize: 0, DefaultUserAgent: "Go-http-client/3", }, func(name, value string) { @@ -215,7 +234,13 @@ func (cc *clientConn) RoundTrip(req *http.Request) (_ *http.Response, err error) Trailer: trailer, Body: (*transportResponseBody)(rt), } - // TODO: Automatic Content-Type: gzip decoding. + if addedGzip && strings.EqualFold(h.Get("Content-Encoding"), "gzip") { + resp.Body = &gzipReader{body: resp.Body} + h.Del("Content-Encoding") + h.Del("Content-Length") + resp.ContentLength = -1 + resp.Uncompressed = true + } return resp, nil case frameTypePushPromise: if err := cc.handlePushPromise(st); err != nil { @@ -290,7 +315,7 @@ func (b *transportResponseBody) Close() error { rt.closeReqBody() // Close the request stream, since we're done with the request. // Reset closes the sending half of the stream. - rt.st.stream.Reset(uint64(errH3NoError)) + rt.st.Reset(uint64(errH3NoError)) // respBody.Close is responsible for closing the receiving half. err := rt.respBody.Close() if err == nil { diff --git a/src/vendor/golang.org/x/net/internal/http3/server.go b/src/vendor/golang.org/x/net/internal/http3/server.go index fde5d3ddd06487..ef7d9a457e6eb4 100644 --- a/src/vendor/golang.org/x/net/internal/http3/server.go +++ b/src/vendor/golang.org/x/net/internal/http3/server.go @@ -7,10 +7,12 @@ package http3 import ( "context" "crypto/tls" + "errors" "fmt" - "io" "maps" "net/http" + "net/textproto" + "os" "slices" "strconv" "strings" @@ -26,10 +28,9 @@ import ( // The zero value for server is a valid server. type server struct { // handler to invoke for requests, http.DefaultServeMux if nil. - handler http.Handler - - config *quic.Config - + handler http.Handler + config *quic.Config + srv1 *http.Server listenQUIC func(addr string, config *quic.Config) (*quic.Endpoint, error) initOnce sync.Once @@ -98,6 +99,7 @@ func RegisterServer(s *http.Server, opts ServerOpts) { s3 := &server{ config: opts.QUICConfig, listenQUIC: opts.ListenQUIC, + srv1: s, handler: stdHandler, serveCtx: stdHandler.BaseContext(), } @@ -151,7 +153,7 @@ func (s *server) serve(e *quic.Endpoint) error { if err != nil { return err } - go s.newServerConn(qconn, s.handler) + go s.newServerConn(qconn) } } @@ -222,13 +224,42 @@ func (s *server) unregisterConn(sc *serverConn) { } } +func (s *server) readHeaderTimeout() time.Duration { + if s.srv1 == nil || s.srv1.ReadHeaderTimeout == 0 { + return s.readTimeout() + } + return s.srv1.ReadHeaderTimeout +} + +func (s *server) readTimeout() time.Duration { + if s.srv1 == nil { + return 0 + } + return s.srv1.ReadTimeout +} + +func (s *server) writeTimeout() time.Duration { + if s.srv1 == nil { + return 0 + } + return s.srv1.WriteTimeout +} + +// TODO: this is currently unused, enforce it. +func (s *server) idleTimeout() time.Duration { + if s.srv1 == nil || s.srv1.IdleTimeout == 0 { + return s.readTimeout() + } + return s.srv1.IdleTimeout +} + type serverConn struct { qconn *quic.Conn + srv *server genericConn // for handleUnidirectionalStream enc qpackEncoder dec qpackDecoder - handler http.Handler // For handling shutdown. controlStream *stream @@ -237,10 +268,10 @@ type serverConn struct { goawaySent bool } -func (s *server) newServerConn(qconn *quic.Conn, handler http.Handler) { +func (s *server) newServerConn(qconn *quic.Conn) { sc := &serverConn{ - qconn: qconn, - handler: handler, + qconn: qconn, + srv: s, } s.registerConn(sc) defer s.unregisterConn(sc) @@ -324,7 +355,7 @@ func (sc *serverConn) handlePushStream(*stream) error { } } -// hasDisallowedConnectionHeader reports whether h contains connnection headers +// hasDisallowedConnectionHeader reports whether h contains connection headers // that are not allowed in HTTP/3: // // "An endpoint MUST NOT generate an HTTP/3 field section containing @@ -477,11 +508,27 @@ func (sc *serverConn) handleRequestStream(st *stream) error { message: "GOAWAY request with equal or lower ID than the stream has been sent", } } + + readStartTime := time.Now() + if t := sc.srv.readHeaderTimeout(); t > 0 { + st.readDeadline.set(readStartTime.Add(t)) + } header, pHeader, err := sc.parseHeader(st) if err != nil { + if errors.Is(err, os.ErrDeadlineExceeded) { + return &streamError{ + code: errH3RequestRejected, + message: "exceeded deadline while parsing header", + } + } return err } + if t := sc.srv.readTimeout(); t > 0 { + st.readDeadline.set(readStartTime.Add(t)) + } else { + st.readDeadline.set(time.Time{}) + } reqInfo := httpcommon.NewServerRequest(httpcommon.ServerRequestParam{ Method: pHeader.method, Scheme: pHeader.scheme, @@ -496,20 +543,10 @@ func (sc *serverConn) handleRequestStream(st *stream) error { } } - var body io.ReadCloser contentLength := int64(-1) if n, err := strconv.Atoi(header.Get("Content-Length")); err == nil { contentLength = int64(n) } - if contentLength != 0 || len(reqInfo.Trailer) != 0 { - body = &bodyReader{ - st: st, - remain: contentLength, - trailer: reqInfo.Trailer, - } - } else { - body = http.NoBody - } req := &http.Request{ Proto: "HTTP/3.0", @@ -520,11 +557,9 @@ func (sc *serverConn) handleRequestStream(st *stream) error { Trailer: reqInfo.Trailer, ProtoMajor: 3, RemoteAddr: sc.qconn.RemoteAddr().String(), - Body: body, Header: header, ContentLength: contentLength, } - defer req.Body.Close() rw := &responseWriter{ st: st, @@ -540,16 +575,29 @@ func (sc *serverConn) handleRequestStream(st *stream) error { enc: &sc.enc, }, } - defer rw.close() - if reqInfo.NeedsContinue { - req.Body.(*bodyReader).send100Continue = func() { - rw.WriteHeader(100) + + if contentLength != 0 || len(reqInfo.Trailer) != 0 { + req.Body = &serverRequestReader{ + rw: rw, + br: bodyReader{ + st: st, + remain: contentLength, + trailer: reqInfo.Trailer, + filterTrailer: true, + }, + needsContinue: reqInfo.NeedsContinue, } + defer req.Body.Close() + } else { + req.Body = http.NoBody } // TODO: handle panic coming from the HTTP handler. - sc.handler.ServeHTTP(rw, req) - return nil + if t := sc.srv.writeTimeout(); t > 0 { + st.writeDeadline.set(time.Now().Add(t)) + } + sc.srv.handler.ServeHTTP(rw, req) + return rw.close() } // abort closes the connection with an error. @@ -578,16 +626,23 @@ func responseCanHaveBody(status int) bool { return true } +// trailerPrefix is a magic prefix for [responseWriter.Header] map keys that, +// if present, signals that the map entry is actually for the response +// trailers, and not the response headers. See [net/http.TrailerPrefix] for +// details. +const trailerPrefix = "Trailer:" + type responseWriter struct { st *stream bw *bodyWriter mu sync.Mutex headers http.Header + snapHeaders http.Header // Snapshot of headers at WriteHeader time trailer http.Header bb bodyBuffer wroteHeader bool // Non-1xx header has been (logically) written. - statusCode int // Status of the response that will be sent in HEADERS frame. - statusCodeSet bool // Status of the response has been set via a call to WriteHeader. + statusCode int // Non-1xx status of the response that will be sent in HEADERS frame. Zero means none has been set. + sent100 bool // Status 100 has been sent by the server. cannotHaveBody bool // Response should not have a body (e.g. response to a HEAD request). bodyLenLeft int // How much of the content body is left to be sent, set via "Content-Length" header. -1 if unknown. } @@ -607,6 +662,12 @@ func (rw *responseWriter) prepareTrailerForWriteLocked() { delete(rw.trailer, name) } } + for name, vals := range rw.headers { + if name, found := strings.CutPrefix(name, trailerPrefix); found { + name = textproto.CanonicalMIMEHeaderKey(textproto.TrimString(name)) + rw.trailer[name] = vals + } + } if len(rw.trailer) > 0 { rw.bw.trailer = rw.trailer } @@ -623,18 +684,18 @@ func (rw *responseWriter) writeHeaderLockedOnce() { if !responseCanHaveBody(rw.statusCode) { rw.cannotHaveBody = true } - // If there is any Trailer declared in headers, save them so we know which - // trailers have been pre-declared. Also, write back the extracted value, - // which is canonicalized, to rw.Header for consistency. - if _, ok := rw.headers["Trailer"]; ok { - extractTrailerFromHeader(rw.headers, rw.trailer) - rw.headers.Set("Trailer", strings.Join(slices.Sorted(maps.Keys(rw.trailer)), ", ")) + // If there is any Trailer declared, save them so we know which trailers + // have been pre-declared. Also, write back the extracted value, which is + // canonicalized, for consistency. + if _, ok := rw.snapHeaders["Trailer"]; ok { + extractTrailerFromHeader(rw.snapHeaders, rw.trailer) + rw.snapHeaders.Set("Trailer", strings.Join(slices.Sorted(maps.Keys(rw.trailer)), ", ")) } - rw.bb.inferHeader(rw.headers, rw.statusCode) + rw.bb.inferHeader(rw.snapHeaders, rw.statusCode) encHeaders := rw.bw.enc.encode(func(f func(itype indexType, name, value string)) { f(mayIndex, ":status", strconv.Itoa(rw.statusCode)) - for name, values := range rw.headers { + for name, values := range rw.snapHeaders { if !httpguts.ValidHeaderFieldName(name) { continue } @@ -662,6 +723,12 @@ func (rw *responseWriter) writeHeaderLocked(statusCode int) { if rw.wroteHeader { return } + if statusCode == 100 { + if rw.sent100 { + return + } + rw.sent100 = true + } encHeaders := rw.bw.enc.encode(func(f func(itype indexType, name, value string)) { f(mayIndex, ":status", strconv.Itoa(statusCode)) for name, values := range rw.headers { @@ -710,7 +777,7 @@ func (rw *responseWriter) WriteHeader(statusCode int) { // TODO: handle sending informational status headers (e.g. 103). rw.mu.Lock() defer rw.mu.Unlock() - if rw.statusCodeSet { + if rw.statusCode != 0 { return } checkWriteHeaderCode(statusCode) @@ -725,8 +792,8 @@ func (rw *responseWriter) WriteHeader(statusCode int) { // Non-informational headers should only be set once, and should be // buffered. - rw.statusCodeSet = true rw.statusCode = statusCode + rw.snapHeaders = rw.headers.Clone() if n, err := strconv.Atoi(rw.Header().Get("Content-Length")); err == nil { rw.bodyLenLeft = n } else { @@ -796,7 +863,22 @@ func (rw *responseWriter) Write(b []byte) (n int, err error) { return initialBLen, nil } -func (rw *responseWriter) Flush() { +func (rw *responseWriter) SetReadDeadline(deadline time.Time) error { + rw.st.readDeadline.set(deadline) + return nil +} + +func (rw *responseWriter) SetWriteDeadline(deadline time.Time) error { + rw.st.writeDeadline.set(deadline) + return nil +} + +func (rw *responseWriter) EnableFullDuplex() error { + return nil +} + +func (rw *responseWriter) Flush() { rw.FlushError() } +func (rw *responseWriter) FlushError() error { // Calling Flush implicitly calls WriteHeader(200) if WriteHeader has not // been called before. rw.WriteHeader(http.StatusOK) @@ -804,21 +886,37 @@ func (rw *responseWriter) Flush() { defer rw.mu.Unlock() rw.writeHeaderLockedOnce() if !rw.cannotHaveBody { - rw.bw.Write(rw.bb) + _, err := rw.bw.Write(rw.bb) rw.bb.discard() + if err != nil { + return err + } } - rw.st.Flush() + return rw.st.Flush() } func (rw *responseWriter) close() error { - rw.Flush() + if errors.Is(rw.st.writeDeadline.err(), os.ErrDeadlineExceeded) { + return &streamError{ + code: errH3RequestCancelled, + message: "exceeded deadline while writing response", + } + } + + retErr := rw.FlushError() rw.mu.Lock() defer rw.mu.Unlock() rw.prepareTrailerForWriteLocked() - if err := rw.bw.Close(); err != nil { - return err + if err := rw.bw.Close(); retErr == nil { + retErr = err } - return rw.st.stream.Close() + if errors.Is(retErr, os.ErrDeadlineExceeded) { + return &streamError{ + code: errH3RequestCancelled, + message: retErr.Error(), + } + } + return retErr } // defaultBodyBufferCap is the default number of bytes of body that we are @@ -864,3 +962,42 @@ func (bb *bodyBuffer) inferHeader(h http.Header, status int) { // we have chosen not to do so for now as Content-Length is not very // important for HTTP/3, and such inconsistent behavior might be confusing. } + +// serverRequestReader wraps around bodyReader, allowing Read and Close calls +// done from within a server handler to coordinate correctly with the +// responseWriter; for example, sending status 100 on Read when appropriate. +type serverRequestReader struct { + rw *responseWriter + br bodyReader + needsContinue bool +} + +// maybeSendContinue attempts to send a 100 Continue status code. It +// ensures that status 100 will only be sent once and when appropriate. If a +// non-1xx header has been set before 100 was ever set, it also ensures that +// all subsequent Read will fail. +func (srr *serverRequestReader) maybeSendContinue() { + if !srr.needsContinue { + return + } + srr.rw.mu.Lock() + defer srr.rw.mu.Unlock() + if srr.rw.sent100 { + return + } + if srr.rw.statusCode != 0 { + srr.br.Close() + return + } + srr.rw.writeHeaderLocked(100) + srr.rw.st.Flush() +} + +func (srr *serverRequestReader) Read(p []byte) (int, error) { + srr.maybeSendContinue() + return srr.br.Read(p) +} + +func (srr *serverRequestReader) Close() error { + return srr.br.Close() +} diff --git a/src/vendor/golang.org/x/net/internal/http3/stream.go b/src/vendor/golang.org/x/net/internal/http3/stream.go index 93294d43de1fdd..35299838cdf27f 100644 --- a/src/vendor/golang.org/x/net/internal/http3/stream.go +++ b/src/vendor/golang.org/x/net/internal/http3/stream.go @@ -7,6 +7,9 @@ package http3 import ( "context" "io" + "os" + "sync" + "time" "golang.org/x/net/quic" ) @@ -21,6 +24,9 @@ type stream struct { // results in an error. // -1 indicates no limit. lim int64 + + readDeadline deadline + writeDeadline deadline } // newConnStream creates a new stream on a connection. @@ -42,10 +48,7 @@ func newConnStream(ctx context.Context, qconn *quic.Conn, stype streamType) (*st if err != nil { return nil, err } - st := &stream{ - stream: qs, - lim: -1, // no limit - } + st := newStream(qs) if stype != streamTypeRequest { // Unidirectional stream header. st.writeVarint(int64(stype)) @@ -54,9 +57,121 @@ func newConnStream(ctx context.Context, qconn *quic.Conn, stype streamType) (*st } func newStream(qs *quic.Stream) *stream { - return &stream{ + readCtx, readCancel := context.WithCancelCause(context.Background()) + writeCtx, writeCancel := context.WithCancelCause(context.Background()) + st := &stream{ stream: qs, lim: -1, // no limit + readDeadline: deadline{ + ctx: readCtx, + cancel: readCancel, + }, + writeDeadline: deadline{ + ctx: writeCtx, + cancel: writeCancel, + }, + } + qs.SetReadContext(readCtx) + qs.SetWriteContext(writeCtx) + return st +} + +func (st *stream) Close() error { + st.readDeadline.stop() + st.writeDeadline.stop() + return st.stream.Close() +} + +func (st *stream) CloseRead() { + st.readDeadline.stop() + st.stream.CloseRead() +} + +func (st *stream) CloseWrite() { + st.writeDeadline.stop() + st.stream.CloseWrite() +} + +func (st *stream) Reset(code uint64) { + st.readDeadline.stop() + st.writeDeadline.stop() + st.stream.Reset(code) +} + +// deadline manages ctx, and cancels it when timer expires, with +// [os.ErrDeadlineExceeded] as the cause. If the deadline is manually stopped +// before timer expires, the context will be canceled with [context.Canceled] +// as the cause. Once a deadline is exceeded, its timer can no longer be +// extended. +// Practically, this lets the http3 package support time-based deadlines by +// utilizing the quic package's support for context-based deadlines. +type deadline struct { + ctx context.Context + cancel context.CancelCauseFunc + + mu sync.Mutex // Guards below. + timer *time.Timer +} + +// stopTimerLocked stops the deadline timer and sets it to nil. +// The caller must hold d.mu. +func (d *deadline) stopTimerLocked() { + if d.timer != nil { + d.timer.Stop() + d.timer = nil + } +} + +// stop stops the deadline timer and cancels the context with +// [context.Canceled] as the cause. +func (d *deadline) stop() { + d.mu.Lock() + d.stopTimerLocked() + d.mu.Unlock() + d.cancel(context.Canceled) +} + +// err returns the deadline's context cancelation cause, if any. +func (d *deadline) err() error { + return context.Cause(d.ctx) +} + +// errOf returns the deadline's context cancelation cause if the given err is +// non-nil. This can be used to check whether an error value returned by I/O +// operations at the QUIC layer is non-nil because the deadline has expired. +func (d *deadline) errOf(err error) error { + if dErr := d.err(); err != nil && dErr != nil { + return dErr + } + return err +} + +// set configures a new deadline using the given deadlineTime. +// Once deadline is exceeded, it remains in the expired (sticky) state, and +// subsequent attempts to extend or reset the deadline are ignored. +func (d *deadline) set(deadlineTime time.Time) { + d.mu.Lock() + defer d.mu.Unlock() + + if d.ctx.Err() != nil { // Already expired, sticky error. + return + } + if deadlineTime.IsZero() { + d.stopTimerLocked() + return + } + dur := time.Until(deadlineTime) + if dur <= 0 { + d.stopTimerLocked() + d.cancel(os.ErrDeadlineExceeded) + return + } + if d.timer == nil { + d.timer = time.AfterFunc(dur, func() { + d.cancel(os.ErrDeadlineExceeded) + }) + } else { + d.timer.Reset(dur) } } @@ -110,21 +225,36 @@ func (st *stream) readFrameData() ([]byte, error) { // ReadByte reads one byte from the stream. func (st *stream) ReadByte() (b byte, err error) { + // Check the deadline before doing I/O operations on the QUIC layer. We do + // this because the QUIC layer implements a fast path for I/O operations, + // allowing Read & Write to succeed depending on the state of buffer, even + // if its context has been canceled. By always checking the deadline here, + // we make it so that I/O operations fail as soon as its relevant deadline + // has been exceeded. + if err := st.readDeadline.err(); err != nil { + return 0, err + } if err := st.recordBytesRead(1); err != nil { return 0, err } b, err = st.stream.ReadByte() - if err != nil { - if err == io.EOF && st.lim < 0 { - return 0, io.EOF - } + if err == io.EOF && st.lim >= 0 { return 0, errH3FrameError } - return b, nil + return b, st.readDeadline.errOf(err) } // Read reads from the stream. func (st *stream) Read(b []byte) (int, error) { + // Check the deadline before doing I/O operations on the QUIC layer. We do + // this because the QUIC layer implements a fast path for I/O operations, + // allowing Read & Write to succeed depending on the state of buffer, even + // if its context has been canceled. By always checking the deadline here, + // we make it so that I/O operations fail as soon as its relevant deadline + // has been exceeded. + if err := st.readDeadline.err(); err != nil { + return 0, err + } n, err := st.stream.Read(b) if e2 := st.recordBytesRead(n); e2 != nil { return 0, e2 @@ -141,10 +271,7 @@ func (st *stream) Read(b []byte) (int, error) { return n, io.EOF } } - if err != nil { - return 0, errH3FrameError - } - return n, nil + return n, st.readDeadline.errOf(err) } // discardUnknownFrame discards an unknown frame. @@ -173,7 +300,7 @@ func (st *stream) discardUnknownFrame(ftype frameType) error { func (st *stream) discardFrame() error { // TODO: Consider adding a *quic.Stream method to discard some amount of data. for range st.lim { - _, err := st.stream.ReadByte() + _, err := st.ReadByte() if err != nil { return &streamError{errH3FrameError, err.Error()} } @@ -183,29 +310,66 @@ func (st *stream) discardFrame() error { } // Write writes to the stream. -func (st *stream) Write(b []byte) (int, error) { return st.stream.Write(b) } +func (st *stream) Write(b []byte) (int, error) { + // Check the deadline before doing I/O operations on the QUIC layer. We do + // this because the QUIC layer implements a fast path for I/O operations, + // allowing Read & Write to succeed depending on the state of buffer, even + // if its context has been canceled. By always checking the deadline here, + // we make it so that I/O operations fail as soon as its relevant deadline + // has been exceeded. + if err := st.writeDeadline.err(); err != nil { + return 0, err + } + n, err := st.stream.Write(b) + return n, st.writeDeadline.errOf(err) +} // Flush commits data written to the stream. -func (st *stream) Flush() error { return st.stream.Flush() } +func (st *stream) Flush() error { + // Check the deadline before doing I/O operations on the QUIC layer. We do + // this because the QUIC layer implements a fast path for I/O operations, + // allowing Read & Write to succeed depending on the state of buffer, even + // if its context has been canceled. By always checking the deadline here, + // we make it so that I/O operations fail as soon as its relevant deadline + // has been exceeded. + if err := st.writeDeadline.err(); err != nil { + return err + } + return st.writeDeadline.errOf(st.stream.Flush()) +} + +// WriteByte writes one byte to the stream. +func (st *stream) WriteByte(c byte) error { + // Check the deadline before doing I/O operations on the QUIC layer. We do + // this because the QUIC layer implements a fast path for I/O operations, + // allowing Read & Write to succeed depending on the state of buffer, even + // if its context has been canceled. By always checking the deadline here, + // we make it so that I/O operations fail as soon as its relevant deadline + // has been exceeded. + if err := st.writeDeadline.err(); err != nil { + return err + } + return st.writeDeadline.errOf(st.stream.WriteByte(c)) +} // readVarint reads a QUIC variable-length integer from the stream. func (st *stream) readVarint() (v int64, err error) { - b, err := st.stream.ReadByte() + b, err := st.ReadByte() if err != nil { return 0, err } v = int64(b & 0x3f) n := 1 << (b >> 6) for i := 1; i < n; i++ { - b, err := st.stream.ReadByte() + b, err := st.ReadByte() if err != nil { - return 0, errH3FrameError + if err == io.EOF { + return 0, errH3FrameError + } + return 0, err } v = (v << 8) | int64(b) } - if err := st.recordBytesRead(n); err != nil { - return 0, err - } return v, nil } @@ -219,24 +383,24 @@ func readVarint[T ~int64 | ~uint64](st *stream) (T, error) { func (st *stream) writeVarint(v int64) { switch { case v <= (1<<6)-1: - st.stream.WriteByte(byte(v)) + st.WriteByte(byte(v)) case v <= (1<<14)-1: - st.stream.WriteByte((1 << 6) | byte(v>>8)) - st.stream.WriteByte(byte(v)) + st.WriteByte((1 << 6) | byte(v>>8)) + st.WriteByte(byte(v)) case v <= (1<<30)-1: - st.stream.WriteByte((2 << 6) | byte(v>>24)) - st.stream.WriteByte(byte(v >> 16)) - st.stream.WriteByte(byte(v >> 8)) - st.stream.WriteByte(byte(v)) + st.WriteByte((2 << 6) | byte(v>>24)) + st.WriteByte(byte(v >> 16)) + st.WriteByte(byte(v >> 8)) + st.WriteByte(byte(v)) case v <= (1<<62)-1: - st.stream.WriteByte((3 << 6) | byte(v>>56)) - st.stream.WriteByte(byte(v >> 48)) - st.stream.WriteByte(byte(v >> 40)) - st.stream.WriteByte(byte(v >> 32)) - st.stream.WriteByte(byte(v >> 24)) - st.stream.WriteByte(byte(v >> 16)) - st.stream.WriteByte(byte(v >> 8)) - st.stream.WriteByte(byte(v)) + st.WriteByte((3 << 6) | byte(v>>56)) + st.WriteByte(byte(v >> 48)) + st.WriteByte(byte(v >> 40)) + st.WriteByte(byte(v >> 32)) + st.WriteByte(byte(v >> 24)) + st.WriteByte(byte(v >> 16)) + st.WriteByte(byte(v >> 8)) + st.WriteByte(byte(v)) default: panic("varint too large") } diff --git a/src/vendor/golang.org/x/net/internal/http3/transport.go b/src/vendor/golang.org/x/net/internal/http3/transport.go index 52d9f7c34718e2..16daa24ed6e56c 100644 --- a/src/vendor/golang.org/x/net/internal/http3/transport.go +++ b/src/vendor/golang.org/x/net/internal/http3/transport.go @@ -6,7 +6,9 @@ package http3 import ( "context" + "errors" "fmt" + "math" "net/http" "net/url" "sync" @@ -24,6 +26,7 @@ import ( type transport struct { // config is the QUIC configuration used for client connections. config *quic.Config + tr1 *http.Transport listenQUIC func(addr string, config *quic.Config) (*quic.Endpoint, error) @@ -51,8 +54,8 @@ func (t netHTTPTransport) RoundTrip(*http.Request) (*http.Response, error) { panic("netHTTPTransport.RoundTrip should never be called") } -func (t netHTTPTransport) DialClientConn(ctx context.Context, addr string, _ *url.URL, _ func()) (http.RoundTripper, error) { - return t.transport.dial(ctx, addr) +func (t netHTTPTransport) DialClientConn(ctx context.Context, addr string, _ *url.URL, stateHook func()) (http.RoundTripper, error) { + return t.transport.dial(ctx, addr, stateHook) } type TransportOpts struct { @@ -85,6 +88,7 @@ func RegisterTransport(tr *http.Transport, opts TransportOpts) { tr3 := &transport{ // initConfig will clone the tr.TLSClientConfig. config: initConfig(opts.QUICConfig), + tr1: tr, listenQUIC: opts.ListenQUIC, activeConns: make(map[*clientConn]struct{}), } @@ -138,7 +142,7 @@ func (tr *transport) initEndpoint() (err error) { } // dial creates a new HTTP/3 client connection. -func (tr *transport) dial(ctx context.Context, target string) (*clientConn, error) { +func (tr *transport) dial(ctx context.Context, target string, stateHook func()) (*clientConn, error) { tr.incInFlightDials() defer tr.decInFlightDials() @@ -149,7 +153,7 @@ func (tr *transport) dial(ctx context.Context, target string) (*clientConn, erro if err != nil { return nil, err } - return tr.newClientConn(ctx, qconn) + return tr.newClientConn(ctx, qconn, stateHook) } // CloseIdleConnections is called by net/http.Transport.CloseIdleConnections @@ -172,11 +176,20 @@ func (tr *transport) CloseIdleConnections() { // // Multiple goroutines may invoke methods on a clientConn simultaneously. type clientConn struct { + tr *transport + qconn *quic.Conn genericConn enc qpackEncoder dec qpackDecoder + + // Guarded by genericConn.mu + reserved int + active int + closed bool + + stateHook func() } func (tr *transport) registerConn(cc *clientConn) { @@ -191,9 +204,11 @@ func (tr *transport) unregisterConn(cc *clientConn) { delete(tr.activeConns, cc) } -func (tr *transport) newClientConn(ctx context.Context, qconn *quic.Conn) (*clientConn, error) { +func (tr *transport) newClientConn(ctx context.Context, qconn *quic.Conn, stateHook func()) (*clientConn, error) { cc := &clientConn{ - qconn: qconn, + tr: tr, + qconn: qconn, + stateHook: stateHook, } tr.registerConn(cc) cc.enc.init() @@ -209,12 +224,15 @@ func (tr *transport) newClientConn(ctx context.Context, qconn *quic.Conn) (*clie go func() { cc.acceptStreams(qconn, cc) + cc.mu.Lock() + cc.closed = true + cc.mu.Unlock() tr.unregisterConn(cc) + cc.maybeCallStateHook() }() return cc, nil } -// TODO: implement the rest of net/http.ClientConn methods beyond Close. func (cc *clientConn) Close() error { // We need to use Close rather than Abort on the QUIC connection. // Otherwise, when a net/http.Transport.CloseIdleConnections is called, it @@ -226,22 +244,63 @@ func (cc *clientConn) Close() error { } func (cc *clientConn) Err() error { + cc.mu.Lock() + defer cc.mu.Unlock() + if cc.closed { + return errors.New("connection closed") + } return nil } func (cc *clientConn) Reserve() error { + cc.mu.Lock() + defer cc.mu.Unlock() + if cc.closed { + return errors.New("connection closed") + } + cc.reserved++ return nil } func (cc *clientConn) Release() { + cc.mu.Lock() + defer cc.mu.Unlock() + // This is consistent with RoundTrip: both Release and RoundTrip will + // consume a reservation iff one exists. + if cc.reserved > 0 { + cc.reserved-- + } } func (cc *clientConn) Available() int { - return 0 + cc.mu.Lock() + defer cc.mu.Unlock() + if cc.closed { + return 0 + } + // The general recommendation for HTTP/3 is to reuse the same connection + // for multiple requests rather than creating new connections. As of now, + // we don't have a good understanding of when one might want to create + // multiple HTTP/3 connections to the same server. + // Therefore, for ClientConn API, let HTTP/3 connections have no limit. + // Starting a new RoundTrip when we are at the connection limit will just + // block until a new max stream limit is received. + return math.MaxInt } func (cc *clientConn) InFlight() int { - return 0 + cc.mu.Lock() + defer cc.mu.Unlock() + if cc.closed { + return 0 + } + return cc.reserved + cc.active +} + +func (cc *clientConn) maybeCallStateHook() { + if cc.stateHook != nil { + cc.stateHook() + } } func (cc *clientConn) handleControlStream(st *stream) error { diff --git a/src/vendor/golang.org/x/net/quic/conn_flow.go b/src/vendor/golang.org/x/net/quic/conn_flow.go index b0dbc7268493b1..798c787a755335 100644 --- a/src/vendor/golang.org/x/net/quic/conn_flow.go +++ b/src/vendor/golang.org/x/net/quic/conn_flow.go @@ -17,7 +17,7 @@ import ( // - bytes read by the user // - bytes received from the peer // - limit sent to the peer in a MAX_DATA frame -// - potential new limit to sent to the peer +// - potential new limit to send to the peer // // We maintain a flow control window, so as bytes are read by the user // the potential limit is extended correspondingly. diff --git a/src/vendor/golang.org/x/net/quic/conn_send.go b/src/vendor/golang.org/x/net/quic/conn_send.go index 3e8cf526b51e00..92217c9cfe41e6 100644 --- a/src/vendor/golang.org/x/net/quic/conn_send.go +++ b/src/vendor/golang.org/x/net/quic/conn_send.go @@ -313,7 +313,7 @@ func (c *Conn) appendFrames(now time.Time, space numberSpace, pnum packetNumber, // // A client discards Initial keys when it first sends a Handshake packet // (RFC 9001 Section 4.9.1). Handshake keys are discarded when the handshake - // is confirmed (RFC 9001 Section 4.9.2). The PTO timer is not set for the + // is confirmed (RFC 9001 Section 4.9.2). The PTO timer is not set for the // Application Data packet number space until the handshake is confirmed // (RFC 9002 Section 6.2.1). Therefore, the only times a PTO probe can fire // while data for multiple spaces is in flight are: diff --git a/src/vendor/golang.org/x/net/quic/packet_protection.go b/src/vendor/golang.org/x/net/quic/packet_protection.go index 7856d6b5d8b4e1..5d192b99bc4224 100644 --- a/src/vendor/golang.org/x/net/quic/packet_protection.go +++ b/src/vendor/golang.org/x/net/quic/packet_protection.go @@ -100,7 +100,7 @@ func (k headerKey) unprotect(pkt []byte, pnumOff int, pnumMax packetNumber) (hdr return hdr, pay, pnum, nil } -// headerProtection is the header_protection function as defined in: +// headerProtection is the header_protection function as defined in: // https://www.rfc-editor.org/rfc/rfc9001#section-5.4.1 // // This function takes a sample of the packet ciphertext diff --git a/src/vendor/golang.org/x/net/quic/stream.go b/src/vendor/golang.org/x/net/quic/stream.go index d33778b78564f8..6941e3211b6c3c 100644 --- a/src/vendor/golang.org/x/net/quic/stream.go +++ b/src/vendor/golang.org/x/net/quic/stream.go @@ -424,7 +424,7 @@ func (s *Stream) Write(b []byte) (n int, err error) { // We automatically flush if: // - We have enough data to consume the send window. // Sending this data may cause the peer to extend the window. - // - We have buffered as much data as we're willing do. + // - We have buffered as much data as we're willing to. // We need to send data to clear out buffer space. // - We have enough data to fill a 1-RTT packet using the smallest // possible maximum datagram size (1200 bytes, less header byte, diff --git a/src/vendor/golang.org/x/sys/cpu/parse.go b/src/vendor/golang.org/x/sys/cpu/parse.go index 56a7e1a176f92e..12a99af5c95a8f 100644 --- a/src/vendor/golang.org/x/sys/cpu/parse.go +++ b/src/vendor/golang.org/x/sys/cpu/parse.go @@ -6,38 +6,50 @@ package cpu import "strconv" -// parseRelease parses a dot-separated version number. It follows the semver -// syntax, but allows the minor and patch versions to be elided. +// parseRelease parses a dot-separated version number from the prefix +// of rel. It returns ok=true only if at least the major and minor +// components were successfully parsed; the patch component is +// best-effort. Trailing vendor or build suffixes such as +// "-generic", "+", "_hi3535", or "-rc1" are ignored. // // This is a copy of the Go runtime's parseRelease from -// https://golang.org/cl/209597. +// https://golang.org/cl/209597, updated in https://golang.org/cl/781800. func parseRelease(rel string) (major, minor, patch int, ok bool) { - // Strip anything after a dash or plus. - for i := range len(rel) { - if rel[i] == '-' || rel[i] == '+' { - rel = rel[:i] - break + // next consumes a run of decimal digits from the front of rel, + // returning the parsed value. If the digits are followed by a + // '.', it is consumed and more is set so the caller knows to + // parse another component; otherwise scanning terminates and + // the rest of rel is discarded. + next := func() (n int, more, ok bool) { + i := 0 + for i < len(rel) && rel[i] >= '0' && rel[i] <= '9' { + i++ } - } - - next := func() (int, bool) { - for i := range len(rel) { - if rel[i] == '.' { - ver, err := strconv.Atoi(rel[:i]) - rel = rel[i+1:] - return ver, err == nil - } + if i == 0 { + return 0, false, false + } + n, err := strconv.Atoi(rel[:i]) + if err != nil { + return 0, false, false + } + if i < len(rel) && rel[i] == '.' { + rel = rel[i+1:] + return n, true, true } - ver, err := strconv.Atoi(rel) rel = "" - return ver, err == nil + return n, false, true + } + + var more bool + if major, more, ok = next(); !ok || !more { + return 0, 0, 0, false } - if major, ok = next(); !ok || rel == "" { - return + if minor, more, ok = next(); !ok { + return 0, 0, 0, false } - if minor, ok = next(); !ok || rel == "" { - return + if !more { + return major, minor, 0, true } - patch, ok = next() - return + patch, _, _ = next() + return major, minor, patch, true } diff --git a/src/vendor/golang.org/x/text/unicode/norm/forminfo.go b/src/vendor/golang.org/x/text/unicode/norm/forminfo.go index f3a234e5f53eaf..b3cf5d9bdee236 100644 --- a/src/vendor/golang.org/x/text/unicode/norm/forminfo.go +++ b/src/vendor/golang.org/x/text/unicode/norm/forminfo.go @@ -121,8 +121,12 @@ func (p Properties) BoundaryAfter() bool { // // When all 6 bits are zero, the character is inert, meaning it is never // influenced by normalization. +// +// We set flags to 0x80 (high bit 7 unused in quick check data) to indicate an invalid rune. type qcInfo uint8 +func (p Properties) isInvalid() bool { return p.flags == 0x80 } + func (p Properties) isYesC() bool { return p.flags&0x10 == 0 } func (p Properties) isYesD() bool { return p.flags&0x4 == 0 } @@ -247,6 +251,9 @@ func (f Form) PropertiesString(s string) Properties { // to a Properties. See the comment at the top of the file // for more information on the format. func compInfo(v uint16, sz int) Properties { + if sz == 0 { + return Properties{flags: 0x80, size: 1} + } if v == 0 { return Properties{size: uint8(sz)} } else if v >= 0x8000 { @@ -254,7 +261,7 @@ func compInfo(v uint16, sz int) Properties { size: uint8(sz), ccc: uint8(v), tccc: uint8(v), - flags: qcInfo(v >> 8), + flags: qcInfo(v>>8) & 0x3f, } if p.ccc > 0 || p.combinesBackward() { p.nLead = uint8(p.flags & 0x3) diff --git a/src/vendor/golang.org/x/text/unicode/norm/iter.go b/src/vendor/golang.org/x/text/unicode/norm/iter.go index 417c6b26894da4..3cc059224d9d9e 100644 --- a/src/vendor/golang.org/x/text/unicode/norm/iter.go +++ b/src/vendor/golang.org/x/text/unicode/norm/iter.go @@ -376,16 +376,12 @@ func nextComposed(i *Iter) []byte { goto doNorm } prevCC = i.info.tccc - sz := int(i.info.size) - if sz == 0 { - sz = 1 // illegal rune: copy byte-by-byte - } - p := outp + sz + p := outp + int(i.info.size) if p > len(i.buf) { break } outp = p - i.p += sz + i.p += int(i.info.size) if i.p >= i.rb.nsrc { i.setDone() break diff --git a/src/vendor/golang.org/x/text/unicode/norm/normalize.go b/src/vendor/golang.org/x/text/unicode/norm/normalize.go index 4747ad07a839c1..60b1511caa2bad 100644 --- a/src/vendor/golang.org/x/text/unicode/norm/normalize.go +++ b/src/vendor/golang.org/x/text/unicode/norm/normalize.go @@ -148,7 +148,7 @@ func (f Form) IsNormalString(s string) bool { // patched buffer and whether the decomposition is still in progress. func patchTail(rb *reorderBuffer) bool { info, p := lastRuneStart(&rb.f, rb.out) - if p == -1 || info.size == 0 { + if p == -1 || info.isInvalid() { return true } end := p + int(info.size) @@ -225,7 +225,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte { } fd := &rb.f if doMerge { - var info Properties + info := Properties{flags: 0x80, size: 1} // invalid rune if p < n { info = fd.info(src, p) if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 { @@ -235,7 +235,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte { p = decomposeSegment(rb, p, true) } } - if info.size == 0 { + if info.isInvalid() { rb.doFlush() // Append incomplete UTF-8 encoding. return src.appendSlice(rb.out, p, n) @@ -314,7 +314,7 @@ func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) continue } info := f.info(src, i) - if info.size == 0 { + if info.isInvalid() { if atEOF { // include incomplete runes return n, true @@ -379,7 +379,7 @@ func (f Form) firstBoundary(src input, nsrc int) int { // CGJ insertion points correctly. Luckily it doesn't have to. for { info := fd.info(src, i) - if info.size == 0 { + if info.isInvalid() { return -1 } if s := ss.next(info); s != ssSuccess { @@ -424,7 +424,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int { } fd := formTable[f] info := fd.info(src, 0) - if info.size == 0 { + if info.isInvalid() { if atEOF { return 1 } @@ -435,7 +435,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int { for i := int(info.size); i < nsrc; i += int(info.size) { info = fd.info(src, i) - if info.size == 0 { + if info.isInvalid() { if atEOF { return i } @@ -465,7 +465,7 @@ func lastBoundary(fd *formInfo, b []byte) int { if p == -1 { return -1 } - if info.size == 0 { // ends with incomplete rune + if info.isInvalid() { // ends with incomplete rune if p == 0 { // starts with incomplete rune return -1 } @@ -504,7 +504,7 @@ func lastBoundary(fd *formInfo, b []byte) int { func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { // Force one character to be consumed. info := rb.f.info(rb.src, sp) - if info.size == 0 { + if info.isInvalid() { return 0 } if s := rb.ss.next(info); s == ssStarter { @@ -528,7 +528,7 @@ func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { break } info = rb.f.info(rb.src, sp) - if info.size == 0 { + if info.isInvalid() { if !atEOF { return int(iShortSrc) } diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 54fcbab6a221c0..3592a83513f392 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -1,4 +1,4 @@ -# golang.org/x/crypto v0.52.1-0.20260526024921-9beb694f9766 +# golang.org/x/crypto v0.54.1-0.20260714033321-10b54ffa51b1 ## explicit; go 1.25.0 golang.org/x/crypto/chacha20 golang.org/x/crypto/chacha20poly1305 @@ -7,7 +7,7 @@ golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/hkdf golang.org/x/crypto/internal/alias golang.org/x/crypto/internal/poly1305 -# golang.org/x/net v0.55.1-0.20260526154343-657eb1317b5d +# golang.org/x/net v0.57.1-0.20260714001123-e7e2eb826435 ## explicit; go 1.25.0 golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts @@ -21,10 +21,10 @@ golang.org/x/net/internal/quic/quicwire golang.org/x/net/lif golang.org/x/net/nettest golang.org/x/net/quic -# golang.org/x/sys v0.45.0 +# golang.org/x/sys v0.47.0 ## explicit; go 1.25.0 golang.org/x/sys/cpu -# golang.org/x/text v0.37.0 +# golang.org/x/text v0.40.0 ## explicit; go 1.25.0 golang.org/x/text/secure/bidirule golang.org/x/text/transform From ebdf81fda71d011a0f0b4d67cdce8d6651ae8f7c Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Thu, 16 Jul 2026 11:14:15 -0700 Subject: [PATCH 09/16] Revert "cmd/compile: on AMD64 use leave instruction for go compiled functions" This reverts CL 548317. Reason for revert: breaks darwin-amd64 Change-Id: I2dec9a5f9b5213b0e3e2b2788ff4e92ee56d3b7c Reviewed-on: https://go-review.googlesource.com/c/go/+/801740 Reviewed-by: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov Auto-Submit: Michael Pratt Reviewed-by: Jorropo LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Auto-Submit: Jorropo --- src/cmd/internal/obj/x86/obj6.go | 35 ++++++++++++-------------------- src/runtime/proc.go | 1 - 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index 118c936e813d87..8125acfa2967ff 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -823,30 +823,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { if autoffset != 0 { to := p.To // Keep To attached to RET for retjmp below p.To = obj.Addr{} + if localoffset != 0 { + p.As = AADJSP + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(-localoffset) + p.Spadj = -localoffset + p = obj.Appendp(p, newprog) + } - needSpRestore, needBpRestore := localoffset != 0, bpsize > 0 - // We can't use LEAVE with assembly because the go asm promise - // it will insert save and restores for BP. Thus many pieces - // of code use BP as a scratch register. - if !ctxt.IsAsm && needSpRestore && needBpRestore { - p.As = ALEAVEQ - p.Spadj = -localoffset - int32(bpsize) + if bpsize > 0 { + // Restore caller's BP + p.As = APOPQ + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_BP + p.Spadj = -int32(bpsize) p = obj.Appendp(p, newprog) - } else { - if needSpRestore { - p.As = AADJSP - p.From.Type = obj.TYPE_CONST - p.From.Offset = int64(-localoffset) - p.Spadj = -localoffset - p = obj.Appendp(p, newprog) - } - if needBpRestore { - p.As = APOPQ - p.To.Type = obj.TYPE_REG - p.To.Reg = REG_BP - p.Spadj = -int32(bpsize) - p = obj.Appendp(p, newprog) - } } p.As = obj.ARET diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 3511c834f7532e..9edb1f57bb853d 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -1930,7 +1930,6 @@ func mstart1() { gp.sched.g = guintptr(unsafe.Pointer(gp)) gp.sched.pc = sys.GetCallerPC() gp.sched.sp = sys.GetCallerSP() - gp.sched.bp = getcallerfp() asminit() minit() From a3edc4c682a2741589cabbffa4733d2d48e6cf36 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 29 May 2026 14:58:04 -0700 Subject: [PATCH 10/16] cmd/compile/internal/syntax: allow untyped composite literals For #12854. Change-Id: I424abb56fc2abb4d94425adba1aab04ebf974810 Reviewed-on: https://go-review.googlesource.com/c/go/+/785200 Reviewed-by: Mark Freeman LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Russ Cox --- src/cmd/compile/internal/syntax/parser.go | 31 ++++++------------- .../internal/syntax/testdata/complit.go | 27 ++++++++++++++++ 2 files changed, 37 insertions(+), 21 deletions(-) create mode 100644 src/cmd/compile/internal/syntax/testdata/complit.go diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index f1f15c60a21070..2d33d06d803c32 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -1004,7 +1004,7 @@ func (p *parser) callStmt() *CallStmt { } // Operand = Literal | OperandName | MethodExpr | "(" Expression ")" . -// Literal = BasicLit | CompositeLit | FunctionLit . +// Literal = BasicLit | [ TypeName ] CompositeLit | FunctionLit . // BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit . // OperandName = identifier | QualifiedIdent. func (p *parser) operand(keep_parens bool) Expr { @@ -1019,6 +1019,9 @@ func (p *parser) operand(keep_parens bool) Expr { case _Literal: return p.oliteral() + case _Lbrace: + return p.compositeLit() + case _Lparen: pos := p.pos() p.next() @@ -1068,7 +1071,7 @@ func (p *parser) operand(keep_parens bool) Expr { return ftyp case _Lbrack, _Chan, _Map, _Struct, _Interface: - return p.type_() // othertype + return p.type_() default: x := p.badExpr() @@ -1243,7 +1246,7 @@ loop: p.syntaxError("cannot parenthesize type in composite literal") // already progressed, no need to advance } - n := p.complitexpr() + n := p.compositeLit() n.Type = x x = n @@ -1270,24 +1273,10 @@ func isValue(x Expr) bool { return false } -// Element = Expression | LiteralValue . -func (p *parser) bare_complitexpr() Expr { - if trace { - defer p.trace("bare_complitexpr")() - } - - if p.tok == _Lbrace { - // '{' start_complit braced_keyval_list '}' - return p.complitexpr() - } - - return p.expr() -} - // LiteralValue = "{" [ ElementList [ "," ] ] "}" . -func (p *parser) complitexpr() *CompositeLit { +func (p *parser) compositeLit() *CompositeLit { if trace { - defer p.trace("complitexpr")() + defer p.trace("compositeLit")() } x := new(CompositeLit) @@ -1297,14 +1286,14 @@ func (p *parser) complitexpr() *CompositeLit { p.want(_Lbrace) x.Rbrace = p.list("composite literal", _Comma, _Rbrace, func() bool { // value - e := p.bare_complitexpr() + e := p.expr() if p.tok == _Colon { // key ':' value l := new(KeyValueExpr) l.pos = p.pos() p.next() l.Key = e - l.Value = p.bare_complitexpr() + l.Value = p.expr() e = l x.NKeys++ } diff --git a/src/cmd/compile/internal/syntax/testdata/complit.go b/src/cmd/compile/internal/syntax/testdata/complit.go new file mode 100644 index 00000000000000..998b098db020f3 --- /dev/null +++ b/src/cmd/compile/internal/syntax/testdata/complit.go @@ -0,0 +1,27 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains examples of composite literals. +// The examples don't typecheck. + +package p + +var ( + _ = []int{} + _ = [...]int{} + _ = [42]int{} + _ = map[string]int{} + _ = T{} + _ = T{1, 2, 3} + _ = T{{}, T{}, []int{1, 2, 3}} +) + +var ( + _ []int = {1, 2, 3} + _ T = {1: {}, 2: {}} + _ = T({"a", "b"}) + _ = f(x, y, []byte{1, 2, 3}) + _ = f(x, y, {1, 2, 3}) + _ = g({foo: x, bar: y}) +) From 0ca95db05f2db08f14f923b4e85991bd7451286c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 29 May 2026 17:17:24 -0700 Subject: [PATCH 11/16] go/parser: allow untyped composite literals For #12854. Change-Id: I10ad6e979165903be43d0d4a0eddbca897e9d767 Reviewed-on: https://go-review.googlesource.com/c/go/+/785002 Reviewed-by: Russ Cox LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Alan Donovan Reviewed-by: Mark Freeman --- src/go/parser/parser.go | 26 +++++++------------------- src/go/parser/parser_test.go | 2 +- src/go/parser/testdata/complit.src | 27 +++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 20 deletions(-) create mode 100644 src/go/parser/testdata/complit.src diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 30cac2237944a1..a788bab65482bb 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -1475,14 +1475,16 @@ func (p *parser) parseOperand() ast.Expr { switch p.tok { case token.IDENT: - x := p.parseIdent() - return x + return p.parseIdent() case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING: x := &ast.BasicLit{ValuePos: p.pos, ValueEnd: p.end(), Kind: p.tok, Value: p.lit} p.next() return x + case token.LBRACE: + return p.parseLiteralValue(nil) + case token.LPAREN: lparen := p.pos p.next() @@ -1648,30 +1650,16 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { return &ast.CallExpr{Fun: fun, Lparen: lparen, Args: list, Ellipsis: ellipsis, Rparen: rparen} } -func (p *parser) parseValue() ast.Expr { - if p.trace { - defer un(trace(p, "Element")) - } - - if p.tok == token.LBRACE { - return p.parseLiteralValue(nil) - } - - x := p.parseExpr() - - return x -} - func (p *parser) parseElement() ast.Expr { if p.trace { defer un(trace(p, "Element")) } - x := p.parseValue() + x := p.parseExpr() if p.tok == token.COLON { colon := p.pos p.next() - x = &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseValue()} + x = &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseExpr()} } return x @@ -1777,7 +1765,7 @@ func (p *parser) parsePrimaryExpr(x ast.Expr) ast.Expr { p.error(t.Pos(), "cannot parenthesize type in composite literal") // already progressed, no need to advance } - x = p.parseLiteralValue(x) + x = p.parseLiteralValue(t) default: return x } diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go index 81181892309839..65ad718530fc1d 100644 --- a/src/go/parser/parser_test.go +++ b/src/go/parser/parser_test.go @@ -603,7 +603,7 @@ var parseDepthTests = []struct { {name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", parseMultiplier: 3}, // Parser nodes: UnaryExpr, CompositeLit {name: "structlit", format: "package main; var x = «struct{x any}{«nil»}»", parseMultiplier: 3}, // Parser nodes: UnaryExpr, CompositeLit {name: "maplit", format: "package main; var x = «map[int]any{1:«nil»}»", parseMultiplier: 3}, // Parser nodes: CompositeLit, KeyValueExpr - {name: "element", format: "package main; var x = struct{x any}{x: «{«»}»}"}, + //{name: "element", format: "package main; var x = struct{x any}{x: «{«»}»}"}, // TODO: fix this - currently fails {name: "dot", format: "package main; var x = «x.»x"}, {name: "index", format: "package main; var x = x«[1]»"}, {name: "slice", format: "package main; var x = x«[1:2]»"}, diff --git a/src/go/parser/testdata/complit.src b/src/go/parser/testdata/complit.src new file mode 100644 index 00000000000000..998b098db020f3 --- /dev/null +++ b/src/go/parser/testdata/complit.src @@ -0,0 +1,27 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains examples of composite literals. +// The examples don't typecheck. + +package p + +var ( + _ = []int{} + _ = [...]int{} + _ = [42]int{} + _ = map[string]int{} + _ = T{} + _ = T{1, 2, 3} + _ = T{{}, T{}, []int{1, 2, 3}} +) + +var ( + _ []int = {1, 2, 3} + _ T = {1: {}, 2: {}} + _ = T({"a", "b"}) + _ = f(x, y, []byte{1, 2, 3}) + _ = f(x, y, {1, 2, 3}) + _ = g({foo: x, bar: y}) +) From 54539e7c9e410bba29eb9f7e9e4ec487dcf80676 Mon Sep 17 00:00:00 2001 From: Mark Freeman Date: Wed, 24 Jun 2026 14:11:31 -0400 Subject: [PATCH 12/16] go/types, types2: reorder channel sends to extract value target type For channel sends, we currently check the sent value before inspecting the channel element type. If we check the channel element type first, we can extract a target type for the value. This change reorders processing to do so. This is a necessary prerequisite for composite literal type inference. For #12854 Change-Id: I19b1ef73a2f82b3c45cd3f4a3f0dc32cd795e7ac Reviewed-on: https://go-review.googlesource.com/c/go/+/793980 Reviewed-by: Robert Griesemer LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Auto-Submit: Mark Freeman --- src/cmd/compile/internal/types2/stmt.go | 17 +++++++++++------ src/go/types/stmt.go | 17 +++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 7bd5d8712b3889..40fd79b301d234 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -463,12 +463,17 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { case *syntax.SendStmt: var ch, val operand check.expr(nil, &ch, s.Chan) - check.genericExpr(&val, s.Value, nil) - if !ch.isValid() || !val.isValid() { - return - } - if elem := check.chanElem(s, &ch, false); elem != nil { - check.assignment(&val, elem, "send") + if ch.isValid() { + // try to get a target type for the sent value + // TODO(mark): use T in an upcoming CL + T := check.chanElem(s, &ch, false) + check.genericExpr(&val, s.Value, nil) + if T != nil { + check.assignment(&val, T, "send") + } + } else { + // no target type, don't drop work on the floor + check.genericExpr(&val, s.Value, nil) } case *syntax.AssignStmt: diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index 85c7576d7660c0..87cd9b6e81225e 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -464,12 +464,17 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { case *ast.SendStmt: var ch, val operand check.expr(nil, &ch, s.Chan) - check.genericExpr(&val, s.Value, nil) - if !ch.isValid() || !val.isValid() { - return - } - if elem := check.chanElem(inNode(s, s.Arrow), &ch, false); elem != nil { - check.assignment(&val, elem, "send") + if ch.isValid() { + // extract a target type for the sent value + // TODO(mark): use T in an upcoming CL + T := check.chanElem(inNode(s, s.Arrow), &ch, false) + check.genericExpr(&val, s.Value, nil) + if T != nil { + check.assignment(&val, T, "send") + } + } else { + // no target type, don't drop work on the floor + check.genericExpr(&val, s.Value, nil) } case *ast.IncDecStmt: From 17810c616ff9b846ef7544cdf46b3b0300b92df3 Mon Sep 17 00:00:00 2001 From: Mark Freeman Date: Wed, 24 Jun 2026 15:12:06 -0400 Subject: [PATCH 13/16] go/types, types2: thread composite literal target through expressions This change threads a type target through the major expression type checking logic in Checker.expr and its related methods. For now, this new argument isn't used. This is done to reduce the surface area of upcoming changes. For #12854 Change-Id: I0e21c010c5d0d6ea3fd6dd09b5289b1479a88f7f Reviewed-on: https://go-review.googlesource.com/c/go/+/794040 Auto-Submit: Mark Freeman Reviewed-by: Robert Griesemer LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- .../compile/internal/types2/assignments.go | 8 ++--- src/cmd/compile/internal/types2/builtins.go | 4 +-- src/cmd/compile/internal/types2/call.go | 10 +++--- src/cmd/compile/internal/types2/decl.go | 4 +-- src/cmd/compile/internal/types2/expr.go | 36 ++++++++++--------- src/cmd/compile/internal/types2/index.go | 8 ++--- src/cmd/compile/internal/types2/literals.go | 12 +++---- src/cmd/compile/internal/types2/range.go | 2 +- src/cmd/compile/internal/types2/stmt.go | 26 +++++++------- src/cmd/compile/internal/types2/typexpr.go | 2 +- src/go/types/assignments.go | 8 ++--- src/go/types/builtins.go | 4 +-- src/go/types/call.go | 10 +++--- src/go/types/decl.go | 4 +-- src/go/types/eval.go | 4 +-- src/go/types/expr.go | 36 ++++++++++--------- src/go/types/index.go | 8 ++--- src/go/types/literals.go | 12 +++---- src/go/types/range.go | 2 +- src/go/types/stmt.go | 26 +++++++------- src/go/types/typexpr.go | 2 +- 21 files changed, 118 insertions(+), 110 deletions(-) diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go index ac565fd6ab191b..86ef8c4d930c26 100644 --- a/src/cmd/compile/internal/types2/assignments.go +++ b/src/cmd/compile/internal/types2/assignments.go @@ -209,7 +209,7 @@ func (check *Checker) lhsVar(lhs syntax.Expr) Type { } var x operand - check.expr(nil, &x, lhs) + check.expr(nil, nil, &x, lhs) if v != nil { check.usedVars[v] = v_used // restore v.used @@ -229,7 +229,7 @@ func (check *Checker) lhsVar(lhs syntax.Expr) Type { default: if sel, ok := x.expr.(*syntax.SelectorExpr); ok { var op operand - check.expr(nil, &op, sel.X) + check.expr(nil, nil, &op, sel.X) if op.mode() == mapindex { check.errorf(&x, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(x.expr)) return Typ[Invalid] @@ -265,7 +265,7 @@ func (check *Checker) assignVar(lhs, rhs syntax.Expr, x *operand, context string } } x = new(operand) - check.expr(target, x, rhs) + check.expr(target, nil, x, rhs) } if T == nil && context == "assignment" { @@ -407,7 +407,7 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnStmt sy if returnStmt != nil && desc == "" { desc = "result variable" } - check.expr(newTarget(lhs.typ, desc), &x, orig_rhs[i]) + check.expr(newTarget(lhs.typ, desc), nil, &x, orig_rhs[i]) check.initVar(lhs, &x, context) } return diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index e9cfcf541d76fe..ca83762bb0a7a0 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -779,7 +779,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( return } - check.expr(nil, x, selx.X) + check.expr(nil, nil, x, selx.X) if !x.isValid() { return } @@ -967,7 +967,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( var t operand x1 := x for _, arg := range argList { - check.rawExpr(nil, x1, arg, nil, false) // permit trace for types, e.g.: new(trace(T)) + check.rawExpr(nil, nil, x1, arg, nil, false) // permit trace for types, e.g.: new(trace(T)) check.dump("%v: %s", atPos(x1), x1) x1 = &t // use incoming x only for first argument } diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 87c68ce9da3491..6b8059cc5a500e 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -208,7 +208,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind { case 0: check.errorf(call, WrongArgCount, "missing argument in conversion to %s", T) case 1: - check.expr(newTarget(T, "conversion"), x, call.ArgList[0]) + check.expr(newTarget(T, "conversion"), nil, x, call.ArgList[0]) if x.isValid() { if t, _ := T.Underlying().(*Interface); t != nil && !isTypeParam(T) { if !t.IsMethodSet() { @@ -358,7 +358,7 @@ func (check *Checker) exprList(elist []syntax.Expr) (xlist []*operand) { xlist = make([]*operand, n) for i, e := range elist { var x operand - check.expr(nil, &x, e) + check.expr(nil, nil, &x, e) xlist[i] = &x } } @@ -415,7 +415,7 @@ func (check *Checker) genericExprList(elist []syntax.Expr) (resList []*operand, resList = []*operand{&x} } else { // x is not a function instantiation (it may still be a generic function). - check.rawExpr(nil, &x, e, nil, true) + check.rawExpr(nil, nil, &x, e, nil, true) check.exclude(&x, 1<= len(fields) { check.errorf(x, InvalidStructLit, "too many values in struct literal of type %s", base) break // cannot continue @@ -277,7 +277,7 @@ func (check *Checker) compositeLit(x *operand, e *syntax.CompositeLit, hint Type check.error(e, MissingLitKey, "missing key in map literal") continue } - check.genericExpr(x, kv.Key, utyp.key) + check.genericExpr(nil, x, kv.Key, utyp.key) check.assignment(x, utyp.key, "map literal") if !x.isValid() { continue @@ -302,7 +302,7 @@ func (check *Checker) compositeLit(x *operand, e *syntax.CompositeLit, hint Type continue } } - check.genericExpr(x, kv.Value, utyp.elem) + check.genericExpr(nil, x, kv.Value, utyp.elem) check.assignment(x, utyp.elem, "map literal") } @@ -379,7 +379,7 @@ func (check *Checker) indexedElts(elts []syntax.Expr, typ Type, length int64) in // check element against composite literal element type var x operand - check.genericExpr(&x, eval, typ) + check.genericExpr(nil, &x, eval, typ) check.assignment(&x, typ, "array or slice literal") } return max diff --git a/src/cmd/compile/internal/types2/range.go b/src/cmd/compile/internal/types2/range.go index f7ecbb4c760766..56264a42034b7e 100644 --- a/src/cmd/compile/internal/types2/range.go +++ b/src/cmd/compile/internal/types2/range.go @@ -32,7 +32,7 @@ func (check *Checker) rangeStmt(inner stmtContext, rangeStmt *syntax.ForStmt, no // described situation. check.hasCallOrRecv = false - check.expr(nil, &x, rangeVar) + check.expr(nil, nil, &x, rangeVar) if isTypes2 && x.isValid() && sValue == nil && !check.hasCallOrRecv { if t, ok := arrayPtrDeref(x.typ().Underlying()).(*Array); ok { diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 40fd79b301d234..1c29cbdbf293e8 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -177,7 +177,7 @@ func (check *Checker) suspendedCall(keyword string, call syntax.Expr) { var x operand var msg string - switch check.rawExpr(nil, &x, call, nil, false) { + switch check.rawExpr(nil, nil, &x, call, nil, false) { case conversion: msg = "requires function call, not conversion" case expression: @@ -237,7 +237,7 @@ func (check *Checker) caseValues(x *operand, values []syntax.Expr, seen valueMap L: for _, e := range values { var v operand - check.expr(nil, &v, e) + check.expr(nil, nil, &v, e) if !x.isValid() || !v.isValid() { continue L } @@ -311,7 +311,7 @@ L: // The spec allows the value nil instead of a type. if check.isNil(e) { T = nil - check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings + check.expr(nil, nil, &dummy, e) // run e through expr so we get the usual Info recordings } else { T = check.varType(e) if !isValid(T) { @@ -363,7 +363,7 @@ L: // The spec allows the value nil instead of a type. var hash string if check.isNil(e) { - check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings + check.expr(nil, nil, &dummy, e) // run e through expr so we get the usual Info recordings T = nil hash = "" // avoid collision with a type named nil } else { @@ -441,7 +441,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { // function and method calls and receive operations can appear // in statement context. Such statements may be parenthesized." var x operand - kind := check.rawExpr(nil, &x, s.X, nil, false) + kind := check.rawExpr(nil, nil, &x, s.X, nil, false) var msg string var code Code switch x.mode() { @@ -462,18 +462,18 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { case *syntax.SendStmt: var ch, val operand - check.expr(nil, &ch, s.Chan) + check.expr(nil, nil, &ch, s.Chan) if ch.isValid() { // try to get a target type for the sent value // TODO(mark): use T in an upcoming CL T := check.chanElem(s, &ch, false) - check.genericExpr(&val, s.Value, nil) + check.genericExpr(nil, &val, s.Value, nil) if T != nil { check.assignment(&val, T, "send") } } else { // no target type, don't drop work on the floor - check.genericExpr(&val, s.Value, nil) + check.genericExpr(nil, &val, s.Value, nil) } case *syntax.AssignStmt: @@ -481,7 +481,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { // x++ or x-- // (no need to call unpackExpr as s.Lhs must be single-valued) var x operand - check.expr(nil, &x, s.Lhs) + check.expr(nil, nil, &x, s.Lhs) if !x.isValid() { return } @@ -596,7 +596,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { check.simpleStmt(s.Init) var x operand - check.expr(nil, &x, s.Cond) + check.expr(nil, nil, &x, s.Cond) if x.isValid() && !allBoolean(x.typ()) { check.error(s.Cond, InvalidCond, "non-boolean condition in if statement") } @@ -698,7 +698,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { check.simpleStmt(s.Init) if s.Cond != nil { var x operand - check.expr(nil, &x, s.Cond) + check.expr(nil, nil, &x, s.Cond) if x.isValid() && !allBoolean(x.typ()) { check.error(s.Cond, InvalidCond, "non-boolean condition in for statement") } @@ -722,7 +722,7 @@ func (check *Checker) switchStmt(inner stmtContext, s *syntax.SwitchStmt) { var x operand if s.Tag != nil { - check.expr(nil, &x, s.Tag) + check.expr(nil, nil, &x, s.Tag) // By checking assignment of x to an invisible temporary // (as a compiler would), we get all the relevant checks. check.assignment(&x, nil, "switch expression") @@ -789,7 +789,7 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu var sx *operand // switch expression against which cases are compared against; nil if invalid { var x operand - check.expr(nil, &x, guard.X) + check.expr(nil, nil, &x, guard.X) if x.isValid() { if isTypeParam(x.typ()) { check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x) diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index bffc9ba684eb45..0139fed433965b 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -481,7 +481,7 @@ func (check *Checker) arrayLength(e syntax.Expr) int64 { } var x operand - check.expr(nil, &x, e) + check.expr(nil, nil, &x, e) if x.mode() != constant_ { if x.isValid() { check.errorf(&x, InvalidArrayLen, "array length %s must be constant", &x) diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index 05b6e4845a9ff2..f4094bfcf1f3a5 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -212,7 +212,7 @@ func (check *Checker) lhsVar(lhs ast.Expr) Type { } var x operand - check.expr(nil, &x, lhs) + check.expr(nil, nil, &x, lhs) if v != nil { check.usedVars[v] = v_used // restore v.used @@ -232,7 +232,7 @@ func (check *Checker) lhsVar(lhs ast.Expr) Type { default: if sel, ok := x.expr.(*ast.SelectorExpr); ok { var op operand - check.expr(nil, &op, sel.X) + check.expr(nil, nil, &op, sel.X) if op.mode() == mapindex { check.errorf(&x, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(x.expr)) return Typ[Invalid] @@ -268,7 +268,7 @@ func (check *Checker) assignVar(lhs, rhs ast.Expr, x *operand, context string) { } } x = new(operand) - check.expr(target, x, rhs) + check.expr(target, nil, x, rhs) } if T == nil && context == "assignment" { @@ -410,7 +410,7 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnStmt ast.S if returnStmt != nil && desc == "" { desc = "result variable" } - check.expr(newTarget(lhs.typ, desc), &x, orig_rhs[i]) + check.expr(newTarget(lhs.typ, desc), nil, &x, orig_rhs[i]) check.initVar(lhs, &x, context) } return diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index ed2c1b4568ede5..c0eb0b856d157b 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -782,7 +782,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b return } - check.expr(nil, x, selx.X) + check.expr(nil, nil, x, selx.X) if !x.isValid() { return } @@ -970,7 +970,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b var t operand x1 := x for _, arg := range argList { - check.rawExpr(nil, x1, arg, nil, false) // permit trace for types, e.g.: new(trace(T)) + check.rawExpr(nil, nil, x1, arg, nil, false) // permit trace for types, e.g.: new(trace(T)) check.dump("%v: %s", x1.Pos(), x1) x1 = &t // use incoming x only for first argument } diff --git a/src/go/types/call.go b/src/go/types/call.go index 4d0bda0d404269..aaa7695ff89b8c 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -210,7 +210,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { case 0: check.errorf(inNode(call, call.Rparen), WrongArgCount, "missing argument in conversion to %s", T) case 1: - check.expr(newTarget(T, "conversion"), x, call.Args[0]) + check.expr(newTarget(T, "conversion"), nil, x, call.Args[0]) if x.isValid() { if hasDots(call) { check.errorf(call.Args[0], BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T) @@ -360,7 +360,7 @@ func (check *Checker) exprList(elist []ast.Expr) (xlist []*operand) { xlist = make([]*operand, n) for i, e := range elist { var x operand - check.expr(nil, &x, e) + check.expr(nil, nil, &x, e) xlist[i] = &x } } @@ -417,7 +417,7 @@ func (check *Checker) genericExprList(elist []ast.Expr) (resList []*operand, tar resList = []*operand{&x} } else { // x is not a function instantiation (it may still be a generic function). - check.rawExpr(nil, &x, e, nil, true) + check.rawExpr(nil, nil, &x, e, nil, true) check.exclude(&x, 1<= len(fields) { check.errorf(x, InvalidStructLit, "too many values in struct literal of type %s", base) break // cannot continue @@ -281,7 +281,7 @@ func (check *Checker) compositeLit(x *operand, e *ast.CompositeLit, hint Type) { check.error(e, MissingLitKey, "missing key in map literal") continue } - check.genericExpr(x, kv.Key, utyp.key) + check.genericExpr(nil, x, kv.Key, utyp.key) check.assignment(x, utyp.key, "map literal") if !x.isValid() { continue @@ -306,7 +306,7 @@ func (check *Checker) compositeLit(x *operand, e *ast.CompositeLit, hint Type) { continue } } - check.genericExpr(x, kv.Value, utyp.elem) + check.genericExpr(nil, x, kv.Value, utyp.elem) check.assignment(x, utyp.elem, "map literal") } @@ -383,7 +383,7 @@ func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64 // check element against composite literal element type var x operand - check.genericExpr(&x, eval, typ) + check.genericExpr(nil, &x, eval, typ) check.assignment(&x, typ, "array or slice literal") } return max diff --git a/src/go/types/range.go b/src/go/types/range.go index 8eceb4d7879679..98f3d96957c12b 100644 --- a/src/go/types/range.go +++ b/src/go/types/range.go @@ -35,7 +35,7 @@ func (check *Checker) rangeStmt(inner stmtContext, rangeStmt *ast.RangeStmt, noN // described situation. check.hasCallOrRecv = false - check.expr(nil, &x, rangeVar) + check.expr(nil, nil, &x, rangeVar) if isTypes2 && x.isValid() && sValue == nil && !check.hasCallOrRecv { if t, ok := arrayPtrDeref(x.typ().Underlying()).(*Array); ok { diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index 87cd9b6e81225e..9093a104608eb8 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -174,7 +174,7 @@ func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) { var x operand var msg string var code Code - switch check.rawExpr(nil, &x, call, nil, false) { + switch check.rawExpr(nil, nil, &x, call, nil, false) { case conversion: msg = "requires function call, not conversion" code = InvalidDefer @@ -238,7 +238,7 @@ func (check *Checker) caseValues(x *operand, values []ast.Expr, seen valueMap) { L: for _, e := range values { var v operand - check.expr(nil, &v, e) + check.expr(nil, nil, &v, e) if !x.isValid() || !v.isValid() { continue L } @@ -312,7 +312,7 @@ L: // The spec allows the value nil instead of a type. if check.isNil(e) { T = nil - check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings + check.expr(nil, nil, &dummy, e) // run e through expr so we get the usual Info recordings } else { T = check.varType(e) if !isValid(T) { @@ -364,7 +364,7 @@ L: // The spec allows the value nil instead of a type. var hash string if check.isNil(e) { - check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings + check.expr(nil, nil, &dummy, e) // run e through expr so we get the usual Info recordings T = nil hash = "" // avoid collision with a type named nil } else { @@ -442,7 +442,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { // function and method calls and receive operations can appear // in statement context. Such statements may be parenthesized." var x operand - kind := check.rawExpr(nil, &x, s.X, nil, false) + kind := check.rawExpr(nil, nil, &x, s.X, nil, false) var msg string var code Code switch x.mode() { @@ -463,18 +463,18 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { case *ast.SendStmt: var ch, val operand - check.expr(nil, &ch, s.Chan) + check.expr(nil, nil, &ch, s.Chan) if ch.isValid() { // extract a target type for the sent value // TODO(mark): use T in an upcoming CL T := check.chanElem(inNode(s, s.Arrow), &ch, false) - check.genericExpr(&val, s.Value, nil) + check.genericExpr(nil, &val, s.Value, nil) if T != nil { check.assignment(&val, T, "send") } } else { // no target type, don't drop work on the floor - check.genericExpr(&val, s.Value, nil) + check.genericExpr(nil, &val, s.Value, nil) } case *ast.IncDecStmt: @@ -490,7 +490,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { } var x operand - check.expr(nil, &x, s.X) + check.expr(nil, nil, &x, s.X) if !x.isValid() { return } @@ -613,7 +613,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { check.simpleStmt(s.Init) var x operand - check.expr(nil, &x, s.Cond) + check.expr(nil, nil, &x, s.Cond) if x.isValid() && !allBoolean(x.typ()) { check.error(s.Cond, InvalidCond, "non-boolean condition in if statement") } @@ -637,7 +637,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { check.simpleStmt(s.Init) var x operand if s.Tag != nil { - check.expr(nil, &x, s.Tag) + check.expr(nil, nil, &x, s.Tag) // By checking assignment of x to an invisible temporary // (as a compiler would), we get all the relevant checks. check.assignment(&x, nil, "switch expression") @@ -732,7 +732,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { var sx *operand // switch expression against which cases are compared against; nil if invalid { var x operand - check.expr(nil, &x, expr.X) + check.expr(nil, nil, &x, expr.X) if x.isValid() { if isTypeParam(x.typ()) { check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x) @@ -841,7 +841,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { check.simpleStmt(s.Init) if s.Cond != nil { var x operand - check.expr(nil, &x, s.Cond) + check.expr(nil, nil, &x, s.Cond) if x.isValid() && !allBoolean(x.typ()) { check.error(s.Cond, InvalidCond, "non-boolean condition in for statement") } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index f289844f3315b6..bb81630dad9dd3 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -477,7 +477,7 @@ func (check *Checker) arrayLength(e ast.Expr) int64 { } var x operand - check.expr(nil, &x, e) + check.expr(nil, nil, &x, e) if x.mode() != constant_ { if x.isValid() { check.errorf(&x, InvalidArrayLen, "array length %s must be constant", &x) From 39cc89aa117aec3ab14a4268f13f4495c154703e Mon Sep 17 00:00:00 2001 From: Mark Freeman Date: Wed, 24 Jun 2026 15:45:51 -0400 Subject: [PATCH 14/16] go/types, types2: check for composite literal type target This change checks for a type target for composite literals and performs the appropriate type inference. Note that U is currently always nil; we still need to pipe in the types for the relevant contexts. Thus, this change is a no-op for now. For #12854 Change-Id: I8517ef72da3b09328be5661021f700b6b00e5f1f Reviewed-on: https://go-review.googlesource.com/c/go/+/794060 Reviewed-by: Robert Griesemer Auto-Submit: Mark Freeman LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/cmd/compile/internal/types2/literals.go | 26 +++++++++++++++++---- src/cmd/compile/internal/types2/version.go | 1 + src/go/types/literals.go | 26 +++++++++++++++++---- src/go/types/version.go | 1 + 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/types2/literals.go b/src/cmd/compile/internal/types2/literals.go index 89c6fa3a758696..09cd0f4a730f6f 100644 --- a/src/cmd/compile/internal/types2/literals.go +++ b/src/cmd/compile/internal/types2/literals.go @@ -124,6 +124,8 @@ func (check *Checker) compositeLit(U Type, x *operand, e *syntax.CompositeLit, h typ = check.typ(e.Type) base = typ + // The hint mechanism is kept around to avoid reporting a false "need Go 1.28" error + // for users of a Go 1.27 compiler. case hint != nil: // no composite literal type present - use hint (element type of enclosing type) typ = hint @@ -136,11 +138,25 @@ func (check *Checker) compositeLit(U Type, x *operand, e *syntax.CompositeLit, h isElem = true default: - // TODO(gri) provide better error messages depending on context - check.error(e, UntypedLit, "missing type in composite literal") - // continue with invalid type so that elements are "used" (go.dev/issue/69092) - typ = Typ[Invalid] - base = typ + // no composite literal type or hint present - use assignment context (if available and past Go 1.28) + if U != nil { + // report a version error only if we have an inferred type + check.verifyVersionf(e, go1_28, "missing type in composite literal") + // continue with the inferred type regardless of version + typ = U + base = typ + // *T implies &T{} + u, _ := commonUnder(base, nil) + if b, ok := deref(u); ok { + base = b + } + } else { + // TODO(gri) provide better error messages depending on context + check.error(e, UntypedLit, "missing type in composite literal") + // continue with invalid type so that elements are "used" (go.dev/issue/69092) + typ = Typ[Invalid] + base = typ + } } // We cannot create a literal of an incomplete type; make sure it's complete. diff --git a/src/cmd/compile/internal/types2/version.go b/src/cmd/compile/internal/types2/version.go index 05cb9391b957da..6fdbc1b7270548 100644 --- a/src/cmd/compile/internal/types2/version.go +++ b/src/cmd/compile/internal/types2/version.go @@ -45,6 +45,7 @@ var ( go1_23 = asGoVersion("go1.23") go1_26 = asGoVersion("go1.26") go1_27 = asGoVersion("go1.27") + go1_28 = asGoVersion("go1.28") // current (deployed) Go version go_current = asGoVersion(fmt.Sprintf("go1.%d", goversion.Version)) diff --git a/src/go/types/literals.go b/src/go/types/literals.go index 02fff9be5b0e39..f0feda67700f46 100644 --- a/src/go/types/literals.go +++ b/src/go/types/literals.go @@ -128,6 +128,8 @@ func (check *Checker) compositeLit(U Type, x *operand, e *ast.CompositeLit, hint typ = check.typ(e.Type) base = typ + // The hint mechanism is kept around to avoid reporting a false "need Go 1.28" error + // for users of a Go 1.27 compiler. case hint != nil: // no composite literal type present - use hint (element type of enclosing type) typ = hint @@ -140,11 +142,25 @@ func (check *Checker) compositeLit(U Type, x *operand, e *ast.CompositeLit, hint isElem = true default: - // TODO(gri) provide better error messages depending on context - check.error(e, UntypedLit, "missing type in composite literal") - // continue with invalid type so that elements are "used" (go.dev/issue/69092) - typ = Typ[Invalid] - base = typ + // no composite literal type or hint present - use assignment context (if available and past Go 1.28) + if U != nil { + // report a version error only if we have an inferred type + check.verifyVersionf(e, go1_28, "missing type in composite literal") + // continue with the inferred type regardless of version + typ = U + base = typ + // *T implies &T{} + u, _ := commonUnder(base, nil) + if b, ok := deref(u); ok { + base = b + } + } else { + // TODO(gri) provide better error messages depending on context + check.error(e, UntypedLit, "missing type in composite literal") + // continue with invalid type so that elements are "used" (go.dev/issue/69092) + typ = Typ[Invalid] + base = typ + } } // We cannot create a literal of an incomplete type; make sure it's complete. diff --git a/src/go/types/version.go b/src/go/types/version.go index a00c57a7a1fb12..59797626bebd42 100644 --- a/src/go/types/version.go +++ b/src/go/types/version.go @@ -48,6 +48,7 @@ var ( go1_23 = asGoVersion("go1.23") go1_26 = asGoVersion("go1.26") go1_27 = asGoVersion("go1.27") + go1_28 = asGoVersion("go1.28") // current (deployed) Go version go_current = asGoVersion(fmt.Sprintf("go1.%d", goversion.Version)) From c7abbff510b8b22da706da9412a050f41954383f Mon Sep 17 00:00:00 2001 From: Mark Freeman Date: Wed, 24 Jun 2026 17:02:58 -0400 Subject: [PATCH 15/16] go/types, types2: pass in some targets for composite literal types This change handles the more straightforward targets for composite literal type inference; they are typically identical to the targets passed for generic function values. A variety of test cases are added. Those which are awaiting implementation are commented out for now. For #12854 Change-Id: I776e160dd7bce0768589a552c4e7913b1c70220f Reviewed-on: https://go-review.googlesource.com/c/go/+/794088 Reviewed-by: Robert Griesemer LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Auto-Submit: Mark Freeman --- .../compile/internal/types2/assignments.go | 4 +- src/cmd/compile/internal/types2/call.go | 2 +- src/cmd/compile/internal/types2/decl.go | 2 +- src/cmd/compile/internal/types2/index.go | 4 +- src/cmd/compile/internal/types2/literals.go | 6 +- src/cmd/compile/internal/types2/stmt.go | 2 +- src/go/types/assignments.go | 4 +- src/go/types/call.go | 2 +- src/go/types/decl.go | 2 +- src/go/types/index.go | 4 +- src/go/types/literals.go | 6 +- src/go/types/stmt.go | 2 +- .../{compliterals.go => compliterals0.go} | 0 .../types/testdata/check/compliterals1.go | 96 ++++++++++++++++++ .../types/testdata/check/compliterals2.go | 99 +++++++++++++++++++ .../types/testdata/check/compliterals3.go | 63 ++++++++++++ 16 files changed, 278 insertions(+), 20 deletions(-) rename src/internal/types/testdata/check/{compliterals.go => compliterals0.go} (100%) create mode 100644 src/internal/types/testdata/check/compliterals1.go create mode 100644 src/internal/types/testdata/check/compliterals2.go create mode 100644 src/internal/types/testdata/check/compliterals3.go diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go index 86ef8c4d930c26..cff9e95c0fdb26 100644 --- a/src/cmd/compile/internal/types2/assignments.go +++ b/src/cmd/compile/internal/types2/assignments.go @@ -265,7 +265,7 @@ func (check *Checker) assignVar(lhs, rhs syntax.Expr, x *operand, context string } } x = new(operand) - check.expr(target, nil, x, rhs) + check.expr(target, T, x, rhs) } if T == nil && context == "assignment" { @@ -407,7 +407,7 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnStmt sy if returnStmt != nil && desc == "" { desc = "result variable" } - check.expr(newTarget(lhs.typ, desc), nil, &x, orig_rhs[i]) + check.expr(newTarget(lhs.typ, desc), lhs.typ, &x, orig_rhs[i]) check.initVar(lhs, &x, context) } return diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 6b8059cc5a500e..a887b80841d920 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -208,7 +208,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind { case 0: check.errorf(call, WrongArgCount, "missing argument in conversion to %s", T) case 1: - check.expr(newTarget(T, "conversion"), nil, x, call.ArgList[0]) + check.expr(newTarget(T, "conversion"), T, x, call.ArgList[0]) if x.isValid() { if t, _ := T.Underlying().(*Interface); t != nil && !isTypeParam(T) { if !t.IsMethodSet() { diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index e8a53078696b2f..efe6423fd91c83 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -382,7 +382,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) { if lhs == nil || len(lhs) == 1 { assert(lhs == nil || lhs[0] == obj) var x operand - check.expr(newTarget(obj.typ, obj.name), nil, &x, init) + check.expr(newTarget(obj.typ, obj.name), obj.typ, &x, init) check.initVar(obj, &x, "variable declaration") return } diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index 8938319ee05df2..fab21a8d7c8e1b 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -114,7 +114,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo return false } var key operand - check.genericExpr(nil, &key, index, nil) + check.genericExpr(typ.key, &key, index, nil) check.assignment(&key, typ.key, "map index") // ok to continue even if indexing failed - map element type is known x.mode_ = mapindex @@ -188,7 +188,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo return false } var k operand - check.genericExpr(nil, &k, index, nil) + check.genericExpr(key, &k, index, nil) check.assignment(&k, key, "map index") // ok to continue even if indexing failed - map element type is known x.mode_ = mapindex diff --git a/src/cmd/compile/internal/types2/literals.go b/src/cmd/compile/internal/types2/literals.go index 09cd0f4a730f6f..3a8e44b197822d 100644 --- a/src/cmd/compile/internal/types2/literals.go +++ b/src/cmd/compile/internal/types2/literals.go @@ -293,7 +293,7 @@ func (check *Checker) compositeLit(U Type, x *operand, e *syntax.CompositeLit, h check.error(e, MissingLitKey, "missing key in map literal") continue } - check.genericExpr(nil, x, kv.Key, utyp.key) + check.genericExpr(utyp.key, x, kv.Key, utyp.key) check.assignment(x, utyp.key, "map literal") if !x.isValid() { continue @@ -318,7 +318,7 @@ func (check *Checker) compositeLit(U Type, x *operand, e *syntax.CompositeLit, h continue } } - check.genericExpr(nil, x, kv.Value, utyp.elem) + check.genericExpr(utyp.elem, x, kv.Value, utyp.elem) check.assignment(x, utyp.elem, "map literal") } @@ -395,7 +395,7 @@ func (check *Checker) indexedElts(elts []syntax.Expr, typ Type, length int64) in // check element against composite literal element type var x operand - check.genericExpr(nil, &x, eval, typ) + check.genericExpr(typ, &x, eval, typ) check.assignment(&x, typ, "array or slice literal") } return max diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 1c29cbdbf293e8..19f3096e566c77 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -467,7 +467,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { // try to get a target type for the sent value // TODO(mark): use T in an upcoming CL T := check.chanElem(s, &ch, false) - check.genericExpr(nil, &val, s.Value, nil) + check.genericExpr(T, &val, s.Value, nil) if T != nil { check.assignment(&val, T, "send") } diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index f4094bfcf1f3a5..871d598ff14681 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -268,7 +268,7 @@ func (check *Checker) assignVar(lhs, rhs ast.Expr, x *operand, context string) { } } x = new(operand) - check.expr(target, nil, x, rhs) + check.expr(target, T, x, rhs) } if T == nil && context == "assignment" { @@ -410,7 +410,7 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnStmt ast.S if returnStmt != nil && desc == "" { desc = "result variable" } - check.expr(newTarget(lhs.typ, desc), nil, &x, orig_rhs[i]) + check.expr(newTarget(lhs.typ, desc), lhs.typ, &x, orig_rhs[i]) check.initVar(lhs, &x, context) } return diff --git a/src/go/types/call.go b/src/go/types/call.go index aaa7695ff89b8c..c6247e9018594c 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -210,7 +210,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { case 0: check.errorf(inNode(call, call.Rparen), WrongArgCount, "missing argument in conversion to %s", T) case 1: - check.expr(newTarget(T, "conversion"), nil, x, call.Args[0]) + check.expr(newTarget(T, "conversion"), T, x, call.Args[0]) if x.isValid() { if hasDots(call) { check.errorf(call.Args[0], BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 5dacc40963c8a4..927178196b5240 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -458,7 +458,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { if lhs == nil || len(lhs) == 1 { assert(lhs == nil || lhs[0] == obj) var x operand - check.expr(newTarget(obj.typ, obj.name), nil, &x, init) + check.expr(newTarget(obj.typ, obj.name), obj.typ, &x, init) check.initVar(obj, &x, "variable declaration") return } diff --git a/src/go/types/index.go b/src/go/types/index.go index ae116be5e77345..98f56c67d90b4d 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -115,7 +115,7 @@ func (check *Checker) indexExpr(x *operand, e *indexedExpr) (isFuncInst bool) { return false } var key operand - check.genericExpr(nil, &key, index, nil) + check.genericExpr(typ.key, &key, index, nil) check.assignment(&key, typ.key, "map index") // ok to continue even if indexing failed - map element type is known x.mode_ = mapindex @@ -189,7 +189,7 @@ func (check *Checker) indexExpr(x *operand, e *indexedExpr) (isFuncInst bool) { return false } var k operand - check.genericExpr(nil, &k, index, nil) + check.genericExpr(key, &k, index, nil) check.assignment(&k, key, "map index") // ok to continue even if indexing failed - map element type is known x.mode_ = mapindex diff --git a/src/go/types/literals.go b/src/go/types/literals.go index f0feda67700f46..f0121e3172175e 100644 --- a/src/go/types/literals.go +++ b/src/go/types/literals.go @@ -297,7 +297,7 @@ func (check *Checker) compositeLit(U Type, x *operand, e *ast.CompositeLit, hint check.error(e, MissingLitKey, "missing key in map literal") continue } - check.genericExpr(nil, x, kv.Key, utyp.key) + check.genericExpr(utyp.key, x, kv.Key, utyp.key) check.assignment(x, utyp.key, "map literal") if !x.isValid() { continue @@ -322,7 +322,7 @@ func (check *Checker) compositeLit(U Type, x *operand, e *ast.CompositeLit, hint continue } } - check.genericExpr(nil, x, kv.Value, utyp.elem) + check.genericExpr(utyp.elem, x, kv.Value, utyp.elem) check.assignment(x, utyp.elem, "map literal") } @@ -399,7 +399,7 @@ func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64 // check element against composite literal element type var x operand - check.genericExpr(nil, &x, eval, typ) + check.genericExpr(typ, &x, eval, typ) check.assignment(&x, typ, "array or slice literal") } return max diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index 9093a104608eb8..b6dad78499cbd1 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -468,7 +468,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { // extract a target type for the sent value // TODO(mark): use T in an upcoming CL T := check.chanElem(inNode(s, s.Arrow), &ch, false) - check.genericExpr(nil, &val, s.Value, nil) + check.genericExpr(T, &val, s.Value, nil) if T != nil { check.assignment(&val, T, "send") } diff --git a/src/internal/types/testdata/check/compliterals.go b/src/internal/types/testdata/check/compliterals0.go similarity index 100% rename from src/internal/types/testdata/check/compliterals.go rename to src/internal/types/testdata/check/compliterals0.go diff --git a/src/internal/types/testdata/check/compliterals1.go b/src/internal/types/testdata/check/compliterals1.go new file mode 100644 index 00000000000000..bf75889456ea52 --- /dev/null +++ b/src/internal/types/testdata/check/compliterals1.go @@ -0,0 +1,96 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Composite literals with inferred types + +package comp_literals + +type T struct {} + +// var declaration +func _() { + var _ T = {} +} + +// assignment +func _() { + var x T + x = {} + _ = x // "use" it +} + +// // argument to function call +// func _() { +// f := func(_ T) {} +// f({}) +// } + +// // argument to function call with variadic arguments +// func _() { +// f := func(_ ...T) {} +// f({}, {}) +// } + +// map index expression +func _() { + var x map[T]int + _ = x[{}] +} + +// map index expression through a type parameter +func _[P map[T]int](x P) { + _ = x[{}] +} + +// // value of a struct literal with keys / values +// func _() { +// type S struct { +// f T +// } +// _ = S{f: {}} +// } + +// // value of a struct literal without keys / values +// func _() { +// type S struct { +// f T +// } +// _ = S{{}} +// } + +// values sent to a channel +func _() { + var x chan<- T + x <- {} +} + +// argument to conversion +func _() { + _ = T({}) +} + +// The below are all covered by the inference mechanism used before +// Go 1.28 (AKA "hints"). They are included here for completeness. + +// keys of a map literal +func _() { + type M map[T]int + _ = M{{}: 42} +} + +// values of a map literal +func _() { + type M map[int]T + _ = M{42: {}} +} + +// elements in an array literal +func _() { + _ = [42]T{{}} +} + +// elements in a slice literal +func _() { + _ = []T{{}} +} diff --git a/src/internal/types/testdata/check/compliterals2.go b/src/internal/types/testdata/check/compliterals2.go new file mode 100644 index 00000000000000..4e16bb33602d9b --- /dev/null +++ b/src/internal/types/testdata/check/compliterals2.go @@ -0,0 +1,99 @@ +// -lang=go1.27 + +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is a replica of compliterals1.go at Go 1.27 to ensure error +// messages are reported as expected. + +package comp_literals + +type T struct {} + +// var declaration +func _() { + var _ T = { /* ERROR "requires go1.28 or later" */ } +} + +// assignment +func _() { + var x T + x = { /* ERROR "requires go1.28 or later" */ } + _ = x // "use" it +} + +// // argument to function call +// func _() { +// f := func(_ T) {} +// f({ /* ERROR "requires go1.28 or later" */ }) +// } + +// // argument to function call with variadic arguments +// func _() { +// f := func(_ ...T) {} +// f({ /* ERROR "requires go1.28 or later" */ }, { /* ERROR "requires go1.28 or later" */ }) +// } + +// map index expression +func _() { + var x map[T]int + _ = x[{ /* ERROR "requires go1.28 or later" */ }] +} + +// map index expression through a type parameter +func _[P map[T]int](x P) { + _ = x[{ /* ERROR "requires go1.28 or later" */ }] +} + +// // value of a struct literal with keys / values +// func _() { +// type S struct { +// f T +// } +// _ = S{f: { /* ERROR "requires go1.28 or later" */ }} +// } + +// // value of a struct literal without keys / values +// func _() { +// type S struct { +// f T +// } +// _ = S{{ /* ERROR "requires go1.28 or later" */ }} +// } + +// values sent to a channel +func _() { + var x chan<- T + x <- { /* ERROR "requires go1.28 or later" */ } +} + +// argument to conversion +func _() { + _ = T({ /* ERROR "requires go1.28 or later" */ }) +} + +// The below are all covered by the inference mechanism used before +// Go 1.28 (AKA "hints"). They are included here for completeness. + +// keys of a map literal +func _() { + type M map[T]int + _ = M{{}: 42} +} + +// values of a map literal +func _() { + type M map[int]T + _ = M{42: {}} +} + +// elements in an array literal +func _() { + _ = [42]T{{}} +} + +// elements in a slice literal +func _() { + _ = []T{{}} +} diff --git a/src/internal/types/testdata/check/compliterals3.go b/src/internal/types/testdata/check/compliterals3.go new file mode 100644 index 00000000000000..6e4fa8c2c42b35 --- /dev/null +++ b/src/internal/types/testdata/check/compliterals3.go @@ -0,0 +1,63 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Some additional checks for inferred composite literal types + +package comp_literals + +type S1 struct{ + x int + y float64 + s string +} + +var ( + _ = { /* ERROR "missing type in composite literal" */ } + _ []int = {} + _ struct{} = {} + _ [10]byte = {1, 2, 3, 9: 10} + _ map[string]int = {"foo": 0, "bar": 1} +) + +// var ( +// _ = struct{ f struct { f int }}{{1}} +// ) + +func _() []int { + return nil + return {} + return {1, 2, 3} +} + +func _() S1 { + return {} + return {1, 2, "3"} + return {1.0, 2, ""} + return {s: "foo"} +} + +func _() []S1 { + return {} + return {{}} + return {{x: 1}, {y: 2}, {1, 2.0, "3"}} +} + +func f(s []int) { + s = {} + s = {1, 2, 3} + s = {0: 0, 1: 1} + s = {"foo" /* ERRORx "cannot use .* as int value" */ } +} + +// func _() { +// f({}) +// } + +type S2 struct { + f func(x int) +} + +func g1[T any](x T) {} + +var _ S2 = { g1 } From c122d7e6c50f8f1950a99b8e7b2b36e8a54cffce Mon Sep 17 00:00:00 2001 From: Mauri de Souza Meneguzzo Date: Fri, 12 Jun 2026 23:35:18 +0000 Subject: [PATCH 16/16] cmd/internal/obj/arm64: add CASPA/CASPAL/CASPL pair atomic instructions https://developer.arm.com/documentation/111108/2026-03/Base-Instructions/CASP--CASPA--CASPAL--CASPL--Compare-and-swap-pair-of-words-or-doublewords-in-memory- For #61236. Change-Id: I48d6c2548a5bc6c09ad50cef6261b455761db389 GitHub-Last-Rev: b5fa3b3ae8c228d0ccda2e11824fe6dd96c0907e GitHub-Pull-Request: golang/go#79992 Reviewed-on: https://go-review.googlesource.com/c/go/+/790321 Reviewed-by: Cherry Mui LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Dmitri Shuralyov --- src/cmd/asm/internal/arch/arm64.go | 5 ++++- src/cmd/asm/internal/asm/testdata/arm64.s | 6 ++++++ src/cmd/internal/obj/arm64/a.out.go | 6 ++++++ src/cmd/internal/obj/arm64/anames.go | 6 ++++++ src/cmd/internal/obj/arm64/asm7.go | 16 ++++++++++++++-- 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go index 24020a336b7536..c2c97b75f1fa93 100644 --- a/src/cmd/asm/internal/arch/arm64.go +++ b/src/cmd/asm/internal/arch/arm64.go @@ -137,7 +137,10 @@ func IsARM64TBL(op obj.As) bool { // destination is a register pair that require special handling. func IsARM64CASP(op obj.As) bool { switch op { - case arm64.ACASPD, arm64.ACASPW: + case arm64.ACASPD, arm64.ACASPW, + arm64.ACASPAD, arm64.ACASPAW, + arm64.ACASPALD, arm64.ACASPALW, + arm64.ACASPLD, arm64.ACASPLW: return true } return false diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index be4bf0c65a58e9..4487c71b9d0ef8 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -1215,6 +1215,12 @@ again: CASPD (R30, ZR), (RSP), (R8, R9) // e87f3e48 CASPW (R6, R7), (R8), (R4, R5) // 047d2608 CASPD (R2, R3), (R2), (R8, R9) // 487c2248 + CASPAD (R2, R3), (R2), (R8, R9) // 487c6248 + CASPAW (R6, R7), (R8), (R4, R5) // 047d6608 + CASPALD (R2, R3), (R2), (R8, R9) // 48fc6248 + CASPALW (R6, R7), (R8), (R4, R5) // 04fd6608 + CASPLD (R2, R3), (R2), (R8, R9) // 48fc2248 + CASPLW (R6, R7), (R8), (R4, R5) // 04fd2608 // RET RET // c0035fd6 diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go index 1426c72ee050eb..27146f6aa13f6d 100644 --- a/src/cmd/internal/obj/arm64/a.out.go +++ b/src/cmd/internal/obj/arm64/a.out.go @@ -717,7 +717,13 @@ const ( ACASH ACASLD ACASLW + ACASPAD + ACASPALD + ACASPALW + ACASPAW ACASPD + ACASPLD + ACASPLW ACASPW ACASW ACBNZ diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go index 62620e8737cd97..1f8222a1598612 100644 --- a/src/cmd/internal/obj/arm64/anames.go +++ b/src/cmd/internal/obj/arm64/anames.go @@ -64,7 +64,13 @@ var Anames = []string{ "CASH", "CASLD", "CASLW", + "CASPAD", + "CASPALD", + "CASPALW", + "CASPAW", "CASPD", + "CASPLD", + "CASPLW", "CASPW", "CASW", "CBNZ", diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 5bd3c4a8f306d9..0442df4ab9f28a 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -193,8 +193,14 @@ var atomicSWP = map[obj.As]uint32{ ACASALB: 0<<30 | 0x47<<21 | 0x3f<<10, } var atomicCASP = map[obj.As]uint32{ - ACASPD: 1<<30 | 0x41<<21 | 0x1f<<10, - ACASPW: 0<<30 | 0x41<<21 | 0x1f<<10, + ACASPD: 1<<30 | 0x41<<21 | 0x1f<<10, // CASP + ACASPW: 0<<30 | 0x41<<21 | 0x1f<<10, + ACASPAD: 1<<30 | 0x43<<21 | 0x1f<<10, // CASPA (acquire) + ACASPAW: 0<<30 | 0x43<<21 | 0x1f<<10, + ACASPALD: 1<<30 | 0x43<<21 | 0x3f<<10, // CASPAL (acquire+release) + ACASPALW: 0<<30 | 0x43<<21 | 0x3f<<10, + ACASPLD: 1<<30 | 0x41<<21 | 0x3f<<10, // CASPL (release) + ACASPLW: 0<<30 | 0x41<<21 | 0x3f<<10, } var oprange [obj.AllowedOpCodes][]Optab @@ -2874,6 +2880,12 @@ func buildop(ctxt *obj.Link) { case ACASPD: oprangeset(ACASPW, t) + oprangeset(ACASPAD, t) + oprangeset(ACASPAW, t) + oprangeset(ACASPALD, t) + oprangeset(ACASPALW, t) + oprangeset(ACASPLD, t) + oprangeset(ACASPLW, t) case ABEQ: oprangeset(ABNE, t) oprangeset(ABCS, t)