mirror of
https://github.com/golang/go.git
synced 2026-01-31 16:12:04 +03:00
Compare commits
69 Commits
go1.21rc2
...
dev.inline
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71aaa8bde1 | ||
|
|
894d24d617 | ||
|
|
ac9137f8d3 | ||
|
|
158d11196f | ||
|
|
d3d78b4bcc | ||
|
|
39c5070712 | ||
|
|
e6ec2a34dc | ||
|
|
449ef3795d | ||
|
|
6305d7fdd3 | ||
|
|
b490bdc27d | ||
|
|
36ea4f9680 | ||
|
|
3fce111535 | ||
|
|
c8dad424bf | ||
|
|
cd6676126b | ||
|
|
b2215e49c7 | ||
|
|
e126572f8a | ||
|
|
e4ed92a355 | ||
|
|
5c1a15df41 | ||
|
|
5b72f45dd1 | ||
|
|
18e17e2cb1 | ||
|
|
1e97c51536 | ||
|
|
683f51d307 | ||
|
|
2db31efdba | ||
|
|
3aba453b66 | ||
|
|
499458f7ca | ||
|
|
fe73c186eb | ||
|
|
da5d8fdd0c | ||
|
|
411c99671a | ||
|
|
03cd8a7b0e | ||
|
|
8b5fe5980c | ||
|
|
79d4defa75 | ||
|
|
a3093eca64 | ||
|
|
6691f438c3 | ||
|
|
942c1c12d8 | ||
|
|
4ad4128d3c | ||
|
|
4f36f7e4dd | ||
|
|
8008c0840f | ||
|
|
13529cc5f4 | ||
|
|
1dbbafc70f | ||
|
|
7cc0740596 | ||
|
|
d49017a7c3 | ||
|
|
b3ca8d2b3c | ||
|
|
ee361ce66c | ||
|
|
9f6e87ff74 | ||
|
|
f5015b5164 | ||
|
|
a031f4ef83 | ||
|
|
ea927e560d | ||
|
|
3619255777 | ||
|
|
48dbb6227a | ||
|
|
3adcce5ae7 | ||
|
|
6dce882b3a | ||
|
|
164aceea08 | ||
|
|
82e17c4d11 | ||
|
|
25e46693a1 | ||
|
|
f8616b8484 | ||
|
|
51885c1fa2 | ||
|
|
3479e1e543 | ||
|
|
20313660f5 | ||
|
|
78c3aba470 | ||
|
|
633b742ae0 | ||
|
|
ad2c517708 | ||
|
|
b23cae8095 | ||
|
|
b1f1fb2950 | ||
|
|
e45202f215 | ||
|
|
36edde9d9f | ||
|
|
413e6c0499 | ||
|
|
f3bf18117b | ||
|
|
e122ebabb6 | ||
|
|
8484f2fe02 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -33,12 +33,10 @@ _testmain.go
|
||||
/src/cmd/cgo/zdefaultcc.go
|
||||
/src/cmd/dist/dist
|
||||
/src/cmd/go/internal/cfg/zdefaultcc.go
|
||||
/src/cmd/go/internal/cfg/zosarch.go
|
||||
/src/cmd/internal/objabi/zbootstrap.go
|
||||
/src/go/build/zcgo.go
|
||||
/src/go/doc/headscan
|
||||
/src/internal/buildcfg/zbootstrap.go
|
||||
/src/internal/platform/zosarch.go
|
||||
/src/runtime/internal/sys/zversion.go
|
||||
/src/unicode/maketables
|
||||
/src/time/tzdata/zzipdata.go
|
||||
|
||||
@@ -174,6 +174,7 @@ pkg go/build, type Package struct, Directives []Directive #56986
|
||||
pkg go/build, type Package struct, TestDirectives []Directive #56986
|
||||
pkg go/build, type Package struct, XTestDirectives []Directive #56986
|
||||
pkg go/token, method (*File) Lines() []int #57708
|
||||
pkg go/types, method (*Package) GoVersion() string #61175
|
||||
pkg html/template, const ErrJSTemplate = 12 #59584
|
||||
pkg html/template, const ErrJSTemplate ErrorCode #59584
|
||||
pkg io/fs, func FormatDirEntry(DirEntry) string #54451
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
branch: release-branch.go1.21
|
||||
branch: dev.inline
|
||||
parent-branch: master
|
||||
|
||||
@@ -473,6 +473,16 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
The new <a href="/pkg/context/#AfterFunc"><code>AfterFunc</code></a>
|
||||
function registers a function to run after a context has been cancelled.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 455455 -->
|
||||
An optimization means that the results of calling
|
||||
<a href="/pkg/context/#Background"><code>Background</code></a>
|
||||
and <a href="/pkg/context/#TODO"><code>TODO</code></a> and
|
||||
converting them to a shared type can be considered equal.
|
||||
In previous releases they were always different. Comparing
|
||||
<a href="/pkg/context/#Context"><code>Context</code></a> values
|
||||
for equality has never been well-defined, so this is not
|
||||
considered to be an incompatible change.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@@ -495,7 +505,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
<dl id="crypto/rsa"><dt><a href="/pkg/crypto/rsa/">crypto/rsa</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 471259, CL 492935 -->
|
||||
The performance of private RSA operations (decryption and signing) is now better than Go 1.19 for <code>GOOS=amd64</code> and <code>GOOS=arm64</code>. It had regressed in Go 1.20.
|
||||
The performance of private RSA operations (decryption and signing) is now better than Go 1.19 for <code>GOARCH=amd64</code> and <code>GOARCH=arm64</code>. It had regressed in Go 1.20.
|
||||
</p>
|
||||
<p>
|
||||
Due to the addition of private fields to <a href="/pkg/crypto/rsa/#PrecomputedValues"><code>PrecomputedValues</code></a>, <a href="/pkg/crypto/rsa/#PrivateKey.Precompute"><code>PrivateKey.Precompute</code></a> must be called for optimal performance even if deserializing (for example from JSON) a previously-precomputed private key.
|
||||
@@ -511,7 +521,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
<dl id="crypto/sha256"><dt><a href="/pkg/crypto/sha256/">crypto/sha256</a></dt>
|
||||
<dd>
|
||||
<p><!-- https://go.dev/issue/50543, CL 408795 -->
|
||||
SHA-224 and SHA-256 operations now use native instructions when available when <code>GOOS=amd64</code>, providing a performance improvement on the order of 3-4x.
|
||||
SHA-224 and SHA-256 operations now use native instructions when available when <code>GOARCH=amd64</code>, providing a performance improvement on the order of 3-4x.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/sha256 -->
|
||||
@@ -579,7 +589,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
|
||||
<dd>
|
||||
<p><!-- https://go.dev/issue/53573, CL 468875 -->
|
||||
<a href="/pkg/crypto/x509/#RevocationList.RevokedCertificates"><code>RevocationList.RevokedCertificates</code></a> has been deprecated and replaced with the new <a href="/pkg/crypto/x509/#RevocationList.Entries"><code>RevocationList.Entries</code></a> field, which is a slice of <a href="/pkg/crypto/x509/#RevocationListEntry"><code>RevocationListEntry</code></a>. <a href="/pkg/crypto/x509/#RevocationListEntry"><code>RevocationListEntry</code></a> contains all of the fields in <a href="/pkg/crypto/x509/#pkix.RevokedCertificate"><code>pkix.RevokedCertificate</code></a>, as well as the revocation reason code.
|
||||
<a href="/pkg/crypto/x509/#RevocationList.RevokedCertificates"><code>RevocationList.RevokedCertificates</code></a> has been deprecated and replaced with the new <a href="/pkg/crypto/x509/#RevocationList.RevokedCertificateEntries"><code>RevokedCertificateEntries</code></a> field, which is a slice of <a href="/pkg/crypto/x509/#RevocationListEntry"><code>RevocationListEntry</code></a>. <a href="/pkg/crypto/x509/#RevocationListEntry"><code>RevocationListEntry</code></a> contains all of the fields in <a href="/pkg/crypto/x509/pkix#RevokedCertificate"><code>pkix.RevokedCertificate</code></a>, as well as the revocation reason code.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/x509 -->
|
||||
|
||||
@@ -652,6 +652,38 @@ func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEqualBothUnaligned(b *testing.B) {
|
||||
sizes := []int{64, 4 << 10}
|
||||
if !isRaceBuilder {
|
||||
sizes = append(sizes, []int{4 << 20, 64 << 20}...)
|
||||
}
|
||||
maxSize := 2 * (sizes[len(sizes)-1] + 8)
|
||||
if len(bmbuf) < maxSize {
|
||||
bmbuf = make([]byte, maxSize)
|
||||
}
|
||||
|
||||
for _, n := range sizes {
|
||||
for _, off := range []int{0, 1, 4, 7} {
|
||||
buf1 := bmbuf[off : off+n]
|
||||
buf2Start := (len(bmbuf) / 2) + off
|
||||
buf2 := bmbuf[buf2Start : buf2Start+n]
|
||||
buf1[n-1] = 'x'
|
||||
buf2[n-1] = 'x'
|
||||
b.Run(fmt.Sprint(n, off), func(b *testing.B) {
|
||||
b.SetBytes(int64(n))
|
||||
for i := 0; i < b.N; i++ {
|
||||
eq := Equal(buf1, buf2)
|
||||
if !eq {
|
||||
b.Fatal("bad equal")
|
||||
}
|
||||
}
|
||||
})
|
||||
buf1[n-1] = '\x00'
|
||||
buf2[n-1] = '\x00'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIndex(b *testing.B) {
|
||||
benchBytes(b, indexSizes, func(b *testing.B, n int) {
|
||||
buf := bmbuf[0:n]
|
||||
|
||||
@@ -65,7 +65,7 @@ func (s *Slice) Col() int {
|
||||
// #define A #define B(x) x
|
||||
// and
|
||||
// #define A #define B (x) x
|
||||
// The first has definition of B has an argument, the second doesn't. Because we let
|
||||
// The first definition of B has an argument, the second doesn't. Because we let
|
||||
// text/scanner strip the blanks for us, this is extremely rare, hard to fix, and not worth it.
|
||||
return s.pos
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
// Package devirtualize implements two "devirtualization" optimization passes:
|
||||
//
|
||||
// - "Static" devirtualization which replaces interface method calls with
|
||||
// direct concrete-type method calls where possible.
|
||||
// - "Profile-guided" devirtualization which replaces indirect calls with a
|
||||
// conditional direct call to the hottest concrete callee from a profile, as
|
||||
// well as a fallback using the original indirect call.
|
||||
// - "Static" devirtualization which replaces interface method calls with
|
||||
// direct concrete-type method calls where possible.
|
||||
// - "Profile-guided" devirtualization which replaces indirect calls with a
|
||||
// conditional direct call to the hottest concrete callee from a profile, as
|
||||
// well as a fallback using the original indirect call.
|
||||
package devirtualize
|
||||
|
||||
import (
|
||||
|
||||
@@ -52,7 +52,6 @@ type Node interface {
|
||||
// 0 means the node is not typechecked
|
||||
// 1 means the node is completely typechecked
|
||||
// 2 means typechecking of the node is in progress
|
||||
// 3 means the node has its type from types2, but may need transformation
|
||||
Typecheck() uint8
|
||||
SetTypecheck(x uint8)
|
||||
NonNil() bool
|
||||
|
||||
@@ -115,6 +115,17 @@ func VisitList(list Nodes, visit func(Node)) {
|
||||
}
|
||||
}
|
||||
|
||||
// VisitFuncAndClosures calls visit on each non-nil node in fn.Body,
|
||||
// including any nested closure bodies.
|
||||
func VisitFuncAndClosures(fn *Func, visit func(n Node)) {
|
||||
VisitList(fn.Body, func(n Node) {
|
||||
visit(n)
|
||||
if n, ok := n.(*ClosureExpr); ok && n.Op() == OCLOSURE {
|
||||
VisitFuncAndClosures(n.Func, visit)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Any looks for a non-nil node x in the IR tree rooted at n
|
||||
// for which cond(x) returns true.
|
||||
// Any considers nodes in a depth-first, preorder traversal.
|
||||
|
||||
@@ -3919,7 +3919,11 @@ func finishWrapperFunc(fn *ir.Func, target *ir.Package) {
|
||||
// The body of wrapper function after inlining may reveal new ir.OMETHVALUE node,
|
||||
// we don't know whether wrapper function has been generated for it or not, so
|
||||
// generate one immediately here.
|
||||
ir.VisitList(fn.Body, func(n ir.Node) {
|
||||
//
|
||||
// Further, after CL 492017, function that construct closures is allowed to be inlined,
|
||||
// even though the closure itself can't be inline. So we also need to visit body of any
|
||||
// closure that we see when visiting body of the wrapper function.
|
||||
ir.VisitFuncAndClosures(fn, func(n ir.Node) {
|
||||
if n, ok := n.(*ir.SelectorExpr); ok && n.Op() == ir.OMETHVALUE {
|
||||
wrapMethodValue(n.X.Type(), n.Selection, target, true)
|
||||
}
|
||||
|
||||
@@ -836,11 +836,11 @@
|
||||
//
|
||||
// Key:
|
||||
//
|
||||
// [+ -](x * y) [+ -] z.
|
||||
// _ N A S
|
||||
// D U
|
||||
// D B
|
||||
// [+ -](x * y [+ -] z).
|
||||
// _ N A S
|
||||
// D U
|
||||
// D B
|
||||
//
|
||||
// Note: multiplication commutativity handled by rule generator.
|
||||
(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMADD|MADD|NMSUB|MSUB)D x y z)
|
||||
(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMSUB|MSUB|NMADD|MADD)D x y z)
|
||||
(F(MADD|NMADD|MSUB|NMSUB)D x y neg:(FNEGD z)) && neg.Uses == 1 => (F(MSUB|NMSUB|MADD|NMADD)D x y z)
|
||||
|
||||
@@ -3322,7 +3322,7 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (FMADDD neg:(FNEGD x) y z)
|
||||
// cond: neg.Uses == 1
|
||||
// result: (FNMADDD x y z)
|
||||
// result: (FNMSUBD x y z)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
neg := v_0
|
||||
@@ -3335,7 +3335,7 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
|
||||
if !(neg.Uses == 1) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpRISCV64FNMADDD)
|
||||
v.reset(OpRISCV64FNMSUBD)
|
||||
v.AddArg3(x, y, z)
|
||||
return true
|
||||
}
|
||||
@@ -3367,7 +3367,7 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (FMSUBD neg:(FNEGD x) y z)
|
||||
// cond: neg.Uses == 1
|
||||
// result: (FNMSUBD x y z)
|
||||
// result: (FNMADDD x y z)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
neg := v_0
|
||||
@@ -3380,7 +3380,7 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool {
|
||||
if !(neg.Uses == 1) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpRISCV64FNMSUBD)
|
||||
v.reset(OpRISCV64FNMADDD)
|
||||
v.AddArg3(x, y, z)
|
||||
return true
|
||||
}
|
||||
@@ -3412,7 +3412,7 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (FNMADDD neg:(FNEGD x) y z)
|
||||
// cond: neg.Uses == 1
|
||||
// result: (FMADDD x y z)
|
||||
// result: (FMSUBD x y z)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
neg := v_0
|
||||
@@ -3425,7 +3425,7 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool {
|
||||
if !(neg.Uses == 1) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpRISCV64FMADDD)
|
||||
v.reset(OpRISCV64FMSUBD)
|
||||
v.AddArg3(x, y, z)
|
||||
return true
|
||||
}
|
||||
@@ -3457,7 +3457,7 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (FNMSUBD neg:(FNEGD x) y z)
|
||||
// cond: neg.Uses == 1
|
||||
// result: (FMSUBD x y z)
|
||||
// result: (FMADDD x y z)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
neg := v_0
|
||||
@@ -3470,7 +3470,7 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool {
|
||||
if !(neg.Uses == 1) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpRISCV64FMSUBD)
|
||||
v.reset(OpRISCV64FMADDD)
|
||||
v.AddArg3(x, y, z)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3620,8 +3620,13 @@ func (s *state) minMax(n *ir.CallExpr) *ssa.Value {
|
||||
|
||||
// ternary emits code to evaluate cond ? x : y.
|
||||
func (s *state) ternary(cond, x, y *ssa.Value) *ssa.Value {
|
||||
// Note that we need a new ternaryVar each time (unlike okVar where we can
|
||||
// reuse the variable) because it might have a different type every time.
|
||||
ternaryVar := ssaMarker("ternary")
|
||||
|
||||
bThen := s.f.NewBlock(ssa.BlockPlain)
|
||||
bElse := s.f.NewBlock(ssa.BlockPlain)
|
||||
bEnd := s.f.NewBlock(ssa.BlockPlain)
|
||||
|
||||
b := s.endBlock()
|
||||
b.Kind = ssa.BlockIf
|
||||
@@ -3629,11 +3634,18 @@ func (s *state) ternary(cond, x, y *ssa.Value) *ssa.Value {
|
||||
b.AddEdgeTo(bThen)
|
||||
b.AddEdgeTo(bElse)
|
||||
|
||||
s.startBlock(bElse)
|
||||
s.endBlock().AddEdgeTo(bThen)
|
||||
|
||||
s.startBlock(bThen)
|
||||
return s.newValue2(ssa.OpPhi, x.Type, x, y)
|
||||
s.vars[ternaryVar] = x
|
||||
s.endBlock().AddEdgeTo(bEnd)
|
||||
|
||||
s.startBlock(bElse)
|
||||
s.vars[ternaryVar] = y
|
||||
s.endBlock().AddEdgeTo(bEnd)
|
||||
|
||||
s.startBlock(bEnd)
|
||||
r := s.variable(ternaryVar, x.Type)
|
||||
delete(s.vars, ternaryVar)
|
||||
return r
|
||||
}
|
||||
|
||||
// condBranch evaluates the boolean expression cond and branches to yes
|
||||
|
||||
@@ -607,7 +607,7 @@ func tcSwitchType(n *ir.SwitchStmt) {
|
||||
if !n1.Type().IsInterface() {
|
||||
why := ImplementsExplain(n1.Type(), t)
|
||||
if why != "" {
|
||||
base.ErrorfAt(ncase.Pos(), errors.ImpossibleAssert, "impossible type switch case: %L cannot have dynamic type %v (%s)" , guard.X, n1.Type(), why)
|
||||
base.ErrorfAt(ncase.Pos(), errors.ImpossibleAssert, "impossible type switch case: %L cannot have dynamic type %v (%s)", guard.X, n1.Type(), why)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -713,12 +713,12 @@ func ImplementsExplain(t, iface *types.Type) string {
|
||||
return fmt.Sprintf("%v does not implement %v (%v method is marked 'nointerface')", t, iface, missing.Sym)
|
||||
} else if have != nil && have.Sym == missing.Sym {
|
||||
return fmt.Sprintf("%v does not implement %v (wrong type for %v method)\n"+
|
||||
"\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
||||
"\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
||||
} else if ptr != 0 {
|
||||
return fmt.Sprintf("%v does not implement %v (%v method has pointer receiver)", t, iface, missing.Sym)
|
||||
} else if have != nil {
|
||||
return fmt.Sprintf("%v does not implement %v (missing %v method)\n"+
|
||||
"\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
||||
"\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
||||
}
|
||||
return fmt.Sprintf("%v does not implement %v (missing %v method)", t, iface, missing.Sym)
|
||||
}
|
||||
|
||||
@@ -578,6 +578,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
x.mode = value
|
||||
}
|
||||
|
||||
// Use the final type computed above for all arguments.
|
||||
for _, a := range args {
|
||||
check.updateExprType(a.expr, x.typ, true)
|
||||
}
|
||||
|
||||
if check.recordTypes() && x.mode != constant_ {
|
||||
types := make([]Type, nargs)
|
||||
for i := range types {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"internal/goversion"
|
||||
. "internal/types/errors"
|
||||
)
|
||||
|
||||
@@ -231,19 +232,19 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
|
||||
info = new(Info)
|
||||
}
|
||||
|
||||
version, err := parseGoVersion(conf.GoVersion)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
|
||||
}
|
||||
// Note: clients may call NewChecker with the Unsafe package, which is
|
||||
// globally shared and must not be mutated. Therefore NewChecker must not
|
||||
// mutate *pkg.
|
||||
//
|
||||
// (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
|
||||
|
||||
return &Checker{
|
||||
conf: conf,
|
||||
ctxt: conf.Context,
|
||||
pkg: pkg,
|
||||
Info: info,
|
||||
version: version,
|
||||
objMap: make(map[Object]*declInfo),
|
||||
impMap: make(map[importKey]*Package),
|
||||
conf: conf,
|
||||
ctxt: conf.Context,
|
||||
pkg: pkg,
|
||||
Info: info,
|
||||
objMap: make(map[Object]*declInfo),
|
||||
impMap: make(map[importKey]*Package),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,6 +334,20 @@ func (check *Checker) Files(files []*syntax.File) error { return check.checkFile
|
||||
var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
|
||||
|
||||
func (check *Checker) checkFiles(files []*syntax.File) (err error) {
|
||||
if check.pkg == Unsafe {
|
||||
// Defensive handling for Unsafe, which cannot be type checked, and must
|
||||
// not be mutated. See https://go.dev/issue/61212 for an example of where
|
||||
// Unsafe is passed to NewChecker.
|
||||
return nil
|
||||
}
|
||||
|
||||
check.version, err = parseGoVersion(check.conf.GoVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if check.version.after(version{1, goversion.Version}) {
|
||||
return fmt.Errorf("package requires newer Go version %v", check.version)
|
||||
}
|
||||
if check.conf.FakeImportC && check.conf.go115UsesCgo {
|
||||
return errBadCgo
|
||||
}
|
||||
@@ -377,6 +392,7 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
|
||||
check.monomorph()
|
||||
}
|
||||
|
||||
check.pkg.goVersion = check.conf.GoVersion
|
||||
check.pkg.complete = true
|
||||
|
||||
// no longer needed - release memory
|
||||
|
||||
@@ -184,6 +184,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
|
||||
|
||||
if !valid {
|
||||
check.errorf(e.Pos(), NonSliceableOperand, invalidOp+"cannot index %s", x)
|
||||
check.use(e.Index)
|
||||
x.mode = invalid
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -497,14 +497,14 @@ func TestIssue43088(t *testing.T) {
|
||||
// _ T2
|
||||
// }
|
||||
// }
|
||||
n1 := NewTypeName(syntax.Pos{}, nil, "T1", nil)
|
||||
n1 := NewTypeName(nopos, nil, "T1", nil)
|
||||
T1 := NewNamed(n1, nil, nil)
|
||||
n2 := NewTypeName(syntax.Pos{}, nil, "T2", nil)
|
||||
n2 := NewTypeName(nopos, nil, "T2", nil)
|
||||
T2 := NewNamed(n2, nil, nil)
|
||||
s1 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil)
|
||||
s1 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
|
||||
T1.SetUnderlying(s1)
|
||||
s2 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil)
|
||||
s3 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", s2, false)}, nil)
|
||||
s2 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
|
||||
s3 := NewStruct([]*Var{NewField(nopos, nil, "_", s2, false)}, nil)
|
||||
T2.SetUnderlying(s3)
|
||||
|
||||
// These calls must terminate (no endless recursion).
|
||||
@@ -535,38 +535,69 @@ func TestIssue44515(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue43124(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
// TODO(rFindley) move this to testdata by enhancing support for importing.
|
||||
|
||||
testenv.MustHaveGoBuild(t) // The go command is needed for the importer to determine the locations of stdlib .a files.
|
||||
|
||||
// All involved packages have the same name (template). Error messages should
|
||||
// disambiguate between text/template and html/template by printing the full
|
||||
// path.
|
||||
const (
|
||||
asrc = `package a; import "text/template"; func F(template.Template) {}; func G(int) {}`
|
||||
bsrc = `package b; import ("a"; "html/template"); func _() { a.F(template.Template{}) }`
|
||||
csrc = `package c; import ("a"; "html/template"); func _() { a.G(template.Template{}) }`
|
||||
bsrc = `
|
||||
package b
|
||||
|
||||
import (
|
||||
"a"
|
||||
"html/template"
|
||||
)
|
||||
|
||||
func _() {
|
||||
// Packages should be fully qualified when there is ambiguity within the
|
||||
// error string itself.
|
||||
a.F(template /* ERRORx "cannot use.*html/template.* as .*text/template" */ .Template{})
|
||||
}
|
||||
`
|
||||
csrc = `
|
||||
package c
|
||||
|
||||
import (
|
||||
"a"
|
||||
"fmt"
|
||||
"html/template"
|
||||
)
|
||||
|
||||
// go.dev/issue/46905: make sure template is not the first package qualified.
|
||||
var _ fmt.Stringer = 1 // ERRORx "cannot use 1.*as fmt\\.Stringer"
|
||||
|
||||
// Packages should be fully qualified when there is ambiguity in reachable
|
||||
// packages. In this case both a (and for that matter html/template) import
|
||||
// text/template.
|
||||
func _() { a.G(template /* ERRORx "cannot use .*html/template.*Template" */ .Template{}) }
|
||||
`
|
||||
|
||||
tsrc = `
|
||||
package template
|
||||
|
||||
import "text/template"
|
||||
|
||||
type T int
|
||||
|
||||
// Verify that the current package name also causes disambiguation.
|
||||
var _ T = template /* ERRORx "cannot use.*text/template.* as T value" */.Template{}
|
||||
`
|
||||
)
|
||||
|
||||
a := mustTypecheck(asrc, nil, nil)
|
||||
conf := Config{Importer: importHelper{pkg: a, fallback: defaultImporter()}}
|
||||
imp := importHelper{pkg: a, fallback: defaultImporter()}
|
||||
|
||||
// Packages should be fully qualified when there is ambiguity within the
|
||||
// error string itself.
|
||||
_, err := typecheck(bsrc, &conf, nil)
|
||||
if err == nil {
|
||||
t.Fatal("package b had no errors")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "text/template") || !strings.Contains(err.Error(), "html/template") {
|
||||
t.Errorf("type checking error for b does not disambiguate package template: %q", err)
|
||||
withImporter := func(cfg *Config) {
|
||||
cfg.Importer = imp
|
||||
}
|
||||
|
||||
// ...and also when there is any ambiguity in reachable packages.
|
||||
_, err = typecheck(csrc, &conf, nil)
|
||||
if err == nil {
|
||||
t.Fatal("package c had no errors")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "html/template") {
|
||||
t.Errorf("type checking error for c does not disambiguate package template: %q", err)
|
||||
}
|
||||
testFiles(t, []string{"b.go"}, [][]byte{[]byte(bsrc)}, 0, false, withImporter)
|
||||
testFiles(t, []string{"c.go"}, [][]byte{[]byte(csrc)}, 0, false, withImporter)
|
||||
testFiles(t, []string{"t.go"}, [][]byte{[]byte(tsrc)}, 0, false, withImporter)
|
||||
}
|
||||
|
||||
func TestIssue50646(t *testing.T) {
|
||||
|
||||
@@ -10,13 +10,14 @@ import (
|
||||
|
||||
// A Package describes a Go package.
|
||||
type Package struct {
|
||||
path string
|
||||
name string
|
||||
scope *Scope
|
||||
imports []*Package
|
||||
complete bool
|
||||
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
|
||||
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
|
||||
path string
|
||||
name string
|
||||
scope *Scope
|
||||
imports []*Package
|
||||
complete bool
|
||||
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
|
||||
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
|
||||
goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod)
|
||||
}
|
||||
|
||||
// NewPackage returns a new Package for the given package path and name.
|
||||
@@ -35,6 +36,12 @@ func (pkg *Package) Name() string { return pkg.name }
|
||||
// SetName sets the package name.
|
||||
func (pkg *Package) SetName(name string) { pkg.name = name }
|
||||
|
||||
// GoVersion returns the minimum Go version required by this package.
|
||||
// If the minimum version is unknown, GoVersion returns the empty string.
|
||||
// Individual source files may specify a different minimum Go version,
|
||||
// as reported in the [go/ast.File.GoVersion] field.
|
||||
func (pkg *Package) GoVersion() string { return pkg.goVersion }
|
||||
|
||||
// Scope returns the (complete or incomplete) package scope
|
||||
// holding the objects declared at package level (TypeNames,
|
||||
// Consts, Vars, and Funcs).
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestSizeof(t *testing.T) {
|
||||
|
||||
// Misc
|
||||
{Scope{}, 60, 104},
|
||||
{Package{}, 36, 72},
|
||||
{Package{}, 44, 88},
|
||||
{_TypeSet{}, 28, 56},
|
||||
}
|
||||
|
||||
|
||||
@@ -124,6 +124,20 @@ const (
|
||||
exact
|
||||
)
|
||||
|
||||
func (m unifyMode) String() string {
|
||||
switch m {
|
||||
case 0:
|
||||
return "inexact"
|
||||
case assign:
|
||||
return "assign"
|
||||
case exact:
|
||||
return "exact"
|
||||
case assign | exact:
|
||||
return "assign, exact"
|
||||
}
|
||||
return fmt.Sprintf("mode %d", m)
|
||||
}
|
||||
|
||||
// unify attempts to unify x and y and reports whether it succeeded.
|
||||
// As a side-effect, types may be inferred for type parameters.
|
||||
// The mode parameter controls how types are compared.
|
||||
@@ -256,6 +270,15 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
|
||||
return list
|
||||
}
|
||||
|
||||
// asInterface returns the underlying type of x as an interface if
|
||||
// it is a non-type parameter interface. Otherwise it returns nil.
|
||||
func asInterface(x Type) (i *Interface) {
|
||||
if _, ok := x.(*TypeParam); !ok {
|
||||
i, _ = under(x).(*Interface)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// nify implements the core unification algorithm which is an
|
||||
// adapted version of Checker.identical. For changes to that
|
||||
// code the corresponding changes should be made here.
|
||||
@@ -263,7 +286,7 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
|
||||
func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
u.depth++
|
||||
if traceInference {
|
||||
u.tracef("%s ≡ %s (mode %d)", x, y, mode)
|
||||
u.tracef("%s ≡ %s\t// %s", x, y, mode)
|
||||
}
|
||||
defer func() {
|
||||
if traceInference && !result {
|
||||
@@ -294,7 +317,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// - type parameter recorded with u, make sure one is in x
|
||||
if _, ok := x.(*Named); ok || u.asTypeParam(y) != nil {
|
||||
if traceInference {
|
||||
u.tracef("%s ≡ %s (swap)", y, x)
|
||||
u.tracef("%s ≡ %s\t// swap", y, x)
|
||||
}
|
||||
x, y = y, x
|
||||
}
|
||||
@@ -350,11 +373,49 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
if x := u.at(px); x != nil {
|
||||
// x has an inferred type which must match y
|
||||
if u.nify(x, y, mode, p) {
|
||||
// If we have a match, possibly through underlying types,
|
||||
// and y is a defined type, make sure we record that type
|
||||
// We have a match, possibly through underlying types.
|
||||
xi := asInterface(x)
|
||||
yi := asInterface(y)
|
||||
_, xn := x.(*Named)
|
||||
_, yn := y.(*Named)
|
||||
// If we have two interfaces, what to do depends on
|
||||
// whether they are named and their method sets.
|
||||
if xi != nil && yi != nil {
|
||||
// Both types are interfaces.
|
||||
// If both types are defined types, they must be identical
|
||||
// because unification doesn't know which type has the "right" name.
|
||||
if xn && yn {
|
||||
return Identical(x, y)
|
||||
}
|
||||
// In all other cases, the method sets must match.
|
||||
// The types unified so we know that corresponding methods
|
||||
// match and we can simply compare the number of methods.
|
||||
// TODO(gri) We may be able to relax this rule and select
|
||||
// the more general interface. But if one of them is a defined
|
||||
// type, it's not clear how to choose and whether we introduce
|
||||
// an order dependency or not. Requiring the same method set
|
||||
// is conservative.
|
||||
if len(xi.typeSet().methods) != len(yi.typeSet().methods) {
|
||||
return false
|
||||
}
|
||||
} else if xi != nil || yi != nil {
|
||||
// One but not both of them are interfaces.
|
||||
// In this case, either x or y could be viable matches for the corresponding
|
||||
// type parameter, which means choosing either introduces an order dependence.
|
||||
// Therefore, we must fail unification (go.dev/issue/60933).
|
||||
return false
|
||||
}
|
||||
// If y is a defined type, make sure we record that type
|
||||
// for type parameter x, which may have until now only
|
||||
// recorded an underlying type (go.dev/issue/43056).
|
||||
if _, ok := y.(*Named); ok {
|
||||
// Either both types are interfaces, or neither type is.
|
||||
// If both are interfaces, they have the same methods.
|
||||
//
|
||||
// Note: Changing the recorded type for a type parameter to
|
||||
// a defined type is only ok when unification is inexact.
|
||||
// But in exact unification, if we have a match, x and y must
|
||||
// be identical, so changing the recorded type for x is a no-op.
|
||||
if yn {
|
||||
u.set(px, y)
|
||||
}
|
||||
return true
|
||||
@@ -384,14 +445,8 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
if enableInterfaceInference && mode&exact == 0 {
|
||||
// One or both interfaces may be defined types.
|
||||
// Look under the name, but not under type parameters (go.dev/issue/60564).
|
||||
var xi *Interface
|
||||
if _, ok := x.(*TypeParam); !ok {
|
||||
xi, _ = under(x).(*Interface)
|
||||
}
|
||||
var yi *Interface
|
||||
if _, ok := y.(*TypeParam); !ok {
|
||||
yi, _ = under(y).(*Interface)
|
||||
}
|
||||
xi := asInterface(x)
|
||||
yi := asInterface(y)
|
||||
// If we have two interfaces, check the type terms for equivalence,
|
||||
// and unify common methods if possible.
|
||||
if xi != nil && yi != nil {
|
||||
@@ -492,7 +547,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// TODO(gri) Factor out type parameter handling from the switch.
|
||||
if isTypeParam(y) {
|
||||
if traceInference {
|
||||
u.tracef("%s ≡ %s (swap)", y, x)
|
||||
u.tracef("%s ≡ %s\t// swap", y, x)
|
||||
}
|
||||
x, y = y, x
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ package types2
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/syntax"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
@@ -44,23 +43,24 @@ var (
|
||||
go1_21 = version{1, 21}
|
||||
)
|
||||
|
||||
var errVersionSyntax = errors.New("invalid Go version syntax")
|
||||
|
||||
// parseGoVersion parses a Go version string (such as "go1.12")
|
||||
// and returns the version, or an error. If s is the empty
|
||||
// string, the version is 0.0.
|
||||
func parseGoVersion(s string) (v version, err error) {
|
||||
bad := func() (version, error) {
|
||||
return version{}, fmt.Errorf("invalid Go version syntax %q", s)
|
||||
}
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(s, "go") {
|
||||
return version{}, errVersionSyntax
|
||||
return bad()
|
||||
}
|
||||
s = s[len("go"):]
|
||||
i := 0
|
||||
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
|
||||
if i >= 10 || i == 0 && s[i] == '0' {
|
||||
return version{}, errVersionSyntax
|
||||
return bad()
|
||||
}
|
||||
v.major = 10*v.major + int(s[i]) - '0'
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func parseGoVersion(s string) (v version, err error) {
|
||||
return
|
||||
}
|
||||
if i == 0 || s[i] != '.' {
|
||||
return version{}, errVersionSyntax
|
||||
return bad()
|
||||
}
|
||||
s = s[i+1:]
|
||||
if s == "0" {
|
||||
@@ -81,14 +81,15 @@ func parseGoVersion(s string) (v version, err error) {
|
||||
i = 0
|
||||
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
|
||||
if i >= 10 || i == 0 && s[i] == '0' {
|
||||
return version{}, errVersionSyntax
|
||||
return bad()
|
||||
}
|
||||
v.minor = 10*v.minor + int(s[i]) - '0'
|
||||
}
|
||||
if i > 0 && i == len(s) {
|
||||
return
|
||||
}
|
||||
return version{}, errVersionSyntax
|
||||
// Accept any suffix after the minor number.
|
||||
// We are only looking for the language version (major.minor)
|
||||
// but want to accept any valid Go version, like go1.21.0
|
||||
// and go1.21rc2.
|
||||
return
|
||||
}
|
||||
|
||||
// langCompat reports an error if the representation of a numeric
|
||||
|
||||
24
src/cmd/compile/internal/types2/version_test.go
Normal file
24
src/cmd/compile/internal/types2/version_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2023 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 types2
|
||||
|
||||
import "testing"
|
||||
|
||||
var parseGoVersionTests = []struct {
|
||||
in string
|
||||
out version
|
||||
}{
|
||||
{"go1.21", version{1, 21}},
|
||||
{"go1.21.0", version{1, 21}},
|
||||
{"go1.21rc2", version{1, 21}},
|
||||
}
|
||||
|
||||
func TestParseGoVersion(t *testing.T) {
|
||||
for _, tt := range parseGoVersionTests {
|
||||
if out, err := parseGoVersion(tt.in); out != tt.out || err != nil {
|
||||
t.Errorf("parseGoVersion(%q) = %v, %v, want %v, nil", tt.in, out, err, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -755,7 +755,7 @@ func (o *orderState) stmt(n ir.Node) {
|
||||
o.out = append(o.out, n)
|
||||
o.popTemp(t)
|
||||
|
||||
case ir.OMAX, ir.OMIN, ir.OPRINT, ir.OPRINTN, ir.ORECOVERFP:
|
||||
case ir.OPRINT, ir.OPRINTN, ir.ORECOVERFP:
|
||||
n := n.(*ir.CallExpr)
|
||||
t := o.markTemp()
|
||||
o.call(n)
|
||||
@@ -1247,6 +1247,8 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
|
||||
ir.OMAKEMAP,
|
||||
ir.OMAKESLICE,
|
||||
ir.OMAKESLICECOPY,
|
||||
ir.OMAX,
|
||||
ir.OMIN,
|
||||
ir.ONEW,
|
||||
ir.OREAL,
|
||||
ir.ORECOVERFP,
|
||||
|
||||
@@ -337,10 +337,14 @@ func mayCall(n ir.Node) bool {
|
||||
n := n.(*ir.ConvExpr)
|
||||
return ssagen.Arch.SoftFloat && (isSoftFloat(n.Type()) || isSoftFloat(n.X.Type()))
|
||||
|
||||
case ir.OMIN, ir.OMAX:
|
||||
// string or float requires runtime call, see (*ssagen.state).minmax method.
|
||||
return n.Type().IsString() || n.Type().IsFloat()
|
||||
|
||||
case ir.OLITERAL, ir.ONIL, ir.ONAME, ir.OLINKSYMOFFSET, ir.OMETHEXPR,
|
||||
ir.OAND, ir.OANDNOT, ir.OLSH, ir.OOR, ir.ORSH, ir.OXOR, ir.OCOMPLEX, ir.OEFACE,
|
||||
ir.OADDR, ir.OBITNOT, ir.ONOT, ir.OPLUS,
|
||||
ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL, ir.OMIN, ir.OMAX,
|
||||
ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL,
|
||||
ir.OCONVNOP, ir.ODOT,
|
||||
ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.OSPTR,
|
||||
ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OSLICEHEADER, ir.OSTRINGHEADER:
|
||||
|
||||
@@ -95,7 +95,7 @@ const (
|
||||
func main() {
|
||||
objabi.AddVersionFlag()
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
objabi.Flagparse(usage)
|
||||
|
||||
// Usage information when no arguments.
|
||||
if flag.NFlag() == 0 && flag.NArg() == 0 {
|
||||
|
||||
9
src/cmd/dist/build.go
vendored
9
src/cmd/dist/build.go
vendored
@@ -631,7 +631,6 @@ var gentab = []struct {
|
||||
}{
|
||||
{"go/build", "zcgo.go", mkzcgo},
|
||||
{"cmd/go/internal/cfg", "zdefaultcc.go", mkzdefaultcc},
|
||||
{"internal/platform", "zosarch.go", mkzosarch},
|
||||
{"runtime/internal/sys", "zversion.go", mkzversion},
|
||||
{"time/tzdata", "zzipdata.go", mktzdata},
|
||||
}
|
||||
@@ -1899,11 +1898,12 @@ func cmdversion() {
|
||||
// cmdlist lists all supported platforms.
|
||||
func cmdlist() {
|
||||
jsonFlag := flag.Bool("json", false, "produce JSON output")
|
||||
brokenFlag := flag.Bool("broken", false, "include broken ports")
|
||||
xflagparse(0)
|
||||
|
||||
var plats []string
|
||||
for p := range cgoEnabled {
|
||||
if broken[p] {
|
||||
if broken[p] && !*brokenFlag {
|
||||
continue
|
||||
}
|
||||
plats = append(plats, p)
|
||||
@@ -1922,6 +1922,7 @@ func cmdlist() {
|
||||
GOARCH string
|
||||
CgoSupported bool
|
||||
FirstClass bool
|
||||
Broken bool `json:",omitempty"`
|
||||
}
|
||||
var results []jsonResult
|
||||
for _, p := range plats {
|
||||
@@ -1930,7 +1931,9 @@ func cmdlist() {
|
||||
GOOS: fields[0],
|
||||
GOARCH: fields[1],
|
||||
CgoSupported: cgoEnabled[p],
|
||||
FirstClass: firstClass[p]})
|
||||
FirstClass: firstClass[p],
|
||||
Broken: broken[p],
|
||||
})
|
||||
}
|
||||
out, err := json.MarshalIndent(results, "", "\t")
|
||||
if err != nil {
|
||||
|
||||
23
src/cmd/dist/buildruntime.go
vendored
23
src/cmd/dist/buildruntime.go
vendored
@@ -6,7 +6,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -80,25 +79,3 @@ func mkobjabi(file string) {
|
||||
|
||||
writefile(buf.String(), file, writeSkipSame)
|
||||
}
|
||||
|
||||
// mkzosarch writes zosarch.go for internal/platform.
|
||||
func mkzosarch(dir, file string) {
|
||||
// sort for deterministic file contents.
|
||||
var list []string
|
||||
for plat := range cgoEnabled {
|
||||
list = append(list, plat)
|
||||
}
|
||||
sort.Strings(list)
|
||||
|
||||
var buf strings.Builder
|
||||
writeHeader(&buf)
|
||||
fmt.Fprintf(&buf, "package platform\n")
|
||||
fmt.Fprintln(&buf)
|
||||
fmt.Fprintf(&buf, "var osArchSupportsCgo = map[string]bool{\n")
|
||||
for _, plat := range list {
|
||||
fmt.Fprintf(&buf, "\t\t%s: %v,\n", quote(plat), cgoEnabled[plat])
|
||||
}
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
|
||||
writefile(buf.String(), file, writeSkipSame)
|
||||
}
|
||||
|
||||
6
src/cmd/dist/buildtool.go
vendored
6
src/cmd/dist/buildtool.go
vendored
@@ -70,6 +70,11 @@ var bootstrapDirs = []string{
|
||||
"internal/goexperiment",
|
||||
"internal/goroot",
|
||||
"internal/goversion",
|
||||
// internal/lazyregexp is provided by Go 1.17, which permits it to
|
||||
// be imported by other packages in this list, but is not provided
|
||||
// by the Go 1.17 version of gccgo. It's on this list only to
|
||||
// support gccgo, and can be removed if we require gccgo 14 or later.
|
||||
"internal/lazyregexp",
|
||||
"internal/pkgbits",
|
||||
"internal/platform",
|
||||
"internal/profile",
|
||||
@@ -126,7 +131,6 @@ func bootstrapBuildTools() {
|
||||
|
||||
mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot))
|
||||
mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
|
||||
mkzosarch("", pathf("%s/src/internal/platform/zosarch.go", goroot))
|
||||
|
||||
// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
|
||||
// We use a subdirectory of $GOROOT/pkg because that's the
|
||||
|
||||
16
src/cmd/dist/main.go
vendored
16
src/cmd/dist/main.go
vendored
@@ -16,14 +16,14 @@ func usage() {
|
||||
xprintf(`usage: go tool dist [command]
|
||||
Commands are:
|
||||
|
||||
banner print installation banner
|
||||
bootstrap rebuild everything
|
||||
clean deletes all built files
|
||||
env [-p] print environment (-p: include $PATH)
|
||||
install [dir] install individual directory
|
||||
list [-json] list all supported platforms
|
||||
test [-h] run Go test(s)
|
||||
version print Go version
|
||||
banner print installation banner
|
||||
bootstrap rebuild everything
|
||||
clean deletes all built files
|
||||
env [-p] print environment (-p: include $PATH)
|
||||
install [dir] install individual directory
|
||||
list [-json] [-broken] list all supported platforms
|
||||
test [-h] run Go test(s)
|
||||
version print Go version
|
||||
|
||||
All commands take -v flags to emit extra information.
|
||||
`)
|
||||
|
||||
@@ -127,7 +127,6 @@ func main() {
|
||||
// Generated during cmd/dist. See ../dist/build.go:/gentab.
|
||||
"src/cmd/go/internal/cfg/zdefaultcc.go",
|
||||
"src/go/build/zcgo.go",
|
||||
"src/internal/platform/zosarch.go",
|
||||
"src/runtime/internal/sys/zversion.go",
|
||||
"src/time/tzdata/zzipdata.go",
|
||||
|
||||
|
||||
@@ -11,20 +11,31 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/par"
|
||||
)
|
||||
|
||||
// Tool returns the path to the named tool (for example, "vet").
|
||||
// If the tool cannot be found, Tool exits the process.
|
||||
func Tool(toolName string) string {
|
||||
toolPath := filepath.Join(build.ToolDir, toolName) + cfg.ToolExeSuffix()
|
||||
if len(cfg.BuildToolexec) > 0 {
|
||||
return toolPath
|
||||
}
|
||||
// Give a nice message if there is no tool with that name.
|
||||
if _, err := os.Stat(toolPath); err != nil {
|
||||
toolPath, err := ToolPath(toolName)
|
||||
if err != nil && len(cfg.BuildToolexec) == 0 {
|
||||
// Give a nice message if there is no tool with that name.
|
||||
fmt.Fprintf(os.Stderr, "go: no such tool %q\n", toolName)
|
||||
SetExitStatus(2)
|
||||
Exit()
|
||||
}
|
||||
return toolPath
|
||||
}
|
||||
|
||||
// Tool returns the path at which we expect to find the named tool
|
||||
// (for example, "vet"), and the error (if any) from statting that path.
|
||||
func ToolPath(toolName string) (string, error) {
|
||||
toolPath := filepath.Join(build.ToolDir, toolName) + cfg.ToolExeSuffix()
|
||||
err := toolStatCache.Do(toolPath, func() error {
|
||||
_, err := os.Stat(toolPath)
|
||||
return err
|
||||
})
|
||||
return toolPath, err
|
||||
}
|
||||
|
||||
var toolStatCache par.Cache[string, error]
|
||||
|
||||
@@ -111,7 +111,6 @@ func IsPrerelease(x string) bool {
|
||||
//
|
||||
// Prev("1.2") = "1.1"
|
||||
// Prev("1.3rc4") = "1.2"
|
||||
//
|
||||
func Prev(x string) string {
|
||||
v := parse(x)
|
||||
if cmpInt(v.minor, "1") <= 0 {
|
||||
|
||||
@@ -660,6 +660,7 @@ var defaultVetFlags = []string{
|
||||
"-printf",
|
||||
// "-rangeloops",
|
||||
// "-shift",
|
||||
"-slog",
|
||||
"-stringintconv",
|
||||
// "-structtags",
|
||||
// "-tests",
|
||||
|
||||
@@ -7,8 +7,11 @@ package tool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"internal/platform"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
@@ -68,10 +71,25 @@ func runTool(ctx context.Context, cmd *base.Command, args []string) {
|
||||
return
|
||||
}
|
||||
}
|
||||
toolPath := base.Tool(toolName)
|
||||
if toolPath == "" {
|
||||
return
|
||||
|
||||
toolPath, err := base.ToolPath(toolName)
|
||||
if err != nil {
|
||||
if toolName == "dist" && len(args) > 1 && args[1] == "list" {
|
||||
// cmd/distpack removes the 'dist' tool from the toolchain to save space,
|
||||
// since it is normally only used for building the toolchain in the first
|
||||
// place. However, 'go tool dist list' is useful for listing all supported
|
||||
// platforms.
|
||||
//
|
||||
// If the dist tool does not exist, impersonate this command.
|
||||
if impersonateDistList(args[2:]) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the usual error for the missing tool.
|
||||
_ = base.Tool(toolName)
|
||||
}
|
||||
|
||||
if toolN {
|
||||
cmd := toolPath
|
||||
if len(args) > 1 {
|
||||
@@ -88,7 +106,7 @@ func runTool(ctx context.Context, cmd *base.Command, args []string) {
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
}
|
||||
err := toolCmd.Start()
|
||||
err = toolCmd.Start()
|
||||
if err == nil {
|
||||
c := make(chan os.Signal, 100)
|
||||
signal.Notify(c)
|
||||
@@ -145,3 +163,62 @@ func listTools() {
|
||||
fmt.Println(name)
|
||||
}
|
||||
}
|
||||
|
||||
func impersonateDistList(args []string) (handled bool) {
|
||||
fs := flag.NewFlagSet("go tool dist list", flag.ContinueOnError)
|
||||
jsonFlag := fs.Bool("json", false, "produce JSON output")
|
||||
brokenFlag := fs.Bool("broken", false, "include broken ports")
|
||||
|
||||
// The usage for 'go tool dist' claims that
|
||||
// “All commands take -v flags to emit extra information”,
|
||||
// but list -v appears not to have any effect.
|
||||
_ = fs.Bool("v", false, "emit extra information")
|
||||
|
||||
if err := fs.Parse(args); err != nil || len(fs.Args()) > 0 {
|
||||
// Unrecognized flag or argument.
|
||||
// Force fallback to the real 'go tool dist'.
|
||||
return false
|
||||
}
|
||||
|
||||
if !*jsonFlag {
|
||||
for _, p := range platform.List {
|
||||
if !*brokenFlag && platform.Broken(p.GOOS, p.GOARCH) {
|
||||
continue
|
||||
}
|
||||
fmt.Println(p)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type jsonResult struct {
|
||||
GOOS string
|
||||
GOARCH string
|
||||
CgoSupported bool
|
||||
FirstClass bool
|
||||
Broken bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
var results []jsonResult
|
||||
for _, p := range platform.List {
|
||||
broken := platform.Broken(p.GOOS, p.GOARCH)
|
||||
if broken && !*brokenFlag {
|
||||
continue
|
||||
}
|
||||
if *jsonFlag {
|
||||
results = append(results, jsonResult{
|
||||
GOOS: p.GOOS,
|
||||
GOARCH: p.GOARCH,
|
||||
CgoSupported: platform.CgoSupported(p.GOOS, p.GOARCH),
|
||||
FirstClass: platform.FirstClass(p.GOOS, p.GOARCH),
|
||||
Broken: broken,
|
||||
})
|
||||
}
|
||||
}
|
||||
out, err := json.MarshalIndent(results, "", "\t")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
os.Stdout.Write(out)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1115,6 +1115,7 @@ type vetConfig struct {
|
||||
PackageVetx map[string]string // map package path to vetx data from earlier vet run
|
||||
VetxOnly bool // only compute vetx data; don't report detected problems
|
||||
VetxOutput string // write vetx data to this output file
|
||||
GoVersion string // Go version for package
|
||||
|
||||
SucceedOnTypecheckFailure bool // awful hack; see #18395 and below
|
||||
}
|
||||
@@ -1149,6 +1150,13 @@ func buildVetConfig(a *Action, srcfiles []string) {
|
||||
PackageFile: make(map[string]string),
|
||||
Standard: make(map[string]bool),
|
||||
}
|
||||
if a.Package.Module != nil {
|
||||
v := a.Package.Module.GoVersion
|
||||
if v == "" {
|
||||
v = gover.DefaultGoModVersion
|
||||
}
|
||||
vcfg.GoVersion = "go" + v
|
||||
}
|
||||
a.vetCfg = vcfg
|
||||
for i, raw := range a.Package.Internal.RawImports {
|
||||
final := a.Package.Imports[i]
|
||||
@@ -3886,7 +3894,7 @@ func useResponseFile(path string, argLen int) bool {
|
||||
// TODO: Note that other toolchains like CC are missing here for now.
|
||||
prog := strings.TrimSuffix(filepath.Base(path), ".exe")
|
||||
switch prog {
|
||||
case "compile", "link", "cgo", "asm":
|
||||
case "compile", "link", "cgo", "asm", "cover":
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -85,19 +85,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
|
||||
if p.Module != nil {
|
||||
v := p.Module.GoVersion
|
||||
if v == "" {
|
||||
// We started adding a 'go' directive to the go.mod file unconditionally
|
||||
// as of Go 1.12, so any module that still lacks such a directive must
|
||||
// either have been authored before then, or have a hand-edited go.mod
|
||||
// file that hasn't been updated by cmd/go since that edit.
|
||||
//
|
||||
// Unfortunately, through at least Go 1.16 we didn't add versions to
|
||||
// vendor/modules.txt. So this could also be a vendored 1.16 dependency.
|
||||
//
|
||||
// Fortunately, there were no breaking changes to the language between Go
|
||||
// 1.11 and 1.16, so if we assume Go 1.16 semantics we will not introduce
|
||||
// any spurious errors — we will only mask errors, and not particularly
|
||||
// important ones at that.
|
||||
v = "1.16"
|
||||
v = gover.DefaultGoModVersion
|
||||
}
|
||||
if allowedVersion(v) {
|
||||
defaultGcFlags = append(defaultGcFlags, "-lang=go"+gover.Lang(v))
|
||||
|
||||
@@ -300,10 +300,10 @@ func maybeStartTrace(pctx context.Context) context.Context {
|
||||
//
|
||||
// We have to handle the -C flag this way for two reasons:
|
||||
//
|
||||
// 1. Toolchain selection needs to be in the right directory to look for go.mod and go.work.
|
||||
// 1. Toolchain selection needs to be in the right directory to look for go.mod and go.work.
|
||||
//
|
||||
// 2. A toolchain switch later on reinvokes the new go command with the same arguments.
|
||||
// The parent toolchain has already done the chdir; the child must not try to do it again.
|
||||
// 2. A toolchain switch later on reinvokes the new go command with the same arguments.
|
||||
// The parent toolchain has already done the chdir; the child must not try to do it again.
|
||||
func handleChdirFlag() {
|
||||
_, used := lookupCmd(os.Args[1:])
|
||||
used++ // because of [1:]
|
||||
|
||||
30
src/cmd/go/testdata/script/build_pgo_auto.txt
vendored
30
src/cmd/go/testdata/script/build_pgo_auto.txt
vendored
@@ -3,7 +3,7 @@
|
||||
[short] skip 'compiles and links executables'
|
||||
|
||||
# use default.pgo for a single main package
|
||||
go build -a -x -pgo=auto -o a1.exe ./a/a1
|
||||
go build -n -pgo=auto -o a1.exe ./a/a1
|
||||
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
|
||||
|
||||
# check that pgo applied to dependencies
|
||||
@@ -12,25 +12,22 @@ stderr 'compile.*-p test/dep.*-pgoprofile=.*default\.pgo'
|
||||
# check that pgo appears in build info
|
||||
# N.B. we can't start the stdout check with -pgo because the script assumes that
|
||||
# if the first arg starts with - it is a grep flag.
|
||||
go version -m a1.exe
|
||||
stdout 'build\s+-pgo=.*default\.pgo'
|
||||
stderr 'build\\t-pgo=.*default\.pgo'
|
||||
|
||||
# use default.pgo for ... with a single main package
|
||||
go build -a -x -pgo=auto ./a/...
|
||||
go build -n -pgo=auto ./a/...
|
||||
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
|
||||
|
||||
# check that pgo appears in build info
|
||||
go version -m a1$GOEXE
|
||||
stdout 'build\s+-pgo=.*default\.pgo'
|
||||
stderr 'build\\t-pgo=.*default\.pgo'
|
||||
|
||||
# build succeeds without PGO when default.pgo file is absent
|
||||
go build -a -x -pgo=auto -o nopgo.exe ./nopgo
|
||||
go build -n -pgo=auto -o nopgo.exe ./nopgo
|
||||
stderr 'compile.*nopgo.go'
|
||||
! stderr 'compile.*-pgoprofile'
|
||||
|
||||
# check that pgo doesn't appear in build info
|
||||
go version -m nopgo.exe
|
||||
! stdout 'build\s+-pgo='
|
||||
! stderr 'build\\t-pgo='
|
||||
|
||||
# other build-related commands
|
||||
go install -a -n -pgo=auto ./a/a1
|
||||
@@ -52,30 +49,27 @@ go list -deps -pgo=auto ./a/a1
|
||||
|
||||
# -pgo=auto is the default. Commands without explicit -pgo=auto
|
||||
# should work as -pgo=auto.
|
||||
go build -a -x -o a1.exe ./a/a1
|
||||
go build -a -n -o a1.exe ./a/a1
|
||||
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
|
||||
stderr 'compile.*-p test/dep.*-pgoprofile=.*default\.pgo'
|
||||
|
||||
# check that pgo appears in build info
|
||||
go version -m a1.exe
|
||||
stdout 'build\s+-pgo=.*default\.pgo'
|
||||
stderr 'build\\t-pgo=.*default\.pgo'
|
||||
|
||||
go build -a -x -o nopgo.exe ./nopgo
|
||||
go build -a -n -o nopgo.exe ./nopgo
|
||||
stderr 'compile.*nopgo.go'
|
||||
! stderr 'compile.*-pgoprofile'
|
||||
|
||||
# check that pgo doesn't appear in build info
|
||||
go version -m nopgo.exe
|
||||
! stdout 'build\s+-pgo='
|
||||
! stderr 'build\\t-pgo='
|
||||
|
||||
# -pgo=off should turn off PGO.
|
||||
go build -a -x -pgo=off -o a1.exe ./a/a1
|
||||
go build -a -n -pgo=off -o a1.exe ./a/a1
|
||||
stderr 'compile.*a1.go'
|
||||
! stderr 'compile.*-pgoprofile'
|
||||
|
||||
# check that pgo doesn't appear in build info
|
||||
go version -m a1.exe
|
||||
! stdout 'build\s+-pgo='
|
||||
! stderr 'build\\t-pgo='
|
||||
|
||||
-- go.mod --
|
||||
module test
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
# Test go build -pgo=auto flag with multiple main packages.
|
||||
|
||||
[short] skip 'compiles and links executables'
|
||||
|
||||
env GOBIN=$WORK/bin
|
||||
go install -a -x -pgo=auto ./a ./b ./nopgo
|
||||
go install -a -n -pgo=auto ./a ./b ./nopgo
|
||||
|
||||
# a/default.pgo applies to package a and (transitive)
|
||||
# dependencies.
|
||||
@@ -36,16 +33,9 @@ stderr -count=3 'compile.*dep3(/|\\\\)dep3.go'
|
||||
stderr -count=2 'compile.*-pgoprofile=.*dep3(/|\\\\)dep3\.go'
|
||||
|
||||
# check that pgo appears or not in build info as expected
|
||||
# N.B. we can't start the stdout check with -pgo because the script assumes that
|
||||
# if the first arg starts with - it is a grep flag.
|
||||
go version -m $GOBIN/a$GOEXE
|
||||
stdout 'build\s+-pgo=.*a'${/}'default\.pgo'
|
||||
|
||||
go version -m $GOBIN/b$GOEXE
|
||||
stdout 'build\s+-pgo=.*b'${/}'default\.pgo'
|
||||
|
||||
go version -m $GOBIN/nopgo$GOEXE
|
||||
! stdout 'build\s+-pgo='
|
||||
stderr 'path\\ttest/a\\n.*build\\t-pgo=.*a(/|\\\\)default\.pgo'
|
||||
stderr 'path\\ttest/b\\n.*build\\t-pgo=.*b(/|\\\\)default\.pgo'
|
||||
! stderr 'path\\ttest/nopgo\\n.*build\\t-pgo='
|
||||
|
||||
# go test works the same way
|
||||
go test -a -n -pgo=auto ./a ./b ./nopgo
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[compiler:gccgo] skip # gccgo assumes cross-compilation is always possible
|
||||
|
||||
env GOOS=windwos
|
||||
env GOOS=windwos # intentional misspelling of windows
|
||||
|
||||
! go build -n exclude
|
||||
stderr 'unsupported GOOS/GOARCH pair'
|
||||
stderr 'unsupported GOOS/GOARCH pair'
|
||||
|
||||
57
src/cmd/go/testdata/script/dist_list_missing.txt
vendored
Normal file
57
src/cmd/go/testdata/script/dist_list_missing.txt
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
# Regression test for #60939: when 'go tool dist' is missing,
|
||||
# 'go tool dist list' should inject its output.
|
||||
|
||||
|
||||
# Set GOROOT to a directory that definitely does not include
|
||||
# a compiled 'dist' tool. 'go tool dist list' should still
|
||||
# work, because 'cmd/go' itself can impersonate this command.
|
||||
|
||||
mkdir $WORK/goroot/bin
|
||||
mkdir $WORK/goroot/pkg/tool/${GOOS}_${GOARCH}
|
||||
env GOROOT=$WORK/goroot
|
||||
|
||||
! go tool -n dist
|
||||
stderr 'go: no such tool "dist"'
|
||||
|
||||
go tool dist list
|
||||
stdout linux/amd64
|
||||
cp stdout tool.txt
|
||||
|
||||
go tool dist list -v
|
||||
stdout linux/amd64
|
||||
cp stdout tool-v.txt
|
||||
|
||||
go tool dist list -broken
|
||||
stdout $GOOS/$GOARCH
|
||||
cp stdout tool-broken.txt
|
||||
|
||||
go tool dist list -json
|
||||
stdout '"GOOS": "linux",\n\s*"GOARCH": "amd64",\n'
|
||||
cp stdout tool-json.txt
|
||||
|
||||
go tool dist list -json -broken
|
||||
stdout '"GOOS": "'$GOOS'",\n\s*"GOARCH": "'$GOARCH'",\n'
|
||||
cp stdout tool-json-broken.txt
|
||||
|
||||
[short] stop
|
||||
|
||||
|
||||
# Check against the real cmd/dist as the source of truth.
|
||||
|
||||
env GOROOT=$TESTGO_GOROOT
|
||||
go build -o dist.exe cmd/dist
|
||||
|
||||
exec ./dist.exe list
|
||||
cmp stdout tool.txt
|
||||
|
||||
exec ./dist.exe list -v
|
||||
cmp stdout tool-v.txt
|
||||
|
||||
exec ./dist.exe list -broken
|
||||
cmp stdout tool-broken.txt
|
||||
|
||||
exec ./dist.exe list -json
|
||||
cmp stdout tool-json.txt
|
||||
|
||||
exec ./dist.exe list -json -broken
|
||||
cmp stdout tool-json-broken.txt
|
||||
22
src/cmd/go/testdata/script/gcflags_patterns.txt
vendored
22
src/cmd/go/testdata/script/gcflags_patterns.txt
vendored
@@ -3,17 +3,15 @@ env GO111MODULE=off
|
||||
[!compiler:gc] skip 'using -gcflags and -ldflags'
|
||||
[short] skip
|
||||
|
||||
env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache.
|
||||
|
||||
# -gcflags=-e applies to named packages, not dependencies
|
||||
go build -n -v -gcflags=-e z1 z2
|
||||
go build -a -n -v -gcflags=-e z1 z2
|
||||
stderr 'compile.* -p z1.* -e '
|
||||
stderr 'compile.* -p z2.* -e '
|
||||
stderr 'compile.* -p y'
|
||||
! stderr 'compile.* -p [^z].* -e '
|
||||
|
||||
# -gcflags can specify package=flags, and can be repeated; last match wins
|
||||
go build -n -v -gcflags=-e -gcflags=z1=-N z1 z2
|
||||
go build -a -n -v -gcflags=-e -gcflags=z1=-N z1 z2
|
||||
stderr 'compile.* -p z1.* -N '
|
||||
! stderr 'compile.* -p z1.* -e '
|
||||
! stderr 'compile.* -p z2.* -N '
|
||||
@@ -23,11 +21,11 @@ stderr 'compile.* -p y'
|
||||
! stderr 'compile.* -p [^z].* -N '
|
||||
|
||||
# -gcflags can have arbitrary spaces around the flags
|
||||
go build -n -v -gcflags=' z1 = -e ' z1
|
||||
go build -a -n -v -gcflags=' z1 = -e ' z1
|
||||
stderr 'compile.* -p z1.* -e '
|
||||
|
||||
# -gcflags='all=-e' should apply to all packages, even with go test
|
||||
go test -c -n -gcflags='all=-e' z1
|
||||
go test -a -c -n -gcflags='all=-e' z1
|
||||
stderr 'compile.* -p z3.* -e '
|
||||
|
||||
# this particular -gcflags argument made the compiler crash
|
||||
@@ -39,31 +37,31 @@ stderr 'PhaseOptions usage'
|
||||
stderr 'invalid value'
|
||||
|
||||
# -ldflags for implicit test package applies to test binary
|
||||
go test -c -n -gcflags=-N -ldflags=-X=x.y=z z1
|
||||
go test -a -c -n -gcflags=-N -ldflags=-X=x.y=z z1
|
||||
stderr 'compile.* -N .*z_test.go'
|
||||
stderr 'link.* -X=x.y=z'
|
||||
|
||||
# -ldflags for explicit test package applies to test binary
|
||||
go test -c -n -gcflags=z1=-N -ldflags=z1=-X=x.y=z z1
|
||||
go test -a -c -n -gcflags=z1=-N -ldflags=z1=-X=x.y=z z1
|
||||
stderr 'compile.* -N .*z_test.go'
|
||||
stderr 'link.* -X=x.y=z'
|
||||
|
||||
# -ldflags applies to link of command
|
||||
go build -n -ldflags=-X=math.pi=3 my/cmd/prog
|
||||
go build -a -n -ldflags=-X=math.pi=3 my/cmd/prog
|
||||
stderr 'link.* -X=math.pi=3'
|
||||
|
||||
# -ldflags applies to link of command even with strange directory name
|
||||
go build -n -ldflags=-X=math.pi=3 my/cmd/prog/
|
||||
go build -a -n -ldflags=-X=math.pi=3 my/cmd/prog/
|
||||
stderr 'link.* -X=math.pi=3'
|
||||
|
||||
# -ldflags applies to current directory
|
||||
cd my/cmd/prog
|
||||
go build -n -ldflags=-X=math.pi=3
|
||||
go build -a -n -ldflags=-X=math.pi=3
|
||||
stderr 'link.* -X=math.pi=3'
|
||||
|
||||
# -ldflags applies to current directory even if GOPATH is funny
|
||||
[!case-sensitive] cd $WORK/GoPath/src/my/cmd/prog
|
||||
go build -n -ldflags=-X=math.pi=3
|
||||
go build -a -n -ldflags=-X=math.pi=3
|
||||
stderr 'link.* -X=math.pi=3'
|
||||
|
||||
# cgo.a should not be a dependency of internally-linked go package
|
||||
|
||||
@@ -5,33 +5,12 @@ env GO111MODULE=on
|
||||
|
||||
# Regression test for golang.org/issue/29667:
|
||||
# spurious 'failed to cache compiled Go files' errors.
|
||||
# This test failed reliably when run with -count=10
|
||||
# on a Linux workstation.
|
||||
|
||||
env GOCACHE=$WORK/gocache
|
||||
mkdir $GOCACHE
|
||||
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
go list -json -compiled -test=false -export=false -deps=true -- . &
|
||||
|
||||
wait
|
||||
|
||||
-- go.mod --
|
||||
|
||||
14
src/cmd/go/testdata/script/vet_flags.txt
vendored
14
src/cmd/go/testdata/script/vet_flags.txt
vendored
@@ -52,27 +52,25 @@ env GOFLAGS='-unsafeptr'
|
||||
stderr 'go: parsing \$GOFLAGS: unknown flag -unsafeptr'
|
||||
env GOFLAGS=
|
||||
|
||||
env GOCACHE=$WORK/gocache
|
||||
|
||||
# "go test" on a user package should by default enable an explicit list of analyzers.
|
||||
go test -x -run=none .
|
||||
go test -n -run=none .
|
||||
stderr '[/\\]vet'$GOEXE'["]? .* -errorsas .* ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
|
||||
|
||||
# An explicitly-empty -vet argument should imply the default analyzers.
|
||||
go test -x -vet= -run=none .
|
||||
go test -n -vet= -run=none .
|
||||
stderr '[/\\]vet'$GOEXE'["]? .* -errorsas .* ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
|
||||
|
||||
# "go test" on a standard package should by default disable an explicit list.
|
||||
go test -x -run=none encoding/binary
|
||||
go test -n -run=none encoding/binary
|
||||
stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
|
||||
|
||||
go test -x -vet= -run=none encoding/binary
|
||||
go test -n -vet= -run=none encoding/binary
|
||||
stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
|
||||
|
||||
# Both should allow users to override via the -vet flag.
|
||||
go test -x -vet=unreachable -run=none .
|
||||
go test -n -vet=unreachable -run=none .
|
||||
stderr '[/\\]vet'$GOEXE'["]? -unreachable ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
|
||||
go test -x -vet=unreachable -run=none encoding/binary
|
||||
go test -n -vet=unreachable -run=none encoding/binary
|
||||
stderr '[/\\]vet'$GOEXE'["]? -unreachable ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
|
||||
|
||||
-- go.mod --
|
||||
|
||||
@@ -16,7 +16,11 @@ import (
|
||||
)
|
||||
|
||||
type Curve interface {
|
||||
// GenerateKey generates a new PrivateKey from rand.
|
||||
// GenerateKey generates a random PrivateKey.
|
||||
//
|
||||
// Most applications should use [crypto/rand.Reader] as rand. Note that the
|
||||
// returned key does not depend deterministically on the bytes read from rand,
|
||||
// and may change between calls and/or between versions.
|
||||
GenerateKey(rand io.Reader) (*PrivateKey, error)
|
||||
|
||||
// NewPrivateKey checks that key is valid and returns a PrivateKey.
|
||||
|
||||
@@ -150,7 +150,11 @@ func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOp
|
||||
return SignASN1(rand, priv, digest)
|
||||
}
|
||||
|
||||
// GenerateKey generates a public and private key pair.
|
||||
// GenerateKey generates a new ECDSA private key for the specified curve.
|
||||
//
|
||||
// Most applications should use [crypto/rand.Reader] as rand. Note that the
|
||||
// returned key does not depend deterministically on the bytes read from rand,
|
||||
// and may change between calls and/or between versions.
|
||||
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
|
||||
randutil.MaybeReadByte(rand)
|
||||
|
||||
@@ -245,6 +249,10 @@ var errNoAsm = errors.New("no assembly implementation available")
|
||||
// using the private key, priv. If the hash is longer than the bit-length of the
|
||||
// private key's curve order, the hash will be truncated to that length. It
|
||||
// returns the ASN.1 encoded signature.
|
||||
//
|
||||
// The signature is randomized. Most applications should use [crypto/rand.Reader]
|
||||
// as rand. Note that the returned signature does not depend deterministically on
|
||||
// the bytes read from rand, and may change between calls and/or between versions.
|
||||
func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
|
||||
randutil.MaybeReadByte(rand)
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ func (priv PrivateKey) Seed() []byte {
|
||||
return bytes.Clone(priv[:SeedSize])
|
||||
}
|
||||
|
||||
// Sign signs the given message with priv. rand is ignored.
|
||||
// Sign signs the given message with priv. rand is ignored and can be nil.
|
||||
//
|
||||
// If opts.HashFunc() is [crypto.SHA512], the pre-hashed variant Ed25519ph is used
|
||||
// and message is expected to be a SHA-512 hash, otherwise opts.HashFunc() must
|
||||
@@ -132,6 +132,9 @@ func (o *Options) HashFunc() crypto.Hash { return o.Hash }
|
||||
|
||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
||||
// If rand is nil, [crypto/rand.Reader] will be used.
|
||||
//
|
||||
// The output of this function is deterministic, and equivalent to reading
|
||||
// [SeedSize] bytes from rand, and passing them to [NewKeyFromSeed].
|
||||
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
|
||||
if rand == nil {
|
||||
rand = cryptorand.Reader
|
||||
|
||||
@@ -31,7 +31,10 @@ type PKCS1v15DecryptOptions struct {
|
||||
//
|
||||
// The random parameter is used as a source of entropy to ensure that
|
||||
// encrypting the same message twice doesn't result in the same
|
||||
// ciphertext.
|
||||
// ciphertext. Most applications should use [crypto/rand.Reader]
|
||||
// as random. Note that the returned ciphertext does not depend
|
||||
// deterministically on the bytes read from random, and may change
|
||||
// between calls and/or between versions.
|
||||
//
|
||||
// WARNING: use of this function to encrypt plaintexts other than
|
||||
// session keys is dangerous. Use RSA OAEP in new protocols.
|
||||
@@ -79,7 +82,7 @@ func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, erro
|
||||
}
|
||||
|
||||
// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS #1 v1.5.
|
||||
// The random parameter is legacy and ignored, and it can be as nil.
|
||||
// The random parameter is legacy and ignored, and it can be nil.
|
||||
//
|
||||
// Note that whether this function returns an error or not discloses secret
|
||||
// information. If an attacker can cause this function to run repeatedly and
|
||||
@@ -275,7 +278,7 @@ var hashPrefixes = map[crypto.Hash][]byte{
|
||||
// function. If hash is zero, hashed is signed directly. This isn't
|
||||
// advisable except for interoperability.
|
||||
//
|
||||
// The random parameter is legacy and ignored, and it can be as nil.
|
||||
// The random parameter is legacy and ignored, and it can be nil.
|
||||
//
|
||||
// This function is deterministic. Thus, if the set of possible
|
||||
// messages is small, an attacker may be able to build a map from
|
||||
|
||||
@@ -285,7 +285,17 @@ var invalidSaltLenErr = errors.New("crypto/rsa: PSSOptions.SaltLength cannot be
|
||||
// digest must be the result of hashing the input message using the given hash
|
||||
// function. The opts argument may be nil, in which case sensible defaults are
|
||||
// used. If opts.Hash is set, it overrides hash.
|
||||
//
|
||||
// The signature is randomized depending on the message, key, and salt size,
|
||||
// using bytes from rand. Most applications should use [crypto/rand.Reader] as
|
||||
// rand.
|
||||
func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, opts *PSSOptions) ([]byte, error) {
|
||||
// Note that while we don't commit to deterministic execution with respect
|
||||
// to the rand stream, we also don't apply MaybeReadByte, so per Hyrum's Law
|
||||
// it's probably relied upon by some. It's a tolerable promise because a
|
||||
// well-specified number of random bytes is included in the signature, in a
|
||||
// well-specified way.
|
||||
|
||||
if boring.Enabled && rand == boring.RandReader {
|
||||
bkey, err := boringPrivateKey(priv)
|
||||
if err != nil {
|
||||
|
||||
@@ -263,8 +263,11 @@ func (priv *PrivateKey) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateKey generates an RSA keypair of the given bit size using the
|
||||
// random source random (for example, crypto/rand.Reader).
|
||||
// GenerateKey generates a random RSA private key of the given bit size.
|
||||
//
|
||||
// Most applications should use [crypto/rand.Reader] as rand. Note that the
|
||||
// returned key does not depend deterministically on the bytes read from rand,
|
||||
// and may change between calls and/or between versions.
|
||||
func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
|
||||
return GenerateMultiPrimeKey(random, 2, bits)
|
||||
}
|
||||
@@ -500,6 +503,7 @@ func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) {
|
||||
//
|
||||
// The random parameter is used as a source of entropy to ensure that
|
||||
// encrypting the same message twice doesn't result in the same ciphertext.
|
||||
// Most applications should use [crypto/rand.Reader] as random.
|
||||
//
|
||||
// The label parameter may contain arbitrary data that will not be encrypted,
|
||||
// but which gives important context to the message. For example, if a given
|
||||
@@ -510,6 +514,12 @@ func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) {
|
||||
// The message must be no longer than the length of the public modulus minus
|
||||
// twice the hash length, minus a further 2.
|
||||
func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
|
||||
// Note that while we don't commit to deterministic execution with respect
|
||||
// to the random stream, we also don't apply MaybeReadByte, so per Hyrum's
|
||||
// Law it's probably relied upon by some. It's a tolerable promise because a
|
||||
// well-specified number of random bytes is included in the ciphertext, in a
|
||||
// well-specified way.
|
||||
|
||||
if err := checkPub(pub); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -691,7 +701,7 @@ func decrypt(priv *PrivateKey, ciphertext []byte, check bool) ([]byte, error) {
|
||||
// Encryption and decryption of a given message must use the same hash function
|
||||
// and sha256.New() is a reasonable choice.
|
||||
//
|
||||
// The random parameter is legacy and ignored, and it can be as nil.
|
||||
// The random parameter is legacy and ignored, and it can be nil.
|
||||
//
|
||||
// The label parameter must match the value given when encrypting. See
|
||||
// EncryptOAEP for details.
|
||||
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPlatformVerifier(t *testing.T) {
|
||||
func TestPlatformVerifierLegacy(t *testing.T) {
|
||||
// TODO(#52108): This can be removed once the synthetic test root is deployed on
|
||||
// builders.
|
||||
if !testenv.HasExternalNetwork() {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPlatformVerifier(t *testing.T) {
|
||||
func TestPlatformVerifierLegacy(t *testing.T) {
|
||||
// TODO(#52108): This can be removed once the synthetic test root is deployed on
|
||||
// builders.
|
||||
if !testenv.HasExternalNetwork() {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
@@ -512,22 +512,21 @@ func testVerify(t *testing.T, test verifyTest, useSystemRoots bool) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Every expected chain should match 1 returned chain
|
||||
// Every expected chain should match one (or more) returned chain. We tolerate multiple
|
||||
// matches, as due to root store semantics it is plausible that (at least on the system
|
||||
// verifiers) multiple identical (looking) chains may be returned when two roots with the
|
||||
// same subject are present.
|
||||
for _, expectedChain := range test.expectedChains {
|
||||
nChainMatched := 0
|
||||
var match bool
|
||||
for _, chain := range chains {
|
||||
if doesMatch(expectedChain, chain) {
|
||||
nChainMatched++
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if nChainMatched != 1 {
|
||||
t.Errorf("Got %v matches instead of %v for expected chain %v", nChainMatched, 1, expectedChain)
|
||||
for _, chain := range chains {
|
||||
if doesMatch(expectedChain, chain) {
|
||||
t.Errorf("\t matched %v", chainToDebugString(chain))
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
t.Errorf("No match found for %v", expectedChain)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2944,15 +2944,17 @@ func (rs *Rows) initContextClose(ctx, txctx context.Context) {
|
||||
if bypassRowsAwaitDone {
|
||||
return
|
||||
}
|
||||
ctx, rs.cancel = context.WithCancel(ctx)
|
||||
go rs.awaitDone(ctx, txctx)
|
||||
closectx, cancel := context.WithCancel(ctx)
|
||||
rs.cancel = cancel
|
||||
go rs.awaitDone(ctx, txctx, closectx)
|
||||
}
|
||||
|
||||
// awaitDone blocks until either ctx or txctx is canceled. The ctx is provided
|
||||
// from the query context and is canceled when the query Rows is closed.
|
||||
// awaitDone blocks until ctx, txctx, or closectx is canceled.
|
||||
// The ctx is provided from the query context.
|
||||
// If the query was issued in a transaction, the transaction's context
|
||||
// is also provided in txctx to ensure Rows is closed if the Tx is closed.
|
||||
func (rs *Rows) awaitDone(ctx, txctx context.Context) {
|
||||
// is also provided in txctx, to ensure Rows is closed if the Tx is closed.
|
||||
// The closectx is closed by an explicit call to rs.Close.
|
||||
func (rs *Rows) awaitDone(ctx, txctx, closectx context.Context) {
|
||||
var txctxDone <-chan struct{}
|
||||
if txctx != nil {
|
||||
txctxDone = txctx.Done()
|
||||
@@ -2964,6 +2966,9 @@ func (rs *Rows) awaitDone(ctx, txctx context.Context) {
|
||||
case <-txctxDone:
|
||||
err := txctx.Err()
|
||||
rs.contextDone.Store(&err)
|
||||
case <-closectx.Done():
|
||||
// rs.cancel was called via Close(); don't store this into contextDone
|
||||
// to ensure Err() is unaffected.
|
||||
}
|
||||
rs.close(ctx.Err())
|
||||
}
|
||||
|
||||
@@ -4493,6 +4493,31 @@ func TestContextCancelBetweenNextAndErr(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilErrorAfterClose(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
// This WithCancel is important; Rows contains an optimization to avoid
|
||||
// spawning a goroutine when the query/transaction context cannot be
|
||||
// canceled, but this test tests a bug which is caused by said goroutine.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
r, err := db.QueryContext(ctx, "SELECT|people|name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := r.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Millisecond) // increase odds of seeing failure
|
||||
if err := r.Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// badConn implements a bad driver.Conn, for TestBadDriver.
|
||||
// The Exec method panics.
|
||||
type badConn struct{}
|
||||
|
||||
@@ -50,7 +50,8 @@ const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
|
||||
const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
|
||||
|
||||
// NewEncoding returns a new Encoding defined by the given alphabet,
|
||||
// which must be a 32-byte string.
|
||||
// which must be a 32-byte string. The alphabet is treated as sequence
|
||||
// of byte values without any special treatment for multi-byte UTF-8.
|
||||
func NewEncoding(encoder string) *Encoding {
|
||||
if len(encoder) != 32 {
|
||||
panic("encoding alphabet is not 32-bytes long")
|
||||
@@ -80,6 +81,8 @@ var HexEncoding = NewEncoding(encodeHex)
|
||||
// The padding character must not be '\r' or '\n', must not
|
||||
// be contained in the encoding's alphabet and must be a rune equal or
|
||||
// below '\xff'.
|
||||
// Padding characters above '\x7f' are encoded as their exact byte value
|
||||
// rather than using the UTF-8 representation of the codepoint.
|
||||
func (enc Encoding) WithPadding(padding rune) *Encoding {
|
||||
if padding == '\r' || padding == '\n' || padding > 0xff {
|
||||
panic("invalid padding")
|
||||
|
||||
@@ -54,7 +54,8 @@ const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678
|
||||
|
||||
// NewEncoding returns a new padded Encoding defined by the given alphabet,
|
||||
// which must be a 64-byte string that does not contain the padding character
|
||||
// or CR / LF ('\r', '\n').
|
||||
// or CR / LF ('\r', '\n'). The alphabet is treated as sequence of byte values
|
||||
// without any special treatment for multi-byte UTF-8.
|
||||
// The resulting Encoding uses the default padding character ('='),
|
||||
// which may be changed or disabled via WithPadding.
|
||||
func NewEncoding(encoder string) *Encoding {
|
||||
@@ -83,6 +84,8 @@ func NewEncoding(encoder string) *Encoding {
|
||||
// The padding character must not be '\r' or '\n', must not
|
||||
// be contained in the encoding's alphabet and must be a rune equal or
|
||||
// below '\xff'.
|
||||
// Padding characters above '\x7f' are encoded as their exact byte value
|
||||
// rather than using the UTF-8 representation of the codepoint.
|
||||
func (enc Encoding) WithPadding(padding rune) *Encoding {
|
||||
if padding == '\r' || padding == '\n' || padding > 0xff {
|
||||
panic("invalid padding")
|
||||
|
||||
@@ -479,7 +479,6 @@ func dataSize(v reflect.Value) int {
|
||||
if s := sizeof(v.Type().Elem()); s >= 0 {
|
||||
return s * v.Len()
|
||||
}
|
||||
return -1
|
||||
|
||||
case reflect.Struct:
|
||||
t := v.Type()
|
||||
@@ -491,8 +490,12 @@ func dataSize(v reflect.Value) int {
|
||||
return size
|
||||
|
||||
default:
|
||||
return sizeof(v.Type())
|
||||
if v.IsValid() {
|
||||
return sizeof(v.Type())
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable.
|
||||
|
||||
@@ -351,6 +351,26 @@ func TestSizeStructCache(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSizeInvalid(t *testing.T) {
|
||||
testcases := []any{
|
||||
int(0),
|
||||
new(int),
|
||||
(*int)(nil),
|
||||
[1]uint{},
|
||||
new([1]uint),
|
||||
(*[1]uint)(nil),
|
||||
[]int{},
|
||||
[]int(nil),
|
||||
new([]int),
|
||||
(*[]int)(nil),
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
if got := Size(tc); got != -1 {
|
||||
t.Errorf("Size(%T) = %d, want -1", tc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An attempt to read into a struct with an unexported field will
|
||||
// panic. This is probably not the best choice, but at this point
|
||||
// anything else would be an API change.
|
||||
|
||||
@@ -286,7 +286,7 @@ var depsRules = `
|
||||
math/big, go/token
|
||||
< go/constant;
|
||||
|
||||
container/heap, go/constant, go/parser, internal/types/errors
|
||||
container/heap, go/constant, go/parser, internal/goversion, internal/types/errors
|
||||
< go/types;
|
||||
|
||||
# The vast majority of standard library packages should not be resorting to regexp.
|
||||
|
||||
@@ -577,6 +577,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
x.mode = value
|
||||
}
|
||||
|
||||
// Use the final type computed above for all arguments.
|
||||
for _, a := range args {
|
||||
check.updateExprType(a.expr, x.typ, true)
|
||||
}
|
||||
|
||||
if check.recordTypes() && x.mode != constant_ {
|
||||
types := make([]Type, nargs)
|
||||
for i := range types {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"internal/goversion"
|
||||
. "internal/types/errors"
|
||||
)
|
||||
|
||||
@@ -233,20 +234,20 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
|
||||
info = new(Info)
|
||||
}
|
||||
|
||||
version, err := parseGoVersion(conf.GoVersion)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
|
||||
}
|
||||
// Note: clients may call NewChecker with the Unsafe package, which is
|
||||
// globally shared and must not be mutated. Therefore NewChecker must not
|
||||
// mutate *pkg.
|
||||
//
|
||||
// (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
|
||||
|
||||
return &Checker{
|
||||
conf: conf,
|
||||
ctxt: conf.Context,
|
||||
fset: fset,
|
||||
pkg: pkg,
|
||||
Info: info,
|
||||
version: version,
|
||||
objMap: make(map[Object]*declInfo),
|
||||
impMap: make(map[importKey]*Package),
|
||||
conf: conf,
|
||||
ctxt: conf.Context,
|
||||
fset: fset,
|
||||
pkg: pkg,
|
||||
Info: info,
|
||||
objMap: make(map[Object]*declInfo),
|
||||
impMap: make(map[importKey]*Package),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,6 +343,20 @@ func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(f
|
||||
var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
|
||||
|
||||
func (check *Checker) checkFiles(files []*ast.File) (err error) {
|
||||
if check.pkg == Unsafe {
|
||||
// Defensive handling for Unsafe, which cannot be type checked, and must
|
||||
// not be mutated. See https://go.dev/issue/61212 for an example of where
|
||||
// Unsafe is passed to NewChecker.
|
||||
return nil
|
||||
}
|
||||
|
||||
check.version, err = parseGoVersion(check.conf.GoVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if check.version.after(version{1, goversion.Version}) {
|
||||
return fmt.Errorf("package requires newer Go version %v", check.version)
|
||||
}
|
||||
if check.conf.FakeImportC && check.conf.go115UsesCgo {
|
||||
return errBadCgo
|
||||
}
|
||||
@@ -386,6 +401,7 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
|
||||
check.monomorph()
|
||||
}
|
||||
|
||||
check.pkg.goVersion = check.conf.GoVersion
|
||||
check.pkg.complete = true
|
||||
|
||||
// no longer needed - release memory
|
||||
|
||||
@@ -141,6 +141,7 @@ var filemap = map[string]action{
|
||||
"universe.go": fixGlobalTypVarDecl,
|
||||
"util_test.go": fixTokenPos,
|
||||
"validtype.go": nil,
|
||||
"version_test.go": nil,
|
||||
}
|
||||
|
||||
// TODO(gri) We should be able to make these rewriters more configurable/composable.
|
||||
|
||||
@@ -186,6 +186,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
|
||||
if !valid {
|
||||
// types2 uses the position of '[' for the error
|
||||
check.errorf(x, NonIndexableOperand, invalidOp+"cannot index %s", x)
|
||||
check.use(e.Indices...)
|
||||
x.mode = invalid
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -12,13 +12,14 @@ import (
|
||||
|
||||
// A Package describes a Go package.
|
||||
type Package struct {
|
||||
path string
|
||||
name string
|
||||
scope *Scope
|
||||
imports []*Package
|
||||
complete bool
|
||||
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
|
||||
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
|
||||
path string
|
||||
name string
|
||||
scope *Scope
|
||||
imports []*Package
|
||||
complete bool
|
||||
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
|
||||
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
|
||||
goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod)
|
||||
}
|
||||
|
||||
// NewPackage returns a new Package for the given package path and name.
|
||||
@@ -37,6 +38,12 @@ func (pkg *Package) Name() string { return pkg.name }
|
||||
// SetName sets the package name.
|
||||
func (pkg *Package) SetName(name string) { pkg.name = name }
|
||||
|
||||
// GoVersion returns the minimum Go version required by this package.
|
||||
// If the minimum version is unknown, GoVersion returns the empty string.
|
||||
// Individual source files may specify a different minimum Go version,
|
||||
// as reported in the [go/ast.File.GoVersion] field.
|
||||
func (pkg *Package) GoVersion() string { return pkg.goVersion }
|
||||
|
||||
// Scope returns the (complete or incomplete) package scope
|
||||
// holding the objects declared at package level (TypeNames,
|
||||
// Consts, Vars, and Funcs).
|
||||
|
||||
@@ -46,7 +46,7 @@ func TestSizeof(t *testing.T) {
|
||||
|
||||
// Misc
|
||||
{Scope{}, 44, 88},
|
||||
{Package{}, 36, 72},
|
||||
{Package{}, 44, 88},
|
||||
{_TypeSet{}, 28, 56},
|
||||
}
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -126,6 +126,20 @@ const (
|
||||
exact
|
||||
)
|
||||
|
||||
func (m unifyMode) String() string {
|
||||
switch m {
|
||||
case 0:
|
||||
return "inexact"
|
||||
case assign:
|
||||
return "assign"
|
||||
case exact:
|
||||
return "exact"
|
||||
case assign | exact:
|
||||
return "assign, exact"
|
||||
}
|
||||
return fmt.Sprintf("mode %d", m)
|
||||
}
|
||||
|
||||
// unify attempts to unify x and y and reports whether it succeeded.
|
||||
// As a side-effect, types may be inferred for type parameters.
|
||||
// The mode parameter controls how types are compared.
|
||||
@@ -258,6 +272,15 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
|
||||
return list
|
||||
}
|
||||
|
||||
// asInterface returns the underlying type of x as an interface if
|
||||
// it is a non-type parameter interface. Otherwise it returns nil.
|
||||
func asInterface(x Type) (i *Interface) {
|
||||
if _, ok := x.(*TypeParam); !ok {
|
||||
i, _ = under(x).(*Interface)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// nify implements the core unification algorithm which is an
|
||||
// adapted version of Checker.identical. For changes to that
|
||||
// code the corresponding changes should be made here.
|
||||
@@ -265,7 +288,7 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
|
||||
func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
u.depth++
|
||||
if traceInference {
|
||||
u.tracef("%s ≡ %s (mode %d)", x, y, mode)
|
||||
u.tracef("%s ≡ %s\t// %s", x, y, mode)
|
||||
}
|
||||
defer func() {
|
||||
if traceInference && !result {
|
||||
@@ -296,7 +319,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// - type parameter recorded with u, make sure one is in x
|
||||
if _, ok := x.(*Named); ok || u.asTypeParam(y) != nil {
|
||||
if traceInference {
|
||||
u.tracef("%s ≡ %s (swap)", y, x)
|
||||
u.tracef("%s ≡ %s\t// swap", y, x)
|
||||
}
|
||||
x, y = y, x
|
||||
}
|
||||
@@ -352,11 +375,49 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
if x := u.at(px); x != nil {
|
||||
// x has an inferred type which must match y
|
||||
if u.nify(x, y, mode, p) {
|
||||
// If we have a match, possibly through underlying types,
|
||||
// and y is a defined type, make sure we record that type
|
||||
// We have a match, possibly through underlying types.
|
||||
xi := asInterface(x)
|
||||
yi := asInterface(y)
|
||||
_, xn := x.(*Named)
|
||||
_, yn := y.(*Named)
|
||||
// If we have two interfaces, what to do depends on
|
||||
// whether they are named and their method sets.
|
||||
if xi != nil && yi != nil {
|
||||
// Both types are interfaces.
|
||||
// If both types are defined types, they must be identical
|
||||
// because unification doesn't know which type has the "right" name.
|
||||
if xn && yn {
|
||||
return Identical(x, y)
|
||||
}
|
||||
// In all other cases, the method sets must match.
|
||||
// The types unified so we know that corresponding methods
|
||||
// match and we can simply compare the number of methods.
|
||||
// TODO(gri) We may be able to relax this rule and select
|
||||
// the more general interface. But if one of them is a defined
|
||||
// type, it's not clear how to choose and whether we introduce
|
||||
// an order dependency or not. Requiring the same method set
|
||||
// is conservative.
|
||||
if len(xi.typeSet().methods) != len(yi.typeSet().methods) {
|
||||
return false
|
||||
}
|
||||
} else if xi != nil || yi != nil {
|
||||
// One but not both of them are interfaces.
|
||||
// In this case, either x or y could be viable matches for the corresponding
|
||||
// type parameter, which means choosing either introduces an order dependence.
|
||||
// Therefore, we must fail unification (go.dev/issue/60933).
|
||||
return false
|
||||
}
|
||||
// If y is a defined type, make sure we record that type
|
||||
// for type parameter x, which may have until now only
|
||||
// recorded an underlying type (go.dev/issue/43056).
|
||||
if _, ok := y.(*Named); ok {
|
||||
// Either both types are interfaces, or neither type is.
|
||||
// If both are interfaces, they have the same methods.
|
||||
//
|
||||
// Note: Changing the recorded type for a type parameter to
|
||||
// a defined type is only ok when unification is inexact.
|
||||
// But in exact unification, if we have a match, x and y must
|
||||
// be identical, so changing the recorded type for x is a no-op.
|
||||
if yn {
|
||||
u.set(px, y)
|
||||
}
|
||||
return true
|
||||
@@ -386,14 +447,8 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
if enableInterfaceInference && mode&exact == 0 {
|
||||
// One or both interfaces may be defined types.
|
||||
// Look under the name, but not under type parameters (go.dev/issue/60564).
|
||||
var xi *Interface
|
||||
if _, ok := x.(*TypeParam); !ok {
|
||||
xi, _ = under(x).(*Interface)
|
||||
}
|
||||
var yi *Interface
|
||||
if _, ok := y.(*TypeParam); !ok {
|
||||
yi, _ = under(y).(*Interface)
|
||||
}
|
||||
xi := asInterface(x)
|
||||
yi := asInterface(y)
|
||||
// If we have two interfaces, check the type terms for equivalence,
|
||||
// and unify common methods if possible.
|
||||
if xi != nil && yi != nil {
|
||||
@@ -494,7 +549,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// TODO(gri) Factor out type parameter handling from the switch.
|
||||
if isTypeParam(y) {
|
||||
if traceInference {
|
||||
u.tracef("%s ≡ %s (swap)", y, x)
|
||||
u.tracef("%s ≡ %s\t// swap", y, x)
|
||||
}
|
||||
x, y = y, x
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
@@ -45,23 +44,24 @@ var (
|
||||
go1_21 = version{1, 21}
|
||||
)
|
||||
|
||||
var errVersionSyntax = errors.New("invalid Go version syntax")
|
||||
|
||||
// parseGoVersion parses a Go version string (such as "go1.12")
|
||||
// and returns the version, or an error. If s is the empty
|
||||
// string, the version is 0.0.
|
||||
func parseGoVersion(s string) (v version, err error) {
|
||||
bad := func() (version, error) {
|
||||
return version{}, fmt.Errorf("invalid Go version syntax %q", s)
|
||||
}
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(s, "go") {
|
||||
return version{}, errVersionSyntax
|
||||
return bad()
|
||||
}
|
||||
s = s[len("go"):]
|
||||
i := 0
|
||||
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
|
||||
if i >= 10 || i == 0 && s[i] == '0' {
|
||||
return version{}, errVersionSyntax
|
||||
return bad()
|
||||
}
|
||||
v.major = 10*v.major + int(s[i]) - '0'
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func parseGoVersion(s string) (v version, err error) {
|
||||
return
|
||||
}
|
||||
if i == 0 || s[i] != '.' {
|
||||
return version{}, errVersionSyntax
|
||||
return bad()
|
||||
}
|
||||
s = s[i+1:]
|
||||
if s == "0" {
|
||||
@@ -82,14 +82,15 @@ func parseGoVersion(s string) (v version, err error) {
|
||||
i = 0
|
||||
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
|
||||
if i >= 10 || i == 0 && s[i] == '0' {
|
||||
return version{}, errVersionSyntax
|
||||
return bad()
|
||||
}
|
||||
v.minor = 10*v.minor + int(s[i]) - '0'
|
||||
}
|
||||
if i > 0 && i == len(s) {
|
||||
return
|
||||
}
|
||||
return version{}, errVersionSyntax
|
||||
// Accept any suffix after the minor number.
|
||||
// We are only looking for the language version (major.minor)
|
||||
// but want to accept any valid Go version, like go1.21.0
|
||||
// and go1.21rc2.
|
||||
return
|
||||
}
|
||||
|
||||
// langCompat reports an error if the representation of a numeric
|
||||
|
||||
26
src/go/types/version_test.go
Normal file
26
src/go/types/version_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
|
||||
|
||||
// Copyright 2023 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 types
|
||||
|
||||
import "testing"
|
||||
|
||||
var parseGoVersionTests = []struct {
|
||||
in string
|
||||
out version
|
||||
}{
|
||||
{"go1.21", version{1, 21}},
|
||||
{"go1.21.0", version{1, 21}},
|
||||
{"go1.21rc2", version{1, 21}},
|
||||
}
|
||||
|
||||
func TestParseGoVersion(t *testing.T) {
|
||||
for _, tt := range parseGoVersionTests {
|
||||
if out, err := parseGoVersion(tt.in); out != tt.out || err != nil {
|
||||
t.Errorf("parseGoVersion(%q) = %v, %v, want %v, nil", tt.in, out, err, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !gccgo
|
||||
|
||||
package abi
|
||||
|
||||
// FuncPC* intrinsics.
|
||||
|
||||
21
src/internal/abi/funcpc_gccgo.go
Normal file
21
src/internal/abi/funcpc_gccgo.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
// For bootstrapping with gccgo.
|
||||
|
||||
//go:build gccgo
|
||||
|
||||
package abi
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func FuncPCABI0(f interface{}) uintptr {
|
||||
words := (*[2]unsafe.Pointer)(unsafe.Pointer(&f))
|
||||
return *(*uintptr)(unsafe.Pointer(words[1]))
|
||||
}
|
||||
|
||||
func FuncPCABIInternal(f interface{}) uintptr {
|
||||
words := (*[2]unsafe.Pointer)(unsafe.Pointer(&f))
|
||||
return *(*uintptr)(unsafe.Pointer(words[1]))
|
||||
}
|
||||
@@ -37,6 +37,8 @@ TEXT memequal<>(SB),NOSPLIT|NOFRAME,$0
|
||||
BEQZ X9, loop32_check
|
||||
|
||||
// Check one byte at a time until we reach 8 byte alignment.
|
||||
SUB X9, X0, X9
|
||||
ADD $8, X9, X9
|
||||
SUB X9, X12, X12
|
||||
align:
|
||||
ADD $-1, X9
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// the instrumentation is OS specific, but only amd64 and arm64 are
|
||||
// supported in the runtime. See src/runtime/libfuzzer*.
|
||||
//
|
||||
// If you update this constraint, also update internal/platform.FuzzInstrumeted.
|
||||
// If you update this constraint, also update internal/platform.FuzzInstrumented.
|
||||
//
|
||||
//go:build !((darwin || linux || windows || freebsd) && (amd64 || arm64))
|
||||
|
||||
|
||||
@@ -2,8 +2,19 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go test . -run=TestGenerated -fix
|
||||
|
||||
package platform
|
||||
|
||||
// An OSArch is a pair of GOOS and GOARCH values indicating a platform.
|
||||
type OSArch struct {
|
||||
GOOS, GOARCH string
|
||||
}
|
||||
|
||||
func (p OSArch) String() string {
|
||||
return p.GOOS + "/" + p.GOARCH
|
||||
}
|
||||
|
||||
// RaceDetectorSupported reports whether goos/goarch supports the race
|
||||
// detector. There is a copy of this function in cmd/dist/test.go.
|
||||
// Race detector only supports 48-bit VMA on arm64. But it will always
|
||||
@@ -123,11 +134,11 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
platform := goos + "/" + goarch
|
||||
if _, ok := osArchSupportsCgo[platform]; !ok {
|
||||
if _, ok := distInfo[OSArch{goos, goarch}]; !ok {
|
||||
return false // platform unrecognized
|
||||
}
|
||||
|
||||
platform := goos + "/" + goarch
|
||||
switch buildmode {
|
||||
case "archive":
|
||||
return true
|
||||
@@ -239,11 +250,6 @@ func DefaultPIE(goos, goarch string, isRace bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CgoSupported reports whether goos/goarch supports cgo.
|
||||
func CgoSupported(goos, goarch string) bool {
|
||||
return osArchSupportsCgo[goos+"/"+goarch]
|
||||
}
|
||||
|
||||
// ExecutableHasDWARF reports whether the linked executable includes DWARF
|
||||
// symbols on goos/goarch.
|
||||
func ExecutableHasDWARF(goos, goarch string) bool {
|
||||
@@ -253,3 +259,28 @@ func ExecutableHasDWARF(goos, goarch string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// osArchInfo describes information about an OSArch extracted from cmd/dist and
|
||||
// stored in the generated distInfo map.
|
||||
type osArchInfo struct {
|
||||
CgoSupported bool
|
||||
FirstClass bool
|
||||
Broken bool
|
||||
}
|
||||
|
||||
// CgoSupported reports whether goos/goarch supports cgo.
|
||||
func CgoSupported(goos, goarch string) bool {
|
||||
return distInfo[OSArch{goos, goarch}].CgoSupported
|
||||
}
|
||||
|
||||
// FirstClass reports whether goos/goarch is considered a “first class” port.
|
||||
// (See https://go.dev/wiki/PortingPolicy#first-class-ports.)
|
||||
func FirstClass(goos, goarch string) bool {
|
||||
return distInfo[OSArch{goos, goarch}].FirstClass
|
||||
}
|
||||
|
||||
// Broken reportsr whether goos/goarch is considered a broken port.
|
||||
// (See https://go.dev/wiki/PortingPolicy#broken-ports.)
|
||||
func Broken(goos, goarch string) bool {
|
||||
return distInfo[OSArch{goos, goarch}].Broken
|
||||
}
|
||||
|
||||
114
src/internal/platform/zosarch.go
Normal file
114
src/internal/platform/zosarch.go
Normal file
@@ -0,0 +1,114 @@
|
||||
// Code generated by go test internal/platform -fix. DO NOT EDIT.
|
||||
|
||||
// To change the information in this file, edit the cgoEnabled and/or firstClass
|
||||
// maps in cmd/dist/build.go, then run 'go generate internal/platform'.
|
||||
|
||||
package platform
|
||||
|
||||
// List is the list of all valid GOOS/GOARCH combinations,
|
||||
// including known-broken ports.
|
||||
var List = []OSArch{
|
||||
{"aix", "ppc64"},
|
||||
{"android", "386"},
|
||||
{"android", "amd64"},
|
||||
{"android", "arm"},
|
||||
{"android", "arm64"},
|
||||
{"darwin", "amd64"},
|
||||
{"darwin", "arm64"},
|
||||
{"dragonfly", "amd64"},
|
||||
{"freebsd", "386"},
|
||||
{"freebsd", "amd64"},
|
||||
{"freebsd", "arm"},
|
||||
{"freebsd", "arm64"},
|
||||
{"freebsd", "riscv64"},
|
||||
{"illumos", "amd64"},
|
||||
{"ios", "amd64"},
|
||||
{"ios", "arm64"},
|
||||
{"js", "wasm"},
|
||||
{"linux", "386"},
|
||||
{"linux", "amd64"},
|
||||
{"linux", "arm"},
|
||||
{"linux", "arm64"},
|
||||
{"linux", "loong64"},
|
||||
{"linux", "mips"},
|
||||
{"linux", "mips64"},
|
||||
{"linux", "mips64le"},
|
||||
{"linux", "mipsle"},
|
||||
{"linux", "ppc64"},
|
||||
{"linux", "ppc64le"},
|
||||
{"linux", "riscv64"},
|
||||
{"linux", "s390x"},
|
||||
{"linux", "sparc64"},
|
||||
{"netbsd", "386"},
|
||||
{"netbsd", "amd64"},
|
||||
{"netbsd", "arm"},
|
||||
{"netbsd", "arm64"},
|
||||
{"openbsd", "386"},
|
||||
{"openbsd", "amd64"},
|
||||
{"openbsd", "arm"},
|
||||
{"openbsd", "arm64"},
|
||||
{"openbsd", "mips64"},
|
||||
{"openbsd", "ppc64"},
|
||||
{"plan9", "386"},
|
||||
{"plan9", "amd64"},
|
||||
{"plan9", "arm"},
|
||||
{"solaris", "amd64"},
|
||||
{"wasip1", "wasm"},
|
||||
{"windows", "386"},
|
||||
{"windows", "amd64"},
|
||||
{"windows", "arm"},
|
||||
{"windows", "arm64"},
|
||||
}
|
||||
|
||||
var distInfo = map[OSArch]osArchInfo{
|
||||
{"aix", "ppc64"}: {CgoSupported: true},
|
||||
{"android", "386"}: {CgoSupported: true},
|
||||
{"android", "amd64"}: {CgoSupported: true},
|
||||
{"android", "arm"}: {CgoSupported: true},
|
||||
{"android", "arm64"}: {CgoSupported: true},
|
||||
{"darwin", "amd64"}: {CgoSupported: true, FirstClass: true},
|
||||
{"darwin", "arm64"}: {CgoSupported: true, FirstClass: true},
|
||||
{"dragonfly", "amd64"}: {CgoSupported: true},
|
||||
{"freebsd", "386"}: {CgoSupported: true},
|
||||
{"freebsd", "amd64"}: {CgoSupported: true},
|
||||
{"freebsd", "arm"}: {CgoSupported: true},
|
||||
{"freebsd", "arm64"}: {CgoSupported: true},
|
||||
{"freebsd", "riscv64"}: {CgoSupported: true},
|
||||
{"illumos", "amd64"}: {CgoSupported: true},
|
||||
{"ios", "amd64"}: {CgoSupported: true},
|
||||
{"ios", "arm64"}: {CgoSupported: true},
|
||||
{"js", "wasm"}: {},
|
||||
{"linux", "386"}: {CgoSupported: true, FirstClass: true},
|
||||
{"linux", "amd64"}: {CgoSupported: true, FirstClass: true},
|
||||
{"linux", "arm"}: {CgoSupported: true, FirstClass: true},
|
||||
{"linux", "arm64"}: {CgoSupported: true, FirstClass: true},
|
||||
{"linux", "loong64"}: {CgoSupported: true},
|
||||
{"linux", "mips"}: {CgoSupported: true},
|
||||
{"linux", "mips64"}: {CgoSupported: true},
|
||||
{"linux", "mips64le"}: {CgoSupported: true},
|
||||
{"linux", "mipsle"}: {CgoSupported: true},
|
||||
{"linux", "ppc64"}: {},
|
||||
{"linux", "ppc64le"}: {CgoSupported: true},
|
||||
{"linux", "riscv64"}: {CgoSupported: true},
|
||||
{"linux", "s390x"}: {CgoSupported: true},
|
||||
{"linux", "sparc64"}: {CgoSupported: true, Broken: true},
|
||||
{"netbsd", "386"}: {CgoSupported: true},
|
||||
{"netbsd", "amd64"}: {CgoSupported: true},
|
||||
{"netbsd", "arm"}: {CgoSupported: true},
|
||||
{"netbsd", "arm64"}: {CgoSupported: true},
|
||||
{"openbsd", "386"}: {CgoSupported: true},
|
||||
{"openbsd", "amd64"}: {CgoSupported: true},
|
||||
{"openbsd", "arm"}: {CgoSupported: true},
|
||||
{"openbsd", "arm64"}: {CgoSupported: true},
|
||||
{"openbsd", "mips64"}: {CgoSupported: true, Broken: true},
|
||||
{"openbsd", "ppc64"}: {Broken: true},
|
||||
{"plan9", "386"}: {},
|
||||
{"plan9", "amd64"}: {},
|
||||
{"plan9", "arm"}: {},
|
||||
{"solaris", "amd64"}: {CgoSupported: true},
|
||||
{"wasip1", "wasm"}: {},
|
||||
{"windows", "386"}: {CgoSupported: true, FirstClass: true},
|
||||
{"windows", "amd64"}: {CgoSupported: true, FirstClass: true},
|
||||
{"windows", "arm"}: {},
|
||||
{"windows", "arm64"}: {CgoSupported: true},
|
||||
}
|
||||
109
src/internal/platform/zosarch_test.go
Normal file
109
src/internal/platform/zosarch_test.go
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright 2023 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 platform_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"internal/diff"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var flagFix = flag.Bool("fix", false, "if true, fix out-of-date generated files")
|
||||
|
||||
// TestGenerated verifies that zosarch.go is up to date,
|
||||
// or regenerates it if the -fix flag is set.
|
||||
func TestGenerated(t *testing.T) {
|
||||
testenv.MustHaveGoRun(t)
|
||||
|
||||
// Here we use 'go run cmd/dist' instead of 'go tool dist' in case the
|
||||
// installed cmd/dist is stale or missing. We don't want to miss a
|
||||
// skew in the data due to a stale binary.
|
||||
cmd := testenv.Command(t, "go", "run", "cmd/dist", "list", "-json", "-broken")
|
||||
|
||||
// cmd/dist requires GOROOT to be set explicitly in the environment.
|
||||
cmd.Env = append(cmd.Environ(), "GOROOT="+testenv.GOROOT(t))
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
|
||||
t.Logf("stderr:\n%s", ee.Stderr)
|
||||
}
|
||||
t.Fatalf("%v: %v", cmd, err)
|
||||
}
|
||||
|
||||
type listEntry struct {
|
||||
GOOS, GOARCH string
|
||||
CgoSupported bool
|
||||
FirstClass bool
|
||||
Broken bool
|
||||
}
|
||||
var entries []listEntry
|
||||
if err := json.Unmarshal(out, &entries); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tmplOut := new(bytes.Buffer)
|
||||
tmpl := template.Must(template.New("zosarch").Parse(zosarchTmpl))
|
||||
err = tmpl.Execute(tmplOut, entries)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd = testenv.Command(t, "gofmt")
|
||||
cmd.Stdin = bytes.NewReader(tmplOut.Bytes())
|
||||
want, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Logf("stdin:\n%s", tmplOut.Bytes())
|
||||
if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
|
||||
t.Logf("stderr:\n%s", ee.Stderr)
|
||||
}
|
||||
t.Fatalf("%v: %v", cmd, err)
|
||||
}
|
||||
|
||||
got, err := os.ReadFile("zosarch.go")
|
||||
if err == nil && bytes.Equal(got, want) {
|
||||
return
|
||||
}
|
||||
|
||||
if !*flagFix {
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
} else {
|
||||
t.Logf("diff:\n%s", diff.Diff("zosarch.go", got, "want", want))
|
||||
}
|
||||
t.Fatalf("zosarch.go is missing or out of date; to regenerate, run\ngo generate internal/platform")
|
||||
}
|
||||
|
||||
if err := os.WriteFile("zosarch.go", want, 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
const zosarchTmpl = `// Code generated by go test internal/platform -fix. DO NOT EDIT.
|
||||
|
||||
// To change the information in this file, edit the cgoEnabled and/or firstClass
|
||||
// maps in cmd/dist/build.go, then run 'go generate internal/platform'.
|
||||
|
||||
package platform
|
||||
|
||||
// List is the list of all valid GOOS/GOARCH combinations,
|
||||
// including known-broken ports.
|
||||
var List = []OSArch{
|
||||
{{range .}} { {{ printf "%q" .GOOS }}, {{ printf "%q" .GOARCH }} },
|
||||
{{end}}
|
||||
}
|
||||
|
||||
var distInfo = map[OSArch]osArchInfo {
|
||||
{{range .}} { {{ printf "%q" .GOOS }}, {{ printf "%q" .GOARCH }} }:
|
||||
{ {{if .CgoSupported}}CgoSupported: true, {{end}}{{if .FirstClass}}FirstClass: true, {{end}}{{if .Broken}} Broken: true, {{end}} },
|
||||
{{end}}
|
||||
}
|
||||
`
|
||||
11
src/internal/types/testdata/fixedbugs/issue60906.go
vendored
Normal file
11
src/internal/types/testdata/fixedbugs/issue60906.go
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2023 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 p
|
||||
|
||||
func _() {
|
||||
var x int
|
||||
var f func() []int
|
||||
_ = f /* ERROR "cannot index f" */ [x]
|
||||
}
|
||||
67
src/internal/types/testdata/fixedbugs/issue60933.go
vendored
Normal file
67
src/internal/types/testdata/fixedbugs/issue60933.go
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2023 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 p
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func g[T any](...T) {}
|
||||
|
||||
// Interface and non-interface types do not match.
|
||||
func _() {
|
||||
var file *os.File
|
||||
g(file, io /* ERROR "type io.Writer of io.Discard does not match inferred type *os.File for T" */ .Discard)
|
||||
g(file, os.Stdout)
|
||||
}
|
||||
|
||||
func _() {
|
||||
var a *os.File
|
||||
var b any
|
||||
g(a, a)
|
||||
g(a, b /* ERROR "type any of b does not match inferred type *os.File for T" */)
|
||||
}
|
||||
|
||||
var writer interface {
|
||||
Write(p []byte) (n int, err error)
|
||||
}
|
||||
|
||||
func _() {
|
||||
var file *os.File
|
||||
g(file, writer /* ERROR "type interface{Write(p []byte) (n int, err error)} of writer does not match inferred type *os.File for T" */)
|
||||
g(writer, file /* ERROR "type *os.File of file does not match inferred type interface{Write(p []byte) (n int, err error)} for T" */)
|
||||
}
|
||||
|
||||
// Different named interface types do not match.
|
||||
func _() {
|
||||
g(io.ReadWriter(nil), io.ReadWriter(nil))
|
||||
g(io.ReadWriter(nil), io /* ERROR "does not match" */ .Writer(nil))
|
||||
g(io.Writer(nil), io /* ERROR "does not match" */ .ReadWriter(nil))
|
||||
}
|
||||
|
||||
// Named and unnamed interface types match if they have the same methods.
|
||||
func _() {
|
||||
g(io.Writer(nil), writer)
|
||||
g(io.ReadWriter(nil), writer /* ERROR "does not match" */ )
|
||||
}
|
||||
|
||||
// There must be no order dependency for named and unnamed interfaces.
|
||||
func f[T interface{ m(T) }](a, b T) {}
|
||||
|
||||
type F interface {
|
||||
m(F)
|
||||
}
|
||||
|
||||
func _() {
|
||||
var i F
|
||||
var j interface {
|
||||
m(F)
|
||||
}
|
||||
|
||||
// order doesn't matter
|
||||
f(i, j)
|
||||
f(j, i)
|
||||
}
|
||||
38
src/internal/types/testdata/fixedbugs/issue60946.go
vendored
Normal file
38
src/internal/types/testdata/fixedbugs/issue60946.go
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2023 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 p
|
||||
|
||||
type Tn interface{ m() }
|
||||
type T1 struct{}
|
||||
type T2 struct{}
|
||||
|
||||
func (*T1) m() {}
|
||||
func (*T2) m() {}
|
||||
|
||||
func g[P any](...P) {}
|
||||
|
||||
func _() {
|
||||
var t interface{ m() }
|
||||
var tn Tn
|
||||
var t1 *T1
|
||||
var t2 *T2
|
||||
|
||||
// these are ok (interface types only)
|
||||
g(t, t)
|
||||
g(t, tn)
|
||||
g(tn, t)
|
||||
g(tn, tn)
|
||||
|
||||
// these are not ok (interface and non-interface types)
|
||||
g(t, t1 /* ERROR "does not match" */)
|
||||
g(t1, t /* ERROR "does not match" */)
|
||||
g(tn, t1 /* ERROR "does not match" */)
|
||||
g(t1, tn /* ERROR "does not match" */)
|
||||
|
||||
g(t, t1 /* ERROR "does not match" */, t2)
|
||||
g(t1, t2 /* ERROR "does not match" */, t)
|
||||
g(tn, t1 /* ERROR "does not match" */, t2)
|
||||
g(t1, t2 /* ERROR "does not match" */, tn)
|
||||
}
|
||||
@@ -81,7 +81,7 @@ func argsToAttrSlice(args []any) []Attr {
|
||||
}
|
||||
|
||||
// Any returns an Attr for the supplied value.
|
||||
// See [Value.AnyValue] for how values are treated.
|
||||
// See [AnyValue] for how values are treated.
|
||||
func Any(key string, value any) Attr {
|
||||
return Attr{key, AnyValue(value)}
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ and hidden fields that refer to state (such as attributes) indirectly. This
|
||||
means that modifying a simple copy of a Record (e.g. by calling
|
||||
[Record.Add] or [Record.AddAttrs] to add attributes)
|
||||
may have unexpected effects on the original.
|
||||
Before modifying a Record, use [Clone] to
|
||||
Before modifying a Record, use [Record.Clone] to
|
||||
create a copy that shares no state with the original,
|
||||
or create a new Record with [NewRecord]
|
||||
and build up its Attrs by traversing the old ones with [Record.Attrs].
|
||||
|
||||
@@ -140,7 +140,7 @@ type HandlerOptions struct {
|
||||
|
||||
// ReplaceAttr is called to rewrite each non-group attribute before it is logged.
|
||||
// The attribute's value has been resolved (see [Value.Resolve]).
|
||||
// If ReplaceAttr returns an Attr with Key == "", the attribute is discarded.
|
||||
// If ReplaceAttr returns a zero Attr, the attribute is discarded.
|
||||
//
|
||||
// The built-in attributes with keys "time", "level", "source", and "msg"
|
||||
// are passed to this function, except that time is omitted
|
||||
@@ -221,6 +221,11 @@ func (h *commonHandler) enabled(l Level) bool {
|
||||
}
|
||||
|
||||
func (h *commonHandler) withAttrs(as []Attr) *commonHandler {
|
||||
// We are going to ignore empty groups, so if the entire slice consists of
|
||||
// them, there is nothing to do.
|
||||
if countEmptyGroups(as) == len(as) {
|
||||
return h
|
||||
}
|
||||
h2 := h.clone()
|
||||
// Pre-format the attributes as an optimization.
|
||||
state := h2.newHandleState((*buffer.Buffer)(&h2.preformattedAttrs), false, "")
|
||||
@@ -308,15 +313,20 @@ func (s *handleState) appendNonBuiltIns(r Record) {
|
||||
}
|
||||
// Attrs in Record -- unlike the built-in ones, they are in groups started
|
||||
// from WithGroup.
|
||||
s.prefix.WriteString(s.h.groupPrefix)
|
||||
s.openGroups()
|
||||
r.Attrs(func(a Attr) bool {
|
||||
s.appendAttr(a)
|
||||
return true
|
||||
})
|
||||
// If the record has no Attrs, don't output any groups.
|
||||
nOpenGroups := s.h.nOpenGroups
|
||||
if r.NumAttrs() > 0 {
|
||||
s.prefix.WriteString(s.h.groupPrefix)
|
||||
s.openGroups()
|
||||
nOpenGroups = len(s.h.groups)
|
||||
r.Attrs(func(a Attr) bool {
|
||||
s.appendAttr(a)
|
||||
return true
|
||||
})
|
||||
}
|
||||
if s.h.json {
|
||||
// Close all open groups.
|
||||
for range s.h.groups {
|
||||
for range s.h.groups[:nOpenGroups] {
|
||||
s.buf.WriteByte('}')
|
||||
}
|
||||
// Close the top-level object.
|
||||
|
||||
@@ -214,6 +214,28 @@ func TestJSONAndTextHandlers(t *testing.T) {
|
||||
wantText: "msg=message h.a=1",
|
||||
wantJSON: `{"msg":"message","h":{"a":1}}`,
|
||||
},
|
||||
{
|
||||
name: "nested empty group",
|
||||
replace: removeKeys(TimeKey, LevelKey),
|
||||
attrs: []Attr{
|
||||
Group("g",
|
||||
Group("h",
|
||||
Group("i"), Group("j"))),
|
||||
},
|
||||
wantText: `msg=message`,
|
||||
wantJSON: `{"msg":"message"}`,
|
||||
},
|
||||
{
|
||||
name: "nested non-empty group",
|
||||
replace: removeKeys(TimeKey, LevelKey),
|
||||
attrs: []Attr{
|
||||
Group("g",
|
||||
Group("h",
|
||||
Group("i"), Group("j", Int("a", 1)))),
|
||||
},
|
||||
wantText: `msg=message g.h.j.a=1`,
|
||||
wantJSON: `{"msg":"message","g":{"h":{"j":{"a":1}}}}`,
|
||||
},
|
||||
{
|
||||
name: "escapes",
|
||||
replace: removeKeys(TimeKey, LevelKey),
|
||||
@@ -281,6 +303,34 @@ func TestJSONAndTextHandlers(t *testing.T) {
|
||||
wantText: "msg=message p1=1 s1.s2.a=one s1.s2.b=2",
|
||||
wantJSON: `{"msg":"message","p1":1,"s1":{"s2":{"a":"one","b":2}}}`,
|
||||
},
|
||||
{
|
||||
name: "empty with-groups",
|
||||
replace: removeKeys(TimeKey, LevelKey),
|
||||
with: func(h Handler) Handler {
|
||||
return h.WithGroup("x").WithGroup("y")
|
||||
},
|
||||
wantText: "msg=message",
|
||||
wantJSON: `{"msg":"message"}`,
|
||||
},
|
||||
{
|
||||
name: "empty with-groups, no non-empty attrs",
|
||||
replace: removeKeys(TimeKey, LevelKey),
|
||||
with: func(h Handler) Handler {
|
||||
return h.WithGroup("x").WithAttrs([]Attr{Group("g")}).WithGroup("y")
|
||||
},
|
||||
wantText: "msg=message",
|
||||
wantJSON: `{"msg":"message"}`,
|
||||
},
|
||||
{
|
||||
name: "one empty with-group",
|
||||
replace: removeKeys(TimeKey, LevelKey),
|
||||
with: func(h Handler) Handler {
|
||||
return h.WithGroup("x").WithAttrs([]Attr{Int("a", 1)}).WithGroup("y")
|
||||
},
|
||||
attrs: []Attr{Group("g", Group("h"))},
|
||||
wantText: "msg=message x.a=1",
|
||||
wantJSON: `{"msg":"message","x":{"a":1}}`,
|
||||
},
|
||||
{
|
||||
name: "GroupValue as Attr value",
|
||||
replace: removeKeys(TimeKey, LevelKey),
|
||||
|
||||
@@ -106,7 +106,7 @@ func TestConnections(t *testing.T) {
|
||||
// log.Logger's output goes through the handler.
|
||||
SetDefault(New(NewTextHandler(&slogbuf, &HandlerOptions{AddSource: true})))
|
||||
log.Print("msg2")
|
||||
checkLogOutput(t, slogbuf.String(), "time="+timeRE+` level=INFO source=.*logger_test.go:\d{3} msg=msg2`)
|
||||
checkLogOutput(t, slogbuf.String(), "time="+timeRE+` level=INFO source=.*logger_test.go:\d{3}"? msg=msg2`)
|
||||
|
||||
// The default log.Logger always outputs at Info level.
|
||||
slogbuf.Reset()
|
||||
|
||||
@@ -93,9 +93,17 @@ func (r Record) Attrs(f func(Attr) bool) {
|
||||
}
|
||||
|
||||
// AddAttrs appends the given Attrs to the Record's list of Attrs.
|
||||
// It omits empty groups.
|
||||
func (r *Record) AddAttrs(attrs ...Attr) {
|
||||
n := copy(r.front[r.nFront:], attrs)
|
||||
r.nFront += n
|
||||
var i int
|
||||
for i = 0; i < len(attrs) && r.nFront < len(r.front); i++ {
|
||||
a := attrs[i]
|
||||
if a.Value.isEmptyGroup() {
|
||||
continue
|
||||
}
|
||||
r.front[r.nFront] = a
|
||||
r.nFront++
|
||||
}
|
||||
// Check if a copy was modified by slicing past the end
|
||||
// and seeing if the Attr there is non-zero.
|
||||
if cap(r.back) > len(r.back) {
|
||||
@@ -104,15 +112,25 @@ func (r *Record) AddAttrs(attrs ...Attr) {
|
||||
panic("copies of a slog.Record were both modified")
|
||||
}
|
||||
}
|
||||
r.back = append(r.back, attrs[n:]...)
|
||||
ne := countEmptyGroups(attrs[i:])
|
||||
r.back = slices.Grow(r.back, len(attrs[i:])-ne)
|
||||
for _, a := range attrs[i:] {
|
||||
if !a.Value.isEmptyGroup() {
|
||||
r.back = append(r.back, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add converts the args to Attrs as described in [Logger.Log],
|
||||
// then appends the Attrs to the Record's list of Attrs.
|
||||
// It omits empty groups.
|
||||
func (r *Record) Add(args ...any) {
|
||||
var a Attr
|
||||
for len(args) > 0 {
|
||||
a, args = argsToAttr(args)
|
||||
if a.Value.isEmptyGroup() {
|
||||
continue
|
||||
}
|
||||
if r.nFront < len(r.front) {
|
||||
r.front[r.nFront] = a
|
||||
r.nFront++
|
||||
|
||||
@@ -164,9 +164,32 @@ func DurationValue(v time.Duration) Value {
|
||||
// GroupValue returns a new Value for a list of Attrs.
|
||||
// The caller must not subsequently mutate the argument slice.
|
||||
func GroupValue(as ...Attr) Value {
|
||||
// Remove empty groups.
|
||||
// It is simpler overall to do this at construction than
|
||||
// to check each Group recursively for emptiness.
|
||||
if n := countEmptyGroups(as); n > 0 {
|
||||
as2 := make([]Attr, 0, len(as)-n)
|
||||
for _, a := range as {
|
||||
if !a.Value.isEmptyGroup() {
|
||||
as2 = append(as2, a)
|
||||
}
|
||||
}
|
||||
as = as2
|
||||
}
|
||||
return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))}
|
||||
}
|
||||
|
||||
// countEmptyGroups returns the number of empty group values in its argument.
|
||||
func countEmptyGroups(as []Attr) int {
|
||||
n := 0
|
||||
for _, a := range as {
|
||||
if a.Value.isEmptyGroup() {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// AnyValue returns a Value for the supplied value.
|
||||
//
|
||||
// If the supplied value is of type Value, it is returned
|
||||
@@ -399,6 +422,17 @@ func (v Value) Equal(w Value) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// isEmptyGroup reports whether v is a group that has no attributes.
|
||||
func (v Value) isEmptyGroup() bool {
|
||||
if v.Kind() != KindGroup {
|
||||
return false
|
||||
}
|
||||
// We do not need to recursively examine the group's Attrs for emptiness,
|
||||
// because GroupValue removed them when the group was constructed, and
|
||||
// groups are immutable.
|
||||
return len(v.group()) == 0
|
||||
}
|
||||
|
||||
// append appends a text representation of v to dst.
|
||||
// v is formatted as with fmt.Sprint.
|
||||
func (v Value) append(dst []byte) []byte {
|
||||
|
||||
@@ -229,6 +229,18 @@ func TestZeroTime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyGroup(t *testing.T) {
|
||||
g := GroupValue(
|
||||
Int("a", 1),
|
||||
Group("g1", Group("g2")),
|
||||
Group("g3", Group("g4", Int("b", 2))))
|
||||
got := g.Group()
|
||||
want := []Attr{Int("a", 1), Group("g3", Group("g4", Int("b", 2)))}
|
||||
if !attrsEqual(got, want) {
|
||||
t.Errorf("\ngot %v\nwant %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
type replace struct {
|
||||
v Value
|
||||
}
|
||||
|
||||
45
src/maps/example_test.go
Normal file
45
src/maps/example_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2023 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 maps_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ExampleDeleteFunc() {
|
||||
m := map[string]int{
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3,
|
||||
"four": 4,
|
||||
}
|
||||
maps.DeleteFunc(m, func(k string, v int) bool {
|
||||
return v%2 != 0 // delete odd values
|
||||
})
|
||||
fmt.Println(m)
|
||||
// Output:
|
||||
// map[four:4 two:2]
|
||||
}
|
||||
|
||||
func ExampleEqualFunc() {
|
||||
m1 := map[int]string{
|
||||
1: "one",
|
||||
10: "Ten",
|
||||
1000: "THOUSAND",
|
||||
}
|
||||
m2 := map[int][]byte{
|
||||
1: []byte("One"),
|
||||
10: []byte("Ten"),
|
||||
1000: []byte("Thousand"),
|
||||
}
|
||||
eq := maps.EqualFunc(m1, m2, func(v1 string, v2 []byte) bool {
|
||||
return strings.ToLower(v1) == strings.ToLower(string(v2))
|
||||
})
|
||||
fmt.Println(eq)
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
@@ -2059,6 +2059,9 @@ var fmaC = []struct{ x, y, z, want float64 }{
|
||||
|
||||
// Special
|
||||
{0, 0, 0, 0},
|
||||
{Copysign(0, -1), 0, 0, 0},
|
||||
{0, 0, Copysign(0, -1), 0},
|
||||
{Copysign(0, -1), 0, Copysign(0, -1), Copysign(0, -1)},
|
||||
{-1.1754226043408471e-38, NaN(), Inf(0), NaN()},
|
||||
{0, 0, 2.22507385643494e-308, 2.22507385643494e-308},
|
||||
{-8.65697792e+09, NaN(), -7.516192799999999e+09, NaN()},
|
||||
@@ -2077,6 +2080,10 @@ var fmaC = []struct{ x, y, z, want float64 }{
|
||||
{4.612811918325842e+18, 1.4901161193847641e-08, 2.6077032311277997e-08, 6.873625395187494e+10},
|
||||
{-9.094947033611148e-13, 4.450691014249257e-308, 2.086006742350485e-308, 2.086006742346437e-308},
|
||||
{-7.751454006381804e-05, 5.588653777189071e-308, -2.2207280111272877e-308, -2.2211612130544025e-308},
|
||||
|
||||
// Issue #61130
|
||||
{-1, 1, 1, 0},
|
||||
{1, 1, -1, 0},
|
||||
}
|
||||
|
||||
var sqrt32 = []float32{
|
||||
@@ -3099,6 +3106,45 @@ func TestFMA(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func fmsub(x, y, z float64) float64 {
|
||||
return FMA(x, y, -z)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func fnmsub(x, y, z float64) float64 {
|
||||
return FMA(-x, y, z)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func fnmadd(x, y, z float64) float64 {
|
||||
return FMA(-x, y, -z)
|
||||
}
|
||||
|
||||
func TestFMANegativeArgs(t *testing.T) {
|
||||
// Some architectures have instructions for fused multiply-subtract and
|
||||
// also negated variants of fused multiply-add and subtract. This test
|
||||
// aims to check that the optimizations that generate those instructions
|
||||
// are applied correctly, if they exist.
|
||||
for _, c := range fmaC {
|
||||
want := PortableFMA(c.x, c.y, -c.z)
|
||||
got := fmsub(c.x, c.y, c.z)
|
||||
if !alike(got, want) {
|
||||
t.Errorf("FMA(%g, %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want)
|
||||
}
|
||||
want = PortableFMA(-c.x, c.y, c.z)
|
||||
got = fnmsub(c.x, c.y, c.z)
|
||||
if !alike(got, want) {
|
||||
t.Errorf("FMA(-(%g), %g, %g) == %g, want %g", c.x, c.y, c.z, got, want)
|
||||
}
|
||||
want = PortableFMA(-c.x, c.y, -c.z)
|
||||
got = fnmadd(c.x, c.y, c.z)
|
||||
if !alike(got, want) {
|
||||
t.Errorf("FMA(-(%g), %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that math functions of high angle values
|
||||
// return accurate results. [Since (vf[i] + large) - large != vf[i],
|
||||
// testing for Trig(vf[i] + large) == Trig(vf[i]), where large is
|
||||
|
||||
@@ -132,6 +132,11 @@ func FMA(x, y, z float64) float64 {
|
||||
ps, pe, pm1, pm2, zs, ze, zm1, zm2 = zs, ze, zm1, zm2, ps, pe, pm1, pm2
|
||||
}
|
||||
|
||||
// Special case: if p == -z the result is always +0 since neither operand is zero.
|
||||
if ps != zs && pe == ze && pm1 == zm1 && pm2 == zm2 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Align significands
|
||||
zm1, zm2 = shrcompress(zm1, zm2, uint(pe-ze))
|
||||
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file holds stub versions of the cgo functions called on Unix systems.
|
||||
// We build this file if using the netgo build tag, or if cgo is not
|
||||
// enabled and we are using a Unix system other than Darwin.
|
||||
// Darwin is exempted because it always provides the cgo routines,
|
||||
// in cgo_unix_syscall.go.
|
||||
// We build this file:
|
||||
// - if using the netgo build tag on a Unix system
|
||||
// - on a Unix system without the cgo resolver functions
|
||||
// (Darwin always provides the cgo functions, in cgo_unix_syscall.go)
|
||||
// - on wasip1, where cgo is never available
|
||||
|
||||
//go:build netgo || (!cgo && unix && !darwin)
|
||||
//go:build (netgo && unix) || (unix && !cgo && !darwin) || wasip1
|
||||
|
||||
package net
|
||||
|
||||
|
||||
@@ -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 !js && !wasip1
|
||||
//go:build !js
|
||||
|
||||
package net
|
||||
|
||||
|
||||
@@ -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 !js && !wasip1
|
||||
//go:build !js
|
||||
|
||||
// DNS client: see RFC 1035.
|
||||
// Has to be linked into package net for Dial.
|
||||
|
||||
@@ -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 !js && !wasip1 && !windows
|
||||
//go:build !js && !windows
|
||||
|
||||
// Read system DNS config from /etc/resolv.conf
|
||||
|
||||
|
||||
@@ -48,35 +48,6 @@ func TestForeachHeaderElement(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanHost(t *testing.T) {
|
||||
tests := []struct {
|
||||
in, want string
|
||||
}{
|
||||
{"www.google.com", "www.google.com"},
|
||||
{"www.google.com foo", "www.google.com"},
|
||||
{"www.google.com/foo", "www.google.com"},
|
||||
{" first character is a space", ""},
|
||||
{"[1::6]:8080", "[1::6]:8080"},
|
||||
|
||||
// Punycode:
|
||||
{"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"},
|
||||
{"bücher.de", "xn--bcher-kva.de"},
|
||||
{"bücher.de:8080", "xn--bcher-kva.de:8080"},
|
||||
// Verify we convert to lowercase before punycode:
|
||||
{"BÜCHER.de", "xn--bcher-kva.de"},
|
||||
{"BÜCHER.de:8080", "xn--bcher-kva.de:8080"},
|
||||
// Verify we normalize to NFC before punycode:
|
||||
{"gophér.nfc", "xn--gophr-esa.nfc"}, // NFC input; no work needed
|
||||
{"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := cleanHost(tt.in)
|
||||
if tt.want != got {
|
||||
t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that cmd/go doesn't link in the HTTP server.
|
||||
//
|
||||
// This catches accidental dependencies between the HTTP transport and
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"io"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http/httptrace"
|
||||
"net/http/internal/ascii"
|
||||
"net/textproto"
|
||||
@@ -27,6 +26,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
@@ -580,12 +580,19 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
|
||||
// is not given, use the host from the request URL.
|
||||
//
|
||||
// Clean the host, in case it arrives with unexpected stuff in it.
|
||||
host := cleanHost(r.Host)
|
||||
host := r.Host
|
||||
if host == "" {
|
||||
if r.URL == nil {
|
||||
return errMissingHost
|
||||
}
|
||||
host = cleanHost(r.URL.Host)
|
||||
host = r.URL.Host
|
||||
}
|
||||
host, err = httpguts.PunycodeHostPort(host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !httpguts.ValidHostHeader(host) {
|
||||
return errors.New("http: invalid Host header")
|
||||
}
|
||||
|
||||
// According to RFC 6874, an HTTP client, proxy, or other
|
||||
@@ -742,40 +749,6 @@ func idnaASCII(v string) (string, error) {
|
||||
return idna.Lookup.ToASCII(v)
|
||||
}
|
||||
|
||||
// cleanHost cleans up the host sent in request's Host header.
|
||||
//
|
||||
// It both strips anything after '/' or ' ', and puts the value
|
||||
// into Punycode form, if necessary.
|
||||
//
|
||||
// Ideally we'd clean the Host header according to the spec:
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]")
|
||||
// https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host)
|
||||
// https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host)
|
||||
//
|
||||
// But practically, what we are trying to avoid is the situation in
|
||||
// issue 11206, where a malformed Host header used in the proxy context
|
||||
// would create a bad request. So it is enough to just truncate at the
|
||||
// first offending character.
|
||||
func cleanHost(in string) string {
|
||||
if i := strings.IndexAny(in, " /"); i != -1 {
|
||||
in = in[:i]
|
||||
}
|
||||
host, port, err := net.SplitHostPort(in)
|
||||
if err != nil { // input was just a host
|
||||
a, err := idnaASCII(in)
|
||||
if err != nil {
|
||||
return in // garbage in, garbage out
|
||||
}
|
||||
return a
|
||||
}
|
||||
a, err := idnaASCII(host)
|
||||
if err != nil {
|
||||
return in // garbage in, garbage out
|
||||
}
|
||||
return net.JoinHostPort(a, port)
|
||||
}
|
||||
|
||||
// removeZone removes IPv6 zone identifier from host.
|
||||
// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
|
||||
func removeZone(host string) string {
|
||||
|
||||
@@ -775,15 +775,8 @@ func TestRequestBadHost(t *testing.T) {
|
||||
}
|
||||
req.Host = "foo.com with spaces"
|
||||
req.URL.Host = "foo.com with spaces"
|
||||
req.Write(logWrites{t, &got})
|
||||
want := []string{
|
||||
"GET /after HTTP/1.1\r\n",
|
||||
"Host: foo.com\r\n",
|
||||
"User-Agent: " + DefaultUserAgent + "\r\n",
|
||||
"\r\n",
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Writes = %q\n Want = %q", got, want)
|
||||
if err := req.Write(logWrites{t, &got}); err == nil {
|
||||
t.Errorf("Writing request with invalid Host: succeded, want error")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user