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/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/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}) +) 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/assignments.go b/src/cmd/compile/internal/types2/assignments.go index ac565fd6ab191b..cff9e95c0fdb26 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, 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), &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/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..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"), 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() { @@ -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 +293,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(utyp.key, x, kv.Key, utyp.key) check.assignment(x, utyp.key, "map literal") if !x.isValid() { continue @@ -302,7 +318,7 @@ func (check *Checker) compositeLit(x *operand, e *syntax.CompositeLit, hint Type continue } } - check.genericExpr(x, kv.Value, utyp.elem) + check.genericExpr(utyp.elem, x, kv.Value, utyp.elem) check.assignment(x, utyp.elem, "map literal") } @@ -379,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(&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/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/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/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 7bd5d8712b3889..19f3096e566c77 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,13 +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.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") + 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(T, &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(nil, &val, s.Value, nil) } case *syntax.AssignStmt: @@ -476,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 } @@ -591,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") } @@ -693,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") } @@ -717,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") @@ -784,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/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/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/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/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_ 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) 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/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/crypto/internal/fips140/subtle/xor_generic.go b/src/crypto/internal/fips140/subtle/xor_generic.go index 0b31eec60197d3..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 && !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 new file mode 100644 index 00000000000000..197fe634e0e9d9 --- /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 || mips64 || mips64le) && !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 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/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}) +) diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index 05b6e4845a9ff2..871d598ff14681 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, 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), &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/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..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"), 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) @@ -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<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/index.go b/src/go/types/index.go index 4ed3df46454d96..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(&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(&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 @@ -231,7 +231,7 @@ func (check *Checker) indexExpr(x *operand, e *indexedExpr) (isFuncInst bool) { } func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) { - check.expr(nil, x, e.X) + check.expr(nil, nil, x, e.X) if !x.isValid() { check.use(e.Low, e.High, e.Max) return @@ -422,7 +422,7 @@ func (check *Checker) index(index ast.Expr, max int64) (typ Type, val int64) { val = -1 var x operand - check.expr(nil, &x, index) + check.expr(nil, nil, &x, index) if !check.isValidIndex(&x, InvalidIndex, "index", false) { return } diff --git a/src/go/types/literals.go b/src/go/types/literals.go index 5b5fcf64efc24d..f0121e3172175e 100644 --- a/src/go/types/literals.go +++ b/src/go/types/literals.go @@ -108,7 +108,7 @@ func (check *Checker) funcLit(x *operand, e *ast.FuncLit) { } } -func (check *Checker) compositeLit(x *operand, e *ast.CompositeLit, hint Type) { +func (check *Checker) compositeLit(U Type, x *operand, e *ast.CompositeLit, hint Type) { var typ, base Type var isElem bool // true if composite literal is an element of an enclosing composite literal @@ -128,6 +128,8 @@ func (check *Checker) compositeLit(x *operand, e *ast.CompositeLit, hint Type) { 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(x *operand, e *ast.CompositeLit, hint Type) { 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. @@ -174,7 +190,7 @@ func (check *Checker) compositeLit(x *operand, e *ast.CompositeLit, hint Type) { key, _ := kv.Key.(*ast.Ident) // do all possible checks early (before exiting due to errors) // so we don't drop information on the floor - check.genericExpr(x, kv.Value, nil) + check.genericExpr(nil, x, kv.Value, nil) if key == nil { check.errorf(kv, InvalidLitField, "invalid field name %s in struct literal", kv.Key) continue @@ -218,7 +234,7 @@ func (check *Checker) compositeLit(x *operand, e *ast.CompositeLit, hint Type) { check.error(kv, MixedStructLit, "mixture of field:value and value elements in struct literal") continue } - check.genericExpr(x, e, nil) + check.genericExpr(nil, x, e, nil) if i >= len(fields) { check.errorf(x, InvalidStructLit, "too many values in struct literal of type %s", base) break // cannot continue @@ -281,7 +297,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(utyp.key, x, kv.Key, utyp.key) check.assignment(x, utyp.key, "map literal") if !x.isValid() { continue @@ -306,7 +322,7 @@ func (check *Checker) compositeLit(x *operand, e *ast.CompositeLit, hint Type) { continue } } - check.genericExpr(x, kv.Value, utyp.elem) + check.genericExpr(utyp.elem, x, kv.Value, utyp.elem) check.assignment(x, utyp.elem, "map literal") } @@ -383,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(&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/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/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/go/types/stmt.go b/src/go/types/stmt.go index 85c7576d7660c0..b6dad78499cbd1 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,13 +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.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") + 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(T, &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(nil, &val, s.Value, nil) } case *ast.IncDecStmt: @@ -485,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 } @@ -608,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") } @@ -632,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") @@ -727,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) @@ -836,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) 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)) 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 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/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 } 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() 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{} 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 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 } 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") + } +}