api/go1.10.txt | 18 ------------------ doc/conduct.html | 1 - doc/contribute.html | 2 +- doc/diagnostics.html | 4 +--- doc/editors.html | 196 ----------------------------------------------------- doc/go1.10.html | 27 ++++++++++----------------- doc/go_spec.html | 9 ++++----- doc/install-source.html | 27 ++++++++++++++++++++++----- misc/cgo/test/issue19832.go | 16 ---------------- misc/cgo/test/issue4029.c | 19 +++++++++++++++++++ misc/cgo/test/issue4029.go | 17 +++++++++++------ src/bootstrap.bash | 6 +++++- src/cmd/asm/internal/arch/arm64.go | 7 ++++++- src/cmd/asm/internal/asm/testdata/arm64.s | 16 ++++++++++++++-- src/cmd/asm/internal/asm/testdata/arm64error.s | 2 ++ src/cmd/cgo/gcc.go | 6 ------ src/cmd/compile/internal/gc/asm_test.go | 14 ++++++++++++++ src/cmd/compile/internal/gc/inl.go | 8 +++++++- src/cmd/compile/internal/gc/walk.go | 7 ++++++- src/cmd/fix/typecheck.go | 2 +- src/cmd/go/go_test.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cmd/go/internal/cache/default.go | 8 +++++--- src/cmd/go/internal/load/pkg.go | 10 ++++++++++ src/cmd/go/internal/test/test.go | 18 ++++++++++-------- src/cmd/internal/obj/arm64/asm7.go | 48 ++++++++++++++++++++++++++++++++---------------- src/cmd/link/internal/loadelf/ldelf.go | 27 +++++++++++++++++---------- src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go | 12 ++++++++++++ src/cmd/vet/main.go | 6 ++++-- src/cmd/vet/print.go | 38 +++++++++++++++++++++++++++++++++----- src/cmd/vet/testdata/print.go | 79 ++++++++++++++++++++++++++++++++++++++++++----------- src/cmd/vet/types.go | 16 ++++++++++++++-- src/database/sql/driver/driver.go | 4 ++++ src/database/sql/fakedb_test.go | 5 ----- src/database/sql/sql_test.go | 40 +++------------------------------------- src/go/build/deps_test.go | 2 +- src/go/internal/gccgoimporter/gccgoinstallation_test.go | 4 ---- src/net/sock_bsd.go | 2 +- src/os/exec.go | 5 +++++ src/os/exec/exec.go | 5 +++++ src/os/signal/internal/pty/pty.go | 21 ++++++++++++++++++--- src/os/signal/signal_cgo_test.go | 4 ++++ src/runtime/crash_cgo_test.go | 21 +++++++++++++++++++++ src/runtime/signal_linux_mips64x.go | 1 + src/runtime/signal_mips64x.go | 4 +++- src/runtime/testdata/testprogcgo/sigpanic.go | 28 ++++++++++++++++++++++++++++ src/runtime/traceback.go | 24 ++++++++++++++++++++---- src/syscall/syscall_linux.go | 2 +- src/syscall/syscall_linux_386.go | 1 - src/syscall/syscall_linux_amd64.go | 1 - src/syscall/syscall_linux_arm.go | 1 - src/syscall/syscall_linux_arm64.go | 1 - src/syscall/syscall_linux_mips64x.go | 9 +-------- src/syscall/syscall_linux_mipsx.go | 1 - src/syscall/syscall_linux_ppc64x.go | 1 - src/syscall/syscall_linux_s390x.go | 1 - src/syscall/zsyscall_linux_386.go | 2 +- src/syscall/zsyscall_linux_amd64.go | 2 +- src/syscall/zsyscall_linux_arm.go | 2 +- src/syscall/zsyscall_linux_arm64.go | 2 +- src/syscall/zsyscall_linux_mips.go | 2 +- src/syscall/zsyscall_linux_mips64.go | 2 +- src/syscall/zsyscall_linux_mips64le.go | 2 +- src/syscall/zsyscall_linux_mipsle.go | 2 +- src/syscall/zsyscall_linux_ppc64.go | 2 +- src/syscall/zsyscall_linux_ppc64le.go | 2 +- src/syscall/zsyscall_linux_s390x.go | 2 +- src/syscall/ztypes_linux_mips64.go | 5 +---- src/syscall/ztypes_linux_mips64le.go | 5 +---- src/text/template/doc.go | 6 ------ src/text/template/exec.go | 84 +++++++++++++++-------------------------------------- src/text/template/exec_test.go | 4 ---- src/text/template/parse/lex.go | 4 ---- src/text/template/parse/lex_test.go | 6 +----- src/text/template/parse/node.go | 64 ----------------------------------------------------- src/text/template/parse/parse.go | 44 ++++++-------------------------------------- src/text/template/parse/parse_test.go | 12 ------------ test/fixedbugs/issue23545.go | 35 +++++++++++++++++++++++++++++++++++ test/fixedbugs/issue23719.go | 42 ++++++++++++++++++++++++++++++++++++++++++ diff --git a/api/go1.10.txt b/api/go1.10.txt index f17e54343f974fbb41e9da1dbe9c3d4773debf12..250c10f6abe6c1b200c2d1c03fd46e1220bad764 100644 --- a/api/go1.10.txt +++ b/api/go1.10.txt @@ -618,24 +618,6 @@ pkg syscall (windows-386), func CreateProcessAsUser(Token, *uint16, *uint16, *SecurityAttributes, *SecurityAttributes, bool, uint32, *uint16, *uint16, *StartupInfo, *ProcessInformation) error 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 c40b0074f2163f769d195e83aa0d5233ddadedc8..bf52ef9fd56563299862f2c96d5a1576fe095004 100644 --- a/doc/conduct.html +++ b/doc/conduct.html @@ -183,7 +183,6 @@ diff --git a/doc/contribute.html b/doc/contribute.html index adaf983cee7eab386f4025abf03af12f87a512a1..e5312becbb5e1bb3a1aa1346d34ecb4742070bf8 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -30,7 +30,7 @@ You must go through the following process prior to contributing. You only need to do this once per Google Account.

