diff options
author | Russ Cox <rsc@golang.org> | 2018-02-07 09:33:20 -0500 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2018-02-07 09:35:39 -0500 |
commit | 924ef1c8eaf1830ac6880a603d3af0cb6c02d853 (patch) | |
tree | 5e7827145e2d2c6e5024361921a76ccc0b1c293b | |
parent | 5348aed83e39bd1d450d92d7f627e994c2db6ebf (diff) | |
parent | b2d3d6e676450cc1a5d5a611d3711dce2800bc0d (diff) | |
download | go-924ef1c8eaf1830ac6880a603d3af0cb6c02d853.tar.gz go-924ef1c8eaf1830ac6880a603d3af0cb6c02d853.zip |
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
82 files changed, 644 insertions, 627 deletions
diff --git a/api/go1.10.txt b/api/go1.10.txt index f17e54343f..250c10f6ab 100644 --- a/api/go1.10.txt +++ b/api/go1.10.txt @@ -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 diff --git a/doc/conduct.html b/doc/conduct.html index c40b0074f2..bf52ef9fd5 100644 --- a/doc/conduct.html +++ b/doc/conduct.html @@ -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> diff --git a/doc/contribute.html b/doc/contribute.html index adaf983cee..e5312becbb 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -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 diff --git a/doc/diagnostics.html b/doc/diagnostics.html index decd864f36..0ed0e81b92 100644 --- a/doc/diagnostics.html +++ b/doc/diagnostics.html @@ -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> diff --git a/doc/editors.html b/doc/editors.html index 4a8c7eab6b..617a100130 100644 --- a/doc/editors.html +++ b/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> diff --git a/doc/editors/go-plus.png b/doc/editors/go-plus.png Binary files differdeleted file mode 100644 index c09c7fe675..0000000000 --- a/doc/editors/go-plus.png +++ /dev/null diff --git a/doc/editors/goland.png b/doc/editors/goland.png Binary files differdeleted file mode 100644 index 842f089e4a..0000000000 --- a/doc/editors/goland.png +++ /dev/null diff --git a/doc/editors/vimgo.png b/doc/editors/vimgo.png Binary files differdeleted file mode 100644 index cf317eff32..0000000000 --- a/doc/editors/vimgo.png +++ /dev/null diff --git a/doc/editors/vscodego.png b/doc/editors/vscodego.png Binary files differdeleted file mode 100644 index 4e6c7b8047..0000000000 --- a/doc/editors/vscodego.png +++ /dev/null diff --git a/doc/go1.10.html b/doc/go1.10.html index fba4dcf190..5885176f46 100644 --- a/doc/go1.10.html +++ b/doc/go1.10.html @@ -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> diff --git a/doc/go_spec.html b/doc/go_spec.html index 33b66cb905..9a166ccdf4 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -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> diff --git a/doc/install-source.html b/doc/install-source.html index 8813455cbc..4ed9487504 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -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> diff --git a/misc/cgo/test/issue19832.go b/misc/cgo/test/issue19832.go deleted file mode 100644 index 44587770af..0000000000 --- a/misc/cgo/test/issue19832.go +++ /dev/null @@ -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) -} diff --git a/misc/cgo/test/issue4029.c b/misc/cgo/test/issue4029.c index eab3683450..7205c5a5a2 100644 --- a/misc/cgo/test/issue4029.c +++ b/misc/cgo/test/issue4029.c @@ -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(); diff --git a/misc/cgo/test/issue4029.go b/misc/cgo/test/issue4029.go index 5789b99ef6..8e468d367d 100644 --- a/misc/cgo/test/issue4029.go +++ b/misc/cgo/test/issue4029.go @@ -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 } diff --git a/src/bootstrap.bash b/src/bootstrap.bash index 7b4f57461f..32b736ad78 100755 --- a/src/bootstrap.bash +++ b/src/bootstrap.bash @@ -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. diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go index 2fd21b58b8..63664d663c 100644 --- a/src/cmd/asm/internal/arch/arm64.go +++ b/src/cmd/asm/internal/arch/arm64.go @@ -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 { diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index ab6ad5bcb7..cb563bb996 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -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 diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index 97af09c4dd..e4fad9c741 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -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 diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 4f16fe0e31..2ebe906699 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -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 diff --git a/src/cmd/compile/internal/gc/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go index 8eb3d07f2c..50857e6533 100644 --- a/src/cmd/compile/internal/gc/asm_test.go +++ b/src/cmd/compile/internal/gc/asm_test.go @@ -1004,6 +1004,20 @@ var linuxAMD64Tests = []*asmTest{ }, { 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 { return a == b }`, diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 2f96b46f2b..c8296971cd 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -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, diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 34c73acce0..f48513dc73 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -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) diff --git a/src/cmd/fix/typecheck.go b/src/cmd/fix/typecheck.go index c5900d8dcd..eafb626c74 100644 --- a/src/cmd/fix/typecheck.go +++ b/src/cmd/fix/typecheck.go @@ -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 diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 7eaaf48759..92600b6238 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -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") + } +} diff --git a/src/cmd/go/internal/cache/default.go b/src/cmd/go/internal/cache/default.go index 8285f787d4..9728376225 100644 --- a/src/cmd/go/internal/cache/default.go +++ b/src/cmd/go/internal/cache/default.go @@ -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 } diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index beccbb5689..eaff7177b6 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -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 } diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 7f7ce63eda..a99c6a5ec2 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -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) } diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index fdf1fb565d..ca81238c93 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -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) diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go index 793fd961d1..b95664830f 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -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 diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go index 32af2e9b20..abce5b5c70 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go @@ -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() diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go index 807e800959..7265aa6f57 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -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) diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go index 456fbcc044..04c59551b2 100644 --- a/src/cmd/vet/print.go +++ b/src/cmd/vet/print.go @@ -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. diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go index 55ab84fae7..6508c8e615 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/print.go @@ -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) } diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go index 799dc655e6..1f30b4b42b 100644 --- a/src/cmd/vet/types.go +++ b/src/cmd/vet/types.go @@ -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. diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go index 19a3a4f7c9..1e54b4cf2c 100644 --- a/src/database/sql/driver/driver.go +++ b/src/database/sql/driver/driver.go @@ -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 } diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go index e795412de0..abb8d40fc0 100644 --- a/src/database/sql/fakedb_test.go +++ b/src/database/sql/fakedb_test.go @@ -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 diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index 8137eff82b..ae6bf7102e 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -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() } diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index d21eacc6fb..07a9cd3c82 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -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 diff --git a/src/go/internal/gccgoimporter/gccgoinstallation_test.go b/src/go/internal/gccgoimporter/gccgoinstallation_test.go index e601411237..da4931ef1e 100644 --- a/src/go/internal/gccgoimporter/gccgoinstallation_test.go +++ b/src/go/internal/gccgoimporter/gccgoinstallation_test.go @@ -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", diff --git a/src/net/sock_bsd.go b/src/net/sock_bsd.go index dfb0920550..516e557cfd 100644 --- a/src/net/sock_bsd.go +++ b/src/net/sock_bsd.go @@ -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": diff --git a/src/os/exec.go b/src/os/exec.go index b3f60b62d0..a7f8710b95 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -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. // diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go index 8a49fe3b58..5ef9540141 100644 --- a/src/os/exec/exec.go +++ b/src/os/exec/exec.go @@ -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 diff --git a/src/os/signal/internal/pty/pty.go b/src/os/signal/internal/pty/pty.go index fe293a0126..c4c1567fce 100644 --- a/src/os/signal/internal/pty/pty.go +++ b/src/os/signal/internal/pty/pty.go @@ -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 diff --git a/src/os/signal/signal_cgo_test.go b/src/os/signal/signal_cgo_test.go index 27707fadce..84a2a08ce9 100644 --- a/src/os/signal/signal_cgo_test.go +++ b/src/os/signal/signal_cgo_test.go @@ -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() diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index 8993a75ad3..3b9fedc7a4 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -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) + } +} diff --git a/src/runtime/signal_linux_mips64x.go b/src/runtime/signal_linux_mips64x.go index 9e0cf42c70..b608197d60 100644 --- a/src/runtime/signal_linux_mips64x.go +++ b/src/runtime/signal_linux_mips64x.go @@ -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 } diff --git a/src/runtime/signal_mips64x.go b/src/runtime/signal_mips64x.go index 9546a5af99..35b356c2fb 100644 --- a/src/runtime/signal_mips64x.go +++ b/src/runtime/signal_mips64x.go @@ -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) } diff --git a/src/runtime/testdata/testprogcgo/sigpanic.go b/src/runtime/testdata/testprogcgo/sigpanic.go new file mode 100644 index 0000000000..cb46030980 --- /dev/null +++ b/src/runtime/testdata/testprogcgo/sigpanic.go @@ -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() +} diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 62622df2e7..747176c278 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -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 diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index 3fb9b1aa3f..d2cb7c1afe 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -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) { diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go index 2c5d9a3eee..13b9e2ece5 100644 --- a/src/syscall/syscall_linux_386.go +++ b/src/syscall/syscall_linux_386.go @@ -11,7 +11,6 @@ import "unsafe" const ( _SYS_dup = SYS_DUP2 - _SYS_getdents = SYS_GETDENTS64 _SYS_setgroups = SYS_SETGROUPS32 ) diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go index eaba868f89..4b4aa6d414 100644 --- a/src/syscall/syscall_linux_amd64.go +++ b/src/syscall/syscall_linux_amd64.go @@ -6,7 +6,6 @@ package syscall const ( _SYS_dup = SYS_DUP2 - _SYS_getdents = SYS_GETDENTS64 _SYS_setgroups = SYS_SETGROUPS ) diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go index 5c652b2e5b..5ccab9bb74 100644 --- a/src/syscall/syscall_linux_arm.go +++ b/src/syscall/syscall_linux_arm.go @@ -8,7 +8,6 @@ import "unsafe" const ( _SYS_dup = SYS_DUP2 - _SYS_getdents = SYS_GETDENTS64 _SYS_setgroups = SYS_SETGROUPS32 ) diff --git a/src/syscall/syscall_linux_arm64.go b/src/syscall/syscall_linux_arm64.go index 12b9ebcb43..27c351d7bd 100644 --- a/src/syscall/syscall_linux_arm64.go +++ b/src/syscall/syscall_linux_arm64.go @@ -6,7 +6,6 @@ package syscall const ( _SYS_dup = SYS_DUP3 - _SYS_getdents = SYS_GETDENTS64 _SYS_setgroups = SYS_SETGROUPS ) diff --git a/src/syscall/syscall_linux_mips64x.go b/src/syscall/syscall_linux_mips64x.go index e4bc77530c..d9eba62b06 100644 --- a/src/syscall/syscall_linux_mips64x.go +++ b/src/syscall/syscall_linux_mips64x.go @@ -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 ) diff --git a/src/syscall/syscall_linux_mipsx.go b/src/syscall/syscall_linux_mipsx.go index 1da265d3c4..92785e1596 100644 --- a/src/syscall/syscall_linux_mipsx.go +++ b/src/syscall/syscall_linux_mipsx.go @@ -11,7 +11,6 @@ import "unsafe" const ( _SYS_dup = SYS_DUP2 - _SYS_getdents = SYS_GETDENTS64 _SYS_setgroups = SYS_SETGROUPS ) diff --git a/src/syscall/syscall_linux_ppc64x.go b/src/syscall/syscall_linux_ppc64x.go index 55ade887ec..f743b77163 100644 --- a/src/syscall/syscall_linux_ppc64x.go +++ b/src/syscall/syscall_linux_ppc64x.go @@ -9,7 +9,6 @@ package syscall const ( _SYS_dup = SYS_DUP2 - _SYS_getdents = SYS_GETDENTS64 _SYS_setgroups = SYS_SETGROUPS ) diff --git a/src/syscall/syscall_linux_s390x.go b/src/syscall/syscall_linux_s390x.go index 8f3bbfc6f7..6bd9744bdf 100644 --- a/src/syscall/syscall_linux_s390x.go +++ b/src/syscall/syscall_linux_s390x.go @@ -8,7 +8,6 @@ import "unsafe" const ( _SYS_dup = SYS_DUP2 - _SYS_getdents = SYS_GETDENTS64 _SYS_setgroups = SYS_SETGROUPS ) diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go index 8955fca336..86f8ec15fa 100644 --- a/src/syscall/zsyscall_linux_386.go +++ b/src/syscall/zsyscall_linux_386.go @@ -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) diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go index 34cbed812c..6545d1a159 100644 --- a/src/syscall/zsyscall_linux_amd64.go +++ b/src/syscall/zsyscall_linux_amd64.go @@ -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) diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go index c9fa1c86e2..0f0464bf1c 100644 --- a/src/syscall/zsyscall_linux_arm.go +++ b/src/syscall/zsyscall_linux_arm.go @@ -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) diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go index a694b83b0b..27470ac0c9 100644 --- a/src/syscall/zsyscall_linux_arm64.go +++ b/src/syscall/zsyscall_linux_arm64.go @@ -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) diff --git a/src/syscall/zsyscall_linux_mips.go b/src/syscall/zsyscall_linux_mips.go index 5aa984d780..6b26f7bb92 100644 --- a/src/syscall/zsyscall_linux_mips.go +++ b/src/syscall/zsyscall_linux_mips.go @@ -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) diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go index 110b35870a..00a8f7f0c0 100644 --- a/src/syscall/zsyscall_linux_mips64.go +++ b/src/syscall/zsyscall_linux_mips64.go @@ -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) diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go index 23597f8388..97a68ff9e8 100644 --- a/src/syscall/zsyscall_linux_mips64le.go +++ b/src/syscall/zsyscall_linux_mips64le.go @@ -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) diff --git a/src/syscall/zsyscall_linux_mipsle.go b/src/syscall/zsyscall_linux_mipsle.go index 07825a3b80..face54ba28 100644 --- a/src/syscall/zsyscall_linux_mipsle.go +++ b/src/syscall/zsyscall_linux_mipsle.go @@ -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) diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go index 56fb3b8d93..7df49c728a 100644 --- a/src/syscall/zsyscall_linux_ppc64.go +++ b/src/syscall/zsyscall_linux_ppc64.go @@ -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) diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go index d08279f4fb..f073f7dbd1 100644 --- a/src/syscall/zsyscall_linux_ppc64le.go +++ b/src/syscall/zsyscall_linux_ppc64le.go @@ -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) diff --git a/src/syscall/zsyscall_linux_s390x.go b/src/syscall/zsyscall_linux_s390x.go index e8f1a70b43..689f2f472c 100644 --- a/src/syscall/zsyscall_linux_s390x.go +++ b/src/syscall/zsyscall_linux_s390x.go @@ -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) diff --git a/src/syscall/ztypes_linux_mips64.go b/src/syscall/ztypes_linux_mips64.go index 925afb9d1c..8c5a0d1d76 100644 --- a/src/syscall/ztypes_linux_mips64.go +++ b/src/syscall/ztypes_linux_mips64.go @@ -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 } diff --git a/src/syscall/ztypes_linux_mips64le.go b/src/syscall/ztypes_linux_mips64le.go index 925afb9d1c..8c5a0d1d76 100644 --- a/src/syscall/ztypes_linux_mips64le.go +++ b/src/syscall/ztypes_linux_mips64le.go @@ -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 } diff --git a/src/text/template/doc.go b/src/text/template/doc.go index f7609293ce..d174ebd9cf 100644 --- a/src/text/template/doc.go +++ b/src/text/template/doc.go @@ -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. diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 87cf1e9b1c..83c38cdf13 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -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) { diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index 79b504f8a4..d0cda6bd62 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -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}, diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go index da766cc7c3..e112cb7714 100644 --- a/src/text/template/parse/lex.go +++ b/src/text/template/parse/lex.go @@ -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, diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go index ca7c3f64bc..cb01cd98b6 100644 --- a/src/text/template/parse/lex_test.go +++ b/src/text/template/parse/lex_test.go @@ -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, }}, diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go index 7e16349b31..55ff46c17a 100644 --- a/src/text/template/parse/node.go +++ b/src/text/template/parse/node.go @@ -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 diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go index ad9c051978..a91a544ce0 100644 --- a/src/text/template/parse/parse.go +++ b/src/text/template/parse/parse.go @@ -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}} diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go index aade33ea48..81f14aca98 100644 --- a/src/text/template/parse/parse_test.go +++ b/src/text/template/parse/parse_test.go @@ -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{}{ diff --git a/test/fixedbugs/issue23545.go b/test/fixedbugs/issue23545.go new file mode 100644 index 0000000000..24485c11c5 --- /dev/null +++ b/test/fixedbugs/issue23545.go @@ -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) +} diff --git a/test/fixedbugs/issue23719.go b/test/fixedbugs/issue23719.go new file mode 100644 index 0000000000..c97e63636c --- /dev/null +++ b/test/fixedbugs/issue23719.go @@ -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") + } +} |