mirror of
https://github.com/golang/go.git
synced 2026-02-01 08:32:04 +03:00
Compare commits
98 Commits
go1.21rc1
...
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 | ||
|
|
a7b1793701 | ||
|
|
3d279283a4 | ||
|
|
3b4b7b84de | ||
|
|
6459494014 | ||
|
|
02789816c4 | ||
|
|
98617fd23f | ||
|
|
bc21d6a4fc | ||
|
|
261e267618 | ||
|
|
dbf9bf2c39 | ||
|
|
0183c1aa02 | ||
|
|
199fbd4b59 | ||
|
|
a48f9c26d5 | ||
|
|
3891ecbd35 | ||
|
|
60876717b4 | ||
|
|
c1bc44642d | ||
|
|
9ece9a7ac9 | ||
|
|
23c5e48c4a | ||
|
|
cf7ae4f136 | ||
|
|
3c8b7a9551 | ||
|
|
548790e64a | ||
|
|
6dc2d2aa6b | ||
|
|
2b0ff4b629 | ||
|
|
4eceefa338 | ||
|
|
1a7709d6af | ||
|
|
3e7ec13166 | ||
|
|
30b17f4f97 | ||
|
|
65db95d0ed | ||
|
|
60e6afb689 | ||
|
|
f6e0dcc474 |
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 +1,2 @@
|
||||
branch: master
|
||||
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
|
||||
}
|
||||
|
||||
@@ -731,6 +731,10 @@ func TestThreeGopathShlibs(t *testing.T) {
|
||||
func requireGccgo(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" {
|
||||
t.Skip("gccgo test skipped on PPC64 until issue #60798 is resolved")
|
||||
}
|
||||
|
||||
gccgoName := os.Getenv("GCCGO")
|
||||
if gccgoName == "" {
|
||||
gccgoName = "gccgo"
|
||||
@@ -748,7 +752,7 @@ func requireGccgo(t *testing.T) {
|
||||
if dot > 0 {
|
||||
output = output[:dot]
|
||||
}
|
||||
major, err := strconv.Atoi(string(output))
|
||||
major, err := strconv.Atoi(strings.TrimSpace(string(output)))
|
||||
if err != nil {
|
||||
t.Skipf("can't parse gccgo version number %s", output)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -70,6 +70,18 @@ func TestStdLib(t *testing.T) {
|
||||
filepath.Join(goroot, "src"),
|
||||
filepath.Join(goroot, "misc"),
|
||||
} {
|
||||
if filepath.Base(dir) == "misc" {
|
||||
// cmd/distpack deletes GOROOT/misc, so skip that directory if it isn't present.
|
||||
// cmd/distpack also requires GOROOT/VERSION to exist, so use that to
|
||||
// suppress false-positive skips.
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(filepath.Join(testenv.GOROOT(t), "VERSION")); err == nil {
|
||||
fmt.Printf("%s not present; skipping\n", dir)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walkDirs(t, dir, func(filename string) {
|
||||
if skipRx != nil && skipRx.MatchString(filename) {
|
||||
// Always report skipped files since regexp
|
||||
|
||||
@@ -184,13 +184,6 @@ func tcArith(n ir.Node, op ir.Op, l, r ir.Node) (ir.Node, ir.Node, *types.Type)
|
||||
}
|
||||
}
|
||||
|
||||
if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
|
||||
if constant.Sign(r.Val()) == 0 {
|
||||
base.Errorf("division by zero")
|
||||
return l, r, nil
|
||||
}
|
||||
}
|
||||
|
||||
return l, r, t
|
||||
}
|
||||
|
||||
|
||||
@@ -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},
|
||||
}
|
||||
|
||||
|
||||
@@ -206,6 +206,14 @@ func firstComment(filename string) (first string) {
|
||||
func testTestDir(t *testing.T, path string, ignore ...string) {
|
||||
files, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
// cmd/distpack deletes GOROOT/test, so skip the test if it isn't present.
|
||||
// cmd/distpack also requires GOROOT/VERSION to exist, so use that to
|
||||
// suppress false-positive skips.
|
||||
if _, err := os.Stat(filepath.Join(testenv.GOROOT(t), "test")); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(filepath.Join(testenv.GOROOT(t), "VERSION")); err == nil {
|
||||
t.Skipf("skipping: GOROOT/test not present")
|
||||
}
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
`)
|
||||
|
||||
@@ -92,7 +92,7 @@ func (a *Archive) Add(name, src string, info fs.FileInfo) {
|
||||
}
|
||||
|
||||
// Sort sorts the files in the archive.
|
||||
// It is only necessary to call Sort after calling Add.
|
||||
// It is only necessary to call Sort after calling Add or RenameGoMod.
|
||||
// ArchiveDir returns a sorted archive, and the other methods
|
||||
// preserve the sorting of the archive.
|
||||
func (a *Archive) Sort() {
|
||||
@@ -164,6 +164,16 @@ func (a *Archive) SetTime(t time.Time) {
|
||||
}
|
||||
}
|
||||
|
||||
// RenameGoMod renames the go.mod files in the archive to _go.mod,
|
||||
// for use with the module form, which cannot contain other go.mod files.
|
||||
func (a *Archive) RenameGoMod() {
|
||||
for i, f := range a.Files {
|
||||
if strings.HasSuffix(f.Name, "/go.mod") {
|
||||
a.Files[i].Name = strings.TrimSuffix(f.Name, "go.mod") + "_go.mod"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func amatch(pattern, name string) (bool, error) {
|
||||
// firstN returns the prefix of name corresponding to the first n path elements.
|
||||
// If n <= 0, firstN returns the entire name.
|
||||
|
||||
@@ -14,6 +14,17 @@
|
||||
// A cross-compiled distribution for goos/goarch can be built using:
|
||||
//
|
||||
// GOOS=goos GOARCH=goarch ./make.bash -distpack
|
||||
//
|
||||
// To test that the module downloads are usable with the go command:
|
||||
//
|
||||
// ./make.bash -distpack
|
||||
// mkdir -p /tmp/goproxy/golang.org/toolchain/
|
||||
// ln -sf $(pwd)/../pkg/distpack /tmp/goproxy/golang.org/toolchain/@v
|
||||
// GOPROXY=file:///tmp/goproxy GOTOOLCHAIN=$(sed 1q ../VERSION) gotip version
|
||||
//
|
||||
// gotip can be replaced with an older released Go version once there is one.
|
||||
// It just can't be the one make.bash built, because it knows it is already that
|
||||
// version and will skip the download.
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -116,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",
|
||||
|
||||
@@ -199,6 +209,8 @@ func main() {
|
||||
)
|
||||
modVers := modVersionPrefix + "-" + version + "." + goosDashGoarch
|
||||
modArch.AddPrefix(modPath + "@" + modVers)
|
||||
modArch.RenameGoMod()
|
||||
modArch.Sort()
|
||||
testMod(modArch)
|
||||
|
||||
// distpack returns the full path to name in the distpack directory.
|
||||
@@ -235,6 +247,8 @@ func mode(name string, _ fs.FileMode) fs.FileMode {
|
||||
strings.HasSuffix(name, ".pl") ||
|
||||
strings.HasSuffix(name, ".rc") {
|
||||
return 0o755
|
||||
} else if ok, _ := amatch("**/go_?*_?*_exec", name); ok {
|
||||
return 0o755
|
||||
}
|
||||
return 0o644
|
||||
}
|
||||
|
||||
@@ -95,6 +95,10 @@ var modRules = []testRule{
|
||||
{name: "golang.org/toolchain@*/pkg/tool/*/compile", goos: "darwin"},
|
||||
{name: "golang.org/toolchain@*/pkg/tool/*/compile", goos: "windows", exclude: true},
|
||||
{name: "golang.org/toolchain@*/pkg/tool/*/compile.exe", goos: "windows"},
|
||||
|
||||
// go.mod are renamed to _go.mod.
|
||||
{name: "**/go.mod", exclude: true},
|
||||
{name: "**/_go.mod"},
|
||||
}
|
||||
|
||||
func testSrc(a *Archive) {
|
||||
|
||||
@@ -2,12 +2,19 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
//go:build unix
|
||||
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
@@ -33,3 +40,80 @@ func TestGoBuildUmask(t *testing.T) {
|
||||
t.Fatalf("wrote x with mode=%v, wanted no 0077 bits", mode)
|
||||
}
|
||||
}
|
||||
|
||||
// TestTestInterrupt verifies the fix for issue #60203.
|
||||
//
|
||||
// If the whole process group for a 'go test' invocation receives
|
||||
// SIGINT (as would be sent by pressing ^C on a console),
|
||||
// it should return quickly, not deadlock.
|
||||
func TestTestInterrupt(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skipf("skipping in short mode: test executes many subprocesses")
|
||||
}
|
||||
// Don't run this test in parallel, for the same reason.
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.setenv("GOROOT", testGOROOT)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cmd := testenv.CommandContext(t, ctx, tg.goTool(), "test", "std", "-short", "-count=1")
|
||||
cmd.Dir = tg.execDir
|
||||
|
||||
// Override $TMPDIR when running the tests: since we're terminating the tests
|
||||
// with a signal they might fail to clean up some temp files, and we don't
|
||||
// want that to cause an "unexpected files" failure at the end of the run.
|
||||
cmd.Env = append(slices.Clip(tg.env), tempEnvName()+"="+t.TempDir())
|
||||
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
Setpgid: true,
|
||||
}
|
||||
cmd.Cancel = func() error {
|
||||
pgid := cmd.Process.Pid
|
||||
return syscall.Kill(-pgid, syscall.SIGINT)
|
||||
}
|
||||
|
||||
pipe, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Logf("running %v", cmd)
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stdout := new(strings.Builder)
|
||||
r := bufio.NewReader(pipe)
|
||||
line, err := r.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stdout.WriteString(line)
|
||||
|
||||
// The output line for some test was written, so we know things are in progress.
|
||||
//
|
||||
// Cancel the rest of the run by sending SIGINT to the process group:
|
||||
// it should finish up and exit with a nonzero status,
|
||||
// not have to be killed with SIGKILL.
|
||||
cancel()
|
||||
|
||||
io.Copy(stdout, r)
|
||||
if stdout.Len() > 0 {
|
||||
t.Logf("stdout:\n%s", stdout)
|
||||
}
|
||||
err = cmd.Wait()
|
||||
|
||||
ee, _ := err.(*exec.ExitError)
|
||||
if ee == nil {
|
||||
t.Fatalf("unexpectedly finished with nonzero status")
|
||||
}
|
||||
if len(ee.Stderr) > 0 {
|
||||
t.Logf("stderr:\n%s", ee.Stderr)
|
||||
}
|
||||
if !ee.Exited() {
|
||||
t.Fatalf("'go test' did not exit after interrupt: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("interrupted tests without deadlocking")
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -730,6 +730,9 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
|
||||
}
|
||||
}
|
||||
if cfg.Experiment.CoverageRedesign && cfg.BuildCover {
|
||||
load.PrepareForCoverageBuild(pkgs)
|
||||
}
|
||||
b.Do(ctx, a)
|
||||
}
|
||||
|
||||
|
||||
@@ -1013,7 +1013,7 @@ func (r *codeRepo) retractedVersions(ctx context.Context) (func(string) bool, er
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retractions := make([]modfile.VersionInterval, len(f.Retract))
|
||||
retractions := make([]modfile.VersionInterval, 0, len(f.Retract))
|
||||
for _, r := range f.Retract {
|
||||
retractions = append(retractions, r.VersionInterval)
|
||||
}
|
||||
|
||||
@@ -34,12 +34,34 @@ import (
|
||||
// useSumDB reports whether to use the Go checksum database for the given module.
|
||||
func useSumDB(mod module.Version) bool {
|
||||
if mod.Path == "golang.org/toolchain" {
|
||||
must := true
|
||||
// Downloaded toolchains cannot be listed in go.sum,
|
||||
// so we require checksum database lookups even if
|
||||
// GOSUMDB=off or GONOSUMDB matches the pattern.
|
||||
// If GOSUMDB=off, then the eventual lookup will fail
|
||||
// with a good error message.
|
||||
return true
|
||||
|
||||
// Exception #1: using GOPROXY=file:// to test a distpack.
|
||||
if strings.HasPrefix(cfg.GOPROXY, "file://") && !strings.ContainsAny(cfg.GOPROXY, ",|") {
|
||||
must = false
|
||||
}
|
||||
// Exception #2: the Go proxy+checksum database cannot check itself
|
||||
// while doing the initial download.
|
||||
if strings.Contains(os.Getenv("GIT_HTTP_USER_AGENT"), "proxy.golang.org") {
|
||||
must = false
|
||||
}
|
||||
|
||||
// Another potential exception would be GOPROXY=direct,
|
||||
// but that would make toolchain downloads only as secure
|
||||
// as HTTPS, and in particular they'd be susceptible to MITM
|
||||
// attacks on systems with less-than-trustworthy root certificates.
|
||||
// The checksum database provides a stronger guarantee,
|
||||
// so we don't make that exception.
|
||||
|
||||
// Otherwise, require the checksum database.
|
||||
if must {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return cfg.GOSUMDB != "off" && !module.MatchPrefixPatterns(cfg.GONOSUMDB, mod.Path)
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ func GetModule(modroot string) (*Module, error) {
|
||||
return nil, errNotFromModuleCache
|
||||
}
|
||||
modroot = filepath.Clean(modroot)
|
||||
if !str.HasFilePathPrefix(modroot, cfg.GOMODCACHE) {
|
||||
if str.HasFilePathPrefix(modroot, cfg.GOROOTsrc) || !str.HasFilePathPrefix(modroot, cfg.GOMODCACHE) {
|
||||
return nil, errNotFromModuleCache
|
||||
}
|
||||
return openIndexModule(modroot, true)
|
||||
|
||||
@@ -660,6 +660,7 @@ var defaultVetFlags = []string{
|
||||
"-printf",
|
||||
// "-rangeloops",
|
||||
// "-shift",
|
||||
"-slog",
|
||||
"-stringintconv",
|
||||
// "-structtags",
|
||||
// "-tests",
|
||||
@@ -1217,7 +1218,15 @@ func (lockedStdout) Write(b []byte) (int, error) {
|
||||
|
||||
func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action) error {
|
||||
// Wait for previous test to get started and print its first json line.
|
||||
<-r.prev
|
||||
select {
|
||||
case <-r.prev:
|
||||
case <-base.Interrupted:
|
||||
// We can't wait for the previous test action to complete: we don't start
|
||||
// new actions after an interrupt, so if that action wasn't already running
|
||||
// it might never happen. Instead, just don't log anything for this action.
|
||||
base.SetExitStatus(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
if a.Failed {
|
||||
// We were unable to build the binary.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -245,6 +245,8 @@ var TestVersionSwitch string
|
||||
func Exec(gotoolchain string) {
|
||||
log.SetPrefix("go: ")
|
||||
|
||||
writeBits = sysWriteBits()
|
||||
|
||||
count, _ := strconv.Atoi(os.Getenv(countEnv))
|
||||
if count >= maxSwitch-10 {
|
||||
fmt.Fprintf(os.Stderr, "go: switching from go%v to %v [depth %d]\n", gover.Local(), gotoolchain, count)
|
||||
@@ -357,10 +359,101 @@ func Exec(gotoolchain string) {
|
||||
}
|
||||
}
|
||||
|
||||
srcUGoMod := filepath.Join(dir, "src/_go.mod")
|
||||
srcGoMod := filepath.Join(dir, "src/go.mod")
|
||||
if size(srcGoMod) != size(srcUGoMod) {
|
||||
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if path == srcUGoMod {
|
||||
// Leave for last, in case we are racing with another go command.
|
||||
return nil
|
||||
}
|
||||
if pdir, name := filepath.Split(path); name == "_go.mod" {
|
||||
if err := raceSafeCopy(path, pdir+"go.mod"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
// Handle src/go.mod; this is the signal to other racing go commands
|
||||
// that everything is okay and they can skip this step.
|
||||
if err == nil {
|
||||
err = raceSafeCopy(srcUGoMod, srcGoMod)
|
||||
}
|
||||
if err != nil {
|
||||
base.Fatalf("download %s: %v", gotoolchain, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Reinvoke the go command.
|
||||
execGoToolchain(gotoolchain, dir, filepath.Join(dir, "bin/go"))
|
||||
}
|
||||
|
||||
func size(path string) int64 {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return info.Size()
|
||||
}
|
||||
|
||||
var writeBits fs.FileMode
|
||||
|
||||
// raceSafeCopy copies the file old to the file new, being careful to ensure
|
||||
// that if multiple go commands call raceSafeCopy(old, new) at the same time,
|
||||
// they don't interfere with each other: both will succeed and return and
|
||||
// later observe the correct content in new. Like in the build cache, we arrange
|
||||
// this by opening new without truncation and then writing the content.
|
||||
// Both go commands can do this simultaneously and will write the same thing
|
||||
// (old never changes content).
|
||||
func raceSafeCopy(old, new string) error {
|
||||
oldInfo, err := os.Stat(old)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newInfo, err := os.Stat(new)
|
||||
if err == nil && newInfo.Size() == oldInfo.Size() {
|
||||
return nil
|
||||
}
|
||||
data, err := os.ReadFile(old)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// The module cache has unwritable directories by default.
|
||||
// Restore the user write bit in the directory so we can create
|
||||
// the new go.mod file. We clear it again at the end on a
|
||||
// best-effort basis (ignoring failures).
|
||||
dir := filepath.Dir(old)
|
||||
info, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Chmod(dir, info.Mode()|writeBits); err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Chmod(dir, info.Mode())
|
||||
// Note: create the file writable, so that a racing go command
|
||||
// doesn't get an error before we store the actual data.
|
||||
f, err := os.OpenFile(new, os.O_CREATE|os.O_WRONLY, writeBits&^0o111)
|
||||
if err != nil {
|
||||
// If OpenFile failed because a racing go command completed our work
|
||||
// (and then OpenFile failed because the directory or file is now read-only),
|
||||
// count that as a success.
|
||||
if size(old) == size(new) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer os.Chmod(new, oldInfo.Mode())
|
||||
if _, err := f.Write(data); err != nil {
|
||||
f.Close()
|
||||
return err
|
||||
}
|
||||
return f.Close()
|
||||
}
|
||||
|
||||
// modGoToolchain finds the enclosing go.work or go.mod file
|
||||
// and returns the go version and toolchain lines from the file.
|
||||
// The toolchain line overrides the version line
|
||||
|
||||
13
src/cmd/go/internal/toolchain/umask_none.go
Normal file
13
src/cmd/go/internal/toolchain/umask_none.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// 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.
|
||||
|
||||
//go:build !(darwin || freebsd || linux || netbsd || openbsd)
|
||||
|
||||
package toolchain
|
||||
|
||||
import "io/fs"
|
||||
|
||||
func sysWriteBits() fs.FileMode {
|
||||
return 0700
|
||||
}
|
||||
28
src/cmd/go/internal/toolchain/umask_unix.go
Normal file
28
src/cmd/go/internal/toolchain/umask_unix.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
|
||||
//go:build darwin || freebsd || linux || netbsd || openbsd
|
||||
|
||||
package toolchain
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// sysWriteBits determines which bits to OR into the mode to make a directory writable.
|
||||
// It must be called when there are no other file system operations happening.
|
||||
func sysWriteBits() fs.FileMode {
|
||||
// Read current umask. There's no way to read it without also setting it,
|
||||
// so set it conservatively and then restore the original one.
|
||||
m := syscall.Umask(0o777)
|
||||
syscall.Umask(m) // restore bits
|
||||
if m&0o22 == 0o22 { // group and world are unwritable by default
|
||||
return 0o700
|
||||
}
|
||||
if m&0o2 == 0o2 { // group is writable by default, but not world
|
||||
return 0o770
|
||||
}
|
||||
return 0o777 // everything is writable by default
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
39
src/cmd/go/testdata/script/cover_list.txt
vendored
39
src/cmd/go/testdata/script/cover_list.txt
vendored
@@ -16,6 +16,28 @@ go install m/example
|
||||
# with -cover.
|
||||
stale -cover m/example
|
||||
|
||||
# Collect build ID from for m/example built with -cover.
|
||||
go list -cover -export -f '{{.BuildID}}' m/example
|
||||
cp stdout $WORK/listbuildid.txt
|
||||
|
||||
# Now build the m/example binary with coverage.
|
||||
go build -cover -o $WORK/m.exe m/example
|
||||
|
||||
# Ask for the binary build ID by running "go tool buildid".
|
||||
go tool buildid $WORK/m.exe
|
||||
cp stdout $WORK/rawtoolbuildid.txt
|
||||
|
||||
# Make sure that the two build IDs agree with respect to the
|
||||
# m/example package. Build IDs from binaries are of the form X/Y/Z/W
|
||||
# where Y/Z is the package build ID; running the program below will
|
||||
# pick out the parts of the ID that we want.
|
||||
env GOCOVERDIR=$WORK
|
||||
exec $WORK/m.exe $WORK/rawtoolbuildid.txt
|
||||
cp stdout $WORK/toolbuildid.txt
|
||||
|
||||
# Build IDs should match here.
|
||||
cmp $WORK/toolbuildid.txt $WORK/listbuildid.txt
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
@@ -23,6 +45,21 @@ go 1.20
|
||||
-- example/main.go --
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
println("hi mom")
|
||||
println(os.Args[1])
|
||||
content, err := os.ReadFile(os.Args[1])
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
fields := strings.Split(strings.TrimSpace(string(content)), "/")
|
||||
if len(fields) != 4 {
|
||||
os.Exit(2)
|
||||
}
|
||||
fmt.Println(fields[1] + "/" + fields[2])
|
||||
}
|
||||
|
||||
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 --
|
||||
|
||||
@@ -504,7 +504,7 @@ func findGorootModules(t *testing.T) []gorootModule {
|
||||
knownGOROOTModules := [...]string{
|
||||
"std",
|
||||
"cmd",
|
||||
"misc",
|
||||
// The "misc" module sometimes exists, but cmd/distpack intentionally removes it.
|
||||
}
|
||||
var seen = make(map[string]bool) // Key is module path.
|
||||
for _, m := range goroot.modules {
|
||||
|
||||
@@ -64,7 +64,7 @@ var (
|
||||
|
||||
// dirs are the directories to look for *.go files in.
|
||||
// TODO(bradfitz): just use all directories?
|
||||
dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi", "typeparam", "typeparam/mdempsky"}
|
||||
dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi", "typeparam", "typeparam/mdempsky", "arenas"}
|
||||
)
|
||||
|
||||
// Test is the main entrypoint that runs tests in the GOROOT/test directory.
|
||||
@@ -117,6 +117,15 @@ func Test(t *testing.T) {
|
||||
runoutputGate: make(chan bool, *runoutputLimit),
|
||||
}
|
||||
|
||||
// cmd/distpack deletes GOROOT/test, so skip the test if it isn't present.
|
||||
// cmd/distpack also requires GOROOT/VERSION to exist, so use that to
|
||||
// suppress false-positive skips.
|
||||
if _, err := os.Stat(common.gorootTestDir); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(filepath.Join(testenv.GOROOT(t), "VERSION")); err == nil {
|
||||
t.Skipf("skipping: GOROOT/test not present")
|
||||
}
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
for _, goFile := range goFiles(t, dir) {
|
||||
test := test{testCommon: common, dir: dir, goFile: goFile}
|
||||
|
||||
@@ -60,7 +60,7 @@ func (br *bitReader) ReadBits64(bits uint) (n uint64) {
|
||||
// |------------|
|
||||
// br.bits (num valid bits)
|
||||
//
|
||||
// This the next line right shifts the desired bits into the
|
||||
// The next line right shifts the desired bits into the
|
||||
// least-significant places and masks off anything above.
|
||||
n = (br.n >> (br.bits - bits)) & ((1 << bits) - 1)
|
||||
br.bits -= bits
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -137,6 +137,16 @@ func TestImportTypeparamTests(t *testing.T) {
|
||||
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
|
||||
}
|
||||
|
||||
// cmd/distpack removes the GOROOT/test directory, so skip if it isn't there.
|
||||
// cmd/distpack also requires the presence of GOROOT/VERSION, so use that to
|
||||
// avoid false-positive skips.
|
||||
gorootTest := filepath.Join(testenv.GOROOT(t), "test")
|
||||
if _, err := os.Stat(gorootTest); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(filepath.Join(testenv.GOROOT(t), "VERSION")); err == nil {
|
||||
t.Skipf("skipping: GOROOT/test not present")
|
||||
}
|
||||
}
|
||||
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
tmpdir := mktmpdir(t)
|
||||
@@ -144,7 +154,7 @@ func TestImportTypeparamTests(t *testing.T) {
|
||||
|
||||
// Check go files in test/typeparam, except those that fail for a known
|
||||
// reason.
|
||||
rootDir := filepath.Join(testenv.GOROOT(t), "test", "typeparam")
|
||||
rootDir := filepath.Join(gorootTest, "typeparam")
|
||||
list, err := os.ReadDir(rootDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -209,6 +209,14 @@ func firstComment(filename string) string {
|
||||
func testTestDir(t *testing.T, path string, ignore ...string) {
|
||||
files, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
// cmd/distpack deletes GOROOT/test, so skip the test if it isn't present.
|
||||
// cmd/distpack also requires GOROOT/VERSION to exist, so use that to
|
||||
// suppress false-positive skips.
|
||||
if _, err := os.Stat(filepath.Join(testenv.GOROOT(t), "test")); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(filepath.Join(testenv.GOROOT(t), "VERSION")); err == nil {
|
||||
t.Skipf("skipping: GOROOT/test not present")
|
||||
}
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -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]))
|
||||
}
|
||||
@@ -198,10 +198,20 @@ func New(pattern string) (*Matcher, error) {
|
||||
|
||||
m := new(Matcher)
|
||||
|
||||
// Allow multiple v, so that “bisect cmd vPATTERN” can force verbose all the time.
|
||||
p := pattern
|
||||
// Special case for leading 'q' so that 'qn' quietly disables, e.g. fmahash=qn to disable fma
|
||||
// Any instance of 'v' disables 'q'.
|
||||
if len(p) > 0 && p[0] == 'q' {
|
||||
m.quiet = true
|
||||
p = p[1:]
|
||||
if p == "" {
|
||||
return nil, &parseError{"invalid pattern syntax: " + pattern}
|
||||
}
|
||||
}
|
||||
// Allow multiple v, so that “bisect cmd vPATTERN” can force verbose all the time.
|
||||
for len(p) > 0 && p[0] == 'v' {
|
||||
m.verbose = true
|
||||
m.quiet = false
|
||||
p = p[1:]
|
||||
if p == "" {
|
||||
return nil, &parseError{"invalid pattern syntax: " + pattern}
|
||||
@@ -297,7 +307,8 @@ func New(pattern string) (*Matcher, error) {
|
||||
// A Matcher is the parsed, compiled form of a PATTERN string.
|
||||
// The nil *Matcher is valid: it has all changes enabled but none reported.
|
||||
type Matcher struct {
|
||||
verbose bool
|
||||
verbose bool // annotate reporting with human-helpful information
|
||||
quiet bool // disables all reporting. reset if verbose is true. use case is -d=fmahash=qn
|
||||
enable bool // when true, list is for “enable and report” (when false, “disable and report”)
|
||||
list []cond // conditions; later ones win over earlier ones
|
||||
dedup atomicPointerDedup
|
||||
@@ -339,20 +350,19 @@ func (m *Matcher) ShouldEnable(id uint64) bool {
|
||||
if m == nil {
|
||||
return true
|
||||
}
|
||||
for i := len(m.list) - 1; i >= 0; i-- {
|
||||
c := &m.list[i]
|
||||
if id&c.mask == c.bits {
|
||||
return c.result == m.enable
|
||||
}
|
||||
}
|
||||
return false == m.enable
|
||||
return m.matchResult(id) == m.enable
|
||||
}
|
||||
|
||||
// ShouldPrint reports whether to print identifying information about the change with the given id.
|
||||
func (m *Matcher) ShouldPrint(id uint64) bool {
|
||||
if m == nil {
|
||||
if m == nil || m.quiet {
|
||||
return false
|
||||
}
|
||||
return m.matchResult(id)
|
||||
}
|
||||
|
||||
// matchResult returns the result from the first condition that matches id.
|
||||
func (m *Matcher) matchResult(id uint64) bool {
|
||||
for i := len(m.list) - 1; i >= 0; i-- {
|
||||
c := &m.list[i]
|
||||
if id&c.mask == c.bits {
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user