-

Automatically set up & diagnose your development environment

+

Automatically set up & diagnose your development environment

The go-contrib-init 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 decd864f3645e75642f7cdfbe553ab595b727a61..0ed0e81b92b741d2860a683f7aa4fed5be0147e1 100644 --- a/doc/diagnostics.html +++ b/doc/diagnostics.html @@ -354,9 +354,7 @@

What’s the recommended debugger user interface?

Even though both delve and gdb provides CLIs, most editor integrations -and IDEs provides debugging-specific user interfaces. Please refer to -the editors guide to see the options -with debugger UI support. +and IDEs provides debugging-specific user interfaces.

Is it possible to do postmortem debugging with Go programs?

diff --git a/doc/editors.html b/doc/editors.html index 4a8c7eab6bd9b50a2882f545a452539075a0ff0e..617a1001303ef9cd8af7f7de737f9a4a6b751cf5 100644 --- a/doc/editors.html +++ b/doc/editors.html @@ -33,199 +33,3 @@ community-maintained list of IDEs and text editor plugins is available at the Wiki.

- -

-Each development environment integrates a number of Go-specific tools. -The following feature matrix lists and compares the most significant features. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

vim

Visual Studio Code

GoLand

Atom
Editing features
Build and run from the editor/IDEYesYesYesYes
Autocompletion of identifiers (variable, method, and function names)YesYesYesYes
Type-aware autocompletionNoNoYesNo
Rename identifiersYesYesYesYes
Auto format, build, vet, and lint on saveYesYesYes1Yes
Auto insert import paths and remove unused on saveYesYesYes2Yes
Auto generate JSON, XML tags for struct fieldsYesYesYesYes
Navigation features
Display documentation inline, or open godoc in browserYesYesYesYes
Switch between *.go and *_test.go fileYesYesYesNo
Jump to definition and refereesYesYesYesYes
Look up for interface implementationsYesYesYesYes
Search for callers and calleesYesYesYesYes
Testing and debugging features
Debugger supportNoYesYesYes3
Run a single test case, all tests from file, or all tests from a packageYesYesYesNo
Auto generate tests for packages, files and identifiersNoYesYesNo
Debug testsNoYesYesYes3
Display test coverageYesYesYesYes
InstallInstallInstallInstall
- -

-1Possible when enabled via Settings > Go > On Save, go vet and golint are available via plugins. Also runs tests on save if configured. -
-2Additionally, user input can disambiguate when two or more options are available. -
-3Available if the go-debug package is installed. -

- - - - diff --git a/doc/editors/go-plus.png b/doc/editors/go-plus.png deleted file mode 100644 index c09c7fe6756a7203964d15d079593811557c9672..0000000000000000000000000000000000000000 Binary files a/doc/editors/go-plus.png and /dev/null differ diff --git a/doc/editors/goland.png b/doc/editors/goland.png deleted file mode 100644 index 842f089e4ad9851cc2823ea0c17e02e577b2fcb1..0000000000000000000000000000000000000000 Binary files a/doc/editors/goland.png and /dev/null differ diff --git a/doc/editors/vimgo.png b/doc/editors/vimgo.png deleted file mode 100644 index cf317eff32f178ecc2b33291fa8f0290072489ea..0000000000000000000000000000000000000000 Binary files a/doc/editors/vimgo.png and /dev/null differ diff --git a/doc/editors/vscodego.png b/doc/editors/vscodego.png deleted file mode 100644 index 4e6c7b8047b71e1ca39641d8e6d4623115f44bc6..0000000000000000000000000000000000000000 Binary files a/doc/editors/vscodego.png and /dev/null differ diff --git a/doc/go1.10.html b/doc/go1.10.html index fba4dcf19025b88831ea2767c532ed48e08b5633..5885176f46c01620e53d4e73bf8e060781174266 100644 --- a/doc/go1.10.html +++ b/doc/go1.10.html @@ -277,9 +277,9 @@

Cgo now supports direct access to Go string values from C. Functions in the C preamble may use the type _GoString_ -to accept a Go string as an argument. +to accept a Go string as an argument. C code may call _GoStringLen and _GoStringPtr -for direct access to the contents of the string. +for direct access to the contents of the string. A value of type _GoString_ may be passed in a call to an exported Go function that takes an argument of Go type string.

@@ -814,6 +814,13 @@
database/sql/driver

+Drivers that currently hold on to the destination buffer provided by +driver.Rows.Next 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 +driver.Rows. +

+

Drivers that want to construct a sql.DB for their clients can now implement the Connector interface and call the new sql.OpenDB function, @@ -1062,11 +1069,6 @@

html/template

-The new actions {{"{{break}}"}} and {{"{{continue}}"}} -break out of the innermost {{"{{range"}} ...}} loop, -like the corresponding Go statements. -

-

The new Srcset content type allows for proper handling of values within the srcset @@ -1340,7 +1342,7 @@ in the corresponding StructField, with the result that for those fields, and Value.CanSet incorrectly returned true and -and Value.Set +Value.Set incorrectly succeeded. The underlying metadata has been corrected; for those fields, @@ -1401,15 +1403,6 @@

On BSD, macOS, and Solaris systems, UtimesNano is now implemented. -

-
- -
text/template
-
-

-The new actions {{"{{break}}"}} and {{"{{continue}}"}} -break out of the innermost {{"{{range"}} ...}} loop, -like the corresponding Go statements.

diff --git a/doc/go_spec.html b/doc/go_spec.html index 33b66cb9053699d614a7ace12538ded53ce7881e..9a166ccdf40077502a94935a2bed9a78947d273c 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -2148,9 +2148,8 @@ to a function.

-FunctionDecl = "func" FunctionName ( Function | Signature ) .
+FunctionDecl = "func" FunctionName Signature [ FunctionBody ] .
 FunctionName = identifier .
-Function     = Signature FunctionBody .
 FunctionBody = Block .
 
@@ -2196,7 +2195,7 @@ and associates the method with the receiver's base type.

-MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
+MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] .
 Receiver   = Parameters .
 
@@ -2518,7 +2517,7 @@ A function literal represents an anonymous function.

-FunctionLit = "func" Function .
+FunctionLit = "func" Signature FunctionBody .
 
diff --git a/doc/install-source.html b/doc/install-source.html
index 8813455cbc3b884e342f8c02b8ac0ad055a55561..4ed9487504c897f4bb5ae00b404ce2b013efe585 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -446,6 +446,7 @@ defaults to the parent of the directory where all.bash was run.
 There is no need to set this unless you want to switch between multiple
 local copies of the repository.
 

+
  • $GOROOT_FINAL

    @@ -456,12 +457,14 @@ If you want to build the Go tree in one location but move it elsewhere after the build, set $GOROOT_FINAL to the eventual location.

    +
  • $GOOS and $GOARCH

    The name of the target operating system and compilation architecture. These default to the values of $GOHOSTOS and $GOHOSTARCH respectively (described below). +

  • Choices for $GOOS 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.

    +

    Valid choices are the same as for $GOOS and @@ -600,6 +604,7 @@ directory to your $PATH, so you can use the tools. If $GOBIN is set, the go command installs all commands there.

    +
  • $GO386 (for 386 only, default is auto-detected if built on either 386 or amd64, 387 otherwise) @@ -609,9 +614,10 @@ (set to 387) or SSE2 instructions (set to sse2) for floating point computations.

      -
    • GO386=387: use x87 for floating point operations; should support all x86 chips (Pentium MMX or later). -
    • GO386=sse2: use SSE2 for floating point operations; has better performance than 387, but only available on Pentium 4/Opteron/Athlon 64 or later. +
    • GO386=387: use x87 for floating point operations; should support all x86 chips (Pentium MMX or later).
    • +
    • GO386=sse2: use SSE2 for floating point operations; has better performance than 387, but only available on Pentium 4/Opteron/Athlon 64 or later.
    +
  • $GOARM (for arm 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.

      -
    • GOARM=5: use software floating point; when CPU doesn't have VFP co-processor -
    • GOARM=6: use VFPv1 only; default if cross compiling; usually ARM11 or better cores (VFPv2 or better is also supported) -
    • GOARM=7: use VFPv3; usually Cortex-A cores +
    • GOARM=5: use software floating point; when CPU doesn't have VFP co-processor
    • +
    • GOARM=6: use VFPv1 only; default if cross compiling; usually ARM11 or better cores (VFPv2 or better is also supported)
    • +
    • GOARM=7: use VFPv3; usually Cortex-A cores

    If in doubt, leave this variable unset, and adjust it if required @@ -631,6 +637,17 @@ The GoARM page on the Go community wiki contains further details regarding Go's ARM support.

    +
  • + +
  • $GOMIPS (for mips and mipsle only) +

    +This sets whether to use floating point instructions. +

    +
      +
    • GOMIPS=hardfloat: use floating point instructions (the default)
    • +
    • GOMIPS=softfloat: use soft floating point
    • +
    +
  • diff --git a/misc/cgo/test/issue19832.go b/misc/cgo/test/issue19832.go deleted file mode 100644 index 44587770af41ab38575fd16bfbef8cfc6cf21d2e..0000000000000000000000000000000000000000 --- 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 eab36834501ff78389eb00ad127a074c1f65b09e..7205c5a5a2505250adf5bfa54909f37bb27b8798 100644 --- a/misc/cgo/test/issue4029.c +++ b/misc/cgo/test/issue4029.c @@ -4,6 +4,25 @@ // license that can be found in the LICENSE file. // +build !windows +#include +#include + +// 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 5789b99ef67034f4644bac0aa9186e40675a1cf4..8e468d367d1ec9d9ad21ae6b564e64293bc93057 100644 --- a/misc/cgo/test/issue4029.go +++ b/misc/cgo/test/issue4029.go @@ -7,10 +7,15 @@ package cgotest /* +#include #include #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 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 7b4f57461fc05a8e99c6758b8212ed747b691a07..32b736ad7885e7547e1abb74354ea4c90c525aa3 100755 --- a/src/bootstrap.bash +++ b/src/bootstrap.bash @@ -77,7 +77,11 @@ rmdir bin/*_* 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 2fd21b58b8f3e495b22384d2fe1a7e9439a9d744..63664d663c1ce9b44e56dfc7fa02cc8caa6db118 100644 --- a/src/cmd/asm/internal/arch/arm64.go +++ b/src/cmd/asm/internal/arch/arm64.go @@ -123,6 +123,11 @@ // 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 @@ case "UXTH": 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 ab6ad5bcb79796d0d413a6f78b3733f4ce29fe50..cb563bb9961d92914a1c47724cada58c8cdc0234 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -29,8 +29,20 @@ ADD R1>>11, R2, R3 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 97af09c4dd6d5e6a510e284948f8d84d81331939..e4fad9c741feaf0a00b45347a6f0d3f8529dddb5 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -10,4 +10,6 @@ VLD1 8(R9), [V2.B16] // ERROR "illegal combination" 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 4f16fe0e319916e745ed055084d1b5e70a65a987..2ebe9066992785348d33e386624bde2364e188a6 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -2250,12 +2250,6 @@ if c.badPointerTypedef(dt) { 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 8eb3d07f2cc42bc3cdc9aa130ec42a20a20c3d67..50857e65339cb2525cd65231c10032f835754e07 100644 --- a/src/cmd/compile/internal/gc/asm_test.go +++ b/src/cmd/compile/internal/gc/asm_test.go @@ -1004,6 +1004,20 @@ pos: []string{"\tCMPL\t[A-Z]"}, }, { fn: ` + func $(a,b [3]int16) bool { + return a == b + }`, + pos: []string{"\tCMPL\t[A-Z]"}, + }, + { + fn: ` + func $(a,b [12]int8) bool { + return a == b + }`, + pos: []string{"\tCMPQ\t[A-Z]", "\tCMPL\t[A-Z]"}, + }, + { + fn: ` func f70(a,b [15]byte) bool { return a == b }`, diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 2f96b46f2be35d084166bdd886f4309de63c59ae..c8296971cd3da008077fa2e46da2774a9948c67a 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -314,11 +314,17 @@ return true } // 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, diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 34c73acce0b96e49cd86eda3063c128e0eec1f33..f48513dc73d1efef0c0e58f61a0d0d4d96773239 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3415,18 +3415,23 @@ ) 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 c5900d8dcd1d16a6436f229d7f2ba34423fd6bbd..eafb626c74768133293d2eef82d91f11f129cc93 100644 --- a/src/cmd/fix/typecheck.go +++ b/src/cmd/fix/typecheck.go @@ -166,7 +166,7 @@ dir, err := ioutil.TempDir(os.TempDir(), "fix_cgo_typecheck") 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 7eaaf4875946967cecf64f01e8dea5b5d769e61a..92600b6238fcd5c32fa2236e5f77bef180c735df 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -81,6 +81,13 @@ // the full set of external tests. 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 @@ tg.grepStdout(`\(cached\)`, "did not cache") } } +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) @@ -5406,6 +5437,44 @@ tg.runFail("test", "vetfail/...") tg.grepStderr(`Printf format %d`, "did not diagnose bad Printf") 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) { @@ -5655,3 +5724,18 @@ tg.must(os.Remove(out)) 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 8285f787d4c9cae46b178f6ecee94ae538fdcfbe..97283762258d659c0a6fcacc5d9c32fe80eebc88 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 @@ if dir == "off" { 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 @@ } 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 beccbb568971982f4a55b50adea689c61958d74d..eaff7177b6fffffa135fc858528fccdac6538368 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -416,6 +416,9 @@ var bp *build.Package 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 @@ // If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path, // 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 7f7ce63eda8cc4abf714015df1fe8e21431a280b..a99c6a5ec220200b8398f4ae76b38501c573d6e1 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -659,6 +659,15 @@ matched[i] = true 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 @@ pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest) 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 @@ // This makes sure that q sees the modifications to p. // 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 fdf1fb565dc5cb1e5526e57ad61d820f2f16ec12..ca81238c93e93fe81f154bfb1011253a5184d771 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -2362,7 +2362,7 @@ if r == 0 { 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 @@ rt := int(p.To.Reg) o1 |= (REGZERO & 31 << 5) | uint32(rt&31) case 27: /* op Rm<> 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 @@ 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 @@ if r == 0 { 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 @@ o3 |= 2 << 23 } 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 @@ } else { 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 @@ } } /* - * 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 793fd961d12b4cbe26ad4cf3932acf51e15be600..b95664830f2fa132912868e66cdeae4aaaaa31fd 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -405,13 +405,10 @@ // format used means that we have to parse all of the file-level attributes to // 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 @@ data = data[sectionlength:] 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 @@ attrList := elfAttributeList{data: subsectiondata} 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,10 +684,19 @@ if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" { 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 { 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 32af2e9b20729fdbcb99138fa22905319c9a4952..abce5b5c70c52b339f57193209ceaf96f46dfd8f 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 807e80095904d4e088fbc700f2caf86075b44597..7265aa6f5793f7ca6b8f0407414db5fd57547464 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -195,9 +195,11 @@ // 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 456fbcc044de5410caa214517fa03bf8449f060e..04c59551b2f88d31376c9455bfbb026502c61548 100644 --- a/src/cmd/vet/print.go +++ b/src/cmd/vet/print.go @@ -187,12 +187,14 @@ } 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 @@ // Used only during parse. 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 @@ } // 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 @@ w = len(state.format) 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 @@ -342,6 +349,10 @@ } } // Dotdotdot is hard. 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. @@ -402,6 +413,7 @@ s.nbytes++ // skip ']' 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 @@ f.Badf(call.Pos(), "%s format %s has unknown verb %c", state.name, state.format, state.verb) 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 @@ // 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 @@ obj = e.Obj case *ast.UnaryExpr: if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND { obj = id.Obj + ptr = true } } @@ -647,7 +666,16 @@ // 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 55ab84fae7685d6716e9f55b0f03e6bc1a96cd37..6508c8e61552e5a56cdf5ce9b4662c9ac79c0143 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/print.go @@ -130,8 +130,8 @@ fmt.Printf("%t", 23) // ERROR "Printf format %t has arg 23 of wrong type int" 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 @@ const format = "%s %s\n" 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 @@ Printf("%d %[0]d %d %[2]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[0\]" 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 @@ } 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 @@ } 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 799dc655e607cb68e28197dde9865a4a54a50f0e..1f30b4b42b8a321bcb852699b09c0fdca377ac45 100644 --- a/src/cmd/vet/types.go +++ b/src/cmd/vet/types.go @@ -172,7 +172,7 @@ if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { 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 @@ return false } 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 19a3a4f7c9aa2bcaa23c559f93d80e101a52bf1e..1e54b4cf2cf1759f4fc6dedc9e0fd18ada651d19 100644 --- a/src/database/sql/driver/driver.go +++ b/src/database/sql/driver/driver.go @@ -379,6 +379,10 @@ // the provided slice. The provided slice will be the same // 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 e795412de01c97c7cc4faf2d6d3cbe106713375a..abb8d40fc022ed5c492e2709bdd1ec82b8fcccac 100644 --- a/src/database/sql/fakedb_test.go +++ b/src/database/sql/fakedb_test.go @@ -1020,11 +1020,6 @@ rc.line++ } 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 8137eff82b4ae1511bb63b11de4ff41e90b54b90..ae6bf7102e36c907fdd293ffee615ff6fb5c8f0f 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -663,43 +663,6 @@ t.Fatalf("PingContext (Normal): %v", err) } } -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 @@ // Test failure will happen with a panic or other race condition being // 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 d21eacc6fbd0b7b62341fd70466257cafef20ec2..07a9cd3c8218550be56c694be60f4e670dc15db2 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -301,7 +301,7 @@ // Plan 9 alone needs io/ioutil and os. "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 e601411237f9cde04908e6025ddc3195e8dc3a6f..da4931ef1e72244fe14f49087e3ed808106edfcf 100644 --- a/src/go/internal/gccgoimporter/gccgoinstallation_test.go +++ b/src/go/internal/gccgoimporter/gccgoinstallation_test.go @@ -62,8 +62,6 @@ "encoding/json", "encoding/pem", "encoding/xml", "errors", - "exp/proxy", - "exp/terminal", "expvar", "flag", "fmt", @@ -114,8 +112,6 @@ "net/rpc/jsonrpc", "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 dfb092055021f3956311ea93907e667f6dd4367e..516e557cfd29816ac1904dc577bbd5bec9ec22d9 100644 --- a/src/net/sock_bsd.go +++ b/src/net/sock_bsd.go @@ -20,7 +20,7 @@ switch runtime.GOOS { 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 b3f60b62d0379b9653490a948b8df09bee95e6ad..a7f8710b955db572679762e03ee3c99ec8a69fe5 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -88,6 +88,11 @@ // StartProcess starts a new process with the program, arguments and attributes // 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 8a49fe3b58eb68889225e8395360348859f0beae..5ef9540141ef0e7bba36b6b97bc3e1c7de81b92c 100644 --- a/src/os/exec/exec.go +++ b/src/os/exec/exec.go @@ -293,6 +293,11 @@ // status. // // 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 fe293a0126f8d89b6bb786a7701a71b4e1099dd7..c4c1567fce0b314f9acd386b6fa1a4aef36ccec9 100644 --- a/src/os/signal/internal/pty/pty.go +++ b/src/os/signal/internal/pty/pty.go @@ -21,21 +21,36 @@ 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 27707fadcee4b60ff8ea8a658011163af7e3812e..84a2a08ce9b6e5a11e072f581b72cbc890e40414 100644 --- a/src/os/signal/signal_cgo_test.go +++ b/src/os/signal/signal_cgo_test.go @@ -72,6 +72,10 @@ // case a pseudo-terminal. 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 8993a75ad3fb1080d6d0459fc1d6b77692a43647..3b9fedc7a43a6182e71d01a10f6b504cbf65e07d 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -481,3 +481,24 @@ if got != want { 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 9e0cf42c706ae05191875d5a78b28a7d32d8cf9e..b608197d605a1503acb8fe4121b0763d59bab9ed 100644 --- a/src/runtime/signal_linux_mips64x.go +++ b/src/runtime/signal_linux_mips64x.go @@ -66,6 +66,7 @@ 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 9546a5af997bc49a7a52be35d8b00c420f97c21e..35b356c2fb104ebcd1ee5d134922c327abbdc849 100644 --- a/src/runtime/signal_mips64x.go +++ b/src/runtime/signal_mips64x.go @@ -89,6 +89,8 @@ c.set_link(uint64(pc)) } // 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 0000000000000000000000000000000000000000..cb46030980260d1a6d029bd860a7f84577b73b23 --- /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 62622df2e75dd97b9b2fbef37f3b5a4a9fb32b41..747176c278202757fb62591f2cd0b891570b1818 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -43,6 +43,7 @@ mcallPC uintptr morestackPC uintptr mstartPC uintptr rt0_goPC uintptr + asmcgocallPC uintptr sigpanicPC uintptr runfinqPC uintptr bgsweepPC uintptr @@ -70,6 +71,7 @@ mcallPC = funcPC(mcall) 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 @@ frame.fp += sys.RegSize } } 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 @@ // This happens if you get a profiling interrupt at just the wrong time. // 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 @@ }) } // 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 3fb9b1aa3f30b1f3e41212234625fb534cff48b8..d2cb7c1afe7c38d6c4c31c1262eb12fe8ecfcac3 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -831,7 +831,7 @@ //sys fcntl(fd int, cmd int, arg int) (val int, err error) //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 2c5d9a3eee79a797c445f6c45502afae3a5a237c..13b9e2ece53a8a1043ad9acb6990f2ca3c322b17 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 eaba868f89491c6574addf62a99bf00f8718ed1b..4b4aa6d4144ec3b475da4aa0184503025f1fb9b6 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 5c652b2e5bfce582ec79a1c76e64cdbd532538dd..5ccab9bb74bf35885ca6d93ef16cada4a738e595 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 12b9ebcb4327a09c81179e9221117af80d53b567..27c351d7bd13888659ae7bc7313384f419a0c0d3 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 e4bc77530c9793db15cf0b38359f08db3eba644c..d9eba62b0671d67b792bc5aa3671ba49e33be2b8 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 1da265d3c450b5e1375d47b5e3caf535f6608fd3..92785e1596f489ae22947c3c5e19f0eeadf14cd4 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 55ade887ecce245cad286b30139565bac5bf7218..f743b77163a7e96387904b3686d02abdafc5308f 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 8f3bbfc6f74c08a0782aeb71c69109d2cbac1c87..6bd9744bdfb9ad4f3f2bb9db79793938cf838b83 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 8955fca33673245f1cbb9e8b31e069b1cdf1c59d..86f8ec15fa9ab454c33bfa358391ea5c446cf046 100644 --- a/src/syscall/zsyscall_linux_386.go +++ b/src/syscall/zsyscall_linux_386.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 34cbed812cbb1354e43539abbfb20523a2ff88ae..6545d1a159671a6fa0799b0878caa4ca85f29a56 100644 --- a/src/syscall/zsyscall_linux_amd64.go +++ b/src/syscall/zsyscall_linux_amd64.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 c9fa1c86e2db83c6021cd99ff334ca7dfcddd4b3..0f0464bf1ce752395b752fc18ec47b47a6872c50 100644 --- a/src/syscall/zsyscall_linux_arm.go +++ b/src/syscall/zsyscall_linux_arm.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 a694b83b0bf7268cd820d01c85c3deb2fa8246dc..27470ac0c9cdf730be7838d6143f74a9833e10ce 100644 --- a/src/syscall/zsyscall_linux_arm64.go +++ b/src/syscall/zsyscall_linux_arm64.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 5aa984d780044deb938bb7f7c2b3355a76cec71f..6b26f7bb926f79d96f3f9126768994ebe5b8bb80 100644 --- a/src/syscall/zsyscall_linux_mips.go +++ b/src/syscall/zsyscall_linux_mips.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 110b35870ae8f95ed62c43ab37255623ae25624e..00a8f7f0c06ad48ee123e95a706f5959b9558550 100644 --- a/src/syscall/zsyscall_linux_mips64.go +++ b/src/syscall/zsyscall_linux_mips64.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 23597f83885ff535f1e2be1a2d5170246af47afa..97a68ff9e84017e8869f35d88c4ae7fa21099cd9 100644 --- a/src/syscall/zsyscall_linux_mips64le.go +++ b/src/syscall/zsyscall_linux_mips64le.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 07825a3b807b95919c0cfb46cfdd124f8a83151c..face54ba284a439f99df0268623ea437bf90e61f 100644 --- a/src/syscall/zsyscall_linux_mipsle.go +++ b/src/syscall/zsyscall_linux_mipsle.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 56fb3b8d931103158e9eb1fe833958f6a923c0d3..7df49c728ac4e33422080af55fd2436be4424dbe 100644 --- a/src/syscall/zsyscall_linux_ppc64.go +++ b/src/syscall/zsyscall_linux_ppc64.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 d08279f4fb3848859a6a0b976701df6c25cb9243..f073f7dbd112913e2b36e2c027d904313411d519 100644 --- a/src/syscall/zsyscall_linux_ppc64le.go +++ b/src/syscall/zsyscall_linux_ppc64le.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 e8f1a70b436cac074c6f126a63d557df9bbb6c30..689f2f472c908cf042135f9c466ea0f7cd1f1543 100644 --- a/src/syscall/zsyscall_linux_s390x.go +++ b/src/syscall/zsyscall_linux_s390x.go @@ -479,7 +479,7 @@ _p0 = unsafe.Pointer(&buf[0]) } 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 925afb9d1c26aaa62574f8c98ffc4494e17188c8..8c5a0d1d76c3a4aa358493efd9f9d94ed5e0cc17 100644 --- a/src/syscall/ztypes_linux_mips64.go +++ b/src/syscall/ztypes_linux_mips64.go @@ -130,15 +130,12 @@ Flags int64 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 925afb9d1c26aaa62574f8c98ffc4494e17188c8..8c5a0d1d76c3a4aa358493efd9f9d94ed5e0cc17 100644 --- a/src/syscall/ztypes_linux_mips64le.go +++ b/src/syscall/ztypes_linux_mips64le.go @@ -130,15 +130,12 @@ Flags int64 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 f7609293cea8a6d6942f1998bac9f31d7b6caf69..d174ebd9cfeedc5a589ad9268609e21b39998764 100644 --- a/src/text/template/doc.go +++ b/src/text/template/doc.go @@ -110,12 +110,6 @@ If the value of the pipeline has length zero, dot is unaffected and 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 87cf1e9b1c32b3a3e3227118e37e51f1d6c40ebd..83c38cdf13ce7c39d7b14f789e9c401341a50771 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -25,12 +25,11 @@ // state represents the state of an execution. It's not part of the // 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 @@ } 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 @@ if len(node.Pipe.Decl) == 0 { 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 @@ if _, err := s.wr.Write(node.Text); err != nil { 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 @@ s.errorf("if/with can't use %v", val) } 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 @@ } 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 @@ // Set next var (lexically the first if there are two) to the index. 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 @@ if val.Len() == 0 { 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 @@ elem, ok := val.Recv() 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 79b504f8a4d02001f78e5d717540e979ad3e20d0..d0cda6bd625da787d8dd41fb204ff79ae392fbce 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -513,10 +513,6 @@ {"range $x PSI", "{{range $x := .PSI}}<{{$x}}>{{end}}", "<21><22><23>", tVal, true}, {"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 da766cc7c32be8b2c29de1a7377eccc4ec57408b..e112cb7714a422a58fd824e751a8a569deda9e88 100644 --- a/src/text/template/parse/lex.go +++ b/src/text/template/parse/lex.go @@ -60,8 +60,6 @@ itemVariable // variable starting with '$', such as '$' or '$1' or '$hello' // 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 @@ 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 ca7c3f64bc7701c1054635e10611ddc99b83b0cb..cb01cd98b6ab2263618a5feec888e8bfc58807d5 100644 --- a/src/text/template/parse/lex_test.go +++ b/src/text/template/parse/lex_test.go @@ -192,7 +192,7 @@ mkItem(itemField, ".z"), 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 @@ tSpace, 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 7e16349b31eabd62b36598b09cae87a6301d9ed7..55ff46c17ab28e84875f70758cc41796651fa53e 100644 --- a/src/text/template/parse/node.go +++ b/src/text/template/parse/node.go @@ -69,8 +69,6 @@ NodeString // A string constant. NodeTemplate // A template invocation action. NodeVariable // A $ variable. NodeWith // A with action. - NodeBreak // A break action. - NodeContinue // A continue action. ) // Nodes. @@ -796,68 +794,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. diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go index ad9c05197895bafbb36f9d963baed346d7dd0725..a91a544ce016f2c5446c441dcc30a3abf5d39966 100644 --- a/src/text/template/parse/parse.go +++ b/src/text/template/parse/parse.go @@ -23,13 +23,12 @@ ParseName string // name of the top-level template during parsing, for error messages. 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 @@ t.lex = nil 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 @@ case itemTemplate: 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, pipe *PipeNode, list, elseList *ListNode) { 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: @@ -508,26 +496,6 @@ // {{range pipeline}} itemList {{else}} itemList {{end}} // Range keyword is past. 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: diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go index aade33ea48e98b5e34e3ed503f06f7e363010c1b..81f14aca986cdcb8774f0c2562cc388bf6a4bb16 100644 --- a/src/text/template/parse/parse_test.go +++ b/src/text/template/parse/parse_test.go @@ -218,12 +218,6 @@ {"range 1 var", "{{range $x := .SI}}{{.}}{{end}}", noError, `{{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 @@ {"wrong pipeline nil", "{{'c'|nil}}", hasError, ""}, {"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 0000000000000000000000000000000000000000..24485c11c5528aafdf4524baff14bdb45949f54e --- /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 0000000000000000000000000000000000000000..c97e63636c06f6cdc0dbe6c4c662b214fd013aed --- /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") + } +}