mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[dev.types] all: merge master into dev.types
Change-Id: Ia6964cb4e09153c15cc9c5b441373d1b3cb8f757
This commit is contained in:
commit
f8b1c17ace
14
api/next.txt
14
api/next.txt
@ -3,3 +3,17 @@ pkg unicode, var Chorasmian *RangeTable
|
||||
pkg unicode, var Dives_Akuru *RangeTable
|
||||
pkg unicode, var Khitan_Small_Script *RangeTable
|
||||
pkg unicode, var Yezidi *RangeTable
|
||||
pkg text/template/parse, const NodeComment = 20
|
||||
pkg text/template/parse, const NodeComment NodeType
|
||||
pkg text/template/parse, const ParseComments = 1
|
||||
pkg text/template/parse, const ParseComments Mode
|
||||
pkg text/template/parse, method (*CommentNode) Copy() Node
|
||||
pkg text/template/parse, method (*CommentNode) String() string
|
||||
pkg text/template/parse, method (CommentNode) Position() Pos
|
||||
pkg text/template/parse, method (CommentNode) Type() NodeType
|
||||
pkg text/template/parse, type CommentNode struct
|
||||
pkg text/template/parse, type CommentNode struct, Text string
|
||||
pkg text/template/parse, type CommentNode struct, embedded NodeType
|
||||
pkg text/template/parse, type CommentNode struct, embedded Pos
|
||||
pkg text/template/parse, type Mode uint
|
||||
pkg text/template/parse, type Tree struct, Mode Mode
|
||||
|
@ -687,6 +687,13 @@ MOVQ g(CX), AX // Move g into AX.
|
||||
MOVQ g_m(AX), BX // Move g.m into BX.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Register <code>BP</code> is callee-save.
|
||||
The assembler automatically inserts <code>BP</code> save/restore when frame size is larger than zero.
|
||||
Using <code>BP</code> as a general purpose register is allowed,
|
||||
however it can interfere with sampling-based profiling.
|
||||
</p>
|
||||
|
||||
<h3 id="arm">ARM</h3>
|
||||
|
||||
<p>
|
||||
|
@ -609,6 +609,12 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
If a program needs to accept invalid numbers like the empty string,
|
||||
consider wrapping the type with <a href="/pkg/encoding/json/#Unmarshaler"><code>Unmarshaler</code></a>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 200237 -->
|
||||
<a href="/pkg/encoding/json/#Unmarshal"><code>Unmarshal</code></a>
|
||||
can now support map keys with string underlying type which implement
|
||||
<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- encoding/json -->
|
||||
|
||||
|
@ -43,6 +43,37 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
|
||||
<h3 id="go-command">Go command</h3>
|
||||
|
||||
<p><!-- golang.org/issue/24031 -->
|
||||
<code>retract</code> directives may now be used in a <code>go.mod</code> file
|
||||
to indicate that certain published versions of the module should not be used
|
||||
by other modules. A module author may retract a version after a severe problem
|
||||
is discovered or if the version was published unintentionally.<br>
|
||||
TODO: write and link to section in golang.org/ref/mod<br>
|
||||
TODO: write and link to tutorial or blog post
|
||||
</p>
|
||||
|
||||
<p><!-- golang.org/issue/29062 -->
|
||||
When using <code>go test</code>, a test that
|
||||
calls <code>os.Exit(0)</code> during execution of a test function
|
||||
will now be considered to fail.
|
||||
This will help catch cases in which a test calls code that calls
|
||||
os.Exit(0) and thereby stops running all future tests.
|
||||
If a <code>TestMain</code> function calls <code>os.Exit(0)</code>
|
||||
that is still considered to be a passing test.
|
||||
</p>
|
||||
|
||||
<h4 id="all-pattern">The <code>all</code> pattern</h4>
|
||||
|
||||
<p><!-- golang.org/cl/240623 -->
|
||||
When the main module's <code>go.mod</code> file
|
||||
declares <code>go</code> <code>1.16</code> or higher, the <code>all</code>
|
||||
package pattern now matches only those packages that are transitively imported
|
||||
by a package or test found in the main module. (Packages imported by <em>tests
|
||||
of</em> packages imported by the main module are no longer included.) This is
|
||||
the same set of packages retained
|
||||
by <code>go</code> <code>mod</code> <code>vendor</code> since Go 1.11.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
TODO
|
||||
</p>
|
||||
@ -90,6 +121,28 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
TODO
|
||||
</p>
|
||||
|
||||
<h3 id="net"><a href="/pkg/net/">net</a></h3>
|
||||
|
||||
<p><!-- CL 250357 -->
|
||||
The case of I/O on a closed network connection, or I/O on a network
|
||||
connection that is closed before any of the I/O completes, can now
|
||||
be detected using the new <a href="/pkg/net/#ErrClosed">ErrClosed</a> error.
|
||||
A typical use would be <code>errors.Is(err, net.ErrClosed)</code>.
|
||||
In earlier releases the only way to reliably detect this case was to
|
||||
match the string returned by the <code>Error</code> method
|
||||
with <code>"use of closed network connection"</code>.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="text/template/parse"><a href="/pkg/text/template/parse/">text/template/parse</a></h3>
|
||||
|
||||
<p><!-- CL 229398, golang.org/issue/34652 -->
|
||||
A new <a href="/pkg/text/template/parse/#CommentNode"><code>CommentNode</code></a>
|
||||
was added to the parse tree. The <a href="/pkg/text/template/parse/#Mode"><code>Mode</code></a>
|
||||
field in the <code>parse.Tree</code> enables access to it.
|
||||
</p>
|
||||
<!-- text/template/parse -->
|
||||
|
||||
<h3 id="unicode"><a href="/pkg/unicode/">unicode</a></h3>
|
||||
|
||||
<p><!-- CL 248765 -->
|
||||
@ -112,3 +165,27 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
<p>
|
||||
TODO
|
||||
</p>
|
||||
|
||||
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 233637 -->
|
||||
In the <a href="/pkg/net/http/"><code>net/http</code></a> package, the
|
||||
behavior of <a href="/pkg/net/http/#StripPrefix"><code>StripPrefix</code></a>
|
||||
has been changed to strip the prefix from the request URL's
|
||||
<code>RawPath</code> field in addition to its <code>Path</code> field.
|
||||
In past releases, only the <code>Path</code> field was trimmed, and so if the
|
||||
request URL contained any escaped characters the URL would be modified to
|
||||
have mismatched <code>Path</code> and <code>RawPath</code> fields.
|
||||
In Go 1.16, <code>StripPrefix</code> trims both fields.
|
||||
If there are escaped characters in the prefix part of the request URL the
|
||||
handler serves a 404 instead of its previous behavior of invoking the
|
||||
underlying handler with a mismatched <code>Path</code>/<code>RawPath</code> pair.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 252497 -->
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package now rejects HTTP range requests
|
||||
of the form <code>"Range": "bytes=--N"</code> where <code>"-N"</code> is a negative suffix length, for
|
||||
example <code>"Range": "bytes=--2"</code>. It now replies with a <code>416 "Range Not Satisfiable"</code> response.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- net/http -->
|
||||
|
@ -600,6 +600,9 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
|
||||
<td></td><td><code>linux</code></td> <td><code>mips64le</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>linux</code></td> <td><code>riscv64</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>linux</code></td> <td><code>s390x</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -319,6 +319,7 @@ typedef enum {
|
||||
|
||||
// issue 4339
|
||||
// We've historically permitted #include <>, so test it here. Issue 29333.
|
||||
// Also see issue 41059.
|
||||
#include <issue4339.h>
|
||||
|
||||
// issue 4417
|
||||
|
@ -11,6 +11,7 @@
|
||||
// - Node.js
|
||||
// - Electron
|
||||
// - Parcel
|
||||
// - Webpack
|
||||
|
||||
if (typeof global !== "undefined") {
|
||||
// global already exists
|
||||
@ -28,7 +29,7 @@
|
||||
|
||||
if (!global.fs && global.require) {
|
||||
const fs = require("fs");
|
||||
if (Object.keys(fs) !== 0) {
|
||||
if (typeof fs === "object" && fs !== null && Object.keys(fs).length !== 0) {
|
||||
global.fs = fs;
|
||||
}
|
||||
}
|
||||
@ -556,6 +557,7 @@
|
||||
}
|
||||
|
||||
if (
|
||||
typeof module !== "undefined" &&
|
||||
global.require &&
|
||||
global.require.main === module &&
|
||||
global.process &&
|
||||
|
63
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
63
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
@ -145,6 +145,37 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
VZIP2 V10.D2, V13.D2, V3.D2 // a379ca4e
|
||||
VZIP1 V17.S2, V4.S2, V26.S2 // 9a38910e
|
||||
VZIP2 V25.S2, V14.S2, V25.S2 // d979990e
|
||||
VUXTL V30.B8, V30.H8 // dea7082f
|
||||
VUXTL V30.H4, V29.S4 // dda7102f
|
||||
VUXTL V29.S2, V2.D2 // a2a7202f
|
||||
VUXTL2 V30.H8, V30.S4 // dea7106f
|
||||
VUXTL2 V29.S4, V2.D2 // a2a7206f
|
||||
VUXTL2 V30.B16, V2.H8 // c2a7086f
|
||||
VBIT V21.B16, V25.B16, V4.B16 // 241fb56e
|
||||
VBSL V23.B16, V3.B16, V7.B16 // 671c776e
|
||||
VCMTST V2.B8, V29.B8, V2.B8 // a28f220e
|
||||
VCMTST V2.D2, V23.D2, V3.D2 // e38ee24e
|
||||
VSUB V2.B8, V30.B8, V30.B8 // de87222e
|
||||
VUZP1 V0.B8, V30.B8, V1.B8 // c11b000e
|
||||
VUZP1 V1.B16, V29.B16, V2.B16 // a21b014e
|
||||
VUZP1 V2.H4, V28.H4, V3.H4 // 831b420e
|
||||
VUZP1 V3.H8, V27.H8, V4.H8 // 641b434e
|
||||
VUZP1 V28.S2, V2.S2, V5.S2 // 45189c0e
|
||||
VUZP1 V29.S4, V1.S4, V6.S4 // 26189d4e
|
||||
VUZP1 V30.D2, V0.D2, V7.D2 // 0718de4e
|
||||
VUZP2 V0.D2, V30.D2, V1.D2 // c15bc04e
|
||||
VUZP2 V30.D2, V0.D2, V29.D2 // 1d58de4e
|
||||
VUSHLL $0, V30.B8, V30.H8 // dea7082f
|
||||
VUSHLL $0, V30.H4, V29.S4 // dda7102f
|
||||
VUSHLL $0, V29.S2, V2.D2 // a2a7202f
|
||||
VUSHLL2 $0, V30.B16, V2.H8 // c2a7086f
|
||||
VUSHLL2 $0, V30.H8, V30.S4 // dea7106f
|
||||
VUSHLL2 $0, V29.S4, V2.D2 // a2a7206f
|
||||
VUSHLL $7, V30.B8, V30.H8 // dea70f2f
|
||||
VUSHLL $15, V30.H4, V29.S4 // dda71f2f
|
||||
VUSHLL2 $31, V30.S4, V2.D2 // c2a73f6f
|
||||
VBIF V0.B8, V30.B8, V1.B8 // c11fe02e
|
||||
VBIF V30.B16, V0.B16, V2.B16 // 021cfe6e
|
||||
MOVD (R2)(R6.SXTW), R4 // 44c866f8
|
||||
MOVD (R3)(R6), R5 // MOVD (R3)(R6*1), R5 // 656866f8
|
||||
MOVD (R2)(R6), R4 // MOVD (R2)(R6*1), R4 // 446866f8
|
||||
@ -186,6 +217,10 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
FMOVS $(0.96875), F3 // 03f02d1e
|
||||
FMOVD $(28.0), F4 // 0490671e
|
||||
|
||||
// move a large constant to a Vd.
|
||||
FMOVD $0x8040201008040201, V20 // FMOVD $-9205322385119247871, V20
|
||||
FMOVQ $0x8040201008040202, V29 // FMOVQ $-9205322385119247870, V29
|
||||
|
||||
FMOVS (R2)(R6), F4 // FMOVS (R2)(R6*1), F4 // 446866bc
|
||||
FMOVS (R2)(R6<<2), F4 // 447866bc
|
||||
FMOVD (R2)(R6), F4 // FMOVD (R2)(R6*1), F4 // 446866fc
|
||||
@ -359,18 +394,22 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
VLD4 (R15), [V10.H4, V11.H4, V12.H4, V13.H4] // ea05400c
|
||||
VLD4.P 32(R24), [V31.B8, V0.B8, V1.B8, V2.B8] // 1f03df0c
|
||||
VLD4.P (R13)(R9), [V14.S2, V15.S2, V16.S2, V17.S2] // VLD4.P (R13)(R9*1), [V14.S2,V15.S2,V16.S2,V17.S2] // ae09c90c
|
||||
VLD1R (R0), [V0.B16] // 00c0404d
|
||||
VLD1R.P 16(R0), [V0.B16] // 00c0df4d
|
||||
VLD1R.P (R15)(R1), [V15.H4] // VLD1R.P (R15)(R1*1), [V15.H4] // efc5c10d
|
||||
VLD2R (R15), [V15.H4, V16.H4] // efc5600d
|
||||
VLD2R.P 32(R0), [V0.D2, V1.D2] // 00ccff4d
|
||||
VLD2R.P (R0)(R5), [V31.D1, V0.D1] // VLD2R.P (R0)(R5*1), [V31.D1, V0.D1] // 1fcce50d
|
||||
VLD3R (RSP), [V31.S2, V0.S2, V1.S2] // ffeb400d
|
||||
VLD3R.P 24(R15), [V15.H4, V16.H4, V17.H4] // efe5df0d
|
||||
VLD3R.P (R15)(R6), [V15.H8, V16.H8, V17.H8] // VLD3R.P (R15)(R6*1), [V15.H8, V16.H8, V17.H8] // efe5c64d
|
||||
VLD4R (R0), [V0.B8, V1.B8, V2.B8, V3.B8] // 00e0600d
|
||||
VLD4R.P 64(RSP), [V31.S4, V0.S4, V1.S4, V2.S4] // ffebff4d
|
||||
VLD4R.P (R15)(R9), [V15.H4, V16.H4, V17.H4, V18.H4] // VLD4R.P (R15)(R9*1), [V15.H4, V16.H4, V17.H4, V18.H4] // efe5e90d
|
||||
VLD1R (R1), [V9.B8] // 29c0400d
|
||||
VLD1R.P (R1), [V9.B8] // 29c0df0d
|
||||
VLD1R.P 1(R1), [V2.B8] // 22c0df0d
|
||||
VLD1R.P 2(R1), [V2.H4] // 22c4df0d
|
||||
VLD1R (R0), [V0.B16] // 00c0404d
|
||||
VLD1R.P (R0), [V0.B16] // 00c0df4d
|
||||
VLD1R.P (R15)(R1), [V15.H4] // VLD1R.P (R15)(R1*1), [V15.H4] // efc5c10d
|
||||
VLD2R (R15), [V15.H4, V16.H4] // efc5600d
|
||||
VLD2R.P 16(R0), [V0.D2, V1.D2] // 00ccff4d
|
||||
VLD2R.P (R0)(R5), [V31.D1, V0.D1] // VLD2R.P (R0)(R5*1), [V31.D1, V0.D1] // 1fcce50d
|
||||
VLD3R (RSP), [V31.S2, V0.S2, V1.S2] // ffeb400d
|
||||
VLD3R.P 6(R15), [V15.H4, V16.H4, V17.H4] // efe5df0d
|
||||
VLD3R.P (R15)(R6), [V15.H8, V16.H8, V17.H8] // VLD3R.P (R15)(R6*1), [V15.H8, V16.H8, V17.H8] // efe5c64d
|
||||
VLD4R (R0), [V0.B8, V1.B8, V2.B8, V3.B8] // 00e0600d
|
||||
VLD4R.P 16(RSP), [V31.S4, V0.S4, V1.S4, V2.S4] // ffebff4d
|
||||
VLD4R.P (R15)(R9), [V15.H4, V16.H4, V17.H4, V18.H4] // VLD4R.P (R15)(R9*1), [V15.H4, V16.H4, V17.H4, V18.H4] // efe5e90d
|
||||
VST1.P [V24.S2], 8(R2) // 58789f0c
|
||||
VST1 [V29.S2, V30.S2], (R29) // bdab000c
|
||||
VST1 [V14.H4, V15.H4, V16.H4], (R27) // 6e67000c
|
||||
|
4
src/cmd/asm/internal/asm/testdata/arm64enc.s
vendored
4
src/cmd/asm/internal/asm/testdata/arm64enc.s
vendored
@ -591,7 +591,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
|
||||
FMOVS R8, F15 // 0f01271e
|
||||
FMOVD F2, F9 // 4940601e
|
||||
FMOVS F4, F27 // 9b40201e
|
||||
//TODO VFMOV $3.125, V8.2D // 28f5006f
|
||||
//TODO VFMOV $3.125, V8.D2 // 28f5006f
|
||||
FMSUBS F13, F21, F13, F19 // b3d50d1f
|
||||
FMSUBD F11, F7, F15, F31 // ff9d4b1f
|
||||
//TODO VFMUL V9.S[2], F21, F19 // b39a895f
|
||||
@ -648,7 +648,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
|
||||
FSUBS F25, F23, F0 // e03a391e
|
||||
FSUBD F11, F13, F24 // b8396b1e
|
||||
//TODO SCVTFSS F30, F20 // d4db215e
|
||||
//TODO VSCVTF V7.2S, V17.2S // f1d8210e
|
||||
//TODO VSCVTF V7.S2, V17.S2 // f1d8210e
|
||||
SCVTFWS R3, F16 // 7000221e
|
||||
SCVTFWD R20, F4 // 8402621e
|
||||
SCVTFS R16, F12 // 0c02229e
|
||||
|
14
src/cmd/asm/internal/asm/testdata/arm64error.s
vendored
14
src/cmd/asm/internal/asm/testdata/arm64error.s
vendored
@ -339,4 +339,18 @@ TEXT errors(SB),$0
|
||||
MRS ICV_EOIR1_EL1, R3 // ERROR "system register is not readable"
|
||||
MRS PMSWINC_EL0, R3 // ERROR "system register is not readable"
|
||||
MRS OSLAR_EL1, R3 // ERROR "system register is not readable"
|
||||
VLD3R.P 24(R15), [V15.H4,V16.H4,V17.H4] // ERROR "invalid post-increment offset"
|
||||
VBIT V1.H4, V12.H4, V3.H4 // ERROR "invalid arrangement"
|
||||
VBSL V1.D2, V12.D2, V3.D2 // ERROR "invalid arrangement"
|
||||
VUXTL V30.D2, V30.H8 // ERROR "operand mismatch"
|
||||
VUXTL2 V20.B8, V21.H8 // ERROR "operand mismatch"
|
||||
VUXTL V3.D2, V4.B8 // ERROR "operand mismatch"
|
||||
VUZP1 V0.B8, V30.B8, V1.B16 // ERROR "operand mismatch"
|
||||
VUZP2 V0.Q1, V30.Q1, V1.Q1 // ERROR "invalid arrangement"
|
||||
VUSHLL $0, V30.D2, V30.H8 // ERROR "operand mismatch"
|
||||
VUSHLL2 $0, V20.B8, V21.H8 // ERROR "operand mismatch"
|
||||
VUSHLL $8, V30.B8, V30.H8 // ERROR "shift amount out of range"
|
||||
VUSHLL2 $32, V30.S4, V2.D2 // ERROR "shift amount out of range"
|
||||
VBIF V0.B8, V1.B8, V2.B16 // ERROR "operand mismatch"
|
||||
VBIF V0.D2, V1.D2, V2.D2 // ERROR "invalid arrangement"
|
||||
RET
|
||||
|
@ -112,6 +112,13 @@ The default C and C++ compilers may be changed by the CC and CXX
|
||||
environment variables, respectively; those environment variables
|
||||
may include command line options.
|
||||
|
||||
The cgo tool will always invoke the C compiler with the source file's
|
||||
directory in the include path; i.e. -I${SRCDIR} is always implied. This
|
||||
means that if a header file foo/bar.h exists both in the source
|
||||
directory and also in the system include directory (or some other place
|
||||
specified by a -I flag), then "#include <foo/bar.h>" will always find the
|
||||
local version in preference to any other version.
|
||||
|
||||
The cgo tool is enabled by default for native builds on systems where
|
||||
it is expected to work. It is disabled by default when
|
||||
cross-compiling. You can control this by setting the CGO_ENABLED
|
||||
|
@ -369,7 +369,18 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
|
||||
"int __cgo__1 = __cgo__2;\n")
|
||||
|
||||
stderr := p.gccErrors(b.Bytes())
|
||||
// We need to parse the output from this gcc command, so ensure that it
|
||||
// doesn't have any ANSI escape sequences in it. (TERM=dumb is
|
||||
// insufficient; if the user specifies CGO_CFLAGS=-fdiagnostics-color,
|
||||
// GCC will ignore TERM, and GCC can also be configured at compile-time
|
||||
// to ignore TERM.)
|
||||
stderr := p.gccErrors(b.Bytes(), "-fdiagnostics-color=never")
|
||||
if strings.Contains(stderr, "unrecognized command line option") {
|
||||
// We're using an old version of GCC that doesn't understand
|
||||
// -fdiagnostics-color. Those versions can't print color anyway,
|
||||
// so just rerun without that option.
|
||||
stderr = p.gccErrors(b.Bytes())
|
||||
}
|
||||
if stderr == "" {
|
||||
fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
|
||||
}
|
||||
@ -1970,22 +1981,25 @@ func (p *Package) gccDefines(stdin []byte) string {
|
||||
// gccErrors runs gcc over the C program stdin and returns
|
||||
// the errors that gcc prints. That is, this function expects
|
||||
// gcc to fail.
|
||||
func (p *Package) gccErrors(stdin []byte) string {
|
||||
func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string {
|
||||
// TODO(rsc): require failure
|
||||
args := p.gccCmd()
|
||||
|
||||
// Optimization options can confuse the error messages; remove them.
|
||||
nargs := make([]string, 0, len(args))
|
||||
nargs := make([]string, 0, len(args)+len(extraArgs))
|
||||
for _, arg := range args {
|
||||
if !strings.HasPrefix(arg, "-O") {
|
||||
nargs = append(nargs, arg)
|
||||
}
|
||||
}
|
||||
|
||||
// Force -O0 optimization but keep the trailing "-" at the end.
|
||||
nargs = append(nargs, "-O0")
|
||||
nl := len(nargs)
|
||||
nargs[nl-2], nargs[nl-1] = nargs[nl-1], nargs[nl-2]
|
||||
// Force -O0 optimization and append extra arguments, but keep the
|
||||
// trailing "-" at the end.
|
||||
li := len(nargs) - 1
|
||||
last := nargs[li]
|
||||
nargs[li] = "-O0"
|
||||
nargs = append(nargs, extraArgs...)
|
||||
nargs = append(nargs, last)
|
||||
|
||||
if *debugGcc {
|
||||
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
|
||||
|
@ -319,8 +319,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
// TODO(khr): issue only the -1 fixup code we need.
|
||||
// For instance, if only the quotient is used, no point in zeroing the remainder.
|
||||
|
||||
j1.To.Val = n1
|
||||
j2.To.Val = s.Pc()
|
||||
j1.To.SetTarget(n1)
|
||||
j2.To.SetTarget(s.Pc())
|
||||
}
|
||||
|
||||
case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU:
|
||||
|
@ -816,7 +816,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
}
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p.From.Reg = condBits[v.Aux.(ssa.Op)]
|
||||
p.From.Reg = condBits[ssa.Op(v.AuxInt)]
|
||||
p.Reg = v.Args[0].Reg()
|
||||
p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r1})
|
||||
p.To.Type = obj.TYPE_REG
|
||||
|
@ -429,8 +429,7 @@ func hashfor(t *types.Type) *Node {
|
||||
}
|
||||
|
||||
n := newname(sym)
|
||||
n.SetClass(PFUNC)
|
||||
n.Sym.SetFunc(true)
|
||||
setNodeNameFunc(n)
|
||||
n.Type = functype(nil, []*Node{
|
||||
anonfield(types.NewPtr(t)),
|
||||
anonfield(types.Types[TUINTPTR]),
|
||||
@ -646,17 +645,11 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
// Build a list of conditions to satisfy.
|
||||
// The conditions are a list-of-lists. Conditions are reorderable
|
||||
// within each inner list. The outer lists must be evaluated in order.
|
||||
// Even within each inner list, track their order so that we can preserve
|
||||
// aspects of that order. (TODO: latter part needed?)
|
||||
type nodeIdx struct {
|
||||
n *Node
|
||||
idx int
|
||||
}
|
||||
var conds [][]nodeIdx
|
||||
conds = append(conds, []nodeIdx{})
|
||||
var conds [][]*Node
|
||||
conds = append(conds, []*Node{})
|
||||
and := func(n *Node) {
|
||||
i := len(conds) - 1
|
||||
conds[i] = append(conds[i], nodeIdx{n: n, idx: len(conds[i])})
|
||||
conds[i] = append(conds[i], n)
|
||||
}
|
||||
|
||||
// Walk the struct using memequal for runs of AMEM
|
||||
@ -674,7 +667,7 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
if !IsRegularMemory(f.Type) {
|
||||
if EqCanPanic(f.Type) {
|
||||
// Enforce ordering by starting a new set of reorderable conditions.
|
||||
conds = append(conds, []nodeIdx{})
|
||||
conds = append(conds, []*Node{})
|
||||
}
|
||||
p := nodSym(OXDOT, np, f.Sym)
|
||||
q := nodSym(OXDOT, nq, f.Sym)
|
||||
@ -688,7 +681,7 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
}
|
||||
if EqCanPanic(f.Type) {
|
||||
// Also enforce ordering after something that can panic.
|
||||
conds = append(conds, []nodeIdx{})
|
||||
conds = append(conds, []*Node{})
|
||||
}
|
||||
i++
|
||||
continue
|
||||
@ -713,14 +706,13 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
|
||||
// Sort conditions to put runtime calls last.
|
||||
// Preserve the rest of the ordering.
|
||||
var flatConds []nodeIdx
|
||||
var flatConds []*Node
|
||||
for _, c := range conds {
|
||||
isCall := func(n *Node) bool {
|
||||
return n.Op == OCALL || n.Op == OCALLFUNC
|
||||
}
|
||||
sort.SliceStable(c, func(i, j int) bool {
|
||||
x, y := c[i], c[j]
|
||||
if (x.n.Op != OCALL) == (y.n.Op != OCALL) {
|
||||
return x.idx < y.idx
|
||||
}
|
||||
return x.n.Op != OCALL
|
||||
return !isCall(c[i]) && isCall(c[j])
|
||||
})
|
||||
flatConds = append(flatConds, c...)
|
||||
}
|
||||
@ -729,9 +721,9 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
if len(flatConds) == 0 {
|
||||
cond = nodbool(true)
|
||||
} else {
|
||||
cond = flatConds[0].n
|
||||
cond = flatConds[0]
|
||||
for _, c := range flatConds[1:] {
|
||||
cond = nod(OANDAND, cond, c.n)
|
||||
cond = nod(OANDAND, cond, c)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,18 +107,7 @@ func typecheckclosure(clo *Node, top int) {
|
||||
}
|
||||
|
||||
xfunc.Func.Nname.Sym = closurename(Curfn)
|
||||
disableExport(xfunc.Func.Nname.Sym)
|
||||
if xfunc.Func.Nname.Sym.Def != nil {
|
||||
// The only case we can reach here is when the outer function was redeclared.
|
||||
// In that case, don't bother to redeclare the closure. Otherwise, we will get
|
||||
// a spurious error message, see #17758. While we are here, double check that
|
||||
// we already reported other error.
|
||||
if nsavederrors+nerrors == 0 {
|
||||
Fatalf("unexpected symbol collision %v", xfunc.Func.Nname.Sym)
|
||||
}
|
||||
} else {
|
||||
declare(xfunc.Func.Nname, PFUNC)
|
||||
}
|
||||
setNodeNameFunc(xfunc.Func.Nname)
|
||||
xfunc = typecheck(xfunc, ctxStmt)
|
||||
|
||||
// Type check the body now, but only if we're inside a function.
|
||||
@ -473,7 +462,6 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
||||
tfn.List.Set(structargs(t0.Params(), true))
|
||||
tfn.Rlist.Set(structargs(t0.Results(), false))
|
||||
|
||||
disableExport(sym)
|
||||
xfunc := dclfunc(sym, tfn)
|
||||
xfunc.Func.SetDupok(true)
|
||||
xfunc.Func.SetNeedctxt(true)
|
||||
|
@ -90,7 +90,7 @@ func declare(n *Node, ctxt Class) {
|
||||
lineno = n.Pos
|
||||
Fatalf("automatic outside function")
|
||||
}
|
||||
if Curfn != nil {
|
||||
if Curfn != nil && ctxt != PFUNC {
|
||||
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
|
||||
}
|
||||
if n.Op == OTYPE {
|
||||
@ -297,6 +297,16 @@ func oldname(s *types.Sym) *Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// importName is like oldname, but it reports an error if sym is from another package and not exported.
|
||||
func importName(sym *types.Sym) *Node {
|
||||
n := oldname(sym)
|
||||
if !types.IsExported(sym.Name) && sym.Pkg != localpkg {
|
||||
n.SetDiag(true)
|
||||
yyerror("cannot refer to unexported name %s.%s", sym.Pkg.Name, sym.Name)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// := declarations
|
||||
func colasname(n *Node) bool {
|
||||
switch n.Op {
|
||||
@ -975,10 +985,14 @@ func makefuncsym(s *types.Sym) {
|
||||
}
|
||||
}
|
||||
|
||||
// disableExport prevents sym from being included in package export
|
||||
// data. To be effectual, it must be called before declare.
|
||||
func disableExport(sym *types.Sym) {
|
||||
sym.SetOnExportList(true)
|
||||
// setNodeNameFunc marks a node as a function.
|
||||
func setNodeNameFunc(n *Node) {
|
||||
if n.Op != ONAME || n.Class() != Pxxx {
|
||||
Fatalf("expected ONAME/Pxxx node, got %v", n)
|
||||
}
|
||||
|
||||
n.SetClass(PFUNC)
|
||||
n.Sym.SetFunc(true)
|
||||
}
|
||||
|
||||
func dclfunc(sym *types.Sym, tfn *Node) *Node {
|
||||
@ -990,7 +1004,7 @@ func dclfunc(sym *types.Sym, tfn *Node) *Node {
|
||||
fn.Func.Nname = newfuncnamel(lineno, sym)
|
||||
fn.Func.Nname.Name.Defn = fn
|
||||
fn.Func.Nname.Name.Param.Ntype = tfn
|
||||
declare(fn.Func.Nname, PFUNC)
|
||||
setNodeNameFunc(fn.Func.Nname)
|
||||
funchdr(fn)
|
||||
fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, ctxType)
|
||||
return fn
|
||||
|
@ -377,7 +377,7 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||
// This really doesn't have much to do with escape analysis per se,
|
||||
// but we are reusing the ability to annotate an individual function
|
||||
// argument and pass those annotations along to importing code.
|
||||
if f.Type.Etype == TUINTPTR {
|
||||
if f.Type.IsUintptr() {
|
||||
if Debug['m'] != 0 {
|
||||
Warnl(f.Pos, "assuming %v is unsafe uintptr", name())
|
||||
}
|
||||
@ -407,13 +407,13 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||
}
|
||||
|
||||
if fn.Func.Pragma&UintptrEscapes != 0 {
|
||||
if f.Type.Etype == TUINTPTR {
|
||||
if f.Type.IsUintptr() {
|
||||
if Debug['m'] != 0 {
|
||||
Warnl(f.Pos, "marking %v as escaping uintptr", name())
|
||||
}
|
||||
return uintptrEscapesTag
|
||||
}
|
||||
if f.IsDDD() && f.Type.Elem().Etype == TUINTPTR {
|
||||
if f.IsDDD() && f.Type.Elem().IsUintptr() {
|
||||
// final argument is ...uintptr.
|
||||
if Debug['m'] != 0 {
|
||||
Warnl(f.Pos, "marking %v as escaping ...uintptr", name())
|
||||
|
@ -485,7 +485,7 @@ func (e *Escape) exprSkipInit(k EscHole, n *Node) {
|
||||
e.discard(max)
|
||||
|
||||
case OCONV, OCONVNOP:
|
||||
if checkPtr(e.curfn, 2) && n.Type.Etype == TUNSAFEPTR && n.Left.Type.IsPtr() {
|
||||
if checkPtr(e.curfn, 2) && n.Type.IsUnsafePtr() && n.Left.Type.IsPtr() {
|
||||
// When -d=checkptr=2 is enabled, treat
|
||||
// conversions to unsafe.Pointer as an
|
||||
// escaping operation. This allows better
|
||||
@ -493,7 +493,7 @@ func (e *Escape) exprSkipInit(k EscHole, n *Node) {
|
||||
// easily detect object boundaries on the heap
|
||||
// than the stack.
|
||||
e.assignHeap(n.Left, "conversion to unsafe.Pointer", n)
|
||||
} else if n.Type.Etype == TUNSAFEPTR && n.Left.Type.Etype == TUINTPTR {
|
||||
} else if n.Type.IsUnsafePtr() && n.Left.Type.IsUintptr() {
|
||||
e.unsafeValue(k, n.Left)
|
||||
} else {
|
||||
e.expr(k, n.Left)
|
||||
@ -625,7 +625,7 @@ func (e *Escape) unsafeValue(k EscHole, n *Node) {
|
||||
|
||||
switch n.Op {
|
||||
case OCONV, OCONVNOP:
|
||||
if n.Left.Type.Etype == TUNSAFEPTR {
|
||||
if n.Left.Type.IsUnsafePtr() {
|
||||
e.expr(k, n.Left)
|
||||
} else {
|
||||
e.discard(n.Left)
|
||||
@ -1029,6 +1029,9 @@ func (e *Escape) newLoc(n *Node, transient bool) *EscLocation {
|
||||
if e.curfn == nil {
|
||||
Fatalf("e.curfn isn't set")
|
||||
}
|
||||
if n != nil && n.Type != nil && n.Type.NotInHeap() {
|
||||
yyerrorl(n.Pos, "%v is go:notinheap; stack allocation disallowed", n.Type)
|
||||
}
|
||||
|
||||
n = canonicalNode(n)
|
||||
loc := &EscLocation{
|
||||
|
@ -1616,7 +1616,8 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
|
||||
}
|
||||
n1.exprfmt(s, nprec, mode)
|
||||
}
|
||||
|
||||
case ODDD:
|
||||
mode.Fprintf(s, "...")
|
||||
default:
|
||||
mode.Fprintf(s, "<node %v>", n.Op)
|
||||
}
|
||||
|
@ -342,6 +342,6 @@ func Patch(p *obj.Prog, to *obj.Prog) {
|
||||
if p.To.Type != obj.TYPE_BRANCH {
|
||||
Fatalf("patch: not a branch")
|
||||
}
|
||||
p.To.Val = to
|
||||
p.To.SetTarget(to)
|
||||
p.To.Offset = to.Pc
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ func fninit(n []*Node) {
|
||||
if len(nf) > 0 {
|
||||
lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt
|
||||
initializers := lookup("init")
|
||||
disableExport(initializers)
|
||||
fn := dclfunc(initializers, nod(OTFUNC, nil, nil))
|
||||
for _, dcl := range dummyInitFn.Func.Dcl {
|
||||
dcl.Name.Curfn = fn
|
||||
|
@ -653,7 +653,7 @@ func (p *noder) expr(expr syntax.Expr) *Node {
|
||||
obj := p.expr(expr.X)
|
||||
if obj.Op == OPACK {
|
||||
obj.Name.SetUsed(true)
|
||||
return oldname(restrictlookup(expr.Sel.Value, obj.Name.Pkg))
|
||||
return importName(obj.Name.Pkg.Lookup(expr.Sel.Value))
|
||||
}
|
||||
n := nodSym(OXDOT, obj, p.name(expr.Sel))
|
||||
n.Pos = p.pos(expr) // lineno may have been changed by p.expr(expr.X)
|
||||
@ -857,7 +857,7 @@ func (p *noder) interfaceType(expr *syntax.InterfaceType) *Node {
|
||||
p.setlineno(method)
|
||||
var n *Node
|
||||
if method.Name == nil {
|
||||
n = p.nodSym(method, ODCLFIELD, oldname(p.packname(method.Type)), nil)
|
||||
n = p.nodSym(method, ODCLFIELD, importName(p.packname(method.Type)), nil)
|
||||
} else {
|
||||
mname := p.name(method.Name)
|
||||
sig := p.typeExpr(method.Type)
|
||||
@ -896,7 +896,7 @@ func (p *noder) packname(expr syntax.Expr) *types.Sym {
|
||||
def.Name.SetUsed(true)
|
||||
pkg = def.Name.Pkg
|
||||
}
|
||||
return restrictlookup(expr.Sel.Value, pkg)
|
||||
return pkg.Lookup(expr.Sel.Value)
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected packname: %#v", expr))
|
||||
}
|
||||
@ -911,7 +911,7 @@ func (p *noder) embedded(typ syntax.Expr) *Node {
|
||||
}
|
||||
|
||||
sym := p.packname(typ)
|
||||
n := p.nodSym(typ, ODCLFIELD, oldname(sym), lookup(sym.Name))
|
||||
n := p.nodSym(typ, ODCLFIELD, importName(sym), lookup(sym.Name))
|
||||
n.SetEmbedded(true)
|
||||
|
||||
if isStar {
|
||||
@ -1641,10 +1641,3 @@ func mkname(sym *types.Sym) *Node {
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func unparen(x *Node) *Node {
|
||||
for x.Op == OPAREN {
|
||||
x = x.Left
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
@ -502,6 +502,7 @@ func (o *Order) call(n *Node) {
|
||||
x := o.copyExpr(arg.Left, arg.Left.Type, false)
|
||||
x.Name.SetKeepalive(true)
|
||||
arg.Left = x
|
||||
n.SetNeedsWrapper(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -507,7 +507,7 @@ func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
|
||||
if Ctxt.FixedFrameSize() == 0 {
|
||||
offs -= int64(Widthptr)
|
||||
}
|
||||
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
|
||||
if objabi.Framepointer_enabled || objabi.GOARCH == "arm64" {
|
||||
// There is a word space for FP on ARM64 even if the frame pointer is disabled
|
||||
offs -= int64(Widthptr)
|
||||
}
|
||||
@ -703,7 +703,7 @@ func stackOffset(slot ssa.LocalSlot) int32 {
|
||||
if Ctxt.FixedFrameSize() == 0 {
|
||||
base -= int64(Widthptr)
|
||||
}
|
||||
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
|
||||
if objabi.Framepointer_enabled || objabi.GOARCH == "arm64" {
|
||||
// There is a word space for FP on ARM64 even if the frame pointer is disabled
|
||||
base -= int64(Widthptr)
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ func typeWithoutPointers() *types.Type {
|
||||
|
||||
func typeWithPointers() *types.Type {
|
||||
t := types.New(TSTRUCT)
|
||||
f := &types.Field{Type: types.New(TPTR)}
|
||||
f := &types.Field{Type: types.NewPtr(types.New(TINT))}
|
||||
t.SetFields([]*types.Field{f})
|
||||
return t
|
||||
}
|
||||
@ -181,14 +181,6 @@ func TestStackvarSort(t *testing.T) {
|
||||
nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "xyz"}}, PAUTO),
|
||||
nodeWithClass(Node{Type: typeWithoutPointers(), Sym: &types.Sym{}}, PAUTO),
|
||||
}
|
||||
// haspointers updates Type.Haspointers as a side effect, so
|
||||
// exercise this function on all inputs so that reflect.DeepEqual
|
||||
// doesn't produce false positives.
|
||||
for i := range want {
|
||||
want[i].Type.HasPointers()
|
||||
inp[i].Type.HasPointers()
|
||||
}
|
||||
|
||||
sort.Sort(byStackVar(inp))
|
||||
if !reflect.DeepEqual(want, inp) {
|
||||
t.Error("sort failed")
|
||||
|
@ -436,7 +436,7 @@ func (lv *Liveness) regEffects(v *ssa.Value) (uevar, kill liveRegMask) {
|
||||
case ssa.LocalSlot:
|
||||
return mask
|
||||
case *ssa.Register:
|
||||
if ptrOnly && !v.Type.HasHeapPointer() {
|
||||
if ptrOnly && !v.Type.HasPointers() {
|
||||
return mask
|
||||
}
|
||||
regs[0] = loc
|
||||
@ -451,7 +451,7 @@ func (lv *Liveness) regEffects(v *ssa.Value) (uevar, kill liveRegMask) {
|
||||
if loc1 == nil {
|
||||
continue
|
||||
}
|
||||
if ptrOnly && !v.Type.FieldType(i).HasHeapPointer() {
|
||||
if ptrOnly && !v.Type.FieldType(i).HasPointers() {
|
||||
continue
|
||||
}
|
||||
regs[nreg] = loc1.(*ssa.Register)
|
||||
@ -568,13 +568,13 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) {
|
||||
if t.Align > 0 && off&int64(t.Align-1) != 0 {
|
||||
Fatalf("onebitwalktype1: invalid initial alignment: type %v has alignment %d, but offset is %v", t, t.Align, off)
|
||||
}
|
||||
if !t.HasPointers() {
|
||||
// Note: this case ensures that pointers to go:notinheap types
|
||||
// are not considered pointers by garbage collection and stack copying.
|
||||
return
|
||||
}
|
||||
|
||||
switch t.Etype {
|
||||
case TINT8, TUINT8, TINT16, TUINT16,
|
||||
TINT32, TUINT32, TINT64, TUINT64,
|
||||
TINT, TUINT, TUINTPTR, TBOOL,
|
||||
TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128:
|
||||
|
||||
case TPTR, TUNSAFEPTR, TFUNC, TCHAN, TMAP:
|
||||
if off&int64(Widthptr-1) != 0 {
|
||||
Fatalf("onebitwalktype1: invalid alignment, %v", t)
|
||||
|
@ -586,7 +586,7 @@ func arrayClear(n, v1, v2, a *Node) bool {
|
||||
n.Nbody.Append(nod(OAS, hn, tmp))
|
||||
|
||||
var fn *Node
|
||||
if a.Type.Elem().HasHeapPointer() {
|
||||
if a.Type.Elem().HasPointers() {
|
||||
// memclrHasPointers(hp, hn)
|
||||
Curfn.Func.setWBPos(stmt.Pos)
|
||||
fn = mkcall("memclrHasPointers", nil, nil, hp, hn)
|
||||
|
@ -251,10 +251,8 @@ func walkselectcases(cases *Nodes) []*Node {
|
||||
r = typecheck(r, ctxStmt)
|
||||
init = append(init, r)
|
||||
|
||||
// No initialization for order; runtime.selectgo is responsible for that.
|
||||
order := temp(types.NewArray(types.Types[TUINT16], 2*int64(ncas)))
|
||||
r = nod(OAS, order, nil)
|
||||
r = typecheck(r, ctxStmt)
|
||||
init = append(init, r)
|
||||
|
||||
var pc0, pcs *Node
|
||||
if flag_race {
|
||||
|
@ -295,7 +295,10 @@ func (s *state) emitOpenDeferInfo() {
|
||||
// worker indicates which of the backend workers is doing the processing.
|
||||
func buildssa(fn *Node, worker int) *ssa.Func {
|
||||
name := fn.funcname()
|
||||
printssa := name == ssaDump
|
||||
printssa := false
|
||||
if ssaDump != "" { // match either a simple name e.g. "(*Reader).Reset", or a package.name e.g. "compress/gzip.(*Reader).Reset"
|
||||
printssa = name == ssaDump || myimportpath+"."+name == ssaDump
|
||||
}
|
||||
var astBuf *bytes.Buffer
|
||||
if printssa {
|
||||
astBuf = &bytes.Buffer{}
|
||||
@ -2110,7 +2113,7 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
}
|
||||
|
||||
// unsafe.Pointer <--> *T
|
||||
if to.Etype == TUNSAFEPTR && from.IsPtrShaped() || from.Etype == TUNSAFEPTR && to.IsPtrShaped() {
|
||||
if to.IsUnsafePtr() && from.IsPtrShaped() || from.IsUnsafePtr() && to.IsPtrShaped() {
|
||||
return v
|
||||
}
|
||||
|
||||
@ -6179,7 +6182,7 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
|
||||
// Resolve branches, and relax DefaultStmt into NotStmt
|
||||
for _, br := range s.Branches {
|
||||
br.P.To.Val = s.bstart[br.B.ID]
|
||||
br.P.To.SetTarget(s.bstart[br.B.ID])
|
||||
if br.P.Pos.IsStmt() != src.PosIsStmt {
|
||||
br.P.Pos = br.P.Pos.WithNotStmt()
|
||||
} else if v0 := br.B.FirstPossibleStmtValue(); v0 != nil && v0.Pos.Line() == br.P.Pos.Line() && v0.Pos.IsStmt() == src.PosIsStmt {
|
||||
|
@ -271,13 +271,6 @@ func autolabel(prefix string) *types.Sym {
|
||||
return lookupN(prefix, int(n))
|
||||
}
|
||||
|
||||
func restrictlookup(name string, pkg *types.Pkg) *types.Sym {
|
||||
if !types.IsExported(name) && pkg != localpkg {
|
||||
yyerror("cannot refer to unexported name %s.%s", pkg.Name, name)
|
||||
}
|
||||
return pkg.Lookup(name)
|
||||
}
|
||||
|
||||
// find all the exported symbols in package opkg
|
||||
// and make them available in the current package
|
||||
func importdot(opkg *types.Pkg, pack *Node) {
|
||||
@ -788,12 +781,12 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
|
||||
}
|
||||
|
||||
// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
|
||||
if (src.IsPtr() || src.Etype == TUINTPTR) && dst.Etype == TUNSAFEPTR {
|
||||
if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
|
||||
return OCONVNOP
|
||||
}
|
||||
|
||||
// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
|
||||
if src.Etype == TUNSAFEPTR && (dst.IsPtr() || dst.Etype == TUINTPTR) {
|
||||
if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
|
||||
return OCONVNOP
|
||||
}
|
||||
|
||||
@ -1550,7 +1543,6 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
||||
tfn.List.Set(structargs(method.Type.Params(), true))
|
||||
tfn.Rlist.Set(structargs(method.Type.Results(), false))
|
||||
|
||||
disableExport(newnam)
|
||||
fn := dclfunc(newnam, tfn)
|
||||
fn.Func.SetDupok(true)
|
||||
|
||||
@ -1638,8 +1630,7 @@ func hashmem(t *types.Type) *Node {
|
||||
sym := Runtimepkg.Lookup("memhash")
|
||||
|
||||
n := newname(sym)
|
||||
n.SetClass(PFUNC)
|
||||
n.Sym.SetFunc(true)
|
||||
setNodeNameFunc(n)
|
||||
n.Type = functype(nil, []*Node{
|
||||
anonfield(types.NewPtr(t)),
|
||||
anonfield(types.Types[TUINTPTR]),
|
||||
|
@ -141,19 +141,20 @@ const (
|
||||
nodeInitorder, _ // tracks state during init1; two bits
|
||||
_, _ // second nodeInitorder bit
|
||||
_, nodeHasBreak
|
||||
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
|
||||
_, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP; or ANDNOT lowered to OAND
|
||||
_, nodeIsDDD // is the argument variadic
|
||||
_, nodeDiag // already printed error about this
|
||||
_, nodeColas // OAS resulting from :=
|
||||
_, nodeNonNil // guaranteed to be non-nil
|
||||
_, nodeTransient // storage can be reused immediately after this statement
|
||||
_, nodeBounded // bounds check unnecessary
|
||||
_, nodeHasCall // expression contains a function call
|
||||
_, nodeLikely // if statement condition likely
|
||||
_, nodeHasVal // node.E contains a Val
|
||||
_, nodeHasOpt // node.E contains an Opt
|
||||
_, nodeEmbedded // ODCLFIELD embedded type
|
||||
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
|
||||
_, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP; or ANDNOT lowered to OAND
|
||||
_, nodeIsDDD // is the argument variadic
|
||||
_, nodeDiag // already printed error about this
|
||||
_, nodeColas // OAS resulting from :=
|
||||
_, nodeNonNil // guaranteed to be non-nil
|
||||
_, nodeTransient // storage can be reused immediately after this statement
|
||||
_, nodeBounded // bounds check unnecessary
|
||||
_, nodeHasCall // expression contains a function call
|
||||
_, nodeLikely // if statement condition likely
|
||||
_, nodeHasVal // node.E contains a Val
|
||||
_, nodeHasOpt // node.E contains an Opt
|
||||
_, nodeEmbedded // ODCLFIELD embedded type
|
||||
_, nodeNeedsWrapper // OCALLxxx node that needs to be wrapped
|
||||
)
|
||||
|
||||
func (n *Node) Class() Class { return Class(n.flags.get3(nodeClass)) }
|
||||
@ -286,6 +287,20 @@ func (n *Node) SetIota(x int64) {
|
||||
n.Xoffset = x
|
||||
}
|
||||
|
||||
func (n *Node) NeedsWrapper() bool {
|
||||
return n.flags&nodeNeedsWrapper != 0
|
||||
}
|
||||
|
||||
// SetNeedsWrapper indicates that OCALLxxx node needs to be wrapped by a closure.
|
||||
func (n *Node) SetNeedsWrapper(b bool) {
|
||||
switch n.Op {
|
||||
case OCALLFUNC, OCALLMETH, OCALLINTER:
|
||||
default:
|
||||
Fatalf("Node.SetNeedsWrapper %v", n.Op)
|
||||
}
|
||||
n.flags.set(nodeNeedsWrapper, b)
|
||||
}
|
||||
|
||||
// mayBeShared reports whether n may occur in multiple places in the AST.
|
||||
// Extra care must be taken when mutating such a node.
|
||||
func (n *Node) mayBeShared() bool {
|
||||
|
@ -232,7 +232,11 @@ func walkstmt(n *Node) *Node {
|
||||
n.Left = copyany(n.Left, &n.Ninit, true)
|
||||
|
||||
default:
|
||||
n.Left = walkexpr(n.Left, &n.Ninit)
|
||||
if n.Left.NeedsWrapper() {
|
||||
n.Left = wrapCall(n.Left, &n.Ninit)
|
||||
} else {
|
||||
n.Left = walkexpr(n.Left, &n.Ninit)
|
||||
}
|
||||
}
|
||||
|
||||
case OFOR, OFORUNTIL:
|
||||
@ -954,11 +958,11 @@ opswitch:
|
||||
case OCONV, OCONVNOP:
|
||||
n.Left = walkexpr(n.Left, init)
|
||||
if n.Op == OCONVNOP && checkPtr(Curfn, 1) {
|
||||
if n.Type.IsPtr() && n.Left.Type.Etype == TUNSAFEPTR { // unsafe.Pointer to *T
|
||||
if n.Type.IsPtr() && n.Left.Type.IsUnsafePtr() { // unsafe.Pointer to *T
|
||||
n = walkCheckPtrAlignment(n, init, nil)
|
||||
break
|
||||
}
|
||||
if n.Type.Etype == TUNSAFEPTR && n.Left.Type.Etype == TUINTPTR { // uintptr to unsafe.Pointer
|
||||
if n.Type.IsUnsafePtr() && n.Left.Type.IsUintptr() { // uintptr to unsafe.Pointer
|
||||
n = walkCheckPtrArithmetic(n, init)
|
||||
break
|
||||
}
|
||||
@ -1123,7 +1127,7 @@ opswitch:
|
||||
n.List.SetSecond(walkexpr(n.List.Second(), init))
|
||||
|
||||
case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
|
||||
checkSlice := checkPtr(Curfn, 1) && n.Op == OSLICE3ARR && n.Left.Op == OCONVNOP && n.Left.Left.Type.Etype == TUNSAFEPTR
|
||||
checkSlice := checkPtr(Curfn, 1) && n.Op == OSLICE3ARR && n.Left.Op == OCONVNOP && n.Left.Left.Type.IsUnsafePtr()
|
||||
if checkSlice {
|
||||
n.Left.Left = walkexpr(n.Left.Left, init)
|
||||
} else {
|
||||
@ -1156,6 +1160,9 @@ opswitch:
|
||||
}
|
||||
|
||||
case ONEW:
|
||||
if n.Type.Elem().NotInHeap() {
|
||||
yyerror("%v is go:notinheap; heap allocation disallowed", n.Type.Elem())
|
||||
}
|
||||
if n.Esc == EscNone {
|
||||
if n.Type.Elem().Width >= maxImplicitStackVarSize {
|
||||
Fatalf("large ONEW with EscNone: %v", n)
|
||||
@ -1324,6 +1331,9 @@ opswitch:
|
||||
l = r
|
||||
}
|
||||
t := n.Type
|
||||
if t.Elem().NotInHeap() {
|
||||
yyerror("%v is go:notinheap; heap allocation disallowed", t.Elem())
|
||||
}
|
||||
if n.Esc == EscNone {
|
||||
if !isSmallMakeSlice(n) {
|
||||
Fatalf("non-small OMAKESLICE with EscNone: %v", n)
|
||||
@ -1365,10 +1375,6 @@ opswitch:
|
||||
// When len and cap can fit into int, use makeslice instead of
|
||||
// makeslice64, which is faster and shorter on 32 bit platforms.
|
||||
|
||||
if t.Elem().NotInHeap() {
|
||||
yyerror("%v is go:notinheap; heap allocation disallowed", t.Elem())
|
||||
}
|
||||
|
||||
len, cap := l, r
|
||||
|
||||
fnname := "makeslice64"
|
||||
@ -1403,7 +1409,7 @@ opswitch:
|
||||
|
||||
t := n.Type
|
||||
if t.Elem().NotInHeap() {
|
||||
Fatalf("%v is go:notinheap; heap allocation disallowed", t.Elem())
|
||||
yyerror("%v is go:notinheap; heap allocation disallowed", t.Elem())
|
||||
}
|
||||
|
||||
length := conv(n.Left, types.Types[TINT])
|
||||
@ -2012,9 +2018,6 @@ func walkprint(nn *Node, init *Nodes) *Node {
|
||||
}
|
||||
|
||||
func callnew(t *types.Type) *Node {
|
||||
if t.NotInHeap() {
|
||||
yyerror("%v is go:notinheap; heap allocation disallowed", t)
|
||||
}
|
||||
dowidth(t)
|
||||
n := nod(ONEWOBJ, typename(t), nil)
|
||||
n.Type = types.NewPtr(t)
|
||||
@ -2589,7 +2592,7 @@ func mapfast(t *types.Type) int {
|
||||
}
|
||||
switch algtype(t.Key()) {
|
||||
case AMEM32:
|
||||
if !t.Key().HasHeapPointer() {
|
||||
if !t.Key().HasPointers() {
|
||||
return mapfast32
|
||||
}
|
||||
if Widthptr == 4 {
|
||||
@ -2597,7 +2600,7 @@ func mapfast(t *types.Type) int {
|
||||
}
|
||||
Fatalf("small pointer %v", t.Key())
|
||||
case AMEM64:
|
||||
if !t.Key().HasHeapPointer() {
|
||||
if !t.Key().HasPointers() {
|
||||
return mapfast64
|
||||
}
|
||||
if Widthptr == 8 {
|
||||
@ -2744,7 +2747,7 @@ func appendslice(n *Node, init *Nodes) *Node {
|
||||
nodes.Append(nod(OAS, s, nt))
|
||||
|
||||
var ncopy *Node
|
||||
if elemtype.HasHeapPointer() {
|
||||
if elemtype.HasPointers() {
|
||||
// copy(s[len(l1):], l2)
|
||||
nptr1 := nod(OSLICE, s, nil)
|
||||
nptr1.Type = s.Type
|
||||
@ -3082,7 +3085,7 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
|
||||
// Also works if b is a string.
|
||||
//
|
||||
func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
|
||||
if n.Left.Type.Elem().HasHeapPointer() {
|
||||
if n.Left.Type.Elem().HasPointers() {
|
||||
Curfn.Func.setWBPos(n.Pos)
|
||||
fn := writebarrierfn("typedslicecopy", n.Left.Type.Elem(), n.Right.Type.Elem())
|
||||
n.Left = cheapexpr(n.Left, init)
|
||||
@ -3167,8 +3170,7 @@ func eqfor(t *types.Type) (n *Node, needsize bool) {
|
||||
case ASPECIAL:
|
||||
sym := typesymprefix(".eq", t)
|
||||
n := newname(sym)
|
||||
n.SetClass(PFUNC)
|
||||
n.Sym.SetFunc(true)
|
||||
setNodeNameFunc(n)
|
||||
n.Type = functype(nil, []*Node{
|
||||
anonfield(types.NewPtr(t)),
|
||||
anonfield(types.NewPtr(t)),
|
||||
@ -3859,6 +3861,14 @@ func candiscard(n *Node) bool {
|
||||
// builtin(a1, a2, a3)
|
||||
// }(x, y, z)
|
||||
// for print, println, and delete.
|
||||
//
|
||||
// Rewrite
|
||||
// go f(x, y, uintptr(unsafe.Pointer(z)))
|
||||
// into
|
||||
// go func(a1, a2, a3) {
|
||||
// builtin(a1, a2, uintptr(a3))
|
||||
// }(x, y, unsafe.Pointer(z))
|
||||
// for function contains unsafe-uintptr arguments.
|
||||
|
||||
var wrapCall_prgen int
|
||||
|
||||
@ -3870,9 +3880,17 @@ func wrapCall(n *Node, init *Nodes) *Node {
|
||||
init.AppendNodes(&n.Ninit)
|
||||
}
|
||||
|
||||
isBuiltinCall := n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER
|
||||
// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
|
||||
origArgs := make([]*Node, n.List.Len())
|
||||
t := nod(OTFUNC, nil, nil)
|
||||
for i, arg := range n.List.Slice() {
|
||||
s := lookupN("a", i)
|
||||
if !isBuiltinCall && arg.Op == OCONVNOP && arg.Type.IsUintptr() && arg.Left.Type.IsUnsafePtr() {
|
||||
origArgs[i] = arg
|
||||
arg = arg.Left
|
||||
n.List.SetIndex(i, arg)
|
||||
}
|
||||
t.List.Append(symfield(s, arg.Type))
|
||||
}
|
||||
|
||||
@ -3880,10 +3898,22 @@ func wrapCall(n *Node, init *Nodes) *Node {
|
||||
sym := lookupN("wrap·", wrapCall_prgen)
|
||||
fn := dclfunc(sym, t)
|
||||
|
||||
a := nod(n.Op, nil, nil)
|
||||
a.List.Set(paramNnames(t.Type))
|
||||
a = typecheck(a, ctxStmt)
|
||||
fn.Nbody.Set1(a)
|
||||
args := paramNnames(t.Type)
|
||||
for i, origArg := range origArgs {
|
||||
if origArg == nil {
|
||||
continue
|
||||
}
|
||||
arg := nod(origArg.Op, args[i], nil)
|
||||
arg.Type = origArg.Type
|
||||
args[i] = arg
|
||||
}
|
||||
call := nod(n.Op, nil, nil)
|
||||
if !isBuiltinCall {
|
||||
call.Op = OCALL
|
||||
call.Left = n.Left
|
||||
}
|
||||
call.List.Set(args)
|
||||
fn.Nbody.Set1(call)
|
||||
|
||||
funcbody()
|
||||
|
||||
@ -3891,12 +3921,12 @@ func wrapCall(n *Node, init *Nodes) *Node {
|
||||
typecheckslice(fn.Nbody.Slice(), ctxStmt)
|
||||
xtop = append(xtop, fn)
|
||||
|
||||
a = nod(OCALL, nil, nil)
|
||||
a.Left = fn.Func.Nname
|
||||
a.List.Set(n.List.Slice())
|
||||
a = typecheck(a, ctxStmt)
|
||||
a = walkexpr(a, init)
|
||||
return a
|
||||
call = nod(OCALL, nil, nil)
|
||||
call.Left = fn.Func.Nname
|
||||
call.List.Set(n.List.Slice())
|
||||
call = typecheck(call, ctxStmt)
|
||||
call = walkexpr(call, init)
|
||||
return call
|
||||
}
|
||||
|
||||
// substArgTypes substitutes the given list of types for
|
||||
@ -4011,7 +4041,7 @@ func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
|
||||
walk(n.Left)
|
||||
}
|
||||
case OCONVNOP:
|
||||
if n.Left.Type.Etype == TUNSAFEPTR {
|
||||
if n.Left.Type.IsUnsafePtr() {
|
||||
n.Left = cheapexpr(n.Left, init)
|
||||
originals = append(originals, convnop(n.Left, types.Types[TUNSAFEPTR]))
|
||||
}
|
||||
|
@ -629,23 +629,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = r
|
||||
|
||||
case ssa.OpPPC64MaskIfNotCarry:
|
||||
r := v.Reg()
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = ppc64.REGZERO
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = r
|
||||
|
||||
case ssa.OpPPC64ADDconstForCarry:
|
||||
r1 := v.Args[0].Reg()
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.Reg = r1
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = v.AuxInt
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = ppc64.REGTMP // Ignored; this is for the carry effect.
|
||||
|
||||
case ssa.OpPPC64NEG, ssa.OpPPC64FNEG, ssa.OpPPC64FSQRT, ssa.OpPPC64FSQRTS, ssa.OpPPC64FFLOOR, ssa.OpPPC64FTRUNC, ssa.OpPPC64FCEIL,
|
||||
ssa.OpPPC64FCTIDZ, ssa.OpPPC64FCTIWZ, ssa.OpPPC64FCFID, ssa.OpPPC64FCFIDS, ssa.OpPPC64FRSP, ssa.OpPPC64CNTLZD, ssa.OpPPC64CNTLZW,
|
||||
ssa.OpPPC64POPCNTD, ssa.OpPPC64POPCNTW, ssa.OpPPC64POPCNTB, ssa.OpPPC64MFVSRD, ssa.OpPPC64MTVSRD, ssa.OpPPC64FABS, ssa.OpPPC64FNABS,
|
||||
@ -666,6 +649,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
|
||||
case ssa.OpPPC64SUBFCconst:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: v.AuxInt})
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = v.Args[0].Reg()
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
|
||||
case ssa.OpPPC64ANDCCconst:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.Reg = v.Args[0].Reg()
|
||||
@ -1802,7 +1793,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
v.Fatalf("Pseudo-op should not make it to codegen: %s ###\n", v.LongString())
|
||||
case ssa.OpPPC64InvertFlags:
|
||||
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
|
||||
case ssa.OpPPC64FlagEQ, ssa.OpPPC64FlagLT, ssa.OpPPC64FlagGT, ssa.OpPPC64FlagCarrySet, ssa.OpPPC64FlagCarryClear:
|
||||
case ssa.OpPPC64FlagEQ, ssa.OpPPC64FlagLT, ssa.OpPPC64FlagGT:
|
||||
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
|
||||
case ssa.OpClobber:
|
||||
// TODO: implement for clobberdead experiment. Nop is ok for now.
|
||||
|
@ -338,8 +338,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
n.To.Reg = dividend
|
||||
}
|
||||
|
||||
j.To.Val = n
|
||||
j2.To.Val = s.Pc()
|
||||
j.To.SetTarget(n)
|
||||
j2.To.SetTarget(s.Pc())
|
||||
}
|
||||
case ssa.OpS390XADDconst, ssa.OpS390XADDWconst:
|
||||
opregregimm(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt)
|
||||
|
@ -7,12 +7,14 @@ package ssa
|
||||
// addressingModes combines address calculations into memory operations
|
||||
// that can perform complicated addressing modes.
|
||||
func addressingModes(f *Func) {
|
||||
isInImmediateRange := is32Bit
|
||||
switch f.Config.arch {
|
||||
default:
|
||||
// Most architectures can't do this.
|
||||
return
|
||||
case "amd64", "386":
|
||||
// TODO: s390x?
|
||||
case "s390x":
|
||||
isInImmediateRange = is20Bit
|
||||
}
|
||||
|
||||
var tmp []*Value
|
||||
@ -40,7 +42,7 @@ func addressingModes(f *Func) {
|
||||
switch [2]auxType{opcodeTable[v.Op].auxType, opcodeTable[p.Op].auxType} {
|
||||
case [2]auxType{auxSymOff, auxInt32}:
|
||||
// TODO: introduce auxSymOff32
|
||||
if !is32Bit(v.AuxInt + p.AuxInt) {
|
||||
if !isInImmediateRange(v.AuxInt + p.AuxInt) {
|
||||
continue
|
||||
}
|
||||
v.AuxInt += p.AuxInt
|
||||
@ -48,7 +50,7 @@ func addressingModes(f *Func) {
|
||||
if v.Aux != nil && p.Aux != nil {
|
||||
continue
|
||||
}
|
||||
if !is32Bit(v.AuxInt + p.AuxInt) {
|
||||
if !isInImmediateRange(v.AuxInt + p.AuxInt) {
|
||||
continue
|
||||
}
|
||||
if p.Aux != nil {
|
||||
@ -398,4 +400,61 @@ var combine = map[[2]Op]Op{
|
||||
[2]Op{Op386ANDLconstmodify, Op386LEAL4}: Op386ANDLconstmodifyidx4,
|
||||
[2]Op{Op386ORLconstmodify, Op386LEAL4}: Op386ORLconstmodifyidx4,
|
||||
[2]Op{Op386XORLconstmodify, Op386LEAL4}: Op386XORLconstmodifyidx4,
|
||||
|
||||
// s390x
|
||||
[2]Op{OpS390XMOVDload, OpS390XADD}: OpS390XMOVDloadidx,
|
||||
[2]Op{OpS390XMOVWload, OpS390XADD}: OpS390XMOVWloadidx,
|
||||
[2]Op{OpS390XMOVHload, OpS390XADD}: OpS390XMOVHloadidx,
|
||||
[2]Op{OpS390XMOVBload, OpS390XADD}: OpS390XMOVBloadidx,
|
||||
|
||||
[2]Op{OpS390XMOVWZload, OpS390XADD}: OpS390XMOVWZloadidx,
|
||||
[2]Op{OpS390XMOVHZload, OpS390XADD}: OpS390XMOVHZloadidx,
|
||||
[2]Op{OpS390XMOVBZload, OpS390XADD}: OpS390XMOVBZloadidx,
|
||||
|
||||
[2]Op{OpS390XMOVDBRload, OpS390XADD}: OpS390XMOVDBRloadidx,
|
||||
[2]Op{OpS390XMOVWBRload, OpS390XADD}: OpS390XMOVWBRloadidx,
|
||||
[2]Op{OpS390XMOVHBRload, OpS390XADD}: OpS390XMOVHBRloadidx,
|
||||
|
||||
[2]Op{OpS390XFMOVDload, OpS390XADD}: OpS390XFMOVDloadidx,
|
||||
[2]Op{OpS390XFMOVSload, OpS390XADD}: OpS390XFMOVSloadidx,
|
||||
|
||||
[2]Op{OpS390XMOVDstore, OpS390XADD}: OpS390XMOVDstoreidx,
|
||||
[2]Op{OpS390XMOVWstore, OpS390XADD}: OpS390XMOVWstoreidx,
|
||||
[2]Op{OpS390XMOVHstore, OpS390XADD}: OpS390XMOVHstoreidx,
|
||||
[2]Op{OpS390XMOVBstore, OpS390XADD}: OpS390XMOVBstoreidx,
|
||||
|
||||
[2]Op{OpS390XMOVDBRstore, OpS390XADD}: OpS390XMOVDBRstoreidx,
|
||||
[2]Op{OpS390XMOVWBRstore, OpS390XADD}: OpS390XMOVWBRstoreidx,
|
||||
[2]Op{OpS390XMOVHBRstore, OpS390XADD}: OpS390XMOVHBRstoreidx,
|
||||
|
||||
[2]Op{OpS390XFMOVDstore, OpS390XADD}: OpS390XFMOVDstoreidx,
|
||||
[2]Op{OpS390XFMOVSstore, OpS390XADD}: OpS390XFMOVSstoreidx,
|
||||
|
||||
[2]Op{OpS390XMOVDload, OpS390XMOVDaddridx}: OpS390XMOVDloadidx,
|
||||
[2]Op{OpS390XMOVWload, OpS390XMOVDaddridx}: OpS390XMOVWloadidx,
|
||||
[2]Op{OpS390XMOVHload, OpS390XMOVDaddridx}: OpS390XMOVHloadidx,
|
||||
[2]Op{OpS390XMOVBload, OpS390XMOVDaddridx}: OpS390XMOVBloadidx,
|
||||
|
||||
[2]Op{OpS390XMOVWZload, OpS390XMOVDaddridx}: OpS390XMOVWZloadidx,
|
||||
[2]Op{OpS390XMOVHZload, OpS390XMOVDaddridx}: OpS390XMOVHZloadidx,
|
||||
[2]Op{OpS390XMOVBZload, OpS390XMOVDaddridx}: OpS390XMOVBZloadidx,
|
||||
|
||||
[2]Op{OpS390XMOVDBRload, OpS390XMOVDaddridx}: OpS390XMOVDBRloadidx,
|
||||
[2]Op{OpS390XMOVWBRload, OpS390XMOVDaddridx}: OpS390XMOVWBRloadidx,
|
||||
[2]Op{OpS390XMOVHBRload, OpS390XMOVDaddridx}: OpS390XMOVHBRloadidx,
|
||||
|
||||
[2]Op{OpS390XFMOVDload, OpS390XMOVDaddridx}: OpS390XFMOVDloadidx,
|
||||
[2]Op{OpS390XFMOVSload, OpS390XMOVDaddridx}: OpS390XFMOVSloadidx,
|
||||
|
||||
[2]Op{OpS390XMOVDstore, OpS390XMOVDaddridx}: OpS390XMOVDstoreidx,
|
||||
[2]Op{OpS390XMOVWstore, OpS390XMOVDaddridx}: OpS390XMOVWstoreidx,
|
||||
[2]Op{OpS390XMOVHstore, OpS390XMOVDaddridx}: OpS390XMOVHstoreidx,
|
||||
[2]Op{OpS390XMOVBstore, OpS390XMOVDaddridx}: OpS390XMOVBstoreidx,
|
||||
|
||||
[2]Op{OpS390XMOVDBRstore, OpS390XMOVDaddridx}: OpS390XMOVDBRstoreidx,
|
||||
[2]Op{OpS390XMOVWBRstore, OpS390XMOVDaddridx}: OpS390XMOVWBRstoreidx,
|
||||
[2]Op{OpS390XMOVHBRstore, OpS390XMOVDaddridx}: OpS390XMOVHBRstoreidx,
|
||||
|
||||
[2]Op{OpS390XFMOVDstore, OpS390XMOVDaddridx}: OpS390XFMOVDstoreidx,
|
||||
[2]Op{OpS390XFMOVSstore, OpS390XMOVDaddridx}: OpS390XFMOVSstoreidx,
|
||||
}
|
||||
|
@ -171,10 +171,10 @@ func checkFunc(f *Func) {
|
||||
canHaveAuxInt = true
|
||||
canHaveAux = true
|
||||
case auxCCop:
|
||||
if _, ok := v.Aux.(Op); !ok {
|
||||
f.Fatalf("bad type %T for CCop in %v", v.Aux, v)
|
||||
if opcodeTable[Op(v.AuxInt)].name == "OpInvalid" {
|
||||
f.Fatalf("value %v has an AuxInt value that is a valid opcode", v)
|
||||
}
|
||||
canHaveAux = true
|
||||
canHaveAuxInt = true
|
||||
case auxS390XCCMask:
|
||||
if _, ok := v.Aux.(s390x.CCMask); !ok {
|
||||
f.Fatalf("bad type %T for S390XCCMask in %v", v.Aux, v)
|
||||
|
@ -23,9 +23,11 @@ func decomposeBuiltIn(f *Func) {
|
||||
}
|
||||
|
||||
// Decompose other values
|
||||
applyRewrite(f, rewriteBlockdec, rewriteValuedec)
|
||||
// Note: deadcode is false because we need to keep the original
|
||||
// values around so the name component resolution below can still work.
|
||||
applyRewrite(f, rewriteBlockdec, rewriteValuedec, leaveDeadValues)
|
||||
if f.Config.RegSize == 4 {
|
||||
applyRewrite(f, rewriteBlockdec64, rewriteValuedec64)
|
||||
applyRewrite(f, rewriteBlockdec64, rewriteValuedec64, leaveDeadValues)
|
||||
}
|
||||
|
||||
// Split up named values into their components.
|
||||
@ -139,7 +141,7 @@ func decomposeStringPhi(v *Value) {
|
||||
|
||||
func decomposeSlicePhi(v *Value) {
|
||||
types := &v.Block.Func.Config.Types
|
||||
ptrType := types.BytePtr
|
||||
ptrType := v.Type.Elem().PtrTo()
|
||||
lenType := types.Int
|
||||
|
||||
ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
|
||||
@ -215,7 +217,7 @@ func decomposeInterfacePhi(v *Value) {
|
||||
}
|
||||
|
||||
func decomposeArgs(f *Func) {
|
||||
applyRewrite(f, rewriteBlockdecArgs, rewriteValuedecArgs)
|
||||
applyRewrite(f, rewriteBlockdecArgs, rewriteValuedecArgs, removeDeadValues)
|
||||
}
|
||||
|
||||
func decomposeUser(f *Func) {
|
||||
|
@ -257,6 +257,49 @@ func (f *Func) LogStat(key string, args ...interface{}) {
|
||||
f.Warnl(f.Entry.Pos, "\t%s\t%s%s\t%s", n, key, value, f.Name)
|
||||
}
|
||||
|
||||
// unCacheLine removes v from f's constant cache "line" for aux,
|
||||
// resets v.InCache when it is found (and removed),
|
||||
// and returns whether v was found in that line.
|
||||
func (f *Func) unCacheLine(v *Value, aux int64) bool {
|
||||
vv := f.constants[aux]
|
||||
for i, cv := range vv {
|
||||
if v == cv {
|
||||
vv[i] = vv[len(vv)-1]
|
||||
vv[len(vv)-1] = nil
|
||||
f.constants[aux] = vv[0 : len(vv)-1]
|
||||
v.InCache = false
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// unCache removes v from f's constant cache.
|
||||
func (f *Func) unCache(v *Value) {
|
||||
if v.InCache {
|
||||
aux := v.AuxInt
|
||||
if f.unCacheLine(v, aux) {
|
||||
return
|
||||
}
|
||||
if aux == 0 {
|
||||
switch v.Op {
|
||||
case OpConstNil:
|
||||
aux = constNilMagic
|
||||
case OpConstSlice:
|
||||
aux = constSliceMagic
|
||||
case OpConstString:
|
||||
aux = constEmptyStringMagic
|
||||
case OpConstInterface:
|
||||
aux = constInterfaceMagic
|
||||
}
|
||||
if aux != 0 && f.unCacheLine(v, aux) {
|
||||
return
|
||||
}
|
||||
}
|
||||
f.Fatalf("unCached value %s not found in cache, auxInt=0x%x, adjusted aux=0x%x", v.LongString(), v.AuxInt, aux)
|
||||
}
|
||||
}
|
||||
|
||||
// freeValue frees a value. It must no longer be referenced or have any args.
|
||||
func (f *Func) freeValue(v *Value) {
|
||||
if v.Block == nil {
|
||||
@ -270,19 +313,8 @@ func (f *Func) freeValue(v *Value) {
|
||||
}
|
||||
// Clear everything but ID (which we reuse).
|
||||
id := v.ID
|
||||
|
||||
// Values with zero arguments and OpOffPtr values might be cached, so remove them there.
|
||||
nArgs := opcodeTable[v.Op].argLen
|
||||
if nArgs == 0 || v.Op == OpOffPtr {
|
||||
vv := f.constants[v.AuxInt]
|
||||
for i, cv := range vv {
|
||||
if v == cv {
|
||||
vv[i] = vv[len(vv)-1]
|
||||
vv[len(vv)-1] = nil
|
||||
f.constants[v.AuxInt] = vv[0 : len(vv)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
if v.InCache {
|
||||
f.unCache(v)
|
||||
}
|
||||
*v = Value{}
|
||||
v.ID = id
|
||||
@ -548,6 +580,7 @@ func (f *Func) constVal(op Op, t *types.Type, c int64, setAuxInt bool) *Value {
|
||||
v = f.Entry.NewValue0(src.NoXPos, op, t)
|
||||
}
|
||||
f.constants[c] = append(vv, v)
|
||||
v.InCache = true
|
||||
return v
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -132,65 +132,65 @@
|
||||
// we compare to 64 to ensure Go semantics for large shifts
|
||||
// Rules about rotates with non-const shift are based on the following rules,
|
||||
// if the following rules change, please also modify the rules based on them.
|
||||
(Lsh64x64 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Lsh64x32 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Lsh64x16 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Lsh64x8 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
(Lsh64x64 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Lsh64x32 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Lsh64x16 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Lsh64x8 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
|
||||
(Lsh32x64 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Lsh32x32 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Lsh32x16 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Lsh32x8 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
(Lsh32x64 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Lsh32x32 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Lsh32x16 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Lsh32x8 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
|
||||
(Lsh16x64 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Lsh16x32 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Lsh16x16 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Lsh16x8 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
(Lsh16x64 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Lsh16x32 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Lsh16x16 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Lsh16x8 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
|
||||
(Lsh8x64 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Lsh8x32 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Lsh8x16 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Lsh8x8 <t> x y) => (CSEL {OpARM64LessThanU} (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
(Lsh8x64 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Lsh8x32 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Lsh8x16 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Lsh8x8 <t> x y) => (CSEL [OpARM64LessThanU] (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
|
||||
(Rsh64Ux64 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Rsh64Ux32 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Rsh64Ux16 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Rsh64Ux8 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
(Rsh64Ux64 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Rsh64Ux32 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Rsh64Ux16 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Rsh64Ux8 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
|
||||
(Rsh32Ux64 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt32to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Rsh32Ux32 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt32to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Rsh32Ux16 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt32to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Rsh32Ux8 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt32to64 x) (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
(Rsh32Ux64 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt32to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Rsh32Ux32 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt32to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Rsh32Ux16 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt32to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Rsh32Ux8 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt32to64 x) (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
|
||||
(Rsh16Ux64 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt16to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Rsh16Ux32 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt16to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Rsh16Ux16 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt16to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Rsh16Ux8 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt16to64 x) (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
(Rsh16Ux64 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt16to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Rsh16Ux32 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt16to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Rsh16Ux16 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt16to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Rsh16Ux8 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt16to64 x) (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
|
||||
(Rsh8Ux64 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt8to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Rsh8Ux32 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt8to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Rsh8Ux16 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt8to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Rsh8Ux8 <t> x y) => (CSEL {OpARM64LessThanU} (SRL <t> (ZeroExt8to64 x) (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
(Rsh8Ux64 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt8to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
|
||||
(Rsh8Ux32 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt8to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
|
||||
(Rsh8Ux16 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt8to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
|
||||
(Rsh8Ux8 <t> x y) => (CSEL [OpARM64LessThanU] (SRL <t> (ZeroExt8to64 x) (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
|
||||
|
||||
(Rsh64x64 x y) => (SRA x (CSEL {OpARM64LessThanU} <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
|
||||
(Rsh64x32 x y) => (SRA x (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
|
||||
(Rsh64x16 x y) => (SRA x (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
|
||||
(Rsh64x8 x y) => (SRA x (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
|
||||
(Rsh64x64 x y) => (SRA x (CSEL [OpARM64LessThanU] <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
|
||||
(Rsh64x32 x y) => (SRA x (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
|
||||
(Rsh64x16 x y) => (SRA x (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
|
||||
(Rsh64x8 x y) => (SRA x (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
|
||||
|
||||
(Rsh32x64 x y) => (SRA (SignExt32to64 x) (CSEL {OpARM64LessThanU} <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
|
||||
(Rsh32x32 x y) => (SRA (SignExt32to64 x) (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
|
||||
(Rsh32x16 x y) => (SRA (SignExt32to64 x) (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
|
||||
(Rsh32x8 x y) => (SRA (SignExt32to64 x) (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
|
||||
(Rsh32x64 x y) => (SRA (SignExt32to64 x) (CSEL [OpARM64LessThanU] <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
|
||||
(Rsh32x32 x y) => (SRA (SignExt32to64 x) (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
|
||||
(Rsh32x16 x y) => (SRA (SignExt32to64 x) (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
|
||||
(Rsh32x8 x y) => (SRA (SignExt32to64 x) (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
|
||||
|
||||
(Rsh16x64 x y) => (SRA (SignExt16to64 x) (CSEL {OpARM64LessThanU} <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
|
||||
(Rsh16x32 x y) => (SRA (SignExt16to64 x) (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
|
||||
(Rsh16x16 x y) => (SRA (SignExt16to64 x) (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
|
||||
(Rsh16x8 x y) => (SRA (SignExt16to64 x) (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
|
||||
(Rsh16x64 x y) => (SRA (SignExt16to64 x) (CSEL [OpARM64LessThanU] <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
|
||||
(Rsh16x32 x y) => (SRA (SignExt16to64 x) (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
|
||||
(Rsh16x16 x y) => (SRA (SignExt16to64 x) (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
|
||||
(Rsh16x8 x y) => (SRA (SignExt16to64 x) (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
|
||||
|
||||
(Rsh8x64 x y) => (SRA (SignExt8to64 x) (CSEL {OpARM64LessThanU} <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
|
||||
(Rsh8x32 x y) => (SRA (SignExt8to64 x) (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
|
||||
(Rsh8x16 x y) => (SRA (SignExt8to64 x) (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
|
||||
(Rsh8x8 x y) => (SRA (SignExt8to64 x) (CSEL {OpARM64LessThanU} <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
|
||||
(Rsh8x64 x y) => (SRA (SignExt8to64 x) (CSEL [OpARM64LessThanU] <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
|
||||
(Rsh8x32 x y) => (SRA (SignExt8to64 x) (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
|
||||
(Rsh8x16 x y) => (SRA (SignExt8to64 x) (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
|
||||
(Rsh8x8 x y) => (SRA (SignExt8to64 x) (CSEL [OpARM64LessThanU] <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
|
||||
|
||||
// constants
|
||||
(Const(64|32|16|8) [val]) => (MOVDconst [int64(val)])
|
||||
@ -315,8 +315,8 @@
|
||||
(FCMPD (FMOVDconst [0]) x) => (InvertFlags (FCMPD0 x))
|
||||
|
||||
// CSEL needs a flag-generating argument. Synthesize a CMPW if necessary.
|
||||
(CondSelect x y boolval) && flagArg(boolval) != nil => (CSEL {boolval.Op} x y flagArg(boolval))
|
||||
(CondSelect x y boolval) && flagArg(boolval) == nil => (CSEL {OpARM64NotEqual} x y (CMPWconst [0] boolval))
|
||||
(CondSelect x y boolval) && flagArg(boolval) != nil => (CSEL [boolval.Op] x y flagArg(boolval))
|
||||
(CondSelect x y boolval) && flagArg(boolval) == nil => (CSEL [OpARM64NotEqual] x y (CMPWconst [0] boolval))
|
||||
|
||||
(OffPtr [off] ptr:(SP)) && is32Bit(off) => (MOVDaddr [int32(off)] ptr)
|
||||
(OffPtr [off] ptr) => (ADDconst [off] ptr)
|
||||
@ -1324,8 +1324,8 @@
|
||||
(XOR x (MVN y)) -> (EON x y)
|
||||
(OR x (MVN y)) -> (ORN x y)
|
||||
(MVN (XOR x y)) -> (EON x y)
|
||||
(CSEL {cc} x (MOVDconst [0]) flag) -> (CSEL0 {cc} x flag)
|
||||
(CSEL {cc} (MOVDconst [0]) y flag) -> (CSEL0 {arm64Negate(cc.(Op))} y flag)
|
||||
(CSEL [cc] x (MOVDconst [0]) flag) => (CSEL0 [cc] x flag)
|
||||
(CSEL [cc] (MOVDconst [0]) y flag) => (CSEL0 [arm64Negate(cc)] y flag)
|
||||
(SUB x (SUB y z)) -> (SUB (ADD <v.Type> x z) y)
|
||||
(SUB (SUB x y) z) -> (SUB x (ADD <y.Type> y z))
|
||||
|
||||
@ -1481,8 +1481,8 @@
|
||||
(GTnoov (InvertFlags cmp) yes no) => (LTnoov cmp yes no)
|
||||
|
||||
// absorb InvertFlags into CSEL(0)
|
||||
(CSEL {cc} x y (InvertFlags cmp)) => (CSEL {arm64Invert(cc)} x y cmp)
|
||||
(CSEL0 {cc} x (InvertFlags cmp)) => (CSEL0 {arm64Invert(cc)} x cmp)
|
||||
(CSEL [cc] x y (InvertFlags cmp)) => (CSEL [arm64Invert(cc)] x y cmp)
|
||||
(CSEL0 [cc] x (InvertFlags cmp)) => (CSEL0 [arm64Invert(cc)] x cmp)
|
||||
|
||||
// absorb flag constants into boolean values
|
||||
(Equal (FlagConstant [fc])) => (MOVDconst [b2i(fc.eq())])
|
||||
@ -1517,20 +1517,20 @@
|
||||
(MOVBUreg x) && x.Type.IsBoolean() => (MOVDreg x)
|
||||
|
||||
// absorb flag constants into conditional instructions
|
||||
(CSEL {cc} x _ flag) && ccARM64Eval(cc, flag) > 0 => x
|
||||
(CSEL {cc} _ y flag) && ccARM64Eval(cc, flag) < 0 => y
|
||||
(CSEL0 {cc} x flag) && ccARM64Eval(cc, flag) > 0 => x
|
||||
(CSEL0 {cc} _ flag) && ccARM64Eval(cc, flag) < 0 => (MOVDconst [0])
|
||||
(CSEL [cc] x _ flag) && ccARM64Eval(cc, flag) > 0 => x
|
||||
(CSEL [cc] _ y flag) && ccARM64Eval(cc, flag) < 0 => y
|
||||
(CSEL0 [cc] x flag) && ccARM64Eval(cc, flag) > 0 => x
|
||||
(CSEL0 [cc] _ flag) && ccARM64Eval(cc, flag) < 0 => (MOVDconst [0])
|
||||
|
||||
// absorb flags back into boolean CSEL
|
||||
(CSEL {cc} x y (CMPWconst [0] boolval)) && cc == OpARM64NotEqual && flagArg(boolval) != nil =>
|
||||
(CSEL {boolval.Op} x y flagArg(boolval))
|
||||
(CSEL {cc} x y (CMPWconst [0] boolval)) && cc == OpARM64Equal && flagArg(boolval) != nil =>
|
||||
(CSEL {arm64Negate(boolval.Op)} x y flagArg(boolval))
|
||||
(CSEL0 {cc} x (CMPWconst [0] boolval)) && cc == OpARM64NotEqual && flagArg(boolval) != nil =>
|
||||
(CSEL0 {boolval.Op} x flagArg(boolval))
|
||||
(CSEL0 {cc} x (CMPWconst [0] boolval)) && cc == OpARM64Equal && flagArg(boolval) != nil =>
|
||||
(CSEL0 {arm64Negate(boolval.Op)} x flagArg(boolval))
|
||||
(CSEL [cc] x y (CMPWconst [0] boolval)) && cc == OpARM64NotEqual && flagArg(boolval) != nil =>
|
||||
(CSEL [boolval.Op] x y flagArg(boolval))
|
||||
(CSEL [cc] x y (CMPWconst [0] boolval)) && cc == OpARM64Equal && flagArg(boolval) != nil =>
|
||||
(CSEL [arm64Negate(boolval.Op)] x y flagArg(boolval))
|
||||
(CSEL0 [cc] x (CMPWconst [0] boolval)) && cc == OpARM64NotEqual && flagArg(boolval) != nil =>
|
||||
(CSEL0 [boolval.Op] x flagArg(boolval))
|
||||
(CSEL0 [cc] x (CMPWconst [0] boolval)) && cc == OpARM64Equal && flagArg(boolval) != nil =>
|
||||
(CSEL0 [arm64Negate(boolval.Op)] x flagArg(boolval))
|
||||
|
||||
// absorb shifts into ops
|
||||
(NEG x:(SLLconst [c] y)) && clobberIfDead(x) => (NEGshiftLL [c] y)
|
||||
@ -1691,11 +1691,11 @@
|
||||
// "|" can also be "^" or "+".
|
||||
// As arm64 does not have a ROL instruction, so ROL(x, y) is replaced by ROR(x, -y).
|
||||
((ADD|OR|XOR) (SLL x (ANDconst <t> [63] y))
|
||||
(CSEL0 <typ.UInt64> {cc} (SRL <typ.UInt64> x (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y)))
|
||||
(CSEL0 <typ.UInt64> [cc] (SRL <typ.UInt64> x (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y)))
|
||||
(CMPconst [64] (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y))))) && cc == OpARM64LessThanU
|
||||
=> (ROR x (NEG <t> y))
|
||||
((ADD|OR|XOR) (SRL <typ.UInt64> x (ANDconst <t> [63] y))
|
||||
(CSEL0 <typ.UInt64> {cc} (SLL x (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y)))
|
||||
(CSEL0 <typ.UInt64> [cc] (SLL x (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y)))
|
||||
(CMPconst [64] (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y))))) && cc == OpARM64LessThanU
|
||||
=> (ROR x y)
|
||||
|
||||
@ -1705,11 +1705,11 @@
|
||||
// "|" can also be "^" or "+".
|
||||
// As arm64 does not have a ROLW instruction, so ROLW(x, y) is replaced by RORW(x, -y).
|
||||
((ADD|OR|XOR) (SLL x (ANDconst <t> [31] y))
|
||||
(CSEL0 <typ.UInt32> {cc} (SRL <typ.UInt32> (MOVWUreg x) (SUB <t> (MOVDconst [32]) (ANDconst <t> [31] y)))
|
||||
(CSEL0 <typ.UInt32> [cc] (SRL <typ.UInt32> (MOVWUreg x) (SUB <t> (MOVDconst [32]) (ANDconst <t> [31] y)))
|
||||
(CMPconst [64] (SUB <t> (MOVDconst [32]) (ANDconst <t> [31] y))))) && cc == OpARM64LessThanU
|
||||
=> (RORW x (NEG <t> y))
|
||||
((ADD|OR|XOR) (SRL <typ.UInt32> (MOVWUreg x) (ANDconst <t> [31] y))
|
||||
(CSEL0 <typ.UInt32> {cc} (SLL x (SUB <t> (MOVDconst [32]) (ANDconst <t> [31] y)))
|
||||
(CSEL0 <typ.UInt32> [cc] (SLL x (SUB <t> (MOVDconst [32]) (ANDconst <t> [31] y)))
|
||||
(CMPconst [64] (SUB <t> (MOVDconst [32]) (ANDconst <t> [31] y))))) && cc == OpARM64LessThanU
|
||||
=> (RORW x y)
|
||||
|
||||
|
@ -467,8 +467,8 @@ func init() {
|
||||
|
||||
// conditional instructions; auxint is
|
||||
// one of the arm64 comparison pseudo-ops (LessThan, LessThanU, etc.)
|
||||
{name: "CSEL", argLength: 3, reg: gp2flags1, asm: "CSEL", aux: "CCop"}, // aux(flags) ? arg0 : arg1
|
||||
{name: "CSEL0", argLength: 2, reg: gp1flags1, asm: "CSEL", aux: "CCop"}, // aux(flags) ? arg0 : 0
|
||||
{name: "CSEL", argLength: 3, reg: gp2flags1, asm: "CSEL", aux: "CCop"}, // auxint(flags) ? arg0 : arg1
|
||||
{name: "CSEL0", argLength: 2, reg: gp1flags1, asm: "CSEL", aux: "CCop"}, // auxint(flags) ? arg0 : 0
|
||||
|
||||
// function calls
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
|
@ -110,13 +110,21 @@
|
||||
// Rotate generation with non-const shift
|
||||
// these match patterns from math/bits/RotateLeft[32|64], but there could be others
|
||||
(ADD (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
|
||||
(ADD (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
|
||||
( OR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
|
||||
( OR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
|
||||
(XOR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
|
||||
(XOR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
|
||||
|
||||
|
||||
(ADD (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
|
||||
(ADD (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
|
||||
( OR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
|
||||
( OR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
|
||||
(XOR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
|
||||
(XOR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
|
||||
|
||||
|
||||
// Lowering rotates
|
||||
(RotateLeft32 x y) => (ROTLW x y)
|
||||
(RotateLeft64 x y) => (ROTL x y)
|
||||
@ -192,11 +200,15 @@
|
||||
(Rsh64Ux64 x (AND y (MOVDconst [63]))) => (SRD x (ANDconst <typ.Int64> [63] y))
|
||||
(Rsh64Ux64 x (ANDconst <typ.UInt> [63] y)) => (SRD x (ANDconst <typ.UInt> [63] y))
|
||||
(Rsh64Ux64 x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y))) => (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
|
||||
(Rsh64Ux64 x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))) => (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
(Rsh64Ux64 x (SUB <typ.UInt> (MOVDconst [64]) (AND <typ.UInt> y (MOVDconst [63])))) => (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
|
||||
(Rsh64Ux64 x (SUBFCconst <typ.UInt> [64] (AND <typ.UInt> y (MOVDconst [63])))) => (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
(Rsh64x64 x (AND y (MOVDconst [63]))) => (SRAD x (ANDconst <typ.Int64> [63] y))
|
||||
(Rsh64x64 x (ANDconst <typ.UInt> [63] y)) => (SRAD x (ANDconst <typ.UInt> [63] y))
|
||||
(Rsh64x64 x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y))) => (SRAD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
|
||||
(Rsh64x64 x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))) => (SRAD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
(Rsh64x64 x (SUB <typ.UInt> (MOVDconst [64]) (AND <typ.UInt> y (MOVDconst [63])))) => (SRAD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
|
||||
(Rsh64x64 x (SUBFCconst <typ.UInt> [64] (AND <typ.UInt> y (MOVDconst [63])))) => (SRAD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
|
||||
(Lsh64x64 x y) => (SLD x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [64]))))
|
||||
(Rsh64x64 x y) => (SRAD x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [64]))))
|
||||
@ -208,12 +220,16 @@
|
||||
(Rsh32Ux64 x (AND y (MOVDconst [31]))) => (SRW x (ANDconst <typ.Int32> [31] y))
|
||||
(Rsh32Ux64 x (ANDconst <typ.UInt> [31] y)) => (SRW x (ANDconst <typ.UInt> [31] y))
|
||||
(Rsh32Ux64 x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))) => (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
|
||||
(Rsh32Ux64 x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))) => (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
(Rsh32Ux64 x (SUB <typ.UInt> (MOVDconst [32]) (AND <typ.UInt> y (MOVDconst [31])))) => (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
|
||||
(Rsh32Ux64 x (SUBFCconst <typ.UInt> [32] (AND <typ.UInt> y (MOVDconst [31])))) => (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
|
||||
(Rsh32x64 x (AND y (MOVDconst [31]))) => (SRAW x (ANDconst <typ.Int32> [31] y))
|
||||
(Rsh32x64 x (ANDconst <typ.UInt> [31] y)) => (SRAW x (ANDconst <typ.UInt> [31] y))
|
||||
(Rsh32x64 x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))) => (SRAW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
|
||||
(Rsh32x64 x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))) => (SRAW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
(Rsh32x64 x (SUB <typ.UInt> (MOVDconst [32]) (AND <typ.UInt> y (MOVDconst [31])))) => (SRAW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
|
||||
(Rsh32x64 x (SUBFCconst <typ.UInt> [32] (AND <typ.UInt> y (MOVDconst [31])))) => (SRAW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
|
||||
(Rsh32x64 x y) => (SRAW x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [32]))))
|
||||
(Rsh32Ux64 x y) => (SRW x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [32]))))
|
||||
@ -276,18 +292,11 @@
|
||||
(Rsh8Ux8 x y) => (SRW (ZeroExt8to32 x) (ISEL [0] y (MOVDconst [-1]) (CMPU (ZeroExt8to64 y) (MOVDconst [8]))))
|
||||
(Lsh8x8 x y) => (SLW x (ISEL [0] y (MOVDconst [-1]) (CMPU (ZeroExt8to64 y) (MOVDconst [8]))))
|
||||
|
||||
// Cleaning up shift ops when input is masked
|
||||
(MaskIfNotCarry (ADDconstForCarry [c] (ANDconst [d] _))) && c < 0 && d > 0 && int64(c) + d < 0 => (MOVDconst [-1])
|
||||
// Cleaning up shift ops
|
||||
(ISEL [0] (ANDconst [d] y) (MOVDconst [-1]) (CMPU (ANDconst [d] y) (MOVDconst [c]))) && c >= d => (ANDconst [d] y)
|
||||
(ISEL [0] (ANDconst [d] y) (MOVDconst [-1]) (CMPUconst [c] (ANDconst [d] y))) && c >= d => (ANDconst [d] y)
|
||||
(ORN x (MOVDconst [-1])) => x
|
||||
|
||||
(ADDconstForCarry [c] (MOVDconst [d])) && c < 0 && (c < 0 || int64(c) + d >= 0) => (FlagCarryClear)
|
||||
(ADDconstForCarry [c] (MOVDconst [d])) && c < 0 && c >= 0 && int64(c) + d < 0 => (FlagCarrySet)
|
||||
|
||||
(MaskIfNotCarry (FlagCarrySet)) => (MOVDconst [0])
|
||||
(MaskIfNotCarry (FlagCarryClear)) => (MOVDconst [-1])
|
||||
|
||||
(S(RAD|RD|LD) x (MOVDconst [c])) => (S(RAD|RD|LD)const [c&63 | (c>>6&1*63)] x)
|
||||
(S(RAW|RW|LW) x (MOVDconst [c])) => (S(RAW|RW|LW)const [c&31 | (c>>5&1*31)] x)
|
||||
|
||||
@ -306,8 +315,8 @@
|
||||
(Ctz16 x) => (POPCNTW (MOVHZreg (ANDN <typ.Int16> (ADDconst <typ.Int16> [-1] x) x)))
|
||||
(Ctz8 x) => (POPCNTB (MOVBZreg (ANDN <typ.UInt8> (ADDconst <typ.UInt8> [-1] x) x)))
|
||||
|
||||
(BitLen64 x) => (SUB (MOVDconst [64]) (CNTLZD <typ.Int> x))
|
||||
(BitLen32 x) => (SUB (MOVDconst [32]) (CNTLZW <typ.Int> x))
|
||||
(BitLen64 x) => (SUBFCconst [64] (CNTLZD <typ.Int> x))
|
||||
(BitLen32 x) => (SUBFCconst [32] (CNTLZW <typ.Int> x))
|
||||
|
||||
(PopCount64 ...) => (POPCNTD ...)
|
||||
(PopCount32 x) => (POPCNTW (MOVWZreg x))
|
||||
@ -777,10 +786,19 @@
|
||||
(ADDconst [c] (ADDconst [d] x)) && is32Bit(c+d) => (ADDconst [c+d] x)
|
||||
(ADDconst [0] x) => x
|
||||
(SUB x (MOVDconst [c])) && is32Bit(-c) => (ADDconst [-c] x)
|
||||
// TODO deal with subtract-from-const
|
||||
|
||||
(ADDconst [c] (MOVDaddr [d] {sym} x)) && is32Bit(c+int64(d)) => (MOVDaddr [int32(c+int64(d))] {sym} x)
|
||||
|
||||
// Subtract from (with carry, but ignored) constant.
|
||||
// Note, these clobber the carry bit.
|
||||
(SUB (MOVDconst [c]) x) && is32Bit(c) => (SUBFCconst [c] x)
|
||||
(SUBFCconst [c] (NEG x)) => (ADDconst [c] x)
|
||||
(SUBFCconst [c] (SUBFCconst [d] x)) && is32Bit(c-d) => (ADDconst [c-d] x)
|
||||
(SUBFCconst [0] x) => (NEG x)
|
||||
(ADDconst [c] (SUBFCconst [d] x)) && is32Bit(c+d) => (SUBFCconst [c+d] x)
|
||||
(NEG (ADDconst [c] x)) && is32Bit(-c) => (SUBFCconst [-c] x)
|
||||
(NEG (SUBFCconst [c] x)) && is32Bit(-c) => (ADDconst [-c] x)
|
||||
|
||||
// Use register moves instead of stores and loads to move int<=>float values
|
||||
// Common with math Float64bits, Float64frombits
|
||||
(MOVDload [off] {sym} ptr (FMOVDstore [off] {sym} ptr x _)) => (MFVSRD x)
|
||||
|
@ -175,6 +175,7 @@ func init() {
|
||||
{name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true}, // arg0+arg1
|
||||
{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0+arg1
|
||||
{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0-arg1
|
||||
{name: "SUBFCconst", argLength: 1, reg: gp11, asm: "SUBC", aux: "Int64"}, // auxInt - arg0 (with carry)
|
||||
{name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"}, // arg0-arg1
|
||||
{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"}, // arg0-arg1
|
||||
|
||||
@ -206,9 +207,7 @@ func init() {
|
||||
{name: "ROTL", argLength: 2, reg: gp21, asm: "ROTL"}, // arg0 rotate left by arg1 mod 64
|
||||
{name: "ROTLW", argLength: 2, reg: gp21, asm: "ROTLW"}, // uint32(arg0) rotate left by arg1 mod 32
|
||||
|
||||
{name: "LoweredAdd64Carry", argLength: 3, reg: gp32, resultNotInArgs: true}, // arg0 + arg1 + carry, returns (sum, carry)
|
||||
{name: "ADDconstForCarry", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, aux: "Int16", asm: "ADDC", typ: "Flags"}, // _, carry := arg0 + auxint
|
||||
{name: "MaskIfNotCarry", argLength: 1, reg: crgp, asm: "ADDME", typ: "Int64"}, // carry - 1 (if carry then 0 else -1)
|
||||
{name: "LoweredAdd64Carry", argLength: 3, reg: gp32, resultNotInArgs: true}, // arg0 + arg1 + carry, returns (sum, carry)
|
||||
|
||||
{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
|
||||
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
|
||||
@ -674,11 +673,9 @@ func init() {
|
||||
|
||||
// These ops are for temporary use by rewrite rules. They
|
||||
// cannot appear in the generated assembly.
|
||||
{name: "FlagEQ"}, // equal
|
||||
{name: "FlagLT"}, // signed < or unsigned <
|
||||
{name: "FlagGT"}, // signed > or unsigned >
|
||||
{name: "FlagCarrySet"}, // carry flag set
|
||||
{name: "FlagCarryClear"}, // carry flag clear
|
||||
{name: "FlagEQ"}, // equal
|
||||
{name: "FlagLT"}, // signed < or unsigned <
|
||||
{name: "FlagGT"}, // signed > or unsigned >
|
||||
}
|
||||
|
||||
blocks := []blockData{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -66,14 +66,14 @@
|
||||
(Load <typ.Int>
|
||||
(OffPtr <typ.IntPtr> [2*config.PtrSize] ptr)
|
||||
mem))
|
||||
(Store dst (SliceMake ptr len cap) mem) =>
|
||||
(Store {t} dst (SliceMake ptr len cap) mem) =>
|
||||
(Store {typ.Int}
|
||||
(OffPtr <typ.IntPtr> [2*config.PtrSize] dst)
|
||||
cap
|
||||
(Store {typ.Int}
|
||||
(OffPtr <typ.IntPtr> [config.PtrSize] dst)
|
||||
len
|
||||
(Store {typ.BytePtr} dst ptr mem)))
|
||||
(Store {t.Elem().PtrTo()} dst ptr mem)))
|
||||
|
||||
// interface ops
|
||||
(ITab (IMake itab _)) => itab
|
||||
|
@ -1423,7 +1423,8 @@ func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxi
|
||||
|
||||
func opHasAuxInt(op opData) bool {
|
||||
switch op.aux {
|
||||
case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "TypSize", "ARM64BitField", "FlagConstant":
|
||||
case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64",
|
||||
"SymOff", "SymValAndOff", "TypSize", "ARM64BitField", "FlagConstant", "CCop":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -1431,7 +1432,7 @@ func opHasAuxInt(op opData) bool {
|
||||
|
||||
func opHasAux(op opData) bool {
|
||||
switch op.aux {
|
||||
case "String", "Sym", "SymOff", "SymValAndOff", "Typ", "TypSize", "CCop",
|
||||
case "String", "Sym", "SymOff", "SymValAndOff", "Typ", "TypSize",
|
||||
"S390XCCMask", "S390XRotateParams":
|
||||
return true
|
||||
}
|
||||
@ -1784,8 +1785,6 @@ func (op opData) auxType() string {
|
||||
return "s390x.CCMask"
|
||||
case "S390XRotateParams":
|
||||
return "s390x.RotateParams"
|
||||
case "CCop":
|
||||
return "CCop"
|
||||
default:
|
||||
return "invalid"
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ package ssa
|
||||
// convert to machine-dependent ops
|
||||
func lower(f *Func) {
|
||||
// repeat rewrites until we find no more rewrites
|
||||
applyRewrite(f, f.Config.lowerBlock, f.Config.lowerValue)
|
||||
applyRewrite(f, f.Config.lowerBlock, f.Config.lowerValue, removeDeadValues)
|
||||
}
|
||||
|
||||
// checkLower checks for unlowered opcodes and fails if we find one.
|
||||
|
@ -235,7 +235,7 @@ func nilcheckelim2(f *Func) {
|
||||
continue
|
||||
}
|
||||
if v.Type.IsMemory() || v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
|
||||
if v.Op == OpVarKill || v.Op == OpVarLive || (v.Op == OpVarDef && !v.Aux.(GCNode).Typ().HasHeapPointer()) {
|
||||
if v.Op == OpVarKill || v.Op == OpVarLive || (v.Op == OpVarDef && !v.Aux.(GCNode).Typ().HasPointers()) {
|
||||
// These ops don't really change memory.
|
||||
continue
|
||||
// Note: OpVarDef requires that the defined variable not have pointers.
|
||||
|
@ -1828,6 +1828,7 @@ const (
|
||||
OpPPC64FADD
|
||||
OpPPC64FADDS
|
||||
OpPPC64SUB
|
||||
OpPPC64SUBFCconst
|
||||
OpPPC64FSUB
|
||||
OpPPC64FSUBS
|
||||
OpPPC64MULLD
|
||||
@ -1853,8 +1854,6 @@ const (
|
||||
OpPPC64ROTL
|
||||
OpPPC64ROTLW
|
||||
OpPPC64LoweredAdd64Carry
|
||||
OpPPC64ADDconstForCarry
|
||||
OpPPC64MaskIfNotCarry
|
||||
OpPPC64SRADconst
|
||||
OpPPC64SRAWconst
|
||||
OpPPC64SRDconst
|
||||
@ -2027,8 +2026,6 @@ const (
|
||||
OpPPC64FlagEQ
|
||||
OpPPC64FlagLT
|
||||
OpPPC64FlagGT
|
||||
OpPPC64FlagCarrySet
|
||||
OpPPC64FlagCarryClear
|
||||
|
||||
OpRISCV64ADD
|
||||
OpRISCV64ADDI
|
||||
@ -24317,6 +24314,20 @@ var opcodeTable = [...]opInfo{
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SUBFCconst",
|
||||
auxType: auxInt64,
|
||||
argLen: 1,
|
||||
asm: ppc64.ASUBC,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "FSUB",
|
||||
argLen: 2,
|
||||
@ -24683,28 +24694,6 @@ var opcodeTable = [...]opInfo{
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ADDconstForCarry",
|
||||
auxType: auxInt16,
|
||||
argLen: 1,
|
||||
asm: ppc64.AADDC,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 2147483648, // R31
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MaskIfNotCarry",
|
||||
argLen: 1,
|
||||
asm: ppc64.AADDME,
|
||||
reg: regInfo{
|
||||
outputs: []outputInfo{
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SRADconst",
|
||||
auxType: auxInt64,
|
||||
@ -26964,16 +26953,6 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagCarrySet",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagCarryClear",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
|
||||
{
|
||||
name: "ADD",
|
||||
|
@ -6,5 +6,5 @@ package ssa
|
||||
|
||||
// machine-independent optimization
|
||||
func opt(f *Func) {
|
||||
applyRewrite(f, rewriteBlockgeneric, rewriteValuegeneric)
|
||||
applyRewrite(f, rewriteBlockgeneric, rewriteValuegeneric, removeDeadValues)
|
||||
}
|
||||
|
@ -588,7 +588,7 @@ func (s *regAllocState) init(f *Func) {
|
||||
if s.f.Config.hasGReg {
|
||||
s.allocatable &^= 1 << s.GReg
|
||||
}
|
||||
if s.f.Config.ctxt.Framepointer_enabled && s.f.Config.FPReg >= 0 {
|
||||
if objabi.Framepointer_enabled && s.f.Config.FPReg >= 0 {
|
||||
s.allocatable &^= 1 << uint(s.f.Config.FPReg)
|
||||
}
|
||||
if s.f.Config.LinkReg != -1 {
|
||||
|
@ -20,7 +20,15 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter) {
|
||||
type deadValueChoice bool
|
||||
|
||||
const (
|
||||
leaveDeadValues deadValueChoice = false
|
||||
removeDeadValues = true
|
||||
)
|
||||
|
||||
// deadcode indicates that rewrite should try to remove any values that become dead.
|
||||
func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValueChoice) {
|
||||
// repeat rewrites until we find no more rewrites
|
||||
pendingLines := f.cachedLineStarts // Holds statement boundaries that need to be moved to a new value/block
|
||||
pendingLines.clear()
|
||||
@ -56,6 +64,18 @@ func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter) {
|
||||
*v0 = *v
|
||||
v0.Args = append([]*Value{}, v.Args...) // make a new copy, not aliasing
|
||||
}
|
||||
if v.Uses == 0 && v.removeable() {
|
||||
if v.Op != OpInvalid && deadcode == removeDeadValues {
|
||||
// Reset any values that are now unused, so that we decrement
|
||||
// the use count of all of its arguments.
|
||||
// Not quite a deadcode pass, because it does not handle cycles.
|
||||
// But it should help Uses==1 rules to fire.
|
||||
v.reset(OpInvalid)
|
||||
change = true
|
||||
}
|
||||
// No point rewriting values which aren't used.
|
||||
continue
|
||||
}
|
||||
|
||||
vchange := phielimValue(v)
|
||||
if vchange && debug > 1 {
|
||||
@ -631,6 +651,10 @@ func auxIntToFlagConstant(x int64) flagConstant {
|
||||
return flagConstant(x)
|
||||
}
|
||||
|
||||
func auxIntToOp(cc int64) Op {
|
||||
return Op(cc)
|
||||
}
|
||||
|
||||
func boolToAuxInt(b bool) int64 {
|
||||
if b {
|
||||
return 1
|
||||
@ -674,6 +698,10 @@ func flagConstantToAuxInt(x flagConstant) int64 {
|
||||
return int64(x)
|
||||
}
|
||||
|
||||
func opToAuxInt(o Op) int64 {
|
||||
return int64(o)
|
||||
}
|
||||
|
||||
func auxToString(i interface{}) string {
|
||||
return i.(string)
|
||||
}
|
||||
@ -707,13 +735,6 @@ func s390xCCMaskToAux(c s390x.CCMask) interface{} {
|
||||
func s390xRotateParamsToAux(r s390x.RotateParams) interface{} {
|
||||
return r
|
||||
}
|
||||
func cCopToAux(o Op) interface{} {
|
||||
return o
|
||||
}
|
||||
|
||||
func auxToCCop(cc interface{}) Op {
|
||||
return cc.(Op)
|
||||
}
|
||||
|
||||
// uaddOvf reports whether unsigned a+b would overflow.
|
||||
func uaddOvf(a, b int64) bool {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -428,8 +428,6 @@ func rewriteValuePPC64(v *Value) bool {
|
||||
return rewriteValuePPC64_OpPPC64ADD(v)
|
||||
case OpPPC64ADDconst:
|
||||
return rewriteValuePPC64_OpPPC64ADDconst(v)
|
||||
case OpPPC64ADDconstForCarry:
|
||||
return rewriteValuePPC64_OpPPC64ADDconstForCarry(v)
|
||||
case OpPPC64AND:
|
||||
return rewriteValuePPC64_OpPPC64AND(v)
|
||||
case OpPPC64ANDN:
|
||||
@ -570,8 +568,8 @@ func rewriteValuePPC64(v *Value) bool {
|
||||
return rewriteValuePPC64_OpPPC64MOVWstorezero(v)
|
||||
case OpPPC64MTVSRD:
|
||||
return rewriteValuePPC64_OpPPC64MTVSRD(v)
|
||||
case OpPPC64MaskIfNotCarry:
|
||||
return rewriteValuePPC64_OpPPC64MaskIfNotCarry(v)
|
||||
case OpPPC64NEG:
|
||||
return rewriteValuePPC64_OpPPC64NEG(v)
|
||||
case OpPPC64NOR:
|
||||
return rewriteValuePPC64_OpPPC64NOR(v)
|
||||
case OpPPC64NotEqual:
|
||||
@ -600,6 +598,8 @@ func rewriteValuePPC64(v *Value) bool {
|
||||
return rewriteValuePPC64_OpPPC64SRW(v)
|
||||
case OpPPC64SUB:
|
||||
return rewriteValuePPC64_OpPPC64SUB(v)
|
||||
case OpPPC64SUBFCconst:
|
||||
return rewriteValuePPC64_OpPPC64SUBFCconst(v)
|
||||
case OpPPC64XOR:
|
||||
return rewriteValuePPC64_OpPPC64XOR(v)
|
||||
case OpPPC64XORconst:
|
||||
@ -1025,15 +1025,14 @@ func rewriteValuePPC64_OpBitLen32(v *Value) bool {
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (BitLen32 x)
|
||||
// result: (SUB (MOVDconst [32]) (CNTLZW <typ.Int> x))
|
||||
// result: (SUBFCconst [32] (CNTLZW <typ.Int> x))
|
||||
for {
|
||||
x := v_0
|
||||
v.reset(OpPPC64SUB)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
|
||||
v0.AuxInt = int64ToAuxInt(32)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64CNTLZW, typ.Int)
|
||||
v1.AddArg(x)
|
||||
v.AddArg2(v0, v1)
|
||||
v.reset(OpPPC64SUBFCconst)
|
||||
v.AuxInt = int64ToAuxInt(32)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64CNTLZW, typ.Int)
|
||||
v0.AddArg(x)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -1042,15 +1041,14 @@ func rewriteValuePPC64_OpBitLen64(v *Value) bool {
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (BitLen64 x)
|
||||
// result: (SUB (MOVDconst [64]) (CNTLZD <typ.Int> x))
|
||||
// result: (SUBFCconst [64] (CNTLZD <typ.Int> x))
|
||||
for {
|
||||
x := v_0
|
||||
v.reset(OpPPC64SUB)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
|
||||
v0.AuxInt = int64ToAuxInt(64)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64CNTLZD, typ.Int)
|
||||
v1.AddArg(x)
|
||||
v.AddArg2(v0, v1)
|
||||
v.reset(OpPPC64SUBFCconst)
|
||||
v.AuxInt = int64ToAuxInt(64)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64CNTLZD, typ.Int)
|
||||
v0.AddArg(x)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -3961,6 +3959,76 @@ func rewriteValuePPC64_OpPPC64ADD(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))))
|
||||
// result: (ROTL x y)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
if v_0.Op != OpPPC64SLD {
|
||||
continue
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
v_0_1 := v_0.Args[1]
|
||||
if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int64 || auxIntToInt64(v_0_1.AuxInt) != 63 {
|
||||
continue
|
||||
}
|
||||
y := v_0_1.Args[0]
|
||||
if v_1.Op != OpPPC64SRD {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
if x != v_1.Args[0] {
|
||||
continue
|
||||
}
|
||||
v_1_1 := v_1.Args[1]
|
||||
if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 64 {
|
||||
continue
|
||||
}
|
||||
v_1_1_0 := v_1_1.Args[0]
|
||||
if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 63 || y != v_1_1_0.Args[0] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64ROTL)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))))
|
||||
// result: (ROTLW x y)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
if v_0.Op != OpPPC64SLW {
|
||||
continue
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
v_0_1 := v_0.Args[1]
|
||||
if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int32 || auxIntToInt64(v_0_1.AuxInt) != 31 {
|
||||
continue
|
||||
}
|
||||
y := v_0_1.Args[0]
|
||||
if v_1.Op != OpPPC64SRW {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
if x != v_1.Args[0] {
|
||||
continue
|
||||
}
|
||||
v_1_1 := v_1.Args[1]
|
||||
if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 32 {
|
||||
continue
|
||||
}
|
||||
v_1_1_0 := v_1_1.Args[0]
|
||||
if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 31 || y != v_1_1_0.Args[0] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64ROTLW)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))))
|
||||
// result: (ROTLW x y)
|
||||
for {
|
||||
@ -4073,38 +4141,22 @@ func rewriteValuePPC64_OpPPC64ADDconst(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuePPC64_OpPPC64ADDconstForCarry(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (ADDconstForCarry [c] (MOVDconst [d]))
|
||||
// cond: c < 0 && (c < 0 || int64(c) + d >= 0)
|
||||
// result: (FlagCarryClear)
|
||||
// match: (ADDconst [c] (SUBFCconst [d] x))
|
||||
// cond: is32Bit(c+d)
|
||||
// result: (SUBFCconst [c+d] x)
|
||||
for {
|
||||
c := auxIntToInt16(v.AuxInt)
|
||||
if v_0.Op != OpPPC64MOVDconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpPPC64SUBFCconst {
|
||||
break
|
||||
}
|
||||
d := auxIntToInt64(v_0.AuxInt)
|
||||
if !(c < 0 && (c < 0 || int64(c)+d >= 0)) {
|
||||
x := v_0.Args[0]
|
||||
if !(is32Bit(c + d)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpPPC64FlagCarryClear)
|
||||
return true
|
||||
}
|
||||
// match: (ADDconstForCarry [c] (MOVDconst [d]))
|
||||
// cond: c < 0 && c >= 0 && int64(c) + d < 0
|
||||
// result: (FlagCarrySet)
|
||||
for {
|
||||
c := auxIntToInt16(v.AuxInt)
|
||||
if v_0.Op != OpPPC64MOVDconst {
|
||||
break
|
||||
}
|
||||
d := auxIntToInt64(v_0.AuxInt)
|
||||
if !(c < 0 && c >= 0 && int64(c)+d < 0) {
|
||||
break
|
||||
}
|
||||
v.reset(OpPPC64FlagCarrySet)
|
||||
v.reset(OpPPC64SUBFCconst)
|
||||
v.AuxInt = int64ToAuxInt(c + d)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -10374,46 +10426,40 @@ func rewriteValuePPC64_OpPPC64MTVSRD(v *Value) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuePPC64_OpPPC64MaskIfNotCarry(v *Value) bool {
|
||||
func rewriteValuePPC64_OpPPC64NEG(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MaskIfNotCarry (ADDconstForCarry [c] (ANDconst [d] _)))
|
||||
// cond: c < 0 && d > 0 && int64(c) + d < 0
|
||||
// result: (MOVDconst [-1])
|
||||
// match: (NEG (ADDconst [c] x))
|
||||
// cond: is32Bit(-c)
|
||||
// result: (SUBFCconst [-c] x)
|
||||
for {
|
||||
if v_0.Op != OpPPC64ADDconstForCarry {
|
||||
if v_0.Op != OpPPC64ADDconst {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt16(v_0.AuxInt)
|
||||
v_0_0 := v_0.Args[0]
|
||||
if v_0_0.Op != OpPPC64ANDconst {
|
||||
c := auxIntToInt64(v_0.AuxInt)
|
||||
x := v_0.Args[0]
|
||||
if !(is32Bit(-c)) {
|
||||
break
|
||||
}
|
||||
d := auxIntToInt64(v_0_0.AuxInt)
|
||||
if !(c < 0 && d > 0 && int64(c)+d < 0) {
|
||||
break
|
||||
}
|
||||
v.reset(OpPPC64MOVDconst)
|
||||
v.AuxInt = int64ToAuxInt(-1)
|
||||
v.reset(OpPPC64SUBFCconst)
|
||||
v.AuxInt = int64ToAuxInt(-c)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MaskIfNotCarry (FlagCarrySet))
|
||||
// result: (MOVDconst [0])
|
||||
// match: (NEG (SUBFCconst [c] x))
|
||||
// cond: is32Bit(-c)
|
||||
// result: (ADDconst [-c] x)
|
||||
for {
|
||||
if v_0.Op != OpPPC64FlagCarrySet {
|
||||
if v_0.Op != OpPPC64SUBFCconst {
|
||||
break
|
||||
}
|
||||
v.reset(OpPPC64MOVDconst)
|
||||
v.AuxInt = int64ToAuxInt(0)
|
||||
return true
|
||||
}
|
||||
// match: (MaskIfNotCarry (FlagCarryClear))
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
if v_0.Op != OpPPC64FlagCarryClear {
|
||||
c := auxIntToInt64(v_0.AuxInt)
|
||||
x := v_0.Args[0]
|
||||
if !(is32Bit(-c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpPPC64MOVDconst)
|
||||
v.AuxInt = int64ToAuxInt(-1)
|
||||
v.reset(OpPPC64ADDconst)
|
||||
v.AuxInt = int64ToAuxInt(-c)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -10592,6 +10638,76 @@ func rewriteValuePPC64_OpPPC64OR(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: ( OR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))))
|
||||
// result: (ROTL x y)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
if v_0.Op != OpPPC64SLD {
|
||||
continue
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
v_0_1 := v_0.Args[1]
|
||||
if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int64 || auxIntToInt64(v_0_1.AuxInt) != 63 {
|
||||
continue
|
||||
}
|
||||
y := v_0_1.Args[0]
|
||||
if v_1.Op != OpPPC64SRD {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
if x != v_1.Args[0] {
|
||||
continue
|
||||
}
|
||||
v_1_1 := v_1.Args[1]
|
||||
if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 64 {
|
||||
continue
|
||||
}
|
||||
v_1_1_0 := v_1_1.Args[0]
|
||||
if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 63 || y != v_1_1_0.Args[0] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64ROTL)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: ( OR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))))
|
||||
// result: (ROTLW x y)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
if v_0.Op != OpPPC64SLW {
|
||||
continue
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
v_0_1 := v_0.Args[1]
|
||||
if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int32 || auxIntToInt64(v_0_1.AuxInt) != 31 {
|
||||
continue
|
||||
}
|
||||
y := v_0_1.Args[0]
|
||||
if v_1.Op != OpPPC64SRW {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
if x != v_1.Args[0] {
|
||||
continue
|
||||
}
|
||||
v_1_1 := v_1.Args[1]
|
||||
if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 32 {
|
||||
continue
|
||||
}
|
||||
v_1_1_0 := v_1_1.Args[0]
|
||||
if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 31 || y != v_1_1_0.Args[0] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64ROTLW)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: ( OR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))))
|
||||
// result: (ROTLW x y)
|
||||
for {
|
||||
@ -12191,6 +12307,69 @@ func rewriteValuePPC64_OpPPC64SUB(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (SUB (MOVDconst [c]) x)
|
||||
// cond: is32Bit(c)
|
||||
// result: (SUBFCconst [c] x)
|
||||
for {
|
||||
if v_0.Op != OpPPC64MOVDconst {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_0.AuxInt)
|
||||
x := v_1
|
||||
if !(is32Bit(c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpPPC64SUBFCconst)
|
||||
v.AuxInt = int64ToAuxInt(c)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuePPC64_OpPPC64SUBFCconst(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (SUBFCconst [c] (NEG x))
|
||||
// result: (ADDconst [c] x)
|
||||
for {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpPPC64NEG {
|
||||
break
|
||||
}
|
||||
x := v_0.Args[0]
|
||||
v.reset(OpPPC64ADDconst)
|
||||
v.AuxInt = int64ToAuxInt(c)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (SUBFCconst [c] (SUBFCconst [d] x))
|
||||
// cond: is32Bit(c-d)
|
||||
// result: (ADDconst [c-d] x)
|
||||
for {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpPPC64SUBFCconst {
|
||||
break
|
||||
}
|
||||
d := auxIntToInt64(v_0.AuxInt)
|
||||
x := v_0.Args[0]
|
||||
if !(is32Bit(c - d)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpPPC64ADDconst)
|
||||
v.AuxInt = int64ToAuxInt(c - d)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (SUBFCconst [0] x)
|
||||
// result: (NEG x)
|
||||
for {
|
||||
if auxIntToInt64(v.AuxInt) != 0 {
|
||||
break
|
||||
}
|
||||
x := v_0
|
||||
v.reset(OpPPC64NEG)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuePPC64_OpPPC64XOR(v *Value) bool {
|
||||
@ -12286,6 +12465,76 @@ func rewriteValuePPC64_OpPPC64XOR(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (XOR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))))
|
||||
// result: (ROTL x y)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
if v_0.Op != OpPPC64SLD {
|
||||
continue
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
v_0_1 := v_0.Args[1]
|
||||
if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int64 || auxIntToInt64(v_0_1.AuxInt) != 63 {
|
||||
continue
|
||||
}
|
||||
y := v_0_1.Args[0]
|
||||
if v_1.Op != OpPPC64SRD {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
if x != v_1.Args[0] {
|
||||
continue
|
||||
}
|
||||
v_1_1 := v_1.Args[1]
|
||||
if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 64 {
|
||||
continue
|
||||
}
|
||||
v_1_1_0 := v_1_1.Args[0]
|
||||
if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 63 || y != v_1_1_0.Args[0] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64ROTL)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (XOR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))))
|
||||
// result: (ROTLW x y)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
if v_0.Op != OpPPC64SLW {
|
||||
continue
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
v_0_1 := v_0.Args[1]
|
||||
if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int32 || auxIntToInt64(v_0_1.AuxInt) != 31 {
|
||||
continue
|
||||
}
|
||||
y := v_0_1.Args[0]
|
||||
if v_1.Op != OpPPC64SRW {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
if x != v_1.Args[0] {
|
||||
continue
|
||||
}
|
||||
v_1_1 := v_1.Args[1]
|
||||
if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 32 {
|
||||
continue
|
||||
}
|
||||
v_1_1_0 := v_1_1.Args[0]
|
||||
if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 31 || y != v_1_1_0.Args[0] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64ROTLW)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (XOR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))))
|
||||
// result: (ROTLW x y)
|
||||
for {
|
||||
@ -13257,6 +13506,28 @@ func rewriteValuePPC64_OpRsh32Ux64(v *Value) bool {
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (Rsh32Ux64 x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
// result: (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 32 {
|
||||
break
|
||||
}
|
||||
v_1_0 := v_1.Args[0]
|
||||
if v_1_0.Op != OpPPC64ANDconst || v_1_0.Type != typ.UInt || auxIntToInt64(v_1_0.AuxInt) != 31 {
|
||||
break
|
||||
}
|
||||
y := v_1_0.Args[0]
|
||||
v.reset(OpPPC64SRW)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
|
||||
v0.AuxInt = int64ToAuxInt(32)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
|
||||
v1.AuxInt = int64ToAuxInt(31)
|
||||
v1.AddArg(y)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (Rsh32Ux64 x (SUB <typ.UInt> (MOVDconst [32]) (AND <typ.UInt> y (MOVDconst [31]))))
|
||||
// result: (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
|
||||
for {
|
||||
@ -13294,6 +13565,37 @@ func rewriteValuePPC64_OpRsh32Ux64(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Rsh32Ux64 x (SUBFCconst <typ.UInt> [32] (AND <typ.UInt> y (MOVDconst [31]))))
|
||||
// result: (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 32 {
|
||||
break
|
||||
}
|
||||
v_1_0 := v_1.Args[0]
|
||||
if v_1_0.Op != OpPPC64AND || v_1_0.Type != typ.UInt {
|
||||
break
|
||||
}
|
||||
_ = v_1_0.Args[1]
|
||||
v_1_0_0 := v_1_0.Args[0]
|
||||
v_1_0_1 := v_1_0.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0_0, v_1_0_1 = _i0+1, v_1_0_1, v_1_0_0 {
|
||||
y := v_1_0_0
|
||||
if v_1_0_1.Op != OpPPC64MOVDconst || auxIntToInt64(v_1_0_1.AuxInt) != 31 {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64SRW)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
|
||||
v0.AuxInt = int64ToAuxInt(32)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
|
||||
v1.AuxInt = int64ToAuxInt(31)
|
||||
v1.AddArg(y)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Rsh32Ux64 x y)
|
||||
// result: (SRW x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [32]))))
|
||||
for {
|
||||
@ -13564,6 +13866,28 @@ func rewriteValuePPC64_OpRsh32x64(v *Value) bool {
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (Rsh32x64 x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
// result: (SRAW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 32 {
|
||||
break
|
||||
}
|
||||
v_1_0 := v_1.Args[0]
|
||||
if v_1_0.Op != OpPPC64ANDconst || v_1_0.Type != typ.UInt || auxIntToInt64(v_1_0.AuxInt) != 31 {
|
||||
break
|
||||
}
|
||||
y := v_1_0.Args[0]
|
||||
v.reset(OpPPC64SRAW)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
|
||||
v0.AuxInt = int64ToAuxInt(32)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
|
||||
v1.AuxInt = int64ToAuxInt(31)
|
||||
v1.AddArg(y)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (Rsh32x64 x (SUB <typ.UInt> (MOVDconst [32]) (AND <typ.UInt> y (MOVDconst [31]))))
|
||||
// result: (SRAW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
|
||||
for {
|
||||
@ -13601,6 +13925,37 @@ func rewriteValuePPC64_OpRsh32x64(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Rsh32x64 x (SUBFCconst <typ.UInt> [32] (AND <typ.UInt> y (MOVDconst [31]))))
|
||||
// result: (SRAW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 32 {
|
||||
break
|
||||
}
|
||||
v_1_0 := v_1.Args[0]
|
||||
if v_1_0.Op != OpPPC64AND || v_1_0.Type != typ.UInt {
|
||||
break
|
||||
}
|
||||
_ = v_1_0.Args[1]
|
||||
v_1_0_0 := v_1_0.Args[0]
|
||||
v_1_0_1 := v_1_0.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0_0, v_1_0_1 = _i0+1, v_1_0_1, v_1_0_0 {
|
||||
y := v_1_0_0
|
||||
if v_1_0_1.Op != OpPPC64MOVDconst || auxIntToInt64(v_1_0_1.AuxInt) != 31 {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64SRAW)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
|
||||
v0.AuxInt = int64ToAuxInt(32)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
|
||||
v1.AuxInt = int64ToAuxInt(31)
|
||||
v1.AddArg(y)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Rsh32x64 x y)
|
||||
// result: (SRAW x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [32]))))
|
||||
for {
|
||||
@ -13869,6 +14224,28 @@ func rewriteValuePPC64_OpRsh64Ux64(v *Value) bool {
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (Rsh64Ux64 x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
// result: (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 64 {
|
||||
break
|
||||
}
|
||||
v_1_0 := v_1.Args[0]
|
||||
if v_1_0.Op != OpPPC64ANDconst || v_1_0.Type != typ.UInt || auxIntToInt64(v_1_0.AuxInt) != 63 {
|
||||
break
|
||||
}
|
||||
y := v_1_0.Args[0]
|
||||
v.reset(OpPPC64SRD)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
|
||||
v0.AuxInt = int64ToAuxInt(64)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
|
||||
v1.AuxInt = int64ToAuxInt(63)
|
||||
v1.AddArg(y)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (Rsh64Ux64 x (SUB <typ.UInt> (MOVDconst [64]) (AND <typ.UInt> y (MOVDconst [63]))))
|
||||
// result: (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
|
||||
for {
|
||||
@ -13906,6 +14283,37 @@ func rewriteValuePPC64_OpRsh64Ux64(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Rsh64Ux64 x (SUBFCconst <typ.UInt> [64] (AND <typ.UInt> y (MOVDconst [63]))))
|
||||
// result: (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 64 {
|
||||
break
|
||||
}
|
||||
v_1_0 := v_1.Args[0]
|
||||
if v_1_0.Op != OpPPC64AND || v_1_0.Type != typ.UInt {
|
||||
break
|
||||
}
|
||||
_ = v_1_0.Args[1]
|
||||
v_1_0_0 := v_1_0.Args[0]
|
||||
v_1_0_1 := v_1_0.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0_0, v_1_0_1 = _i0+1, v_1_0_1, v_1_0_0 {
|
||||
y := v_1_0_0
|
||||
if v_1_0_1.Op != OpPPC64MOVDconst || auxIntToInt64(v_1_0_1.AuxInt) != 63 {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64SRD)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
|
||||
v0.AuxInt = int64ToAuxInt(64)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
|
||||
v1.AuxInt = int64ToAuxInt(63)
|
||||
v1.AddArg(y)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Rsh64Ux64 x y)
|
||||
// result: (SRD x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [64]))))
|
||||
for {
|
||||
@ -14176,6 +14584,28 @@ func rewriteValuePPC64_OpRsh64x64(v *Value) bool {
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (Rsh64x64 x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
// result: (SRAD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 64 {
|
||||
break
|
||||
}
|
||||
v_1_0 := v_1.Args[0]
|
||||
if v_1_0.Op != OpPPC64ANDconst || v_1_0.Type != typ.UInt || auxIntToInt64(v_1_0.AuxInt) != 63 {
|
||||
break
|
||||
}
|
||||
y := v_1_0.Args[0]
|
||||
v.reset(OpPPC64SRAD)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
|
||||
v0.AuxInt = int64ToAuxInt(64)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
|
||||
v1.AuxInt = int64ToAuxInt(63)
|
||||
v1.AddArg(y)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (Rsh64x64 x (SUB <typ.UInt> (MOVDconst [64]) (AND <typ.UInt> y (MOVDconst [63]))))
|
||||
// result: (SRAD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
|
||||
for {
|
||||
@ -14213,6 +14643,37 @@ func rewriteValuePPC64_OpRsh64x64(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Rsh64x64 x (SUBFCconst <typ.UInt> [64] (AND <typ.UInt> y (MOVDconst [63]))))
|
||||
// result: (SRAD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 64 {
|
||||
break
|
||||
}
|
||||
v_1_0 := v_1.Args[0]
|
||||
if v_1_0.Op != OpPPC64AND || v_1_0.Type != typ.UInt {
|
||||
break
|
||||
}
|
||||
_ = v_1_0.Args[1]
|
||||
v_1_0_0 := v_1_0.Args[0]
|
||||
v_1_0_1 := v_1_0.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0_0, v_1_0_1 = _i0+1, v_1_0_1, v_1_0_0 {
|
||||
y := v_1_0_0
|
||||
if v_1_0_1.Op != OpPPC64MOVDconst || auxIntToInt64(v_1_0_1.AuxInt) != 63 {
|
||||
continue
|
||||
}
|
||||
v.reset(OpPPC64SRAD)
|
||||
v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
|
||||
v0.AuxInt = int64ToAuxInt(64)
|
||||
v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
|
||||
v1.AuxInt = int64ToAuxInt(63)
|
||||
v1.AddArg(y)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Rsh64x64 x y)
|
||||
// result: (SRAD x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [64]))))
|
||||
for {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -328,9 +328,10 @@ func rewriteValuedec_OpStore(v *Value) bool {
|
||||
v.AddArg3(v0, len, v1)
|
||||
return true
|
||||
}
|
||||
// match: (Store dst (SliceMake ptr len cap) mem)
|
||||
// result: (Store {typ.Int} (OffPtr <typ.IntPtr> [2*config.PtrSize] dst) cap (Store {typ.Int} (OffPtr <typ.IntPtr> [config.PtrSize] dst) len (Store {typ.BytePtr} dst ptr mem)))
|
||||
// match: (Store {t} dst (SliceMake ptr len cap) mem)
|
||||
// result: (Store {typ.Int} (OffPtr <typ.IntPtr> [2*config.PtrSize] dst) cap (Store {typ.Int} (OffPtr <typ.IntPtr> [config.PtrSize] dst) len (Store {t.Elem().PtrTo()} dst ptr mem)))
|
||||
for {
|
||||
t := auxToType(v.Aux)
|
||||
dst := v_0
|
||||
if v_1.Op != OpSliceMake {
|
||||
break
|
||||
@ -350,7 +351,7 @@ func rewriteValuedec_OpStore(v *Value) bool {
|
||||
v2.AuxInt = int64ToAuxInt(config.PtrSize)
|
||||
v2.AddArg(dst)
|
||||
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v3.Aux = typeToAux(typ.BytePtr)
|
||||
v3.Aux = typeToAux(t.Elem().PtrTo())
|
||||
v3.AddArg3(dst, ptr, mem)
|
||||
v1.AddArg3(v2, len, v3)
|
||||
v.AddArg3(v0, cap, v1)
|
||||
|
@ -18,6 +18,7 @@ func softfloat(f *Func) {
|
||||
for _, b := range f.Blocks {
|
||||
for _, v := range b.Values {
|
||||
if v.Type.IsFloat() {
|
||||
f.unCache(v)
|
||||
switch v.Op {
|
||||
case OpPhi, OpLoad, OpArg:
|
||||
if v.Type.Size() == 4 {
|
||||
@ -72,7 +73,7 @@ func softfloat(f *Func) {
|
||||
if newInt64 && f.Config.RegSize == 4 {
|
||||
// On 32bit arch, decompose Uint64 introduced in the switch above.
|
||||
decomposeBuiltIn(f)
|
||||
applyRewrite(f, rewriteBlockdec64, rewriteValuedec64)
|
||||
applyRewrite(f, rewriteBlockdec64, rewriteValuedec64, removeDeadValues)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -54,6 +54,9 @@ type Value struct {
|
||||
// nor a slot on Go stack, and the generation of this value is delayed to its use time.
|
||||
OnWasmStack bool
|
||||
|
||||
// Is this value in the per-function constant cache? If so, remove from cache before changing it or recycling it.
|
||||
InCache bool
|
||||
|
||||
// Storage for the first three args
|
||||
argstorage [3]*Value
|
||||
}
|
||||
@ -210,7 +213,7 @@ func (v *Value) auxString() string {
|
||||
}
|
||||
return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
|
||||
case auxCCop:
|
||||
return fmt.Sprintf(" {%s}", v.Aux.(Op))
|
||||
return fmt.Sprintf(" {%s}", Op(v.AuxInt))
|
||||
case auxS390XCCMask, auxS390XRotateParams:
|
||||
return fmt.Sprintf(" {%v}", v.Aux)
|
||||
case auxFlagConstant:
|
||||
@ -332,6 +335,9 @@ func (v *Value) resetArgs() {
|
||||
// of cmd/compile by almost 10%, and slows it down.
|
||||
//go:noinline
|
||||
func (v *Value) reset(op Op) {
|
||||
if v.InCache {
|
||||
v.Block.Func.unCache(v)
|
||||
}
|
||||
v.Op = op
|
||||
v.resetArgs()
|
||||
v.AuxInt = 0
|
||||
@ -342,6 +348,9 @@ func (v *Value) reset(op Op) {
|
||||
// It modifies v to be (Copy a).
|
||||
//go:noinline
|
||||
func (v *Value) copyOf(a *Value) {
|
||||
if v.InCache {
|
||||
v.Block.Func.unCache(v)
|
||||
}
|
||||
v.Op = OpCopy
|
||||
v.resetArgs()
|
||||
v.AddArg(a)
|
||||
@ -460,3 +469,23 @@ func (v *Value) LackingPos() bool {
|
||||
return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi ||
|
||||
(v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem
|
||||
}
|
||||
|
||||
// removeable reports whether the value v can be removed from the SSA graph entirely
|
||||
// if its use count drops to 0.
|
||||
func (v *Value) removeable() bool {
|
||||
if v.Type.IsVoid() {
|
||||
// Void ops, like nil pointer checks, must stay.
|
||||
return false
|
||||
}
|
||||
if v.Type.IsMemory() {
|
||||
// All memory ops aren't needed here, but we do need
|
||||
// to keep calls at least (because they might have
|
||||
// syncronization operations we can't see).
|
||||
return false
|
||||
}
|
||||
if v.Op.HasSideEffects() {
|
||||
// These are mostly synchronization operations.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ func needwb(v *Value, zeroes map[ID]ZeroRegion) bool {
|
||||
if !ok {
|
||||
v.Fatalf("store aux is not a type: %s", v.LongString())
|
||||
}
|
||||
if !t.HasHeapPointer() {
|
||||
if !t.HasPointers() {
|
||||
return false
|
||||
}
|
||||
if IsStackAddr(v.Args[0]) {
|
||||
|
@ -1230,6 +1230,11 @@ func (t *Type) IsUnsafePtr() bool {
|
||||
return t.Etype == TUNSAFEPTR
|
||||
}
|
||||
|
||||
// IsUintptr reports whether t is an uintptr.
|
||||
func (t *Type) IsUintptr() bool {
|
||||
return t.Etype == TUINTPTR
|
||||
}
|
||||
|
||||
// IsPtrShaped reports whether t is represented by a single machine pointer.
|
||||
// In addition to regular Go pointer types, this includes map, channel, and
|
||||
// function types and unsafe.Pointer. It does not include array or struct types
|
||||
@ -1398,14 +1403,9 @@ func (t *Type) IsUntyped() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO(austin): We probably only need HasHeapPointer. See
|
||||
// golang.org/cl/73412 for discussion.
|
||||
|
||||
// HasPointers reports whether t contains a heap pointer.
|
||||
// Note that this function ignores pointers to go:notinheap types.
|
||||
func (t *Type) HasPointers() bool {
|
||||
return t.hasPointers1(false)
|
||||
}
|
||||
|
||||
func (t *Type) hasPointers1(ignoreNotInHeap bool) bool {
|
||||
switch t.Etype {
|
||||
case TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64,
|
||||
TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL, TSSA:
|
||||
@ -1415,34 +1415,27 @@ func (t *Type) hasPointers1(ignoreNotInHeap bool) bool {
|
||||
if t.NumElem() == 0 { // empty array has no pointers
|
||||
return false
|
||||
}
|
||||
return t.Elem().hasPointers1(ignoreNotInHeap)
|
||||
return t.Elem().HasPointers()
|
||||
|
||||
case TSTRUCT:
|
||||
for _, t1 := range t.Fields().Slice() {
|
||||
if t1.Type.hasPointers1(ignoreNotInHeap) {
|
||||
if t1.Type.HasPointers() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
case TPTR, TSLICE:
|
||||
return !(ignoreNotInHeap && t.Elem().NotInHeap())
|
||||
return !t.Elem().NotInHeap()
|
||||
|
||||
case TTUPLE:
|
||||
ttup := t.Extra.(*Tuple)
|
||||
return ttup.first.hasPointers1(ignoreNotInHeap) || ttup.second.hasPointers1(ignoreNotInHeap)
|
||||
return ttup.first.HasPointers() || ttup.second.HasPointers()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// HasHeapPointer reports whether t contains a heap pointer.
|
||||
// This is used for write barrier insertion, so it ignores
|
||||
// pointers to go:notinheap types.
|
||||
func (t *Type) HasHeapPointer() bool {
|
||||
return t.hasPointers1(true)
|
||||
}
|
||||
|
||||
func (t *Type) Symbol() *obj.LSym {
|
||||
return TypeLinkSym(t)
|
||||
}
|
||||
|
@ -261,8 +261,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
n.To.Reg = x86.REG_DX
|
||||
}
|
||||
|
||||
j.To.Val = n
|
||||
j2.To.Val = s.Pc()
|
||||
j.To.SetTarget(n)
|
||||
j2.To.SetTarget(s.Pc())
|
||||
}
|
||||
|
||||
case ssa.Op386HMULL, ssa.Op386HMULLU:
|
||||
|
5
src/cmd/dist/test.go
vendored
5
src/cmd/dist/test.go
vendored
@ -1106,8 +1106,9 @@ func (t *tester) cgoTest(dt *distTest) error {
|
||||
|
||||
cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
|
||||
cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
|
||||
// A -g argument in CGO_CFLAGS should not affect how the test runs.
|
||||
cmd.Env = append(cmd.Env, "CGO_CFLAGS=-g0")
|
||||
// cgo should be able to cope with both -g arguments and colored
|
||||
// diagnostics.
|
||||
cmd.Env = append(cmd.Env, "CGO_CFLAGS=-g0 -fdiagnostics-color")
|
||||
|
||||
t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto")
|
||||
t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external")
|
||||
|
@ -7,13 +7,9 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type fix struct {
|
||||
@ -323,160 +319,12 @@ func declImports(gen *ast.GenDecl, path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// isPkgDot reports whether t is the expression "pkg.name"
|
||||
// where pkg is an imported identifier.
|
||||
func isPkgDot(t ast.Expr, pkg, name string) bool {
|
||||
sel, ok := t.(*ast.SelectorExpr)
|
||||
return ok && isTopName(sel.X, pkg) && sel.Sel.String() == name
|
||||
}
|
||||
|
||||
// isPtrPkgDot reports whether f is the expression "*pkg.name"
|
||||
// where pkg is an imported identifier.
|
||||
func isPtrPkgDot(t ast.Expr, pkg, name string) bool {
|
||||
ptr, ok := t.(*ast.StarExpr)
|
||||
return ok && isPkgDot(ptr.X, pkg, name)
|
||||
}
|
||||
|
||||
// isTopName reports whether n is a top-level unresolved identifier with the given name.
|
||||
func isTopName(n ast.Expr, name string) bool {
|
||||
id, ok := n.(*ast.Ident)
|
||||
return ok && id.Name == name && id.Obj == nil
|
||||
}
|
||||
|
||||
// isName reports whether n is an identifier with the given name.
|
||||
func isName(n ast.Expr, name string) bool {
|
||||
id, ok := n.(*ast.Ident)
|
||||
return ok && id.String() == name
|
||||
}
|
||||
|
||||
// isCall reports whether t is a call to pkg.name.
|
||||
func isCall(t ast.Expr, pkg, name string) bool {
|
||||
call, ok := t.(*ast.CallExpr)
|
||||
return ok && isPkgDot(call.Fun, pkg, name)
|
||||
}
|
||||
|
||||
// If n is an *ast.Ident, isIdent returns it; otherwise isIdent returns nil.
|
||||
func isIdent(n interface{}) *ast.Ident {
|
||||
id, _ := n.(*ast.Ident)
|
||||
return id
|
||||
}
|
||||
|
||||
// refersTo reports whether n is a reference to the same object as x.
|
||||
func refersTo(n ast.Node, x *ast.Ident) bool {
|
||||
id, ok := n.(*ast.Ident)
|
||||
// The test of id.Name == x.Name handles top-level unresolved
|
||||
// identifiers, which all have Obj == nil.
|
||||
return ok && id.Obj == x.Obj && id.Name == x.Name
|
||||
}
|
||||
|
||||
// isBlank reports whether n is the blank identifier.
|
||||
func isBlank(n ast.Expr) bool {
|
||||
return isName(n, "_")
|
||||
}
|
||||
|
||||
// isEmptyString reports whether n is an empty string literal.
|
||||
func isEmptyString(n ast.Expr) bool {
|
||||
lit, ok := n.(*ast.BasicLit)
|
||||
return ok && lit.Kind == token.STRING && len(lit.Value) == 2
|
||||
}
|
||||
|
||||
func warn(pos token.Pos, msg string, args ...interface{}) {
|
||||
if pos.IsValid() {
|
||||
msg = "%s: " + msg
|
||||
arg1 := []interface{}{fset.Position(pos).String()}
|
||||
args = append(arg1, args...)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
||||
}
|
||||
|
||||
// countUses returns the number of uses of the identifier x in scope.
|
||||
func countUses(x *ast.Ident, scope []ast.Stmt) int {
|
||||
count := 0
|
||||
ff := func(n interface{}) {
|
||||
if n, ok := n.(ast.Node); ok && refersTo(n, x) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
for _, n := range scope {
|
||||
walk(n, ff)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// rewriteUses replaces all uses of the identifier x and !x in scope
|
||||
// with f(x.Pos()) and fnot(x.Pos()).
|
||||
func rewriteUses(x *ast.Ident, f, fnot func(token.Pos) ast.Expr, scope []ast.Stmt) {
|
||||
var lastF ast.Expr
|
||||
ff := func(n interface{}) {
|
||||
ptr, ok := n.(*ast.Expr)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
nn := *ptr
|
||||
|
||||
// The child node was just walked and possibly replaced.
|
||||
// If it was replaced and this is a negation, replace with fnot(p).
|
||||
not, ok := nn.(*ast.UnaryExpr)
|
||||
if ok && not.Op == token.NOT && not.X == lastF {
|
||||
*ptr = fnot(nn.Pos())
|
||||
return
|
||||
}
|
||||
if refersTo(nn, x) {
|
||||
lastF = f(nn.Pos())
|
||||
*ptr = lastF
|
||||
}
|
||||
}
|
||||
for _, n := range scope {
|
||||
walk(n, ff)
|
||||
}
|
||||
}
|
||||
|
||||
// assignsTo reports whether any of the code in scope assigns to or takes the address of x.
|
||||
func assignsTo(x *ast.Ident, scope []ast.Stmt) bool {
|
||||
assigned := false
|
||||
ff := func(n interface{}) {
|
||||
if assigned {
|
||||
return
|
||||
}
|
||||
switch n := n.(type) {
|
||||
case *ast.UnaryExpr:
|
||||
// use of &x
|
||||
if n.Op == token.AND && refersTo(n.X, x) {
|
||||
assigned = true
|
||||
return
|
||||
}
|
||||
case *ast.AssignStmt:
|
||||
for _, l := range n.Lhs {
|
||||
if refersTo(l, x) {
|
||||
assigned = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, n := range scope {
|
||||
if assigned {
|
||||
break
|
||||
}
|
||||
walk(n, ff)
|
||||
}
|
||||
return assigned
|
||||
}
|
||||
|
||||
// newPkgDot returns an ast.Expr referring to "pkg.name" at position pos.
|
||||
func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
|
||||
return &ast.SelectorExpr{
|
||||
X: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: pkg,
|
||||
},
|
||||
Sel: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// renameTop renames all references to the top-level name old.
|
||||
// It reports whether it makes any changes.
|
||||
func renameTop(f *ast.File, old, new string) bool {
|
||||
@ -707,143 +555,3 @@ func rewriteImport(f *ast.File, oldPath, newPath string) (rewrote bool) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func usesImport(f *ast.File, path string) (used bool) {
|
||||
spec := importSpec(f, path)
|
||||
if spec == nil {
|
||||
return
|
||||
}
|
||||
|
||||
name := spec.Name.String()
|
||||
switch name {
|
||||
case "<nil>":
|
||||
// If the package name is not explicitly specified,
|
||||
// make an educated guess. This is not guaranteed to be correct.
|
||||
lastSlash := strings.LastIndex(path, "/")
|
||||
if lastSlash == -1 {
|
||||
name = path
|
||||
} else {
|
||||
name = path[lastSlash+1:]
|
||||
}
|
||||
case "_", ".":
|
||||
// Not sure if this import is used - err on the side of caution.
|
||||
return true
|
||||
}
|
||||
|
||||
walk(f, func(n interface{}) {
|
||||
sel, ok := n.(*ast.SelectorExpr)
|
||||
if ok && isTopName(sel.X, name) {
|
||||
used = true
|
||||
}
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func expr(s string) ast.Expr {
|
||||
x, err := parser.ParseExpr(s)
|
||||
if err != nil {
|
||||
panic("parsing " + s + ": " + err.Error())
|
||||
}
|
||||
// Remove position information to avoid spurious newlines.
|
||||
killPos(reflect.ValueOf(x))
|
||||
return x
|
||||
}
|
||||
|
||||
var posType = reflect.TypeOf(token.Pos(0))
|
||||
|
||||
func killPos(v reflect.Value) {
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
if !v.IsNil() {
|
||||
killPos(v.Elem())
|
||||
}
|
||||
case reflect.Slice:
|
||||
n := v.Len()
|
||||
for i := 0; i < n; i++ {
|
||||
killPos(v.Index(i))
|
||||
}
|
||||
case reflect.Struct:
|
||||
n := v.NumField()
|
||||
for i := 0; i < n; i++ {
|
||||
f := v.Field(i)
|
||||
if f.Type() == posType {
|
||||
f.SetInt(0)
|
||||
continue
|
||||
}
|
||||
killPos(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A Rename describes a single renaming.
|
||||
type rename struct {
|
||||
OldImport string // only apply rename if this import is present
|
||||
NewImport string // add this import during rewrite
|
||||
Old string // old name: p.T or *p.T
|
||||
New string // new name: p.T or *p.T
|
||||
}
|
||||
|
||||
func renameFix(tab []rename) func(*ast.File) bool {
|
||||
return func(f *ast.File) bool {
|
||||
return renameFixTab(f, tab)
|
||||
}
|
||||
}
|
||||
|
||||
func parseName(s string) (ptr bool, pkg, nam string) {
|
||||
i := strings.Index(s, ".")
|
||||
if i < 0 {
|
||||
panic("parseName: invalid name " + s)
|
||||
}
|
||||
if strings.HasPrefix(s, "*") {
|
||||
ptr = true
|
||||
s = s[1:]
|
||||
i--
|
||||
}
|
||||
pkg = s[:i]
|
||||
nam = s[i+1:]
|
||||
return
|
||||
}
|
||||
|
||||
func renameFixTab(f *ast.File, tab []rename) bool {
|
||||
fixed := false
|
||||
added := map[string]bool{}
|
||||
check := map[string]bool{}
|
||||
for _, t := range tab {
|
||||
if !imports(f, t.OldImport) {
|
||||
continue
|
||||
}
|
||||
optr, opkg, onam := parseName(t.Old)
|
||||
walk(f, func(n interface{}) {
|
||||
np, ok := n.(*ast.Expr)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
x := *np
|
||||
if optr {
|
||||
p, ok := x.(*ast.StarExpr)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
x = p.X
|
||||
}
|
||||
if !isPkgDot(x, opkg, onam) {
|
||||
return
|
||||
}
|
||||
if t.NewImport != "" && !added[t.NewImport] {
|
||||
addImport(f, t.NewImport)
|
||||
added[t.NewImport] = true
|
||||
}
|
||||
*np = expr(t.New)
|
||||
check[t.OldImport] = true
|
||||
fixed = true
|
||||
})
|
||||
}
|
||||
|
||||
for ipath := range check {
|
||||
if !usesImport(f, ipath) {
|
||||
deleteImport(f, ipath)
|
||||
}
|
||||
}
|
||||
return fixed
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ require (
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
|
||||
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/mod v0.3.1-0.20200625141748-0b26df4a2231
|
||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449
|
||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054
|
||||
golang.org/x/tools v0.0.0-20200901153117-6e59e24738da
|
||||
golang.org/x/xerrors v0.0.0-20200806184451-1a77d5e9f316 // indirect
|
||||
)
|
||||
|
@ -6,34 +6,34 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 h1:S1+yTUaFPXuDZnPDbO+TrDFIjPzQraYH8/CwSlu9Fac=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d h1:YvwchuJby5xEAPdBGmdAVSiVME50C+RJfJJwJJsGEV8=
|
||||
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.1-0.20200625141748-0b26df4a2231 h1:R11LxkoUvECaAHdM5/ZOevSR7n+016EgTw8nbE1l+XM=
|
||||
golang.org/x/mod v0.3.1-0.20200625141748-0b26df4a2231/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ=
|
||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3rzIsrrXfAQBWnYfn+w=
|
||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200901153117-6e59e24738da h1:8nFbt74voFOsM+Hb5XtF+1SNbbf3dzikH5osZO1hyyo=
|
||||
golang.org/x/tools v0.0.0-20200901153117-6e59e24738da/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200806184451-1a77d5e9f316 h1:Jhw4VC65LaKnpq9FvcK+a8ZzrFm3D+UygvMMrhkOw70=
|
||||
golang.org/x/xerrors v0.0.0-20200806184451-1a77d5e9f316/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
@ -916,6 +916,7 @@
|
||||
// Dir string // directory holding files for this module, if any
|
||||
// GoMod string // path to go.mod file used when loading this module, if any
|
||||
// GoVersion string // go version used in module
|
||||
// Retracted string // retraction information, if any (with -retracted or -u)
|
||||
// Error *ModuleError // error loading module
|
||||
// }
|
||||
//
|
||||
@ -947,14 +948,16 @@
|
||||
// The -u flag adds information about available upgrades.
|
||||
// When the latest version of a given module is newer than
|
||||
// the current one, list -u sets the Module's Update field
|
||||
// to information about the newer module.
|
||||
// to information about the newer module. list -u will also set
|
||||
// the module's Retracted field if the current version is retracted.
|
||||
// The Module's String method indicates an available upgrade by
|
||||
// formatting the newer version in brackets after the current version.
|
||||
// If a version is retracted, the string "(retracted)" will follow it.
|
||||
// For example, 'go list -m -u all' might print:
|
||||
//
|
||||
// my/main/module
|
||||
// golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
|
||||
// rsc.io/pdf v0.1.1 [v0.1.2]
|
||||
// rsc.io/pdf v0.1.1 (retracted) [v0.1.2]
|
||||
//
|
||||
// (For tools, 'go list -m -u -json all' may be more convenient to parse.)
|
||||
//
|
||||
@ -964,6 +967,14 @@
|
||||
// the default output format to display the module path followed by the
|
||||
// space-separated version list.
|
||||
//
|
||||
// The -retracted flag causes list to report information about retracted
|
||||
// module versions. When -retracted is used with -f or -json, the Retracted
|
||||
// field will be set to a string explaining why the version was retracted.
|
||||
// The string is taken from comments on the retract directive in the
|
||||
// module's go.mod file. When -retracted is used with -versions, retracted
|
||||
// versions are listed together with unretracted versions. The -retracted
|
||||
// flag may be used with or without -m.
|
||||
//
|
||||
// The arguments to list -m are interpreted as a list of modules, not packages.
|
||||
// The main module is the module containing the current directory.
|
||||
// The active modules are the main module and its dependencies.
|
||||
@ -1100,9 +1111,14 @@
|
||||
// module path and version pair. If the @v is omitted, a replacement without
|
||||
// a version on the left side is dropped.
|
||||
//
|
||||
// The -retract=version and -dropretract=version flags add and drop a
|
||||
// retraction on the given version. The version may be a single version
|
||||
// like "v1.2.3" or a closed interval like "[v1.1.0-v1.1.9]". Note that
|
||||
// -retract=version is a no-op if that retraction already exists.
|
||||
//
|
||||
// The -require, -droprequire, -exclude, -dropexclude, -replace,
|
||||
// and -dropreplace editing flags may be repeated, and the changes
|
||||
// are applied in the order given.
|
||||
// -dropreplace, -retract, and -dropretract editing flags may be repeated,
|
||||
// and the changes are applied in the order given.
|
||||
//
|
||||
// The -go=version flag sets the expected Go language version.
|
||||
//
|
||||
@ -1136,6 +1152,15 @@
|
||||
// New Module
|
||||
// }
|
||||
//
|
||||
// type Retract struct {
|
||||
// Low string
|
||||
// High string
|
||||
// Rationale string
|
||||
// }
|
||||
//
|
||||
// Retract entries representing a single version (not an interval) will have
|
||||
// the "Low" and "High" fields set to the same value.
|
||||
//
|
||||
// Note that this only describes the go.mod file itself, not other modules
|
||||
// referred to indirectly. For the full set of modules available to a build,
|
||||
// use 'go list -m -json all'.
|
||||
@ -1894,15 +1919,17 @@
|
||||
// require new/thing/v2 v2.3.4
|
||||
// exclude old/thing v1.2.3
|
||||
// replace bad/thing v1.4.5 => good/thing v1.4.5
|
||||
// retract v1.5.6
|
||||
//
|
||||
// The verbs are
|
||||
// module, to define the module path;
|
||||
// go, to set the expected language version;
|
||||
// require, to require a particular module at a given version or later;
|
||||
// exclude, to exclude a particular module version from use; and
|
||||
// replace, to replace a module version with a different module version.
|
||||
// exclude, to exclude a particular module version from use;
|
||||
// replace, to replace a module version with a different module version; and
|
||||
// retract, to indicate a previously released version should not be used.
|
||||
// Exclude and replace apply only in the main module's go.mod and are ignored
|
||||
// in dependencies. See https://research.swtch.com/vgo-mvs for details.
|
||||
// in dependencies. See https://golang.org/ref/mod for details.
|
||||
//
|
||||
// The leading verb can be factored out of adjacent lines to create a block,
|
||||
// like in Go imports:
|
||||
@ -2145,7 +2172,10 @@
|
||||
// before resolving dependencies or building the code.
|
||||
//
|
||||
// The -insecure flag permits fetching from repositories and resolving
|
||||
// custom domains using insecure schemes such as HTTP. Use with caution.
|
||||
// custom domains using insecure schemes such as HTTP. Use with caution. The
|
||||
// GOINSECURE environment variable is usually a better alternative, since it
|
||||
// provides control over which modules may be retrieved using an insecure scheme.
|
||||
// See 'go help environment' for details.
|
||||
//
|
||||
// The -t flag instructs get to also download the packages required to build
|
||||
// the tests for the specified packages.
|
||||
|
@ -28,13 +28,42 @@ func (v *StringsFlag) String() string {
|
||||
return "<StringsFlag>"
|
||||
}
|
||||
|
||||
// explicitStringFlag is like a regular string flag, but it also tracks whether
|
||||
// the string was set explicitly to a non-empty value.
|
||||
type explicitStringFlag struct {
|
||||
value *string
|
||||
explicit *bool
|
||||
}
|
||||
|
||||
func (f explicitStringFlag) String() string {
|
||||
if f.value == nil {
|
||||
return ""
|
||||
}
|
||||
return *f.value
|
||||
}
|
||||
|
||||
func (f explicitStringFlag) Set(v string) error {
|
||||
*f.value = v
|
||||
if v != "" {
|
||||
*f.explicit = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddBuildFlagsNX adds the -n and -x build flags to the flag set.
|
||||
func AddBuildFlagsNX(flags *flag.FlagSet) {
|
||||
flags.BoolVar(&cfg.BuildN, "n", false, "")
|
||||
flags.BoolVar(&cfg.BuildX, "x", false, "")
|
||||
}
|
||||
|
||||
// AddLoadFlags adds the -mod build flag to the flag set.
|
||||
func AddLoadFlags(flags *flag.FlagSet) {
|
||||
flags.StringVar(&cfg.BuildMod, "mod", "", "")
|
||||
// AddModFlag adds the -mod build flag to the flag set.
|
||||
func AddModFlag(flags *flag.FlagSet) {
|
||||
flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
|
||||
}
|
||||
|
||||
// AddModCommonFlags adds the module-related flags common to build commands
|
||||
// and 'go mod' subcommands.
|
||||
func AddModCommonFlags(flags *flag.FlagSet) {
|
||||
flags.BoolVar(&cfg.ModCacheRW, "modcacherw", false, "")
|
||||
flags.StringVar(&cfg.ModFile, "modfile", "", "")
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ var (
|
||||
BuildBuildmode string // -buildmode flag
|
||||
BuildContext = defaultContext()
|
||||
BuildMod string // -mod flag
|
||||
BuildModReason string // reason -mod flag is set, if set by default
|
||||
BuildModExplicit bool // whether -mod was set explicitly
|
||||
BuildModReason string // reason -mod was set, if set by default
|
||||
BuildI bool // -i flag
|
||||
BuildLinkshared bool // -linkshared flag
|
||||
BuildMSan bool // -msan flag
|
||||
@ -48,6 +49,8 @@ var (
|
||||
ModCacheRW bool // -modcacherw flag
|
||||
ModFile string // -modfile flag
|
||||
|
||||
Insecure bool // -insecure flag
|
||||
|
||||
CmdName string // "build", "install", "list", "mod tidy", etc.
|
||||
|
||||
DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
|
||||
|
@ -23,7 +23,8 @@ import (
|
||||
|
||||
func init() {
|
||||
base.AddBuildFlagsNX(&CmdFmt.Flag)
|
||||
base.AddLoadFlags(&CmdFmt.Flag)
|
||||
base.AddModFlag(&CmdFmt.Flag)
|
||||
base.AddModCommonFlags(&CmdFmt.Flag)
|
||||
}
|
||||
|
||||
var CmdFmt = &base.Command{
|
||||
|
@ -18,8 +18,11 @@ import (
|
||||
"cmd/go/internal/load"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/str"
|
||||
"cmd/go/internal/vcs"
|
||||
"cmd/go/internal/web"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
|
||||
var CmdGet = &base.Command{
|
||||
@ -41,7 +44,10 @@ The -fix flag instructs get to run the fix tool on the downloaded packages
|
||||
before resolving dependencies or building the code.
|
||||
|
||||
The -insecure flag permits fetching from repositories and resolving
|
||||
custom domains using insecure schemes such as HTTP. Use with caution.
|
||||
custom domains using insecure schemes such as HTTP. Use with caution. The
|
||||
GOINSECURE environment variable is usually a better alternative, since it
|
||||
provides control over which modules may be retrieved using an insecure scheme.
|
||||
See 'go help environment' for details.
|
||||
|
||||
The -t flag instructs get to also download the packages required to build
|
||||
the tests for the specified packages.
|
||||
@ -103,14 +109,12 @@ var (
|
||||
getT = CmdGet.Flag.Bool("t", false, "")
|
||||
getU = CmdGet.Flag.Bool("u", false, "")
|
||||
getFix = CmdGet.Flag.Bool("fix", false, "")
|
||||
|
||||
Insecure bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags)
|
||||
CmdGet.Run = runGet // break init loop
|
||||
CmdGet.Flag.BoolVar(&Insecure, "insecure", Insecure, "")
|
||||
CmdGet.Flag.BoolVar(&cfg.Insecure, "insecure", cfg.Insecure, "")
|
||||
}
|
||||
|
||||
func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||
@ -403,17 +407,12 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
||||
// to make the first copy of or update a copy of the given package.
|
||||
func downloadPackage(p *load.Package) error {
|
||||
var (
|
||||
vcs *vcsCmd
|
||||
vcsCmd *vcs.Cmd
|
||||
repo, rootPath string
|
||||
err error
|
||||
blindRepo bool // set if the repo has unusual configuration
|
||||
)
|
||||
|
||||
security := web.SecureOnly
|
||||
if Insecure {
|
||||
security = web.Insecure
|
||||
}
|
||||
|
||||
// p can be either a real package, or a pseudo-package whose “import path” is
|
||||
// actually a wildcard pattern.
|
||||
// Trim the path at the element containing the first wildcard,
|
||||
@ -427,22 +426,26 @@ func downloadPackage(p *load.Package) error {
|
||||
}
|
||||
importPrefix = importPrefix[:slash]
|
||||
}
|
||||
if err := CheckImportPath(importPrefix); err != nil {
|
||||
if err := module.CheckImportPath(importPrefix); err != nil {
|
||||
return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
|
||||
}
|
||||
security := web.SecureOnly
|
||||
if cfg.Insecure || module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) {
|
||||
security = web.Insecure
|
||||
}
|
||||
|
||||
if p.Internal.Build.SrcRoot != "" {
|
||||
// Directory exists. Look for checkout along path to src.
|
||||
vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
|
||||
vcsCmd, rootPath, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repo = "<local>" // should be unused; make distinctive
|
||||
|
||||
// Double-check where it came from.
|
||||
if *getU && vcs.remoteRepo != nil {
|
||||
if *getU && vcsCmd.RemoteRepo != nil {
|
||||
dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
|
||||
remote, err := vcs.remoteRepo(vcs, dir)
|
||||
remote, err := vcsCmd.RemoteRepo(vcsCmd, dir)
|
||||
if err != nil {
|
||||
// Proceed anyway. The package is present; we likely just don't understand
|
||||
// the repo configuration (e.g. unusual remote protocol).
|
||||
@ -450,10 +453,10 @@ func downloadPackage(p *load.Package) error {
|
||||
}
|
||||
repo = remote
|
||||
if !*getF && err == nil {
|
||||
if rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security); err == nil {
|
||||
if rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security); err == nil {
|
||||
repo := rr.Repo
|
||||
if rr.vcs.resolveRepo != nil {
|
||||
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
|
||||
if rr.VCS.ResolveRepo != nil {
|
||||
resolved, err := rr.VCS.ResolveRepo(rr.VCS, dir, repo)
|
||||
if err == nil {
|
||||
repo = resolved
|
||||
}
|
||||
@ -467,13 +470,13 @@ func downloadPackage(p *load.Package) error {
|
||||
} else {
|
||||
// Analyze the import path to determine the version control system,
|
||||
// repository, and the import path for the root of the repository.
|
||||
rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security)
|
||||
rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vcs, repo, rootPath = rr.vcs, rr.Repo, rr.Root
|
||||
vcsCmd, repo, rootPath = rr.VCS, rr.Repo, rr.Root
|
||||
}
|
||||
if !blindRepo && !vcs.isSecure(repo) && !Insecure {
|
||||
if !blindRepo && !vcsCmd.IsSecure(repo) && security != web.Insecure {
|
||||
return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
|
||||
}
|
||||
|
||||
@ -496,7 +499,7 @@ func downloadPackage(p *load.Package) error {
|
||||
}
|
||||
root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
|
||||
|
||||
if err := checkNestedVCS(vcs, root, p.Internal.Build.SrcRoot); err != nil {
|
||||
if err := vcs.CheckNested(vcsCmd, root, p.Internal.Build.SrcRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -512,7 +515,7 @@ func downloadPackage(p *load.Package) error {
|
||||
|
||||
// Check that this is an appropriate place for the repo to be checked out.
|
||||
// The target directory must either not exist or have a repo checked out already.
|
||||
meta := filepath.Join(root, "."+vcs.cmd)
|
||||
meta := filepath.Join(root, "."+vcsCmd.Cmd)
|
||||
if _, err := os.Stat(meta); err != nil {
|
||||
// Metadata file or directory does not exist. Prepare to checkout new copy.
|
||||
// Some version control tools require the target directory not to exist.
|
||||
@ -533,12 +536,12 @@ func downloadPackage(p *load.Package) error {
|
||||
fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
|
||||
}
|
||||
|
||||
if err = vcs.create(root, repo); err != nil {
|
||||
if err = vcsCmd.Create(root, repo); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Metadata directory does exist; download incremental updates.
|
||||
if err = vcs.download(root); err != nil {
|
||||
if err = vcsCmd.Download(root); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -547,12 +550,12 @@ func downloadPackage(p *load.Package) error {
|
||||
// Do not show tag sync in -n; it's noise more than anything,
|
||||
// and since we're not running commands, no tag will be found.
|
||||
// But avoid printing nothing.
|
||||
fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
|
||||
fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcsCmd.Cmd)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Select and sync to appropriate version of the repository.
|
||||
tags, err := vcs.tags(root)
|
||||
tags, err := vcsCmd.Tags(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -560,7 +563,7 @@ func downloadPackage(p *load.Package) error {
|
||||
if i := strings.Index(vers, " "); i >= 0 {
|
||||
vers = vers[:i]
|
||||
}
|
||||
if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
|
||||
if err := vcsCmd.TagSync(root, selectTag(vers, tags)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1,192 +0,0 @@
|
||||
// Copyright 2018 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 get
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// The following functions are copied verbatim from golang.org/x/mod/module/module.go,
|
||||
// with a change to additionally reject Windows short-names,
|
||||
// and one to accept arbitrary letters (golang.org/issue/29101).
|
||||
//
|
||||
// TODO(bcmills): After the call site for this function is backported,
|
||||
// consolidate this back down to a single copy.
|
||||
//
|
||||
// NOTE: DO NOT MERGE THESE UNTIL WE DECIDE ABOUT ARBITRARY LETTERS IN MODULE MODE.
|
||||
|
||||
// CheckImportPath checks that an import path is valid.
|
||||
func CheckImportPath(path string) error {
|
||||
if err := checkPath(path, false); err != nil {
|
||||
return fmt.Errorf("malformed import path %q: %v", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkPath checks that a general path is valid.
|
||||
// It returns an error describing why but not mentioning path.
|
||||
// Because these checks apply to both module paths and import paths,
|
||||
// the caller is expected to add the "malformed ___ path %q: " prefix.
|
||||
// fileName indicates whether the final element of the path is a file name
|
||||
// (as opposed to a directory name).
|
||||
func checkPath(path string, fileName bool) error {
|
||||
if !utf8.ValidString(path) {
|
||||
return fmt.Errorf("invalid UTF-8")
|
||||
}
|
||||
if path == "" {
|
||||
return fmt.Errorf("empty string")
|
||||
}
|
||||
if path[0] == '-' {
|
||||
return fmt.Errorf("leading dash")
|
||||
}
|
||||
if strings.Contains(path, "//") {
|
||||
return fmt.Errorf("double slash")
|
||||
}
|
||||
if path[len(path)-1] == '/' {
|
||||
return fmt.Errorf("trailing slash")
|
||||
}
|
||||
elemStart := 0
|
||||
for i, r := range path {
|
||||
if r == '/' {
|
||||
if err := checkElem(path[elemStart:i], fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
elemStart = i + 1
|
||||
}
|
||||
}
|
||||
if err := checkElem(path[elemStart:], fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkElem checks whether an individual path element is valid.
|
||||
// fileName indicates whether the element is a file name (not a directory name).
|
||||
func checkElem(elem string, fileName bool) error {
|
||||
if elem == "" {
|
||||
return fmt.Errorf("empty path element")
|
||||
}
|
||||
if strings.Count(elem, ".") == len(elem) {
|
||||
return fmt.Errorf("invalid path element %q", elem)
|
||||
}
|
||||
if elem[0] == '.' && !fileName {
|
||||
return fmt.Errorf("leading dot in path element")
|
||||
}
|
||||
if elem[len(elem)-1] == '.' {
|
||||
return fmt.Errorf("trailing dot in path element")
|
||||
}
|
||||
|
||||
charOK := pathOK
|
||||
if fileName {
|
||||
charOK = fileNameOK
|
||||
}
|
||||
for _, r := range elem {
|
||||
if !charOK(r) {
|
||||
return fmt.Errorf("invalid char %q", r)
|
||||
}
|
||||
}
|
||||
|
||||
// Windows disallows a bunch of path elements, sadly.
|
||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
||||
short := elem
|
||||
if i := strings.Index(short, "."); i >= 0 {
|
||||
short = short[:i]
|
||||
}
|
||||
for _, bad := range badWindowsNames {
|
||||
if strings.EqualFold(bad, short) {
|
||||
return fmt.Errorf("disallowed path element %q", elem)
|
||||
}
|
||||
}
|
||||
|
||||
// Reject path components that look like Windows short-names.
|
||||
// Those usually end in a tilde followed by one or more ASCII digits.
|
||||
if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 {
|
||||
suffix := short[tilde+1:]
|
||||
suffixIsDigits := true
|
||||
for _, r := range suffix {
|
||||
if r < '0' || r > '9' {
|
||||
suffixIsDigits = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if suffixIsDigits {
|
||||
return fmt.Errorf("trailing tilde and digits in path element")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pathOK reports whether r can appear in an import path element.
|
||||
//
|
||||
// NOTE: This function DIVERGES from module mode pathOK by accepting Unicode letters.
|
||||
func pathOK(r rune) bool {
|
||||
if r < utf8.RuneSelf {
|
||||
return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' ||
|
||||
'0' <= r && r <= '9' ||
|
||||
'A' <= r && r <= 'Z' ||
|
||||
'a' <= r && r <= 'z'
|
||||
}
|
||||
return unicode.IsLetter(r)
|
||||
}
|
||||
|
||||
// fileNameOK reports whether r can appear in a file name.
|
||||
// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
|
||||
// If we expand the set of allowed characters here, we have to
|
||||
// work harder at detecting potential case-folding and normalization collisions.
|
||||
// See note about "safe encoding" below.
|
||||
func fileNameOK(r rune) bool {
|
||||
if r < utf8.RuneSelf {
|
||||
// Entire set of ASCII punctuation, from which we remove characters:
|
||||
// ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
|
||||
// We disallow some shell special characters: " ' * < > ? ` |
|
||||
// (Note that some of those are disallowed by the Windows file system as well.)
|
||||
// We also disallow path separators / : and \ (fileNameOK is only called on path element characters).
|
||||
// We allow spaces (U+0020) in file names.
|
||||
const allowed = "!#$%&()+,-.=@[]^_{}~ "
|
||||
if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
|
||||
return true
|
||||
}
|
||||
for i := 0; i < len(allowed); i++ {
|
||||
if rune(allowed[i]) == r {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
// It may be OK to add more ASCII punctuation here, but only carefully.
|
||||
// For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
|
||||
return unicode.IsLetter(r)
|
||||
}
|
||||
|
||||
// badWindowsNames are the reserved file path elements on Windows.
|
||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
||||
var badWindowsNames = []string{
|
||||
"CON",
|
||||
"PRN",
|
||||
"AUX",
|
||||
"NUL",
|
||||
"COM1",
|
||||
"COM2",
|
||||
"COM3",
|
||||
"COM4",
|
||||
"COM5",
|
||||
"COM6",
|
||||
"COM7",
|
||||
"COM8",
|
||||
"COM9",
|
||||
"LPT1",
|
||||
"LPT2",
|
||||
"LPT3",
|
||||
"LPT4",
|
||||
"LPT5",
|
||||
"LPT6",
|
||||
"LPT7",
|
||||
"LPT8",
|
||||
"LPT9",
|
||||
}
|
@ -10,6 +10,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
@ -215,6 +216,7 @@ applied to a Go struct, but now a Module struct:
|
||||
Dir string // directory holding files for this module, if any
|
||||
GoMod string // path to go.mod file used when loading this module, if any
|
||||
GoVersion string // go version used in module
|
||||
Retracted string // retraction information, if any (with -retracted or -u)
|
||||
Error *ModuleError // error loading module
|
||||
}
|
||||
|
||||
@ -246,14 +248,16 @@ the replaced source code.)
|
||||
The -u flag adds information about available upgrades.
|
||||
When the latest version of a given module is newer than
|
||||
the current one, list -u sets the Module's Update field
|
||||
to information about the newer module.
|
||||
to information about the newer module. list -u will also set
|
||||
the module's Retracted field if the current version is retracted.
|
||||
The Module's String method indicates an available upgrade by
|
||||
formatting the newer version in brackets after the current version.
|
||||
If a version is retracted, the string "(retracted)" will follow it.
|
||||
For example, 'go list -m -u all' might print:
|
||||
|
||||
my/main/module
|
||||
golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
|
||||
rsc.io/pdf v0.1.1 [v0.1.2]
|
||||
rsc.io/pdf v0.1.1 (retracted) [v0.1.2]
|
||||
|
||||
(For tools, 'go list -m -u -json all' may be more convenient to parse.)
|
||||
|
||||
@ -263,6 +267,14 @@ to semantic versioning, earliest to latest. The flag also changes
|
||||
the default output format to display the module path followed by the
|
||||
space-separated version list.
|
||||
|
||||
The -retracted flag causes list to report information about retracted
|
||||
module versions. When -retracted is used with -f or -json, the Retracted
|
||||
field will be set to a string explaining why the version was retracted.
|
||||
The string is taken from comments on the retract directive in the
|
||||
module's go.mod file. When -retracted is used with -versions, retracted
|
||||
versions are listed together with unretracted versions. The -retracted
|
||||
flag may be used with or without -m.
|
||||
|
||||
The arguments to list -m are interpreted as a list of modules, not packages.
|
||||
The main module is the module containing the current directory.
|
||||
The active modules are the main module and its dependencies.
|
||||
@ -296,17 +308,18 @@ func init() {
|
||||
}
|
||||
|
||||
var (
|
||||
listCompiled = CmdList.Flag.Bool("compiled", false, "")
|
||||
listDeps = CmdList.Flag.Bool("deps", false, "")
|
||||
listE = CmdList.Flag.Bool("e", false, "")
|
||||
listExport = CmdList.Flag.Bool("export", false, "")
|
||||
listFmt = CmdList.Flag.String("f", "", "")
|
||||
listFind = CmdList.Flag.Bool("find", false, "")
|
||||
listJson = CmdList.Flag.Bool("json", false, "")
|
||||
listM = CmdList.Flag.Bool("m", false, "")
|
||||
listU = CmdList.Flag.Bool("u", false, "")
|
||||
listTest = CmdList.Flag.Bool("test", false, "")
|
||||
listVersions = CmdList.Flag.Bool("versions", false, "")
|
||||
listCompiled = CmdList.Flag.Bool("compiled", false, "")
|
||||
listDeps = CmdList.Flag.Bool("deps", false, "")
|
||||
listE = CmdList.Flag.Bool("e", false, "")
|
||||
listExport = CmdList.Flag.Bool("export", false, "")
|
||||
listFmt = CmdList.Flag.String("f", "", "")
|
||||
listFind = CmdList.Flag.Bool("find", false, "")
|
||||
listJson = CmdList.Flag.Bool("json", false, "")
|
||||
listM = CmdList.Flag.Bool("m", false, "")
|
||||
listRetracted = CmdList.Flag.Bool("retracted", false, "")
|
||||
listTest = CmdList.Flag.Bool("test", false, "")
|
||||
listU = CmdList.Flag.Bool("u", false, "")
|
||||
listVersions = CmdList.Flag.Bool("versions", false, "")
|
||||
)
|
||||
|
||||
var nl = []byte{'\n'}
|
||||
@ -367,6 +380,16 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
modload.Init()
|
||||
if *listRetracted {
|
||||
if cfg.BuildMod == "vendor" {
|
||||
base.Fatalf("go list -retracted cannot be used when vendoring is enabled")
|
||||
}
|
||||
if !modload.Enabled() {
|
||||
base.Fatalf("go list -retracted can only be used in module-aware mode")
|
||||
}
|
||||
}
|
||||
|
||||
if *listM {
|
||||
// Module mode.
|
||||
if *listCompiled {
|
||||
@ -414,9 +437,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
modload.LoadBuildList(ctx)
|
||||
|
||||
mods := modload.ListModules(ctx, args, *listU, *listVersions)
|
||||
mods := modload.ListModules(ctx, args, *listU, *listVersions, *listRetracted)
|
||||
if !*listE {
|
||||
for _, m := range mods {
|
||||
if m.Error != nil {
|
||||
@ -522,7 +543,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
// Note that -deps is applied after -test,
|
||||
// so that you only get descriptions of tests for the things named
|
||||
// explicitly on the command line, not for all dependencies.
|
||||
pkgs = load.PackageList(pkgs)
|
||||
pkgs = loadPackageList(pkgs)
|
||||
}
|
||||
|
||||
// Do we need to run a build to gather information?
|
||||
@ -557,7 +578,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
if *listTest {
|
||||
all := pkgs
|
||||
if !*listDeps {
|
||||
all = load.PackageList(pkgs)
|
||||
all = loadPackageList(pkgs)
|
||||
}
|
||||
// Update import paths to distinguish the real package p
|
||||
// from p recompiled for q.test.
|
||||
@ -607,6 +628,55 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(golang.org/issue/40676): This mechanism could be extended to support
|
||||
// -u without -m.
|
||||
if *listRetracted {
|
||||
// Load retractions for modules that provide packages that will be printed.
|
||||
// TODO(golang.org/issue/40775): Packages from the same module refer to
|
||||
// distinct ModulePublic instance. It would be nice if they could all point
|
||||
// to the same instance. This would require additional global state in
|
||||
// modload.loaded, so that should be refactored first. For now, we update
|
||||
// all instances.
|
||||
modToArg := make(map[*modinfo.ModulePublic]string)
|
||||
argToMods := make(map[string][]*modinfo.ModulePublic)
|
||||
var args []string
|
||||
addModule := func(mod *modinfo.ModulePublic) {
|
||||
if mod.Version == "" {
|
||||
return
|
||||
}
|
||||
arg := fmt.Sprintf("%s@%s", mod.Path, mod.Version)
|
||||
if argToMods[arg] == nil {
|
||||
args = append(args, arg)
|
||||
}
|
||||
argToMods[arg] = append(argToMods[arg], mod)
|
||||
modToArg[mod] = arg
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
if p.Module == nil {
|
||||
continue
|
||||
}
|
||||
addModule(p.Module)
|
||||
if p.Module.Replace != nil {
|
||||
addModule(p.Module.Replace)
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
listU := false
|
||||
listVersions := false
|
||||
rmods := modload.ListModules(ctx, args, listU, listVersions, *listRetracted)
|
||||
for i, arg := range args {
|
||||
rmod := rmods[i]
|
||||
for _, mod := range argToMods[arg] {
|
||||
mod.Retracted = rmod.Retracted
|
||||
if rmod.Error != nil && mod.Error == nil {
|
||||
mod.Error = rmod.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Record non-identity import mappings in p.ImportMap.
|
||||
for _, p := range pkgs {
|
||||
for i, srcPath := range p.Internal.RawImports {
|
||||
@ -625,6 +695,23 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// loadPackageList is like load.PackageList, but prints error messages and exits
|
||||
// with nonzero status if listE is not set and any package in the expanded list
|
||||
// has errors.
|
||||
func loadPackageList(roots []*load.Package) []*load.Package {
|
||||
pkgs := load.PackageList(roots)
|
||||
|
||||
if !*listE {
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.Error != nil {
|
||||
base.Errorf("%v", pkg.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pkgs
|
||||
}
|
||||
|
||||
// TrackingWriter tracks the last byte written on every write so
|
||||
// we can avoid printing a newline if one was already written or
|
||||
// if there is no output at all.
|
||||
|
@ -191,6 +191,7 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
|
||||
GoFiles: p.XTestGoFiles,
|
||||
Imports: p.XTestImports,
|
||||
ForTest: p.ImportPath,
|
||||
Module: p.Module,
|
||||
Error: pxtestErr,
|
||||
},
|
||||
Internal: PackageInternal{
|
||||
@ -222,6 +223,7 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
|
||||
ImportPath: p.ImportPath + ".test",
|
||||
Root: p.Root,
|
||||
Imports: str.StringList(TestMainDeps),
|
||||
Module: p.Module,
|
||||
},
|
||||
Internal: PackageInternal{
|
||||
Build: &build.Package{Name: "main"},
|
||||
|
@ -12,9 +12,8 @@ import (
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/work"
|
||||
"cmd/go/internal/modload"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
@ -64,7 +63,7 @@ func init() {
|
||||
|
||||
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
|
||||
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
|
||||
work.AddModCommonFlags(cmdDownload)
|
||||
base.AddModCommonFlags(&cmdDownload.Flag)
|
||||
}
|
||||
|
||||
type moduleJSON struct {
|
||||
@ -136,9 +135,10 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||
var mods []*moduleJSON
|
||||
listU := false
|
||||
listVersions := false
|
||||
listRetractions := false
|
||||
type token struct{}
|
||||
sem := make(chan token, runtime.GOMAXPROCS(0))
|
||||
for _, info := range modload.ListModules(ctx, args, listU, listVersions) {
|
||||
for _, info := range modload.ListModules(ctx, args, listU, listVersions, listRetractions) {
|
||||
if info.Replace != nil {
|
||||
info = info.Replace
|
||||
}
|
||||
@ -187,4 +187,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
}
|
||||
|
||||
// Update go.mod and especially go.sum if needed.
|
||||
modload.WriteGoMod()
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ import (
|
||||
"cmd/go/internal/lockedfile"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/mod/module"
|
||||
@ -68,9 +67,14 @@ The -dropreplace=old[@v] flag drops a replacement of the given
|
||||
module path and version pair. If the @v is omitted, a replacement without
|
||||
a version on the left side is dropped.
|
||||
|
||||
The -retract=version and -dropretract=version flags add and drop a
|
||||
retraction on the given version. The version may be a single version
|
||||
like "v1.2.3" or a closed interval like "[v1.1.0-v1.1.9]". Note that
|
||||
-retract=version is a no-op if that retraction already exists.
|
||||
|
||||
The -require, -droprequire, -exclude, -dropexclude, -replace,
|
||||
and -dropreplace editing flags may be repeated, and the changes
|
||||
are applied in the order given.
|
||||
-dropreplace, -retract, and -dropretract editing flags may be repeated,
|
||||
and the changes are applied in the order given.
|
||||
|
||||
The -go=version flag sets the expected Go language version.
|
||||
|
||||
@ -104,6 +108,15 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
|
||||
New Module
|
||||
}
|
||||
|
||||
type Retract struct {
|
||||
Low string
|
||||
High string
|
||||
Rationale string
|
||||
}
|
||||
|
||||
Retract entries representing a single version (not an interval) will have
|
||||
the "Low" and "High" fields set to the same value.
|
||||
|
||||
Note that this only describes the go.mod file itself, not other modules
|
||||
referred to indirectly. For the full set of modules available to a build,
|
||||
use 'go list -m -json all'.
|
||||
@ -137,8 +150,10 @@ func init() {
|
||||
cmdEdit.Flag.Var(flagFunc(flagDropReplace), "dropreplace", "")
|
||||
cmdEdit.Flag.Var(flagFunc(flagReplace), "replace", "")
|
||||
cmdEdit.Flag.Var(flagFunc(flagDropExclude), "dropexclude", "")
|
||||
cmdEdit.Flag.Var(flagFunc(flagRetract), "retract", "")
|
||||
cmdEdit.Flag.Var(flagFunc(flagDropRetract), "dropretract", "")
|
||||
|
||||
work.AddModCommonFlags(cmdEdit)
|
||||
base.AddModCommonFlags(&cmdEdit.Flag)
|
||||
base.AddBuildFlagsNX(&cmdEdit.Flag)
|
||||
}
|
||||
|
||||
@ -252,12 +267,7 @@ func parsePathVersion(flag, arg string) (path, version string) {
|
||||
base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err)
|
||||
}
|
||||
|
||||
// We don't call modfile.CheckPathVersion, because that insists
|
||||
// on versions being in semver form, but here we want to allow
|
||||
// versions like "master" or "1234abcdef", which the go command will resolve
|
||||
// the next time it runs (or during -fix).
|
||||
// Even so, we need to make sure the version is a valid token.
|
||||
if modfile.MustQuote(version) {
|
||||
if !allowedVersionArg(version) {
|
||||
base.Fatalf("go mod: -%s=%s: invalid version %q", flag, arg, version)
|
||||
}
|
||||
|
||||
@ -289,12 +299,48 @@ func parsePathVersionOptional(adj, arg string, allowDirPath bool) (path, version
|
||||
return path, version, fmt.Errorf("invalid %s path: %v", adj, err)
|
||||
}
|
||||
}
|
||||
if path != arg && modfile.MustQuote(version) {
|
||||
if path != arg && !allowedVersionArg(version) {
|
||||
return path, version, fmt.Errorf("invalid %s version: %q", adj, version)
|
||||
}
|
||||
return path, version, nil
|
||||
}
|
||||
|
||||
// parseVersionInterval parses a single version like "v1.2.3" or a closed
|
||||
// interval like "[v1.2.3,v1.4.5]". Note that a single version has the same
|
||||
// representation as an interval with equal upper and lower bounds: both
|
||||
// Low and High are set.
|
||||
func parseVersionInterval(arg string) (modfile.VersionInterval, error) {
|
||||
if !strings.HasPrefix(arg, "[") {
|
||||
if !allowedVersionArg(arg) {
|
||||
return modfile.VersionInterval{}, fmt.Errorf("invalid version: %q", arg)
|
||||
}
|
||||
return modfile.VersionInterval{Low: arg, High: arg}, nil
|
||||
}
|
||||
if !strings.HasSuffix(arg, "]") {
|
||||
return modfile.VersionInterval{}, fmt.Errorf("invalid version interval: %q", arg)
|
||||
}
|
||||
s := arg[1 : len(arg)-1]
|
||||
i := strings.Index(s, ",")
|
||||
if i < 0 {
|
||||
return modfile.VersionInterval{}, fmt.Errorf("invalid version interval: %q", arg)
|
||||
}
|
||||
low := strings.TrimSpace(s[:i])
|
||||
high := strings.TrimSpace(s[i+1:])
|
||||
if !allowedVersionArg(low) || !allowedVersionArg(high) {
|
||||
return modfile.VersionInterval{}, fmt.Errorf("invalid version interval: %q", arg)
|
||||
}
|
||||
return modfile.VersionInterval{Low: low, High: high}, nil
|
||||
}
|
||||
|
||||
// allowedVersionArg returns whether a token may be used as a version in go.mod.
|
||||
// We don't call modfile.CheckPathVersion, because that insists on versions
|
||||
// being in semver form, but here we want to allow versions like "master" or
|
||||
// "1234abcdef", which the go command will resolve the next time it runs (or
|
||||
// during -fix). Even so, we need to make sure the version is a valid token.
|
||||
func allowedVersionArg(arg string) bool {
|
||||
return !modfile.MustQuote(arg)
|
||||
}
|
||||
|
||||
// flagRequire implements the -require flag.
|
||||
func flagRequire(arg string) {
|
||||
path, version := parsePathVersion("require", arg)
|
||||
@ -377,6 +423,32 @@ func flagDropReplace(arg string) {
|
||||
})
|
||||
}
|
||||
|
||||
// flagRetract implements the -retract flag.
|
||||
func flagRetract(arg string) {
|
||||
vi, err := parseVersionInterval(arg)
|
||||
if err != nil {
|
||||
base.Fatalf("go mod: -retract=%s: %v", arg, err)
|
||||
}
|
||||
edits = append(edits, func(f *modfile.File) {
|
||||
if err := f.AddRetract(vi, ""); err != nil {
|
||||
base.Fatalf("go mod: -retract=%s: %v", arg, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// flagDropRetract implements the -dropretract flag.
|
||||
func flagDropRetract(arg string) {
|
||||
vi, err := parseVersionInterval(arg)
|
||||
if err != nil {
|
||||
base.Fatalf("go mod: -dropretract=%s: %v", arg, err)
|
||||
}
|
||||
edits = append(edits, func(f *modfile.File) {
|
||||
if err := f.DropRetract(vi); err != nil {
|
||||
base.Fatalf("go mod: -dropretract=%s: %v", arg, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// fileJSON is the -json output data structure.
|
||||
type fileJSON struct {
|
||||
Module module.Version
|
||||
@ -384,6 +456,7 @@ type fileJSON struct {
|
||||
Require []requireJSON
|
||||
Exclude []module.Version
|
||||
Replace []replaceJSON
|
||||
Retract []retractJSON
|
||||
}
|
||||
|
||||
type requireJSON struct {
|
||||
@ -397,6 +470,12 @@ type replaceJSON struct {
|
||||
New module.Version
|
||||
}
|
||||
|
||||
type retractJSON struct {
|
||||
Low string `json:",omitempty"`
|
||||
High string `json:",omitempty"`
|
||||
Rationale string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// editPrintJSON prints the -json output.
|
||||
func editPrintJSON(modFile *modfile.File) {
|
||||
var f fileJSON
|
||||
@ -415,6 +494,9 @@ func editPrintJSON(modFile *modfile.File) {
|
||||
for _, r := range modFile.Replace {
|
||||
f.Replace = append(f.Replace, replaceJSON{r.Old, r.New})
|
||||
}
|
||||
for _, r := range modFile.Retract {
|
||||
f.Retract = append(f.Retract, retractJSON{r.Low, r.High, r.Rationale})
|
||||
}
|
||||
data, err := json.MarshalIndent(&f, "", "\t")
|
||||
if err != nil {
|
||||
base.Fatalf("go: internal error: %v", err)
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
@ -33,7 +32,7 @@ path@version, except for the main module, which has no @version suffix.
|
||||
}
|
||||
|
||||
func init() {
|
||||
work.AddModCommonFlags(cmdGraph)
|
||||
base.AddModCommonFlags(&cmdGraph.Flag)
|
||||
}
|
||||
|
||||
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
|
||||
@ -48,7 +47,7 @@ func runGraph(ctx context.Context, cmd *base.Command, args []string) {
|
||||
base.Fatalf("go: cannot find main module; see 'go help modules'")
|
||||
}
|
||||
}
|
||||
modload.LoadBuildList(ctx)
|
||||
modload.LoadAllModules(ctx)
|
||||
|
||||
reqs := modload.MinReqs()
|
||||
format := func(m module.Version) string {
|
||||
|
@ -9,7 +9,6 @@ package modcmd
|
||||
import (
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
@ -30,7 +29,7 @@ To override this guess, supply the module path as an argument.
|
||||
}
|
||||
|
||||
func init() {
|
||||
work.AddModCommonFlags(cmdInit)
|
||||
base.AddModCommonFlags(&cmdInit.Flag)
|
||||
}
|
||||
|
||||
func runInit(ctx context.Context, cmd *base.Command, args []string) {
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
"context"
|
||||
)
|
||||
|
||||
@ -32,7 +31,7 @@ to standard error.
|
||||
func init() {
|
||||
cmdTidy.Run = runTidy // break init cycle
|
||||
cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
||||
work.AddModCommonFlags(cmdTidy)
|
||||
base.AddModCommonFlags(&cmdTidy.Flag)
|
||||
}
|
||||
|
||||
func runTidy(ctx context.Context, cmd *base.Command, args []string) {
|
||||
@ -40,6 +39,18 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) {
|
||||
base.Fatalf("go mod tidy: no arguments allowed")
|
||||
}
|
||||
|
||||
// Tidy aims to make 'go test' reproducible for any package in 'all', so we
|
||||
// need to include test dependencies. For modules that specify go 1.15 or
|
||||
// earlier this is a no-op (because 'all' saturates transitive test
|
||||
// dependencies).
|
||||
//
|
||||
// However, with lazy loading (go 1.16+) 'all' includes only the packages that
|
||||
// are transitively imported by the main module, not the test dependencies of
|
||||
// those packages. In order to make 'go test' reproducible for the packages
|
||||
// that are in 'all' but outside of the main module, we must explicitly
|
||||
// request that their test dependencies be included.
|
||||
modload.LoadTests = true
|
||||
|
||||
modload.LoadALL(ctx)
|
||||
modload.TidyBuildList()
|
||||
modload.TrimGoSum()
|
||||
|
@ -19,7 +19,6 @@ import (
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/imports"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/semver"
|
||||
@ -41,7 +40,7 @@ modules and packages to standard error.
|
||||
|
||||
func init() {
|
||||
cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
||||
work.AddModCommonFlags(cmdVendor)
|
||||
base.AddModCommonFlags(&cmdVendor.Flag)
|
||||
}
|
||||
|
||||
func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||
@ -77,7 +76,7 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
for _, m := range modload.BuildList()[1:] {
|
||||
for _, m := range modload.LoadedModules()[1:] {
|
||||
if pkgs := modpkgs[m]; len(pkgs) > 0 || isExplicit[m] {
|
||||
line := moduleLine(m, modload.Replacement(m))
|
||||
buf.WriteString(line)
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/sumdb/dirhash"
|
||||
@ -38,7 +37,7 @@ non-zero status.
|
||||
}
|
||||
|
||||
func init() {
|
||||
work.AddModCommonFlags(cmdVerify)
|
||||
base.AddModCommonFlags(&cmdVerify.Flag)
|
||||
}
|
||||
|
||||
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
||||
@ -60,7 +59,7 @@ func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
||||
sem := make(chan token, runtime.GOMAXPROCS(0))
|
||||
|
||||
// Use a slice of result channels, so that the output is deterministic.
|
||||
mods := modload.LoadBuildList(ctx)[1:]
|
||||
mods := modload.LoadAllModules(ctx)[1:]
|
||||
errsChans := make([]<-chan []error, len(mods))
|
||||
|
||||
for i, mod := range mods {
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
@ -58,23 +57,26 @@ var (
|
||||
|
||||
func init() {
|
||||
cmdWhy.Run = runWhy // break init cycle
|
||||
work.AddModCommonFlags(cmdWhy)
|
||||
base.AddModCommonFlags(&cmdWhy.Flag)
|
||||
}
|
||||
|
||||
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
|
||||
loadALL := modload.LoadALL
|
||||
if *whyVendor {
|
||||
loadALL = modload.LoadVendor
|
||||
} else {
|
||||
modload.LoadTests = true
|
||||
}
|
||||
if *whyM {
|
||||
listU := false
|
||||
listVersions := false
|
||||
listRetractions := false
|
||||
for _, arg := range args {
|
||||
if strings.Contains(arg, "@") {
|
||||
base.Fatalf("go mod why: module query not allowed")
|
||||
}
|
||||
}
|
||||
mods := modload.ListModules(ctx, args, listU, listVersions)
|
||||
mods := modload.ListModules(ctx, args, listU, listVersions, listRetractions)
|
||||
byModule := make(map[module.Version][]string)
|
||||
for _, path := range loadALL(ctx) {
|
||||
m := modload.PackageModule(path)
|
||||
|
@ -503,6 +503,9 @@ func checkGoMod(path, version string, data []byte) error {
|
||||
}
|
||||
|
||||
// checkModSum checks that the recorded checksum for mod is h.
|
||||
//
|
||||
// mod.Version may have the additional suffix "/go.mod" to request the checksum
|
||||
// for the module's go.mod file only.
|
||||
func checkModSum(mod module.Version, h string) error {
|
||||
// We lock goSum when manipulating it,
|
||||
// but we arrange to release the lock when calling checkSumDB,
|
||||
@ -579,9 +582,16 @@ func addModSumLocked(mod module.Version, h string) {
|
||||
// checkSumDB checks the mod, h pair against the Go checksum database.
|
||||
// It calls base.Fatalf if the hash is to be rejected.
|
||||
func checkSumDB(mod module.Version, h string) error {
|
||||
modWithoutSuffix := mod
|
||||
noun := "module"
|
||||
if strings.HasSuffix(mod.Version, "/go.mod") {
|
||||
noun = "go.mod"
|
||||
modWithoutSuffix.Version = strings.TrimSuffix(mod.Version, "/go.mod")
|
||||
}
|
||||
|
||||
db, lines, err := lookupSumDB(mod)
|
||||
if err != nil {
|
||||
return module.VersionError(mod, fmt.Errorf("verifying module: %v", err))
|
||||
return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: %v", noun, err))
|
||||
}
|
||||
|
||||
have := mod.Path + " " + mod.Version + " " + h
|
||||
@ -591,7 +601,7 @@ func checkSumDB(mod module.Version, h string) error {
|
||||
return nil
|
||||
}
|
||||
if strings.HasPrefix(line, prefix) {
|
||||
return module.VersionError(mod, fmt.Errorf("verifying module: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, h, db, line[len(prefix)-len("h1:"):]))
|
||||
return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, noun, h, db, line[len(prefix)-len("h1:"):]))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -6,12 +6,11 @@ package modfetch
|
||||
|
||||
import (
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/get"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
|
||||
// allowInsecure reports whether we are allowed to fetch this path in an insecure manner.
|
||||
func allowInsecure(path string) bool {
|
||||
return get.Insecure || module.MatchPrefixPatterns(cfg.GOINSECURE, path)
|
||||
return cfg.Insecure || module.MatchPrefixPatterns(cfg.GOINSECURE, path)
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ import (
|
||||
"time"
|
||||
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/get"
|
||||
"cmd/go/internal/modfetch/codehost"
|
||||
"cmd/go/internal/par"
|
||||
"cmd/go/internal/vcs"
|
||||
web "cmd/go/internal/web"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
@ -261,13 +261,13 @@ func lookupDirect(path string) (Repo, error) {
|
||||
if allowInsecure(path) {
|
||||
security = web.Insecure
|
||||
}
|
||||
rr, err := get.RepoRootForImportPath(path, get.PreferMod, security)
|
||||
rr, err := vcs.RepoRootForImportPath(path, vcs.PreferMod, security)
|
||||
if err != nil {
|
||||
// We don't know where to find code for a module with this path.
|
||||
return nil, notExistError{err: err}
|
||||
}
|
||||
|
||||
if rr.VCS == "mod" {
|
||||
if rr.VCS.Name == "mod" {
|
||||
// Fetch module from proxy with base URL rr.Repo.
|
||||
return newProxyRepo(rr.Repo, path)
|
||||
}
|
||||
@ -279,8 +279,8 @@ func lookupDirect(path string) (Repo, error) {
|
||||
return newCodeRepo(code, rr.Root, path)
|
||||
}
|
||||
|
||||
func lookupCodeRepo(rr *get.RepoRoot) (codehost.Repo, error) {
|
||||
code, err := codehost.NewRepo(rr.VCS, rr.Repo)
|
||||
func lookupCodeRepo(rr *vcs.RepoRoot) (codehost.Repo, error) {
|
||||
code, err := codehost.NewRepo(rr.VCS.Cmd, rr.Repo)
|
||||
if err != nil {
|
||||
if _, ok := err.(*codehost.VCSError); ok {
|
||||
return nil, err
|
||||
@ -306,7 +306,7 @@ func ImportRepoRev(path, rev string) (Repo, *RevInfo, error) {
|
||||
if allowInsecure(path) {
|
||||
security = web.Insecure
|
||||
}
|
||||
rr, err := get.RepoRootForImportPath(path, get.IgnoreMod, security)
|
||||
rr, err := vcs.RepoRootForImportPath(path, vcs.IgnoreMod, security)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/get"
|
||||
"cmd/go/internal/lockedfile"
|
||||
"cmd/go/internal/web"
|
||||
|
||||
@ -33,7 +32,7 @@ import (
|
||||
|
||||
// useSumDB reports whether to use the Go checksum database for the given module.
|
||||
func useSumDB(mod module.Version) bool {
|
||||
return cfg.GOSUMDB != "off" && !get.Insecure && !module.MatchPrefixPatterns(cfg.GONOSUMDB, mod.Path)
|
||||
return cfg.GOSUMDB != "off" && !cfg.Insecure && !module.MatchPrefixPatterns(cfg.GONOSUMDB, mod.Path)
|
||||
}
|
||||
|
||||
// lookupSumDB returns the Go checksum database's go.sum lines for the given module,
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/get"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/imports"
|
||||
"cmd/go/internal/load"
|
||||
"cmd/go/internal/modload"
|
||||
@ -181,7 +181,7 @@ var (
|
||||
getM = CmdGet.Flag.Bool("m", false, "")
|
||||
getT = CmdGet.Flag.Bool("t", false, "")
|
||||
getU upgradeFlag
|
||||
// -insecure is get.Insecure
|
||||
// -insecure is cfg.Insecure
|
||||
// -v is cfg.BuildV
|
||||
)
|
||||
|
||||
@ -206,7 +206,7 @@ func (v *upgradeFlag) String() string { return "" }
|
||||
func init() {
|
||||
work.AddBuildFlags(CmdGet, work.OmitModFlag)
|
||||
CmdGet.Run = runGet // break init loop
|
||||
CmdGet.Flag.BoolVar(&get.Insecure, "insecure", get.Insecure, "")
|
||||
CmdGet.Flag.BoolVar(&cfg.Insecure, "insecure", cfg.Insecure, "")
|
||||
CmdGet.Flag.Var(&getU, "u", "")
|
||||
}
|
||||
|
||||
@ -278,7 +278,7 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||
}
|
||||
modload.LoadTests = *getT
|
||||
|
||||
buildList := modload.LoadBuildList(ctx)
|
||||
buildList := modload.LoadAllModules(ctx)
|
||||
buildList = buildList[:len(buildList):len(buildList)] // copy on append
|
||||
versionByPath := make(map[string]string)
|
||||
for _, m := range buildList {
|
||||
@ -290,7 +290,7 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||
// what was requested.
|
||||
modload.DisallowWriteGoMod()
|
||||
|
||||
// Allow looking up modules for import paths outside of a module.
|
||||
// Allow looking up modules for import paths when outside of a module.
|
||||
// 'go get' is expected to do this, unlike other commands.
|
||||
modload.AllowMissingModuleImports()
|
||||
|
||||
@ -599,7 +599,7 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||
base.ExitIfErrors()
|
||||
|
||||
// Stop if no changes have been made to the build list.
|
||||
buildList = modload.BuildList()
|
||||
buildList = modload.LoadedModules()
|
||||
eq := len(buildList) == len(prevBuildList)
|
||||
for i := 0; eq && i < len(buildList); i++ {
|
||||
eq = buildList[i] == prevBuildList[i]
|
||||
@ -617,7 +617,7 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||
|
||||
// Handle downgrades.
|
||||
var down []module.Version
|
||||
for _, m := range modload.BuildList() {
|
||||
for _, m := range modload.LoadedModules() {
|
||||
q := byPath[m.Path]
|
||||
if q != nil && semver.Compare(m.Version, q.m.Version) > 0 {
|
||||
down = append(down, module.Version{Path: m.Path, Version: q.m.Version})
|
||||
@ -628,6 +628,10 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||
if err != nil {
|
||||
base.Fatalf("go: %v", err)
|
||||
}
|
||||
|
||||
// TODO(bcmills) What should happen here under lazy loading?
|
||||
// Downgrading may intentionally violate the lazy-loading invariants.
|
||||
|
||||
modload.SetBuildList(buildList)
|
||||
modload.ReloadBuildList() // note: does not update go.mod
|
||||
base.ExitIfErrors()
|
||||
@ -637,7 +641,7 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||
var lostUpgrades []*query
|
||||
if len(down) > 0 {
|
||||
versionByPath = make(map[string]string)
|
||||
for _, m := range modload.BuildList() {
|
||||
for _, m := range modload.LoadedModules() {
|
||||
versionByPath[m.Path] = m.Version
|
||||
}
|
||||
for _, q := range byPath {
|
||||
@ -702,6 +706,15 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||
// Everything succeeded. Update go.mod.
|
||||
modload.AllowWriteGoMod()
|
||||
modload.WriteGoMod()
|
||||
modload.DisallowWriteGoMod()
|
||||
|
||||
// Report warnings if any retracted versions are in the build list.
|
||||
// This must be done after writing go.mod to avoid spurious '// indirect'
|
||||
// comments. These functions read and write global state.
|
||||
// TODO(golang.org/issue/40775): ListModules resets modload.loader, which
|
||||
// contains information about direct dependencies that WriteGoMod uses.
|
||||
// Refactor to avoid these kinds of global side effects.
|
||||
reportRetractions(ctx)
|
||||
|
||||
// If -d was specified, we're done after the module work.
|
||||
// We've already downloaded modules by loading packages above.
|
||||
@ -804,6 +817,14 @@ func getQuery(ctx context.Context, path, vers string, prevM module.Version, forc
|
||||
base.Fatalf("go get: internal error: prevM may be set if and only if forceModulePath is set")
|
||||
}
|
||||
|
||||
// If vers is a query like "latest", we should ignore retracted and excluded
|
||||
// versions. If vers refers to a specific version or commit like "v1.0.0"
|
||||
// or "master", we should only ignore excluded versions.
|
||||
allowed := modload.CheckAllowed
|
||||
if modload.IsRevisionQuery(vers) {
|
||||
allowed = modload.CheckExclusions
|
||||
}
|
||||
|
||||
// If the query must be a module path, try only that module path.
|
||||
if forceModulePath {
|
||||
if path == modload.Target.Path {
|
||||
@ -812,7 +833,7 @@ func getQuery(ctx context.Context, path, vers string, prevM module.Version, forc
|
||||
}
|
||||
}
|
||||
|
||||
info, err := modload.Query(ctx, path, vers, prevM.Version, modload.Allowed)
|
||||
info, err := modload.Query(ctx, path, vers, prevM.Version, allowed)
|
||||
if err == nil {
|
||||
if info.Version != vers && info.Version != prevM.Version {
|
||||
logOncef("go: %s %s => %s", path, vers, info.Version)
|
||||
@ -838,7 +859,7 @@ func getQuery(ctx context.Context, path, vers string, prevM module.Version, forc
|
||||
// If it turns out to only exist as a module, we can detect the resulting
|
||||
// PackageNotInModuleError and avoid a second round-trip through (potentially)
|
||||
// all of the configured proxies.
|
||||
results, err := modload.QueryPattern(ctx, path, vers, modload.Allowed)
|
||||
results, err := modload.QueryPattern(ctx, path, vers, allowed)
|
||||
if err != nil {
|
||||
// If the path doesn't contain a wildcard, check whether it was actually a
|
||||
// module path instead. If so, return that.
|
||||
@ -864,190 +885,41 @@ func getQuery(ctx context.Context, path, vers string, prevM module.Version, forc
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// An upgrader adapts an underlying mvs.Reqs to apply an
|
||||
// upgrade policy to a list of targets and their dependencies.
|
||||
type upgrader struct {
|
||||
mvs.Reqs
|
||||
|
||||
// cmdline maps a module path to a query made for that module at a
|
||||
// specific target version. Each query corresponds to a module
|
||||
// matched by a command line argument.
|
||||
cmdline map[string]*query
|
||||
|
||||
// upgrade is a set of modules providing dependencies of packages
|
||||
// matched by command line arguments. If -u or -u=patch is set,
|
||||
// these modules are upgraded accordingly.
|
||||
upgrade map[string]bool
|
||||
}
|
||||
|
||||
// newUpgrader creates an upgrader. cmdline contains queries made at
|
||||
// specific versions for modules matched by command line arguments. pkgs
|
||||
// is the set of packages matched by command line arguments. If -u or -u=patch
|
||||
// is set, modules providing dependencies of pkgs are upgraded accordingly.
|
||||
func newUpgrader(cmdline map[string]*query, pkgs map[string]bool) *upgrader {
|
||||
u := &upgrader{
|
||||
Reqs: modload.Reqs(),
|
||||
cmdline: cmdline,
|
||||
// reportRetractions prints warnings if any modules in the build list are
|
||||
// retracted.
|
||||
func reportRetractions(ctx context.Context) {
|
||||
// Query for retractions of modules in the build list.
|
||||
// Use modload.ListModules, since that provides information in the same format
|
||||
// as 'go list -m'. Don't query for "all", since that's not allowed outside a
|
||||
// module.
|
||||
buildList := modload.LoadedModules()
|
||||
args := make([]string, 0, len(buildList))
|
||||
for _, m := range buildList {
|
||||
if m.Version == "" {
|
||||
// main module or dummy target module
|
||||
continue
|
||||
}
|
||||
args = append(args, m.Path+"@"+m.Version)
|
||||
}
|
||||
if getU != "" {
|
||||
u.upgrade = make(map[string]bool)
|
||||
|
||||
// Traverse package import graph.
|
||||
// Initialize work queue with root packages.
|
||||
seen := make(map[string]bool)
|
||||
var work []string
|
||||
add := func(path string) {
|
||||
if !seen[path] {
|
||||
seen[path] = true
|
||||
work = append(work, path)
|
||||
}
|
||||
}
|
||||
for pkg := range pkgs {
|
||||
add(pkg)
|
||||
}
|
||||
for len(work) > 0 {
|
||||
pkg := work[0]
|
||||
work = work[1:]
|
||||
m := modload.PackageModule(pkg)
|
||||
u.upgrade[m.Path] = true
|
||||
|
||||
// testImports is empty unless test imports were actually loaded,
|
||||
// i.e., -t was set or "all" was one of the arguments.
|
||||
imports, testImports := modload.PackageImports(pkg)
|
||||
for _, imp := range imports {
|
||||
add(imp)
|
||||
}
|
||||
for _, imp := range testImports {
|
||||
add(imp)
|
||||
listU := false
|
||||
listVersions := false
|
||||
listRetractions := true
|
||||
mods := modload.ListModules(ctx, args, listU, listVersions, listRetractions)
|
||||
retractPath := ""
|
||||
for _, mod := range mods {
|
||||
if len(mod.Retracted) > 0 {
|
||||
if retractPath == "" {
|
||||
retractPath = mod.Path
|
||||
} else {
|
||||
retractPath = "<module>"
|
||||
}
|
||||
rationale := modload.ShortRetractionRationale(mod.Retracted[0])
|
||||
logOncef("go: warning: %s@%s is retracted: %s", mod.Path, mod.Version, rationale)
|
||||
}
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// Required returns the requirement list for m.
|
||||
// For the main module, we override requirements with the modules named
|
||||
// one the command line, and we include new requirements. Otherwise,
|
||||
// we defer to u.Reqs.
|
||||
func (u *upgrader) Required(m module.Version) ([]module.Version, error) {
|
||||
rs, err := u.Reqs.Required(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if modload.HasModRoot() && retractPath != "" {
|
||||
logOncef("go: run 'go get %s@latest' to switch to the latest unretracted version", retractPath)
|
||||
}
|
||||
if m != modload.Target {
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
overridden := make(map[string]bool)
|
||||
for i, m := range rs {
|
||||
if q := u.cmdline[m.Path]; q != nil && q.m.Version != "none" {
|
||||
rs[i] = q.m
|
||||
overridden[q.m.Path] = true
|
||||
}
|
||||
}
|
||||
for _, q := range u.cmdline {
|
||||
if !overridden[q.m.Path] && q.m.Path != modload.Target.Path && q.m.Version != "none" {
|
||||
rs = append(rs, q.m)
|
||||
}
|
||||
}
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
// Upgrade returns the desired upgrade for m.
|
||||
//
|
||||
// If m was requested at a specific version on the command line, then
|
||||
// Upgrade returns that version.
|
||||
//
|
||||
// If -u is set and m provides a dependency of a package matched by
|
||||
// command line arguments, then Upgrade may provider a newer tagged version.
|
||||
// If m is a tagged version, then Upgrade will return the latest tagged
|
||||
// version (with the same minor version number if -u=patch).
|
||||
// If m is a pseudo-version, then Upgrade returns the latest tagged version
|
||||
// only if that version has a time-stamp newer than m. This special case
|
||||
// prevents accidental downgrades when already using a pseudo-version
|
||||
// newer than the latest tagged version.
|
||||
//
|
||||
// If none of the above cases apply, then Upgrade returns m.
|
||||
func (u *upgrader) Upgrade(m module.Version) (module.Version, error) {
|
||||
// Allow pkg@vers on the command line to override the upgrade choice v.
|
||||
// If q's version is < m.Version, then we're going to downgrade anyway,
|
||||
// and it's cleaner to avoid moving back and forth and picking up
|
||||
// extraneous other newer dependencies.
|
||||
// If q's version is > m.Version, then we're going to upgrade past
|
||||
// m.Version anyway, and again it's cleaner to avoid moving back and forth
|
||||
// picking up extraneous other newer dependencies.
|
||||
if q := u.cmdline[m.Path]; q != nil {
|
||||
return q.m, nil
|
||||
}
|
||||
|
||||
if !u.upgrade[m.Path] {
|
||||
// Not involved in upgrade. Leave alone.
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Run query required by upgrade semantics.
|
||||
// Note that Query "latest" is not the same as using repo.Latest,
|
||||
// which may return a pseudoversion for the latest commit.
|
||||
// Query "latest" returns the newest tagged version or the newest
|
||||
// prerelease version if there are no non-prereleases, or repo.Latest
|
||||
// if there aren't any tagged versions.
|
||||
// If we're querying "upgrade" or "patch", Query will compare the current
|
||||
// version against the chosen version and will return the current version
|
||||
// if it is newer.
|
||||
info, err := modload.Query(context.TODO(), m.Path, string(getU), m.Version, modload.Allowed)
|
||||
if err != nil {
|
||||
// Report error but return m, to let version selection continue.
|
||||
// (Reporting the error will fail the command at the next base.ExitIfErrors.)
|
||||
|
||||
// Special case: if the error is for m.Version itself and m.Version has a
|
||||
// replacement, then keep it and don't report the error: the fact that the
|
||||
// version is invalid is likely the reason it was replaced to begin with.
|
||||
var vErr *module.InvalidVersionError
|
||||
if errors.As(err, &vErr) && vErr.Version == m.Version && modload.Replacement(m).Path != "" {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Special case: if the error is "no matching versions" then don't
|
||||
// even report the error. Because Query does not consider pseudo-versions,
|
||||
// it may happen that we have a pseudo-version but during -u=patch
|
||||
// the query v0.0 matches no versions (not even the one we're using).
|
||||
var noMatch *modload.NoMatchingVersionError
|
||||
if !errors.As(err, &noMatch) {
|
||||
base.Errorf("go get: upgrading %s@%s: %v", m.Path, m.Version, err)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
if info.Version != m.Version {
|
||||
logOncef("go: %s %s => %s", m.Path, getU, info.Version)
|
||||
}
|
||||
return module.Version{Path: m.Path, Version: info.Version}, nil
|
||||
}
|
||||
|
||||
// buildListForLostUpgrade returns the build list for the module graph
|
||||
// rooted at lost. Unlike mvs.BuildList, the target module (lost) is not
|
||||
// treated specially. The returned build list may contain a newer version
|
||||
// of lost.
|
||||
//
|
||||
// buildListForLostUpgrade is used after a downgrade has removed a module
|
||||
// requested at a specific version. This helps us understand the requirements
|
||||
// implied by each downgrade.
|
||||
func buildListForLostUpgrade(lost module.Version, reqs mvs.Reqs) ([]module.Version, error) {
|
||||
return mvs.BuildList(lostUpgradeRoot, &lostUpgradeReqs{Reqs: reqs, lost: lost})
|
||||
}
|
||||
|
||||
var lostUpgradeRoot = module.Version{Path: "lost-upgrade-root", Version: ""}
|
||||
|
||||
type lostUpgradeReqs struct {
|
||||
mvs.Reqs
|
||||
lost module.Version
|
||||
}
|
||||
|
||||
func (r *lostUpgradeReqs) Required(mod module.Version) ([]module.Version, error) {
|
||||
if mod == lostUpgradeRoot {
|
||||
return []module.Version{r.lost}, nil
|
||||
}
|
||||
return r.Reqs.Required(mod)
|
||||
}
|
||||
|
||||
var loggedLines sync.Map
|
||||
|
202
src/cmd/go/internal/modget/mvs.go
Normal file
202
src/cmd/go/internal/modget/mvs.go
Normal file
@ -0,0 +1,202 @@
|
||||
// Copyright 2020 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 modget
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/mvs"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
|
||||
// An upgrader adapts an underlying mvs.Reqs to apply an
|
||||
// upgrade policy to a list of targets and their dependencies.
|
||||
type upgrader struct {
|
||||
mvs.Reqs
|
||||
|
||||
// cmdline maps a module path to a query made for that module at a
|
||||
// specific target version. Each query corresponds to a module
|
||||
// matched by a command line argument.
|
||||
cmdline map[string]*query
|
||||
|
||||
// upgrade is a set of modules providing dependencies of packages
|
||||
// matched by command line arguments. If -u or -u=patch is set,
|
||||
// these modules are upgraded accordingly.
|
||||
upgrade map[string]bool
|
||||
}
|
||||
|
||||
// newUpgrader creates an upgrader. cmdline contains queries made at
|
||||
// specific versions for modules matched by command line arguments. pkgs
|
||||
// is the set of packages matched by command line arguments. If -u or -u=patch
|
||||
// is set, modules providing dependencies of pkgs are upgraded accordingly.
|
||||
func newUpgrader(cmdline map[string]*query, pkgs map[string]bool) *upgrader {
|
||||
u := &upgrader{
|
||||
Reqs: modload.Reqs(),
|
||||
cmdline: cmdline,
|
||||
}
|
||||
if getU != "" {
|
||||
u.upgrade = make(map[string]bool)
|
||||
|
||||
// Traverse package import graph.
|
||||
// Initialize work queue with root packages.
|
||||
seen := make(map[string]bool)
|
||||
var work []string
|
||||
add := func(path string) {
|
||||
if !seen[path] {
|
||||
seen[path] = true
|
||||
work = append(work, path)
|
||||
}
|
||||
}
|
||||
for pkg := range pkgs {
|
||||
add(pkg)
|
||||
}
|
||||
for len(work) > 0 {
|
||||
pkg := work[0]
|
||||
work = work[1:]
|
||||
m := modload.PackageModule(pkg)
|
||||
u.upgrade[m.Path] = true
|
||||
|
||||
// testImports is empty unless test imports were actually loaded,
|
||||
// i.e., -t was set or "all" was one of the arguments.
|
||||
imports, testImports := modload.PackageImports(pkg)
|
||||
for _, imp := range imports {
|
||||
add(imp)
|
||||
}
|
||||
for _, imp := range testImports {
|
||||
add(imp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// Required returns the requirement list for m.
|
||||
// For the main module, we override requirements with the modules named
|
||||
// one the command line, and we include new requirements. Otherwise,
|
||||
// we defer to u.Reqs.
|
||||
func (u *upgrader) Required(m module.Version) ([]module.Version, error) {
|
||||
rs, err := u.Reqs.Required(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if m != modload.Target {
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
overridden := make(map[string]bool)
|
||||
for i, m := range rs {
|
||||
if q := u.cmdline[m.Path]; q != nil && q.m.Version != "none" {
|
||||
rs[i] = q.m
|
||||
overridden[q.m.Path] = true
|
||||
}
|
||||
}
|
||||
for _, q := range u.cmdline {
|
||||
if !overridden[q.m.Path] && q.m.Path != modload.Target.Path && q.m.Version != "none" {
|
||||
rs = append(rs, q.m)
|
||||
}
|
||||
}
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
// Upgrade returns the desired upgrade for m.
|
||||
//
|
||||
// If m was requested at a specific version on the command line, then
|
||||
// Upgrade returns that version.
|
||||
//
|
||||
// If -u is set and m provides a dependency of a package matched by
|
||||
// command line arguments, then Upgrade may provider a newer tagged version.
|
||||
// If m is a tagged version, then Upgrade will return the latest tagged
|
||||
// version (with the same minor version number if -u=patch).
|
||||
// If m is a pseudo-version, then Upgrade returns the latest tagged version
|
||||
// only if that version has a time-stamp newer than m. This special case
|
||||
// prevents accidental downgrades when already using a pseudo-version
|
||||
// newer than the latest tagged version.
|
||||
//
|
||||
// If none of the above cases apply, then Upgrade returns m.
|
||||
func (u *upgrader) Upgrade(m module.Version) (module.Version, error) {
|
||||
// Allow pkg@vers on the command line to override the upgrade choice v.
|
||||
// If q's version is < m.Version, then we're going to downgrade anyway,
|
||||
// and it's cleaner to avoid moving back and forth and picking up
|
||||
// extraneous other newer dependencies.
|
||||
// If q's version is > m.Version, then we're going to upgrade past
|
||||
// m.Version anyway, and again it's cleaner to avoid moving back and forth
|
||||
// picking up extraneous other newer dependencies.
|
||||
if q := u.cmdline[m.Path]; q != nil {
|
||||
return q.m, nil
|
||||
}
|
||||
|
||||
if !u.upgrade[m.Path] {
|
||||
// Not involved in upgrade. Leave alone.
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Run query required by upgrade semantics.
|
||||
// Note that Query "latest" is not the same as using repo.Latest,
|
||||
// which may return a pseudoversion for the latest commit.
|
||||
// Query "latest" returns the newest tagged version or the newest
|
||||
// prerelease version if there are no non-prereleases, or repo.Latest
|
||||
// if there aren't any tagged versions.
|
||||
// If we're querying "upgrade" or "patch", Query will compare the current
|
||||
// version against the chosen version and will return the current version
|
||||
// if it is newer.
|
||||
info, err := modload.Query(context.TODO(), m.Path, string(getU), m.Version, modload.CheckAllowed)
|
||||
if err != nil {
|
||||
// Report error but return m, to let version selection continue.
|
||||
// (Reporting the error will fail the command at the next base.ExitIfErrors.)
|
||||
|
||||
// Special case: if the error is for m.Version itself and m.Version has a
|
||||
// replacement, then keep it and don't report the error: the fact that the
|
||||
// version is invalid is likely the reason it was replaced to begin with.
|
||||
var vErr *module.InvalidVersionError
|
||||
if errors.As(err, &vErr) && vErr.Version == m.Version && modload.Replacement(m).Path != "" {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Special case: if the error is "no matching versions" then don't
|
||||
// even report the error. Because Query does not consider pseudo-versions,
|
||||
// it may happen that we have a pseudo-version but during -u=patch
|
||||
// the query v0.0 matches no versions (not even the one we're using).
|
||||
var noMatch *modload.NoMatchingVersionError
|
||||
if !errors.As(err, &noMatch) {
|
||||
base.Errorf("go get: upgrading %s@%s: %v", m.Path, m.Version, err)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
if info.Version != m.Version {
|
||||
logOncef("go: %s %s => %s", m.Path, getU, info.Version)
|
||||
}
|
||||
return module.Version{Path: m.Path, Version: info.Version}, nil
|
||||
}
|
||||
|
||||
// buildListForLostUpgrade returns the build list for the module graph
|
||||
// rooted at lost. Unlike mvs.BuildList, the target module (lost) is not
|
||||
// treated specially. The returned build list may contain a newer version
|
||||
// of lost.
|
||||
//
|
||||
// buildListForLostUpgrade is used after a downgrade has removed a module
|
||||
// requested at a specific version. This helps us understand the requirements
|
||||
// implied by each downgrade.
|
||||
func buildListForLostUpgrade(lost module.Version, reqs mvs.Reqs) ([]module.Version, error) {
|
||||
return mvs.BuildList(lostUpgradeRoot, &lostUpgradeReqs{Reqs: reqs, lost: lost})
|
||||
}
|
||||
|
||||
var lostUpgradeRoot = module.Version{Path: "lost-upgrade-root", Version: ""}
|
||||
|
||||
type lostUpgradeReqs struct {
|
||||
mvs.Reqs
|
||||
lost module.Version
|
||||
}
|
||||
|
||||
func (r *lostUpgradeReqs) Required(mod module.Version) ([]module.Version, error) {
|
||||
if mod == lostUpgradeRoot {
|
||||
return []module.Version{r.lost}, nil
|
||||
}
|
||||
return r.Reqs.Required(mod)
|
||||
}
|
@ -21,6 +21,7 @@ type ModulePublic struct {
|
||||
Dir string `json:",omitempty"` // directory holding local copy of files, if any
|
||||
GoMod string `json:",omitempty"` // path to go.mod file describing module, if any
|
||||
GoVersion string `json:",omitempty"` // go version used in module
|
||||
Retracted []string `json:",omitempty"` // retraction information, if any (with -retracted or -u)
|
||||
Error *ModuleError `json:",omitempty"` // error loading module
|
||||
}
|
||||
|
||||
@ -30,18 +31,26 @@ type ModuleError struct {
|
||||
|
||||
func (m *ModulePublic) String() string {
|
||||
s := m.Path
|
||||
versionString := func(mm *ModulePublic) string {
|
||||
v := mm.Version
|
||||
if len(mm.Retracted) == 0 {
|
||||
return v
|
||||
}
|
||||
return v + " (retracted)"
|
||||
}
|
||||
|
||||
if m.Version != "" {
|
||||
s += " " + m.Version
|
||||
s += " " + versionString(m)
|
||||
if m.Update != nil {
|
||||
s += " [" + m.Update.Version + "]"
|
||||
s += " [" + versionString(m.Update) + "]"
|
||||
}
|
||||
}
|
||||
if m.Replace != nil {
|
||||
s += " => " + m.Replace.Path
|
||||
if m.Replace.Version != "" {
|
||||
s += " " + m.Replace.Version
|
||||
s += " " + versionString(m.Replace)
|
||||
if m.Replace.Update != nil {
|
||||
s += " [" + m.Replace.Update.Version + "]"
|
||||
s += " [" + versionString(m.Replace.Update) + "]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/goroot"
|
||||
"os"
|
||||
@ -58,7 +59,9 @@ func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic {
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return moduleInfo(context.TODO(), m, true)
|
||||
fromBuildList := true
|
||||
listRetracted := false
|
||||
return moduleInfo(context.TODO(), m, fromBuildList, listRetracted)
|
||||
}
|
||||
|
||||
func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
|
||||
@ -66,13 +69,17 @@ func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
|
||||
return nil
|
||||
}
|
||||
|
||||
listRetracted := false
|
||||
if i := strings.Index(path, "@"); i >= 0 {
|
||||
return moduleInfo(ctx, module.Version{Path: path[:i], Version: path[i+1:]}, false)
|
||||
m := module.Version{Path: path[:i], Version: path[i+1:]}
|
||||
fromBuildList := false
|
||||
return moduleInfo(ctx, m, fromBuildList, listRetracted)
|
||||
}
|
||||
|
||||
for _, m := range BuildList() {
|
||||
for _, m := range LoadedModules() {
|
||||
if m.Path == path {
|
||||
return moduleInfo(ctx, m, true)
|
||||
fromBuildList := true
|
||||
return moduleInfo(ctx, m, fromBuildList, listRetracted)
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +97,7 @@ func addUpdate(ctx context.Context, m *modinfo.ModulePublic) {
|
||||
return
|
||||
}
|
||||
|
||||
if info, err := Query(ctx, m.Path, "upgrade", m.Version, Allowed); err == nil && semver.Compare(info.Version, m.Version) > 0 {
|
||||
if info, err := Query(ctx, m.Path, "upgrade", m.Version, CheckAllowed); err == nil && semver.Compare(info.Version, m.Version) > 0 {
|
||||
m.Update = &modinfo.ModulePublic{
|
||||
Path: m.Path,
|
||||
Version: info.Version,
|
||||
@ -100,11 +107,37 @@ func addUpdate(ctx context.Context, m *modinfo.ModulePublic) {
|
||||
}
|
||||
|
||||
// addVersions fills in m.Versions with the list of known versions.
|
||||
func addVersions(m *modinfo.ModulePublic) {
|
||||
m.Versions, _ = versions(m.Path)
|
||||
// Excluded versions will be omitted. If listRetracted is false, retracted
|
||||
// versions will also be omitted.
|
||||
func addVersions(ctx context.Context, m *modinfo.ModulePublic, listRetracted bool) {
|
||||
allowed := CheckAllowed
|
||||
if listRetracted {
|
||||
allowed = CheckExclusions
|
||||
}
|
||||
m.Versions, _ = versions(ctx, m.Path, allowed)
|
||||
}
|
||||
|
||||
func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modinfo.ModulePublic {
|
||||
// addRetraction fills in m.Retracted if the module was retracted by its author.
|
||||
// m.Error is set if there's an error loading retraction information.
|
||||
func addRetraction(ctx context.Context, m *modinfo.ModulePublic) {
|
||||
if m.Version == "" {
|
||||
return
|
||||
}
|
||||
|
||||
err := checkRetractions(ctx, module.Version{Path: m.Path, Version: m.Version})
|
||||
var rerr *retractedError
|
||||
if errors.As(err, &rerr) {
|
||||
if len(rerr.rationale) == 0 {
|
||||
m.Retracted = []string{"retracted by module author"}
|
||||
} else {
|
||||
m.Retracted = rerr.rationale
|
||||
}
|
||||
} else if err != nil && m.Error == nil {
|
||||
m.Error = &modinfo.ModuleError{Err: err.Error()}
|
||||
}
|
||||
}
|
||||
|
||||
func moduleInfo(ctx context.Context, m module.Version, fromBuildList, listRetracted bool) *modinfo.ModulePublic {
|
||||
if m == Target {
|
||||
info := &modinfo.ModulePublic{
|
||||
Path: m.Path,
|
||||
@ -126,12 +159,14 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
|
||||
Version: m.Version,
|
||||
Indirect: fromBuildList && loaded != nil && !loaded.direct[m.Path],
|
||||
}
|
||||
if loaded != nil {
|
||||
info.GoVersion = loaded.goVersion[m.Path]
|
||||
if v, ok := rawGoVersion.Load(m); ok {
|
||||
info.GoVersion = v.(string)
|
||||
}
|
||||
|
||||
// completeFromModCache fills in the extra fields in m using the module cache.
|
||||
completeFromModCache := func(m *modinfo.ModulePublic) {
|
||||
mod := module.Version{Path: m.Path, Version: m.Version}
|
||||
|
||||
if m.Version != "" {
|
||||
if q, err := Query(ctx, m.Path, m.Version, "", nil); err != nil {
|
||||
m.Error = &modinfo.ModuleError{Err: err.Error()}
|
||||
@ -140,7 +175,6 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
|
||||
m.Time = &q.Time
|
||||
}
|
||||
|
||||
mod := module.Version{Path: m.Path, Version: m.Version}
|
||||
gomod, err := modfetch.CachePath(mod, "mod")
|
||||
if err == nil {
|
||||
if info, err := os.Stat(gomod); err == nil && info.Mode().IsRegular() {
|
||||
@ -151,10 +185,22 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
|
||||
if err == nil {
|
||||
m.Dir = dir
|
||||
}
|
||||
|
||||
if listRetracted {
|
||||
addRetraction(ctx, m)
|
||||
}
|
||||
}
|
||||
|
||||
if m.GoVersion == "" {
|
||||
if summary, err := rawGoModSummary(mod); err == nil && summary.goVersionV != "" {
|
||||
m.GoVersion = summary.goVersionV[1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !fromBuildList {
|
||||
// If this was an explicitly-versioned argument to 'go mod download' or
|
||||
// 'go list -m', report the actual requested version, not its replacement.
|
||||
completeFromModCache(info) // Will set m.Error in vendor mode.
|
||||
return info
|
||||
}
|
||||
@ -178,9 +224,11 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
|
||||
// worth the cost, and we're going to overwrite the GoMod and Dir from the
|
||||
// replacement anyway. See https://golang.org/issue/27859.
|
||||
info.Replace = &modinfo.ModulePublic{
|
||||
Path: r.Path,
|
||||
Version: r.Version,
|
||||
GoVersion: info.GoVersion,
|
||||
Path: r.Path,
|
||||
Version: r.Version,
|
||||
}
|
||||
if v, ok := rawGoVersion.Load(m); ok {
|
||||
info.Replace.GoVersion = v.(string)
|
||||
}
|
||||
if r.Version == "" {
|
||||
if filepath.IsAbs(r.Path) {
|
||||
@ -194,7 +242,9 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
|
||||
completeFromModCache(info.Replace)
|
||||
info.Dir = info.Replace.Dir
|
||||
info.GoMod = info.Replace.GoMod
|
||||
info.Retracted = info.Replace.Retracted
|
||||
}
|
||||
info.GoVersion = info.Replace.GoVersion
|
||||
return info
|
||||
}
|
||||
|
||||
|
122
src/cmd/go/internal/modload/buildlist.go
Normal file
122
src/cmd/go/internal/modload/buildlist.go
Normal file
@ -0,0 +1,122 @@
|
||||
// Copyright 2018 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 modload
|
||||
|
||||
import (
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/imports"
|
||||
"cmd/go/internal/mvs"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
|
||||
// buildList is the list of modules to use for building packages.
|
||||
// It is initialized by calling ImportPaths, ImportFromFiles,
|
||||
// LoadALL, or LoadBuildList, each of which uses loaded.load.
|
||||
//
|
||||
// Ideally, exactly ONE of those functions would be called,
|
||||
// and exactly once. Most of the time, that's true.
|
||||
// During "go get" it may not be. TODO(rsc): Figure out if
|
||||
// that restriction can be established, or else document why not.
|
||||
//
|
||||
var buildList []module.Version
|
||||
|
||||
// LoadAllModules loads and returns the list of modules matching the "all"
|
||||
// module pattern, starting with the Target module and in a deterministic
|
||||
// (stable) order, without loading any packages.
|
||||
//
|
||||
// Modules are loaded automatically (and lazily) in ImportPaths:
|
||||
// LoadAllModules need only be called if ImportPaths is not,
|
||||
// typically in commands that care about modules but no particular package.
|
||||
//
|
||||
// The caller must not modify the returned list.
|
||||
func LoadAllModules(ctx context.Context) []module.Version {
|
||||
InitMod(ctx)
|
||||
ReloadBuildList()
|
||||
WriteGoMod()
|
||||
return buildList
|
||||
}
|
||||
|
||||
// LoadedModules returns the list of module requirements loaded or set by a
|
||||
// previous call (typically LoadAllModules or ImportPaths), starting with the
|
||||
// Target module and in a deterministic (stable) order.
|
||||
//
|
||||
// The caller must not modify the returned list.
|
||||
func LoadedModules() []module.Version {
|
||||
return buildList
|
||||
}
|
||||
|
||||
// SetBuildList sets the module build list.
|
||||
// The caller is responsible for ensuring that the list is valid.
|
||||
// SetBuildList does not retain a reference to the original list.
|
||||
func SetBuildList(list []module.Version) {
|
||||
buildList = append([]module.Version{}, list...)
|
||||
}
|
||||
|
||||
// ReloadBuildList resets the state of loaded packages, then loads and returns
|
||||
// the build list set in SetBuildList.
|
||||
func ReloadBuildList() []module.Version {
|
||||
loaded = loadFromRoots(loaderParams{
|
||||
tags: imports.Tags(),
|
||||
listRoots: func() []string { return nil },
|
||||
allClosesOverTests: index.allPatternClosesOverTests(), // but doesn't matter because the root list is empty.
|
||||
})
|
||||
return buildList
|
||||
}
|
||||
|
||||
// TidyBuildList trims the build list to the minimal requirements needed to
|
||||
// retain the same versions of all packages from the preceding Load* or
|
||||
// ImportPaths* call.
|
||||
func TidyBuildList() {
|
||||
used := map[module.Version]bool{Target: true}
|
||||
for _, pkg := range loaded.pkgs {
|
||||
used[pkg.mod] = true
|
||||
}
|
||||
|
||||
keep := []module.Version{Target}
|
||||
var direct []string
|
||||
for _, m := range buildList[1:] {
|
||||
if used[m] {
|
||||
keep = append(keep, m)
|
||||
if loaded.direct[m.Path] {
|
||||
direct = append(direct, m.Path)
|
||||
}
|
||||
} else if cfg.BuildV {
|
||||
if _, ok := index.require[m]; ok {
|
||||
fmt.Fprintf(os.Stderr, "unused %s\n", m.Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
min, err := mvs.Req(Target, direct, &mvsReqs{buildList: keep})
|
||||
if err != nil {
|
||||
base.Fatalf("go: %v", err)
|
||||
}
|
||||
buildList = append([]module.Version{Target}, min...)
|
||||
}
|
||||
|
||||
// checkMultiplePaths verifies that a given module path is used as itself
|
||||
// or as a replacement for another module, but not both at the same time.
|
||||
//
|
||||
// (See https://golang.org/issue/26607 and https://golang.org/issue/34650.)
|
||||
func checkMultiplePaths() {
|
||||
firstPath := make(map[module.Version]string, len(buildList))
|
||||
for _, mod := range buildList {
|
||||
src := mod
|
||||
if rep := Replacement(mod); rep.Path != "" {
|
||||
src = rep
|
||||
}
|
||||
if prev, ok := firstPath[src]; !ok {
|
||||
firstPath[src] = mod.Path
|
||||
} else if prev != mod.Path {
|
||||
base.Errorf("go: %s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path)
|
||||
}
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
}
|
@ -432,15 +432,17 @@ verb followed by arguments. For example:
|
||||
require new/thing/v2 v2.3.4
|
||||
exclude old/thing v1.2.3
|
||||
replace bad/thing v1.4.5 => good/thing v1.4.5
|
||||
retract v1.5.6
|
||||
|
||||
The verbs are
|
||||
module, to define the module path;
|
||||
go, to set the expected language version;
|
||||
require, to require a particular module at a given version or later;
|
||||
exclude, to exclude a particular module version from use; and
|
||||
replace, to replace a module version with a different module version.
|
||||
exclude, to exclude a particular module version from use;
|
||||
replace, to replace a module version with a different module version; and
|
||||
retract, to indicate a previously released version should not be used.
|
||||
Exclude and replace apply only in the main module's go.mod and are ignored
|
||||
in dependencies. See https://research.swtch.com/vgo-mvs for details.
|
||||
in dependencies. See https://golang.org/ref/mod for details.
|
||||
|
||||
The leading verb can be factored out of adjacent lines to create a block,
|
||||
like in Go imports:
|
||||
|
@ -26,6 +26,8 @@ import (
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
var errImportMissing = errors.New("import missing")
|
||||
|
||||
type ImportMissingError struct {
|
||||
Path string
|
||||
Module module.Version
|
||||
@ -48,6 +50,11 @@ func (e *ImportMissingError) Error() string {
|
||||
}
|
||||
return "cannot find module providing package " + e.Path
|
||||
}
|
||||
|
||||
if e.newMissingVersion != "" {
|
||||
return fmt.Sprintf("package %s provided by %s at latest version %s but not at required version %s", e.Path, e.Module.Path, e.Module.Version, e.newMissingVersion)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("missing module for import: %s@%s provides %s", e.Module.Path, e.Module.Version, e.Path)
|
||||
}
|
||||
|
||||
@ -100,18 +107,39 @@ func (e *AmbiguousImportError) Error() string {
|
||||
|
||||
var _ load.ImportPathError = &AmbiguousImportError{}
|
||||
|
||||
// Import finds the module and directory in the build list
|
||||
// containing the package with the given import path.
|
||||
// The answer must be unique: Import returns an error
|
||||
// if multiple modules attempt to provide the same package.
|
||||
// Import can return a module with an empty m.Path, for packages in the standard library.
|
||||
// Import can return an empty directory string, for fake packages like "C" and "unsafe".
|
||||
type invalidImportError struct {
|
||||
importPath string
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *invalidImportError) ImportPath() string {
|
||||
return e.importPath
|
||||
}
|
||||
|
||||
func (e *invalidImportError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func (e *invalidImportError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
var _ load.ImportPathError = &invalidImportError{}
|
||||
|
||||
// importFromBuildList finds the module and directory in the build list
|
||||
// containing the package with the given import path. The answer must be unique:
|
||||
// importFromBuildList returns an error if multiple modules attempt to provide
|
||||
// the same package.
|
||||
//
|
||||
// importFromBuildList can return a module with an empty m.Path, for packages in
|
||||
// the standard library.
|
||||
//
|
||||
// importFromBuildList can return an empty directory string, for fake packages
|
||||
// like "C" and "unsafe".
|
||||
//
|
||||
// If the package cannot be found in the current build list,
|
||||
// Import returns an ImportMissingError as the error.
|
||||
// If Import can identify a module that could be added to supply the package,
|
||||
// the ImportMissingError records that module.
|
||||
func Import(ctx context.Context, path string) (m module.Version, dir string, err error) {
|
||||
// importFromBuildList returns errImportMissing as the error.
|
||||
func importFromBuildList(ctx context.Context, path string) (m module.Version, dir string, err error) {
|
||||
if strings.Contains(path, "@") {
|
||||
return module.Version{}, "", fmt.Errorf("import path should not have @version")
|
||||
}
|
||||
@ -190,29 +218,25 @@ func Import(ctx context.Context, path string) (m module.Version, dir string, err
|
||||
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
|
||||
}
|
||||
|
||||
// Look up module containing the package, for addition to the build list.
|
||||
// Goal is to determine the module, download it to dir, and return m, dir, ErrMissing.
|
||||
if cfg.BuildMod == "readonly" {
|
||||
var queryErr error
|
||||
if !pathIsStd {
|
||||
if cfg.BuildModReason == "" {
|
||||
queryErr = fmt.Errorf("import lookup disabled by -mod=%s", cfg.BuildMod)
|
||||
} else {
|
||||
queryErr = fmt.Errorf("import lookup disabled by -mod=%s\n\t(%s)", cfg.BuildMod, cfg.BuildModReason)
|
||||
}
|
||||
}
|
||||
return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: queryErr}
|
||||
}
|
||||
return module.Version{}, "", errImportMissing
|
||||
}
|
||||
|
||||
// queryImport attempts to locate a module that can be added to the current
|
||||
// build list to provide the package with the given import path.
|
||||
func queryImport(ctx context.Context, path string) (module.Version, error) {
|
||||
pathIsStd := search.IsStandardImportPath(path)
|
||||
|
||||
if modRoot == "" && !allowMissingModuleImports {
|
||||
return module.Version{}, "", &ImportMissingError{
|
||||
return module.Version{}, &ImportMissingError{
|
||||
Path: path,
|
||||
QueryErr: errors.New("working directory is not part of a module"),
|
||||
}
|
||||
}
|
||||
|
||||
// Not on build list.
|
||||
// To avoid spurious remote fetches, next try the latest replacement for each module.
|
||||
// (golang.org/issue/26241)
|
||||
// To avoid spurious remote fetches, next try the latest replacement for each
|
||||
// module (golang.org/issue/26241). This should give a useful message
|
||||
// in -mod=readonly, and it will allow us to add a requirement with -mod=mod.
|
||||
if modFile != nil {
|
||||
latest := map[string]string{} // path -> version
|
||||
for _, r := range modFile.Replace {
|
||||
@ -226,7 +250,7 @@ func Import(ctx context.Context, path string) (m module.Version, dir string, err
|
||||
}
|
||||
}
|
||||
|
||||
mods = make([]module.Version, 0, len(latest))
|
||||
mods := make([]module.Version, 0, len(latest))
|
||||
for p, v := range latest {
|
||||
// If the replacement didn't specify a version, synthesize a
|
||||
// pseudo-version with an appropriate major version and a timestamp below
|
||||
@ -252,19 +276,19 @@ func Import(ctx context.Context, path string) (m module.Version, dir string, err
|
||||
root, isLocal, err := fetch(ctx, m)
|
||||
if err != nil {
|
||||
// Report fetch error as above.
|
||||
return module.Version{}, "", err
|
||||
return module.Version{}, err
|
||||
}
|
||||
if _, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
|
||||
return m, "", err
|
||||
return m, err
|
||||
} else if ok {
|
||||
return m, "", &ImportMissingError{Path: path, Module: m}
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
if len(mods) > 0 && module.CheckPath(path) != nil {
|
||||
// The package path is not valid to fetch remotely,
|
||||
// so it can only exist if in a replaced module,
|
||||
// and we know from the above loop that it is not.
|
||||
return module.Version{}, "", &PackageNotInModuleError{
|
||||
return module.Version{}, &PackageNotInModuleError{
|
||||
Mod: mods[0],
|
||||
Query: "latest",
|
||||
Pattern: path,
|
||||
@ -273,6 +297,11 @@ func Import(ctx context.Context, path string) (m module.Version, dir string, err
|
||||
}
|
||||
}
|
||||
|
||||
// Before any further lookup, check that the path is valid.
|
||||
if err := module.CheckImportPath(path); err != nil {
|
||||
return module.Version{}, &invalidImportError{importPath: path, err: err}
|
||||
}
|
||||
|
||||
if pathIsStd {
|
||||
// This package isn't in the standard library, isn't in any module already
|
||||
// in the build list, and isn't in any other module that the user has
|
||||
@ -281,25 +310,39 @@ func Import(ctx context.Context, path string) (m module.Version, dir string, err
|
||||
// QueryPackage cannot possibly find a module containing this package.
|
||||
//
|
||||
// Instead of trying QueryPackage, report an ImportMissingError immediately.
|
||||
return module.Version{}, "", &ImportMissingError{Path: path}
|
||||
return module.Version{}, &ImportMissingError{Path: path}
|
||||
}
|
||||
|
||||
if cfg.BuildMod == "readonly" {
|
||||
var queryErr error
|
||||
if cfg.BuildModExplicit {
|
||||
queryErr = fmt.Errorf("import lookup disabled by -mod=%s", cfg.BuildMod)
|
||||
} else if cfg.BuildModReason != "" {
|
||||
queryErr = fmt.Errorf("import lookup disabled by -mod=%s\n\t(%s)", cfg.BuildMod, cfg.BuildModReason)
|
||||
}
|
||||
return module.Version{}, &ImportMissingError{Path: path, QueryErr: queryErr}
|
||||
}
|
||||
|
||||
// Look up module containing the package, for addition to the build list.
|
||||
// Goal is to determine the module, download it to dir,
|
||||
// and return m, dir, ImpportMissingError.
|
||||
fmt.Fprintf(os.Stderr, "go: finding module for package %s\n", path)
|
||||
|
||||
candidates, err := QueryPackage(ctx, path, "latest", Allowed)
|
||||
candidates, err := QueryPackage(ctx, path, "latest", CheckAllowed)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// Return "cannot find module providing package […]" instead of whatever
|
||||
// low-level error QueryPackage produced.
|
||||
return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: err}
|
||||
return module.Version{}, &ImportMissingError{Path: path, QueryErr: err}
|
||||
} else {
|
||||
return module.Version{}, "", err
|
||||
return module.Version{}, err
|
||||
}
|
||||
}
|
||||
m = candidates[0].Mod
|
||||
newMissingVersion := ""
|
||||
for _, c := range candidates {
|
||||
|
||||
candidate0MissingVersion := ""
|
||||
for i, c := range candidates {
|
||||
cm := c.Mod
|
||||
canAdd := true
|
||||
for _, bm := range buildList {
|
||||
if bm.Path == cm.Path && semver.Compare(bm.Version, cm.Version) > 0 {
|
||||
// QueryPackage proposed that we add module cm to provide the package,
|
||||
@ -310,13 +353,22 @@ func Import(ctx context.Context, path string) (m module.Version, dir string, err
|
||||
// version (e.g., v1.0.0) of a module, but we have a newer version
|
||||
// of the same module in the build list (e.g., v1.0.1-beta), and
|
||||
// the package is not present there.
|
||||
m = cm
|
||||
newMissingVersion = bm.Version
|
||||
canAdd = false
|
||||
if i == 0 {
|
||||
candidate0MissingVersion = bm.Version
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if canAdd {
|
||||
return cm, nil
|
||||
}
|
||||
}
|
||||
return module.Version{}, &ImportMissingError{
|
||||
Path: path,
|
||||
Module: candidates[0].Mod,
|
||||
newMissingVersion: candidate0MissingVersion,
|
||||
}
|
||||
return m, "", &ImportMissingError{Path: path, Module: m, newMissingVersion: newMissingVersion}
|
||||
}
|
||||
|
||||
// maybeInModule reports whether, syntactically,
|
||||
|
@ -10,15 +10,20 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
|
||||
var importTests = []struct {
|
||||
path string
|
||||
m module.Version
|
||||
err string
|
||||
}{
|
||||
{
|
||||
path: "golang.org/x/net/context",
|
||||
err: "missing module for import: golang.org/x/net@.* provides golang.org/x/net/context",
|
||||
m: module.Version{
|
||||
Path: "golang.org/x/net",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "golang.org/x/net",
|
||||
@ -26,15 +31,23 @@ var importTests = []struct {
|
||||
},
|
||||
{
|
||||
path: "golang.org/x/text",
|
||||
err: "missing module for import: golang.org/x/text@.* provides golang.org/x/text",
|
||||
m: module.Version{
|
||||
Path: "golang.org/x/text",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "github.com/rsc/quote/buggy",
|
||||
err: "missing module for import: github.com/rsc/quote@v1.5.2 provides github.com/rsc/quote/buggy",
|
||||
m: module.Version{
|
||||
Path: "github.com/rsc/quote",
|
||||
Version: "v1.5.2",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "github.com/rsc/quote",
|
||||
err: "missing module for import: github.com/rsc/quote@v1.5.2 provides github.com/rsc/quote",
|
||||
m: module.Version{
|
||||
Path: "github.com/rsc/quote",
|
||||
Version: "v1.5.2",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "golang.org/x/foo/bar",
|
||||
@ -42,7 +55,7 @@ var importTests = []struct {
|
||||
},
|
||||
}
|
||||
|
||||
func TestImport(t *testing.T) {
|
||||
func TestQueryImport(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
testenv.MustHaveExecPath(t, "git")
|
||||
defer func(old bool) {
|
||||
@ -55,12 +68,23 @@ func TestImport(t *testing.T) {
|
||||
for _, tt := range importTests {
|
||||
t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
|
||||
// Note that there is no build list, so Import should always fail.
|
||||
m, dir, err := Import(ctx, tt.path)
|
||||
if err == nil {
|
||||
t.Fatalf("Import(%q) = %v, %v, nil; expected error", tt.path, m, dir)
|
||||
m, err := queryImport(ctx, tt.path)
|
||||
|
||||
if tt.err == "" {
|
||||
if err != nil {
|
||||
t.Fatalf("queryImport(_, %q): %v", tt.path, err)
|
||||
}
|
||||
} else {
|
||||
if err == nil {
|
||||
t.Fatalf("queryImport(_, %q) = %v, nil; expected error", tt.path, m)
|
||||
}
|
||||
if !regexp.MustCompile(tt.err).MatchString(err.Error()) {
|
||||
t.Fatalf("queryImport(_, %q): error %q, want error matching %#q", tt.path, err, tt.err)
|
||||
}
|
||||
}
|
||||
if !regexp.MustCompile(tt.err).MatchString(err.Error()) {
|
||||
t.Fatalf("Import(%q): error %q, want error matching %#q", tt.path, err, tt.err)
|
||||
|
||||
if m.Path != tt.m.Path || (tt.m.Version != "" && m.Version != tt.m.Version) {
|
||||
t.Errorf("queryImport(_, %q) = %v, _; want %v", tt.path, m, tt.m)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -368,13 +368,9 @@ func InitMod(ctx context.Context) {
|
||||
modFile = f
|
||||
index = indexModFile(data, f, fixed)
|
||||
|
||||
if len(f.Syntax.Stmt) == 0 || f.Module == nil {
|
||||
// Empty mod file. Must add module path.
|
||||
path, err := findModulePath(modRoot)
|
||||
if err != nil {
|
||||
base.Fatalf("go: %v", err)
|
||||
}
|
||||
f.AddModuleStmt(path)
|
||||
if f.Module == nil {
|
||||
// No module declaration. Must add module path.
|
||||
base.Fatalf("go: no module declaration in go.mod.\n\tRun 'go mod edit -module=example.com/mod' to specify the module path.")
|
||||
}
|
||||
|
||||
if len(f.Syntax.Stmt) == 1 && f.Module != nil {
|
||||
@ -383,14 +379,61 @@ func InitMod(ctx context.Context) {
|
||||
legacyModInit()
|
||||
}
|
||||
|
||||
modFileToBuildList()
|
||||
if err := checkModulePathLax(f.Module.Mod.Path); err != nil {
|
||||
base.Fatalf("go: %v", err)
|
||||
}
|
||||
|
||||
setDefaultBuildMod()
|
||||
modFileToBuildList()
|
||||
if cfg.BuildMod == "vendor" {
|
||||
readVendorList()
|
||||
checkVendorConsistency()
|
||||
}
|
||||
}
|
||||
|
||||
// checkModulePathLax checks that the path meets some minimum requirements
|
||||
// to avoid confusing users or the module cache. The requirements are weaker
|
||||
// than those of module.CheckPath to allow room for weakening module path
|
||||
// requirements in the future, but strong enough to help users avoid significant
|
||||
// problems.
|
||||
func checkModulePathLax(p string) error {
|
||||
// TODO(matloob): Replace calls of this function in this CL with calls
|
||||
// to module.CheckImportPath once it's been laxened, if it becomes laxened.
|
||||
// See golang.org/issue/29101 for a discussion about whether to make CheckImportPath
|
||||
// more lax or more strict.
|
||||
|
||||
errorf := func(format string, args ...interface{}) error {
|
||||
return fmt.Errorf("invalid module path %q: %s", p, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Disallow shell characters " ' * < > ? ` | to avoid triggering bugs
|
||||
// with file systems and subcommands. Disallow file path separators : and \
|
||||
// because path separators other than / will confuse the module cache.
|
||||
// See fileNameOK in golang.org/x/mod/module/module.go.
|
||||
shellChars := "`" + `\"'*<>?|`
|
||||
fsChars := `\:`
|
||||
if i := strings.IndexAny(p, shellChars); i >= 0 {
|
||||
return errorf("contains disallowed shell character %q", p[i])
|
||||
}
|
||||
if i := strings.IndexAny(p, fsChars); i >= 0 {
|
||||
return errorf("contains disallowed path separator character %q", p[i])
|
||||
}
|
||||
|
||||
// Ensure path.IsAbs and build.IsLocalImport are false, and that the path is
|
||||
// invariant under path.Clean, also to avoid confusing the module cache.
|
||||
if path.IsAbs(p) {
|
||||
return errorf("is an absolute path")
|
||||
}
|
||||
if build.IsLocalImport(p) {
|
||||
return errorf("is a local import path")
|
||||
}
|
||||
if path.Clean(p) != p {
|
||||
return errorf("is not clean")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// fixVersion returns a modfile.VersionFixer implemented using the Query function.
|
||||
//
|
||||
// It resolves commit hashes and branch names to versions,
|
||||
@ -459,7 +502,15 @@ func modFileToBuildList() {
|
||||
|
||||
list := []module.Version{Target}
|
||||
for _, r := range modFile.Require {
|
||||
list = append(list, r.Mod)
|
||||
if index != nil && index.exclude[r.Mod] {
|
||||
if cfg.BuildMod == "mod" {
|
||||
fmt.Fprintf(os.Stderr, "go: dropping requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "go: ignoring requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version)
|
||||
}
|
||||
} else {
|
||||
list = append(list, r.Mod)
|
||||
}
|
||||
}
|
||||
buildList = list
|
||||
}
|
||||
@ -467,46 +518,49 @@ func modFileToBuildList() {
|
||||
// setDefaultBuildMod sets a default value for cfg.BuildMod
|
||||
// if it is currently empty.
|
||||
func setDefaultBuildMod() {
|
||||
if cfg.BuildMod != "" {
|
||||
if cfg.BuildModExplicit {
|
||||
// Don't override an explicit '-mod=' argument.
|
||||
return
|
||||
}
|
||||
cfg.BuildMod = "mod"
|
||||
|
||||
if cfg.CmdName == "get" || strings.HasPrefix(cfg.CmdName, "mod ") {
|
||||
// Don't set -mod implicitly for commands whose purpose is to
|
||||
// manipulate the build list.
|
||||
// 'get' and 'go mod' commands may update go.mod automatically.
|
||||
// TODO(jayconrod): should this narrower? Should 'go mod download' or
|
||||
// 'go mod graph' update go.mod by default?
|
||||
cfg.BuildMod = "mod"
|
||||
return
|
||||
}
|
||||
if modRoot == "" {
|
||||
cfg.BuildMod = "mod"
|
||||
return
|
||||
}
|
||||
|
||||
if fi, err := os.Stat(filepath.Join(modRoot, "vendor")); err == nil && fi.IsDir() {
|
||||
modGo := "unspecified"
|
||||
if index.goVersion != "" {
|
||||
if semver.Compare("v"+index.goVersion, "v1.14") >= 0 {
|
||||
if index.goVersionV != "" {
|
||||
if semver.Compare(index.goVersionV, "v1.14") >= 0 {
|
||||
// The Go version is at least 1.14, and a vendor directory exists.
|
||||
// Set -mod=vendor by default.
|
||||
cfg.BuildMod = "vendor"
|
||||
cfg.BuildModReason = "Go version in go.mod is at least 1.14 and vendor directory exists."
|
||||
return
|
||||
} else {
|
||||
modGo = index.goVersion
|
||||
modGo = index.goVersionV[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// Since a vendor directory exists, we have a non-trivial reason for
|
||||
// choosing -mod=mod, although it probably won't be used for anything.
|
||||
// Record the reason anyway for consistency.
|
||||
// It may be overridden if we switch to mod=readonly below.
|
||||
cfg.BuildModReason = fmt.Sprintf("Go version in go.mod is %s.", modGo)
|
||||
// Since a vendor directory exists, we should record why we didn't use it.
|
||||
// This message won't normally be shown, but it may appear with import errors.
|
||||
cfg.BuildModReason = fmt.Sprintf("Go version in go.mod is %s, so vendor directory was not used.", modGo)
|
||||
}
|
||||
|
||||
p := ModFilePath()
|
||||
if fi, err := os.Stat(p); err == nil && !hasWritePerm(p, fi) {
|
||||
cfg.BuildMod = "readonly"
|
||||
cfg.BuildModReason = "go.mod file is read-only."
|
||||
return
|
||||
}
|
||||
cfg.BuildMod = "mod"
|
||||
}
|
||||
|
||||
func legacyModInit() {
|
||||
@ -674,16 +728,35 @@ func findModulePath(dir string) (string, error) {
|
||||
}
|
||||
|
||||
// Look for path in GOPATH.
|
||||
var badPathErr error
|
||||
for _, gpdir := range filepath.SplitList(cfg.BuildContext.GOPATH) {
|
||||
if gpdir == "" {
|
||||
continue
|
||||
}
|
||||
if rel := search.InDir(dir, filepath.Join(gpdir, "src")); rel != "" && rel != "." {
|
||||
return filepath.ToSlash(rel), nil
|
||||
path := filepath.ToSlash(rel)
|
||||
// TODO(matloob): replace this with module.CheckImportPath
|
||||
// once it's been laxened.
|
||||
// Only checkModulePathLax here. There are some unpublishable
|
||||
// module names that are compatible with checkModulePathLax
|
||||
// but they already work in GOPATH so don't break users
|
||||
// trying to do a build with modules. gorelease will alert users
|
||||
// publishing their modules to fix their paths.
|
||||
if err := checkModulePathLax(path); err != nil {
|
||||
badPathErr = err
|
||||
break
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
|
||||
msg := `cannot determine module path for source directory %s (outside GOPATH, module path must be specified)
|
||||
reason := "outside GOPATH, module path must be specified"
|
||||
if badPathErr != nil {
|
||||
// return a different error message if the module was in GOPATH, but
|
||||
// the module path determined above would be an invalid path.
|
||||
reason = fmt.Sprintf("bad module path inferred from directory in GOPATH: %v", badPathErr)
|
||||
}
|
||||
msg := `cannot determine module path for source directory %s (%s)
|
||||
|
||||
Example usage:
|
||||
'go mod init example.com/m' to initialize a v0 or v1 module
|
||||
@ -691,7 +764,7 @@ Example usage:
|
||||
|
||||
Run 'go help mod init' for more information.
|
||||
`
|
||||
return "", fmt.Errorf(msg, dir)
|
||||
return "", fmt.Errorf(msg, dir, reason)
|
||||
}
|
||||
|
||||
var (
|
||||
@ -787,19 +860,16 @@ func WriteGoMod() {
|
||||
// prefer to report a dirty go.mod over a dirty go.sum
|
||||
if cfg.BuildModReason != "" {
|
||||
base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly\n\t(%s)", cfg.BuildModReason)
|
||||
} else {
|
||||
} else if cfg.BuildModExplicit {
|
||||
base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly")
|
||||
}
|
||||
}
|
||||
|
||||
// Always update go.sum, even if we didn't change go.mod: we may have
|
||||
// downloaded modules that we didn't have before.
|
||||
modfetch.WriteGoSum(keepSums())
|
||||
|
||||
if !dirty && cfg.CmdName != "mod tidy" {
|
||||
// The go.mod file has the same semantic content that it had before
|
||||
// (but not necessarily the same exact bytes).
|
||||
// Ignore any intervening edits.
|
||||
// Don't write go.mod, but write go.sum in case we added or trimmed sums.
|
||||
modfetch.WriteGoSum(keepSums(true))
|
||||
return
|
||||
}
|
||||
|
||||
@ -810,6 +880,9 @@ func WriteGoMod() {
|
||||
defer func() {
|
||||
// At this point we have determined to make the go.mod file on disk equal to new.
|
||||
index = indexModFile(new, modFile, false)
|
||||
|
||||
// Update go.sum after releasing the side lock and refreshing the index.
|
||||
modfetch.WriteGoSum(keepSums(true))
|
||||
}()
|
||||
|
||||
// Make a best-effort attempt to acquire the side lock, only to exclude
|
||||
@ -850,7 +923,10 @@ func WriteGoMod() {
|
||||
// the last load function like ImportPaths, LoadALL, etc.). It also contains
|
||||
// entries for go.mod files needed for MVS (the version of these entries
|
||||
// ends with "/go.mod").
|
||||
func keepSums() map[module.Version]bool {
|
||||
//
|
||||
// If addDirect is true, the set also includes sums for modules directly
|
||||
// required by go.mod, as represented by the index, with replacements applied.
|
||||
func keepSums(addDirect bool) map[module.Version]bool {
|
||||
// Walk the module graph and keep sums needed by MVS.
|
||||
modkey := func(m module.Version) module.Version {
|
||||
return module.Version{Path: m.Path, Version: m.Version + "/go.mod"}
|
||||
@ -862,9 +938,6 @@ func keepSums() map[module.Version]bool {
|
||||
walk = func(m module.Version) {
|
||||
// If we build using a replacement module, keep the sum for the replacement,
|
||||
// since that's the code we'll actually use during a build.
|
||||
//
|
||||
// TODO(golang.org/issue/29182): Perhaps we should keep both sums, and the
|
||||
// sums for both sets of transitive requirements.
|
||||
r := Replacement(m)
|
||||
if r.Path == "" {
|
||||
keep[modkey(m)] = true
|
||||
@ -894,9 +967,27 @@ func keepSums() map[module.Version]bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Add entries for modules directly required by go.mod.
|
||||
if addDirect {
|
||||
for m := range index.require {
|
||||
var kept module.Version
|
||||
if r := Replacement(m); r.Path != "" {
|
||||
kept = r
|
||||
} else {
|
||||
kept = m
|
||||
}
|
||||
keep[kept] = true
|
||||
keep[module.Version{Path: kept.Path, Version: kept.Version + "/go.mod"}] = true
|
||||
}
|
||||
}
|
||||
|
||||
return keep
|
||||
}
|
||||
|
||||
func TrimGoSum() {
|
||||
modfetch.TrimGoSum(keepSums())
|
||||
// Don't retain sums for direct requirements in go.mod. When TrimGoSum is
|
||||
// called, go.mod has not been updated, and it may contain requirements on
|
||||
// modules deleted from the build list.
|
||||
addDirect := false
|
||||
modfetch.TrimGoSum(keepSums(addDirect))
|
||||
}
|
||||
|
@ -20,12 +20,12 @@ import (
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
|
||||
func ListModules(ctx context.Context, args []string, listU, listVersions bool) []*modinfo.ModulePublic {
|
||||
mods := listModules(ctx, args, listVersions)
|
||||
func ListModules(ctx context.Context, args []string, listU, listVersions, listRetracted bool) []*modinfo.ModulePublic {
|
||||
mods := listModules(ctx, args, listVersions, listRetracted)
|
||||
|
||||
type token struct{}
|
||||
sem := make(chan token, runtime.GOMAXPROCS(0))
|
||||
if listU || listVersions {
|
||||
if listU || listVersions || listRetracted {
|
||||
for _, m := range mods {
|
||||
add := func(m *modinfo.ModulePublic) {
|
||||
sem <- token{}
|
||||
@ -34,7 +34,10 @@ func ListModules(ctx context.Context, args []string, listU, listVersions bool) [
|
||||
addUpdate(ctx, m)
|
||||
}
|
||||
if listVersions {
|
||||
addVersions(m)
|
||||
addVersions(ctx, m, listRetracted)
|
||||
}
|
||||
if listRetracted || listU {
|
||||
addRetraction(ctx, m)
|
||||
}
|
||||
<-sem
|
||||
}()
|
||||
@ -54,10 +57,10 @@ func ListModules(ctx context.Context, args []string, listU, listVersions bool) [
|
||||
return mods
|
||||
}
|
||||
|
||||
func listModules(ctx context.Context, args []string, listVersions bool) []*modinfo.ModulePublic {
|
||||
LoadBuildList(ctx)
|
||||
func listModules(ctx context.Context, args []string, listVersions, listRetracted bool) []*modinfo.ModulePublic {
|
||||
LoadAllModules(ctx)
|
||||
if len(args) == 0 {
|
||||
return []*modinfo.ModulePublic{moduleInfo(ctx, buildList[0], true)}
|
||||
return []*modinfo.ModulePublic{moduleInfo(ctx, buildList[0], true, listRetracted)}
|
||||
}
|
||||
|
||||
var mods []*modinfo.ModulePublic
|
||||
@ -83,7 +86,13 @@ func listModules(ctx context.Context, args []string, listVersions bool) []*modin
|
||||
}
|
||||
}
|
||||
|
||||
info, err := Query(ctx, path, vers, current, nil)
|
||||
allowed := CheckAllowed
|
||||
if IsRevisionQuery(vers) || listRetracted {
|
||||
// Allow excluded and retracted versions if the user asked for a
|
||||
// specific revision or used 'go list -retracted'.
|
||||
allowed = nil
|
||||
}
|
||||
info, err := Query(ctx, path, vers, current, allowed)
|
||||
if err != nil {
|
||||
mods = append(mods, &modinfo.ModulePublic{
|
||||
Path: path,
|
||||
@ -92,7 +101,8 @@ func listModules(ctx context.Context, args []string, listVersions bool) []*modin
|
||||
})
|
||||
continue
|
||||
}
|
||||
mods = append(mods, moduleInfo(ctx, module.Version{Path: path, Version: info.Version}, false))
|
||||
mod := moduleInfo(ctx, module.Version{Path: path, Version: info.Version}, false, listRetracted)
|
||||
mods = append(mods, mod)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -117,7 +127,7 @@ func listModules(ctx context.Context, args []string, listVersions bool) []*modin
|
||||
matched = true
|
||||
if !matchedBuildList[i] {
|
||||
matchedBuildList[i] = true
|
||||
mods = append(mods, moduleInfo(ctx, m, true))
|
||||
mods = append(mods, moduleInfo(ctx, m, true, listRetracted))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,7 +139,8 @@ func listModules(ctx context.Context, args []string, listVersions bool) []*modin
|
||||
// Instead, resolve the module, even if it isn't an existing dependency.
|
||||
info, err := Query(ctx, arg, "latest", "", nil)
|
||||
if err == nil {
|
||||
mods = append(mods, moduleInfo(ctx, module.Version{Path: arg, Version: info.Version}, false))
|
||||
mod := moduleInfo(ctx, module.Version{Path: arg, Version: info.Version}, false, listRetracted)
|
||||
mods = append(mods, mod)
|
||||
} else {
|
||||
mods = append(mods, &modinfo.ModulePublic{
|
||||
Path: arg,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,13 +5,31 @@
|
||||
package modload
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/lockedfile"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/par"
|
||||
"cmd/go/internal/trace"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
// lazyLoadingVersion is the Go version (plus leading "v") at which lazy module
|
||||
// loading takes effect.
|
||||
const lazyLoadingVersionV = "v1.16"
|
||||
const go116EnableLazyLoading = true
|
||||
|
||||
var modFile *modfile.File
|
||||
|
||||
// A modFileIndex is an index of data corresponding to a modFile
|
||||
@ -20,7 +38,7 @@ type modFileIndex struct {
|
||||
data []byte
|
||||
dataNeedsFix bool // true if fixVersion applied a change while parsing data
|
||||
module module.Version
|
||||
goVersion string
|
||||
goVersionV string // GoVersion with "v" prefix
|
||||
require map[module.Version]requireMeta
|
||||
replace map[module.Version]module.Version
|
||||
exclude map[module.Version]bool
|
||||
@ -33,9 +51,151 @@ type requireMeta struct {
|
||||
indirect bool
|
||||
}
|
||||
|
||||
// Allowed reports whether module m is allowed (not excluded) by the main module's go.mod.
|
||||
func Allowed(m module.Version) bool {
|
||||
return index == nil || !index.exclude[m]
|
||||
// CheckAllowed returns an error equivalent to ErrDisallowed if m is excluded by
|
||||
// the main module's go.mod or retracted by its author. Most version queries use
|
||||
// this to filter out versions that should not be used.
|
||||
func CheckAllowed(ctx context.Context, m module.Version) error {
|
||||
if err := CheckExclusions(ctx, m); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkRetractions(ctx, m); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ErrDisallowed is returned by version predicates passed to Query and similar
|
||||
// functions to indicate that a version should not be considered.
|
||||
var ErrDisallowed = errors.New("disallowed module version")
|
||||
|
||||
// CheckExclusions returns an error equivalent to ErrDisallowed if module m is
|
||||
// excluded by the main module's go.mod file.
|
||||
func CheckExclusions(ctx context.Context, m module.Version) error {
|
||||
if index != nil && index.exclude[m] {
|
||||
return module.VersionError(m, errExcluded)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var errExcluded = &excludedError{}
|
||||
|
||||
type excludedError struct{}
|
||||
|
||||
func (e *excludedError) Error() string { return "excluded by go.mod" }
|
||||
func (e *excludedError) Is(err error) bool { return err == ErrDisallowed }
|
||||
|
||||
// checkRetractions returns an error if module m has been retracted by
|
||||
// its author.
|
||||
func checkRetractions(ctx context.Context, m module.Version) error {
|
||||
if m.Version == "" {
|
||||
// Main module, standard library, or file replacement module.
|
||||
// Cannot be retracted.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Look up retraction information from the latest available version of
|
||||
// the module. Cache retraction information so we don't parse the go.mod
|
||||
// file repeatedly.
|
||||
type entry struct {
|
||||
retract []retraction
|
||||
err error
|
||||
}
|
||||
path := m.Path
|
||||
e := retractCache.Do(path, func() (v interface{}) {
|
||||
ctx, span := trace.StartSpan(ctx, "checkRetractions "+path)
|
||||
defer span.Done()
|
||||
|
||||
if repl := Replacement(module.Version{Path: m.Path}); repl.Path != "" {
|
||||
// All versions of the module were replaced with a local directory.
|
||||
// Don't load retractions.
|
||||
return &entry{nil, nil}
|
||||
}
|
||||
|
||||
// Find the latest version of the module.
|
||||
// Ignore exclusions from the main module's go.mod.
|
||||
// We may need to account for the current version: for example,
|
||||
// v2.0.0+incompatible is not "latest" if v1.0.0 is current.
|
||||
rev, err := Query(ctx, path, "latest", findCurrentVersion(path), nil)
|
||||
if err != nil {
|
||||
return &entry{err: err}
|
||||
}
|
||||
|
||||
// Load go.mod for that version.
|
||||
// If the version is replaced, we'll load retractions from the replacement.
|
||||
// If there's an error loading the go.mod, we'll return it here.
|
||||
// These errors should generally be ignored by callers of checkRetractions,
|
||||
// since they happen frequently when we're offline. These errors are not
|
||||
// equivalent to ErrDisallowed, so they may be distinguished from
|
||||
// retraction errors.
|
||||
summary, err := goModSummary(module.Version{Path: path, Version: rev.Version})
|
||||
if err != nil {
|
||||
return &entry{err: err}
|
||||
}
|
||||
return &entry{retract: summary.retract}
|
||||
}).(*entry)
|
||||
|
||||
if e.err != nil {
|
||||
return fmt.Errorf("loading module retractions: %v", e.err)
|
||||
}
|
||||
|
||||
var rationale []string
|
||||
isRetracted := false
|
||||
for _, r := range e.retract {
|
||||
if semver.Compare(r.Low, m.Version) <= 0 && semver.Compare(m.Version, r.High) <= 0 {
|
||||
isRetracted = true
|
||||
if r.Rationale != "" {
|
||||
rationale = append(rationale, r.Rationale)
|
||||
}
|
||||
}
|
||||
}
|
||||
if isRetracted {
|
||||
return &retractedError{rationale: rationale}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var retractCache par.Cache
|
||||
|
||||
type retractedError struct {
|
||||
rationale []string
|
||||
}
|
||||
|
||||
func (e *retractedError) Error() string {
|
||||
msg := "retracted by module author"
|
||||
if len(e.rationale) > 0 {
|
||||
// This is meant to be a short error printed on a terminal, so just
|
||||
// print the first rationale.
|
||||
msg += ": " + ShortRetractionRationale(e.rationale[0])
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func (e *retractedError) Is(err error) bool {
|
||||
return err == ErrDisallowed
|
||||
}
|
||||
|
||||
// ShortRetractionRationale returns a retraction rationale string that is safe
|
||||
// to print in a terminal. It returns hard-coded strings if the rationale
|
||||
// is empty, too long, or contains non-printable characters.
|
||||
func ShortRetractionRationale(rationale string) string {
|
||||
const maxRationaleBytes = 500
|
||||
if i := strings.Index(rationale, "\n"); i >= 0 {
|
||||
rationale = rationale[:i]
|
||||
}
|
||||
rationale = strings.TrimSpace(rationale)
|
||||
if rationale == "" {
|
||||
return "retracted by module author"
|
||||
}
|
||||
if len(rationale) > maxRationaleBytes {
|
||||
return "(rationale omitted: too long)"
|
||||
}
|
||||
for _, r := range rationale {
|
||||
if !unicode.IsGraphic(r) && !unicode.IsSpace(r) {
|
||||
return "(rationale omitted: contains non-printable characters)"
|
||||
}
|
||||
}
|
||||
// NOTE: the go.mod parser rejects invalid UTF-8, so we don't check that here.
|
||||
return rationale
|
||||
}
|
||||
|
||||
// Replacement returns the replacement for mod, if any, from go.mod.
|
||||
@ -66,9 +226,11 @@ func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileInd
|
||||
i.module = modFile.Module.Mod
|
||||
}
|
||||
|
||||
i.goVersion = ""
|
||||
i.goVersionV = ""
|
||||
if modFile.Go != nil {
|
||||
i.goVersion = modFile.Go.Version
|
||||
// We're going to use the semver package to compare Go versions, so go ahead
|
||||
// and add the "v" prefix it expects once instead of every time.
|
||||
i.goVersionV = "v" + modFile.Go.Version
|
||||
}
|
||||
|
||||
i.require = make(map[module.Version]requireMeta, len(modFile.Require))
|
||||
@ -92,6 +254,23 @@ func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileInd
|
||||
return i
|
||||
}
|
||||
|
||||
// allPatternClosesOverTests reports whether the "all" pattern includes
|
||||
// dependencies of tests outside the main module (as in Go 1.11–1.15).
|
||||
// (Otherwise — as in Go 1.16+ — the "all" pattern includes only the packages
|
||||
// transitively *imported by* the packages and tests in the main module.)
|
||||
func (i *modFileIndex) allPatternClosesOverTests() bool {
|
||||
if !go116EnableLazyLoading {
|
||||
return true
|
||||
}
|
||||
if i != nil && semver.Compare(i.goVersionV, lazyLoadingVersionV) < 0 {
|
||||
// The module explicitly predates the change in "all" for lazy loading, so
|
||||
// continue to use the older interpretation. (If i == nil, we not in any
|
||||
// module at all and should use the latest semantics.)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// modFileIsDirty reports whether the go.mod file differs meaningfully
|
||||
// from what was indexed.
|
||||
// If modFile has been changed (even cosmetically) since it was first read,
|
||||
@ -114,11 +293,11 @@ func (i *modFileIndex) modFileIsDirty(modFile *modfile.File) bool {
|
||||
}
|
||||
|
||||
if modFile.Go == nil {
|
||||
if i.goVersion != "" {
|
||||
if i.goVersionV != "" {
|
||||
return true
|
||||
}
|
||||
} else if modFile.Go.Version != i.goVersion {
|
||||
if i.goVersion == "" && cfg.BuildMod == "readonly" {
|
||||
} else if "v"+modFile.Go.Version != i.goVersionV {
|
||||
if i.goVersionV == "" && cfg.BuildMod == "readonly" {
|
||||
// go.mod files did not always require a 'go' version, so do not error out
|
||||
// if one is missing — we may be inside an older module in the module
|
||||
// cache, and should bias toward providing useful behavior.
|
||||
@ -162,3 +341,190 @@ func (i *modFileIndex) modFileIsDirty(modFile *modfile.File) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// rawGoVersion records the Go version parsed from each module's go.mod file.
|
||||
//
|
||||
// If a module is replaced, the version of the replacement is keyed by the
|
||||
// replacement module.Version, not the version being replaced.
|
||||
var rawGoVersion sync.Map // map[module.Version]string
|
||||
|
||||
// A modFileSummary is a summary of a go.mod file for which we do not need to
|
||||
// retain complete information — for example, the go.mod file of a dependency
|
||||
// module.
|
||||
type modFileSummary struct {
|
||||
module module.Version
|
||||
goVersionV string // GoVersion with "v" prefix
|
||||
require []module.Version
|
||||
retract []retraction
|
||||
}
|
||||
|
||||
// A retraction consists of a retracted version interval and rationale.
|
||||
// retraction is like modfile.Retract, but it doesn't point to the syntax tree.
|
||||
type retraction struct {
|
||||
modfile.VersionInterval
|
||||
Rationale string
|
||||
}
|
||||
|
||||
// goModSummary returns a summary of the go.mod file for module m,
|
||||
// taking into account any replacements for m, exclusions of its dependencies,
|
||||
// and/or vendoring.
|
||||
//
|
||||
// goModSummary cannot be used on the Target module, as its requirements
|
||||
// may change.
|
||||
//
|
||||
// The caller must not modify the returned summary.
|
||||
func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||
if m == Target {
|
||||
panic("internal error: goModSummary called on the Target module")
|
||||
}
|
||||
|
||||
type cached struct {
|
||||
summary *modFileSummary
|
||||
err error
|
||||
}
|
||||
c := goModSummaryCache.Do(m, func() interface{} {
|
||||
if cfg.BuildMod == "vendor" {
|
||||
summary := &modFileSummary{
|
||||
module: module.Version{Path: m.Path},
|
||||
}
|
||||
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.
|
||||
return cached{summary, nil}
|
||||
}
|
||||
|
||||
// For every module other than the target,
|
||||
// return the full list of modules from modules.txt.
|
||||
readVendorList()
|
||||
|
||||
// TODO(#36876): Load the "go" version from vendor/modules.txt and store it
|
||||
// in rawGoVersion with the appropriate key.
|
||||
|
||||
// We don't know what versions the vendored module actually relies on,
|
||||
// so assume that it requires everything.
|
||||
summary.require = vendorList
|
||||
return cached{summary, nil}
|
||||
}
|
||||
|
||||
actual := Replacement(m)
|
||||
if actual.Path == "" {
|
||||
actual = m
|
||||
}
|
||||
summary, err := rawGoModSummary(actual)
|
||||
if err != nil {
|
||||
return cached{nil, err}
|
||||
}
|
||||
|
||||
if actual.Version == "" {
|
||||
// The actual module is a filesystem-local replacement, for which we have
|
||||
// unfortunately not enforced any sort of invariants about module lines or
|
||||
// matching module paths. Anything goes.
|
||||
//
|
||||
// TODO(bcmills): Remove this special-case, update tests, and add a
|
||||
// release note.
|
||||
} else {
|
||||
if summary.module.Path == "" {
|
||||
return cached{nil, module.VersionError(actual, errors.New("parsing go.mod: missing module line"))}
|
||||
}
|
||||
|
||||
// In theory we should only allow mpath to be unequal to m.Path here if the
|
||||
// version that we fetched lacks an explicit go.mod file: if the go.mod file
|
||||
// is explicit, then it should match exactly (to ensure that imports of other
|
||||
// packages within the module are interpreted correctly). Unfortunately, we
|
||||
// can't determine that information from the module proxy protocol: we'll have
|
||||
// to leave that validation for when we load actual packages from within the
|
||||
// module.
|
||||
if mpath := summary.module.Path; mpath != m.Path && mpath != actual.Path {
|
||||
return cached{nil, module.VersionError(actual, fmt.Errorf(`parsing go.mod:
|
||||
module declares its path as: %s
|
||||
but was required as: %s`, mpath, m.Path))}
|
||||
}
|
||||
}
|
||||
|
||||
if index != nil && len(index.exclude) > 0 {
|
||||
// Drop any requirements on excluded versions.
|
||||
nonExcluded := summary.require[:0]
|
||||
for _, r := range summary.require {
|
||||
if !index.exclude[r] {
|
||||
nonExcluded = append(nonExcluded, r)
|
||||
}
|
||||
}
|
||||
summary.require = nonExcluded
|
||||
}
|
||||
return cached{summary, nil}
|
||||
}).(cached)
|
||||
|
||||
return c.summary, c.err
|
||||
}
|
||||
|
||||
var goModSummaryCache par.Cache // module.Version → goModSummary result
|
||||
|
||||
// rawGoModSummary returns a new summary of the go.mod file for module m,
|
||||
// ignoring all replacements that may apply to m and excludes that may apply to
|
||||
// its dependencies.
|
||||
//
|
||||
// rawGoModSummary cannot be used on the Target module.
|
||||
func rawGoModSummary(m module.Version) (*modFileSummary, error) {
|
||||
if m == Target {
|
||||
panic("internal error: rawGoModSummary called on the Target module")
|
||||
}
|
||||
|
||||
summary := new(modFileSummary)
|
||||
var f *modfile.File
|
||||
if m.Version == "" {
|
||||
// m is a replacement module with only a file path.
|
||||
dir := m.Path
|
||||
if !filepath.IsAbs(dir) {
|
||||
dir = filepath.Join(ModRoot(), dir)
|
||||
}
|
||||
gomod := filepath.Join(dir, "go.mod")
|
||||
|
||||
data, err := lockedfile.Read(gomod)
|
||||
if err != nil {
|
||||
return nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))
|
||||
}
|
||||
f, err = modfile.ParseLax(gomod, data, nil)
|
||||
if err != nil {
|
||||
return nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err))
|
||||
}
|
||||
} else {
|
||||
if !semver.IsValid(m.Version) {
|
||||
// Disallow the broader queries supported by fetch.Lookup.
|
||||
base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version)
|
||||
}
|
||||
|
||||
data, err := modfetch.GoMod(m.Path, m.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err = modfile.ParseLax("go.mod", data, nil)
|
||||
if err != nil {
|
||||
return nil, module.VersionError(m, fmt.Errorf("parsing go.mod: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
if f.Module != nil {
|
||||
summary.module = f.Module.Mod
|
||||
}
|
||||
if f.Go != nil && f.Go.Version != "" {
|
||||
rawGoVersion.LoadOrStore(m, f.Go.Version)
|
||||
summary.goVersionV = "v" + f.Go.Version
|
||||
}
|
||||
if len(f.Require) > 0 {
|
||||
summary.require = make([]module.Version, 0, len(f.Require))
|
||||
for _, req := range f.Require {
|
||||
summary.require = append(summary.require, req.Mod)
|
||||
}
|
||||
}
|
||||
if len(f.Retract) > 0 {
|
||||
summary.retract = make([]retraction, 0, len(f.Retract))
|
||||
for _, ret := range f.Retract {
|
||||
summary.retract = append(summary.retract, retraction{
|
||||
VersionInterval: ret.VersionInterval,
|
||||
Rationale: ret.Rationale,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return summary, nil
|
||||
}
|
||||
|
@ -11,16 +11,10 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/lockedfile"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/mvs"
|
||||
"cmd/go/internal/par"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
@ -29,8 +23,6 @@ import (
|
||||
// with any exclusions or replacements applied internally.
|
||||
type mvsReqs struct {
|
||||
buildList []module.Version
|
||||
cache par.Cache
|
||||
versions sync.Map
|
||||
}
|
||||
|
||||
// Reqs returns the current module requirement graph.
|
||||
@ -44,118 +36,21 @@ func Reqs() mvs.Reqs {
|
||||
}
|
||||
|
||||
func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
|
||||
type cached struct {
|
||||
list []module.Version
|
||||
err error
|
||||
}
|
||||
|
||||
c := r.cache.Do(mod, func() interface{} {
|
||||
list, err := r.required(mod)
|
||||
if err != nil {
|
||||
return cached{nil, err}
|
||||
}
|
||||
for i, mv := range list {
|
||||
if index != nil {
|
||||
for index.exclude[mv] {
|
||||
mv1, err := r.next(mv)
|
||||
if err != nil {
|
||||
return cached{nil, err}
|
||||
}
|
||||
if mv1.Version == "none" {
|
||||
return cached{nil, fmt.Errorf("%s(%s) depends on excluded %s(%s) with no newer version available", mod.Path, mod.Version, mv.Path, mv.Version)}
|
||||
}
|
||||
mv = mv1
|
||||
}
|
||||
}
|
||||
list[i] = mv
|
||||
}
|
||||
|
||||
return cached{list, nil}
|
||||
}).(cached)
|
||||
|
||||
return c.list, c.err
|
||||
}
|
||||
|
||||
func (r *mvsReqs) modFileToList(f *modfile.File) []module.Version {
|
||||
list := make([]module.Version, 0, len(f.Require))
|
||||
for _, r := range f.Require {
|
||||
list = append(list, r.Mod)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// required returns a unique copy of the requirements of mod.
|
||||
func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
|
||||
if mod == Target {
|
||||
if modFile != nil && modFile.Go != nil {
|
||||
r.versions.LoadOrStore(mod, modFile.Go.Version)
|
||||
}
|
||||
return append([]module.Version(nil), r.buildList[1:]...), nil
|
||||
}
|
||||
|
||||
if cfg.BuildMod == "vendor" {
|
||||
// For every module other than the target,
|
||||
// return the full list of modules from modules.txt.
|
||||
readVendorList()
|
||||
return append([]module.Version(nil), vendorList...), nil
|
||||
}
|
||||
|
||||
origPath := mod.Path
|
||||
if repl := Replacement(mod); repl.Path != "" {
|
||||
if repl.Version == "" {
|
||||
// TODO: need to slip the new version into the tags list etc.
|
||||
dir := repl.Path
|
||||
if !filepath.IsAbs(dir) {
|
||||
dir = filepath.Join(ModRoot(), dir)
|
||||
}
|
||||
gomod := filepath.Join(dir, "go.mod")
|
||||
data, err := lockedfile.Read(gomod)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err)
|
||||
}
|
||||
f, err := modfile.ParseLax(gomod, data, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err)
|
||||
}
|
||||
if f.Go != nil {
|
||||
r.versions.LoadOrStore(mod, f.Go.Version)
|
||||
}
|
||||
return r.modFileToList(f), nil
|
||||
}
|
||||
mod = repl
|
||||
// Use the build list as it existed when r was constructed, not the current
|
||||
// global build list.
|
||||
return r.buildList[1:], nil
|
||||
}
|
||||
|
||||
if mod.Version == "none" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if !semver.IsValid(mod.Version) {
|
||||
// Disallow the broader queries supported by fetch.Lookup.
|
||||
base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", mod.Path, mod.Version)
|
||||
}
|
||||
|
||||
data, err := modfetch.GoMod(mod.Path, mod.Version)
|
||||
summary, err := goModSummary(mod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := modfile.ParseLax("go.mod", data, nil)
|
||||
if err != nil {
|
||||
return nil, module.VersionError(mod, fmt.Errorf("parsing go.mod: %v", err))
|
||||
}
|
||||
|
||||
if f.Module == nil {
|
||||
return nil, module.VersionError(mod, errors.New("parsing go.mod: missing module line"))
|
||||
}
|
||||
if mpath := f.Module.Mod.Path; mpath != origPath && mpath != mod.Path {
|
||||
return nil, module.VersionError(mod, fmt.Errorf(`parsing go.mod:
|
||||
module declares its path as: %s
|
||||
but was required as: %s`, mpath, origPath))
|
||||
}
|
||||
if f.Go != nil {
|
||||
r.versions.LoadOrStore(mod, f.Go.Version)
|
||||
}
|
||||
|
||||
return r.modFileToList(f), nil
|
||||
return summary.require, nil
|
||||
}
|
||||
|
||||
// Max returns the maximum of v1 and v2 according to semver.Compare.
|
||||
@ -177,16 +72,29 @@ func (*mvsReqs) Upgrade(m module.Version) (module.Version, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func versions(path string) ([]string, error) {
|
||||
func versions(ctx context.Context, path string, allowed AllowedFunc) ([]string, error) {
|
||||
// Note: modfetch.Lookup and repo.Versions are cached,
|
||||
// so there's no need for us to add extra caching here.
|
||||
var versions []string
|
||||
err := modfetch.TryProxies(func(proxy string) error {
|
||||
repo, err := modfetch.Lookup(proxy, path)
|
||||
if err == nil {
|
||||
versions, err = repo.Versions("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
allVersions, err := repo.Versions("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allowedVersions := make([]string, 0, len(allVersions))
|
||||
for _, v := range allVersions {
|
||||
if err := allowed(ctx, module.Version{Path: path, Version: v}); err == nil {
|
||||
allowedVersions = append(allowedVersions, v)
|
||||
} else if !errors.Is(err, ErrDisallowed) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
versions = allowedVersions
|
||||
return nil
|
||||
})
|
||||
return versions, err
|
||||
}
|
||||
@ -194,7 +102,8 @@ func versions(path string) ([]string, error) {
|
||||
// Previous returns the tagged version of m.Path immediately prior to
|
||||
// m.Version, or version "none" if no prior version is tagged.
|
||||
func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
|
||||
list, err := versions(m.Path)
|
||||
// TODO(golang.org/issue/38714): thread tracing context through MVS.
|
||||
list, err := versions(context.TODO(), m.Path, CheckAllowed)
|
||||
if err != nil {
|
||||
return module.Version{}, err
|
||||
}
|
||||
@ -209,7 +118,8 @@ func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
|
||||
// It is only used by the exclusion processing in the Required method,
|
||||
// not called directly by MVS.
|
||||
func (*mvsReqs) next(m module.Version) (module.Version, error) {
|
||||
list, err := versions(m.Path)
|
||||
// TODO(golang.org/issue/38714): thread tracing context through MVS.
|
||||
list, err := versions(context.TODO(), m.Path, CheckAllowed)
|
||||
if err != nil {
|
||||
return module.Version{}, err
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user