mirror of
https://github.com/golang/go
synced 2024-10-06 08:00:07 +00:00
all: merge master into release-branch.go1.10, for go1.10rc2
*b2d3d6e6
cmd/link/internal/loadelf: fix logic for computing ELF flags on ARM *c07095cd
cmd/cgo: revert CL 49490 "fix for function taking pointer typedef" *23e8e197
cmd/compile: use unsigned loads for multi-element comparisons *85bdd05c
cmd/go: rebuild as needed for tests of packages that add methods *fd7331a8
text/template: revert CL 66410 "add break, continue actions in ranges" *f54f780d
cmd/vet: unexported interface{} fields on %s are ok *a0222ec5
cmd/internal/obj/arm64: fix assemble add/adds/sub/subs/cmp/cmn(extended register) bug *59523176
cmd/go: only run -race test if -race works *4558321e
doc/editors: remove feature matrix for various editors/IDEs *e6756ec1
cmd/go: ignore coverpkg match on sync/atomic in atomic coverage mode *10d096fe
cmd/go: fix import config debugging flag *f598ad58
go/internal/gccgoimporter: remove old and exp gccgo packages in test *2a8229d9
misc/cgo/test: get uintptr, not pointer, from dlopen *851e98f0
spec: remove need for separate Function production (cleanup) *cbe1a61e
net: fix the kernel state name for TCP listen queue on FreeBSD *6f37fee3
cmd/go: fix TestNoCache on Plan 9 *e5186895
runtime: restore RSB for sigpanic call on mips64x *3ff41cdf
runtime: suppress "unexpected return pc" any time we're in cgo *d929e40e
syscall: use SYS_GETDENTS64 on linux/mips64{,le} *43288467
test: add test for gccgo bug 23545 *19150303
cmd/go: if unable to initialize cache, just disable it *ebe38b86
runtime: fail silently if we unwind over sigpanic into C code *5c2be42a
runtime: don't unwind past asmcgocall *03e10bd9
os/signal: skip TestTerminalSignal if posix_openpt fails with EACCES *d30591c1
cmd/vendor/github.com/google/pprof: cherry-pick fix to cope with $HOME not being writable *bcc86d5f
doc: add GOMIPS to source installation docs *926f2787
cmd/fix: cleanup directories created during typecheck *32a08d09
bootstrap.bash: only fetch git revision if we need it *14f8027a
cmd/vet: extra args if any formats are indexed are ok *4072608b
cmd/vet: %s is valid for an array of stringer *1f85917f
cmd/vet: **T is not Stringer if *T has a String method *8c1f21d9
cmd/vet: disable complaint about 0 flag in print *d529aa93
doc: fix the closing tag in contribute.html *f8610bbd
doc: fix two small mistakes in 1.10 release notes *5af1e7d7
cmd/go: skip external tests on plan9/arm *00587e89
doc: fix spelling mistake *3ee8c3cc
os: document inheritance of thread state over exec *b5b35be2
cmd/compile: don't inline functions that call recover *651ddbdb
database/sql: buffers provided to Rows.Next should not be modified by drivers *7350297e
doc: remove Sarah Adams from conduct working group contacts Change-Id: I3c04d83706cd4322252ddf732688afe5d938c1f5
This commit is contained in:
commit
924ef1c8ea
|
@ -618,24 +618,6 @@ pkg syscall (windows-386), func CreateProcessAsUser(Token, *uint16, *uint16, *Se
|
|||
pkg syscall (windows-386), type SysProcAttr struct, Token Token
|
||||
pkg syscall (windows-amd64), func CreateProcessAsUser(Token, *uint16, *uint16, *SecurityAttributes, *SecurityAttributes, bool, uint32, *uint16, *uint16, *StartupInfo, *ProcessInformation) error
|
||||
pkg syscall (windows-amd64), type SysProcAttr struct, Token Token
|
||||
pkg text/template/parse, const NodeBreak = 20
|
||||
pkg text/template/parse, const NodeBreak NodeType
|
||||
pkg text/template/parse, const NodeContinue = 21
|
||||
pkg text/template/parse, const NodeContinue NodeType
|
||||
pkg text/template/parse, method (*BreakNode) Copy() Node
|
||||
pkg text/template/parse, method (*BreakNode) Position() Pos
|
||||
pkg text/template/parse, method (*BreakNode) String() string
|
||||
pkg text/template/parse, method (*BreakNode) Type() NodeType
|
||||
pkg text/template/parse, method (*ContinueNode) Copy() Node
|
||||
pkg text/template/parse, method (*ContinueNode) Position() Pos
|
||||
pkg text/template/parse, method (*ContinueNode) String() string
|
||||
pkg text/template/parse, method (*ContinueNode) Type() NodeType
|
||||
pkg text/template/parse, type BreakNode struct
|
||||
pkg text/template/parse, type BreakNode struct, embedded NodeType
|
||||
pkg text/template/parse, type BreakNode struct, embedded Pos
|
||||
pkg text/template/parse, type ContinueNode struct
|
||||
pkg text/template/parse, type ContinueNode struct, embedded NodeType
|
||||
pkg text/template/parse, type ContinueNode struct, embedded Pos
|
||||
pkg time, func LoadLocationFromTZData(string, []uint8) (*Location, error)
|
||||
pkg unicode, const Version = "10.0.0"
|
||||
pkg unicode, var Masaram_Gondi *RangeTable
|
||||
|
|
|
@ -183,7 +183,6 @@ satisfaction of all parties. They are:
|
|||
<li>Aditya Mukerjee <dev@chimeracoder.net>
|
||||
<li>Andrew Gerrand <adg@golang.org>
|
||||
<li>Peggy Li <peggyli.224@gmail.com>
|
||||
<li>Sarah Adams <sadams.codes@gmail.com>
|
||||
<li>Steve Francia <steve.francia@gmail.com>
|
||||
<li>Verónica López <gveronicalg@gmail.com>
|
||||
</ul>
|
||||
|
|
|
@ -30,7 +30,7 @@ You must go through the following process <em>prior to contributing</em>.
|
|||
You only need to do this once per Google Account.
|
||||
</p>
|
||||
|
||||
<h2 id="go-contrib-init">Automatically set up & diagnose your development environment</h3>
|
||||
<h2 id="go-contrib-init">Automatically set up & diagnose your development environment</h2>
|
||||
<p>
|
||||
The <code>go-contrib-init</code> tool configures and debugs your Go
|
||||
development environment, automatically performing many of the steps
|
||||
|
|
|
@ -354,9 +354,7 @@ $ go build -gcflags="-dwarflocationlists=true"
|
|||
|
||||
<p>
|
||||
Even though both delve and gdb provides CLIs, most editor integrations
|
||||
and IDEs provides debugging-specific user interfaces. Please refer to
|
||||
the <a href="/doc/editors.html">editors guide</a> to see the options
|
||||
with debugger UI support.
|
||||
and IDEs provides debugging-specific user interfaces.
|
||||
</p>
|
||||
|
||||
<p><strong>Is it possible to do postmortem debugging with Go programs?</strong></p>
|
||||
|
|
196
doc/editors.html
196
doc/editors.html
|
@ -33,199 +33,3 @@ community-maintained list of
|
|||
<a href="https://github.com/golang/go/wiki/IDEsAndTextEditorPlugins">IDEs and text editor plugins</a>
|
||||
is available at the Wiki.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Each development environment integrates a number of Go-specific tools.
|
||||
The following feature matrix lists and compares the most significant features.
|
||||
</p>
|
||||
|
||||
<table class="features-matrix">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><img title="Vim Go" src="/doc/editors/vimgo.png"><br>vim</th>
|
||||
<th><img title="Visual Studio Code" src="/doc/editors/vscodego.png"><br>Visual Studio Code</th>
|
||||
<th><img title="GoLand" src="/doc/editors/goland.png"><br>GoLand</th>
|
||||
<th><img title="Go-Plus" src="/doc/editors/go-plus.png"><br>Atom</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feature-row" colspan="5">Editing features</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Build and run from the editor/IDE</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Autocompletion of identifiers (variable, method, and function names)</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Type-aware autocompletion</td>
|
||||
<td class="no">No</td>
|
||||
<td class="no">No</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="no">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rename identifiers</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Auto format, build, vet, and lint on save</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes<sup>1</sup></td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Auto insert import paths and remove unused on save</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes<sup>2</sup></td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Auto generate JSON, XML tags for struct fields</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feature-row" colspan="5">Navigation features</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Display documentation inline, or open godoc in browser</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Switch between <code>*.go</code> and <code>*_test.go</code> file</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jump to definition and referees</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Look up for interface implementations</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Search for callers and callees</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feature-row" colspan="5">Testing and debugging features</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Debugger support</td>
|
||||
<td class="no">No</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes<sup>3</sup></td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Run a single test case, all tests from file, or all tests from a package</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="no">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Auto generate tests for packages, files and identifiers</td>
|
||||
<td class="no">No</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="no">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Debug tests</td>
|
||||
<td class="no">No</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes<sup>3</sup></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Display test coverage</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr class="download">
|
||||
<td></td>
|
||||
<td><a href="https://github.com/fatih/vim-go">Install</a></td>
|
||||
<td><a href="https://marketplace.visualstudio.com/items?itemName=lukehoban.Go">Install</a></td>
|
||||
<td><a href="https://www.jetbrains.com/go">Install</a></td>
|
||||
<td><a href="https://atom.io/packages/go-plus">Install</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
<sup>1</sup>Possible when enabled via Settings > Go > On Save, <code>go</code> <code>vet</code> and <code>golint</code> are available via plugins. Also runs tests on save if configured.
|
||||
<br>
|
||||
<sup>2</sup>Additionally, user input can disambiguate when two or more options are available.
|
||||
<br>
|
||||
<sup>3</sup>Available if the <a href="https://atom.io/packages/go-debug">go-debug</a> package is installed.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.features-matrix {
|
||||
min-width: 800px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.features-matrix th {
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
.features-matrix th img {
|
||||
width: 48px;
|
||||
}
|
||||
.features-matrix .yes {
|
||||
text-align: center;
|
||||
}
|
||||
.features-matrix .no {
|
||||
text-align: center;
|
||||
background-color: #ffe9e9;
|
||||
}
|
||||
.features-matrix .download {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
.features-matrix td {
|
||||
padding: 11px 5px 11px 5px;
|
||||
border-bottom: solid 1px #ebebeb;
|
||||
}
|
||||
.features-matrix .feature-row {
|
||||
background-color: #ebebeb;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB |
|
@ -277,9 +277,9 @@ Go structs and Go arrays are not supported in the type signatures of cgo-exporte
|
|||
<p>
|
||||
Cgo now supports direct access to Go string values from C.
|
||||
Functions in the C preamble may use the type <code>_GoString_</code>
|
||||
to accept a Go string as an argument.
|
||||
to accept a Go string as an argument.
|
||||
C code may call <code>_GoStringLen</code> and <code>_GoStringPtr</code>
|
||||
for direct access to the contents of the string.
|
||||
for direct access to the contents of the string.
|
||||
A value of type <code>_GoString_</code>
|
||||
may be passed in a call to an exported Go function that takes an argument of Go type <code>string</code>.
|
||||
</p>
|
||||
|
@ -814,6 +814,13 @@ formats the X.509 distinguished name in the standard RFC 2253 format.
|
|||
<dl id="database/sql/driver"><dt><a href="/pkg/database/sql/driver/">database/sql/driver</a></dt>
|
||||
<dd>
|
||||
<p>
|
||||
Drivers that currently hold on to the destination buffer provided by
|
||||
<a href="/pkg/database/sql/driver/#Rows.Next"><code>driver.Rows.Next</code></a> should ensure they no longer
|
||||
write to a buffer assigned to the destination array outside of that call.
|
||||
Drivers must be careful that underlying buffers are not modified when closing
|
||||
<a href="/pkg/database/sql/driver/#Rows"><code>driver.Rows</code></a>.
|
||||
</p>
|
||||
<p>
|
||||
Drivers that want to construct a <a href="/pkg/database/sql/#DB"><code>sql.DB</code></a> for
|
||||
their clients can now implement the <a href="/pkg/database/sql/driver/#Connector"><code>Connector</code></a> interface
|
||||
and call the new <a href="/pkg/database/sql/#OpenDB"><code>sql.OpenDB</code></a> function,
|
||||
|
@ -1062,11 +1069,6 @@ now implement those interfaces.
|
|||
<dl id="html/template"><dt><a href="/pkg/html/template/">html/template</a></dt>
|
||||
<dd>
|
||||
<p>
|
||||
The new actions <code>{{"{{break}}"}}</code> and <code>{{"{{continue}}"}}</code>
|
||||
break out of the innermost <code>{{"{{range"}}</code> ...<code>}}</code> loop,
|
||||
like the corresponding Go statements.
|
||||
</p>
|
||||
<p>
|
||||
The new <a href="/pkg/html/template#Srcset"><code>Srcset</code></a> content
|
||||
type allows for proper handling of values within the
|
||||
<a href="https://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset"><code>srcset</code></a>
|
||||
|
@ -1340,7 +1342,7 @@ in the corresponding <a href="/pkg/reflect/#StructField">StructField</a>,
|
|||
with the result that for those fields,
|
||||
and <a href="/pkg/reflect/#Value.CanSet"><code>Value.CanSet</code></a>
|
||||
incorrectly returned true and
|
||||
and <a href="/pkg/reflect/#Value.Set"><code>Value.Set</code></a>
|
||||
<a href="/pkg/reflect/#Value.Set"><code>Value.Set</code></a>
|
||||
incorrectly succeeded.
|
||||
The underlying metadata has been corrected;
|
||||
for those fields,
|
||||
|
@ -1404,15 +1406,6 @@ is now implemented.
|
|||
</p>
|
||||
</dl>
|
||||
|
||||
<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
|
||||
<dd>
|
||||
<p>
|
||||
The new actions <code>{{"{{break}}"}}</code> and <code>{{"{{continue}}"}}</code>
|
||||
break out of the innermost <code>{{"{{range"}}</code> ...<code>}}</code> loop,
|
||||
like the corresponding Go statements.
|
||||
</p>
|
||||
</dl>
|
||||
|
||||
<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
|
||||
<dd>
|
||||
<p>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of January 23, 2018",
|
||||
"Subtitle": "Version of February 1, 2018",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
|
@ -2148,9 +2148,8 @@ to a function.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
FunctionDecl = "func" FunctionName ( Function | Signature ) .
|
||||
FunctionDecl = "func" FunctionName Signature [ FunctionBody ] .
|
||||
FunctionName = identifier .
|
||||
Function = Signature FunctionBody .
|
||||
FunctionBody = Block .
|
||||
</pre>
|
||||
|
||||
|
@ -2196,7 +2195,7 @@ and associates the method with the receiver's <i>base type</i>.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
|
||||
MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] .
|
||||
Receiver = Parameters .
|
||||
</pre>
|
||||
|
||||
|
@ -2518,7 +2517,7 @@ A function literal represents an anonymous <a href="#Function_declarations">func
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
FunctionLit = "func" Function .
|
||||
FunctionLit = "func" Signature FunctionBody .
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
|
|
|
@ -446,6 +446,7 @@ defaults to the parent of the directory where <code>all.bash</code> was run.
|
|||
There is no need to set this unless you want to switch between multiple
|
||||
local copies of the repository.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li><code>$GOROOT_FINAL</code>
|
||||
<p>
|
||||
|
@ -456,12 +457,14 @@ If you want to build the Go tree in one location
|
|||
but move it elsewhere after the build, set
|
||||
<code>$GOROOT_FINAL</code> to the eventual location.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li><code>$GOOS</code> and <code>$GOARCH</code>
|
||||
<p>
|
||||
The name of the target operating system and compilation architecture.
|
||||
These default to the values of <code>$GOHOSTOS</code> and
|
||||
<code>$GOHOSTARCH</code> respectively (described below).
|
||||
</li>
|
||||
|
||||
<p>
|
||||
Choices for <code>$GOOS</code> are
|
||||
|
@ -582,6 +585,7 @@ The name of the host operating system and compilation architecture.
|
|||
These default to the local system's operating system and
|
||||
architecture.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<p>
|
||||
Valid choices are the same as for <code>$GOOS</code> and
|
||||
|
@ -600,6 +604,7 @@ directory to your <code>$PATH</code>, so you can use the tools.
|
|||
If <code>$GOBIN</code> is set, the <a href="/cmd/go">go command</a>
|
||||
installs all commands there.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li><code>$GO386</code> (for <code>386</code> only, default is auto-detected
|
||||
if built on either <code>386</code> or <code>amd64</code>, <code>387</code> otherwise)
|
||||
|
@ -609,9 +614,10 @@ This controls the code generated by gc to use either the 387 floating-point unit
|
|||
floating point computations.
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>GO386=387</code>: use x87 for floating point operations; should support all x86 chips (Pentium MMX or later).
|
||||
<li><code>GO386=sse2</code>: use SSE2 for floating point operations; has better performance than 387, but only available on Pentium 4/Opteron/Athlon 64 or later.
|
||||
<li><code>GO386=387</code>: use x87 for floating point operations; should support all x86 chips (Pentium MMX or later).</li>
|
||||
<li><code>GO386=sse2</code>: use SSE2 for floating point operations; has better performance than 387, but only available on Pentium 4/Opteron/Athlon 64 or later.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><code>$GOARM</code> (for <code>arm</code> only; default is auto-detected if building
|
||||
on the target processor, 6 if not)
|
||||
|
@ -620,9 +626,9 @@ This sets the ARM floating point co-processor architecture version the run-time
|
|||
should target. If you are compiling on the target system, its value will be auto-detected.
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>GOARM=5</code>: use software floating point; when CPU doesn't have VFP co-processor
|
||||
<li><code>GOARM=6</code>: use VFPv1 only; default if cross compiling; usually ARM11 or better cores (VFPv2 or better is also supported)
|
||||
<li><code>GOARM=7</code>: use VFPv3; usually Cortex-A cores
|
||||
<li><code>GOARM=5</code>: use software floating point; when CPU doesn't have VFP co-processor</li>
|
||||
<li><code>GOARM=6</code>: use VFPv1 only; default if cross compiling; usually ARM11 or better cores (VFPv2 or better is also supported)</li>
|
||||
<li><code>GOARM=7</code>: use VFPv3; usually Cortex-A cores</li>
|
||||
</ul>
|
||||
<p>
|
||||
If in doubt, leave this variable unset, and adjust it if required
|
||||
|
@ -631,6 +637,17 @@ The <a href="//golang.org/wiki/GoArm">GoARM</a> page
|
|||
on the <a href="//golang.org/wiki">Go community wiki</a>
|
||||
contains further details regarding Go's ARM support.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li><code>$GOMIPS</code> (for <code>mips</code> and <code>mipsle</code> only)
|
||||
<p>
|
||||
This sets whether to use floating point instructions.
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>GOMIPS=hardfloat</code>: use floating point instructions (the default)</li>
|
||||
<li><code>GOMIPS=softfloat</code>: use soft floating point</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// Issue 19832. Functions taking a pointer typedef were being expanded and triggering a compiler error.
|
||||
|
||||
package cgotest
|
||||
|
||||
// typedef struct { int i; } *PS;
|
||||
// void T19832(PS p) {}
|
||||
import "C"
|
||||
import "testing"
|
||||
|
||||
func test19832(t *testing.T) {
|
||||
C.T19832(nil)
|
||||
}
|
|
@ -4,6 +4,25 @@
|
|||
|
||||
// +build !windows
|
||||
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
// Write our own versions of dlopen/dlsym/dlclose so that we represent
|
||||
// the opaque handle as a Go uintptr rather than a Go pointer to avoid
|
||||
// garbage collector confusion. See issue 23663.
|
||||
|
||||
uintptr_t dlopen4029(char* name, int flags) {
|
||||
return (uintptr_t)(dlopen(name, flags));
|
||||
}
|
||||
|
||||
uintptr_t dlsym4029(uintptr_t handle, char* name) {
|
||||
return (uintptr_t)(dlsym((void*)(handle), name));
|
||||
}
|
||||
|
||||
int dlclose4029(uintptr_t handle) {
|
||||
return dlclose((void*)(handle));
|
||||
}
|
||||
|
||||
void call4029(void *arg) {
|
||||
void (*fn)(void) = arg;
|
||||
fn();
|
||||
|
|
|
@ -7,10 +7,15 @@
|
|||
package cgotest
|
||||
|
||||
/*
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
#cgo linux LDFLAGS: -ldl
|
||||
|
||||
extern void call4029(void *arg);
|
||||
extern uintptr_t dlopen4029(char*, int);
|
||||
extern uintptr_t dlsym4029(uintptr_t, char*);
|
||||
extern int dlclose4029(uintptr_t);
|
||||
|
||||
extern void call4029(uintptr_t arg);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
|
@ -51,15 +56,15 @@ func test4029(t *testing.T) {
|
|||
}
|
||||
|
||||
func loadThySelf(t *testing.T, symbol string) {
|
||||
this_process := C.dlopen(nil, C.RTLD_NOW)
|
||||
if this_process == nil {
|
||||
this_process := C.dlopen4029(nil, C.RTLD_NOW)
|
||||
if this_process == 0 {
|
||||
t.Error("dlopen:", C.GoString(C.dlerror()))
|
||||
return
|
||||
}
|
||||
defer C.dlclose(this_process)
|
||||
defer C.dlclose4029(this_process)
|
||||
|
||||
symbol_address := C.dlsym(this_process, C.CString(symbol))
|
||||
if symbol_address == nil {
|
||||
symbol_address := C.dlsym4029(this_process, C.CString(symbol))
|
||||
if symbol_address == 0 {
|
||||
t.Error("dlsym:", C.GoString(C.dlerror()))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -77,7 +77,11 @@ else
|
|||
rm -rf "pkg/${gohostos}_${gohostarch}" "pkg/tool/${gohostos}_${gohostarch}"
|
||||
fi
|
||||
|
||||
GITREV=$(git rev-parse --short HEAD)
|
||||
if [ "$BOOTSTRAP_FORMAT" = "mintgz" ]; then
|
||||
# Fetch git revision before rm -rf .git.
|
||||
GITREV=$(git rev-parse --short HEAD)
|
||||
fi
|
||||
|
||||
rm -rf pkg/bootstrap pkg/obj .git
|
||||
|
||||
# Support for building minimal tar.gz for the builders.
|
||||
|
|
|
@ -123,6 +123,11 @@ func arm64RegisterNumber(name string, n int16) (int16, bool) {
|
|||
// ARM64RegisterExtension parses an ARM64 register with extension or arrangment.
|
||||
func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
|
||||
rm := uint32(reg)
|
||||
if isAmount {
|
||||
if num < 0 || num > 7 {
|
||||
return errors.New("shift amount out of range")
|
||||
}
|
||||
}
|
||||
switch ext {
|
||||
case "UXTB":
|
||||
if !isAmount {
|
||||
|
@ -134,7 +139,7 @@ func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, i
|
|||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_UXTH + (num & 31) + int16(num<<5)
|
||||
a.Reg = arm64.REG_UXTH + (reg & 31) + int16(num<<5)
|
||||
a.Offset = int64(((rm & 31) << 16) | (1 << 13) | (uint32(num) << 10))
|
||||
case "UXTW":
|
||||
if !isAmount {
|
||||
|
|
16
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
16
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
|
@ -29,8 +29,20 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
|||
ADD R1<<22, R2, R3
|
||||
ADD R1->33, R2, R3
|
||||
AND R1@>33, R2, R3
|
||||
ADD R1.UXTB, R2, R3 // 4360218b
|
||||
ADD R1.UXTB<<4, R2, R3 // 4370218b
|
||||
ADD R1.UXTB, R2, R3 // 4300218b
|
||||
ADD R1.UXTB<<4, R2, R3 // 4310218b
|
||||
ADDW R2.SXTW, R10, R12 // 4cc1220b
|
||||
ADD R18.UXTX, R14, R17 // d161328b
|
||||
ADDSW R18.UXTW, R14, R17 // d141322b
|
||||
ADDS R12.SXTX, R3, R1 // 61e02cab
|
||||
SUB R19.UXTH<<4, R2, R21 // 553033cb
|
||||
SUBW R1.UXTX<<1, R3, R2 // 6264214b
|
||||
SUBS R3.UXTX, R8, R9 // 096123eb
|
||||
SUBSW R17.UXTH, R15, R21 // f521316b
|
||||
CMP R2.SXTH, R13 // bfa122eb
|
||||
CMN R1.SXTX<<2, R10 // 5fe921ab
|
||||
CMPW R2.UXTH<<3, R11 // 7f2d226b
|
||||
CMNW R1.SXTB, R9 // 3f81212b
|
||||
VADDP V1.B16, V2.B16, V3.B16 // 43bc214e
|
||||
VADDP V1.S4, V2.S4, V3.S4 // 43bca14e
|
||||
VADDP V1.D2, V2.D2, V3.D2 // 43bce14e
|
||||
|
|
|
@ -10,4 +10,6 @@ TEXT errors(SB),$0
|
|||
VST1 [V1.B16], (R8)(R13) // ERROR "illegal combination"
|
||||
VST1 [V1.B16], 9(R2) // ERROR "illegal combination"
|
||||
VLD1 8(R8)(R13), [V2.B16] // ERROR "illegal combination"
|
||||
ADD R1.UXTB<<5, R2, R3 // ERROR "shift amount out of range 0 to 4"
|
||||
ADDS R1.UXTX<<7, R2, R3 // ERROR "shift amount out of range 0 to 4"
|
||||
RET
|
||||
|
|
|
@ -2250,12 +2250,6 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
break
|
||||
}
|
||||
|
||||
// If we already know the typedef for t just use that.
|
||||
// See issue 19832.
|
||||
if def := typedef[t.Go.(*ast.Ident).Name]; def != nil {
|
||||
break
|
||||
}
|
||||
|
||||
t = c.Type(ptr, pos)
|
||||
if t == nil {
|
||||
return nil
|
||||
|
|
|
@ -1002,6 +1002,20 @@ var linuxAMD64Tests = []*asmTest{
|
|||
}`,
|
||||
pos: []string{"\tCMPL\t[A-Z]"},
|
||||
},
|
||||
{
|
||||
fn: `
|
||||
func $(a,b [3]int16) bool {
|
||||
return a == b
|
||||
}`,
|
||||
pos: []string{"\tCMPL\t[A-Z]"},
|
||||
},
|
||||
{
|
||||
fn: `
|
||||
func $(a,b [12]int8) bool {
|
||||
return a == b
|
||||
}`,
|
||||
pos: []string{"\tCMPQ\t[A-Z]", "\tCMPL\t[A-Z]"},
|
||||
},
|
||||
{
|
||||
fn: `
|
||||
func f70(a,b [15]byte) bool {
|
||||
|
|
|
@ -314,12 +314,18 @@ func (v *hairyVisitor) visit(n *Node) bool {
|
|||
}
|
||||
|
||||
// Things that are too hairy, irrespective of the budget
|
||||
case OCALL, OCALLINTER, OPANIC, ORECOVER:
|
||||
case OCALL, OCALLINTER, OPANIC:
|
||||
if Debug['l'] < 4 {
|
||||
v.reason = "non-leaf op " + n.Op.String()
|
||||
return true
|
||||
}
|
||||
|
||||
case ORECOVER:
|
||||
// recover matches the argument frame pointer to find
|
||||
// the right panic value, so it needs an argument frame.
|
||||
v.reason = "call to recover"
|
||||
return true
|
||||
|
||||
case OCLOSURE,
|
||||
OCALLPART,
|
||||
ORANGE,
|
||||
|
|
|
@ -3415,18 +3415,23 @@ func walkcompare(n *Node, init *Nodes) *Node {
|
|||
i++
|
||||
remains -= t.Elem().Width
|
||||
} else {
|
||||
elemType := t.Elem().ToUnsigned()
|
||||
cmplw := nod(OINDEX, cmpl, nodintconst(int64(i)))
|
||||
cmplw = conv(cmplw, convType)
|
||||
cmplw = conv(cmplw, elemType) // convert to unsigned
|
||||
cmplw = conv(cmplw, convType) // widen
|
||||
cmprw := nod(OINDEX, cmpr, nodintconst(int64(i)))
|
||||
cmprw = conv(cmprw, elemType)
|
||||
cmprw = conv(cmprw, convType)
|
||||
// For code like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
|
||||
// ssa will generate a single large load.
|
||||
for offset := int64(1); offset < step; offset++ {
|
||||
lb := nod(OINDEX, cmpl, nodintconst(int64(i+offset)))
|
||||
lb = conv(lb, elemType)
|
||||
lb = conv(lb, convType)
|
||||
lb = nod(OLSH, lb, nodintconst(int64(8*t.Elem().Width*offset)))
|
||||
cmplw = nod(OOR, cmplw, lb)
|
||||
rb := nod(OINDEX, cmpr, nodintconst(int64(i+offset)))
|
||||
rb = conv(rb, elemType)
|
||||
rb = conv(rb, convType)
|
||||
rb = nod(OLSH, rb, nodintconst(int64(8*t.Elem().Width*offset)))
|
||||
cmprw = nod(OOR, cmprw, rb)
|
||||
|
|
|
@ -166,7 +166,7 @@ func typecheck(cfg *TypeConfig, f *ast.File) (typeof map[interface{}]string, ass
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(dir)
|
||||
defer os.RemoveAll(dir)
|
||||
err = ioutil.WriteFile(filepath.Join(dir, "in.go"), txt, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -81,6 +81,13 @@ func init() {
|
|||
skipExternal = true
|
||||
canRun = false
|
||||
}
|
||||
case "plan9":
|
||||
switch runtime.GOARCH {
|
||||
case "arm":
|
||||
// many plan9/arm machines are too slow to run
|
||||
// the full set of external tests.
|
||||
skipExternal = true
|
||||
}
|
||||
case "windows":
|
||||
exeSuffix = ".exe"
|
||||
}
|
||||
|
@ -5366,6 +5373,30 @@ func TestTestCacheInputs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNoCache(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
t.Skipf("no unwritable directories on %s", runtime.GOOS)
|
||||
}
|
||||
if os.Getuid() == 0 {
|
||||
t.Skip("skipping test because running as root")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempFile("triv.go", `package main; func main() {}`)
|
||||
tg.must(os.MkdirAll(tg.path("unwritable"), 0555))
|
||||
home := "HOME"
|
||||
if runtime.GOOS == "plan9" {
|
||||
home = "home"
|
||||
}
|
||||
tg.setenv(home, tg.path(filepath.Join("unwritable", "home")))
|
||||
tg.unsetenv("GOCACHE")
|
||||
tg.run("build", "-o", tg.path("triv"), tg.path("triv.go"))
|
||||
tg.grepStderr("disabling cache", "did not disable cache")
|
||||
}
|
||||
|
||||
func TestTestVet(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tg := testgo(t)
|
||||
|
@ -5408,6 +5439,44 @@ func TestTestVet(t *testing.T) {
|
|||
tg.grepStdout(`ok\s+vetfail/p2`, "did not run vetfail/p2")
|
||||
}
|
||||
|
||||
func TestTestRebuild(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
|
||||
// golang.org/issue/23701.
|
||||
// b_test imports b with augmented method from export_test.go.
|
||||
// b_test also imports a, which imports b.
|
||||
// Must not accidentally see un-augmented b propagate through a to b_test.
|
||||
tg.tempFile("src/a/a.go", `package a
|
||||
import "b"
|
||||
type Type struct{}
|
||||
func (*Type) M() b.T {return 0}
|
||||
`)
|
||||
tg.tempFile("src/b/b.go", `package b
|
||||
type T int
|
||||
type I interface {M() T}
|
||||
`)
|
||||
tg.tempFile("src/b/export_test.go", `package b
|
||||
func (*T) Method() *T { return nil }
|
||||
`)
|
||||
tg.tempFile("src/b/b_test.go", `package b_test
|
||||
import (
|
||||
"testing"
|
||||
"a"
|
||||
. "b"
|
||||
)
|
||||
func TestBroken(t *testing.T) {
|
||||
x := new(T)
|
||||
x.Method()
|
||||
_ = new(a.Type)
|
||||
}
|
||||
`)
|
||||
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.run("test", "b")
|
||||
}
|
||||
|
||||
func TestInstallDeps(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tg := testgo(t)
|
||||
|
@ -5655,3 +5724,18 @@ func TestCpuprofileTwice(t *testing.T) {
|
|||
tg.run("test", "-o="+bin, "-cpuprofile="+out, "x")
|
||||
tg.mustExist(out)
|
||||
}
|
||||
|
||||
// Issue 23694.
|
||||
func TestAtomicCoverpkgAll(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
|
||||
tg.tempFile("src/x/x.go", `package x; import _ "sync/atomic"; func F() {}`)
|
||||
tg.tempFile("src/x/x_test.go", `package x; import "testing"; func TestF(t *testing.T) { F() }`)
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.run("test", "-coverpkg=all", "-covermode=atomic", "x")
|
||||
if canRace {
|
||||
tg.run("test", "-coverpkg=all", "-race", "x")
|
||||
}
|
||||
}
|
||||
|
|
8
src/cmd/go/internal/cache/default.go
vendored
8
src/cmd/go/internal/cache/default.go
vendored
|
@ -5,7 +5,7 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"cmd/go/internal/base"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -40,7 +40,8 @@ func initDefaultCache() {
|
|||
return
|
||||
}
|
||||
if err := os.MkdirAll(dir, 0777); err != nil {
|
||||
base.Fatalf("initializing cache in $GOCACHE: %s", err)
|
||||
fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err)
|
||||
return
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(dir, "README")); err != nil {
|
||||
// Best effort.
|
||||
|
@ -49,7 +50,8 @@ func initDefaultCache() {
|
|||
|
||||
c, err := Open(dir)
|
||||
if err != nil {
|
||||
base.Fatalf("initializing cache in $GOCACHE: %s", err)
|
||||
fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err)
|
||||
return
|
||||
}
|
||||
defaultCache = c
|
||||
}
|
||||
|
|
|
@ -416,6 +416,9 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
|
|||
var err error
|
||||
if debugDeprecatedImportcfgDir != "" {
|
||||
bp, err = cfg.BuildContext.ImportDir(debugDeprecatedImportcfgDir, 0)
|
||||
} else if DebugDeprecatedImportcfg.enabled {
|
||||
bp = new(build.Package)
|
||||
err = fmt.Errorf("unknown import path %q: not in import cfg", importPath)
|
||||
} else {
|
||||
buildMode := build.ImportComment
|
||||
if mode&UseVendor == 0 || path != origPath {
|
||||
|
@ -514,6 +517,13 @@ func isDir(path string) bool {
|
|||
// x/vendor/path, vendor/path, or else stay path if none of those exist.
|
||||
// VendoredImportPath returns the expanded path or, if no expansion is found, the original.
|
||||
func VendoredImportPath(parent *Package, path string) (found string) {
|
||||
if DebugDeprecatedImportcfg.enabled {
|
||||
if d, i := DebugDeprecatedImportcfg.lookup(parent, path); d != "" {
|
||||
return i
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
if parent == nil || parent.Root == "" {
|
||||
return path
|
||||
}
|
||||
|
|
|
@ -659,6 +659,15 @@ func runTest(cmd *base.Command, args []string) {
|
|||
haveMatch = true
|
||||
}
|
||||
}
|
||||
|
||||
// Silently ignore attempts to run coverage on
|
||||
// sync/atomic when using atomic coverage mode.
|
||||
// Atomic coverage mode uses sync/atomic, so
|
||||
// we can't also do coverage on it.
|
||||
if testCoverMode == "atomic" && p.Standard && p.ImportPath == "sync/atomic" {
|
||||
continue
|
||||
}
|
||||
|
||||
if haveMatch {
|
||||
testCoverPkgs = append(testCoverPkgs, p)
|
||||
}
|
||||
|
@ -888,7 +897,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
|||
t.ImportXtest = true
|
||||
}
|
||||
|
||||
if ptest != p && localCover {
|
||||
if ptest != p {
|
||||
// We have made modifications to the package p being tested
|
||||
// and are rebuilding p (as ptest).
|
||||
// Arrange to rebuild all packages q such that
|
||||
|
@ -897,13 +906,6 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
|||
// Strictly speaking, the rebuild is only necessary if the
|
||||
// modifications to p change its export metadata, but
|
||||
// determining that is a bit tricky, so we rebuild always.
|
||||
// TODO(rsc): Once we get export metadata changes
|
||||
// handled properly, look into the expense of dropping
|
||||
// "&& localCover" above.
|
||||
//
|
||||
// This will cause extra compilation, so for now we only do it
|
||||
// when testCover is set. The conditions are more general, though,
|
||||
// and we may find that we need to do it always in the future.
|
||||
recompileForTest(pmain, p, ptest, pxtest)
|
||||
}
|
||||
|
||||
|
|
|
@ -2362,7 +2362,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||
r = rt
|
||||
}
|
||||
if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
|
||||
o2 = c.opxrrr(p, p.As)
|
||||
o2 = c.opxrrr(p, p.As, false)
|
||||
o2 |= REGTMP & 31 << 16
|
||||
o2 |= LSL0_64
|
||||
} else {
|
||||
|
@ -2591,11 +2591,16 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||
o1 |= (REGZERO & 31 << 5) | uint32(rt&31)
|
||||
|
||||
case 27: /* op Rm<<n[,Rn],Rd (extended register) */
|
||||
o1 = c.opxrrr(p, p.As)
|
||||
|
||||
if (p.From.Reg-obj.RBaseARM64)®_EXT != 0 {
|
||||
amount := (p.From.Reg >> 5) & 7
|
||||
if amount > 4 {
|
||||
c.ctxt.Diag("shift amount out of range 0 to 4: %v", p)
|
||||
}
|
||||
o1 = c.opxrrr(p, p.As, true)
|
||||
o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
|
||||
} else {
|
||||
o1 = c.opxrrr(p, p.As, false)
|
||||
o1 |= uint32(p.From.Reg&31) << 16
|
||||
}
|
||||
rt := int(p.To.Reg)
|
||||
|
@ -2755,7 +2760,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||
if !(o1 != 0) {
|
||||
break
|
||||
}
|
||||
o2 = c.opxrrr(p, AADD)
|
||||
o2 = c.opxrrr(p, AADD, false)
|
||||
o2 |= REGTMP & 31 << 16
|
||||
o2 |= LSL0_64
|
||||
r := int(p.From.Reg)
|
||||
|
@ -3122,7 +3127,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||
r = rt
|
||||
}
|
||||
if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
|
||||
o2 = c.opxrrr(p, p.As)
|
||||
o2 = c.opxrrr(p, p.As, false)
|
||||
o2 |= REGTMP & 31 << 16
|
||||
o2 |= LSL0_64
|
||||
} else {
|
||||
|
@ -3373,7 +3378,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||
}
|
||||
|
||||
o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
|
||||
o2 = c.opxrrr(p, AADD)
|
||||
o2 = c.opxrrr(p, AADD, false)
|
||||
o2 |= (REGTMP & 31) << 16
|
||||
o2 |= uint32(r&31) << 5
|
||||
o2 |= uint32(REGTMP & 31)
|
||||
|
@ -3426,7 +3431,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||
o3 |= 2 << 23
|
||||
}
|
||||
o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
|
||||
o2 = c.opxrrr(p, AADD)
|
||||
o2 = c.opxrrr(p, AADD, false)
|
||||
o2 |= REGTMP & 31 << 16
|
||||
o2 |= uint32(r&31) << 5
|
||||
o2 |= uint32(REGTMP & 31)
|
||||
|
@ -4518,33 +4523,44 @@ func (c *ctxt7) opbit(p *obj.Prog, a obj.As) uint32 {
|
|||
}
|
||||
|
||||
/*
|
||||
* add/subtract extended register
|
||||
* add/subtract sign or zero-extended register
|
||||
*/
|
||||
func (c *ctxt7) opxrrr(p *obj.Prog, a obj.As) uint32 {
|
||||
func (c *ctxt7) opxrrr(p *obj.Prog, a obj.As, extend bool) uint32 {
|
||||
extension := uint32(0)
|
||||
if !extend {
|
||||
switch a {
|
||||
case AADD, ACMN, AADDS, ASUB, ACMP, ASUBS:
|
||||
extension = LSL0_64
|
||||
|
||||
case AADDW, ACMNW, AADDSW, ASUBW, ACMPW, ASUBSW:
|
||||
extension = LSL0_32
|
||||
}
|
||||
}
|
||||
|
||||
switch a {
|
||||
case AADD:
|
||||
return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
|
||||
return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
|
||||
|
||||
case AADDW:
|
||||
return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
|
||||
return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
|
||||
|
||||
case ACMN, AADDS:
|
||||
return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
|
||||
return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
|
||||
|
||||
case ACMNW, AADDSW:
|
||||
return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
|
||||
return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
|
||||
|
||||
case ASUB:
|
||||
return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
|
||||
return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
|
||||
|
||||
case ASUBW:
|
||||
return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
|
||||
return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
|
||||
|
||||
case ACMP, ASUBS:
|
||||
return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
|
||||
return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
|
||||
|
||||
case ACMPW, ASUBSW:
|
||||
return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
|
||||
return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
|
||||
}
|
||||
|
||||
c.ctxt.Diag("bad opxrrr %v\n%v", a, p)
|
||||
|
|
|
@ -405,13 +405,10 @@ func (a *elfAttributeList) done() bool {
|
|||
// find the one we are looking for. This format is slightly documented in "ELF
|
||||
// for the ARM Architecture" but mostly this is derived from reading the source
|
||||
// to gold and readelf.
|
||||
func parseArmAttributes(e binary.ByteOrder, initEhdrFlags uint32, data []byte) (ehdrFlags uint32, err error) {
|
||||
// We assume the soft-float ABI unless we see a tag indicating otherwise.
|
||||
if initEhdrFlags == 0x5000002 {
|
||||
ehdrFlags = 0x5000202
|
||||
}
|
||||
func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags uint32, err error) {
|
||||
found = false
|
||||
if data[0] != 'A' {
|
||||
return 0, fmt.Errorf(".ARM.attributes has unexpected format %c\n", data[0])
|
||||
return false, 0, fmt.Errorf(".ARM.attributes has unexpected format %c\n", data[0])
|
||||
}
|
||||
data = data[1:]
|
||||
for len(data) != 0 {
|
||||
|
@ -421,7 +418,7 @@ func parseArmAttributes(e binary.ByteOrder, initEhdrFlags uint32, data []byte) (
|
|||
|
||||
nulIndex := bytes.IndexByte(sectiondata, 0)
|
||||
if nulIndex < 0 {
|
||||
return 0, fmt.Errorf("corrupt .ARM.attributes (section name not NUL-terminated)\n")
|
||||
return false, 0, fmt.Errorf("corrupt .ARM.attributes (section name not NUL-terminated)\n")
|
||||
}
|
||||
name := string(sectiondata[:nulIndex])
|
||||
sectiondata = sectiondata[nulIndex+1:]
|
||||
|
@ -442,15 +439,16 @@ func parseArmAttributes(e binary.ByteOrder, initEhdrFlags uint32, data []byte) (
|
|||
for !attrList.done() {
|
||||
attr := attrList.armAttr()
|
||||
if attr.tag == TagABIVFPArgs && attr.ival == 1 {
|
||||
found = true
|
||||
ehdrFlags = 0x5000402 // has entry point, Version5 EABI, hard-float ABI
|
||||
}
|
||||
}
|
||||
if attrList.err != nil {
|
||||
return 0, fmt.Errorf("could not parse .ARM.attributes\n")
|
||||
return false, 0, fmt.Errorf("could not parse .ARM.attributes\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
return ehdrFlags, nil
|
||||
return found, ehdrFlags, nil
|
||||
}
|
||||
|
||||
// Load loads the ELF file pn from f.
|
||||
|
@ -686,11 +684,20 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
|
|||
if err := elfmap(elfobj, sect); err != nil {
|
||||
return errorf("%s: malformed elf file: %v", pn, err)
|
||||
}
|
||||
ehdrFlags, err = parseArmAttributes(e, initEhdrFlags, sect.base[:sect.size])
|
||||
// We assume the soft-float ABI unless we see a tag indicating otherwise.
|
||||
if initEhdrFlags == 0x5000002 {
|
||||
ehdrFlags = 0x5000202
|
||||
} else {
|
||||
ehdrFlags = initEhdrFlags
|
||||
}
|
||||
found, newEhdrFlags, err := parseArmAttributes(e, sect.base[:sect.size])
|
||||
if err != nil {
|
||||
// TODO(dfc) should this return an error?
|
||||
log.Printf("%s: %v", pn, err)
|
||||
}
|
||||
if found {
|
||||
ehdrFlags = newEhdrFlags
|
||||
}
|
||||
}
|
||||
if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 {
|
||||
continue
|
||||
|
|
12
src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go
generated
vendored
12
src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go
generated
vendored
|
@ -362,6 +362,18 @@ func TestHttpsInsecure(t *testing.T) {
|
|||
if runtime.GOOS == "nacl" {
|
||||
t.Skip("test assumes tcp available")
|
||||
}
|
||||
saveHome := os.Getenv(homeEnv())
|
||||
tempdir, err := ioutil.TempDir("", "home")
|
||||
if err != nil {
|
||||
t.Fatal("creating temp dir: ", err)
|
||||
}
|
||||
defer os.RemoveAll(tempdir)
|
||||
|
||||
// pprof writes to $HOME/pprof by default which is not necessarily
|
||||
// writeable (e.g. on a Debian buildd) so set $HOME to something we
|
||||
// know we can write to for the duration of the test.
|
||||
os.Setenv(homeEnv(), tempdir)
|
||||
defer os.Setenv(homeEnv(), saveHome)
|
||||
|
||||
baseVars := pprofVariables
|
||||
pprofVariables = baseVars.makeCopy()
|
||||
|
|
|
@ -195,9 +195,11 @@ type File struct {
|
|||
// Parsed package "foo" when checking package "foo_test"
|
||||
basePkg *Package
|
||||
|
||||
// The objects that are receivers of a "String() string" method.
|
||||
// The keys are the objects that are receivers of a "String()
|
||||
// string" method. The value reports whether the method has a
|
||||
// pointer receiver.
|
||||
// This is used by the recursiveStringer method in print.go.
|
||||
stringers map[*ast.Object]bool
|
||||
stringerPtrs map[*ast.Object]bool
|
||||
|
||||
// Registered checkers to run.
|
||||
checkers map[ast.Node][]func(*File, ast.Node)
|
||||
|
|
|
@ -187,12 +187,14 @@ func checkFmtPrintfCall(f *File, node ast.Node) {
|
|||
|
||||
if d, ok := node.(*ast.FuncDecl); ok && isStringer(f, d) {
|
||||
// Remember we saw this.
|
||||
if f.stringers == nil {
|
||||
f.stringers = make(map[*ast.Object]bool)
|
||||
if f.stringerPtrs == nil {
|
||||
f.stringerPtrs = make(map[*ast.Object]bool)
|
||||
}
|
||||
if l := d.Recv.List; len(l) == 1 {
|
||||
if n := l[0].Names; len(n) == 1 {
|
||||
f.stringers[n[0].Obj] = true
|
||||
typ := f.pkg.types[l[0].Type]
|
||||
_, ptrRecv := typ.Type.(*types.Pointer)
|
||||
f.stringerPtrs[n[0].Obj] = ptrRecv
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -293,6 +295,7 @@ type formatState struct {
|
|||
file *File
|
||||
call *ast.CallExpr
|
||||
argNum int // Which argument we're expecting to format now.
|
||||
hasIndex bool // Whether the argument is indexed.
|
||||
indexPending bool // Whether we have an indexed argument that has not resolved.
|
||||
nbytes int // number of bytes of the format string consumed.
|
||||
}
|
||||
|
@ -317,6 +320,7 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
|
|||
// Hard part: check formats against args.
|
||||
argNum := firstArg
|
||||
maxArgNum := firstArg
|
||||
anyIndex := false
|
||||
for i, w := 0, 0; i < len(format); i += w {
|
||||
w = 1
|
||||
if format[i] != '%' {
|
||||
|
@ -330,6 +334,9 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
|
|||
if !f.okPrintfArg(call, state) { // One error per format is enough.
|
||||
return
|
||||
}
|
||||
if state.hasIndex {
|
||||
anyIndex = true
|
||||
}
|
||||
if len(state.argNums) > 0 {
|
||||
// Continue with the next sequential argument.
|
||||
argNum = state.argNums[len(state.argNums)-1] + 1
|
||||
|
@ -344,6 +351,10 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
|
|||
if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
|
||||
return
|
||||
}
|
||||
// If any formats are indexed, extra arguments are ignored.
|
||||
if anyIndex {
|
||||
return
|
||||
}
|
||||
// There should be no leftover arguments.
|
||||
if maxArgNum != len(call.Args) {
|
||||
expect := maxArgNum - firstArg
|
||||
|
@ -402,6 +413,7 @@ func (s *formatState) parseIndex() bool {
|
|||
arg := int(arg32)
|
||||
arg += s.firstArg - 1 // We want to zero-index the actual arguments.
|
||||
s.argNum = arg
|
||||
s.hasIndex = true
|
||||
s.indexPending = true
|
||||
return true
|
||||
}
|
||||
|
@ -569,6 +581,11 @@ func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
|
|||
return false
|
||||
}
|
||||
for _, flag := range state.flags {
|
||||
// TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11.
|
||||
// See issues 23598 and 23605.
|
||||
if flag == '0' {
|
||||
continue
|
||||
}
|
||||
if !strings.ContainsRune(v.flags, rune(flag)) {
|
||||
f.Badf(call.Pos(), "%s format %s has unrecognized flag %c", state.name, state.format, flag)
|
||||
return false
|
||||
|
@ -623,9 +640,10 @@ func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
|
|||
// recursiveStringer reports whether the provided argument is r or &r for the
|
||||
// fmt.Stringer receiver identifier r.
|
||||
func (f *File) recursiveStringer(e ast.Expr) bool {
|
||||
if len(f.stringers) == 0 {
|
||||
if len(f.stringerPtrs) == 0 {
|
||||
return false
|
||||
}
|
||||
ptr := false
|
||||
var obj *ast.Object
|
||||
switch e := e.(type) {
|
||||
case *ast.Ident:
|
||||
|
@ -633,6 +651,7 @@ func (f *File) recursiveStringer(e ast.Expr) bool {
|
|||
case *ast.UnaryExpr:
|
||||
if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND {
|
||||
obj = id.Obj
|
||||
ptr = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -647,7 +666,16 @@ func (f *File) recursiveStringer(e ast.Expr) bool {
|
|||
// We compare the underlying Object, which checks that the identifier
|
||||
// is the one we declared as the receiver for the String method in
|
||||
// which this printf appears.
|
||||
return f.stringers[obj]
|
||||
ptrRecv, exist := f.stringerPtrs[obj]
|
||||
if !exist {
|
||||
return false
|
||||
}
|
||||
// We also need to check that using &t when we declared String
|
||||
// on (t *T) is ok; in such a case, the address is printed.
|
||||
if ptr && ptrRecv {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isFunctionValue reports whether the expression is a function as opposed to a function call.
|
||||
|
|
79
src/cmd/vet/testdata/print.go
vendored
79
src/cmd/vet/testdata/print.go
vendored
|
@ -130,8 +130,8 @@ func PrintfTests() {
|
|||
fmt.Printf("%U", x) // ERROR "Printf format %U has arg x of wrong type float64"
|
||||
fmt.Printf("%x", nil) // ERROR "Printf format %x has arg nil of wrong type untyped nil"
|
||||
fmt.Printf("%X", 2.3) // ERROR "Printf format %X has arg 2.3 of wrong type float64"
|
||||
fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type testdata.stringer"
|
||||
fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type testdata.stringer"
|
||||
fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type testdata.ptrStringer"
|
||||
fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type testdata.ptrStringer"
|
||||
fmt.Printf("%s", embeddedStringerv) // ERROR "Printf format %s has arg embeddedStringerv of wrong type testdata.embeddedStringer"
|
||||
fmt.Printf("%t", embeddedStringerv) // ERROR "Printf format %t has arg embeddedStringerv of wrong type testdata.embeddedStringer"
|
||||
fmt.Printf("%q", notstringerv) // ERROR "Printf format %q has arg notstringerv of wrong type testdata.notstringer"
|
||||
|
@ -168,7 +168,7 @@ func PrintfTests() {
|
|||
Printf(format, "hi", "there")
|
||||
Printf(format, "hi") // ERROR "Printf format %s reads arg #2, but call has only 1 arg$"
|
||||
Printf("%s %d %.3v %q", "str", 4) // ERROR "Printf format %.3v reads arg #3, but call has only 2 args"
|
||||
f := new(stringer)
|
||||
f := new(ptrStringer)
|
||||
f.Warn(0, "%s", "hello", 3) // ERROR "Warn call has possible formatting directive %s"
|
||||
f.Warnf(0, "%s", "hello", 3) // ERROR "Warnf call needs 1 arg but has 2 args"
|
||||
f.Warnf(0, "%r", "hello") // ERROR "Warnf format %r has unknown verb r"
|
||||
|
@ -270,8 +270,9 @@ func PrintfTests() {
|
|||
Printf("%d %[3]d %d %[-2]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[-2\]"
|
||||
Printf("%d %[3]d %d %[2234234234234]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[2234234234234\]"
|
||||
Printf("%d %[3]d %-10d %[2]d x", 1, 2, 3) // ERROR "Printf format %-10d reads arg #4, but call has only 3 args"
|
||||
Printf("%d %[3]d %d %[2]d x", 1, 2, 3, 4, 5) // ERROR "Printf call needs 4 args but has 5 args"
|
||||
Printf("%[1][3]d x", 1, 2) // ERROR "Printf format %\[1\]\[ has unknown verb \["
|
||||
Printf("%[1]d x", 1, 2) // OK
|
||||
Printf("%d %[3]d %d %[2]d x", 1, 2, 3, 4, 5) // OK
|
||||
|
||||
// wrote Println but meant Fprintln
|
||||
Printf("%p\n", os.Stdout) // OK
|
||||
|
@ -352,25 +353,29 @@ func multi() []interface{} {
|
|||
panic("don't call - testing only")
|
||||
}
|
||||
|
||||
type stringer float64
|
||||
type stringer int
|
||||
|
||||
var stringerv stringer
|
||||
func (stringer) String() string { return "string" }
|
||||
|
||||
func (*stringer) String() string {
|
||||
type ptrStringer float64
|
||||
|
||||
var stringerv ptrStringer
|
||||
|
||||
func (*ptrStringer) String() string {
|
||||
return "string"
|
||||
}
|
||||
|
||||
func (*stringer) Warn(int, ...interface{}) string {
|
||||
func (*ptrStringer) Warn(int, ...interface{}) string {
|
||||
return "warn"
|
||||
}
|
||||
|
||||
func (*stringer) Warnf(int, string, ...interface{}) string {
|
||||
func (*ptrStringer) Warnf(int, string, ...interface{}) string {
|
||||
return "warnf"
|
||||
}
|
||||
|
||||
type embeddedStringer struct {
|
||||
foo string
|
||||
stringer
|
||||
ptrStringer
|
||||
bar int
|
||||
}
|
||||
|
||||
|
@ -440,6 +445,7 @@ type recursivePtrStringer int
|
|||
|
||||
func (p *recursivePtrStringer) String() string {
|
||||
_ = fmt.Sprintf("%v", *p)
|
||||
_ = fmt.Sprint(&p) // ok; prints address
|
||||
return fmt.Sprintln(p) // ERROR "Sprintln arg p causes recursive call to String method"
|
||||
}
|
||||
|
||||
|
@ -478,13 +484,17 @@ type RecursiveStruct2 struct {
|
|||
|
||||
var recursiveStruct1V = &RecursiveStruct1{}
|
||||
|
||||
// Issue 17798: unexported stringer cannot be formatted.
|
||||
type unexportedInterface struct {
|
||||
f interface{}
|
||||
}
|
||||
|
||||
// Issue 17798: unexported ptrStringer cannot be formatted.
|
||||
type unexportedStringer struct {
|
||||
t stringer
|
||||
t ptrStringer
|
||||
}
|
||||
type unexportedStringerOtherFields struct {
|
||||
s string
|
||||
t stringer
|
||||
t ptrStringer
|
||||
S string
|
||||
}
|
||||
|
||||
|
@ -502,7 +512,23 @@ type errorer struct{}
|
|||
|
||||
func (e errorer) Error() string { return "errorer" }
|
||||
|
||||
type unexportedCustomError struct {
|
||||
e errorer
|
||||
}
|
||||
|
||||
type errorInterface interface {
|
||||
error
|
||||
ExtraMethod()
|
||||
}
|
||||
|
||||
type unexportedErrorInterface struct {
|
||||
e errorInterface
|
||||
}
|
||||
|
||||
func UnexportedStringerOrError() {
|
||||
fmt.Printf("%s", unexportedInterface{"foo"}) // ok; prints {foo}
|
||||
fmt.Printf("%s", unexportedInterface{3}) // ok; we can't see the problem
|
||||
|
||||
us := unexportedStringer{}
|
||||
fmt.Printf("%s", us) // ERROR "Printf format %s has arg us of wrong type testdata.unexportedStringer"
|
||||
fmt.Printf("%s", &us) // ERROR "Printf format %s has arg &us of wrong type [*]testdata.unexportedStringer"
|
||||
|
@ -528,8 +554,29 @@ func UnexportedStringerOrError() {
|
|||
fmt.Printf("%s", uef) // ERROR "Printf format %s has arg uef of wrong type testdata.unexportedErrorOtherFields"
|
||||
fmt.Printf("%s", &uef) // ERROR "Printf format %s has arg &uef of wrong type [*]testdata.unexportedErrorOtherFields"
|
||||
|
||||
uce := unexportedCustomError{
|
||||
e: errorer{},
|
||||
}
|
||||
fmt.Printf("%s", uce) // ERROR "Printf format %s has arg uce of wrong type testdata.unexportedCustomError"
|
||||
|
||||
uei := unexportedErrorInterface{}
|
||||
fmt.Printf("%s", uei) // ERROR "Printf format %s has arg uei of wrong type testdata.unexportedErrorInterface"
|
||||
fmt.Println("foo\n", "bar") // not an error
|
||||
fmt.Println("foo\n") // ERROR "Println arg list ends with redundant newline"
|
||||
fmt.Println("foo\\n") // not an error
|
||||
fmt.Println(`foo\n`) // not an error
|
||||
|
||||
fmt.Println("foo\n") // ERROR "Println arg list ends with redundant newline"
|
||||
fmt.Println("foo\\n") // not an error
|
||||
fmt.Println(`foo\n`) // not an error
|
||||
|
||||
intSlice := []int{3, 4}
|
||||
fmt.Printf("%s", intSlice) // ERROR "Printf format %s has arg intSlice of wrong type \[\]int"
|
||||
nonStringerArray := [1]unexportedStringer{{}}
|
||||
fmt.Printf("%s", nonStringerArray) // ERROR "Printf format %s has arg nonStringerArray of wrong type \[1\]testdata.unexportedStringer"
|
||||
fmt.Printf("%s", []stringer{3, 4}) // not an error
|
||||
fmt.Printf("%s", [2]stringer{3, 4}) // not an error
|
||||
}
|
||||
|
||||
// TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11.
|
||||
// See issues 23598 and 23605.
|
||||
func DisableErrorForFlag0() {
|
||||
fmt.Printf("%0t", true)
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp
|
|||
return true // %s matches []byte
|
||||
}
|
||||
// Recur: []int matches %d.
|
||||
return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress)
|
||||
return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)
|
||||
|
||||
case *types.Slice:
|
||||
// Same as array.
|
||||
|
@ -269,7 +269,19 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp
|
|||
}
|
||||
|
||||
func isConvertibleToString(typ types.Type) bool {
|
||||
return types.AssertableTo(errorType, typ) || stringerType != nil && types.AssertableTo(stringerType, typ)
|
||||
if bt, ok := typ.(*types.Basic); ok && bt.Kind() == types.UntypedNil {
|
||||
// We explicitly don't want untyped nil, which is
|
||||
// convertible to both of the interfaces below, as it
|
||||
// would just panic anyway.
|
||||
return false
|
||||
}
|
||||
if types.ConvertibleTo(typ, errorType) {
|
||||
return true // via .Error()
|
||||
}
|
||||
if stringerType != nil && types.ConvertibleTo(typ, stringerType) {
|
||||
return true // via .String()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasBasicType reports whether x's type is a types.Basic with the given kind.
|
||||
|
|
|
@ -379,6 +379,10 @@ type Rows interface {
|
|||
// size as the Columns() are wide.
|
||||
//
|
||||
// Next should return io.EOF when there are no more rows.
|
||||
//
|
||||
// The dest should not be written to outside of Next. Care
|
||||
// should be taken when closing Rows not to modify
|
||||
// a buffer held in dest.
|
||||
Next(dest []Value) error
|
||||
}
|
||||
|
||||
|
|
|
@ -1020,11 +1020,6 @@ func (rc *rowsCursor) touchMem() {
|
|||
}
|
||||
|
||||
func (rc *rowsCursor) Close() error {
|
||||
if !rc.closed {
|
||||
for _, bs := range rc.bytesClone {
|
||||
bs[0] = 255 // first byte corrupted
|
||||
}
|
||||
}
|
||||
rc.touchMem()
|
||||
rc.parentMem.touchMem()
|
||||
rc.closed = true
|
||||
|
|
|
@ -663,43 +663,6 @@ func TestPoolExhaustOnCancel(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestByteOwnership(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
rows, err := db.Query("SELECT|people|name,photo|")
|
||||
if err != nil {
|
||||
t.Fatalf("Query: %v", err)
|
||||
}
|
||||
type row struct {
|
||||
name []byte
|
||||
photo RawBytes
|
||||
}
|
||||
got := []row{}
|
||||
for rows.Next() {
|
||||
var r row
|
||||
err = rows.Scan(&r.name, &r.photo)
|
||||
if err != nil {
|
||||
t.Fatalf("Scan: %v", err)
|
||||
}
|
||||
got = append(got, r)
|
||||
}
|
||||
corruptMemory := []byte("\xffPHOTO")
|
||||
want := []row{
|
||||
{name: []byte("Alice"), photo: corruptMemory},
|
||||
{name: []byte("Bob"), photo: corruptMemory},
|
||||
{name: []byte("Chris"), photo: corruptMemory},
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want)
|
||||
}
|
||||
|
||||
var photo RawBytes
|
||||
err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo)
|
||||
if err == nil {
|
||||
t.Error("want error scanning into RawBytes from QueryRow")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRowsColumns(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
@ -3192,8 +3155,11 @@ func TestIssue18429(t *testing.T) {
|
|||
// reported.
|
||||
rows, _ := tx.QueryContext(ctx, "WAIT|"+qwait+"|SELECT|people|name|")
|
||||
if rows != nil {
|
||||
var name string
|
||||
// Call Next to test Issue 21117 and check for races.
|
||||
for rows.Next() {
|
||||
// Scan the buffer so it is read and checked for races.
|
||||
rows.Scan(&name)
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
|
|
|
@ -301,7 +301,7 @@ var pkgDeps = map[string][]string{
|
|||
"os/user": {"L4", "CGO", "io/ioutil", "os", "syscall"},
|
||||
|
||||
// Internal package used only for testing.
|
||||
"os/signal/internal/pty": {"CGO", "fmt", "os"},
|
||||
"os/signal/internal/pty": {"CGO", "fmt", "os", "syscall"},
|
||||
|
||||
// Basic networking.
|
||||
// Because net must be used by any package that wants to
|
||||
|
|
|
@ -62,8 +62,6 @@ var importablePackages = [...]string{
|
|||
"encoding/pem",
|
||||
"encoding/xml",
|
||||
"errors",
|
||||
"exp/proxy",
|
||||
"exp/terminal",
|
||||
"expvar",
|
||||
"flag",
|
||||
"fmt",
|
||||
|
@ -114,8 +112,6 @@ var importablePackages = [...]string{
|
|||
"net/smtp",
|
||||
"net/textproto",
|
||||
"net/url",
|
||||
"old/regexp",
|
||||
"old/template",
|
||||
"os/exec",
|
||||
"os",
|
||||
"os/signal",
|
||||
|
|
|
@ -20,7 +20,7 @@ func maxListenerBacklog() int {
|
|||
case "darwin":
|
||||
n, err = syscall.SysctlUint32("kern.ipc.somaxconn")
|
||||
case "freebsd":
|
||||
n, err = syscall.SysctlUint32("kern.ipc.acceptqueue")
|
||||
n, err = syscall.SysctlUint32("kern.ipc.soacceptqueue")
|
||||
case "netbsd":
|
||||
// NOTE: NetBSD has no somaxconn-like kernel state so far
|
||||
case "openbsd":
|
||||
|
|
|
@ -88,6 +88,11 @@ func FindProcess(pid int) (*Process, error) {
|
|||
// specified by name, argv and attr. The argv slice will become os.Args in the
|
||||
// new process, so it normally starts with the program name.
|
||||
//
|
||||
// If the calling goroutine has locked the operating system thread
|
||||
// with runtime.LockOSThread and modified any inheritable OS-level
|
||||
// thread state (for example, Linux or Plan 9 name spaces), the new
|
||||
// process will inherit the caller's thread state.
|
||||
//
|
||||
// StartProcess is a low-level interface. The os/exec package provides
|
||||
// higher-level interfaces.
|
||||
//
|
||||
|
|
|
@ -293,6 +293,11 @@ func (c *Cmd) closeDescriptors(closers []io.Closer) {
|
|||
//
|
||||
// If the command starts but does not complete successfully, the error is of
|
||||
// type *ExitError. Other error types may be returned for other situations.
|
||||
//
|
||||
// If the calling goroutine has locked the operating system thread
|
||||
// with runtime.LockOSThread and modified any inheritable OS-level
|
||||
// thread state (for example, Linux or Plan 9 name spaces), the new
|
||||
// process will inherit the caller's thread state.
|
||||
func (c *Cmd) Run() error {
|
||||
if err := c.Start(); err != nil {
|
||||
return err
|
||||
|
|
|
@ -21,21 +21,36 @@ import "C"
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type PtyError struct {
|
||||
FuncName string
|
||||
ErrorString string
|
||||
Errno syscall.Errno
|
||||
}
|
||||
|
||||
func ptyError(name string, err error) *PtyError {
|
||||
return &PtyError{name, err.Error(), err.(syscall.Errno)}
|
||||
}
|
||||
|
||||
func (e *PtyError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.FuncName, e.ErrorString)
|
||||
}
|
||||
|
||||
// Open returns a master pty and the name of the linked slave tty.
|
||||
func Open() (master *os.File, slave string, err error) {
|
||||
m, err := C.posix_openpt(C.O_RDWR)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("posix_openpt: %v", err)
|
||||
return nil, "", ptyError("posix_openpt", err)
|
||||
}
|
||||
if _, err := C.grantpt(m); err != nil {
|
||||
C.close(m)
|
||||
return nil, "", fmt.Errorf("grantpt: %v", err)
|
||||
return nil, "", ptyError("grantpt", err)
|
||||
}
|
||||
if _, err := C.unlockpt(m); err != nil {
|
||||
C.close(m)
|
||||
return nil, "", fmt.Errorf("unlockpt: %v", err)
|
||||
return nil, "", ptyError("unlockpt", err)
|
||||
}
|
||||
slave = C.GoString(C.ptsname(m))
|
||||
return os.NewFile(uintptr(m), "pty-master"), slave, nil
|
||||
|
|
|
@ -72,6 +72,10 @@ func TestTerminalSignal(t *testing.T) {
|
|||
|
||||
master, sname, err := pty.Open()
|
||||
if err != nil {
|
||||
ptyErr := err.(*pty.PtyError)
|
||||
if ptyErr.FuncName == "posix_openpt" && ptyErr.Errno == syscall.EACCES {
|
||||
t.Skip("posix_openpt failed with EACCES, assuming chroot and skipping")
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer master.Close()
|
||||
|
|
|
@ -481,3 +481,24 @@ func TestSigStackSwapping(t *testing.T) {
|
|||
t.Errorf("expected %q got %v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgoTracebackSigpanic(t *testing.T) {
|
||||
// Test unwinding over a sigpanic in C code without a C
|
||||
// symbolizer. See issue #23576.
|
||||
if runtime.GOOS == "windows" {
|
||||
// On Windows if we get an exception in C code, we let
|
||||
// the Windows exception handler unwind it, rather
|
||||
// than injecting a sigpanic.
|
||||
t.Skip("no sigpanic in C on windows")
|
||||
}
|
||||
t.Parallel()
|
||||
got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
|
||||
want := "runtime.sigpanic"
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
|
||||
}
|
||||
nowant := "unexpected return pc"
|
||||
if strings.Contains(got, nowant) {
|
||||
t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ func (c *sigctxt) hi() uint64 { return c.regs().sc_mdhi }
|
|||
func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
|
||||
func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
|
||||
|
||||
func (c *sigctxt) set_r28(x uint64) { c.regs().sc_regs[28] = x }
|
||||
func (c *sigctxt) set_r30(x uint64) { c.regs().sc_regs[30] = x }
|
||||
func (c *sigctxt) set_pc(x uint64) { c.regs().sc_pc = x }
|
||||
func (c *sigctxt) set_sp(x uint64) { c.regs().sc_regs[29] = x }
|
||||
|
|
|
@ -89,6 +89,8 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
|||
}
|
||||
|
||||
// In case we are panicking from external C code
|
||||
sigpanicPC := uint64(funcPC(sigpanic))
|
||||
c.set_r28(sigpanicPC >> 32 << 32) // RSB register
|
||||
c.set_r30(uint64(uintptr(unsafe.Pointer(gp))))
|
||||
c.set_pc(uint64(funcPC(sigpanic)))
|
||||
c.set_pc(sigpanicPC)
|
||||
}
|
||||
|
|
28
src/runtime/testdata/testprogcgo/sigpanic.go
vendored
Normal file
28
src/runtime/testdata/testprogcgo/sigpanic.go
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
// 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 main
|
||||
|
||||
// This program will crash.
|
||||
// We want to test unwinding from sigpanic into C code (without a C symbolizer).
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -O0
|
||||
|
||||
char *pnil;
|
||||
|
||||
static int f1(void) {
|
||||
*pnil = 0;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func init() {
|
||||
register("TracebackSigpanic", TracebackSigpanic)
|
||||
}
|
||||
|
||||
func TracebackSigpanic() {
|
||||
C.f1()
|
||||
}
|
|
@ -43,6 +43,7 @@ var (
|
|||
morestackPC uintptr
|
||||
mstartPC uintptr
|
||||
rt0_goPC uintptr
|
||||
asmcgocallPC uintptr
|
||||
sigpanicPC uintptr
|
||||
runfinqPC uintptr
|
||||
bgsweepPC uintptr
|
||||
|
@ -70,6 +71,7 @@ func tracebackinit() {
|
|||
morestackPC = funcPC(morestack)
|
||||
mstartPC = funcPC(mstart)
|
||||
rt0_goPC = funcPC(rt0_go)
|
||||
asmcgocallPC = funcPC(asmcgocall)
|
||||
sigpanicPC = funcPC(sigpanic)
|
||||
runfinqPC = funcPC(runfinq)
|
||||
bgsweepPC = funcPC(bgsweep)
|
||||
|
@ -251,7 +253,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
|||
}
|
||||
}
|
||||
var flr funcInfo
|
||||
if topofstack(f) {
|
||||
if topofstack(f, gp.m != nil && gp == gp.m.g0) {
|
||||
frame.lr = 0
|
||||
flr = funcInfo{}
|
||||
} else if usesLR && f.entry == jmpdeferPC {
|
||||
|
@ -284,7 +286,15 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
|||
// In that context it is okay to stop early.
|
||||
// But if callback is set, we're doing a garbage collection and must
|
||||
// get everything, so crash loudly.
|
||||
if callback != nil || printing {
|
||||
doPrint := printing
|
||||
if doPrint && gp.m.incgo {
|
||||
// We can inject sigpanic
|
||||
// calls directly into C code,
|
||||
// in which case we'll see a C
|
||||
// return PC. Don't complain.
|
||||
doPrint = false
|
||||
}
|
||||
if callback != nil || doPrint {
|
||||
print("runtime: unexpected return pc for ", funcname(f), " called from ", hex(frame.lr), "\n")
|
||||
tracebackHexdump(gp.stack, &frame, lrPtr)
|
||||
}
|
||||
|
@ -920,14 +930,20 @@ func tracebackHexdump(stk stack, frame *stkframe, bad uintptr) {
|
|||
}
|
||||
|
||||
// Does f mark the top of a goroutine stack?
|
||||
func topofstack(f funcInfo) bool {
|
||||
func topofstack(f funcInfo, g0 bool) bool {
|
||||
pc := f.entry
|
||||
return pc == goexitPC ||
|
||||
pc == mstartPC ||
|
||||
pc == mcallPC ||
|
||||
pc == morestackPC ||
|
||||
pc == rt0_goPC ||
|
||||
externalthreadhandlerp != 0 && pc == externalthreadhandlerp
|
||||
externalthreadhandlerp != 0 && pc == externalthreadhandlerp ||
|
||||
// asmcgocall is TOS on the system stack because it
|
||||
// switches to the system stack, but in this case we
|
||||
// can come back to the regular stack and still want
|
||||
// to be able to unwind through the call that appeared
|
||||
// on the regular stack.
|
||||
(g0 && pc == asmcgocallPC)
|
||||
}
|
||||
|
||||
// isSystemGoroutine reports whether the goroutine g must be omitted in
|
||||
|
|
|
@ -831,7 +831,7 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
|
|||
//sys Fdatasync(fd int) (err error)
|
||||
//sys Flock(fd int, how int) (err error)
|
||||
//sys Fsync(fd int) (err error)
|
||||
//sys Getdents(fd int, buf []byte) (n int, err error) = _SYS_getdents
|
||||
//sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
|
||||
//sysnb Getpgid(pid int) (pgid int, err error)
|
||||
|
||||
func Getpgrp() (pid int) {
|
||||
|
|
|
@ -11,7 +11,6 @@ import "unsafe"
|
|||
|
||||
const (
|
||||
_SYS_dup = SYS_DUP2
|
||||
_SYS_getdents = SYS_GETDENTS64
|
||||
_SYS_setgroups = SYS_SETGROUPS32
|
||||
)
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ package syscall
|
|||
|
||||
const (
|
||||
_SYS_dup = SYS_DUP2
|
||||
_SYS_getdents = SYS_GETDENTS64
|
||||
_SYS_setgroups = SYS_SETGROUPS
|
||||
)
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import "unsafe"
|
|||
|
||||
const (
|
||||
_SYS_dup = SYS_DUP2
|
||||
_SYS_getdents = SYS_GETDENTS64
|
||||
_SYS_setgroups = SYS_SETGROUPS32
|
||||
)
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ package syscall
|
|||
|
||||
const (
|
||||
_SYS_dup = SYS_DUP3
|
||||
_SYS_getdents = SYS_GETDENTS64
|
||||
_SYS_setgroups = SYS_SETGROUPS
|
||||
)
|
||||
|
||||
|
|
|
@ -8,14 +8,7 @@
|
|||
package syscall
|
||||
|
||||
const (
|
||||
_SYS_dup = SYS_DUP2
|
||||
|
||||
// Linux introduced getdents64 syscall for N64 ABI only in 3.10
|
||||
// (May 21 2013, rev dec33abaafc89bcbd78f85fad0513170415a26d5),
|
||||
// to support older kernels, we have to use getdents for mips64.
|
||||
// Also note that struct dirent is different for these two.
|
||||
// Lookup linux_dirent{,64} in kernel source code for details.
|
||||
_SYS_getdents = SYS_GETDENTS
|
||||
_SYS_dup = SYS_DUP2
|
||||
_SYS_setgroups = SYS_SETGROUPS
|
||||
)
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import "unsafe"
|
|||
|
||||
const (
|
||||
_SYS_dup = SYS_DUP2
|
||||
_SYS_getdents = SYS_GETDENTS64
|
||||
_SYS_setgroups = SYS_SETGROUPS
|
||||
)
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ package syscall
|
|||
|
||||
const (
|
||||
_SYS_dup = SYS_DUP2
|
||||
_SYS_getdents = SYS_GETDENTS64
|
||||
_SYS_setgroups = SYS_SETGROUPS
|
||||
)
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import "unsafe"
|
|||
|
||||
const (
|
||||
_SYS_dup = SYS_DUP2
|
||||
_SYS_getdents = SYS_GETDENTS64
|
||||
_SYS_setgroups = SYS_SETGROUPS
|
||||
)
|
||||
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -479,7 +479,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
|
|||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
|
|
|
@ -130,15 +130,12 @@ type Statfs_t struct {
|
|||
Spare [5]int64
|
||||
}
|
||||
|
||||
// Note: on mips64, we're using the getdents syscall,
|
||||
// so the Dirent struct is different.
|
||||
|
||||
type Dirent struct {
|
||||
Ino uint64
|
||||
Off int64
|
||||
Reclen uint16
|
||||
Name [256]int8
|
||||
Type uint8
|
||||
Name [256]int8
|
||||
Pad_cgo_0 [5]byte
|
||||
}
|
||||
|
||||
|
|
|
@ -130,15 +130,12 @@ type Statfs_t struct {
|
|||
Spare [5]int64
|
||||
}
|
||||
|
||||
// Note: on mips64, we're using the getdents syscall,
|
||||
// so the Dirent struct is different.
|
||||
|
||||
type Dirent struct {
|
||||
Ino uint64
|
||||
Off int64
|
||||
Reclen uint16
|
||||
Name [256]int8
|
||||
Type uint8
|
||||
Name [256]int8
|
||||
Pad_cgo_0 [5]byte
|
||||
}
|
||||
|
||||
|
|
|
@ -110,12 +110,6 @@ data, defined in detail in the corresponding sections that follow.
|
|||
T0 is executed; otherwise, dot is set to the successive elements
|
||||
of the array, slice, or map and T1 is executed.
|
||||
|
||||
{{break}}
|
||||
Break out of the surrounding range loop.
|
||||
|
||||
{{continue}}
|
||||
Begin the next iteration of the surrounding range loop.
|
||||
|
||||
{{template "name"}}
|
||||
The template with the specified name is executed with nil data.
|
||||
|
||||
|
|
|
@ -25,12 +25,11 @@ const maxExecDepth = 100000
|
|||
// template so that multiple executions of the same template
|
||||
// can execute in parallel.
|
||||
type state struct {
|
||||
tmpl *Template
|
||||
wr io.Writer
|
||||
node parse.Node // current node, for errors.
|
||||
vars []variable // push-down stack of variable values.
|
||||
depth int // the height of the stack of executing templates.
|
||||
rangeDepth int // nesting level of range loops.
|
||||
tmpl *Template
|
||||
wr io.Writer
|
||||
node parse.Node // current node, for errors
|
||||
vars []variable // push-down stack of variable values.
|
||||
depth int // the height of the stack of executing templates.
|
||||
}
|
||||
|
||||
// variable holds the dynamic value of a variable such as $, $x etc.
|
||||
|
@ -221,17 +220,9 @@ func (t *Template) DefinedTemplates() string {
|
|||
return s
|
||||
}
|
||||
|
||||
type rangeControl int8
|
||||
|
||||
const (
|
||||
rangeNone rangeControl = iota // no action.
|
||||
rangeBreak // break out of range.
|
||||
rangeContinue // continues next range iteration.
|
||||
)
|
||||
|
||||
// Walk functions step through the major pieces of the template structure,
|
||||
// generating output as they go.
|
||||
func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl {
|
||||
func (s *state) walk(dot reflect.Value, node parse.Node) {
|
||||
s.at(node)
|
||||
switch node := node.(type) {
|
||||
case *parse.ActionNode:
|
||||
|
@ -242,15 +233,13 @@ func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl {
|
|||
s.printValue(node, val)
|
||||
}
|
||||
case *parse.IfNode:
|
||||
return s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList)
|
||||
s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList)
|
||||
case *parse.ListNode:
|
||||
for _, node := range node.Nodes {
|
||||
if c := s.walk(dot, node); c != rangeNone {
|
||||
return c
|
||||
}
|
||||
s.walk(dot, node)
|
||||
}
|
||||
case *parse.RangeNode:
|
||||
return s.walkRange(dot, node)
|
||||
s.walkRange(dot, node)
|
||||
case *parse.TemplateNode:
|
||||
s.walkTemplate(dot, node)
|
||||
case *parse.TextNode:
|
||||
|
@ -258,26 +247,15 @@ func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl {
|
|||
s.writeError(err)
|
||||
}
|
||||
case *parse.WithNode:
|
||||
return s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList)
|
||||
case *parse.BreakNode:
|
||||
if s.rangeDepth == 0 {
|
||||
s.errorf("invalid break outside of range")
|
||||
}
|
||||
return rangeBreak
|
||||
case *parse.ContinueNode:
|
||||
if s.rangeDepth == 0 {
|
||||
s.errorf("invalid continue outside of range")
|
||||
}
|
||||
return rangeContinue
|
||||
s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList)
|
||||
default:
|
||||
s.errorf("unknown node: %s", node)
|
||||
}
|
||||
return rangeNone
|
||||
}
|
||||
|
||||
// walkIfOrWith walks an 'if' or 'with' node. The two control structures
|
||||
// are identical in behavior except that 'with' sets dot.
|
||||
func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) rangeControl {
|
||||
func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) {
|
||||
defer s.pop(s.mark())
|
||||
val := s.evalPipeline(dot, pipe)
|
||||
truth, ok := isTrue(val)
|
||||
|
@ -286,14 +264,13 @@ func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.
|
|||
}
|
||||
if truth {
|
||||
if typ == parse.NodeWith {
|
||||
return s.walk(val, list)
|
||||
s.walk(val, list)
|
||||
} else {
|
||||
return s.walk(dot, list)
|
||||
s.walk(dot, list)
|
||||
}
|
||||
} else if elseList != nil {
|
||||
return s.walk(dot, elseList)
|
||||
s.walk(dot, elseList)
|
||||
}
|
||||
return rangeNone
|
||||
}
|
||||
|
||||
// IsTrue reports whether the value is 'true', in the sense of not the zero of its type,
|
||||
|
@ -331,14 +308,13 @@ func isTrue(val reflect.Value) (truth, ok bool) {
|
|||
return truth, true
|
||||
}
|
||||
|
||||
func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl {
|
||||
func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
|
||||
s.at(r)
|
||||
defer s.pop(s.mark())
|
||||
val, _ := indirect(s.evalPipeline(dot, r.Pipe))
|
||||
// mark top of stack before any variables in the body are pushed.
|
||||
mark := s.mark()
|
||||
s.rangeDepth++
|
||||
oneIteration := func(index, elem reflect.Value) rangeControl {
|
||||
oneIteration := func(index, elem reflect.Value) {
|
||||
// Set top var (lexically the second if there are two) to the element.
|
||||
if len(r.Pipe.Decl) > 0 {
|
||||
s.setVar(1, elem)
|
||||
|
@ -347,9 +323,8 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl {
|
|||
if len(r.Pipe.Decl) > 1 {
|
||||
s.setVar(2, index)
|
||||
}
|
||||
ctrl := s.walk(elem, r.List)
|
||||
s.walk(elem, r.List)
|
||||
s.pop(mark)
|
||||
return ctrl
|
||||
}
|
||||
switch val.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
|
@ -357,23 +332,17 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl {
|
|||
break
|
||||
}
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
if ctrl := oneIteration(reflect.ValueOf(i), val.Index(i)); ctrl == rangeBreak {
|
||||
break
|
||||
}
|
||||
oneIteration(reflect.ValueOf(i), val.Index(i))
|
||||
}
|
||||
s.rangeDepth--
|
||||
return rangeNone
|
||||
return
|
||||
case reflect.Map:
|
||||
if val.Len() == 0 {
|
||||
break
|
||||
}
|
||||
for _, key := range sortKeys(val.MapKeys()) {
|
||||
if ctrl := oneIteration(key, val.MapIndex(key)); ctrl == rangeBreak {
|
||||
break
|
||||
}
|
||||
oneIteration(key, val.MapIndex(key))
|
||||
}
|
||||
s.rangeDepth--
|
||||
return rangeNone
|
||||
return
|
||||
case reflect.Chan:
|
||||
if val.IsNil() {
|
||||
break
|
||||
|
@ -384,25 +353,20 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl {
|
|||
if !ok {
|
||||
break
|
||||
}
|
||||
if ctrl := oneIteration(reflect.ValueOf(i), elem); ctrl == rangeBreak {
|
||||
break
|
||||
}
|
||||
oneIteration(reflect.ValueOf(i), elem)
|
||||
}
|
||||
if i == 0 {
|
||||
break
|
||||
}
|
||||
s.rangeDepth--
|
||||
return rangeNone
|
||||
return
|
||||
case reflect.Invalid:
|
||||
break // An invalid value is likely a nil map, etc. and acts like an empty map.
|
||||
default:
|
||||
s.errorf("range can't iterate over %v", val)
|
||||
}
|
||||
s.rangeDepth--
|
||||
if r.ElseList != nil {
|
||||
return s.walk(dot, r.ElseList)
|
||||
s.walk(dot, r.ElseList)
|
||||
}
|
||||
return rangeNone
|
||||
}
|
||||
|
||||
func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
|
||||
|
|
|
@ -513,10 +513,6 @@ var execTests = []execTest{
|
|||
{"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true},
|
||||
{"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true},
|
||||
{"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true},
|
||||
{"range quick break", `{{range .SI}}{{break}}{{.}}{{end}}`, "", tVal, true},
|
||||
{"range break after two", `{{range $i, $x := .SI}}{{if ge $i 2}}{{break}}{{end}}{{.}}{{end}}`, "34", tVal, true},
|
||||
{"range continue", `{{range .SI}}{{continue}}{{.}}{{end}}`, "", tVal, true},
|
||||
{"range continue condition", `{{range .SI}}{{if eq . 3 }}{{continue}}{{end}}{{.}}{{end}}`, "45", tVal, true},
|
||||
|
||||
// Cute examples.
|
||||
{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
|
||||
|
|
|
@ -60,8 +60,6 @@ const (
|
|||
// Keywords appear after all the rest.
|
||||
itemKeyword // used only to delimit the keywords
|
||||
itemBlock // block keyword
|
||||
itemBreak // break keyword
|
||||
itemContinue // continue keyword
|
||||
itemDot // the cursor, spelled '.'
|
||||
itemDefine // define keyword
|
||||
itemElse // else keyword
|
||||
|
@ -76,8 +74,6 @@ const (
|
|||
var key = map[string]itemType{
|
||||
".": itemDot,
|
||||
"block": itemBlock,
|
||||
"break": itemBreak,
|
||||
"continue": itemContinue,
|
||||
"define": itemDefine,
|
||||
"else": itemElse,
|
||||
"end": itemEnd,
|
||||
|
|
|
@ -192,7 +192,7 @@ var lexTests = []lexTest{
|
|||
tRight,
|
||||
tEOF,
|
||||
}},
|
||||
{"keywords", "{{range if else end with break continue}}", []item{
|
||||
{"keywords", "{{range if else end with}}", []item{
|
||||
tLeft,
|
||||
mkItem(itemRange, "range"),
|
||||
tSpace,
|
||||
|
@ -203,10 +203,6 @@ var lexTests = []lexTest{
|
|||
mkItem(itemEnd, "end"),
|
||||
tSpace,
|
||||
mkItem(itemWith, "with"),
|
||||
tSpace,
|
||||
mkItem(itemBreak, "break"),
|
||||
tSpace,
|
||||
mkItem(itemContinue, "continue"),
|
||||
tRight,
|
||||
tEOF,
|
||||
}},
|
||||
|
|
|
@ -69,8 +69,6 @@ const (
|
|||
NodeTemplate // A template invocation action.
|
||||
NodeVariable // A $ variable.
|
||||
NodeWith // A with action.
|
||||
NodeBreak // A break action.
|
||||
NodeContinue // A continue action.
|
||||
)
|
||||
|
||||
// Nodes.
|
||||
|
@ -798,68 +796,6 @@ func (r *RangeNode) Copy() Node {
|
|||
return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
|
||||
}
|
||||
|
||||
// BreakNode represents a {{break}} action.
|
||||
type BreakNode struct {
|
||||
NodeType
|
||||
Pos
|
||||
tr *Tree
|
||||
}
|
||||
|
||||
func (t *Tree) newBreak(pos Pos) *BreakNode {
|
||||
return &BreakNode{NodeType: NodeBreak, Pos: pos, tr: t}
|
||||
}
|
||||
|
||||
func (b *BreakNode) Type() NodeType {
|
||||
return b.NodeType
|
||||
}
|
||||
|
||||
func (b *BreakNode) String() string {
|
||||
return "{{break}}"
|
||||
}
|
||||
|
||||
func (b *BreakNode) Copy() Node {
|
||||
return b.tr.newBreak(b.Pos)
|
||||
}
|
||||
|
||||
func (b *BreakNode) Position() Pos {
|
||||
return b.Pos
|
||||
}
|
||||
|
||||
func (b *BreakNode) tree() *Tree {
|
||||
return b.tr
|
||||
}
|
||||
|
||||
// ContinueNode represents a {{continue}} action.
|
||||
type ContinueNode struct {
|
||||
NodeType
|
||||
Pos
|
||||
tr *Tree
|
||||
}
|
||||
|
||||
func (t *Tree) newContinue(pos Pos) *ContinueNode {
|
||||
return &ContinueNode{NodeType: NodeContinue, Pos: pos, tr: t}
|
||||
}
|
||||
|
||||
func (c *ContinueNode) Type() NodeType {
|
||||
return c.NodeType
|
||||
}
|
||||
|
||||
func (c *ContinueNode) String() string {
|
||||
return "{{continue}}"
|
||||
}
|
||||
|
||||
func (c *ContinueNode) Copy() Node {
|
||||
return c.tr.newContinue(c.Pos)
|
||||
}
|
||||
|
||||
func (c *ContinueNode) Position() Pos {
|
||||
return c.Pos
|
||||
}
|
||||
|
||||
func (c *ContinueNode) tree() *Tree {
|
||||
return c.tr
|
||||
}
|
||||
|
||||
// WithNode represents a {{with}} action and its commands.
|
||||
type WithNode struct {
|
||||
BranchNode
|
||||
|
|
|
@ -23,13 +23,12 @@ type Tree struct {
|
|||
Root *ListNode // top-level root of the tree.
|
||||
text string // text parsed to create the template (or its parent)
|
||||
// Parsing only; cleared after parse.
|
||||
funcs []map[string]interface{}
|
||||
lex *lexer
|
||||
token [3]item // three-token lookahead for parser.
|
||||
peekCount int
|
||||
vars []string // variables defined at the moment.
|
||||
treeSet map[string]*Tree
|
||||
rangeDepth int // nesting level of range loops.
|
||||
funcs []map[string]interface{}
|
||||
lex *lexer
|
||||
token [3]item // three-token lookahead for parser.
|
||||
peekCount int
|
||||
vars []string // variables defined at the moment.
|
||||
treeSet map[string]*Tree
|
||||
}
|
||||
|
||||
// Copy returns a copy of the Tree. Any parsing state is discarded.
|
||||
|
@ -220,7 +219,6 @@ func (t *Tree) stopParse() {
|
|||
t.vars = nil
|
||||
t.funcs = nil
|
||||
t.treeSet = nil
|
||||
t.rangeDepth = 0
|
||||
}
|
||||
|
||||
// Parse parses the template definition string to construct a representation of
|
||||
|
@ -375,10 +373,6 @@ func (t *Tree) action() (n Node) {
|
|||
return t.templateControl()
|
||||
case itemWith:
|
||||
return t.withControl()
|
||||
case itemBreak:
|
||||
return t.breakControl()
|
||||
case itemContinue:
|
||||
return t.continueControl()
|
||||
}
|
||||
t.backup()
|
||||
token := t.peek()
|
||||
|
@ -459,13 +453,7 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int
|
|||
defer t.popVars(len(t.vars))
|
||||
pipe = t.pipeline(context)
|
||||
var next Node
|
||||
if context == "range" {
|
||||
t.rangeDepth++
|
||||
}
|
||||
list, next = t.itemList()
|
||||
if context == "range" {
|
||||
t.rangeDepth--
|
||||
}
|
||||
switch next.Type() {
|
||||
case nodeEnd: //done
|
||||
case nodeElse:
|
||||
|
@ -510,26 +498,6 @@ func (t *Tree) rangeControl() Node {
|
|||
return t.newRange(t.parseControl(false, "range"))
|
||||
}
|
||||
|
||||
// Break:
|
||||
// {{break}}
|
||||
// Break keyword is past.
|
||||
func (t *Tree) breakControl() Node {
|
||||
if t.rangeDepth == 0 {
|
||||
t.errorf("unexpected break outside of range")
|
||||
}
|
||||
return t.newBreak(t.expect(itemRightDelim, "break").pos)
|
||||
}
|
||||
|
||||
// Continue:
|
||||
// {{continue}}
|
||||
// Continue keyword is past.
|
||||
func (t *Tree) continueControl() Node {
|
||||
if t.rangeDepth == 0 {
|
||||
t.errorf("unexpected continue outside of range")
|
||||
}
|
||||
return t.newContinue(t.expect(itemRightDelim, "continue").pos)
|
||||
}
|
||||
|
||||
// With:
|
||||
// {{with pipeline}} itemList {{end}}
|
||||
// {{with pipeline}} itemList {{else}} itemList {{end}}
|
||||
|
|
|
@ -218,12 +218,6 @@ var parseTests = []parseTest{
|
|||
`{{range $x := .SI}}{{.}}{{end}}`},
|
||||
{"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError,
|
||||
`{{range $x, $y := .SI}}{{.}}{{end}}`},
|
||||
{"range []int with break", "{{range .SI}}{{break}}{{.}}{{end}}", noError,
|
||||
`{{range .SI}}{{break}}{{.}}{{end}}`},
|
||||
{"range []int with break in else", "{{range .SI}}{{range .SI}}{{.}}{{else}}{{break}}{{end}}{{end}}", noError,
|
||||
`{{range .SI}}{{range .SI}}{{.}}{{else}}{{break}}{{end}}{{end}}`},
|
||||
{"range []int with continue", "{{range .SI}}{{continue}}{{.}}{{end}}", noError,
|
||||
`{{range .SI}}{{continue}}{{.}}{{end}}`},
|
||||
{"constants", "{{range .SI 1 -3.2i true false 'a' nil}}{{end}}", noError,
|
||||
`{{range .SI 1 -3.2i true false 'a' nil}}{{end}}`},
|
||||
{"template", "{{template `x`}}", noError,
|
||||
|
@ -294,12 +288,6 @@ var parseTests = []parseTest{
|
|||
{"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""},
|
||||
// Missing pipeline in block
|
||||
{"block definition", `{{block "foo"}}hello{{end}}`, hasError, ""},
|
||||
// Invalid range control
|
||||
{"break outside of range", `{{break}}`, hasError, ""},
|
||||
{"break in range else, outside of range", `{{range .}}{{.}}{{else}}{{break}}{{end}}`, hasError, ""},
|
||||
{"continue outside of range", `{{continue}}`, hasError, ""},
|
||||
{"continue in range else, outside of range", `{{range .}}{{.}}{{else}}{{continue}}{{end}}`, hasError, ""},
|
||||
{"additional break data", `{{range .}}{{break label}}{{end}}`, hasError, ""},
|
||||
}
|
||||
|
||||
var builtins = map[string]interface{}{
|
||||
|
|
35
test/fixedbugs/issue23545.go
Normal file
35
test/fixedbugs/issue23545.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
// run
|
||||
|
||||
// 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.
|
||||
|
||||
// +build gccgo
|
||||
|
||||
// Issue 23545: gccgo didn't lower array comparison to
|
||||
// proper equality function in some case.
|
||||
// TODO: build only on gccgo for now, as it hits issue
|
||||
// #23546.
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
if a := Get(); a != dummyID(1234) {
|
||||
panic("FAIL")
|
||||
}
|
||||
}
|
||||
|
||||
func dummyID(x int) [Size]interface{} {
|
||||
var out [Size]interface{}
|
||||
out[0] = x
|
||||
return out
|
||||
}
|
||||
|
||||
const Size = 32
|
||||
|
||||
type OutputID [Size]interface{}
|
||||
|
||||
//go:noinline
|
||||
func Get() OutputID {
|
||||
return dummyID(1234)
|
||||
}
|
42
test/fixedbugs/issue23719.go
Normal file
42
test/fixedbugs/issue23719.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
func main() {
|
||||
v1 := [2]int32{-1, 88}
|
||||
v2 := [2]int32{-1, 99}
|
||||
if v1 == v2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
|
||||
w1 := [2]int16{-1, 88}
|
||||
w2 := [2]int16{-1, 99}
|
||||
if w1 == w2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
x1 := [4]int16{-1, 88, 88, 88}
|
||||
x2 := [4]int16{-1, 99, 99, 99}
|
||||
if x1 == x2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
|
||||
a1 := [2]int8{-1, 88}
|
||||
a2 := [2]int8{-1, 99}
|
||||
if a1 == a2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
b1 := [4]int8{-1, 88, 88, 88}
|
||||
b2 := [4]int8{-1, 99, 99, 99}
|
||||
if b1 == b2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
c1 := [8]int8{-1, 88, 88, 88, 88, 88, 88, 88}
|
||||
c2 := [8]int8{-1, 99, 99, 99, 99, 99, 99, 99}
|
||||
if c1 == c2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue