mirror of
https://github.com/golang/go.git
synced 2026-01-29 23:22:06 +03:00
Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c358ffe97 | ||
|
|
312920c00a | ||
|
|
4db13d762b | ||
|
|
08a58dd8b6 | ||
|
|
65092835c5 | ||
|
|
bca817594c | ||
|
|
b8e67d1ddd | ||
|
|
3db4f8146c | ||
|
|
6b45fb7b73 | ||
|
|
be30960e58 | ||
|
|
b59efe6c34 | ||
|
|
c32f1afb41 | ||
|
|
c7b145655b | ||
|
|
03063101a2 | ||
|
|
d51e322a3f | ||
|
|
49594244d3 | ||
|
|
4719048211 | ||
|
|
6c606fc191 | ||
|
|
63ad2b5811 | ||
|
|
95f377daad | ||
|
|
a7a48fad7e | ||
|
|
f5172dcd38 | ||
|
|
8b3acefcbe | ||
|
|
1008486a9f | ||
|
|
e827d41c0a | ||
|
|
c0ed873cd8 | ||
|
|
356a419e2f | ||
|
|
fa60c381ed | ||
|
|
36144ba429 | ||
|
|
5036ba77eb | ||
|
|
b249ec5655 | ||
|
|
4b95fc1e6c | ||
|
|
31a1e19a59 | ||
|
|
450c8021a5 | ||
|
|
22741120ee | ||
|
|
9270e3be8f | ||
|
|
600636e931 | ||
|
|
afbe101950 | ||
|
|
324c3ace2d | ||
|
|
337dd75343 | ||
|
|
4a28cad666 | ||
|
|
090590fdcc | ||
|
|
25b4f40625 | ||
|
|
484535e67b | ||
|
|
813a811d33 | ||
|
|
ee42d468f5 | ||
|
|
446493f5b8 | ||
|
|
0684cecad5 | ||
|
|
ecf7e00db8 | ||
|
|
1dbbac7d79 | ||
|
|
99001c460e | ||
|
|
dcc9bdf380 | ||
|
|
5c7c20e262 | ||
|
|
7c47a6b157 | ||
|
|
20374d1d75 | ||
|
|
e7c4b07ecf | ||
|
|
bf8c7c575c | ||
|
|
ec18f62df5 | ||
|
|
ea6b5a64dd | ||
|
|
3991f6c41c | ||
|
|
9a164d1c41 | ||
|
|
8dce4ca8df | ||
|
|
94c02a3cc4 | ||
|
|
65fa8a6931 | ||
|
|
b52a6963bf | ||
|
|
3ff6dbdf5b | ||
|
|
fa42da156a | ||
|
|
5c7cc468a8 | ||
|
|
b852f39511 | ||
|
|
4df95d5145 | ||
|
|
aee9a19c55 | ||
|
|
26eeaec89c | ||
|
|
9629fa1874 | ||
|
|
3243f93747 | ||
|
|
d2d0ee2049 | ||
|
|
230765a11a | ||
|
|
bdd86bda09 | ||
|
|
aef8a8cd42 | ||
|
|
ef793801f8 | ||
|
|
aaace6dda7 | ||
|
|
0f4483cfdc | ||
|
|
1362737f50 | ||
|
|
602eeaab38 | ||
|
|
ac556f35a2 | ||
|
|
1acd39cc92 | ||
|
|
7b398b1ff7 | ||
|
|
2d01f3695b | ||
|
|
965e9ba0fb | ||
|
|
85ded85b78 | ||
|
|
828b05cc64 | ||
|
|
202a1a5706 | ||
|
|
8e02cffd8e | ||
|
|
5286ac4ed8 | ||
|
|
53b43607d9 | ||
|
|
bdf07c2e16 | ||
|
|
3a04b6e12e | ||
|
|
00f5d3001a | ||
|
|
7628627cb2 | ||
|
|
1fa2deb1b1 | ||
|
|
a943fd0ccc | ||
|
|
fbba58a0a4 | ||
|
|
9987cb6cf3 | ||
|
|
90b06002c4 | ||
|
|
487be3f90b | ||
|
|
7302f83d87 | ||
|
|
de4748c47c | ||
|
|
52bd3b186b | ||
|
|
be7e4fee4b | ||
|
|
b68d699aa7 | ||
|
|
10124c2631 | ||
|
|
5adb0ca8e9 | ||
|
|
8b34676710 | ||
|
|
d7c6da8bac | ||
|
|
9eed826bf9 | ||
|
|
670ce9b8a8 | ||
|
|
b3160e8bce | ||
|
|
9efc2e7f95 | ||
|
|
32593a9192 | ||
|
|
eb598248ba | ||
|
|
9f02342144 | ||
|
|
0480336414 |
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.20
|
||||
parent-branch: master
|
||||
|
||||
@@ -1200,9 +1200,8 @@ proxyHandler := &httputil.ReverseProxy{
|
||||
</p>
|
||||
|
||||
<p><!-- CL 444277 -->
|
||||
The <a href="/pkg/time/#Time.MarshalJSON"><code>Time.MarshalJSON</code></a> and
|
||||
<a href="/pkg/time/#Time.UnmarshalJSON"><code>Time.UnmarshalJSON</code></a> methods
|
||||
are now more strict about adherence to RFC 3339.
|
||||
The <a href="/pkg/time/#Time.MarshalJSON"><code>Time.MarshalJSON</code></a> method
|
||||
is now more strict about adherence to RFC 3339.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- time -->
|
||||
|
||||
@@ -1112,8 +1112,13 @@ func TestStd(t *testing.T) {
|
||||
t.Skip("skip in short mode")
|
||||
}
|
||||
t.Parallel()
|
||||
tmpDir := t.TempDir()
|
||||
// Use a temporary pkgdir to not interfere with other tests, and not write to GOROOT.
|
||||
// Cannot use goCmd as it runs with cloned GOROOT which is incomplete.
|
||||
runWithEnv(t, "building std", []string{"GOROOT=" + oldGOROOT},
|
||||
filepath.Join(oldGOROOT, "bin", "go"), "install", "-buildmode=shared", "-pkgdir="+t.TempDir(), "std")
|
||||
filepath.Join(oldGOROOT, "bin", "go"), "install", "-buildmode=shared", "-pkgdir="+tmpDir, "std")
|
||||
|
||||
// Issue #58966.
|
||||
runWithEnv(t, "testing issue #58966", []string{"GOROOT=" + oldGOROOT},
|
||||
filepath.Join(oldGOROOT, "bin", "go"), "run", "-linkshared", "-pkgdir="+tmpDir, "./issue58966/main.go")
|
||||
}
|
||||
|
||||
15
misc/cgo/testshared/testdata/issue58966/main.go
vendored
Normal file
15
misc/cgo/testshared/testdata/issue58966/main.go
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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 main
|
||||
|
||||
import "crypto/elliptic"
|
||||
|
||||
var curve elliptic.Curve
|
||||
|
||||
func main() {
|
||||
switch curve {
|
||||
case elliptic.P224():
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,11 @@ func (f *File) ParseGo(abspath string, src []byte) {
|
||||
cg = d.Doc
|
||||
}
|
||||
if cg != nil {
|
||||
if strings.ContainsAny(abspath, "\r\n") {
|
||||
// This should have been checked when the file path was first resolved,
|
||||
// but we double check here just to be sure.
|
||||
fatalf("internal error: ParseGo: abspath contains unexpected newline character: %q", abspath)
|
||||
}
|
||||
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), abspath)
|
||||
f.Preamble += commentText(cg) + "\n"
|
||||
f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
|
||||
|
||||
@@ -363,6 +363,12 @@ func main() {
|
||||
|
||||
// Apply trimpath to the file path. The path won't be read from after this point.
|
||||
input, _ = objabi.ApplyRewrites(input, *trimpath)
|
||||
if strings.ContainsAny(input, "\r\n") {
|
||||
// ParseGo, (*Package).writeOutput, and printer.Fprint in SourcePos mode
|
||||
// all emit line directives, which don't permit newlines in the file path.
|
||||
// Bail early if we see anything newline-like in the trimmed path.
|
||||
fatalf("input path contains newline character: %q", input)
|
||||
}
|
||||
goFiles[i] = input
|
||||
|
||||
f := new(File)
|
||||
|
||||
@@ -47,7 +47,9 @@ func (p *Package) writeDefs() {
|
||||
|
||||
fflg := creat(*objDir + "_cgo_flags")
|
||||
for k, v := range p.CgoFlags {
|
||||
fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
|
||||
for _, arg := range v {
|
||||
fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, arg)
|
||||
}
|
||||
if k == "LDFLAGS" && !*gccgo {
|
||||
for _, arg := range v {
|
||||
fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg)
|
||||
@@ -642,6 +644,11 @@ func (p *Package) writeOutput(f *File, srcfile string) {
|
||||
|
||||
// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
|
||||
fmt.Fprintf(fgo1, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
|
||||
if strings.ContainsAny(srcfile, "\r\n") {
|
||||
// This should have been checked when the file path was first resolved,
|
||||
// but we double check here just to be sure.
|
||||
fatalf("internal error: writeOutput: srcfile contains unexpected newline character: %q", srcfile)
|
||||
}
|
||||
fmt.Fprintf(fgo1, "//line %s:1:1\n", srcfile)
|
||||
fgo1.Write(f.Edit.Bytes())
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ func ParseFlags() {
|
||||
|
||||
Debug.ConcurrentOk = true
|
||||
Debug.InlFuncsWithClosures = 1
|
||||
Debug.InlStaticInit = 1
|
||||
Debug.InlStaticInit = 0
|
||||
if buildcfg.Experiment.Unified {
|
||||
Debug.Unified = 1
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func (e *escape) call(ks []hole, call ir.Node) {
|
||||
var init ir.Nodes
|
||||
e.callCommon(ks, call, &init, nil)
|
||||
if len(init) != 0 {
|
||||
call.(*ir.CallExpr).PtrInit().Append(init...)
|
||||
call.(ir.InitNode).PtrInit().Append(init...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,18 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
argumentFunc(nil, k, argp)
|
||||
}
|
||||
|
||||
argumentRType := func(rtypep *ir.Node) {
|
||||
rtype := *rtypep
|
||||
if rtype == nil {
|
||||
return
|
||||
}
|
||||
// common case: static rtype/itab argument, which can be evaluated within the wrapper instead.
|
||||
if addr, ok := rtype.(*ir.AddrExpr); ok && addr.Op() == ir.OADDR && addr.X.Op() == ir.OLINKSYMOFFSET {
|
||||
return
|
||||
}
|
||||
e.wrapExpr(rtype.Pos(), rtypep, init, call, wrapper)
|
||||
}
|
||||
|
||||
switch call.Op() {
|
||||
default:
|
||||
ir.Dump("esc", call)
|
||||
@@ -153,6 +165,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
argument(e.heapHole(), &args[i])
|
||||
}
|
||||
}
|
||||
argumentRType(&call.RType)
|
||||
|
||||
case ir.OCOPY:
|
||||
call := call.(*ir.BinaryExpr)
|
||||
@@ -163,6 +176,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
copiedK = e.heapHole().deref(call, "copied slice")
|
||||
}
|
||||
argument(copiedK, &call.Y)
|
||||
argumentRType(&call.RType)
|
||||
|
||||
case ir.OPANIC:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
@@ -179,15 +193,21 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
for i := range call.Args {
|
||||
argument(e.discardHole(), &call.Args[i])
|
||||
}
|
||||
argumentRType(&call.RType)
|
||||
|
||||
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
argument(e.discardHole(), &call.X)
|
||||
|
||||
case ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
argument(ks[0], &call.X)
|
||||
|
||||
case ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
|
||||
call := call.(*ir.BinaryExpr)
|
||||
argument(ks[0], &call.X)
|
||||
argument(e.discardHole(), &call.Y)
|
||||
argumentRType(&call.RType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,9 @@ func lookupGorootExport(pkgDir string) (string, bool) {
|
||||
)
|
||||
f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) {
|
||||
listOnce.Do(func() {
|
||||
cmd := exec.Command("go", "list", "-export", "-f", "{{.Export}}", pkgDir)
|
||||
cmd := exec.Command(filepath.Join(build.Default.GOROOT, "bin", "go"), "list", "-export", "-f", "{{.Export}}", pkgDir)
|
||||
cmd.Dir = build.Default.GOROOT
|
||||
cmd.Env = append(os.Environ(), "PWD="+cmd.Dir, "GOROOT="+build.Default.GOROOT)
|
||||
var output []byte
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
|
||||
@@ -959,6 +959,11 @@ func reassigned(name *Name) bool {
|
||||
if isName(OuterValue(n.X)) {
|
||||
return true
|
||||
}
|
||||
case ORANGE:
|
||||
n := n.(*RangeStmt)
|
||||
if isName(n.Key) || isName(n.Value) {
|
||||
return true
|
||||
}
|
||||
case OCLOSURE:
|
||||
n := n.(*ClosureExpr)
|
||||
if Any(n.Func, do) {
|
||||
|
||||
@@ -147,9 +147,10 @@ func NewFunc(pos src.XPos) *Func {
|
||||
|
||||
func (f *Func) isStmt() {}
|
||||
|
||||
func (n *Func) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
|
||||
func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
|
||||
func (n *Func) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
|
||||
func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
|
||||
func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) }
|
||||
|
||||
func (f *Func) Type() *types.Type { return f.Nname.Type() }
|
||||
func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
|
||||
|
||||
@@ -256,18 +256,24 @@ func processType(t *ast.TypeSpec) {
|
||||
var copyBody strings.Builder
|
||||
var doChildrenBody strings.Builder
|
||||
var editChildrenBody strings.Builder
|
||||
var editChildrenWithHiddenBody strings.Builder
|
||||
for _, f := range fields {
|
||||
names := f.Names
|
||||
ft := f.Type
|
||||
hidden := false
|
||||
if f.Tag != nil {
|
||||
tag := f.Tag.Value[1 : len(f.Tag.Value)-1]
|
||||
if strings.HasPrefix(tag, "mknode:") {
|
||||
if tag[7:] == "\"-\"" {
|
||||
continue
|
||||
if !isNamedType(ft, "Node") {
|
||||
continue
|
||||
}
|
||||
hidden = true
|
||||
} else {
|
||||
panic(fmt.Sprintf("unexpected tag value: %s", tag))
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected tag value: %s", tag))
|
||||
}
|
||||
}
|
||||
names := f.Names
|
||||
ft := f.Type
|
||||
if isNamedType(ft, "Nodes") {
|
||||
// Nodes == []Node
|
||||
ft = &ast.ArrayType{Elt: &ast.Ident{Name: "Node"}}
|
||||
@@ -286,6 +292,20 @@ func processType(t *ast.TypeSpec) {
|
||||
continue
|
||||
}
|
||||
for _, name := range names {
|
||||
ptr := ""
|
||||
if isPtr {
|
||||
ptr = "*"
|
||||
}
|
||||
if isSlice {
|
||||
fmt.Fprintf(&editChildrenWithHiddenBody,
|
||||
"edit%ss(n.%s, edit)\n", ft, name)
|
||||
} else {
|
||||
fmt.Fprintf(&editChildrenWithHiddenBody,
|
||||
"if n.%s != nil {\nn.%s = edit(n.%s).(%s%s)\n}\n", name, name, name, ptr, ft)
|
||||
}
|
||||
if hidden {
|
||||
continue
|
||||
}
|
||||
if isSlice {
|
||||
fmt.Fprintf(©Body, "c.%s = copy%ss(c.%s)\n", name, ft, name)
|
||||
fmt.Fprintf(&doChildrenBody,
|
||||
@@ -295,10 +315,6 @@ func processType(t *ast.TypeSpec) {
|
||||
} else {
|
||||
fmt.Fprintf(&doChildrenBody,
|
||||
"if n.%s != nil && do(n.%s) {\nreturn true\n}\n", name, name)
|
||||
ptr := ""
|
||||
if isPtr {
|
||||
ptr = "*"
|
||||
}
|
||||
fmt.Fprintf(&editChildrenBody,
|
||||
"if n.%s != nil {\nn.%s = edit(n.%s).(%s%s)\n}\n", name, name, name, ptr, ft)
|
||||
}
|
||||
@@ -313,6 +329,9 @@ func processType(t *ast.TypeSpec) {
|
||||
fmt.Fprintf(&buf, "func (n *%s) editChildren(edit func(Node) Node) {\n", name)
|
||||
buf.WriteString(editChildrenBody.String())
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
fmt.Fprintf(&buf, "func (n *%s) editChildrenWithHidden(edit func(Node) Node) {\n", name)
|
||||
buf.WriteString(editChildrenWithHiddenBody.String())
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
}
|
||||
|
||||
func generateHelpers() {
|
||||
|
||||
@@ -134,9 +134,10 @@ type Name struct {
|
||||
|
||||
func (n *Name) isExpr() {}
|
||||
|
||||
func (n *Name) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Name) doChildren(do func(Node) bool) bool { return false }
|
||||
func (n *Name) editChildren(edit func(Node) Node) {}
|
||||
func (n *Name) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Name) doChildren(do func(Node) bool) bool { return false }
|
||||
func (n *Name) editChildren(edit func(Node) Node) {}
|
||||
func (n *Name) editChildrenWithHidden(edit func(Node) Node) {}
|
||||
|
||||
// RecordFrameOffset records the frame offset for the name.
|
||||
// It is used by package types when laying out function arguments.
|
||||
|
||||
@@ -30,6 +30,7 @@ type Node interface {
|
||||
|
||||
doChildren(func(Node) bool) bool
|
||||
editChildren(func(Node) Node)
|
||||
editChildrenWithHidden(func(Node) Node)
|
||||
|
||||
// Abstract graph structure, for generic traversals.
|
||||
Op() Op
|
||||
@@ -290,7 +291,7 @@ const (
|
||||
OEFACE // itable and data words of an empty-interface value.
|
||||
OITAB // itable word of an interface value.
|
||||
OIDATA // data word of an interface value in X
|
||||
OSPTR // base pointer of a slice or string.
|
||||
OSPTR // base pointer of a slice or string. Bounded==1 means known non-nil.
|
||||
OCFUNC // reference to c function pointer (not go func value)
|
||||
OCHECKNIL // emit code to ensure pointer/interface not nil
|
||||
ORESULT // result of a function call; Xoffset is stack offset
|
||||
|
||||
@@ -30,6 +30,13 @@ func (n *AddStringExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *AddStringExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *AddrExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AddrExpr) copy() Node {
|
||||
@@ -58,6 +65,15 @@ func (n *AddrExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *AddrExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *AssignListStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AssignListStmt) copy() Node {
|
||||
@@ -84,6 +100,11 @@ func (n *AssignListStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Lhs, edit)
|
||||
editNodes(n.Rhs, edit)
|
||||
}
|
||||
func (n *AssignListStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Lhs, edit)
|
||||
editNodes(n.Rhs, edit)
|
||||
}
|
||||
|
||||
func (n *AssignOpStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AssignOpStmt) copy() Node {
|
||||
@@ -112,6 +133,15 @@ func (n *AssignOpStmt) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *AssignOpStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *AssignStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AssignStmt) copy() Node {
|
||||
@@ -140,6 +170,15 @@ func (n *AssignStmt) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *AssignStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *BasicLit) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BasicLit) copy() Node {
|
||||
@@ -156,6 +195,9 @@ func (n *BasicLit) doChildren(do func(Node) bool) bool {
|
||||
func (n *BasicLit) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *BasicLit) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *BinaryExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BinaryExpr) copy() Node {
|
||||
@@ -184,6 +226,18 @@ func (n *BinaryExpr) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *BinaryExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *BlockStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BlockStmt) copy() Node {
|
||||
@@ -205,6 +259,10 @@ func (n *BlockStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
}
|
||||
func (n *BlockStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
}
|
||||
|
||||
func (n *BranchStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BranchStmt) copy() Node {
|
||||
@@ -221,6 +279,9 @@ func (n *BranchStmt) doChildren(do func(Node) bool) bool {
|
||||
func (n *BranchStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *BranchStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *CallExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CallExpr) copy() Node {
|
||||
@@ -253,6 +314,17 @@ func (n *CallExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Args, edit)
|
||||
editNames(n.KeepAlive, edit)
|
||||
}
|
||||
func (n *CallExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
editNodes(n.Args, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
editNames(n.KeepAlive, edit)
|
||||
}
|
||||
|
||||
func (n *CaseClause) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CaseClause) copy() Node {
|
||||
@@ -290,6 +362,15 @@ func (n *CaseClause) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.RTypes, edit)
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
func (n *CaseClause) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Var != nil {
|
||||
n.Var = edit(n.Var).(*Name)
|
||||
}
|
||||
editNodes(n.List, edit)
|
||||
editNodes(n.RTypes, edit)
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
|
||||
func (n *ClosureExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ClosureExpr) copy() Node {
|
||||
@@ -312,6 +393,12 @@ func (n *ClosureExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *ClosureExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *CommClause) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CommClause) copy() Node {
|
||||
@@ -339,6 +426,13 @@ func (n *CommClause) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
func (n *CommClause) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Comm != nil {
|
||||
n.Comm = edit(n.Comm).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
|
||||
func (n *CompLitExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CompLitExpr) copy() Node {
|
||||
@@ -366,6 +460,16 @@ func (n *CompLitExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *CompLitExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *ConstExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ConstExpr) copy() Node {
|
||||
@@ -382,6 +486,9 @@ func (n *ConstExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *ConstExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *ConstExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ConvExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ConvExpr) copy() Node {
|
||||
@@ -404,6 +511,24 @@ func (n *ConvExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *ConvExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.TypeWord != nil {
|
||||
n.TypeWord = edit(n.TypeWord).(Node)
|
||||
}
|
||||
if n.SrcRType != nil {
|
||||
n.SrcRType = edit(n.SrcRType).(Node)
|
||||
}
|
||||
if n.ElemRType != nil {
|
||||
n.ElemRType = edit(n.ElemRType).(Node)
|
||||
}
|
||||
if n.ElemElemRType != nil {
|
||||
n.ElemElemRType = edit(n.ElemElemRType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Decl) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *Decl) copy() Node {
|
||||
@@ -421,6 +546,11 @@ func (n *Decl) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *Decl) editChildrenWithHidden(edit func(Node) Node) {
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *DynamicType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *DynamicType) copy() Node {
|
||||
@@ -449,6 +579,15 @@ func (n *DynamicType) editChildren(edit func(Node) Node) {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
func (n *DynamicType) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.ITab != nil {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *DynamicTypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *DynamicTypeAssertExpr) copy() Node {
|
||||
@@ -489,6 +628,21 @@ func (n *DynamicTypeAssertExpr) editChildren(edit func(Node) Node) {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
func (n *DynamicTypeAssertExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.SrcRType != nil {
|
||||
n.SrcRType = edit(n.SrcRType).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.ITab != nil {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *ForStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ForStmt) copy() Node {
|
||||
@@ -522,6 +676,16 @@ func (n *ForStmt) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
func (n *ForStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Cond != nil {
|
||||
n.Cond = edit(n.Cond).(Node)
|
||||
}
|
||||
if n.Post != nil {
|
||||
n.Post = edit(n.Post).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
|
||||
func (n *Func) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
|
||||
@@ -546,6 +710,12 @@ func (n *GoDeferStmt) editChildren(edit func(Node) Node) {
|
||||
n.Call = edit(n.Call).(Node)
|
||||
}
|
||||
}
|
||||
func (n *GoDeferStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Call != nil {
|
||||
n.Call = edit(n.Call).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Ident) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *Ident) copy() Node {
|
||||
@@ -562,6 +732,9 @@ func (n *Ident) doChildren(do func(Node) bool) bool {
|
||||
func (n *Ident) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *Ident) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *IfStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *IfStmt) copy() Node {
|
||||
@@ -594,6 +767,14 @@ func (n *IfStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.Else, edit)
|
||||
}
|
||||
func (n *IfStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Cond != nil {
|
||||
n.Cond = edit(n.Cond).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.Else, edit)
|
||||
}
|
||||
|
||||
func (n *IndexExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *IndexExpr) copy() Node {
|
||||
@@ -622,6 +803,18 @@ func (n *IndexExpr) editChildren(edit func(Node) Node) {
|
||||
n.Index = edit(n.Index).(Node)
|
||||
}
|
||||
}
|
||||
func (n *IndexExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Index != nil {
|
||||
n.Index = edit(n.Index).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *InlineMarkStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *InlineMarkStmt) copy() Node {
|
||||
@@ -638,6 +831,9 @@ func (n *InlineMarkStmt) doChildren(do func(Node) bool) bool {
|
||||
func (n *InlineMarkStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *InlineMarkStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *InlinedCallExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *InlinedCallExpr) copy() Node {
|
||||
@@ -664,6 +860,11 @@ func (n *InlinedCallExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.ReturnVars, edit)
|
||||
}
|
||||
func (n *InlinedCallExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.ReturnVars, edit)
|
||||
}
|
||||
|
||||
func (n *InstExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *InstExpr) copy() Node {
|
||||
@@ -691,6 +892,13 @@ func (n *InstExpr) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
editNtypes(n.Targs, edit)
|
||||
}
|
||||
func (n *InstExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
editNtypes(n.Targs, edit)
|
||||
}
|
||||
|
||||
func (n *JumpTableStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *JumpTableStmt) copy() Node {
|
||||
@@ -713,6 +921,12 @@ func (n *JumpTableStmt) editChildren(edit func(Node) Node) {
|
||||
n.Idx = edit(n.Idx).(Node)
|
||||
}
|
||||
}
|
||||
func (n *JumpTableStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Idx != nil {
|
||||
n.Idx = edit(n.Idx).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *KeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *KeyExpr) copy() Node {
|
||||
@@ -741,6 +955,15 @@ func (n *KeyExpr) editChildren(edit func(Node) Node) {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
func (n *KeyExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Key != nil {
|
||||
n.Key = edit(n.Key).(Node)
|
||||
}
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *LabelStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *LabelStmt) copy() Node {
|
||||
@@ -757,6 +980,9 @@ func (n *LabelStmt) doChildren(do func(Node) bool) bool {
|
||||
func (n *LabelStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *LabelStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *LinksymOffsetExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *LinksymOffsetExpr) copy() Node {
|
||||
@@ -773,6 +999,9 @@ func (n *LinksymOffsetExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *LinksymOffsetExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *LinksymOffsetExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *LogicalExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *LogicalExpr) copy() Node {
|
||||
@@ -801,6 +1030,15 @@ func (n *LogicalExpr) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *LogicalExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *MakeExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *MakeExpr) copy() Node {
|
||||
@@ -829,6 +1067,18 @@ func (n *MakeExpr) editChildren(edit func(Node) Node) {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
func (n *MakeExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
if n.Cap != nil {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Name) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
|
||||
@@ -847,6 +1097,9 @@ func (n *NilExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *NilExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *NilExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ParenExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ParenExpr) copy() Node {
|
||||
@@ -869,6 +1122,12 @@ func (n *ParenExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *ParenExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *RangeStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *RangeStmt) copy() Node {
|
||||
@@ -914,6 +1173,37 @@ func (n *RangeStmt) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *RangeStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.Key != nil {
|
||||
n.Key = edit(n.Key).(Node)
|
||||
}
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
if n.KeyTypeWord != nil {
|
||||
n.KeyTypeWord = edit(n.KeyTypeWord).(Node)
|
||||
}
|
||||
if n.KeySrcRType != nil {
|
||||
n.KeySrcRType = edit(n.KeySrcRType).(Node)
|
||||
}
|
||||
if n.ValueTypeWord != nil {
|
||||
n.ValueTypeWord = edit(n.ValueTypeWord).(Node)
|
||||
}
|
||||
if n.ValueSrcRType != nil {
|
||||
n.ValueSrcRType = edit(n.ValueSrcRType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *RawOrigExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *RawOrigExpr) copy() Node {
|
||||
@@ -930,6 +1220,9 @@ func (n *RawOrigExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *RawOrigExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *RawOrigExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ResultExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ResultExpr) copy() Node {
|
||||
@@ -946,6 +1239,9 @@ func (n *ResultExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *ResultExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *ResultExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ReturnStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ReturnStmt) copy() Node {
|
||||
@@ -967,6 +1263,10 @@ func (n *ReturnStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Results, edit)
|
||||
}
|
||||
func (n *ReturnStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Results, edit)
|
||||
}
|
||||
|
||||
func (n *SelectStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SelectStmt) copy() Node {
|
||||
@@ -993,6 +1293,11 @@ func (n *SelectStmt) editChildren(edit func(Node) Node) {
|
||||
editCommClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
func (n *SelectStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editCommClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
|
||||
func (n *SelectorExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SelectorExpr) copy() Node {
|
||||
@@ -1021,6 +1326,15 @@ func (n *SelectorExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *SelectorExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SendStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SendStmt) copy() Node {
|
||||
@@ -1049,6 +1363,15 @@ func (n *SendStmt) editChildren(edit func(Node) Node) {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
func (n *SendStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Chan != nil {
|
||||
n.Chan = edit(n.Chan).(Node)
|
||||
}
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SliceExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SliceExpr) copy() Node {
|
||||
@@ -1089,6 +1412,21 @@ func (n *SliceExpr) editChildren(edit func(Node) Node) {
|
||||
n.Max = edit(n.Max).(Node)
|
||||
}
|
||||
}
|
||||
func (n *SliceExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Low != nil {
|
||||
n.Low = edit(n.Low).(Node)
|
||||
}
|
||||
if n.High != nil {
|
||||
n.High = edit(n.High).(Node)
|
||||
}
|
||||
if n.Max != nil {
|
||||
n.Max = edit(n.Max).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SliceHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SliceHeaderExpr) copy() Node {
|
||||
@@ -1123,6 +1461,18 @@ func (n *SliceHeaderExpr) editChildren(edit func(Node) Node) {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
func (n *SliceHeaderExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Ptr != nil {
|
||||
n.Ptr = edit(n.Ptr).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
if n.Cap != nil {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StarExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StarExpr) copy() Node {
|
||||
@@ -1145,6 +1495,12 @@ func (n *StarExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *StarExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StringHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StringHeaderExpr) copy() Node {
|
||||
@@ -1173,6 +1529,15 @@ func (n *StringHeaderExpr) editChildren(edit func(Node) Node) {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
}
|
||||
func (n *StringHeaderExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Ptr != nil {
|
||||
n.Ptr = edit(n.Ptr).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StructKeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StructKeyExpr) copy() Node {
|
||||
@@ -1195,6 +1560,12 @@ func (n *StructKeyExpr) editChildren(edit func(Node) Node) {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
func (n *StructKeyExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SwitchStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SwitchStmt) copy() Node {
|
||||
@@ -1227,6 +1598,14 @@ func (n *SwitchStmt) editChildren(edit func(Node) Node) {
|
||||
editCaseClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
func (n *SwitchStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Tag != nil {
|
||||
n.Tag = edit(n.Tag).(Node)
|
||||
}
|
||||
editCaseClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
|
||||
func (n *TailCallStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *TailCallStmt) copy() Node {
|
||||
@@ -1249,6 +1628,12 @@ func (n *TailCallStmt) editChildren(edit func(Node) Node) {
|
||||
n.Call = edit(n.Call).(*CallExpr)
|
||||
}
|
||||
}
|
||||
func (n *TailCallStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Call != nil {
|
||||
n.Call = edit(n.Call).(*CallExpr)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *TypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *TypeAssertExpr) copy() Node {
|
||||
@@ -1271,6 +1656,15 @@ func (n *TypeAssertExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *TypeAssertExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.ITab != nil {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *TypeSwitchGuard) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *TypeSwitchGuard) copy() Node {
|
||||
@@ -1294,6 +1688,14 @@ func (n *TypeSwitchGuard) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *TypeSwitchGuard) editChildrenWithHidden(edit func(Node) Node) {
|
||||
if n.Tag != nil {
|
||||
n.Tag = edit(n.Tag).(*Ident)
|
||||
}
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *UnaryExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *UnaryExpr) copy() Node {
|
||||
@@ -1316,6 +1718,12 @@ func (n *UnaryExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *UnaryExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *typeNode) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *typeNode) copy() Node {
|
||||
@@ -1327,6 +1735,8 @@ func (n *typeNode) doChildren(do func(Node) bool) bool {
|
||||
}
|
||||
func (n *typeNode) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
func (n *typeNode) editChildrenWithHidden(edit func(Node) Node) {
|
||||
}
|
||||
|
||||
func copyCaseClauses(list []*CaseClause) []*CaseClause {
|
||||
if list == nil {
|
||||
|
||||
@@ -184,3 +184,15 @@ func EditChildren(n Node, edit func(Node) Node) {
|
||||
}
|
||||
n.editChildren(edit)
|
||||
}
|
||||
|
||||
// EditChildrenWithHidden is like EditChildren, but also edits
|
||||
// Node-typed fields tagged with `mknode:"-"`.
|
||||
//
|
||||
// TODO(mdempsky): Remove the `mknode:"-"` tags so this function can
|
||||
// go away.
|
||||
func EditChildrenWithHidden(n Node, edit func(Node) Node) {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
n.editChildrenWithHidden(edit)
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ func (l *linker) relocObj(pr *pkgReader, idx pkgbits.Index) pkgbits.Index {
|
||||
l.exportBody(obj, local)
|
||||
}
|
||||
|
||||
if obj.Op() == ir.OTYPE {
|
||||
if obj.Op() == ir.OTYPE && !obj.Alias() {
|
||||
if typ := obj.Type(); !typ.IsInterface() {
|
||||
for _, method := range typ.Methods().Slice() {
|
||||
l.exportBody(method.Nname.(*ir.Name), local)
|
||||
|
||||
@@ -231,6 +231,16 @@ func (r *reader) pos() src.XPos {
|
||||
return base.Ctxt.PosTable.XPos(r.pos0())
|
||||
}
|
||||
|
||||
// origPos reads a position from the bitstream, and returns both the
|
||||
// original raw position and an inlining-adjusted position.
|
||||
func (r *reader) origPos() (origPos, inlPos src.XPos) {
|
||||
r.suppressInlPos++
|
||||
origPos = r.pos()
|
||||
r.suppressInlPos--
|
||||
inlPos = r.inlPos(origPos)
|
||||
return
|
||||
}
|
||||
|
||||
func (r *reader) pos0() src.Pos {
|
||||
r.Sync(pkgbits.SyncPos)
|
||||
if !r.Bool() {
|
||||
@@ -517,13 +527,33 @@ func (r *reader) doTyp() *types.Type {
|
||||
}
|
||||
|
||||
func (r *reader) unionType() *types.Type {
|
||||
terms := make([]*types.Type, r.Len())
|
||||
tildes := make([]bool, len(terms))
|
||||
for i := range terms {
|
||||
tildes[i] = r.Bool()
|
||||
terms[i] = r.typ()
|
||||
// In the types1 universe, we only need to handle value types.
|
||||
// Impure interfaces (i.e., interfaces with non-trivial type sets
|
||||
// like "int | string") can only appear as type parameter bounds,
|
||||
// and this is enforced by the types2 type checker.
|
||||
//
|
||||
// However, type unions can still appear in pure interfaces if the
|
||||
// type union is equivalent to "any". E.g., typeparam/issue52124.go
|
||||
// declares variables with the type "interface { any | int }".
|
||||
//
|
||||
// To avoid needing to represent type unions in types1 (since we
|
||||
// don't have any uses for that today anyway), we simply fold them
|
||||
// to "any". As a consistency check, we still read the union terms
|
||||
// to make sure this substitution is safe.
|
||||
|
||||
pure := false
|
||||
for i, n := 0, r.Len(); i < n; i++ {
|
||||
_ = r.Bool() // tilde
|
||||
term := r.typ()
|
||||
if term.IsEmptyInterface() {
|
||||
pure = true
|
||||
}
|
||||
}
|
||||
return types.NewUnion(terms, tildes)
|
||||
if !pure {
|
||||
base.Fatalf("impure type set used in value type")
|
||||
}
|
||||
|
||||
return types.Types[types.TINTER]
|
||||
}
|
||||
|
||||
func (r *reader) interfaceType() *types.Type {
|
||||
@@ -2097,12 +2127,12 @@ func (r *reader) expr() (res ir.Node) {
|
||||
return typecheck.Callee(r.obj())
|
||||
|
||||
case exprFuncInst:
|
||||
pos := r.pos()
|
||||
origPos, pos := r.origPos()
|
||||
wrapperFn, baseFn, dictPtr := r.funcInst(pos)
|
||||
if wrapperFn != nil {
|
||||
return wrapperFn
|
||||
}
|
||||
return r.curry(pos, false, baseFn, dictPtr, nil)
|
||||
return r.curry(origPos, false, baseFn, dictPtr, nil)
|
||||
|
||||
case exprConst:
|
||||
pos := r.pos()
|
||||
@@ -2132,7 +2162,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
|
||||
case exprMethodVal:
|
||||
recv := r.expr()
|
||||
pos := r.pos()
|
||||
origPos, pos := r.origPos()
|
||||
wrapperFn, baseFn, dictPtr := r.methodExpr()
|
||||
|
||||
// For simple wrapperFn values, the existing machinery for creating
|
||||
@@ -2164,7 +2194,18 @@ func (r *reader) expr() (res ir.Node) {
|
||||
}
|
||||
|
||||
n := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, recv, wrapperFn.Sel)).(*ir.SelectorExpr)
|
||||
assert(n.Selection == wrapperFn.Selection)
|
||||
|
||||
// As a consistency check here, we make sure "n" selected the
|
||||
// same method (represented by a types.Field) that wrapperFn
|
||||
// selected. However, for anonymous receiver types, there can be
|
||||
// multiple such types.Field instances (#58563). So we may need
|
||||
// to fallback to making sure Sym and Type (including the
|
||||
// receiver parameter's type) match.
|
||||
if n.Selection != wrapperFn.Selection {
|
||||
assert(n.Selection.Sym == wrapperFn.Selection.Sym)
|
||||
assert(types.Identical(n.Selection.Type, wrapperFn.Selection.Type))
|
||||
assert(types.Identical(n.Selection.Type.Recv().Type, wrapperFn.Selection.Type.Recv().Type))
|
||||
}
|
||||
|
||||
wrapper := methodValueWrapper{
|
||||
rcvr: n.X.Type(),
|
||||
@@ -2181,7 +2222,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
|
||||
// For more complicated method expressions, we construct a
|
||||
// function literal wrapper.
|
||||
return r.curry(pos, true, baseFn, recv, dictPtr)
|
||||
return r.curry(origPos, true, baseFn, recv, dictPtr)
|
||||
|
||||
case exprMethodExpr:
|
||||
recv := r.typ()
|
||||
@@ -2197,7 +2238,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
addr = true
|
||||
}
|
||||
|
||||
pos := r.pos()
|
||||
origPos, pos := r.origPos()
|
||||
wrapperFn, baseFn, dictPtr := r.methodExpr()
|
||||
|
||||
// If we already have a wrapper and don't need to do anything with
|
||||
@@ -2220,7 +2261,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, ir.TypeNode(recv), method.Sel)).(*ir.SelectorExpr)
|
||||
}
|
||||
|
||||
return r.methodExprWrap(pos, recv, implicits, deref, addr, baseFn, dictPtr)
|
||||
return r.methodExprWrap(origPos, recv, implicits, deref, addr, baseFn, dictPtr)
|
||||
|
||||
case exprIndex:
|
||||
x := r.expr()
|
||||
@@ -2550,7 +2591,7 @@ func (pr *pkgReader) objDictName(idx pkgbits.Index, implicits, explicits []*type
|
||||
// If nilCheck is true and arg0 is an interface value, then it's
|
||||
// checked to be non-nil as an initial step at the point of evaluating
|
||||
// the function literal itself.
|
||||
func (r *reader) curry(pos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node {
|
||||
func (r *reader) curry(origPos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node {
|
||||
var captured ir.Nodes
|
||||
captured.Append(fun, arg0)
|
||||
if arg1 != nil {
|
||||
@@ -2574,13 +2615,13 @@ func (r *reader) curry(pos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.
|
||||
r.syntheticTailCall(pos, fun, args)
|
||||
}
|
||||
|
||||
return r.syntheticClosure(pos, typ, ifaceHack, captured, addBody)
|
||||
return r.syntheticClosure(origPos, typ, ifaceHack, captured, addBody)
|
||||
}
|
||||
|
||||
// methodExprWrap returns a function literal that changes method's
|
||||
// first parameter's type to recv, and uses implicits/deref/addr to
|
||||
// select the appropriate receiver parameter to pass to method.
|
||||
func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node {
|
||||
func (r *reader) methodExprWrap(origPos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node {
|
||||
var captured ir.Nodes
|
||||
captured.Append(method)
|
||||
|
||||
@@ -2631,12 +2672,13 @@ func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int,
|
||||
r.syntheticTailCall(pos, fn, args)
|
||||
}
|
||||
|
||||
return r.syntheticClosure(pos, typ, false, captured, addBody)
|
||||
return r.syntheticClosure(origPos, typ, false, captured, addBody)
|
||||
}
|
||||
|
||||
// syntheticClosure constructs a synthetic function literal for
|
||||
// currying dictionary arguments. pos is the position used for the
|
||||
// closure. typ is the function literal's signature type.
|
||||
// currying dictionary arguments. origPos is the position used for the
|
||||
// closure, which must be a non-inlined position. typ is the function
|
||||
// literal's signature type.
|
||||
//
|
||||
// captures is a list of expressions that need to be evaluated at the
|
||||
// point of function literal evaluation and captured by the function
|
||||
@@ -2647,7 +2689,7 @@ func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int,
|
||||
// list of captured values passed back has the captured variables for
|
||||
// use within the function literal, corresponding to the expressions
|
||||
// in captures.
|
||||
func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node {
|
||||
func (r *reader) syntheticClosure(origPos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node {
|
||||
// isSafe reports whether n is an expression that we can safely
|
||||
// defer to evaluating inside the closure instead, to avoid storing
|
||||
// them into the closure.
|
||||
@@ -2664,9 +2706,15 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool,
|
||||
return false
|
||||
}
|
||||
|
||||
fn := ir.NewClosureFunc(pos, r.curfn != nil)
|
||||
// The ODCLFUNC and its body need to use the original position, but
|
||||
// the OCLOSURE node and any Init statements should use the inlined
|
||||
// position instead. See also the explanation in reader.funcLit.
|
||||
inlPos := r.inlPos(origPos)
|
||||
|
||||
fn := ir.NewClosureFunc(origPos, r.curfn != nil)
|
||||
fn.SetWrapper(true)
|
||||
clo := fn.OClosure
|
||||
clo.SetPos(inlPos)
|
||||
ir.NameClosure(clo, r.curfn)
|
||||
|
||||
setType(fn.Nname, typ)
|
||||
@@ -2679,13 +2727,13 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool,
|
||||
continue // skip capture; can reference directly
|
||||
}
|
||||
|
||||
tmp := r.tempCopy(pos, n, &init)
|
||||
ir.NewClosureVar(pos, fn, tmp)
|
||||
tmp := r.tempCopy(inlPos, n, &init)
|
||||
ir.NewClosureVar(origPos, fn, tmp)
|
||||
|
||||
// We need to nil check interface receivers at the point of method
|
||||
// value evaluation, ugh.
|
||||
if ifaceHack && i == 1 && n.Type().IsInterface() {
|
||||
check := ir.NewUnaryExpr(pos, ir.OCHECKNIL, ir.NewUnaryExpr(pos, ir.OITAB, tmp))
|
||||
check := ir.NewUnaryExpr(inlPos, ir.OCHECKNIL, ir.NewUnaryExpr(inlPos, ir.OITAB, tmp))
|
||||
init.Append(typecheck.Stmt(check))
|
||||
}
|
||||
}
|
||||
@@ -2703,7 +2751,7 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool,
|
||||
}
|
||||
assert(next == len(r.closureVars))
|
||||
|
||||
addBody(pos, r, captured)
|
||||
addBody(origPos, r, captured)
|
||||
}}
|
||||
bodyReader[fn] = pri
|
||||
pri.funcBody(fn)
|
||||
|
||||
@@ -158,7 +158,11 @@ func readBodies(target *ir.Package, duringInlining bool) {
|
||||
// Instantiated generic function: add to Decls for typechecking
|
||||
// and compilation.
|
||||
if fn.OClosure == nil && len(pri.dict.targs) != 0 {
|
||||
if duringInlining {
|
||||
// cmd/link does not support a type symbol referencing a method symbol
|
||||
// across DSO boundary, so force re-compiling methods on a generic type
|
||||
// even it was seen from imported package in linkshared mode, see #58966.
|
||||
canSkipNonGenericMethod := !(base.Ctxt.Flag_linkshared && ir.IsMethod(fn))
|
||||
if duringInlining && canSkipNonGenericMethod {
|
||||
inlDecls = append(inlDecls, fn)
|
||||
} else {
|
||||
target.Decls = append(target.Decls, fn)
|
||||
|
||||
@@ -140,9 +140,30 @@ func New(profileFile string) *Profile {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(profile.Sample) == 0 {
|
||||
// We accept empty profiles, but there is nothing to do.
|
||||
return nil
|
||||
}
|
||||
|
||||
valueIndex := -1
|
||||
for i, s := range profile.SampleType {
|
||||
// Samples count is the raw data collected, and CPU nanoseconds is just
|
||||
// a scaled version of it, so either one we can find is fine.
|
||||
if (s.Type == "samples" && s.Unit == "count") ||
|
||||
(s.Type == "cpu" && s.Unit == "nanoseconds") {
|
||||
valueIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if valueIndex == -1 {
|
||||
log.Fatal("failed to find CPU samples count or CPU nanoseconds value-types in profile.")
|
||||
return nil
|
||||
}
|
||||
|
||||
g := newGraph(profile, &Options{
|
||||
CallTree: false,
|
||||
SampleValue: func(v []int64) int64 { return v[1] },
|
||||
SampleValue: func(v []int64) int64 { return v[valueIndex] },
|
||||
})
|
||||
|
||||
p := &Profile{
|
||||
|
||||
@@ -1757,13 +1757,13 @@
|
||||
x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem))
|
||||
&& x0.Uses == 1
|
||||
&& clobber(x0)
|
||||
=> (MOVWstore [i-1] {s} p (ROLWconst <w.Type> [8] w) mem)
|
||||
=> (MOVWstore [i-1] {s} p (ROLWconst <typ.UInt16> [8] w) mem)
|
||||
(MOVBstore [i] {s} p1 w
|
||||
x0:(MOVBstore [i] {s} p0 (SHRWconst [8] w) mem))
|
||||
&& x0.Uses == 1
|
||||
&& sequentialAddresses(p0, p1, 1)
|
||||
&& clobber(x0)
|
||||
=> (MOVWstore [i] {s} p0 (ROLWconst <w.Type> [8] w) mem)
|
||||
=> (MOVWstore [i] {s} p0 (ROLWconst <typ.UInt16> [8] w) mem)
|
||||
|
||||
// Combine stores + shifts into bswap and larger (unaligned) stores
|
||||
(MOVBstore [i] {s} p w
|
||||
@@ -1774,7 +1774,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVLstore [i-3] {s} p (BSWAPL <w.Type> w) mem)
|
||||
=> (MOVLstore [i-3] {s} p (BSWAPL <typ.UInt32> w) mem)
|
||||
(MOVBstore [i] {s} p3 w
|
||||
x2:(MOVBstore [i] {s} p2 (SHRLconst [8] w)
|
||||
x1:(MOVBstore [i] {s} p1 (SHRLconst [16] w)
|
||||
@@ -1786,7 +1786,7 @@
|
||||
&& sequentialAddresses(p1, p2, 1)
|
||||
&& sequentialAddresses(p2, p3, 1)
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVLstore [i] {s} p0 (BSWAPL <w.Type> w) mem)
|
||||
=> (MOVLstore [i] {s} p0 (BSWAPL <typ.UInt32> w) mem)
|
||||
|
||||
(MOVBstore [i] {s} p w
|
||||
x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w)
|
||||
@@ -1804,7 +1804,7 @@
|
||||
&& x5.Uses == 1
|
||||
&& x6.Uses == 1
|
||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
=> (MOVQstore [i-7] {s} p (BSWAPQ <w.Type> w) mem)
|
||||
=> (MOVQstore [i-7] {s} p (BSWAPQ <typ.UInt64> w) mem)
|
||||
(MOVBstore [i] {s} p7 w
|
||||
x6:(MOVBstore [i] {s} p6 (SHRQconst [8] w)
|
||||
x5:(MOVBstore [i] {s} p5 (SHRQconst [16] w)
|
||||
@@ -1828,7 +1828,7 @@
|
||||
&& sequentialAddresses(p5, p6, 1)
|
||||
&& sequentialAddresses(p6, p7, 1)
|
||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
=> (MOVQstore [i] {s} p0 (BSWAPQ <w.Type> w) mem)
|
||||
=> (MOVQstore [i] {s} p0 (BSWAPQ <typ.UInt64> w) mem)
|
||||
|
||||
// Combine constant stores into larger (unaligned) stores.
|
||||
(MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem))
|
||||
@@ -2180,10 +2180,10 @@
|
||||
(BSWAP(Q|L) (BSWAP(Q|L) p)) => p
|
||||
|
||||
// CPUID feature: MOVBE.
|
||||
(MOV(Q|L)store [i] {s} p x:(BSWAP(Q|L) w) mem) && x.Uses == 1 && buildcfg.GOAMD64 >= 3 => (MOVBE(Q|L)store [i] {s} p w mem)
|
||||
(BSWAP(Q|L) x:(MOV(Q|L)load [i] {s} p mem)) && x.Uses == 1 && buildcfg.GOAMD64 >= 3 => (MOVBE(Q|L)load [i] {s} p mem)
|
||||
(BSWAP(Q|L) (MOVBE(Q|L)load [i] {s} p m)) => (MOV(Q|L)load [i] {s} p m)
|
||||
(MOVBE(Q|L)store [i] {s} p (BSWAP(Q|L) x) m) => (MOV(Q|L)store [i] {s} p x m)
|
||||
(MOV(Q|L)store [i] {s} p x:(BSWAP(Q|L) w) mem) && x.Uses == 1 && buildcfg.GOAMD64 >= 3 => (MOVBE(Q|L)store [i] {s} p w mem)
|
||||
(MOVBE(Q|L)store [i] {s} p x:(BSWAP(Q|L) w) mem) && x.Uses == 1 => (MOV(Q|L)store [i] {s} p w mem)
|
||||
(BSWAP(Q|L) x:(MOV(Q|L)load [i] {s} p mem)) && x.Uses == 1 && buildcfg.GOAMD64 >= 3 => @x.Block (MOVBE(Q|L)load [i] {s} p mem)
|
||||
(BSWAP(Q|L) x:(MOVBE(Q|L)load [i] {s} p mem)) && x.Uses == 1 => @x.Block (MOV(Q|L)load [i] {s} p mem)
|
||||
(MOVWstore [i] {s} p x:(ROLWconst [8] w) mem) && x.Uses == 1 && buildcfg.GOAMD64 >= 3 => (MOVBEWstore [i] {s} p w mem)
|
||||
(MOVBEWstore [i] {s} p x:(ROLWconst [8] w) mem) && x.Uses == 1 => (MOVWstore [i] {s} p w mem)
|
||||
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// split 3 operand LEA.
|
||||
// Note: Don't split pointer computations in order to avoid invalid pointers.
|
||||
(LEA(Q|L|W)1 <t> [c] {s} x y) && isPtr(x.Type) && c != 0 && s == nil => (ADD(Q|L|L) x (ADD(Q|L|L)const <y.Type> [c] y))
|
||||
(LEA(Q|L|W)1 <t> [c] {s} x y) && !isPtr(x.Type) && c != 0 && s == nil => (ADD(Q|L|L) y (ADD(Q|L|L)const <x.Type> [c] x))
|
||||
(LEA(Q|L|W)2 <t> [c] {s} x y) && !isPtr(t) && c != 0 && s == nil => (ADD(Q|L|L)const [c] (LEA(Q|L|W)2 <x.Type> x y))
|
||||
(LEA(Q|L|W)4 <t> [c] {s} x y) && !isPtr(t) && c != 0 && s == nil => (ADD(Q|L|L)const [c] (LEA(Q|L|W)4 <x.Type> x y))
|
||||
(LEA(Q|L|W)8 <t> [c] {s} x y) && !isPtr(t) && c != 0 && s == nil => (ADD(Q|L|L)const [c] (LEA(Q|L|W)8 <x.Type> x y))
|
||||
|
||||
// Prefer SARX/SHLX/SHRX instruction because it has less register restriction on the shift input.
|
||||
(SAR(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SARX(Q|L) x y)
|
||||
(SHL(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SHLX(Q|L) x y)
|
||||
|
||||
@@ -837,25 +837,35 @@
|
||||
(MOVDaddr [int32(off1)+off2] {sym} ptr)
|
||||
|
||||
// fold address into load/store
|
||||
(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBUload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHUload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWUload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDload [off1+int32(off2)] {sym} ptr mem)
|
||||
(LDP [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(LDP [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(LDP [off1+int32(off2)] {sym} ptr mem)
|
||||
(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVSload [off1+int32(off2)] {sym} ptr mem)
|
||||
(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVDload [off1+int32(off2)] {sym} ptr mem)
|
||||
|
||||
// register indexed load
|
||||
@@ -920,29 +930,41 @@
|
||||
(FMOVDloadidx8 ptr (MOVDconst [c]) mem) && is32Bit(c<<3) => (FMOVDload ptr [int32(c)<<3] mem)
|
||||
(FMOVSloadidx4 ptr (MOVDconst [c]) mem) && is32Bit(c<<2) => (FMOVSload ptr [int32(c)<<2] mem)
|
||||
|
||||
(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(STP [off1] {sym} (ADDconst [off2] ptr) val1 val2 mem) && is32Bit(int64(off1)+off2) =>
|
||||
(STP [off1] {sym} (ADDconst [off2] ptr) val1 val2 mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(STP [off1+int32(off2)] {sym} ptr val1 val2 mem)
|
||||
(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVSstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVDstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVQstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVQstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVQstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
|
||||
// register indexed store
|
||||
@@ -991,71 +1013,93 @@
|
||||
(FMOVSstoreidx4 ptr (MOVDconst [c]) val mem) && is32Bit(c<<2) => (FMOVSstore [int32(c)<<2] ptr val mem)
|
||||
|
||||
(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(LDP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(LDP [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
|
||||
(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(STP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val1 val2 mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(STP [off1+off2] {mergeSym(sym1,sym2)} ptr val1 val2 mem)
|
||||
(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVQstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVQstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
|
||||
// store zero
|
||||
@@ -2777,7 +2821,7 @@
|
||||
&& x5.Uses == 1
|
||||
&& x6.Uses == 1
|
||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
=> (MOVDstore [i-7] {s} ptr (REV <w.Type> w) mem)
|
||||
=> (MOVDstore [i-7] {s} ptr (REV <typ.UInt64> w) mem)
|
||||
(MOVBstore [7] {s} p w
|
||||
x0:(MOVBstore [6] {s} p (SRLconst [8] w)
|
||||
x1:(MOVBstore [5] {s} p (SRLconst [16] w)
|
||||
@@ -2797,7 +2841,7 @@
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& isSamePtr(p1, p)
|
||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
=> (MOVDstoreidx ptr0 idx0 (REV <w.Type> w) mem)
|
||||
=> (MOVDstoreidx ptr0 idx0 (REV <typ.UInt64> w) mem)
|
||||
(MOVBstore [i] {s} ptr w
|
||||
x0:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 24)] w)
|
||||
x1:(MOVBstore [i-2] {s} ptr (UBFX [armBFAuxInt(16, 16)] w)
|
||||
@@ -2806,7 +2850,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <w.Type> w) mem)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [3] {s} p w
|
||||
x0:(MOVBstore [2] {s} p (UBFX [armBFAuxInt(8, 24)] w)
|
||||
x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (UBFX [armBFAuxInt(16, 16)] w)
|
||||
@@ -2818,7 +2862,7 @@
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& isSamePtr(p1, p)
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <w.Type> w) mem)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstoreidx ptr (ADDconst [3] idx) w
|
||||
x0:(MOVBstoreidx ptr (ADDconst [2] idx) (UBFX [armBFAuxInt(8, 24)] w)
|
||||
x1:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(16, 16)] w)
|
||||
@@ -2827,7 +2871,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstoreidx ptr idx (REVW <w.Type> w) mem)
|
||||
=> (MOVWstoreidx ptr idx (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstoreidx ptr idx w
|
||||
x0:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(8, 24)] w)
|
||||
x1:(MOVBstoreidx ptr (ADDconst [2] idx) (UBFX [armBFAuxInt(16, 16)] w)
|
||||
@@ -2845,7 +2889,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <w.Type> w) mem)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [3] {s} p w
|
||||
x0:(MOVBstore [2] {s} p (SRLconst [8] (MOVDreg w))
|
||||
x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (SRLconst [16] (MOVDreg w))
|
||||
@@ -2857,7 +2901,7 @@
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& isSamePtr(p1, p)
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <w.Type> w) mem)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [i] {s} ptr w
|
||||
x0:(MOVBstore [i-1] {s} ptr (SRLconst [8] w)
|
||||
x1:(MOVBstore [i-2] {s} ptr (SRLconst [16] w)
|
||||
@@ -2866,7 +2910,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <w.Type> w) mem)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [3] {s} p w
|
||||
x0:(MOVBstore [2] {s} p (SRLconst [8] w)
|
||||
x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (SRLconst [16] w)
|
||||
@@ -2878,31 +2922,31 @@
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& isSamePtr(p1, p)
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <w.Type> w) mem)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (SRLconst [8] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (SRLconst [8] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& s == nil
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 8)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (UBFX [armBFAuxInt(8, 8)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& s == nil
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstoreidx ptr (ADDconst [1] idx) w x:(MOVBstoreidx ptr idx (UBFX [armBFAuxInt(8, 8)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr idx (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr idx (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstoreidx ptr idx w x:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(8, 8)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
@@ -2910,23 +2954,23 @@
|
||||
(MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (SRLconst [8] (MOVDreg w)) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (SRLconst [8] (MOVDreg w)) mem))
|
||||
&& x.Uses == 1
|
||||
&& s == nil
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 24)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (UBFX [armBFAuxInt(8, 24)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& s == nil
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <typ.UInt16> w) mem)
|
||||
|
||||
// FP simplification
|
||||
(FNEGS (FMULS x y)) => (FNMULS x y)
|
||||
|
||||
@@ -856,9 +856,6 @@ func prove(f *Func) {
|
||||
case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
|
||||
ft.update(b, v, v.Args[1], unsigned, lt|eq)
|
||||
ft.update(b, v, v.Args[0], unsigned, lt|eq)
|
||||
case OpOr64, OpOr32, OpOr16, OpOr8:
|
||||
ft.update(b, v, v.Args[1], unsigned, gt|eq)
|
||||
ft.update(b, v, v.Args[0], unsigned, gt|eq)
|
||||
case OpPhi:
|
||||
// Determine the min and max value of OpPhi composed entirely of integer constants.
|
||||
//
|
||||
|
||||
@@ -3533,6 +3533,8 @@ func rewriteValueAMD64_OpAMD64BSFQ(v *Value) bool {
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64BSWAPL(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (BSWAPL (BSWAPL p))
|
||||
// result: p
|
||||
for {
|
||||
@@ -3545,7 +3547,7 @@ func rewriteValueAMD64_OpAMD64BSWAPL(v *Value) bool {
|
||||
}
|
||||
// match: (BSWAPL x:(MOVLload [i] {s} p mem))
|
||||
// cond: x.Uses == 1 && buildcfg.GOAMD64 >= 3
|
||||
// result: (MOVBELload [i] {s} p mem)
|
||||
// result: @x.Block (MOVBELload [i] {s} p mem)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpAMD64MOVLload {
|
||||
@@ -3558,32 +3560,43 @@ func rewriteValueAMD64_OpAMD64BSWAPL(v *Value) bool {
|
||||
if !(x.Uses == 1 && buildcfg.GOAMD64 >= 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVBELload)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v.AddArg2(p, mem)
|
||||
b = x.Block
|
||||
v0 := b.NewValue0(x.Pos, OpAMD64MOVBELload, typ.UInt32)
|
||||
v.copyOf(v0)
|
||||
v0.AuxInt = int32ToAuxInt(i)
|
||||
v0.Aux = symToAux(s)
|
||||
v0.AddArg2(p, mem)
|
||||
return true
|
||||
}
|
||||
// match: (BSWAPL (MOVBELload [i] {s} p m))
|
||||
// result: (MOVLload [i] {s} p m)
|
||||
// match: (BSWAPL x:(MOVBELload [i] {s} p mem))
|
||||
// cond: x.Uses == 1
|
||||
// result: @x.Block (MOVLload [i] {s} p mem)
|
||||
for {
|
||||
if v_0.Op != OpAMD64MOVBELload {
|
||||
x := v_0
|
||||
if x.Op != OpAMD64MOVBELload {
|
||||
break
|
||||
}
|
||||
i := auxIntToInt32(v_0.AuxInt)
|
||||
s := auxToSym(v_0.Aux)
|
||||
m := v_0.Args[1]
|
||||
p := v_0.Args[0]
|
||||
v.reset(OpAMD64MOVLload)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v.AddArg2(p, m)
|
||||
i := auxIntToInt32(x.AuxInt)
|
||||
s := auxToSym(x.Aux)
|
||||
mem := x.Args[1]
|
||||
p := x.Args[0]
|
||||
if !(x.Uses == 1) {
|
||||
break
|
||||
}
|
||||
b = x.Block
|
||||
v0 := b.NewValue0(x.Pos, OpAMD64MOVLload, typ.UInt32)
|
||||
v.copyOf(v0)
|
||||
v0.AuxInt = int32ToAuxInt(i)
|
||||
v0.Aux = symToAux(s)
|
||||
v0.AddArg2(p, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64BSWAPQ(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (BSWAPQ (BSWAPQ p))
|
||||
// result: p
|
||||
for {
|
||||
@@ -3596,7 +3609,7 @@ func rewriteValueAMD64_OpAMD64BSWAPQ(v *Value) bool {
|
||||
}
|
||||
// match: (BSWAPQ x:(MOVQload [i] {s} p mem))
|
||||
// cond: x.Uses == 1 && buildcfg.GOAMD64 >= 3
|
||||
// result: (MOVBEQload [i] {s} p mem)
|
||||
// result: @x.Block (MOVBEQload [i] {s} p mem)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpAMD64MOVQload {
|
||||
@@ -3609,26 +3622,35 @@ func rewriteValueAMD64_OpAMD64BSWAPQ(v *Value) bool {
|
||||
if !(x.Uses == 1 && buildcfg.GOAMD64 >= 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVBEQload)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v.AddArg2(p, mem)
|
||||
b = x.Block
|
||||
v0 := b.NewValue0(x.Pos, OpAMD64MOVBEQload, typ.UInt64)
|
||||
v.copyOf(v0)
|
||||
v0.AuxInt = int32ToAuxInt(i)
|
||||
v0.Aux = symToAux(s)
|
||||
v0.AddArg2(p, mem)
|
||||
return true
|
||||
}
|
||||
// match: (BSWAPQ (MOVBEQload [i] {s} p m))
|
||||
// result: (MOVQload [i] {s} p m)
|
||||
// match: (BSWAPQ x:(MOVBEQload [i] {s} p mem))
|
||||
// cond: x.Uses == 1
|
||||
// result: @x.Block (MOVQload [i] {s} p mem)
|
||||
for {
|
||||
if v_0.Op != OpAMD64MOVBEQload {
|
||||
x := v_0
|
||||
if x.Op != OpAMD64MOVBEQload {
|
||||
break
|
||||
}
|
||||
i := auxIntToInt32(v_0.AuxInt)
|
||||
s := auxToSym(v_0.Aux)
|
||||
m := v_0.Args[1]
|
||||
p := v_0.Args[0]
|
||||
v.reset(OpAMD64MOVQload)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v.AddArg2(p, m)
|
||||
i := auxIntToInt32(x.AuxInt)
|
||||
s := auxToSym(x.Aux)
|
||||
mem := x.Args[1]
|
||||
p := x.Args[0]
|
||||
if !(x.Uses == 1) {
|
||||
break
|
||||
}
|
||||
b = x.Block
|
||||
v0 := b.NewValue0(x.Pos, OpAMD64MOVQload, typ.UInt64)
|
||||
v.copyOf(v0)
|
||||
v0.AuxInt = int32ToAuxInt(i)
|
||||
v0.Aux = symToAux(s)
|
||||
v0.AddArg2(p, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -9398,21 +9420,26 @@ func rewriteValueAMD64_OpAMD64MOVBELstore(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVBELstore [i] {s} p (BSWAPL x) m)
|
||||
// result: (MOVLstore [i] {s} p x m)
|
||||
// match: (MOVBELstore [i] {s} p x:(BSWAPL w) mem)
|
||||
// cond: x.Uses == 1
|
||||
// result: (MOVLstore [i] {s} p w mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
p := v_0
|
||||
if v_1.Op != OpAMD64BSWAPL {
|
||||
x := v_1
|
||||
if x.Op != OpAMD64BSWAPL {
|
||||
break
|
||||
}
|
||||
w := x.Args[0]
|
||||
mem := v_2
|
||||
if !(x.Uses == 1) {
|
||||
break
|
||||
}
|
||||
x := v_1.Args[0]
|
||||
m := v_2
|
||||
v.reset(OpAMD64MOVLstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v.AddArg3(p, x, m)
|
||||
v.AddArg3(p, w, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -9421,21 +9448,26 @@ func rewriteValueAMD64_OpAMD64MOVBEQstore(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVBEQstore [i] {s} p (BSWAPQ x) m)
|
||||
// result: (MOVQstore [i] {s} p x m)
|
||||
// match: (MOVBEQstore [i] {s} p x:(BSWAPQ w) mem)
|
||||
// cond: x.Uses == 1
|
||||
// result: (MOVQstore [i] {s} p w mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
p := v_0
|
||||
if v_1.Op != OpAMD64BSWAPQ {
|
||||
x := v_1
|
||||
if x.Op != OpAMD64BSWAPQ {
|
||||
break
|
||||
}
|
||||
w := x.Args[0]
|
||||
mem := v_2
|
||||
if !(x.Uses == 1) {
|
||||
break
|
||||
}
|
||||
x := v_1.Args[0]
|
||||
m := v_2
|
||||
v.reset(OpAMD64MOVQstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v.AddArg3(p, x, m)
|
||||
v.AddArg3(p, w, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -10244,7 +10276,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p w x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem))
|
||||
// cond: x0.Uses == 1 && clobber(x0)
|
||||
// result: (MOVWstore [i-1] {s} p (ROLWconst <w.Type> [8] w) mem)
|
||||
// result: (MOVWstore [i-1] {s} p (ROLWconst <typ.UInt16> [8] w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10265,7 +10297,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVWstore)
|
||||
v.AuxInt = int32ToAuxInt(i - 1)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, typ.UInt16)
|
||||
v0.AuxInt = int8ToAuxInt(8)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p, v0, mem)
|
||||
@@ -10273,7 +10305,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p1 w x0:(MOVBstore [i] {s} p0 (SHRWconst [8] w) mem))
|
||||
// cond: x0.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x0)
|
||||
// result: (MOVWstore [i] {s} p0 (ROLWconst <w.Type> [8] w) mem)
|
||||
// result: (MOVWstore [i] {s} p0 (ROLWconst <typ.UInt16> [8] w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10292,7 +10324,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVWstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, typ.UInt16)
|
||||
v0.AuxInt = int8ToAuxInt(8)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p0, v0, mem)
|
||||
@@ -10300,7 +10332,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p w x2:(MOVBstore [i-1] {s} p (SHRLconst [8] w) x1:(MOVBstore [i-2] {s} p (SHRLconst [16] w) x0:(MOVBstore [i-3] {s} p (SHRLconst [24] w) mem))))
|
||||
// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2)
|
||||
// result: (MOVLstore [i-3] {s} p (BSWAPL <w.Type> w) mem)
|
||||
// result: (MOVLstore [i-3] {s} p (BSWAPL <typ.UInt32> w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10345,14 +10377,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVLstore)
|
||||
v.AuxInt = int32ToAuxInt(i - 3)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, typ.UInt32)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p3 w x2:(MOVBstore [i] {s} p2 (SHRLconst [8] w) x1:(MOVBstore [i] {s} p1 (SHRLconst [16] w) x0:(MOVBstore [i] {s} p0 (SHRLconst [24] w) mem))))
|
||||
// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && clobber(x0, x1, x2)
|
||||
// result: (MOVLstore [i] {s} p0 (BSWAPL <w.Type> w) mem)
|
||||
// result: (MOVLstore [i] {s} p0 (BSWAPL <typ.UInt32> w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10391,14 +10423,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVLstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, typ.UInt32)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p0, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p w x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w) x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w) x4:(MOVBstore [i-3] {s} p (SHRQconst [24] w) x3:(MOVBstore [i-4] {s} p (SHRQconst [32] w) x2:(MOVBstore [i-5] {s} p (SHRQconst [40] w) x1:(MOVBstore [i-6] {s} p (SHRQconst [48] w) x0:(MOVBstore [i-7] {s} p (SHRQconst [56] w) mem))))))))
|
||||
// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
// result: (MOVQstore [i-7] {s} p (BSWAPQ <w.Type> w) mem)
|
||||
// result: (MOVQstore [i-7] {s} p (BSWAPQ <typ.UInt64> w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10491,14 +10523,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVQstore)
|
||||
v.AuxInt = int32ToAuxInt(i - 7)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, typ.UInt64)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p7 w x6:(MOVBstore [i] {s} p6 (SHRQconst [8] w) x5:(MOVBstore [i] {s} p5 (SHRQconst [16] w) x4:(MOVBstore [i] {s} p4 (SHRQconst [24] w) x3:(MOVBstore [i] {s} p3 (SHRQconst [32] w) x2:(MOVBstore [i] {s} p2 (SHRQconst [40] w) x1:(MOVBstore [i] {s} p1 (SHRQconst [48] w) x0:(MOVBstore [i] {s} p0 (SHRQconst [56] w) mem))))))))
|
||||
// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && sequentialAddresses(p3, p4, 1) && sequentialAddresses(p4, p5, 1) && sequentialAddresses(p5, p6, 1) && sequentialAddresses(p6, p7, 1) && clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
// result: (MOVQstore [i] {s} p0 (BSWAPQ <w.Type> w) mem)
|
||||
// result: (MOVQstore [i] {s} p0 (BSWAPQ <typ.UInt64> w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10577,7 +10609,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVQstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, typ.UInt64)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p0, v0, mem)
|
||||
return true
|
||||
|
||||
@@ -7,30 +7,6 @@ import "internal/buildcfg"
|
||||
|
||||
func rewriteValueAMD64latelower(v *Value) bool {
|
||||
switch v.Op {
|
||||
case OpAMD64LEAL1:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAL1(v)
|
||||
case OpAMD64LEAL2:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAL2(v)
|
||||
case OpAMD64LEAL4:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAL4(v)
|
||||
case OpAMD64LEAL8:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAL8(v)
|
||||
case OpAMD64LEAQ1:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAQ1(v)
|
||||
case OpAMD64LEAQ2:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAQ2(v)
|
||||
case OpAMD64LEAQ4:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAQ4(v)
|
||||
case OpAMD64LEAQ8:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAQ8(v)
|
||||
case OpAMD64LEAW1:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAW1(v)
|
||||
case OpAMD64LEAW2:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAW2(v)
|
||||
case OpAMD64LEAW4:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAW4(v)
|
||||
case OpAMD64LEAW8:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAW8(v)
|
||||
case OpAMD64SARL:
|
||||
return rewriteValueAMD64latelower_OpAMD64SARL(v)
|
||||
case OpAMD64SARQ:
|
||||
@@ -46,375 +22,6 @@ func rewriteValueAMD64latelower(v *Value) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAL1(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAL1 <t> [c] {s} x y)
|
||||
// cond: isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDL x (ADDLconst <y.Type> [c] y))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, y.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LEAL1 <t> [c] {s} x y)
|
||||
// cond: !isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDL y (ADDLconst <x.Type> [c] x))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, x.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
v.AddArg2(y, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAL2(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAL2 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAL2 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAL2, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAL4(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAL4 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAL4 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAL4, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAL8(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAL8 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAL8 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAL8, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAQ1(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAQ1 <t> [c] {s} x y)
|
||||
// cond: isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDQ x (ADDQconst <y.Type> [c] y))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDQ)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, y.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LEAQ1 <t> [c] {s} x y)
|
||||
// cond: !isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDQ y (ADDQconst <x.Type> [c] x))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDQ)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, x.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
v.AddArg2(y, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAQ2(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAQ2 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDQconst [c] (LEAQ2 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDQconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAQ4(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAQ4 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDQconst [c] (LEAQ4 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDQconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAQ8(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAQ8 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDQconst [c] (LEAQ8 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDQconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAW1(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAW1 <t> [c] {s} x y)
|
||||
// cond: isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDL x (ADDLconst <y.Type> [c] y))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, y.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LEAW1 <t> [c] {s} x y)
|
||||
// cond: !isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDL y (ADDLconst <x.Type> [c] x))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, x.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
v.AddArg2(y, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAW2(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAW2 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAW2 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAW2, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAW4(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAW4 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAW4 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAW4, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAW8(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAW8 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAW8 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAW8, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64SARL(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3203,7 +3203,10 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
|
||||
n := n.(*ir.UnaryExpr)
|
||||
a := s.expr(n.X)
|
||||
if n.X.Type().IsSlice() {
|
||||
return s.newValue1(ssa.OpSlicePtr, n.Type(), a)
|
||||
if n.Bounded() {
|
||||
return s.newValue1(ssa.OpSlicePtr, n.Type(), a)
|
||||
}
|
||||
return s.newValue1(ssa.OpSlicePtrUnchecked, n.Type(), a)
|
||||
} else {
|
||||
return s.newValue1(ssa.OpStringPtr, n.Type(), a)
|
||||
}
|
||||
|
||||
@@ -615,6 +615,9 @@ func (s *Schedule) staticAssignInlinedCall(l *ir.Name, loff int64, call *ir.Inli
|
||||
// Build tree with args substituted for params and try it.
|
||||
args := make(map[*ir.Name]ir.Node)
|
||||
for i, v := range as2init.Lhs {
|
||||
if ir.IsBlank(v) {
|
||||
continue
|
||||
}
|
||||
args[v.(*ir.Name)] = as2init.Rhs[i]
|
||||
}
|
||||
r, ok := subst(as2body.Rhs[0], args)
|
||||
@@ -838,7 +841,7 @@ func subst(n ir.Node, m map[*ir.Name]ir.Node) (ir.Node, bool) {
|
||||
return x
|
||||
}
|
||||
x = ir.Copy(x)
|
||||
ir.EditChildren(x, edit)
|
||||
ir.EditChildrenWithHidden(x, edit)
|
||||
if x, ok := x.(*ir.ConvExpr); ok && x.X.Op() == ir.OLITERAL {
|
||||
// A conversion of variable or expression involving variables
|
||||
// may become a conversion of constant after inlining the parameters
|
||||
|
||||
@@ -7,6 +7,7 @@ package test
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"internal/profile"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"os"
|
||||
@@ -213,6 +214,73 @@ func TestPGOIntendedInliningShiftedLines(t *testing.T) {
|
||||
testPGOIntendedInlining(t, dir)
|
||||
}
|
||||
|
||||
// TestPGOSingleIndex tests that the sample index can not be 1 and compilation
|
||||
// will not fail. All it should care about is that the sample type is either
|
||||
// CPU nanoseconds or samples count, whichever it finds first.
|
||||
func TestPGOSingleIndex(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
originalIndex int
|
||||
}{{
|
||||
// The `testdata/pgo/inline/inline_hot.pprof` file is a standard CPU
|
||||
// profile as the runtime would generate. The 0 index contains the
|
||||
// value-type samples and value-unit count. The 1 index contains the
|
||||
// value-type cpu and value-unit nanoseconds. These tests ensure that
|
||||
// the compiler can work with profiles that only have a single index,
|
||||
// but are either samples count or CPU nanoseconds.
|
||||
originalIndex: 0,
|
||||
}, {
|
||||
originalIndex: 1,
|
||||
}} {
|
||||
t.Run(fmt.Sprintf("originalIndex=%d", tc.originalIndex), func(t *testing.T) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting wd: %v", err)
|
||||
}
|
||||
srcDir := filepath.Join(wd, "testdata/pgo/inline")
|
||||
|
||||
// Copy the module to a scratch location so we can add a go.mod.
|
||||
dir := t.TempDir()
|
||||
|
||||
originalPprofFile, err := os.Open(filepath.Join(srcDir, "inline_hot.pprof"))
|
||||
if err != nil {
|
||||
t.Fatalf("error opening inline_hot.pprof: %v", err)
|
||||
}
|
||||
defer originalPprofFile.Close()
|
||||
|
||||
p, err := profile.Parse(originalPprofFile)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing inline_hot.pprof: %v", err)
|
||||
}
|
||||
|
||||
// Move the samples count value-type to the 0 index.
|
||||
p.SampleType = []*profile.ValueType{p.SampleType[tc.originalIndex]}
|
||||
|
||||
// Ensure we only have a single set of sample values.
|
||||
for _, s := range p.Sample {
|
||||
s.Value = []int64{s.Value[tc.originalIndex]}
|
||||
}
|
||||
|
||||
modifiedPprofFile, err := os.Create(filepath.Join(dir, "inline_hot.pprof"))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating inline_hot.pprof: %v", err)
|
||||
}
|
||||
defer modifiedPprofFile.Close()
|
||||
|
||||
if err := p.Write(modifiedPprofFile); err != nil {
|
||||
t.Fatalf("error writing inline_hot.pprof: %v", err)
|
||||
}
|
||||
|
||||
for _, file := range []string{"inline_hot.go", "inline_hot_test.go"} {
|
||||
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
|
||||
t.Fatalf("error copying %s: %v", file, err)
|
||||
}
|
||||
}
|
||||
|
||||
testPGOIntendedInlining(t, dir)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func copyFile(dst, src string) error {
|
||||
s, err := os.Open(src)
|
||||
if err != nil {
|
||||
|
||||
@@ -34,10 +34,7 @@ func roundFloat(v constant.Value, sz int64) constant.Value {
|
||||
// truncate float literal fv to 32-bit or 64-bit precision
|
||||
// according to type; return truncated value.
|
||||
func truncfltlit(v constant.Value, t *types.Type) constant.Value {
|
||||
if t.IsUntyped() || overflow(v, t) {
|
||||
// If there was overflow, simply continuing would set the
|
||||
// value to Inf which in turn would lead to spurious follow-on
|
||||
// errors. Avoid this by returning the existing value.
|
||||
if t.IsUntyped() {
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -48,10 +45,7 @@ func truncfltlit(v constant.Value, t *types.Type) constant.Value {
|
||||
// precision, according to type; return truncated value. In case of
|
||||
// overflow, calls Errorf but does not truncate the input value.
|
||||
func trunccmplxlit(v constant.Value, t *types.Type) constant.Value {
|
||||
if t.IsUntyped() || overflow(v, t) {
|
||||
// If there was overflow, simply continuing would set the
|
||||
// value to Inf which in turn would lead to spurious follow-on
|
||||
// errors. Avoid this by returning the existing value.
|
||||
if t.IsUntyped() {
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -251,7 +245,6 @@ func convertVal(v constant.Value, t *types.Type, explicit bool) constant.Value {
|
||||
switch {
|
||||
case t.IsInteger():
|
||||
v = toint(v)
|
||||
overflow(v, t)
|
||||
return v
|
||||
case t.IsFloat():
|
||||
v = toflt(v)
|
||||
@@ -273,9 +266,6 @@ func tocplx(v constant.Value) constant.Value {
|
||||
|
||||
func toflt(v constant.Value) constant.Value {
|
||||
if v.Kind() == constant.Complex {
|
||||
if constant.Sign(constant.Imag(v)) != 0 {
|
||||
base.Errorf("constant %v truncated to real", v)
|
||||
}
|
||||
v = constant.Real(v)
|
||||
}
|
||||
|
||||
@@ -284,9 +274,6 @@ func toflt(v constant.Value) constant.Value {
|
||||
|
||||
func toint(v constant.Value) constant.Value {
|
||||
if v.Kind() == constant.Complex {
|
||||
if constant.Sign(constant.Imag(v)) != 0 {
|
||||
base.Errorf("constant %v truncated to integer", v)
|
||||
}
|
||||
v = constant.Real(v)
|
||||
}
|
||||
|
||||
@@ -321,25 +308,6 @@ func toint(v constant.Value) constant.Value {
|
||||
return constant.MakeInt64(1)
|
||||
}
|
||||
|
||||
// overflow reports whether constant value v is too large
|
||||
// to represent with type t, and emits an error message if so.
|
||||
func overflow(v constant.Value, t *types.Type) bool {
|
||||
// v has already been converted
|
||||
// to appropriate form for t.
|
||||
if t.IsUntyped() {
|
||||
return false
|
||||
}
|
||||
if v.Kind() == constant.Int && constant.BitLen(v) > ir.ConstPrec {
|
||||
base.Errorf("integer too large")
|
||||
return true
|
||||
}
|
||||
if ir.ConstOverflow(v, t) {
|
||||
base.Errorf("constant %v overflows %v", types.FmtConst(v, false), t)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tostr(v constant.Value) constant.Value {
|
||||
if v.Kind() == constant.Int {
|
||||
r := unicode.ReplacementChar
|
||||
@@ -399,29 +367,7 @@ func EvalConst(n ir.Node) ir.Node {
|
||||
}
|
||||
|
||||
case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT:
|
||||
n := n.(*ir.BinaryExpr)
|
||||
nl, nr := n.X, n.Y
|
||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
||||
rval := nr.Val()
|
||||
|
||||
// check for divisor underflow in complex division (see issue 20227)
|
||||
if n.Op() == ir.ODIV && n.Type().IsComplex() && constant.Sign(square(constant.Real(rval))) == 0 && constant.Sign(square(constant.Imag(rval))) == 0 {
|
||||
base.Errorf("complex division by zero")
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
if (n.Op() == ir.ODIV || n.Op() == ir.OMOD) && constant.Sign(rval) == 0 {
|
||||
base.Errorf("division by zero")
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
tok := tokenForOp[n.Op()]
|
||||
if n.Op() == ir.ODIV && n.Type().IsInteger() {
|
||||
tok = token.QUO_ASSIGN // integer division
|
||||
}
|
||||
return OrigConst(n, constant.BinaryOp(nl.Val(), tok, rval))
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OOROR, ir.OANDAND:
|
||||
n := n.(*ir.LogicalExpr)
|
||||
@@ -438,19 +384,7 @@ func EvalConst(n ir.Node) ir.Node {
|
||||
}
|
||||
|
||||
case ir.OLSH, ir.ORSH:
|
||||
n := n.(*ir.BinaryExpr)
|
||||
nl, nr := n.X, n.Y
|
||||
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
|
||||
// shiftBound from go/types; "so we can express smallestFloat64" (see issue #44057)
|
||||
const shiftBound = 1023 - 1 + 52
|
||||
s, ok := constant.Uint64Val(nr.Val())
|
||||
if !ok || s > shiftBound {
|
||||
base.Errorf("invalid shift count %v", nr)
|
||||
n.SetType(nil)
|
||||
break
|
||||
}
|
||||
return OrigConst(n, constant.Shift(toint(nl.Val()), tokenForOp[n.Op()], uint(s)))
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OCONV, ir.ORUNESTR:
|
||||
n := n.(*ir.ConvExpr)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
|
||||
|
||||
do := func(nn ir.Node, t *types.Type) {
|
||||
if nn != nil {
|
||||
if ir.DeclaredBy(nn, n) {
|
||||
if ir.DeclaredBy(nn, n) && nn.Type() == nil {
|
||||
nn.SetType(t)
|
||||
} else if nn.Type() != nil {
|
||||
if op, why := Assignop(t, nn.Type()); op == ir.OXXX {
|
||||
|
||||
@@ -281,7 +281,9 @@ func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
|
||||
|
||||
// Copy from the static string data to the [n]byte.
|
||||
if len(sc) > 0 {
|
||||
as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), t.PtrTo())))
|
||||
sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
|
||||
sptr.SetBounded(true)
|
||||
as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(sptr, t.PtrTo())))
|
||||
appendWalkStmt(init, as)
|
||||
}
|
||||
|
||||
|
||||
@@ -191,6 +191,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
|
||||
// Pointer to current iteration position. Start on entry to the loop
|
||||
// with the pointer in hu.
|
||||
ptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, hs)
|
||||
ptr.SetBounded(true)
|
||||
huVal := ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], ptr)
|
||||
huVal = ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUINTPTR], huVal)
|
||||
hu := typecheck.Temp(types.Types[types.TUINTPTR])
|
||||
|
||||
@@ -288,6 +288,7 @@ func (d *dstate) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) {
|
||||
}
|
||||
fmt.Printf("\nFunc: %s\n", fd.Funcname)
|
||||
fmt.Printf("Srcfile: %s\n", fd.Srcfile)
|
||||
fmt.Printf("Literal: %v\n", fd.Lit)
|
||||
}
|
||||
for i := 0; i < len(fd.Units); i++ {
|
||||
u := fd.Units[i]
|
||||
|
||||
@@ -568,6 +568,11 @@ func annotate(names []string) {
|
||||
}
|
||||
// TODO: process files in parallel here if it matters.
|
||||
for k, name := range names {
|
||||
if strings.ContainsAny(name, "\r\n") {
|
||||
// annotateFile uses '//line' directives, which don't permit newlines.
|
||||
log.Fatalf("cover: input path contains newline character: %q", name)
|
||||
}
|
||||
|
||||
last := false
|
||||
if k == len(names)-1 {
|
||||
last = true
|
||||
@@ -645,6 +650,11 @@ func (p *Package) annotateFile(name string, fd io.Writer, last bool) {
|
||||
}
|
||||
newContent := file.edit.Bytes()
|
||||
|
||||
if strings.ContainsAny(name, "\r\n") {
|
||||
// This should have been checked by the caller already, but we double check
|
||||
// here just to be sure we haven't missed a caller somewhere.
|
||||
panic(fmt.Sprintf("annotateFile: name contains unexpected newline character: %q", name))
|
||||
}
|
||||
fmt.Fprintf(fd, "//line %s:1:1\n", name)
|
||||
fd.Write(newContent)
|
||||
|
||||
|
||||
@@ -574,3 +574,34 @@ func runExpectingError(c *exec.Cmd, t *testing.T) string {
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func TestSrcPathWithNewline(t *testing.T) {
|
||||
testenv.MustHaveExec(t)
|
||||
t.Parallel()
|
||||
|
||||
// srcPath is intentionally not clean so that the path passed to testcover
|
||||
// will not normalize the trailing / to a \ on Windows.
|
||||
srcPath := t.TempDir() + string(filepath.Separator) + "\npackage main\nfunc main() { panic(string([]rune{'u', 'h', '-', 'o', 'h'}))\n/*/main.go"
|
||||
mainSrc := ` package main
|
||||
|
||||
func main() {
|
||||
/* nothing here */
|
||||
println("ok")
|
||||
}
|
||||
`
|
||||
if err := os.MkdirAll(filepath.Dir(srcPath), 0777); err != nil {
|
||||
t.Skipf("creating directory with bogus path: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(srcPath, []byte(mainSrc), 0666); err != nil {
|
||||
t.Skipf("writing file with bogus directory: %v", err)
|
||||
}
|
||||
|
||||
cmd := testenv.Command(t, testcover(t), "-mode=atomic", srcPath)
|
||||
cmd.Stderr = new(bytes.Buffer)
|
||||
out, err := cmd.Output()
|
||||
t.Logf("%v:\n%s", cmd, out)
|
||||
t.Logf("stderr:\n%s", cmd.Stderr)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected success; want failure due to newline in file path")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ require (
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.3.0
|
||||
golang.org/x/term v0.2.0
|
||||
golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674
|
||||
golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe
|
||||
)
|
||||
|
||||
require github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 // indirect
|
||||
|
||||
@@ -12,5 +12,5 @@ golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674 h1:Lv0Y+JVwLQF2YThz8ImE7rP2FSv/IzV9lS2k7bvua6U=
|
||||
golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe h1:1B2tjdkEp2f885xTfSsY+7mi5fNZHRxWciDl8Hz3EXg=
|
||||
golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
|
||||
@@ -565,6 +565,11 @@
|
||||
// generator, containing the Go toolchain and standard library.
|
||||
// $DOLLAR
|
||||
// A dollar sign.
|
||||
// $PATH
|
||||
// The $PATH of the parent process, with $GOROOT/bin
|
||||
// placed at the beginning. This causes generators
|
||||
// that execute 'go' commands to use the same 'go'
|
||||
// as the parent 'go generate' command.
|
||||
//
|
||||
// Other than variable substitution and quoted-string evaluation, no
|
||||
// special processing such as "globbing" is performed on the command
|
||||
@@ -1697,6 +1702,10 @@
|
||||
// error. (The go command's standard error is reserved for printing
|
||||
// errors building the tests.)
|
||||
//
|
||||
// The go command places $GOROOT/bin at the beginning of $PATH
|
||||
// in the test's environment, so that tests that execute
|
||||
// 'go' commands use the same 'go' as the parent 'go test' command.
|
||||
//
|
||||
// Go test runs in two different modes:
|
||||
//
|
||||
// The first, called local directory mode, occurs when go test is
|
||||
|
||||
@@ -69,14 +69,10 @@ var exeSuffix string = func() string {
|
||||
return ""
|
||||
}()
|
||||
|
||||
func tooSlow(t *testing.T) {
|
||||
func tooSlow(t *testing.T, reason string) {
|
||||
if testing.Short() {
|
||||
// In -short mode; skip test, except run it on the {darwin,linux,windows}/amd64 builders.
|
||||
if testenv.Builder() != "" && runtime.GOARCH == "amd64" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") {
|
||||
return
|
||||
}
|
||||
t.Helper()
|
||||
t.Skip("skipping test in -short mode")
|
||||
t.Skipf("skipping test in -short mode: %s", reason)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,7 +1081,7 @@ func TestPackageMainTestCompilerFlags(t *testing.T) {
|
||||
|
||||
// Issue 4104.
|
||||
func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs a test")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1096,7 +1092,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGoListHasAConsistentOrder(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "walks all of GOROOT/src twice")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1109,7 +1105,7 @@ func TestGoListHasAConsistentOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "walks all of GOROOT/src")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1119,7 +1115,7 @@ func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
|
||||
|
||||
func TestGoListCmdOnlyShowsCommands(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo does not have GOROOT")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "walks all of GOROOT/src/cmd")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1202,7 +1198,8 @@ func TestGoListTest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGoListCompiledCgo(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles cgo files")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1423,7 +1420,7 @@ func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
|
||||
|
||||
func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo does not support -ldflags -X")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and links a binary")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1440,7 +1437,7 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
|
||||
// Test the extremely long command line arguments that contain '\n' characters
|
||||
// get encoded and passed correctly.
|
||||
skipIfGccgo(t, "gccgo does not support -ldflags -X")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and links a binary")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1462,7 +1459,7 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
|
||||
|
||||
func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo has no standard packages")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and links a test binary")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1473,7 +1470,7 @@ func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
|
||||
|
||||
func TestGoTestDashOWritesBinary(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo has no standard packages")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and runs a test binary")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1484,7 +1481,7 @@ func TestGoTestDashOWritesBinary(t *testing.T) {
|
||||
|
||||
// Issue 4515.
|
||||
func TestInstallWithTags(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and links binaries")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1553,7 +1550,7 @@ func TestCgoShowsFullPathNames(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCgoHandlesWlORIGIN(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles cgo files")
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
@@ -1571,7 +1568,7 @@ func TestCgoHandlesWlORIGIN(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCgoPkgConfig(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles cgo files")
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
@@ -1656,7 +1653,7 @@ func TestListTemplateContextFunction(t *testing.T) {
|
||||
// accessed by a non-local import (found in a GOPATH/GOROOT).
|
||||
// See golang.org/issue/17475.
|
||||
func TestImportLocal(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a lot of sequential packages")
|
||||
|
||||
tg := testgo(t)
|
||||
tg.parallel()
|
||||
@@ -1814,7 +1811,7 @@ func TestGoInstallPkgdir(t *testing.T) {
|
||||
// for the install.
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a package with cgo dependencies")
|
||||
|
||||
tg := testgo(t)
|
||||
tg.parallel()
|
||||
@@ -1829,7 +1826,7 @@ func TestGoInstallPkgdir(t *testing.T) {
|
||||
|
||||
// For issue 14337.
|
||||
func TestParallelTest(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs test binaries")
|
||||
tg := testgo(t)
|
||||
tg.parallel()
|
||||
defer tg.cleanup()
|
||||
@@ -1849,7 +1846,7 @@ func TestParallelTest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBinaryOnlyPackages(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles several packages sequentially")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -2051,7 +2048,7 @@ func TestFFLAGS(t *testing.T) {
|
||||
// This is really a cmd/link issue but this is a convenient place to test it.
|
||||
func TestDuplicateGlobalAsmSymbols(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo does not use cmd/asm")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links a binary with cgo dependencies")
|
||||
if runtime.GOARCH != "386" && runtime.GOARCH != "amd64" {
|
||||
t.Skipf("skipping test on %s", runtime.GOARCH)
|
||||
}
|
||||
@@ -2350,10 +2347,11 @@ func TestUpxCompression(t *testing.T) {
|
||||
var gocacheverify = godebug.New("gocacheverify")
|
||||
|
||||
func TestCacheListStale(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links a binary")
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2372,8 +2370,7 @@ func TestCacheListStale(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCacheCoverage(t *testing.T) {
|
||||
tooSlow(t)
|
||||
|
||||
tooSlow(t, "links and runs a test binary with coverage enabled")
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
@@ -2407,10 +2404,11 @@ func TestIssue22588(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue22531(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links binaries")
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2436,10 +2434,11 @@ func TestIssue22531(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue22596(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links binaries")
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2465,7 +2464,7 @@ func TestIssue22596(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTestCache(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs test binaries")
|
||||
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
@@ -2572,7 +2571,8 @@ func TestTestSkipVetAfterFailedBuild(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTestVetRebuild(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs test binaries")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2612,7 +2612,8 @@ func TestTestVetRebuild(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInstallDeps(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links a binary")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2643,7 +2644,8 @@ func TestInstallDeps(t *testing.T) {
|
||||
|
||||
// Issue 22986.
|
||||
func TestImportPath(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs a test binary")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2744,7 +2746,8 @@ func TestTwoPkgConfigs(t *testing.T) {
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
|
||||
t.Skipf("no shell scripts on %s", runtime.GOOS)
|
||||
}
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a package with cgo dependencies")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2775,7 +2778,7 @@ func TestCgoCache(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("no cgo")
|
||||
}
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a package with cgo dependencies")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -2828,7 +2831,7 @@ func TestLinkerTmpDirIsDeleted(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a package with cgo dependencies")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -2875,7 +2878,8 @@ func TestLinkerTmpDirIsDeleted(t *testing.T) {
|
||||
// Issue 25093.
|
||||
func TestCoverpkgTestOnly(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo has no cover tool")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs a test binary with coverage enabled")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
|
||||
@@ -2,12 +2,18 @@
|
||||
// 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"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
@@ -33,3 +39,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(tg.env[:len(tg.env):len(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")
|
||||
}
|
||||
|
||||
@@ -89,6 +89,11 @@ Go generate sets several variables when it runs the generator:
|
||||
generator, containing the Go toolchain and standard library.
|
||||
$DOLLAR
|
||||
A dollar sign.
|
||||
$PATH
|
||||
The $PATH of the parent process, with $GOROOT/bin
|
||||
placed at the beginning. This causes generators
|
||||
that execute 'go' commands to use the same 'go'
|
||||
as the parent 'go generate' command.
|
||||
|
||||
Other than variable substitution and quoted-string evaluation, no
|
||||
special processing such as "globbing" is performed on the command
|
||||
|
||||
@@ -646,7 +646,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
} else {
|
||||
pmain, ptest, pxtest, err = load.TestPackagesFor(ctx, pkgOpts, p, nil)
|
||||
if err != nil {
|
||||
base.Errorf("can't load test package: %s", err)
|
||||
base.Errorf("go: can't load test package: %s", err)
|
||||
}
|
||||
}
|
||||
if pmain != nil {
|
||||
|
||||
@@ -1960,6 +1960,10 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
|
||||
setError(fmt.Errorf("invalid input directory name %q", name))
|
||||
return
|
||||
}
|
||||
if strings.ContainsAny(p.Dir, "\r\n") {
|
||||
setError(fmt.Errorf("invalid package directory %q", p.Dir))
|
||||
return
|
||||
}
|
||||
|
||||
// Build list of imported packages and full dependency list.
|
||||
imports := make([]*Package, 0, len(p.Imports))
|
||||
|
||||
@@ -404,18 +404,6 @@ var codeRepoTests = []codeRepoTest{
|
||||
zipSum: "h1:YJYZRsM9BHFTlVr8YADjT0cJH8uFIDtoc5NLiVqZEx8=",
|
||||
zipFileHash: "c15e49d58b7a4c37966cbe5bc01a0330cd5f2927e990e1839bda1d407766d9c5",
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||
rev: "latest",
|
||||
version: "v2.0.0-20170531160350-a96e63847dc3",
|
||||
name: "a96e63847dc3c67d17befa69c303767e2f84e54f",
|
||||
short: "a96e63847dc3",
|
||||
time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
|
||||
gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
|
||||
zipSum: "h1:AFxeG48hTWHhDTQDk/m2gorfVHUEa9vo3tp3D7TzwjI=",
|
||||
zipFileHash: "b5de0da7bbbec76709eef1ac71b6c9ff423b9fbf3bb97b56743450d4937b06d5",
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||
@@ -818,11 +806,6 @@ var codeRepoVersionsTests = []struct {
|
||||
path: "swtch.com/testmod",
|
||||
versions: []string{"v1.0.0", "v1.1.1"},
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||
versions: []string{"v2.0.0"},
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/odd-tags.git",
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"cmd/go/internal/mvs"
|
||||
"cmd/go/internal/par"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
@@ -689,8 +690,8 @@ func updateWorkspaceRoots(ctx context.Context, rs *Requirements, add []module.Ve
|
||||
// roots) until the set of roots has converged.
|
||||
func tidyPrunedRoots(ctx context.Context, mainModule module.Version, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
|
||||
var (
|
||||
roots []module.Version
|
||||
pathIncluded = map[string]bool{mainModule.Path: true}
|
||||
roots []module.Version
|
||||
pathIsRoot = map[string]bool{mainModule.Path: true}
|
||||
)
|
||||
// We start by adding roots for every package in "all".
|
||||
//
|
||||
@@ -710,9 +711,9 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, direct map[
|
||||
if !pkg.flags.has(pkgInAll) {
|
||||
continue
|
||||
}
|
||||
if pkg.fromExternalModule() && !pathIncluded[pkg.mod.Path] {
|
||||
if pkg.fromExternalModule() && !pathIsRoot[pkg.mod.Path] {
|
||||
roots = append(roots, pkg.mod)
|
||||
pathIncluded[pkg.mod.Path] = true
|
||||
pathIsRoot[pkg.mod.Path] = true
|
||||
}
|
||||
queue = append(queue, pkg)
|
||||
queued[pkg] = true
|
||||
@@ -744,11 +745,12 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, direct map[
|
||||
queue = append(queue, pkg.test)
|
||||
queued[pkg.test] = true
|
||||
}
|
||||
if !pathIncluded[m.Path] {
|
||||
|
||||
if !pathIsRoot[m.Path] {
|
||||
if s := mg.Selected(m.Path); cmpVersion(s, m.Version) < 0 {
|
||||
roots = append(roots, m)
|
||||
pathIsRoot[m.Path] = true
|
||||
}
|
||||
pathIncluded[m.Path] = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -758,10 +760,62 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, direct map[
|
||||
}
|
||||
}
|
||||
|
||||
roots = tidy.rootModules
|
||||
_, err := tidy.Graph(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We try to avoid adding explicit requirements for test-only dependencies of
|
||||
// packages in external modules. However, if we drop the explicit
|
||||
// requirements, that may change an import from unambiguous (due to lazy
|
||||
// module loading) to ambiguous (because lazy module loading no longer
|
||||
// disambiguates it). For any package that has become ambiguous, we try
|
||||
// to fix it by promoting its module to an explicit root.
|
||||
// (See https://go.dev/issue/60313.)
|
||||
q := par.NewQueue(runtime.GOMAXPROCS(0))
|
||||
for {
|
||||
var disambiguateRoot sync.Map
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.mod.Path == "" || pathIsRoot[pkg.mod.Path] {
|
||||
// Lazy module loading will cause pkg.mod to be checked before any other modules
|
||||
// that are only indirectly required. It is as unambiguous as possible.
|
||||
continue
|
||||
}
|
||||
pkg := pkg
|
||||
q.Add(func() {
|
||||
skipModFile := true
|
||||
_, _, _, _, err := importFromModules(ctx, pkg.path, tidy, nil, skipModFile)
|
||||
if aie := (*AmbiguousImportError)(nil); errors.As(err, &aie) {
|
||||
disambiguateRoot.Store(pkg.mod, true)
|
||||
}
|
||||
})
|
||||
}
|
||||
<-q.Idle()
|
||||
|
||||
disambiguateRoot.Range(func(k, _ any) bool {
|
||||
m := k.(module.Version)
|
||||
roots = append(roots, m)
|
||||
pathIsRoot[m.Path] = true
|
||||
return true
|
||||
})
|
||||
|
||||
if len(roots) > len(tidy.rootModules) {
|
||||
module.Sort(roots)
|
||||
tidy = newRequirements(pruned, roots, tidy.direct)
|
||||
_, err = tidy.Graph(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Adding these roots may have pulled additional modules into the module
|
||||
// graph, causing additional packages to become ambiguous. Keep iterating
|
||||
// until we reach a fixed point.
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
return tidy, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -256,7 +256,13 @@ func (e *invalidImportError) Unwrap() error {
|
||||
// If the package is present in exactly one module, importFromModules will
|
||||
// return the module, its root directory, and a list of other modules that
|
||||
// lexically could have provided the package but did not.
|
||||
func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph) (m module.Version, modroot, dir string, altMods []module.Version, err error) {
|
||||
//
|
||||
// If skipModFile is true, the go.mod file for the package is not loaded. This
|
||||
// allows 'go mod tidy' to preserve a minor checksum-preservation bug
|
||||
// (https://go.dev/issue/56222) for modules with 'go' versions between 1.17 and
|
||||
// 1.20, preventing unnecessary go.sum churn and network access in those
|
||||
// modules.
|
||||
func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph, skipModFile bool) (m module.Version, modroot, dir string, altMods []module.Version, err error) {
|
||||
invalidf := func(format string, args ...interface{}) (module.Version, string, string, []module.Version, error) {
|
||||
return module.Version{}, "", "", nil, &invalidImportError{
|
||||
importPath: path,
|
||||
@@ -435,6 +441,18 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
|
||||
}
|
||||
|
||||
if len(mods) == 1 {
|
||||
// We've found the unique module containing the package.
|
||||
// However, in order to actually compile it we need to know what
|
||||
// Go language version to use, which requires its go.mod file.
|
||||
//
|
||||
// If the module graph is pruned and this is a test-only dependency
|
||||
// of a package in "all", we didn't necessarily load that file
|
||||
// when we read the module graph, so do it now to be sure.
|
||||
if !skipModFile && cfg.BuildMod != "vendor" && mods[0].Path != "" && !MainModules.Contains(mods[0].Path) {
|
||||
if _, err := goModSummary(mods[0]); err != nil {
|
||||
return module.Version{}, "", "", nil, err
|
||||
}
|
||||
}
|
||||
return mods[0], roots[0], dirs[0], altMods, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1583,7 +1583,8 @@ func commitRequirements(ctx context.Context) (err error) {
|
||||
// keepSums returns the set of modules (and go.mod file entries) for which
|
||||
// checksums would be needed in order to reload the same set of packages
|
||||
// loaded by the most recent call to LoadPackages or ImportFromFiles,
|
||||
// including any go.mod files needed to reconstruct the MVS result,
|
||||
// including any go.mod files needed to reconstruct the MVS result
|
||||
// or identify go versions,
|
||||
// in addition to the checksums for every module in keepMods.
|
||||
func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums) map[module.Version]bool {
|
||||
// Every module in the full module graph contributes its requirements,
|
||||
@@ -1596,7 +1597,17 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
|
||||
// paths of loaded packages. We need to retain sums for all of these modules —
|
||||
// not just the modules containing the actual packages — in order to rule out
|
||||
// ambiguous import errors the next time we load the package.
|
||||
if ld != nil {
|
||||
keepModSumsForZipSums := true
|
||||
if ld == nil {
|
||||
if cfg.BuildMod != "mod" && semver.Compare("v"+MainModules.GoVersion(), tidyGoModSumVersionV) < 0 {
|
||||
keepModSumsForZipSums = false
|
||||
}
|
||||
} else {
|
||||
keepPkgGoModSums := true
|
||||
if (ld.Tidy || cfg.BuildMod != "mod") && semver.Compare("v"+ld.GoVersion, tidyGoModSumVersionV) < 0 {
|
||||
keepPkgGoModSums = false
|
||||
keepModSumsForZipSums = false
|
||||
}
|
||||
for _, pkg := range ld.pkgs {
|
||||
// We check pkg.mod.Path here instead of pkg.inStd because the
|
||||
// pseudo-package "C" is not in std, but not provided by any module (and
|
||||
@@ -1605,6 +1616,16 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
|
||||
continue
|
||||
}
|
||||
|
||||
// We need the checksum for the go.mod file for pkg.mod
|
||||
// so that we know what Go version to use to compile pkg.
|
||||
// However, we didn't do so before Go 1.21, and the bug is relatively
|
||||
// minor, so we maintain the previous (buggy) behavior in 'go mod tidy' to
|
||||
// avoid introducing unnecessary churn.
|
||||
if keepPkgGoModSums {
|
||||
r := resolveReplacement(pkg.mod)
|
||||
keep[modkey(r)] = true
|
||||
}
|
||||
|
||||
if rs.pruning == pruned && pkg.mod.Path != "" {
|
||||
if v, ok := rs.rootSelected(pkg.mod.Path); ok && v == pkg.mod.Version {
|
||||
// pkg was loaded from a root module, and because the main module has
|
||||
@@ -1660,6 +1681,9 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
|
||||
if which == addBuildListZipSums {
|
||||
for _, m := range mg.BuildList() {
|
||||
r := resolveReplacement(m)
|
||||
if keepModSumsForZipSums {
|
||||
keep[modkey(r)] = true // we need the go version from the go.mod file to do anything useful with the zipfile
|
||||
}
|
||||
keep[r] = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,6 +823,10 @@ type loader struct {
|
||||
// transitively *imported by* the packages and tests in the main module.)
|
||||
allClosesOverTests bool
|
||||
|
||||
// skipImportModFiles indicates whether we may skip loading go.mod files
|
||||
// for imported packages (as in 'go mod tidy' in Go 1.17–1.20).
|
||||
skipImportModFiles bool
|
||||
|
||||
work *par.Queue
|
||||
|
||||
// reset on each iteration
|
||||
@@ -1003,6 +1007,10 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
|
||||
// version higher than the go.mod version adds nothing.
|
||||
ld.TidyCompatibleVersion = ld.GoVersion
|
||||
}
|
||||
|
||||
if semver.Compare("v"+ld.GoVersion, tidyGoModSumVersionV) < 0 {
|
||||
ld.skipImportModFiles = true
|
||||
}
|
||||
}
|
||||
|
||||
if semver.Compare("v"+ld.GoVersion, narrowAllVersionV) < 0 && !ld.UseVendorAll {
|
||||
@@ -1398,7 +1406,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
|
||||
//
|
||||
// In some sense, we can think of this as ‘upgraded the module providing
|
||||
// pkg.path from "none" to a version higher than "none"’.
|
||||
if _, _, _, _, err = importFromModules(ctx, pkg.path, rs, nil); err == nil {
|
||||
if _, _, _, _, err = importFromModules(ctx, pkg.path, rs, nil, ld.skipImportModFiles); err == nil {
|
||||
changed = true
|
||||
break
|
||||
}
|
||||
@@ -1609,7 +1617,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
|
||||
// If the main module is tidy and the package is in "all" — or if we're
|
||||
// lucky — we can identify all of its imports without actually loading the
|
||||
// full module graph.
|
||||
m, _, _, _, err := importFromModules(ctx, path, ld.requirements, nil)
|
||||
m, _, _, _, err := importFromModules(ctx, path, ld.requirements, nil, ld.skipImportModFiles)
|
||||
if err != nil {
|
||||
var missing *ImportMissingError
|
||||
if errors.As(err, &missing) && ld.ResolveMissingImports {
|
||||
@@ -1697,7 +1705,7 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
|
||||
}
|
||||
|
||||
var modroot string
|
||||
pkg.mod, modroot, pkg.dir, pkg.altMods, pkg.err = importFromModules(ctx, pkg.path, ld.requirements, mg)
|
||||
pkg.mod, modroot, pkg.dir, pkg.altMods, pkg.err = importFromModules(ctx, pkg.path, ld.requirements, mg, ld.skipImportModFiles)
|
||||
if pkg.dir == "" {
|
||||
return
|
||||
}
|
||||
@@ -1956,7 +1964,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
|
||||
|
||||
pkg := pkg
|
||||
ld.work.Add(func() {
|
||||
mod, _, _, _, err := importFromModules(ctx, pkg.path, rs, mg)
|
||||
mod, _, _, _, err := importFromModules(ctx, pkg.path, rs, mg, ld.skipImportModFiles)
|
||||
if mod != pkg.mod {
|
||||
mismatches := <-mismatchMu
|
||||
mismatches[pkg] = mismatch{mod: mod, err: err}
|
||||
|
||||
@@ -45,6 +45,13 @@ const (
|
||||
// "// indirect" dependencies are added in a block separate from the direct
|
||||
// ones. See https://golang.org/issue/45965.
|
||||
separateIndirectVersionV = "v1.17"
|
||||
|
||||
// tidyGoModSumVersionV is the Go version (plus leading "v") at which
|
||||
// 'go mod tidy' preserves go.mod checksums needed to build test dependencies
|
||||
// of packages in "all", so that 'go test all' can be run without checksum
|
||||
// errors.
|
||||
// See https://go.dev/issue/56222.
|
||||
tidyGoModSumVersionV = "v1.21"
|
||||
)
|
||||
|
||||
// ReadModFile reads and parses the mod file at gomod. ReadModFile properly applies the
|
||||
@@ -566,6 +573,8 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||
summary := &modFileSummary{
|
||||
module: module.Version{Path: m.Path},
|
||||
}
|
||||
|
||||
readVendorList(MainModules.mustGetSingleMainModule())
|
||||
if vendorVersion[m.Path] != m.Version {
|
||||
// This module is not vendored, so packages cannot be loaded from it and
|
||||
// it cannot be relevant to the build.
|
||||
@@ -574,8 +583,6 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||
|
||||
// For every module other than the target,
|
||||
// return the full list of modules from modules.txt.
|
||||
readVendorList(MainModules.mustGetSingleMainModule())
|
||||
|
||||
// We don't know what versions the vendored module actually relies on,
|
||||
// so assume that it requires everything.
|
||||
summary.require = vendorList
|
||||
@@ -583,10 +590,10 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||
}
|
||||
|
||||
actual := resolveReplacement(m)
|
||||
if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && actual.Version != "" {
|
||||
if mustHaveSums() && actual.Version != "" {
|
||||
key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
|
||||
if !modfetch.HaveSum(key) {
|
||||
suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path)
|
||||
suggestion := fmt.Sprintf(" for go.mod file; to add it:\n\tgo mod download %s", m.Path)
|
||||
return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ func testMain(m *testing.M) (err error) {
|
||||
os.Setenv("GOPATH", dir)
|
||||
cfg.BuildContext.GOPATH = dir
|
||||
cfg.GOMODCACHE = filepath.Join(dir, "pkg/mod")
|
||||
cfg.SumdbDir = filepath.Join(dir, "pkg/sumdb")
|
||||
m.Run()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -432,21 +432,37 @@ func Exec(cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd {
|
||||
}
|
||||
|
||||
func startCommand(s *State, name, path string, args []string, cancel func(*exec.Cmd) error, waitDelay time.Duration) (WaitFunc, error) {
|
||||
var stdoutBuf, stderrBuf strings.Builder
|
||||
cmd := exec.CommandContext(s.Context(), path, args...)
|
||||
if cancel == nil {
|
||||
cmd.Cancel = nil
|
||||
} else {
|
||||
cmd.Cancel = func() error { return cancel(cmd) }
|
||||
}
|
||||
cmd.WaitDelay = waitDelay
|
||||
cmd.Args[0] = name
|
||||
cmd.Dir = s.Getwd()
|
||||
cmd.Env = s.env
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
var (
|
||||
cmd *exec.Cmd
|
||||
stdoutBuf, stderrBuf strings.Builder
|
||||
)
|
||||
for {
|
||||
cmd = exec.CommandContext(s.Context(), path, args...)
|
||||
if cancel == nil {
|
||||
cmd.Cancel = nil
|
||||
} else {
|
||||
cmd.Cancel = func() error { return cancel(cmd) }
|
||||
}
|
||||
cmd.WaitDelay = waitDelay
|
||||
cmd.Args[0] = name
|
||||
cmd.Dir = s.Getwd()
|
||||
cmd.Env = s.env
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
err := cmd.Start()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if isETXTBSY(err) {
|
||||
// If the script (or its host process) just wrote the executable we're
|
||||
// trying to run, a fork+exec in another thread may be holding open the FD
|
||||
// that we used to write the executable (see https://go.dev/issue/22315).
|
||||
// Since the descriptor should have CLOEXEC set, the problem should
|
||||
// resolve as soon as the forked child reaches its exec call.
|
||||
// Keep retrying until that happens.
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
wait := func(s *State) (stdout, stderr string, err error) {
|
||||
|
||||
11
src/cmd/go/internal/script/cmds_other.go
Normal file
11
src/cmd/go/internal/script/cmds_other.go
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.
|
||||
|
||||
//go:build !(unix || windows)
|
||||
|
||||
package script
|
||||
|
||||
func isETXTBSY(err error) bool {
|
||||
return false
|
||||
}
|
||||
16
src/cmd/go/internal/script/cmds_posix.go
Normal file
16
src/cmd/go/internal/script/cmds_posix.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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 unix || windows
|
||||
|
||||
package script
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func isETXTBSY(err error) bool {
|
||||
return errors.Is(err, syscall.ETXTBSY)
|
||||
}
|
||||
@@ -66,6 +66,7 @@ var passAnalyzersToVet = map[string]bool{
|
||||
"structtag": true,
|
||||
"testinggoroutine": true,
|
||||
"tests": true,
|
||||
"timeformat": true,
|
||||
"unmarshal": true,
|
||||
"unreachable": true,
|
||||
"unsafeptr": true,
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"cmd/go/internal/test/internal/genflags"
|
||||
"flag"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg.SetGOROOT(testenv.GOROOT(nil), false)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) {
|
||||
@@ -48,6 +50,8 @@ func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVetAnalyzersSetIsCorrect(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t) // runs 'go tool vet -flags'
|
||||
|
||||
vetAns, err := genflags.VetAnalyzers()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -75,7 +75,7 @@ func testFlags() []string {
|
||||
}
|
||||
|
||||
switch name {
|
||||
case "testlogfile", "paniconexit0", "fuzzcachedir", "fuzzworker":
|
||||
case "testlogfile", "paniconexit0", "fuzzcachedir", "fuzzworker", "gocoverdir":
|
||||
// These flags are only for use by cmd/go.
|
||||
default:
|
||||
names = append(names, name)
|
||||
|
||||
@@ -86,6 +86,10 @@ standard output, even if the test printed them to its own standard
|
||||
error. (The go command's standard error is reserved for printing
|
||||
errors building the tests.)
|
||||
|
||||
The go command places $GOROOT/bin at the beginning of $PATH
|
||||
in the test's environment, so that tests that execute
|
||||
'go' commands use the same 'go' as the parent 'go test' command.
|
||||
|
||||
Go test runs in two different modes:
|
||||
|
||||
The first, called local directory mode, occurs when go test is
|
||||
@@ -1144,7 +1148,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.
|
||||
|
||||
@@ -516,6 +516,12 @@ func (b *Builder) build(ctx context.Context, a *Action) (err error) {
|
||||
b.Print(p.ImportPath + "\n")
|
||||
}
|
||||
|
||||
if p.Error != nil {
|
||||
// Don't try to build anything for packages with errors. There may be a
|
||||
// problem with the inputs that makes the package unsafe to build.
|
||||
return p.Error
|
||||
}
|
||||
|
||||
if p.BinaryOnly {
|
||||
p.Stale = true
|
||||
p.StaleReason = "binary-only packages are no longer supported"
|
||||
@@ -3027,6 +3033,36 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
||||
}
|
||||
}
|
||||
|
||||
// Scrutinize CFLAGS and related for flags that might cause
|
||||
// problems if we are using internal linking (for example, use of
|
||||
// plugins, LTO, etc) by calling a helper routine that builds on
|
||||
// the existing CGO flags allow-lists. If we see anything
|
||||
// suspicious, emit a special token file "preferlinkext" (known to
|
||||
// the linker) in the object file to signal the that it should not
|
||||
// try to link internally and should revert to external linking.
|
||||
// The token we pass is a suggestion, not a mandate; if a user is
|
||||
// explicitly asking for a specific linkmode via the "-linkmode"
|
||||
// flag, the token will be ignored. NB: in theory we could ditch
|
||||
// the token approach and just pass a flag to the linker when we
|
||||
// eventually invoke it, and the linker flag could then be
|
||||
// documented (although coming up with a simple explanation of the
|
||||
// flag might be challenging). For more context see issues #58619,
|
||||
// #58620, and #58848.
|
||||
flagSources := []string{"CGO_CFLAGS", "CGO_CXXFLAGS", "CGO_FFLAGS"}
|
||||
flagLists := [][]string{cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS}
|
||||
if flagsNotCompatibleWithInternalLinking(flagSources, flagLists) {
|
||||
tokenFile := objdir + "preferlinkext"
|
||||
if cfg.BuildN || cfg.BuildX {
|
||||
b.Showcmd("", "echo > %s", tokenFile)
|
||||
}
|
||||
if !cfg.BuildN {
|
||||
if err := os.WriteFile(tokenFile, nil, 0666); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
outObj = append(outObj, tokenFile)
|
||||
}
|
||||
|
||||
if cfg.BuildMSan {
|
||||
cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
|
||||
cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
|
||||
@@ -3276,6 +3312,24 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
||||
return outGo, outObj, nil
|
||||
}
|
||||
|
||||
// flagsNotCompatibleWithInternalLinking scans the list of cgo
|
||||
// compiler flags (C/C++/Fortran) looking for flags that might cause
|
||||
// problems if the build in question uses internal linking. The
|
||||
// primary culprits are use of plugins or use of LTO, but we err on
|
||||
// the side of caution, supporting only those flags that are on the
|
||||
// allow-list for safe flags from security perspective. Return is TRUE
|
||||
// if a sensitive flag is found, FALSE otherwise.
|
||||
func flagsNotCompatibleWithInternalLinking(sourceList []string, flagListList [][]string) bool {
|
||||
for i := range sourceList {
|
||||
sn := sourceList[i]
|
||||
fll := flagListList[i]
|
||||
if err := checkCompilerFlagsForInternalLink(sn, sn, fll); err != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// dynimport creates a Go source file named importGo containing
|
||||
// //go:cgo_import_dynamic directives for each symbol or library
|
||||
// dynamically imported by the object files outObj.
|
||||
|
||||
@@ -280,14 +280,12 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
|
||||
const ldflagsPrefix = "_CGO_LDFLAGS="
|
||||
for _, line := range strings.Split(string(flags), "\n") {
|
||||
if strings.HasPrefix(line, ldflagsPrefix) {
|
||||
newFlags := strings.Fields(line[len(ldflagsPrefix):])
|
||||
for _, flag := range newFlags {
|
||||
// Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS
|
||||
// but they don't mean anything to the linker so filter
|
||||
// them out.
|
||||
if flag != "-g" && !strings.HasPrefix(flag, "-O") {
|
||||
cgoldflags = append(cgoldflags, flag)
|
||||
}
|
||||
flag := line[len(ldflagsPrefix):]
|
||||
// Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS
|
||||
// but they don't mean anything to the linker so filter
|
||||
// them out.
|
||||
if flag != "-g" && !strings.HasPrefix(flag, "-O") {
|
||||
cgoldflags = append(cgoldflags, flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,10 +180,10 @@ var validLinkerFlags = []*lazyregexp.Regexp{
|
||||
re(`-Wl,-berok`),
|
||||
re(`-Wl,-Bstatic`),
|
||||
re(`-Wl,-Bsymbolic-functions`),
|
||||
re(`-Wl,-O([^@,\-][^,]*)?`),
|
||||
re(`-Wl,-O[0-9]+`),
|
||||
re(`-Wl,-d[ny]`),
|
||||
re(`-Wl,--disable-new-dtags`),
|
||||
re(`-Wl,-e[=,][a-zA-Z0-9]*`),
|
||||
re(`-Wl,-e[=,][a-zA-Z0-9]+`),
|
||||
re(`-Wl,--enable-new-dtags`),
|
||||
re(`-Wl,--end-group`),
|
||||
re(`-Wl,--(no-)?export-dynamic`),
|
||||
@@ -192,7 +192,7 @@ var validLinkerFlags = []*lazyregexp.Regexp{
|
||||
re(`-Wl,--hash-style=(sysv|gnu|both)`),
|
||||
re(`-Wl,-headerpad_max_install_names`),
|
||||
re(`-Wl,--no-undefined`),
|
||||
re(`-Wl,-R([^@\-][^,@]*$)`),
|
||||
re(`-Wl,-R,?([^@\-,][^,@]*$)`),
|
||||
re(`-Wl,--just-symbols[=,]([^,@\-][^,@]+)`),
|
||||
re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-s`),
|
||||
@@ -230,32 +230,55 @@ var validLinkerFlagsWithNextArg = []string{
|
||||
}
|
||||
|
||||
func checkCompilerFlags(name, source string, list []string) error {
|
||||
return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg)
|
||||
checkOverrides := true
|
||||
return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides)
|
||||
}
|
||||
|
||||
func checkLinkerFlags(name, source string, list []string) error {
|
||||
return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg)
|
||||
checkOverrides := true
|
||||
return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
}
|
||||
|
||||
func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string) error {
|
||||
// checkCompilerFlagsForInternalLink returns an error if 'list'
|
||||
// contains a flag or flags that may not be fully supported by
|
||||
// internal linking (meaning that we should punt the link to the
|
||||
// external linker).
|
||||
func checkCompilerFlagsForInternalLink(name, source string, list []string) error {
|
||||
checkOverrides := false
|
||||
if err := checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil {
|
||||
return err
|
||||
}
|
||||
// Currently the only flag on the allow list that causes problems
|
||||
// for the linker is "-flto"; check for it manually here.
|
||||
for _, fl := range list {
|
||||
if strings.HasPrefix(fl, "-flto") {
|
||||
return fmt.Errorf("flag %q triggers external linking", fl)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error {
|
||||
// Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
|
||||
var (
|
||||
allow *regexp.Regexp
|
||||
disallow *regexp.Regexp
|
||||
)
|
||||
if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
|
||||
if checkOverrides {
|
||||
if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
|
||||
}
|
||||
allow = r
|
||||
}
|
||||
allow = r
|
||||
}
|
||||
if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
|
||||
if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
|
||||
}
|
||||
disallow = r
|
||||
}
|
||||
disallow = r
|
||||
}
|
||||
|
||||
Args:
|
||||
|
||||
@@ -6,6 +6,7 @@ package work
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -28,6 +29,7 @@ var goodCompilerFlags = [][]string{
|
||||
{"-Wp,-Ufoo"},
|
||||
{"-Wp,-Dfoo1"},
|
||||
{"-Wp,-Ufoo1"},
|
||||
{"-flto"},
|
||||
{"-fobjc-arc"},
|
||||
{"-fno-objc-arc"},
|
||||
{"-fomit-frame-pointer"},
|
||||
@@ -228,6 +230,11 @@ var badLinkerFlags = [][]string{
|
||||
{"-Wl,-R,@foo"},
|
||||
{"-Wl,--just-symbols,@foo"},
|
||||
{"../x.o"},
|
||||
{"-Wl,-R,"},
|
||||
{"-Wl,-O"},
|
||||
{"-Wl,-e="},
|
||||
{"-Wl,-e,"},
|
||||
{"-Wl,-R,-flag"},
|
||||
}
|
||||
|
||||
func TestCheckLinkerFlags(t *testing.T) {
|
||||
@@ -278,3 +285,34 @@ func TestCheckFlagAllowDisallow(t *testing.T) {
|
||||
t.Fatalf("missing error for -fplugin=lint.so: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckCompilerFlagsForInternalLink(t *testing.T) {
|
||||
// Any "bad" compiler flag should trigger external linking.
|
||||
for _, f := range badCompilerFlags {
|
||||
if err := checkCompilerFlagsForInternalLink("test", "test", f); err == nil {
|
||||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
|
||||
// All "good" compiler flags should not trigger external linking,
|
||||
// except for anything that begins with "-flto".
|
||||
for _, f := range goodCompilerFlags {
|
||||
foundLTO := false
|
||||
for _, s := range f {
|
||||
if strings.Contains(s, "-flto") {
|
||||
foundLTO = true
|
||||
}
|
||||
}
|
||||
if err := checkCompilerFlagsForInternalLink("test", "test", f); err != nil {
|
||||
// expect error for -flto
|
||||
if !foundLTO {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
} else {
|
||||
// expect no error for everything else
|
||||
if foundLTO {
|
||||
t.Errorf("missing error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +222,7 @@ func scriptEnv(srv *vcstest.Server, srvCertFile string) ([]string, error) {
|
||||
"devnull=" + os.DevNull,
|
||||
"goversion=" + version,
|
||||
"CMDGO_TEST_RUN_MAIN=true",
|
||||
"newline=\n",
|
||||
}
|
||||
|
||||
if testenv.Builder() != "" || os.Getenv("GIT_TRACE_CURL") == "1" {
|
||||
|
||||
@@ -49,6 +49,7 @@ func scriptConditions() map[string]script.Cond {
|
||||
add("link", lazyBool("testenv.HasLink()", testenv.HasLink))
|
||||
add("mismatched-goroot", script.Condition("test's GOROOT_FINAL does not match the real GOROOT", isMismatchedGoroot))
|
||||
add("msan", sysCondition("-msan", platform.MSanSupported, true))
|
||||
add("cgolinkext", script.BoolCondition("platform requires external linking for cgo", platform.MustLinkExternalGo121(cfg.Goos, cfg.Goarch, true)))
|
||||
add("net", lazyBool("testenv.HasExternalNetwork()", testenv.HasExternalNetwork))
|
||||
add("race", sysCondition("-race", platform.RaceDetectorSupported, true))
|
||||
add("symlink", lazyBool("testenv.HasSymlink()", testenv.HasSymlink))
|
||||
|
||||
2
src/cmd/go/testdata/script/README
vendored
2
src/cmd/go/testdata/script/README
vendored
@@ -382,6 +382,8 @@ The available conditions are:
|
||||
$WORK filesystem is case-sensitive
|
||||
[cgo]
|
||||
host CGO_ENABLED
|
||||
[cgolinkext]
|
||||
platform requires external linking for cgo
|
||||
[compiler:*]
|
||||
runtime.Compiler == <suffix>
|
||||
[cross]
|
||||
|
||||
138
src/cmd/go/testdata/script/build_cwd_newline.txt
vendored
Normal file
138
src/cmd/go/testdata/script/build_cwd_newline.txt
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
[GOOS:windows] skip 'filesystem normalizes / to \'
|
||||
[GOOS:plan9] skip 'filesystem disallows \n in paths'
|
||||
|
||||
# If the directory path containing a package to be built includes a newline,
|
||||
# the go command should refuse to even try to build the package.
|
||||
|
||||
env DIR=$WORK${/}${newline}'package main'${newline}'func main() { panic("uh-oh")'${newline}'/*'
|
||||
|
||||
mkdir $DIR
|
||||
cd $DIR
|
||||
exec pwd
|
||||
cp $WORK/go.mod ./go.mod
|
||||
cp $WORK/main.go ./main.go
|
||||
cp $WORK/main_nocgo.go ./main_nocgo.go
|
||||
cp $WORK/main_test.go ./main_test.go
|
||||
|
||||
! go build -o $devnull .
|
||||
stderr 'package example: invalid package directory .*uh-oh'
|
||||
|
||||
[cgo] ! go build -o $devnull main.go
|
||||
[!cgo] ! go build -o $devnull main_nocgo.go
|
||||
stderr 'package command-line-arguments: invalid package directory .*uh-oh'
|
||||
|
||||
! go run .
|
||||
stderr 'package example: invalid package directory .*uh-oh'
|
||||
|
||||
[cgo] ! go run main.go
|
||||
[!cgo] ! go run main_nocgo.go
|
||||
stderr 'package command-line-arguments: invalid package directory .*uh-oh'
|
||||
|
||||
! go test .
|
||||
stderr 'package example: invalid package directory .*uh-oh'
|
||||
|
||||
[cgo] ! go test -v main.go main_test.go
|
||||
[!cgo] ! go test -v main_nocgo.go main_test.go
|
||||
stderr 'package command-line-arguments: invalid package directory .*uh-oh'
|
||||
|
||||
go list -compiled -e -f '{{with .CompiledGoFiles}}{{.}}{{end}}' .
|
||||
! stdout .
|
||||
! stderr .
|
||||
! exists obj_
|
||||
|
||||
|
||||
# The cgo tool should only accept the source file if the working directory
|
||||
# is not written in line directives in the resulting files.
|
||||
|
||||
[cgo] ! go tool cgo main.go
|
||||
[cgo] stderr 'cgo: input path contains newline character: .*uh-oh'
|
||||
[cgo] ! exists _obj
|
||||
|
||||
[cgo] go tool cgo -trimpath=$PWD main.go
|
||||
[cgo] grep '//line main\.go:1:1' _obj/main.cgo1.go
|
||||
[cgo] ! grep 'uh-oh' _obj/main.cgo1.go
|
||||
[cgo] rm _obj
|
||||
|
||||
|
||||
# Since we do preserve $PWD (or set it appropriately) for commands, and we do
|
||||
# not resolve symlinks unnecessarily, referring to the contents of the unsafe
|
||||
# directory via a safe symlink should be ok, and should not inject the data from
|
||||
# the symlink target path.
|
||||
|
||||
[!symlink] stop 'remainder of test checks symlink behavior'
|
||||
[short] stop 'links and runs binaries'
|
||||
|
||||
symlink $WORK${/}link -> $DIR
|
||||
|
||||
[cgo] go run $WORK${/}link${/}main.go
|
||||
[!cgo] go run $WORK${/}link${/}main_nocgo.go
|
||||
! stdout panic
|
||||
! stderr panic
|
||||
stderr '^ok$'
|
||||
|
||||
[cgo] go test -v $WORK${/}link${/}main.go $WORK${/}link${/}main_test.go
|
||||
[!cgo] go test -v $WORK${/}link${/}main_nocgo.go $WORK${/}link${/}main_test.go
|
||||
! stdout panic
|
||||
! stderr panic
|
||||
stdout '^ok$' # 'go test' combines the test's stdout into stderr
|
||||
|
||||
cd $WORK/link
|
||||
|
||||
[cgo] ! go run $DIR${/}main.go
|
||||
[!cgo] ! go run $DIR${/}main_nocgo.go
|
||||
stderr 'package command-line-arguments: invalid package directory .*uh-oh'
|
||||
|
||||
go run .
|
||||
! stdout panic
|
||||
! stderr panic
|
||||
stderr '^ok$'
|
||||
|
||||
[cgo] go run main.go
|
||||
[!cgo] go run main_nocgo.go
|
||||
! stdout panic
|
||||
! stderr panic
|
||||
stderr '^ok$'
|
||||
|
||||
go test -v
|
||||
! stdout panic
|
||||
! stderr panic
|
||||
stdout '^ok$' # 'go test' combines the test's stdout into stderr
|
||||
|
||||
go test -v .
|
||||
! stdout panic
|
||||
! stderr panic
|
||||
stdout '^ok$' # 'go test' combines the test's stdout into stderr
|
||||
|
||||
[cgo] go tool cgo main.go
|
||||
[cgo] grep '//line .*'${/}'link'${/}'main\.go:1:1' _obj/main.cgo1.go
|
||||
[cgo] ! grep 'uh-oh' _obj/main.cgo1.go
|
||||
|
||||
-- $WORK/go.mod --
|
||||
module example
|
||||
go 1.19
|
||||
-- $WORK/main.go --
|
||||
package main
|
||||
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
/* nothing here */
|
||||
println("ok")
|
||||
}
|
||||
-- $WORK/main_nocgo.go --
|
||||
//go:build !cgo
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
/* nothing here */
|
||||
println("ok")
|
||||
}
|
||||
-- $WORK/main_test.go --
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestMain(*testing.M) {
|
||||
main()
|
||||
}
|
||||
40
src/cmd/go/testdata/script/build_issue59571.txt
vendored
Normal file
40
src/cmd/go/testdata/script/build_issue59571.txt
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# Regression test for https://go.dev/issue/59571
|
||||
# Build should be reproducible, even with aliased generic types.
|
||||
|
||||
go build -a -o 1.a
|
||||
go build -a -o 2.a
|
||||
cmp -q 1.a 2.a
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
go 1.20
|
||||
-- m.go --
|
||||
package m
|
||||
|
||||
type (
|
||||
SliceFlag[T any] struct{}
|
||||
|
||||
Alias1 = SliceFlag[[1]int]
|
||||
Alias2 = SliceFlag[[2]int]
|
||||
Alias3 = SliceFlag[[3]int]
|
||||
Alias4 = SliceFlag[[4]int]
|
||||
Alias5 = SliceFlag[[5]int]
|
||||
Alias6 = SliceFlag[[6]int]
|
||||
Alias7 = SliceFlag[[7]int]
|
||||
Alias8 = SliceFlag[[8]int]
|
||||
Alias9 = SliceFlag[[9]int]
|
||||
Alias10 = SliceFlag[[10]int]
|
||||
Alias11 = SliceFlag[[11]int]
|
||||
Alias12 = SliceFlag[[12]int]
|
||||
Alias13 = SliceFlag[[13]int]
|
||||
Alias14 = SliceFlag[[14]int]
|
||||
Alias15 = SliceFlag[[15]int]
|
||||
Alias16 = SliceFlag[[16]int]
|
||||
Alias17 = SliceFlag[[17]int]
|
||||
Alias18 = SliceFlag[[18]int]
|
||||
Alias19 = SliceFlag[[19]int]
|
||||
Alias20 = SliceFlag[[20]int]
|
||||
)
|
||||
|
||||
func (x *SliceFlag[T]) String() string { return "zzz" }
|
||||
155
src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt
vendored
Normal file
155
src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
# Test case to verify that when we have a package that uses CGO in
|
||||
# combination with selected "unusual" flags (involving plugins, LTO)
|
||||
# that we force external linking. See related
|
||||
# issues 58619, 58620, and 58848.
|
||||
|
||||
[compiler:gccgo] skip # only external linking for gccgo
|
||||
|
||||
# This test requires external linking, so use cgo as a proxy
|
||||
[!cgo] skip
|
||||
|
||||
# Here we build three program: one with explicit CGO use, one with no
|
||||
# CGO use, and one that uses a stdlib package ("runtime/cgo") that has
|
||||
# CGO in it. It used to be that only the explicit use of CGO would
|
||||
# trigger external linking, and that the program that only used
|
||||
# "runtime/cgo" would always be handled with internal linking. This caused
|
||||
# issues when users included odd/unusual flags (ex: -fplugin, -flto)
|
||||
# in CGO_CFLAGS, causing the Go linker to have to read and interpret
|
||||
# non-standard host objects.
|
||||
#
|
||||
# As of 1.21 we continue to use internal linking for programs whose
|
||||
# CGO use comes ony from stdlib packages in the absence of any flag
|
||||
# funny business, however if the Go command sees flags that may be suspicious,
|
||||
# it signals the Go linker to invoke the external linker.
|
||||
|
||||
# The next few tests run builds passing "-n" to the Go command, then
|
||||
# checking the output to see if the Go command is trying to pass a
|
||||
# "preferlinkext" token to the linker to request external linking.
|
||||
|
||||
#-----------------------
|
||||
|
||||
# Use a fresh GOCACHE for these next steps, so as to have the real
|
||||
# actions for the runtime/cgo package appear in the "-n -x" output.
|
||||
env GOCACHE=$WORK/gocache
|
||||
mkdir $GOCACHE
|
||||
|
||||
# First build: there is no CGO in use, so no token should be present regardless
|
||||
# of weird CGO flags.
|
||||
go build -x -n -o dummy.exe ./noUseOfCgo
|
||||
! stderr preferlinkext
|
||||
env CGO_CFLAGS=-flto
|
||||
go build -x -n -o dummy.exe ./noUseOfCgo
|
||||
! stderr preferlinkext
|
||||
env CGO_CFLAGS=
|
||||
|
||||
# Second build uses CGO, so we expect to see the token present in the
|
||||
# -n output only when strange flags are used.
|
||||
go build -x -n -o dummy.exe ./usesInternalCgo
|
||||
! stderr preferlinkext
|
||||
env CGO_CFLAGS=-flto
|
||||
go build -x -n -o dummy.exe ./usesInternalCgo
|
||||
stderr preferlinkext
|
||||
env CGO_CFLAGS=-fplugin
|
||||
go build -x -n -o dummy.exe ./usesInternalCgo
|
||||
stderr preferlinkext
|
||||
env CGO_CFLAGS=-fprofile-instr-generate
|
||||
go build -x -n -o dummy.exe ./usesInternalCgo
|
||||
stderr preferlinkext
|
||||
env CGO_CFLAGS=
|
||||
|
||||
[short] skip
|
||||
|
||||
# In the remaining tests below we do actual builds (without -n) to
|
||||
# verify that the Go linker is going the right thing in addition to the
|
||||
# Go command. Here the idea is to pass "-tmpdir" to the linker, then
|
||||
# check after the link is done for the presence of the file
|
||||
# <tmpdir>/go.o, which the Go linker creates prior to kicking off the
|
||||
# external linker.
|
||||
|
||||
mkdir tmp1
|
||||
mkdir tmp2
|
||||
mkdir tmp3
|
||||
mkdir tmp4
|
||||
mkdir tmp5
|
||||
|
||||
# First build: no external linking expected
|
||||
go build -ldflags=-tmpdir=tmp1 -o $devnull ./noUseOfCgo &
|
||||
|
||||
# Second build: using only "runtime/cgo", expect internal linking.
|
||||
go build -ldflags=-tmpdir=tmp2 -o $devnull ./usesInternalCgo &
|
||||
|
||||
# Third build: program uses only "runtime/cgo", so we would normally
|
||||
# expect internal linking, except that cflags contain suspicious entries
|
||||
# (in this case, a flag that does not appear on the allow list).
|
||||
env CGO_CFLAGS=-fmerge-all-constants
|
||||
env CGO_LDFLAGS=-fmerge-all-constants
|
||||
go build -ldflags=-tmpdir=tmp3 -o $devnull ./usesInternalCgo &
|
||||
env CGO_CFLAGS=
|
||||
env CGO_LDFLAGS=
|
||||
|
||||
# Fourth build: explicit CGO, expect external linking.
|
||||
go build -ldflags=-tmpdir=tmp4 -o $devnull ./usesExplicitCgo &
|
||||
|
||||
# Fifth build: explicit CGO, but we specifically asked for internal linking
|
||||
# via a flag, so using internal linking it is.
|
||||
[cgolinkext] go list ./usesInternalCgo
|
||||
[!cgolinkext] go build '-ldflags=-tmpdir=tmp5 -linkmode=internal' -o $devnull ./usesInternalCgo &
|
||||
|
||||
wait
|
||||
|
||||
# Check first build: no external linking expected
|
||||
! exists tmp1/go.o
|
||||
|
||||
# Check second build: using only "runtime/cgo", expect internal linking.
|
||||
[!cgolinkext] ! exists tmp2/go.o
|
||||
[cgolinkext] exists tmp2/go.o
|
||||
|
||||
# Check third build: has suspicious flag.
|
||||
exists tmp3/go.o
|
||||
|
||||
# Fourth build: explicit CGO, expect external linking.
|
||||
exists tmp4/go.o
|
||||
|
||||
# Fifth build: explicit CGO, -linkmode=internal.
|
||||
! exists tmp5/go.o
|
||||
|
||||
-- go.mod --
|
||||
|
||||
module cgo.example
|
||||
|
||||
go 1.20
|
||||
|
||||
-- noUseOfCgo/main.go --
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
println("clean as a whistle")
|
||||
}
|
||||
|
||||
-- usesInternalCgo/main.go --
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime/cgo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
q := "hello"
|
||||
h := cgo.NewHandle(q)
|
||||
h.Delete()
|
||||
}
|
||||
|
||||
-- usesExplicitCgo/main.go --
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
int meaningOfLife() { return 42; }
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
println(C.meaningOfLife())
|
||||
}
|
||||
23
src/cmd/go/testdata/script/gccgo_link_ldflags.txt
vendored
Normal file
23
src/cmd/go/testdata/script/gccgo_link_ldflags.txt
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# Test that #cgo LDFLAGS are properly quoted.
|
||||
# The #cgo LDFLAGS below should pass a string with spaces to -L,
|
||||
# as though searching a directory with a space in its name.
|
||||
# It should not pass --nosuchoption to the external linker.
|
||||
|
||||
[!cgo] skip
|
||||
|
||||
go build
|
||||
|
||||
[!exec:gccgo] skip
|
||||
|
||||
# TODO: remove once gccgo on builder is updated
|
||||
[GOOS:aix] [GOARCH:ppc64] skip
|
||||
|
||||
go build -compiler gccgo
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
-- cgo.go --
|
||||
package main
|
||||
// #cgo LDFLAGS: -L "./ -Wl,--nosuchoption"
|
||||
import "C"
|
||||
func main() {}
|
||||
9
src/cmd/go/testdata/script/list_empty_import.txt
vendored
Normal file
9
src/cmd/go/testdata/script/list_empty_import.txt
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
! go list a.go
|
||||
! stdout .
|
||||
stderr 'invalid import path'
|
||||
! stderr panic
|
||||
|
||||
-- a.go --
|
||||
package a
|
||||
|
||||
import ""
|
||||
@@ -4,9 +4,9 @@ stderr '^p[/\\]b.go:2:2: expected ''package'', found ''EOF''$'
|
||||
! go list -f '{{range .Imports}}{{.}} {{end}}' ./p
|
||||
stderr '^p[/\\]b.go:2:2: expected ''package'', found ''EOF''$'
|
||||
! go list -test ./t
|
||||
stderr '^can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ'
|
||||
stderr '^go: can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ'
|
||||
! go list -test -f '{{range .Imports}}{{.}} {{end}}' ./t
|
||||
stderr '^can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ'
|
||||
stderr '^go: can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ'
|
||||
|
||||
# 'go list -e' should report imports, even if some files have parse errors
|
||||
# before the import block.
|
||||
|
||||
@@ -16,7 +16,8 @@ env GO111MODULE=auto
|
||||
cd m
|
||||
cp go.mod go.mod.orig
|
||||
! go list -m all
|
||||
stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry; to add it:\n\tgo mod download example.com/cmd$'
|
||||
stderr '^go: example.com/cmd@v1.1.0-doesnotexist: reading http.*/mod/example.com/cmd/@v/v1.1.0-doesnotexist.info: 404 Not Found\n\tserver response: 404 page not found$'
|
||||
stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/cmd$'
|
||||
go install example.com/cmd/a@latest
|
||||
cmp go.mod go.mod.orig
|
||||
exists $GOPATH/bin/a$GOEXE
|
||||
|
||||
2
src/cmd/go/testdata/script/mod_list_sums.txt
vendored
2
src/cmd/go/testdata/script/mod_list_sums.txt
vendored
@@ -29,4 +29,4 @@ stderr '^go: updates to go.sum needed, disabled by -mod=readonly$'
|
||||
#
|
||||
# TODO(#41297): This should not be an error either.
|
||||
! go list -m -mod=readonly -versions rsc.io/sampler
|
||||
stderr '^go: rsc\.io/quote@v1\.5\.1: missing go\.sum entry; to add it:\n\tgo mod download rsc\.io/quote$'
|
||||
stderr '^go: rsc\.io/quote@v1\.5\.1: missing go\.sum entry for go.mod file; to add it:\n\tgo mod download rsc\.io/quote$'
|
||||
|
||||
@@ -21,7 +21,8 @@ env GO111MODULE=on
|
||||
cd m
|
||||
cp go.mod go.mod.orig
|
||||
! go list -m all
|
||||
stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry; to add it:\n\tgo mod download example.com/cmd$'
|
||||
stderr '^go: example.com/cmd@v1.1.0-doesnotexist: reading http.*/mod/example\.com/cmd/@v/v1.1.0-doesnotexist.info: 404 Not Found\n\tserver response: 404 page not found$'
|
||||
stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/cmd$'
|
||||
go run example.com/cmd/a@v1.0.0
|
||||
stdout '^a@v1.0.0$'
|
||||
cmp go.mod go.mod.orig
|
||||
|
||||
72
src/cmd/go/testdata/script/mod_sum_issue56222.txt
vendored
Normal file
72
src/cmd/go/testdata/script/mod_sum_issue56222.txt
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
# Regression test for #56222: 'go get -t' and 'go mod tidy'
|
||||
# should save enough checksums to run 'go test' on the named
|
||||
# packages or any package in "all" respectively.
|
||||
|
||||
|
||||
# At go 1.20 or earlier, 'go mod tidy' should preserve the historical go.sum
|
||||
# contents, but 'go test' should flag the missing checksums (instead of trying
|
||||
# to build the test dependency with the wrong language version).
|
||||
|
||||
cd m1
|
||||
go mod tidy
|
||||
! go test -o $devnull -c example.com/m2/q
|
||||
stderr '^# example.com/m2/q\n'..${/}m2${/}q${/}'q_test.go:3:8: example.com/generics@v1.0.0: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/generics$'
|
||||
|
||||
go mod download -json example.com/generics
|
||||
go list -f '{{if eq .ImportPath "example.com/generics"}}{{.Module.GoVersion}}{{end}}' -deps -test example.com/m2/q
|
||||
stdout 1.18
|
||||
|
||||
|
||||
# Even at go 1.20 or earlier, 'go mod tidy' shouldn't need go.mod files or
|
||||
# checksums that it won't record.
|
||||
|
||||
go mod tidy -go=1.20
|
||||
go clean -modcache # Remove checksums from the module cache, so that only go.sum is used.
|
||||
|
||||
# Issue 60667: 'go list' without -mod=mod shouldn't report the checksums as
|
||||
# dirty either.
|
||||
go list -m -u all
|
||||
|
||||
env OLDSUMDB=$GOSUMDB
|
||||
env GOSUMDB=bad
|
||||
go mod tidy
|
||||
|
||||
env GOSUMDB=$OLDSUMDB
|
||||
|
||||
|
||||
# Regardless of the go version in go.mod, 'go get -t' should fetch
|
||||
# enough checksums to run 'go test' on the named package.
|
||||
|
||||
rm p
|
||||
go mod tidy -go=1.20
|
||||
go list -m all
|
||||
! stdout example.com/generics
|
||||
go get -t example.com/m2/q@v1.0.0
|
||||
go list -f '{{if eq .ImportPath "example.com/generics"}}{{.Module.GoVersion}}{{end}}' -deps -test example.com/m2/q
|
||||
stdout 1.18
|
||||
[!short] go test -o $devnull -c example.com/m2/q
|
||||
|
||||
|
||||
-- m1/go.mod --
|
||||
module example.com/m1
|
||||
|
||||
go 1.20
|
||||
|
||||
require example.com/m2 v1.0.0
|
||||
replace example.com/m2 => ../m2
|
||||
-- m1/p/p.go --
|
||||
package p
|
||||
|
||||
import _ "example.com/m2/q"
|
||||
-- m2/go.mod --
|
||||
module example.com/m2
|
||||
|
||||
go 1.20
|
||||
|
||||
require example.com/generics v1.0.0
|
||||
-- m2/q/q.go --
|
||||
package q
|
||||
-- m2/q/q_test.go --
|
||||
package q
|
||||
|
||||
import _ "example.com/generics"
|
||||
@@ -4,7 +4,7 @@ env GO111MODULE=on
|
||||
# When a sum is needed to load the build list, we get an error for the
|
||||
# specific module. The .mod file is not downloaded, and go.sum is not written.
|
||||
! go list -m all
|
||||
stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
|
||||
stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry for go.mod file; to add it:\n\tgo mod download rsc.io/quote$'
|
||||
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
|
||||
! exists go.sum
|
||||
|
||||
@@ -12,7 +12,7 @@ stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo mod dow
|
||||
# we should see the same error.
|
||||
cp go.sum.h2only go.sum
|
||||
! go list -m all
|
||||
stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
|
||||
stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry for go.mod file; to add it:\n\tgo mod download rsc.io/quote$'
|
||||
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
|
||||
cmp go.sum go.sum.h2only
|
||||
rm go.sum
|
||||
@@ -21,7 +21,7 @@ rm go.sum
|
||||
cp go.mod go.mod.orig
|
||||
go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1
|
||||
! go list -m all
|
||||
stderr '^go: rsc.io/quote@v1.5.2 \(replaced by rsc.io/quote@v1.5.1\): missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
|
||||
stderr '^go: rsc.io/quote@v1.5.2 \(replaced by rsc.io/quote@v1.5.1\): missing go.sum entry for go.mod file; to add it:\n\tgo mod download rsc.io/quote$'
|
||||
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.mod
|
||||
! exists go.sum
|
||||
cp go.mod.orig go.mod
|
||||
|
||||
@@ -50,7 +50,7 @@ cmp stdout m_all.txt
|
||||
|
||||
go mod edit -go=1.16
|
||||
! go list -m all
|
||||
stderr '^go: example.net/lazy@v0.1.0 requires\n\texample.com/version@v1.0.1: missing go.sum entry; to add it:\n\tgo mod download example.com/version$'
|
||||
stderr '^go: example.net/lazy@v0.1.0 requires\n\texample.com/version@v1.0.1: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/version$'
|
||||
|
||||
|
||||
-- go.mod --
|
||||
|
||||
@@ -62,7 +62,7 @@ cmp stdout all-m.txt
|
||||
|
||||
go mod edit -go=1.16
|
||||
! go list -m all
|
||||
stderr '^go: example\.net/indirect@v0\.1\.0 requires\n\texample\.net/ambiguous@v0\.1\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.net/ambiguous\n'
|
||||
stderr '^go: example\.net/indirect@v0\.1\.0 requires\n\texample\.net/ambiguous@v0\.1\.0: missing go\.sum entry for go\.mod file; to add it:\n\tgo mod download example\.net/ambiguous\n'
|
||||
|
||||
|
||||
-- go.mod --
|
||||
|
||||
@@ -45,14 +45,14 @@ go mod tidy -compat=1.17
|
||||
! stderr .
|
||||
cmp go.mod go.mod.orig
|
||||
|
||||
go list -deps -test -f $MODFMT all
|
||||
stdout '^example\.com/retract/incompatible v1\.0\.0$'
|
||||
go list -deps -test -f $MODFMT ./...
|
||||
stdout '^example.net/lazy v0.1.0$'
|
||||
|
||||
go mod edit -go=1.16
|
||||
! go list -deps -test -f $MODFMT all
|
||||
! go list -deps -test -f $MODFMT ./...
|
||||
|
||||
# TODO(#46160): -count=1 instead of -count=2.
|
||||
stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v1\.0\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.com/retract/incompatible$'
|
||||
stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v1\.0\.0: missing go\.sum entry for go\.mod file; to add it:\n\tgo mod download example\.com/retract/incompatible$'
|
||||
|
||||
|
||||
# If we combine a Go 1.16 go.sum file...
|
||||
@@ -63,7 +63,7 @@ cp go.mod.orig go.mod
|
||||
|
||||
# ...then Go 1.17 no longer works. 😞
|
||||
! go list -deps -test -f $MODFMT all
|
||||
stderr -count=1 '^can''t load test package: lazy[/\\]lazy_test.go:3:8: missing go\.sum entry for module providing package example\.com/retract/incompatible \(imported by example\.net/lazy\); to add:\n\tgo get -t example.net/lazy@v0\.1\.0$'
|
||||
stderr -count=1 '^go: can''t load test package: lazy[/\\]lazy_test.go:3:8: missing go\.sum entry for module providing package example\.com/retract/incompatible \(imported by example\.net/lazy\); to add:\n\tgo get -t example.net/lazy@v0\.1\.0$'
|
||||
|
||||
|
||||
# However, if we take the union of the go.sum files...
|
||||
|
||||
@@ -49,7 +49,7 @@ cmp go.mod go.mod.orig
|
||||
go mod edit -go=1.16
|
||||
! go list -f $MODFMT -deps ./...
|
||||
# TODO(#46160): -count=1 instead of -count=2.
|
||||
stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.net/requireincompatible@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v2\.0\.0\+incompatible: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$'
|
||||
stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.net/requireincompatible@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v2\.0\.0\+incompatible: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/retract/incompatible$'
|
||||
|
||||
|
||||
# There are two ways for the module author to bring the two into alignment.
|
||||
|
||||
@@ -48,7 +48,7 @@ cmp stdout out-117.txt
|
||||
go mod edit -go=1.16
|
||||
! go list -deps -test -f $MODFMT all
|
||||
# TODO(#46160): -count=1 instead of -count=2.
|
||||
stderr -count=2 '^go: example.net/lazy@v0.1.0 requires\n\texample.com/retract/incompatible@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$'
|
||||
stderr -count=2 '^go: example.net/lazy@v0.1.0 requires\n\texample.com/retract/incompatible@v1.0.0: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/retract/incompatible$'
|
||||
|
||||
|
||||
-- go.mod --
|
||||
|
||||
69
src/cmd/go/testdata/script/mod_tidy_issue60313.txt
vendored
Normal file
69
src/cmd/go/testdata/script/mod_tidy_issue60313.txt
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# Regression test for https://go.dev/issue/60313: 'go mod tidy' did not preserve
|
||||
# dependencies needed to prevent 'ambiguous import' errors in external test
|
||||
# dependencies.
|
||||
|
||||
cp go.mod go.mod.orig
|
||||
go mod tidy
|
||||
cmp go.mod go.mod.orig
|
||||
|
||||
-- go.mod --
|
||||
module example
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
example.net/a v0.1.0
|
||||
example.net/b v0.1.0
|
||||
)
|
||||
|
||||
require example.net/outer/inner v0.1.0 // indirect
|
||||
|
||||
replace (
|
||||
example.net/a v0.1.0 => ./a
|
||||
example.net/b v0.1.0 => ./b
|
||||
example.net/outer v0.1.0 => ./outer
|
||||
example.net/outer/inner v0.1.0 => ./inner
|
||||
)
|
||||
-- example.go --
|
||||
package example
|
||||
|
||||
import (
|
||||
_ "example.net/a"
|
||||
_ "example.net/b"
|
||||
)
|
||||
-- a/go.mod --
|
||||
module example.net/a
|
||||
|
||||
go 1.20
|
||||
|
||||
require example.net/outer/inner v0.1.0
|
||||
-- a/a.go --
|
||||
package a
|
||||
-- a/a_test.go --
|
||||
package a_test
|
||||
|
||||
import _ "example.net/outer/inner"
|
||||
-- b/go.mod --
|
||||
module example.net/b
|
||||
|
||||
go 1.20
|
||||
|
||||
require example.net/outer v0.1.0
|
||||
-- b/b.go --
|
||||
package b
|
||||
-- b/b_test.go --
|
||||
package b_test
|
||||
|
||||
import _ "example.net/outer/inner"
|
||||
-- inner/go.mod --
|
||||
module example.net/outer/inner
|
||||
|
||||
go 1.20
|
||||
-- inner/inner.go --
|
||||
package inner
|
||||
-- outer/go.mod --
|
||||
module example.net/outer
|
||||
|
||||
go 1.20
|
||||
-- outer/inner/inner.go --
|
||||
package inner
|
||||
3
src/cmd/go/testdata/script/test_flags.txt
vendored
3
src/cmd/go/testdata/script/test_flags.txt
vendored
@@ -15,8 +15,7 @@ stdout '\Aok\s+example.com/x\s+[0-9.s]+\n\z'
|
||||
# Even though ./x looks like a package path, the real package should be
|
||||
# the implicit '.'.
|
||||
! go test --answer=42 ./x
|
||||
stderr '^no Go files in .+$'
|
||||
! stderr '/x'
|
||||
stderr '^no Go files in '$PWD'$'
|
||||
|
||||
# However, *flags* that appear after unrecognized flags should still be
|
||||
# interpreted as flags, under the (possibly-erroneous) assumption that
|
||||
|
||||
24
src/cmd/go/testdata/script/version_gc_sections.txt
vendored
Normal file
24
src/cmd/go/testdata/script/version_gc_sections.txt
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# This test checks that external linking with --gc-sections does not strip version information.
|
||||
|
||||
[short] skip
|
||||
[!cgo] skip
|
||||
[GOOS:aix] skip # no --gc-sections
|
||||
[GOOS:darwin] skip # no --gc-sections
|
||||
|
||||
go build -ldflags='-linkmode=external -extldflags=-Wl,--gc-sections'
|
||||
go version hello$GOEXE
|
||||
! stdout 'not a Go executable'
|
||||
! stderr 'not a Go executable'
|
||||
|
||||
-- go.mod --
|
||||
module hello
|
||||
-- hello.go --
|
||||
package main
|
||||
|
||||
/*
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
println("hello")
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func (r *MReader) Read(p []byte) (int, error) {
|
||||
r.off += int64(amt)
|
||||
return amt, nil
|
||||
}
|
||||
return r.rdr.Read(p)
|
||||
return io.ReadFull(r.rdr, p)
|
||||
}
|
||||
|
||||
func (r *MReader) ReadByte() (byte, error) {
|
||||
|
||||
98
src/cmd/internal/cov/read_test.go
Normal file
98
src/cmd/internal/cov/read_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2022 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 cov_test
|
||||
|
||||
import (
|
||||
"cmd/internal/cov"
|
||||
"fmt"
|
||||
"internal/coverage"
|
||||
"internal/coverage/decodecounter"
|
||||
"internal/coverage/decodemeta"
|
||||
"internal/coverage/pods"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// visitor implements the CovDataVisitor interface in a very stripped
|
||||
// down way, just keeps track of interesting events.
|
||||
type visitor struct {
|
||||
metaFileCount int
|
||||
counterFileCount int
|
||||
funcCounterData int
|
||||
metaFuncCount int
|
||||
}
|
||||
|
||||
func (v *visitor) BeginPod(p pods.Pod) {}
|
||||
func (v *visitor) EndPod(p pods.Pod) {}
|
||||
func (v *visitor) VisitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader) {
|
||||
v.metaFileCount++
|
||||
}
|
||||
func (v *visitor) BeginCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) {
|
||||
v.counterFileCount++
|
||||
}
|
||||
func (v *visitor) EndCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) {}
|
||||
func (v *visitor) VisitFuncCounterData(payload decodecounter.FuncPayload) { v.funcCounterData++ }
|
||||
func (v *visitor) EndCounters() {}
|
||||
func (v *visitor) BeginPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {}
|
||||
func (v *visitor) EndPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {}
|
||||
func (v *visitor) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) { v.metaFuncCount++ }
|
||||
func (v *visitor) Finish() {}
|
||||
|
||||
func TestIssue58411(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
// Build a tiny test program with -cover. Smallness is important;
|
||||
// it is one of the factors that triggers issue 58411.
|
||||
d := t.TempDir()
|
||||
exepath := filepath.Join(d, "small.exe")
|
||||
path := filepath.Join("testdata", "small.go")
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "build",
|
||||
"-o", exepath, "-cover", path)
|
||||
b, err := cmd.CombinedOutput()
|
||||
if len(b) != 0 {
|
||||
t.Logf("## build output:\n%s", b)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("build error: %v", err)
|
||||
}
|
||||
|
||||
// Run to produce coverage data. Note the large argument; we need a large
|
||||
// argument (more than 4k) to trigger the bug, but the overall file
|
||||
// has to remain small (since large files will be read with mmap).
|
||||
covdir := filepath.Join(d, "covdata")
|
||||
if err = os.Mkdir(covdir, 0777); err != nil {
|
||||
t.Fatalf("creating covdir: %v", err)
|
||||
}
|
||||
large := fmt.Sprintf("%07999d", 0)
|
||||
cmd = testenv.Command(t, exepath, "1", "2", "3", large)
|
||||
cmd.Dir = covdir
|
||||
cmd.Env = append(os.Environ(), "GOCOVERDIR="+covdir)
|
||||
b, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Logf("## run output:\n%s", b)
|
||||
t.Fatalf("build error: %v", err)
|
||||
}
|
||||
|
||||
vis := &visitor{}
|
||||
|
||||
// Read resulting coverage data. Without the fix, this would
|
||||
// yield a "short read" error.
|
||||
const verbosityLevel = 0
|
||||
const flags = 0
|
||||
cdr := cov.MakeCovDataReader(vis, []string{covdir}, verbosityLevel, flags, nil)
|
||||
err = cdr.Visit()
|
||||
if err != nil {
|
||||
t.Fatalf("visit failed: %v", err)
|
||||
}
|
||||
|
||||
// make sure we saw a few things just for grins
|
||||
const want = "{metaFileCount:1 counterFileCount:1 funcCounterData:1 metaFuncCount:1}"
|
||||
got := fmt.Sprintf("%+v", *vis)
|
||||
if want != got {
|
||||
t.Errorf("visitor contents: want %v got %v\n", want, got)
|
||||
}
|
||||
}
|
||||
@@ -186,6 +186,7 @@ func (r *CovDataReader) visitPod(p pods.Pod) error {
|
||||
if err != nil {
|
||||
return r.fatal("unable to open meta-file %s", p.MetaFile)
|
||||
}
|
||||
defer f.Close()
|
||||
br := bio.NewReader(f)
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
@@ -209,6 +210,9 @@ func (r *CovDataReader) visitPod(p pods.Pod) error {
|
||||
if err != nil {
|
||||
return r.fatal("opening counter data file %s: %s", cdf, err)
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
f.Close()
|
||||
}(cf)
|
||||
var mr *MReader
|
||||
mr, err = NewMreader(cf)
|
||||
if err != nil {
|
||||
|
||||
7
src/cmd/internal/cov/testdata/small.go
vendored
Normal file
7
src/cmd/internal/cov/testdata/small.go
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
func main() {
|
||||
println(len(os.Args))
|
||||
}
|
||||
@@ -3132,8 +3132,13 @@ func asmout(c *ctxt9, p *obj.Prog, o *Optab, out *[5]uint32) {
|
||||
if r == 0 {
|
||||
r = c.getimpliedreg(&p.From, p)
|
||||
}
|
||||
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v)))
|
||||
o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
|
||||
if o.a6 == C_REG {
|
||||
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v)))
|
||||
o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
|
||||
} else {
|
||||
o1 = AOP_IRR(OP_ADDIS, uint32(REGTMP), uint32(r), uint32(high16adjusted(v)))
|
||||
o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(REGTMP), uint32(v))
|
||||
}
|
||||
|
||||
// Sign extend MOVB if needed
|
||||
o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
|
||||
@@ -3519,8 +3524,8 @@ func asmout(c *ctxt9, p *obj.Prog, o *Optab, out *[5]uint32) {
|
||||
rel.Type = objabi.R_ADDRPOWER_TOCREL_DS
|
||||
}
|
||||
default:
|
||||
reuseBaseReg := p.As != AFMOVD && p.As != AFMOVS
|
||||
// Reuse To.Reg as base register if not FP move.
|
||||
reuseBaseReg := o.a6 == C_REG
|
||||
// Reuse To.Reg as base register if it is a GPR.
|
||||
o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg)
|
||||
}
|
||||
|
||||
|
||||
@@ -396,11 +396,28 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
|
||||
// laid out. Conservatively use a trampoline. This should be rare, as we lay out packages
|
||||
// in dependency order.
|
||||
if ldr.SymValue(rs) != 0 {
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
// Workaround for issue #58425: it appears that the
|
||||
// external linker doesn't always take into account the
|
||||
// relocation addend when doing reachability checks. This
|
||||
// means that if you have a call from function XYZ at
|
||||
// offset 8 to runtime.duffzero with addend 800 (for
|
||||
// example), where the distance between the start of XYZ
|
||||
// and the start of runtime.duffzero is just over the
|
||||
// limit (by 100 bytes, say), you can get "relocation
|
||||
// doesn't fit" errors from the external linker. To deal
|
||||
// with this, ignore the addend when performing the
|
||||
// distance calculation (this assumes that we're only
|
||||
// handling backward jumps; ideally we might want to check
|
||||
// both with and without the addend).
|
||||
if ctxt.IsExternal() {
|
||||
t = (ldr.SymValue(rs) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
} else {
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
}
|
||||
}
|
||||
if t > 0x7fffff || t < -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
|
||||
if t > 0x7fffff || t <= -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
|
||||
// direct call too far, need to insert trampoline.
|
||||
// look up existing trampolines first. if we found one within the range
|
||||
// of direct call, we can reuse it. otherwise create a new one.
|
||||
|
||||
@@ -537,6 +537,13 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
|
||||
ldr.Errorf(s, "internal error: relocation addend overflow: %s+0x%x", ldr.SymName(rs), xadd)
|
||||
}
|
||||
}
|
||||
if rt == objabi.R_CALLARM64 && xadd != 0 {
|
||||
label := ldr.Lookup(offsetLabelName(ldr, rs, xadd), ldr.SymVersion(rs))
|
||||
if label != 0 {
|
||||
xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label) // should always be 0 (checked below)
|
||||
rs = label
|
||||
}
|
||||
}
|
||||
|
||||
if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 ||
|
||||
rt == objabi.R_ARM64_PCREL_LDST8 || rt == objabi.R_ARM64_PCREL_LDST16 ||
|
||||
@@ -564,10 +571,9 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
|
||||
v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
|
||||
case objabi.R_CALLARM64:
|
||||
if xadd != 0 {
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
|
||||
// Addend should be handled above via label symbols.
|
||||
ldr.Errorf(s, "unexpected non-zero addend: %s+%d", ldr.SymName(rs), xadd)
|
||||
}
|
||||
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
|
||||
case objabi.R_ADDRARM64,
|
||||
@@ -788,9 +794,6 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||
|
||||
case objabi.R_CALLARM64:
|
||||
nExtReloc = 1
|
||||
if target.IsDarwin() && r.Add() != 0 {
|
||||
nExtReloc = 2 // need another relocation for addend
|
||||
}
|
||||
return val, nExtReloc, isOk
|
||||
|
||||
case objabi.R_ARM64_TLS_LE:
|
||||
@@ -1184,6 +1187,9 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
|
||||
// addend. For large symbols, we generate "label" symbols in the middle, so
|
||||
// that relocations can target them with smaller addends.
|
||||
// On Windows, we only get 21 bits, again (presumably) signed.
|
||||
// Also, on Windows (always) and Darwin (for very large binaries), the external
|
||||
// linker does't support CALL relocations with addend, so we generate "label"
|
||||
// symbols for functions of which we can target the middle (Duff's devices).
|
||||
if !ctxt.IsDarwin() && !ctxt.IsWindows() || !ctxt.IsExternal() {
|
||||
return
|
||||
}
|
||||
@@ -1193,19 +1199,6 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
|
||||
limit = peRelocLimit
|
||||
}
|
||||
|
||||
if ctxt.IsDarwin() {
|
||||
big := false
|
||||
for _, seg := range ld.Segments {
|
||||
if seg.Length >= machoRelocLimit {
|
||||
big = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !big {
|
||||
return // skip work if nothing big
|
||||
}
|
||||
}
|
||||
|
||||
// addLabelSyms adds "label" symbols at s+limit, s+2*limit, etc.
|
||||
addLabelSyms := func(s loader.Sym, limit, sz int64) {
|
||||
v := ldr.SymValue(s)
|
||||
@@ -1225,23 +1218,36 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
|
||||
}
|
||||
}
|
||||
|
||||
// Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each).
|
||||
if s := ldr.Lookup("runtime.duffcopy", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
|
||||
addLabelSyms(s, 8, 8*64)
|
||||
}
|
||||
if s := ldr.Lookup("runtime.duffzero", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
|
||||
addLabelSyms(s, 4, 4*64)
|
||||
}
|
||||
|
||||
if ctxt.IsDarwin() {
|
||||
big := false
|
||||
for _, seg := range ld.Segments {
|
||||
if seg.Length >= machoRelocLimit {
|
||||
big = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !big {
|
||||
return // skip work if nothing big
|
||||
}
|
||||
}
|
||||
|
||||
for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ {
|
||||
if !ldr.AttrReachable(s) {
|
||||
continue
|
||||
}
|
||||
t := ldr.SymType(s)
|
||||
if t == sym.STEXT {
|
||||
if ctxt.IsDarwin() || ctxt.IsWindows() {
|
||||
// Cannot relocate into middle of function.
|
||||
// Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each).
|
||||
switch ldr.SymName(s) {
|
||||
case "runtime.duffcopy":
|
||||
addLabelSyms(s, 8, 8*64)
|
||||
case "runtime.duffzero":
|
||||
addLabelSyms(s, 4, 4*64)
|
||||
}
|
||||
}
|
||||
continue // we don't target the middle of other functions
|
||||
// Except for Duff's devices (handled above), we don't
|
||||
// target the middle of a function.
|
||||
continue
|
||||
}
|
||||
if t >= sym.SDWARFSECT {
|
||||
continue // no need to add label for DWARF symbols
|
||||
|
||||
@@ -281,7 +281,11 @@ func determineLinkMode(ctxt *Link) {
|
||||
ctxt.LinkMode = LinkExternal
|
||||
via = "via GO_EXTLINK_ENABLED "
|
||||
default:
|
||||
if extNeeded || (iscgo && externalobj) {
|
||||
preferExternal := len(preferlinkext) != 0
|
||||
if preferExternal && ctxt.Debugvlog > 0 {
|
||||
ctxt.Logf("external linking prefer list is %v\n", preferlinkext)
|
||||
}
|
||||
if extNeeded || (iscgo && (externalobj || preferExternal)) {
|
||||
ctxt.LinkMode = LinkExternal
|
||||
} else {
|
||||
ctxt.LinkMode = LinkInternal
|
||||
|
||||
@@ -1669,6 +1669,9 @@ func (ctxt *Link) dodata(symGroupType []sym.SymKind) {
|
||||
func (state *dodataState) allocateDataSectionForSym(seg *sym.Segment, s loader.Sym, rwx int) *sym.Section {
|
||||
ldr := state.ctxt.loader
|
||||
sname := ldr.SymName(s)
|
||||
if strings.HasPrefix(sname, "go:") {
|
||||
sname = ".go." + sname[len("go:"):]
|
||||
}
|
||||
sect := addsection(ldr, state.ctxt.Arch, seg, sname, rwx)
|
||||
sect.Align = symalign(ldr, s)
|
||||
state.datsize = Rnd(state.datsize, int64(sect.Align))
|
||||
@@ -2254,7 +2257,7 @@ func (ctxt *Link) buildinfo() {
|
||||
// Write the buildinfo symbol, which go version looks for.
|
||||
// The code reading this data is in package debug/buildinfo.
|
||||
ldr := ctxt.loader
|
||||
s := ldr.CreateSymForUpdate(".go.buildinfo", 0)
|
||||
s := ldr.CreateSymForUpdate("go:buildinfo", 0)
|
||||
s.SetType(sym.SBUILDINFO)
|
||||
s.SetAlign(16)
|
||||
// The \xff is invalid UTF-8, meant to make it less likely
|
||||
@@ -2276,6 +2279,14 @@ func (ctxt *Link) buildinfo() {
|
||||
}
|
||||
s.SetData(data)
|
||||
s.SetSize(int64(len(data)))
|
||||
|
||||
// Add reference to go:buildinfo from the rodata section,
|
||||
// so that external linking with -Wl,--gc-sections does not
|
||||
// delete the build info.
|
||||
sr := ldr.CreateSymForUpdate("go:buildinfo.ref", 0)
|
||||
sr.SetType(sym.SRODATA)
|
||||
sr.SetAlign(int32(ctxt.Arch.PtrSize))
|
||||
sr.AddAddr(ctxt.Arch, s.Sym())
|
||||
}
|
||||
|
||||
// appendString appends s to data, prefixed by its varint-encoded length.
|
||||
|
||||
@@ -350,6 +350,12 @@ var (
|
||||
// any of these objects, we must link externally. Issue 52863.
|
||||
dynimportfail []string
|
||||
|
||||
// preferlinkext is a list of packages for which the Go command
|
||||
// noticed use of peculiar C flags. If we see any of these,
|
||||
// default to linking externally unless overridden by the
|
||||
// user. See issues #58619, #58620, and #58848.
|
||||
preferlinkext []string
|
||||
|
||||
// unknownObjFormat is set to true if we see an object whose
|
||||
// format we don't recognize.
|
||||
unknownObjFormat = false
|
||||
@@ -1072,6 +1078,13 @@ func loadobjfile(ctxt *Link, lib *sym.Library) {
|
||||
if arhdr.name == "dynimportfail" {
|
||||
dynimportfail = append(dynimportfail, lib.Pkg)
|
||||
}
|
||||
if arhdr.name == "preferlinkext" {
|
||||
// Ignore this directive if -linkmode has been
|
||||
// set explicitly.
|
||||
if ctxt.LinkMode == LinkAuto {
|
||||
preferlinkext = append(preferlinkext, lib.Pkg)
|
||||
}
|
||||
}
|
||||
|
||||
// Skip other special (non-object-file) sections that
|
||||
// build tools may have added. Such sections must have
|
||||
|
||||
5
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
5
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
@@ -303,6 +303,11 @@ func parallelSubtest(info *types.Info, call *ast.CallExpr) []ast.Stmt {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(call.Args) != 2 {
|
||||
// Ignore calls such as t.Run(fn()).
|
||||
return nil
|
||||
}
|
||||
|
||||
lit, _ := call.Args[1].(*ast.FuncLit)
|
||||
if lit == nil {
|
||||
return nil
|
||||
|
||||
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
@@ -910,7 +910,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
|
||||
if reason != "" {
|
||||
details = " (" + reason + ")"
|
||||
}
|
||||
pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s, see also https://pkg.go.dev/fmt#hdr-Printing", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details)
|
||||
pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details)
|
||||
return false
|
||||
}
|
||||
if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user