]> Cypherpunks.ru repositories - gostls13.git/commitdiff
all: merge dev.inline into master
authorRuss Cox <rsc@golang.org>
Wed, 1 Feb 2017 14:35:27 +0000 (09:35 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 1 Feb 2017 14:47:23 +0000 (09:47 -0500)
Change-Id: I7715581a04e513dcda9918e853fa6b1ddc703770

392 files changed:
.gitignore
AUTHORS
CONTRIBUTING.md
CONTRIBUTORS
README.md
api/except.txt
api/go1.8.txt
doc/asm.html
doc/code.html
doc/conduct.html
doc/contribute.html
doc/debugging_with_gdb.html
doc/devel/release.html
doc/devel/weekly.html
doc/gccgo_install.html
doc/go1.8.html
doc/go1.8.txt
doc/go_spec.html
doc/help.html
doc/install-source.html
doc/install.html
lib/time/update.bash
lib/time/zoneinfo.zip
misc/cgo/test/issue17537.go
misc/cgo/test/issue18146.go
misc/cgo/test/issue9400/asm_mipsx.s [new file with mode: 0644]
misc/cgo/test/sigaltstack.go
misc/cgo/testcshared/main2.c
misc/cgo/testplugin/src/iface/main.go [new file with mode: 0644]
misc/cgo/testplugin/src/iface_a/a.go [new file with mode: 0644]
misc/cgo/testplugin/src/iface_b/b.go [new file with mode: 0644]
misc/cgo/testplugin/src/iface_i/i.go [new file with mode: 0644]
misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go [new file with mode: 0644]
misc/cgo/testplugin/src/issue18676/main.go [new file with mode: 0644]
misc/cgo/testplugin/src/issue18676/plugin.go [new file with mode: 0644]
misc/cgo/testplugin/src/plugin1/plugin1.go
misc/cgo/testplugin/src/plugin2/plugin2.go
misc/cgo/testplugin/test.bash
misc/cgo/testsanitizers/msan_shared.go [new file with mode: 0644]
misc/cgo/testsanitizers/test.bash
misc/cgo/testsanitizers/tsan9.go [new file with mode: 0644]
misc/cgo/testshared/shared_test.go
misc/cgo/testshared/src/depBase/dep.go
misc/cgo/testshared/src/exe/exe.go
misc/cgo/testshared/src/iface/main.go [new file with mode: 0644]
misc/cgo/testshared/src/iface_a/a.go [new file with mode: 0644]
misc/cgo/testshared/src/iface_b/b.go [new file with mode: 0644]
misc/cgo/testshared/src/iface_i/i.go [new file with mode: 0644]
misc/ios/clangwrap.sh
misc/ios/go_darwin_arm_exec.go
src/archive/zip/reader.go
src/archive/zip/reader_test.go
src/archive/zip/struct.go
src/archive/zip/testdata/extra-timestamp.zip [deleted file]
src/archive/zip/writer.go
src/archive/zip/writer_test.go
src/archive/zip/zip_test.go
src/bytes/buffer.go
src/cmd/cgo/gcc.go
src/cmd/compile/internal/gc/alg.go
src/cmd/compile/internal/gc/align.go
src/cmd/compile/internal/gc/asm_test.go
src/cmd/compile/internal/gc/bexport.go
src/cmd/compile/internal/gc/bimport.go
src/cmd/compile/internal/gc/builtin.go
src/cmd/compile/internal/gc/builtin/runtime.go
src/cmd/compile/internal/gc/dcl.go
src/cmd/compile/internal/gc/export.go
src/cmd/compile/internal/gc/fmt.go
src/cmd/compile/internal/gc/go.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/noder.go
src/cmd/compile/internal/gc/obj.go
src/cmd/compile/internal/gc/reflect.go
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/syntax.go
src/cmd/compile/internal/gc/testdata/array.go
src/cmd/compile/internal/gc/testdata/string.go
src/cmd/compile/internal/gc/type.go
src/cmd/compile/internal/gc/typecheck.go
src/cmd/compile/internal/gc/universe.go
src/cmd/compile/internal/gc/util.go
src/cmd/compile/internal/gc/walk.go
src/cmd/compile/internal/ssa/checkbce.go
src/cmd/compile/internal/ssa/compile.go
src/cmd/compile/internal/ssa/config.go
src/cmd/compile/internal/ssa/func.go
src/cmd/compile/internal/ssa/gen/ARM64Ops.go
src/cmd/compile/internal/ssa/gen/ARMOps.go
src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
src/cmd/compile/internal/ssa/gen/MIPSOps.go
src/cmd/compile/internal/ssa/gen/PPC64.rules
src/cmd/compile/internal/ssa/gen/PPC64Ops.go
src/cmd/compile/internal/ssa/gen/S390X.rules
src/cmd/compile/internal/ssa/loopreschedchecks.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/nilcheck.go
src/cmd/compile/internal/ssa/op.go
src/cmd/compile/internal/ssa/regalloc.go
src/cmd/compile/internal/ssa/rewritePPC64.go
src/cmd/compile/internal/ssa/rewriteS390X.go
src/cmd/compile/internal/ssa/sparsetree.go
src/cmd/compile/internal/ssa/writebarrier.go
src/cmd/compile/internal/syntax/nodes.go
src/cmd/compile/internal/syntax/parser.go
src/cmd/compile/internal/syntax/printer.go
src/cmd/compile/internal/syntax/printer_test.go
src/cmd/cover/cover.go
src/cmd/cover/cover_test.go
src/cmd/cover/testdata/test.go
src/cmd/dist/build.go
src/cmd/dist/test.go
src/cmd/doc/doc_test.go
src/cmd/doc/pkg.go
src/cmd/doc/testdata/pkg.go
src/cmd/go/alldocs.go
src/cmd/go/bug.go
src/cmd/go/build.go
src/cmd/go/get.go
src/cmd/go/go_test.go
src/cmd/go/help.go
src/cmd/go/http.go
src/cmd/go/pkg.go
src/cmd/go/test.go
src/cmd/go/testdata/src/empty/pkg/pkg.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/pkgtest/pkg.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/pkgtest/test_test.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/pkgxtest/pkg.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/test/test_test.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/testxtest/test_test.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/testxtest/xtest_test.go [new file with mode: 0644]
src/cmd/go/testdata/src/empty/xtest/xtest_test.go [new file with mode: 0644]
src/cmd/go/testdata/timeoutbench_test.go [new file with mode: 0644]
src/cmd/go/testflag.go
src/cmd/go/vendor_test.go
src/cmd/gofmt/testdata/typealias.golden [new file with mode: 0644]
src/cmd/gofmt/testdata/typealias.input [new file with mode: 0644]
src/cmd/internal/obj/go.go
src/cmd/internal/obj/mips/obj0.go
src/cmd/internal/obj/pcln.go
src/cmd/internal/obj/reloctype_string.go
src/cmd/link/internal/arm/obj.go
src/cmd/link/internal/ld/config.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/decodesym.go
src/cmd/link/internal/ld/dwarf.go
src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/macho.go
src/cmd/link/internal/ld/pcln.go
src/cmd/link/internal/ld/symtab.go
src/cmd/link/internal/mips/asm.go
src/cmd/objdump/objdump_test.go
src/cmd/pprof/internal/driver/driver.go
src/cmd/pprof/internal/report/report.go
src/cmd/pprof/internal/report/source.go
src/cmd/pprof/internal/svg/svgpan.go
src/cmd/vet/cgo.go
src/cmd/vet/copylock.go
src/cmd/vet/structtag.go
src/cmd/vet/testdata/cgo/cgo.go
src/cmd/vet/testdata/copylock.go
src/cmd/vet/testdata/copylock_func.go
src/cmd/vet/testdata/structtag.go
src/cmd/vet/vet_test.go
src/compress/bzip2/bzip2_test.go
src/compress/flate/deflate.go
src/compress/flate/deflate_test.go
src/compress/flate/deflatefast.go
src/compress/gzip/issue14937_test.go
src/context/context_test.go
src/crypto/aes/cipher_s390x.go
src/crypto/aes/const.go
src/crypto/aes/gcm_s390x.go
src/crypto/cipher/gcm.go
src/crypto/dsa/dsa.go
src/crypto/dsa/dsa_test.go
src/crypto/elliptic/elliptic.go
src/crypto/elliptic/p224.go
src/crypto/rsa/rsa.go
src/crypto/sha1/sha1block_amd64.s
src/crypto/sha256/sha256block_amd64.s
src/crypto/tls/cipher_suites.go
src/crypto/tls/conn.go
src/crypto/tls/tls.go
src/crypto/x509/cert_pool.go
src/crypto/x509/root_darwin.go
src/crypto/x509/root_darwin_test.go
src/crypto/x509/root_windows.go
src/crypto/x509/verify.go
src/crypto/x509/x509.go
src/crypto/x509/x509_test.go
src/database/sql/ctxutil.go
src/database/sql/driver/driver.go
src/database/sql/internal/types.go [deleted file]
src/database/sql/sql.go
src/database/sql/sql_test.go
src/encoding/asn1/marshal.go
src/fmt/fmt_test.go
src/fmt/print.go
src/go/ast/ast.go
src/go/ast/scope.go
src/go/build/build.go
src/go/build/build_test.go
src/go/build/deps_test.go
src/go/build/doc.go
src/go/build/testdata/ignored/ignored.go [deleted file]
src/go/doc/doc_test.go
src/go/internal/gccgoimporter/importer_test.go
src/go/internal/gccgoimporter/parser.go
src/go/internal/gccgoimporter/testdata/alias.gox [new file with mode: 0644]
src/go/internal/gccgoimporter/testdata/time.gox [new file with mode: 0644]
src/go/internal/gccgoimporter/testdata/unicode.gox [new file with mode: 0644]
src/go/internal/gcimporter/bimport.go
src/go/parser/interface.go
src/go/parser/parser.go
src/go/parser/performance_test.go
src/go/parser/short_test.go
src/go/printer/nodes.go
src/go/printer/printer.go
src/go/printer/testdata/comments2.golden
src/go/printer/testdata/comments2.input
src/go/printer/testdata/declarations.golden
src/go/printer/testdata/declarations.input
src/go/types/api.go
src/go/types/api_test.go
src/go/types/call.go
src/go/types/check_test.go
src/go/types/decl.go
src/go/types/example_test.go
src/go/types/lookup.go
src/go/types/methodset.go
src/go/types/object.go
src/go/types/object_test.go [new file with mode: 0644]
src/go/types/predicates.go
src/go/types/resolver.go
src/go/types/stdlib_test.go
src/go/types/testdata/decls4.src [new file with mode: 0644]
src/go/types/typestring.go
src/go/types/typexpr.go
src/io/io.go
src/io/multi.go
src/io/multi_test.go
src/io/pipe.go
src/io/pipe_test.go
src/math/big/int.go
src/net/addrselect.go
src/net/addrselect_test.go
src/net/dial.go
src/net/dial_test.go
src/net/dnsclient_unix.go
src/net/dnsclient_unix_test.go
src/net/http/client.go
src/net/http/client_test.go
src/net/http/h2_bundle.go
src/net/http/httptrace/trace.go
src/net/http/httputil/dump.go
src/net/http/httputil/dump_test.go
src/net/http/httputil/reverseproxy.go
src/net/http/request.go
src/net/http/requestwrite_test.go
src/net/http/serve_test.go
src/net/http/server.go
src/net/http/transfer.go
src/net/http/transport.go
src/net/http/transport_test.go
src/net/interface.go
src/net/ip.go
src/net/iprawsock.go
src/net/iprawsock_posix.go
src/net/iprawsock_test.go
src/net/ipsock.go
src/net/ipsock_posix.go
src/net/lookup.go
src/net/lookup_plan9.go
src/net/lookup_test.go
src/net/lookup_unix.go
src/net/lookup_windows_test.go
src/net/port_unix.go
src/net/tcpsock_test.go
src/net/udpsock_test.go
src/os/exec/exec_test.go
src/os/file.go
src/os/os_test.go
src/os/path_windows.go
src/os/user/user.go
src/path/filepath/path_plan9.go
src/path/filepath/path_unix.go
src/path/filepath/path_windows.go
src/path/filepath/symlink_windows.go
src/plugin/plugin.go
src/reflect/all_test.go
src/reflect/makefunc.go
src/reflect/type.go
src/reflect/value.go
src/runtime/HACKING.md
src/runtime/asm_amd64.s
src/runtime/asm_mipsx.s
src/runtime/cgo/asm_mipsx.s [new file with mode: 0644]
src/runtime/cgo/gcc_linux_mipsx.c [new file with mode: 0644]
src/runtime/cgo/gcc_mipsx.S [new file with mode: 0644]
src/runtime/cgocall.go
src/runtime/fastlog2.go
src/runtime/iface.go
src/runtime/malloc.go
src/runtime/malloc_test.go
src/runtime/memmove_amd64.s
src/runtime/memmove_test.go
src/runtime/mgc.go
src/runtime/mgcsweep.go
src/runtime/mksizeclasses.go
src/runtime/msan.go
src/runtime/mstats.go
src/runtime/os_linux.go
src/runtime/os_linux_arm.go
src/runtime/os_windows.go
src/runtime/panic.go
src/runtime/plugin.go
src/runtime/pprof/pprof.go
src/runtime/pprof/pprof_test.go
src/runtime/proc.go
src/runtime/rt0_linux_mipsx.s
src/runtime/runtime-gdb_test.go
src/runtime/runtime2.go
src/runtime/select.go
src/runtime/signal_unix.go
src/runtime/sizeclasses.go
src/runtime/stack.go
src/runtime/symtab.go
src/runtime/sys_dragonfly_amd64.s
src/runtime/sys_freebsd_amd64.s
src/runtime/sys_linux_386.s
src/runtime/sys_linux_amd64.s
src/runtime/sys_linux_mipsx.s
src/runtime/sys_netbsd_386.s
src/runtime/sys_netbsd_amd64.s
src/runtime/sys_openbsd_386.s
src/runtime/sys_openbsd_amd64.s
src/runtime/sys_openbsd_arm.s
src/runtime/testdata/testprogcgo/threadpprof.go
src/runtime/testdata/testprogcgo/traceback.go
src/runtime/tls_mipsx.s
src/runtime/traceback.go
src/runtime/type.go
src/syscall/mkpost.go
src/syscall/zsysnum_openbsd_386.go
src/syscall/zsysnum_openbsd_amd64.go
src/syscall/zsysnum_openbsd_arm.go
src/syscall/ztypes_linux_s390x.go
src/testing/benchmark.go
src/testing/sub_test.go
src/testing/testing.go
src/testing/testing_test.go
src/time/format.go
src/time/format_test.go
src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
src/vendor/golang_org/x/crypto/poly1305/sum_amd64.s
src/vendor/golang_org/x/crypto/poly1305/sum_arm.s
test/alias2.go [new file with mode: 0644]
test/alias3.dir/a.go [new file with mode: 0644]
test/alias3.dir/b.go [new file with mode: 0644]
test/alias3.dir/c.go [new file with mode: 0644]
test/alias3.go [new file with mode: 0644]
test/bench/go1/fasta_test.go
test/fixedbugs/bug501.go [new file with mode: 0644]
test/fixedbugs/gcc78763.go [new file with mode: 0644]
test/fixedbugs/issue10607.go
test/fixedbugs/issue10958.go [new file with mode: 0644]
test/fixedbugs/issue11656.go
test/fixedbugs/issue16130.go
test/fixedbugs/issue18392.go [new file with mode: 0644]
test/fixedbugs/issue18410.go [new file with mode: 0644]
test/fixedbugs/issue18459.go [new file with mode: 0644]
test/fixedbugs/issue18640.go [new file with mode: 0644]
test/fixedbugs/issue18655.go [new file with mode: 0644]
test/fixedbugs/issue18661.go [new file with mode: 0644]
test/fixedbugs/issue18725.go [new file with mode: 0644]
test/fixedbugs/issue18808.go [new file with mode: 0644]
test/fixedbugs/issue6772.go [new file with mode: 0644]
test/live.go
test/nilptr3.go
test/nosplit.go
test/opt_branchlikely.go
test/run.go
test/zerodivide.go

index 7173067a759c6f002a8e25510511d2e842c4dddb..552cf187ae83b5368a96d595c43bc84fb347629e 100644 (file)
@@ -18,28 +18,28 @@ _cgo_*
 _obj
 _test
 _testmain.go
-build.out
-test.out
-doc/articles/wiki/*.bin
-misc/cgo/life/run.out
-misc/cgo/stdio/run.out
-misc/cgo/testso/main
-src/cmd/cgo/zdefaultcc.go
-src/cmd/go/zdefaultcc.go
-src/cmd/go/zosarch.go
-src/cmd/internal/obj/zbootstrap.go
-src/go/build/zcgo.go
-src/go/doc/headscan
-src/runtime/internal/sys/zversion.go
-src/unicode/maketables
-src/*.*/
-test/pass.out
-test/run.out
-test/times.out
-test/garbage/*.out
-goinstall.log
-last-change
-VERSION.cache
 
-bin/
-pkg/
+/VERSION.cache
+/bin/
+/build.out
+/doc/articles/wiki/*.bin
+/goinstall.log
+/last-change
+/misc/cgo/life/run.out
+/misc/cgo/stdio/run.out
+/misc/cgo/testso/main
+/pkg/
+/src/*.*/
+/src/cmd/cgo/zdefaultcc.go
+/src/cmd/go/zdefaultcc.go
+/src/cmd/go/zosarch.go
+/src/cmd/internal/obj/zbootstrap.go
+/src/go/build/zcgo.go
+/src/go/doc/headscan
+/src/runtime/internal/sys/zversion.go
+/src/unicode/maketables
+/test.out
+/test/garbage/*.out
+/test/pass.out
+/test/run.out
+/test/times.out
diff --git a/AUTHORS b/AUTHORS
index cb487d57f29960a215a03ad1bffea1ba05f0e689..555ce0a424096204440d84e3016a99c252f7963a 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -29,11 +29,13 @@ Akshat Kumar <seed@mail.nanosouffle.net>
 Alan Shreve <alan@inconshreveable.com>
 Albert Nigmatzianov <albertnigma@gmail.com>
 Albert Strasheim <fullung@gmail.com>
+Albert Yu <yukinying@gmail.com>
 Alberto Bertogli <albertito@blitiri.com.ar>
 Alberto Donizetti <alb.donizetti@gmail.com>
 Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
 Aleksandar Dezelin <dezelin@gmail.com>
 Alessandro Arzilli <alessandro.arzilli@gmail.com>
+Alessandro Baffa <alessandro.baffa@gmail.com>
 Alex A Skinner <alex@lx.lc>
 Alex Brainman <alex.brainman@gmail.com>
 Alex Browne <stephenalexbrowne@gmail.com>
@@ -45,6 +47,7 @@ Alex Sergeyev <abc@alexsergeyev.com>
 Alexander Demakin <alexander.demakin@gmail.com>
 Alexander Döring <email@alexd.ch>
 Alexander Larsson <alexander.larsson@gmail.com>
+Alexander Menzhinsky <amenzhinsky@gmail.com>
 Alexander Morozov <lk4d4math@gmail.com>
 Alexander Neumann <alexander@bumpern.de>
 Alexander Orlov <alexander.orlov@loxal.net>
@@ -53,6 +56,7 @@ Alexander Surma <surma@surmair.de>
 Alexander Zhavnerchik <alex.vizor@gmail.com>
 Alexander Zolotov <goldifit@gmail.com>
 Alexandre Cesaro <alexandre.cesaro@gmail.com>
+Alexandre Fiori <fiorix@gmail.com>
 Alexandre Normand <alexandre.normand@gmail.com>
 Alexei Sholik <alcosholik@gmail.com>
 Alexey Borzenkov <snaury@gmail.com>
@@ -69,6 +73,7 @@ Andreas Auernhammer <aead@mail.de>
 Andreas Litt <andreas.litt@gmail.com>
 Andrei Korzhevskii <a.korzhevskiy@gmail.com>
 Andrei Vieru <euvieru@gmail.com>
+Andrew Austin <andrewaclt@gmail.com>
 Andrew Balholm <andybalholm@gmail.com>
 Andrew Bonventre <andybons@chromium.org>
 Andrew Bursavich <abursavich@gmail.com>
@@ -88,6 +93,7 @@ Andrey Petrov <andrey.petrov@shazow.net>
 Andriy Lytvynov <lytvynov.a.v@gmail.com>
 Andy Balholm <andy@balholm.com>
 Andy Davis <andy@bigandian.com>
+Andy Finkenstadt <afinkenstadt@zynga.com>
 Andy Maloney <asmaloney@gmail.com>
 Anfernee Yongkun Gui <anfernee.gui@gmail.com>
 Angelo Bulfone <mbulfone@gmail.com>
@@ -98,6 +104,8 @@ Anthony Canino <anthony.canino1@gmail.com>
 Anthony Eufemio <anthony.eufemio@gmail.com>
 Anthony Martin <ality@pbrane.org>
 Anthony Starks <ajstarks@gmail.com>
+Anthony Woods <awoods@raintank.io>
+Antonio Bibiano <antbbn@gmail.com>
 Apisak Darakananda <pongad@gmail.com>
 Aram Hăvărneanu <aram@mgk.ro>
 Areski Belaid <areski@gmail.com>
@@ -117,7 +125,9 @@ Aulus Egnatius Varialus <varialus@gmail.com>
 awaw fumin <awawfumin@gmail.com>
 Ayanamist Yang <ayanamist@gmail.com>
 Aymerick Jéhanne <aymerick@jehanne.org>
+Baiju Muthukadan <baiju.m.mail@gmail.com>
 Ben Burkert <ben@benburkert.com>
+Ben Lubar <ben.lubar@gmail.com>
 Ben Olive <sionide21@gmail.com>
 Benjamin Black <b@b3k.us>
 Benny Siegert <bsiegert@gmail.com>
@@ -163,6 +173,7 @@ Chris Jones <chris@cjones.org>
 Chris Kastorff <encryptio@gmail.com>
 Chris Lennert <calennert@gmail.com>
 Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
+Chris Stockton <chrisstocktonaz@gmail.com>
 Christian Couder <chriscool@tuxfamily.org>
 Christian Himpel <chressie@googlemail.com>
 Christine Hansmann <chhansmann@gmail.com>
@@ -258,6 +269,7 @@ Egon Elbre <egonelbre@gmail.com>
 Ehren Kret <ehren.kret@gmail.com>
 Eivind Uggedal <eivind@uggedal.com>
 Elias Naur <elias.naur@gmail.com>
+Elliot Morrison-Reed <elliotmr@gmail.com>
 Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se>
 Emmanuel Odeke <emm.odeke@gmail.com> <odeke@ualberta.ca>
 Empirical Interfaces Inc.
@@ -273,6 +285,7 @@ Erik St. Martin <alakriti@gmail.com>
 Erik Westrup <erik.westrup@gmail.com>
 Ernest Chiang <ernest_chiang@htc.com>
 Esko Luontola <esko.luontola@gmail.com>
+Euan Kemp <euank@euank.com>
 Evan Phoenix <evan@phx.io>
 Evan Shaw <chickencha@gmail.com>
 Ewan Chou <coocood@gmail.com>
@@ -328,6 +341,7 @@ Hajime Hoshi <hajimehoshi@gmail.com>
 Hari haran <hariharan.uno@gmail.com>
 Hariharan Srinath <srinathh@gmail.com>
 Harley Laue <losinggeneration@gmail.com>
+Harry Moreno <morenoh149@gmail.com>
 Harshavardhana <hrshvardhana@gmail.com>
 Håvard Haugen <havard.haugen@gmail.com>
 Hector Chu <hectorchu@gmail.com>
@@ -395,6 +409,7 @@ Jens Frederich <jfrederich@gmail.com>
 Jeremy Jackins <jeremyjackins@gmail.com>
 Jeroen Bobbeldijk <jerbob92@gmail.com>
 Jess Frazelle <me@jessfraz.com>
+Jesse Szwedko <jesse.szwedko@gmail.com>
 Jihyun Yu <yjh0502@gmail.com>
 Jim McGrath <jimmc2@gmail.com>
 Jimmy Zelinskie <jimmyzelinskie@gmail.com>
@@ -429,6 +444,8 @@ Jonathan Rudenberg <jonathan@titanous.com>
 Jonathan Wills <runningwild@gmail.com>
 Jongmin Kim <atomaths@gmail.com>
 Joonas Kuorilehto <joneskoo@derbian.fi>
+Joop Kiefte <ikojba@gmail.com> <joop@kiefte.net>
+Jordan Lewis <jordanthelewis@gmail.com>
 Jose Luis Vázquez González <josvazg@gmail.com>
 Joseph Holsten <joseph@josephholsten.com>
 Josh Bleecher Snyder <josharian@gmail.com>
@@ -450,6 +467,8 @@ Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
 Kang Hu <hukangustc@gmail.com>
 Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
 Katrina Owen <katrina.owen@gmail.com>
+Kaviraj Kanagaraj <kavirajkanagaraj@gmail.com>
+Keegan Carruthers-Smith <keegan.csmith@gmail.com>
 Kei Son <hey.calmdown@gmail.com>
 Keith Ball <inflatablewoman@gmail.com>
 Keith Rarick <kr@xph.us>
@@ -492,12 +511,15 @@ Luigi Riefolo <luigi.riefolo@gmail.com>
 Luit van Drongelen <luitvd@gmail.com>
 Luka Zakrajšek <tr00.g33k@gmail.com>
 Luke Curley <qpingu@gmail.com>
+Maksym Trykur <maksym.trykur@gmail.com>
 Mal Curtis <mal@mal.co.nz>
 Manfred Touron <m@42.am>
 Manu S Ajith <neo@codingarena.in>
 Manuel Mendez <mmendez534@gmail.com>
 Marc Weistroff <marc@weistroff.net>
+Marcel Edmund Franke <marcel.edmund.franke@gmail.com>
 Marco Hennings <marco.hennings@freiheit.com>
+Marin Bašić <marin.basic02@gmail.com>
 Mark Bucciarelli <mkbucc@gmail.com>
 Mark Severson <miquella@gmail.com>
 Mark Theunissen <mark.theunissen@gmail.com>
@@ -535,6 +557,8 @@ Matthew Denton <mdenton@skyportsystems.com>
 Matthew Holt <Matthew.Holt+git@gmail.com>
 Matthew Horsnell <matthew.horsnell@gmail.com>
 Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
+Matthieu Olivier <olivier.matthieu@gmail.com>
+Max Riveiro <kavu13@gmail.com>
 Maxim Khitrov <max@mxcrypt.com>
 Maxwell Krohn <themax@gmail.com>
 MediaMath, Inc
@@ -599,6 +623,7 @@ Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
 Nicholas Sullivan <nicholas.sullivan@gmail.com>
 Nicholas Waples <nwaples@gmail.com>
 Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
+Nick Leli <nicholasleli@gmail.com>
 Nick Patavalis <nick.patavalis@gmail.com>
 Nick Petroni <npetroni@cs.umd.edu>
 Nicolas Kaiser <nikai@nikai.net>
@@ -606,10 +631,12 @@ Nicolas Owens <mischief@offblast.org>
 Nicolas S. Dade <nic.dade@gmail.com>
 Niels Widger <niels.widger@gmail.com>
 Nigel Kerr <nigel.kerr@gmail.com>
+Nik Nyby <nnyby@columbia.edu>
 Niko Dziemba <niko@dziemba.com>
 Nikolay Turpitko <nikolay@turpitko.com>
 Noah Campbell <noahcampbell@gmail.com>
 Norberto Lopes <nlopes.ml@gmail.com>
+Odin Ugedal <odin@ugedal.com>
 Oleg Vakheta <helginet@gmail.com>
 Oleku Konko <oleku.konko@gmail.com>
 Oling Cat <olingcat@gmail.com>
@@ -630,6 +657,7 @@ Pascal S. de Kloe <pascal@quies.net>
 Patrick Crosby <patrick@stathat.com>
 Patrick Gavlin <pgavlin@gmail.com>
 Patrick Higgins <patrick.allen.higgins@gmail.com>
+Patrick Lee <pattyshack101@gmail.com>
 Patrick Mézard <patrick@mezard.eu>
 Patrick Mylund Nielsen <patrick@patrickmn.com>
 Patrick Smith <pat42smith@gmail.com>
@@ -673,9 +701,11 @@ Quentin Perez <qperez@ocs.online.net>
 Quoc-Viet Nguyen <afelion@gmail.com>
 RackTop Systems Inc.
 Radu Berinde <radu@cockroachlabs.com>
+Rafal Jeczalik <rjeczalik@gmail.com>
 Raif S. Naffah <go@naffah-raif.name>
 Rajat Goel <rajat.goel2010@gmail.com>
 Ralph Corderoy <ralph@inputplus.co.uk>
+Raphael Geronimi <raphael.geronimi@gmail.com>
 Red Hat, Inc.
 Reinaldo de Souza Jr <juniorz@gmail.com>
 Rémy Oudompheng <oudomphe@phare.normalesup.org>
@@ -706,10 +736,12 @@ Ron Minnich <rminnich@gmail.com>
 Ross Light <rlight2@gmail.com>
 Rowan Worth <sqweek@gmail.com>
 Russell Haering <russellhaering@gmail.com>
+Ryan Bagwell <ryanbagwell@outlook.com>
 Ryan Hitchman <hitchmanr@gmail.com>
 Ryan Lower <rpjlower@gmail.com>
 Ryan Seys <ryan@ryanseys.com>
 Ryan Slade <ryanslade@gmail.com>
+Ryuzo Yamamoto <ryuzo.yamamoto@gmail.com>
 S.Çağlar Onur <caglar@10ur.org>
 Salmān Aljammāz <s@0x65.net>
 Sam Hug <samuel.b.hug@gmail.com>
@@ -744,6 +776,7 @@ Simon Whitehead <chemnova@gmail.com>
 Sina Siadat <siadat@gmail.com>
 Sokolov Yura <funny.falcon@gmail.com>
 Song Gao <song@gao.io>
+Sourcegraph Inc
 Spencer Nelson <s@spenczar.com>
 Spring Mc <heresy.mc@gmail.com>
 Square, Inc.
@@ -767,6 +800,7 @@ Szabolcs Nagy <nsz@port70.net>
 Tad Glines <tad.glines@gmail.com>
 Taj Khattra <taj.khattra@gmail.com>
 Takeshi YAMANASHI <9.nashi@gmail.com>
+Takuya Ueda <uedatakuya@gmail.com>
 Tal Shprecher <tshprecher@gmail.com>
 Tamir Duberstein <tamird@gmail.com>
 Tarmigan Casebolt <tarmigan@gmail.com>
@@ -780,6 +814,7 @@ Thomas de Zeeuw <thomasdezeeuw@gmail.com>
 Thomas Desrosiers <thomasdesr@gmail.com>
 Thomas Kappler <tkappler@gmail.com>
 Thorben Krueger <thorben.krueger@gmail.com>
+Thordur Bjornsson <thorduri@secnorth.net>
 Tilman Dilo <tilman.dilo@gmail.com>
 Tim Cooijmans <timcooijmans@gmail.com>
 Tim Ebringer <tim.ebringer@gmail.com>
@@ -798,6 +833,7 @@ Totoro W <tw19881113@gmail.com>
 Travis Cline <travis.cline@gmail.com>
 Trey Lawrence <lawrence.trey@gmail.com>
 Trey Tacon <ttacon@gmail.com>
+Tristan Colgate <tcolgate@gmail.com>
 Tristan Ooohry <ooohry@gmail.com>
 Tudor Golubenco <tudor.g@gmail.com>
 Tuo Shan <sturbo89@gmail.com>
@@ -845,8 +881,10 @@ Yoshiyuki Kanno <nekotaroh@gmail.com> <yoshiyuki.kanno@stoic.co.jp>
 Yusuke Kagiwada <block.rxckin.beats@gmail.com>
 Yuusei Kuwana <kuwana@kumama.org>
 Yuval Pavel Zholkover <paulzhol@gmail.com>
+Zac Bergquist <zbergquist99@gmail.com>
 Zemanta d.o.o.
 Zev Goldstein <zev.goldstein@gmail.com>
 Ziad Hatahet <hatahet@gmail.com>
 Zorion Arrizabalaga <zorionk@gmail.com>
+Фахриддин Балтаев <faxriddinjon@gmail.com>
 申习之 <bronze1man@gmail.com>
index 4120daf281308f4cb325db0fab2df3d3fc00de17..9620d81a89f6bffe623d3abf4502972248ad920d 100644 (file)
@@ -7,6 +7,11 @@ It is the work of hundreds of contributors. We appreciate your help!
 
 ## Filing issues
 
+General questions should go to the
+[golang-nuts mailing list](https://groups.google.com/group/golang-nuts) or
+[other forum](https://golang.org/wiki/Questions) instead of the issue tracker.
+The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+
 When filing an issue, make sure to answer these five questions:
 
 1. What version of Go are you using (`go version`)?
@@ -15,8 +20,7 @@ When filing an issue, make sure to answer these five questions:
 4. What did you expect to see?
 5. What did you see instead?
 
-General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
-The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+For change proposals, see [Proposing Changes To Go](https://github.com/golang/proposal/).
 
 Sensitive security-related issues should be reported to [security@golang.org](mailto:security@golang.org).
 
@@ -28,6 +32,7 @@ before sending patches.
 **We do not accept GitHub pull requests**
 (we use [an instance](https://go-review.googlesource.com/) of the
 [Gerrit](https://www.gerritcodereview.com/) code review system instead).
+Also, please do not post patches on the issue tracker.
 
 Unless otherwise noted, the Go source files are distributed under
 the BSD-style license found in the LICENSE file.
index 43d1d9a0d4f063b123090a042b4940ba6176dd29..d410b36d6d398740443dac551ea1d16b027c4203 100644 (file)
@@ -55,11 +55,13 @@ Alan Donovan <adonovan@google.com>
 Alan Shreve <alan@inconshreveable.com>
 Albert Nigmatzianov <albertnigma@gmail.com>
 Albert Strasheim <fullung@gmail.com>
+Albert Yu <yukinying@gmail.com>
 Alberto Bertogli <albertito@blitiri.com.ar>
 Alberto Donizetti <alb.donizetti@gmail.com>
 Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
 Aleksandar Dezelin <dezelin@gmail.com>
 Alessandro Arzilli <alessandro.arzilli@gmail.com>
+Alessandro Baffa <alessandro.baffa@gmail.com>
 Alex A Skinner <alex@lx.lc>
 Alex Brainman <alex.brainman@gmail.com>
 Alex Bramley <abramley@google.com>
@@ -73,6 +75,7 @@ Alex Vaghin <crhyme@google.com>
 Alexander Demakin <alexander.demakin@gmail.com>
 Alexander Döring <email@alexd.ch>
 Alexander Larsson <alexander.larsson@gmail.com>
+Alexander Menzhinsky <amenzhinsky@gmail.com>
 Alexander Morozov <lk4d4math@gmail.com>
 Alexander Neumann <alexander@bumpern.de>
 Alexander Orlov <alexander.orlov@loxal.net>
@@ -81,6 +84,7 @@ Alexander Surma <surma@surmair.de>
 Alexander Zhavnerchik <alex.vizor@gmail.com>
 Alexander Zolotov <goldifit@gmail.com>
 Alexandre Cesaro <alexandre.cesaro@gmail.com>
+Alexandre Fiori <fiorix@gmail.com>
 Alexandre Normand <alexandre.normand@gmail.com>
 Alexandru Moșoi <brtzsnr@gmail.com>
 Alexei Sholik <alcosholik@gmail.com>
@@ -101,6 +105,7 @@ Andreas Litt <andreas.litt@gmail.com>
 Andrei Korzhevskii <a.korzhevskiy@gmail.com>
 Andrei Vieru <euvieru@gmail.com>
 Andres Erbsen <andreser@google.com>
+Andrew Austin <andrewaclt@gmail.com>
 Andrew Balholm <andybalholm@gmail.com>
 Andrew Bonventre <andybons@chromium.org>
 Andrew Bursavich <abursavich@gmail.com>
@@ -123,6 +128,7 @@ Andrey Petrov <andrey.petrov@shazow.net>
 Andriy Lytvynov <lytvynov.a.v@gmail.com>
 Andy Balholm <andy@balholm.com>
 Andy Davis <andy@bigandian.com>
+Andy Finkenstadt <afinkenstadt@zynga.com>
 Andy Maloney <asmaloney@gmail.com>
 Anfernee Yongkun Gui <anfernee.gui@gmail.com>
 Angelo Bulfone <mbulfone@gmail.com>
@@ -133,6 +139,8 @@ Anthony Canino <anthony.canino1@gmail.com>
 Anthony Eufemio <anthony.eufemio@gmail.com>
 Anthony Martin <ality@pbrane.org>
 Anthony Starks <ajstarks@gmail.com>
+Anthony Woods <awoods@raintank.io>
+Antonio Bibiano <antbbn@gmail.com>
 Antonio Murdaca <runcom@redhat.com>
 Apisak Darakananda <pongad@gmail.com>
 Aram Hăvărneanu <aram@mgk.ro>
@@ -155,10 +163,12 @@ Austin Clements <austin@google.com> <aclements@csail.mit.edu>
 awaw fumin <awawfumin@gmail.com>
 Ayanamist Yang <ayanamist@gmail.com>
 Aymerick Jéhanne <aymerick@jehanne.org>
+Baiju Muthukadan <baiju.m.mail@gmail.com>
 Balazs Lecz <leczb@google.com>
 Ben Burkert <ben@benburkert.com>
 Ben Eitzen <eitzenb@golang.org>
 Ben Fried <ben.fried@gmail.com>
+Ben Lubar <ben.lubar@gmail.com>
 Ben Lynn <benlynn@gmail.com>
 Ben Olive <sionide21@gmail.com>
 Benjamin Black <b@b3k.us>
@@ -233,6 +243,7 @@ Chris Kastorff <encryptio@gmail.com>
 Chris Lennert <calennert@gmail.com>
 Chris Manghane <cmang@golang.org>
 Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
+Chris Stockton <chrisstocktonaz@gmail.com>
 Chris Zou <chriszou@ca.ibm.com>
 Christian Couder <chriscool@tuxfamily.org>
 Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
@@ -305,6 +316,7 @@ David Glasser <glasser@meteor.com>
 David Howden <dhowden@gmail.com>
 David Hubbard <dsp@google.com>
 David Jakob Fritz <david.jakob.fritz@gmail.com>
+David Lazar <lazard@golang.org>
 David Leon Gil <coruus@gmail.com>
 David McLeish <davemc@google.com>
 David Presotto <presotto@gmail.com>
@@ -360,6 +372,7 @@ Egon Elbre <egonelbre@gmail.com>
 Ehren Kret <ehren.kret@gmail.com>
 Eivind Uggedal <eivind@uggedal.com>
 Elias Naur <elias.naur@gmail.com>
+Elliot Morrison-Reed <elliotmr@gmail.com>
 Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se>
 Emmanuel Odeke <emm.odeke@gmail.com> <odeke@ualberta.ca>
 Eoghan Sherry <ejsherry@gmail.com>
@@ -379,6 +392,7 @@ Ernest Chiang <ernest_chiang@htc.com>
 Esko Luontola <esko.luontola@gmail.com>
 Ethan Burns <eaburns@google.com>
 Ethan Miller <eamiller@us.ibm.com>
+Euan Kemp <euank@euank.com>
 Evan Broder <evan@stripe.com>
 Evan Brown <evanbrown@google.com>
 Evan Kroske <evankroske@google.com>
@@ -449,6 +463,7 @@ Han-Wen Nienhuys <hanwen@google.com>
 Hari haran <hariharan.uno@gmail.com>
 Hariharan Srinath <srinathh@gmail.com>
 Harley Laue <losinggeneration@gmail.com>
+Harry Moreno <morenoh149@gmail.com>
 Harshavardhana <hrshvardhana@gmail.com>
 Håvard Haugen <havard.haugen@gmail.com>
 Hector Chu <hectorchu@gmail.com>
@@ -470,6 +485,7 @@ Ian Gudger <ian@loosescre.ws>
 Ian Lance Taylor <iant@golang.org>
 Icarus Sparry <golang@icarus.freeuk.com>
 Idora Shinatose <idora.shinatose@gmail.com>
+Igor Bernstein <igorbernstein@google.com>
 Igor Dolzhikov <bluesriverz@gmail.com>
 Ilya Tocar <ilya.tocar@intel.com>
 INADA Naoki <songofacandy@gmail.com>
@@ -518,6 +534,7 @@ Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
 Jani Monoses <jani.monoses@ubuntu.com> <jani.monoses@gmail.com>
 Jaroslavas Počepko <jp@webmaster.ms>
 Jason Barnett <jason.w.barnett@gmail.com>
+Jason Buberel <jbuberel@google.com>
 Jason Del Ponte <delpontej@gmail.com>
 Jason Hall <jasonhall@google.com>
 Jason Smale <jsmale@zendesk.com>
@@ -537,6 +554,7 @@ Jeremy Jackins <jeremyjackins@gmail.com>
 Jeremy Schlatter <jeremy.schlatter@gmail.com>
 Jeroen Bobbeldijk <jerbob92@gmail.com>
 Jess Frazelle <me@jessfraz.com>
+Jesse Szwedko <jesse.szwedko@gmail.com>
 Jihyun Yu <yjh0502@gmail.com>
 Jim Cote <jfcote87@gmail.com>
 Jim Kingdon <jim@bolt.me>
@@ -586,6 +604,8 @@ Jonathan Rudenberg <jonathan@titanous.com>
 Jonathan Wills <runningwild@gmail.com>
 Jongmin Kim <atomaths@gmail.com>
 Joonas Kuorilehto <joneskoo@derbian.fi>
+Joop Kiefte <ikojba@gmail.com> <joop@kiefte.net>
+Jordan Lewis <jordanthelewis@gmail.com>
 Jos Visser <josv@google.com>
 Jose Luis Vázquez González <josvazg@gmail.com>
 Joseph Bonneau <jcb@google.com>
@@ -617,8 +637,10 @@ Kang Hu <hukangustc@gmail.com>
 Karan Dhiman <karandhi@ca.ibm.com>
 Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
 Katrina Owen <katrina.owen@gmail.com>
+Kaviraj Kanagaraj <kavirajkanagaraj@gmail.com>
 Kay Zhu <kayzhu@google.com>
 KB Sriram <kbsriram@google.com>
+Keegan Carruthers-Smith <keegan.csmith@gmail.com>
 Kei Son <hey.calmdown@gmail.com>
 Keith Ball <inflatablewoman@gmail.com>
 Keith Randall <khr@golang.org>
@@ -670,6 +692,7 @@ Luke Curley <qpingu@gmail.com>
 Luna Duclos <luna.duclos@palmstonegames.com>
 Luuk van Dijk <lvd@golang.org> <lvd@google.com>
 Lynn Boger <laboger@linux.vnet.ibm.com>
+Maksym Trykur <maksym.trykur@gmail.com>
 Mal Curtis <mal@mal.co.nz>
 Manfred Touron <m@42.am>
 Manoj Dayaram <platform-dev@moovweb.com> <manoj.dayaram@moovweb.com>
@@ -678,9 +701,11 @@ Manu S Ajith <neo@codingarena.in>
 Manuel Mendez <mmendez534@gmail.com>
 Marc Weistroff <marc@weistroff.net>
 Marc-Antoine Ruel <maruel@chromium.org>
+Marcel Edmund Franke <marcel.edmund.franke@gmail.com>
 Marcel van Lohuizen <mpvl@golang.org>
 Marco Hennings <marco.hennings@freiheit.com>
 Marga Manterola <marga@google.com>
+Marin Bašić <marin.basic02@gmail.com>
 Marius Nuennerich <mnu@google.com>
 Mark Bucciarelli <mkbucc@gmail.com>
 Mark Severson <miquella@gmail.com>
@@ -695,6 +720,7 @@ Markus Zimmermann <zimmski@gmail.com>
 Martin Bertschler <mbertschler@gmail.com>
 Martin Garton <garton@gmail.com>
 Martin Hamrle <martin.hamrle@gmail.com>
+Martin Kreichgauer <martinkr@google.com>
 Martin Möhrmann <moehrmann@google.com> <martisch@uos.de>
 Martin Neubauer <m.ne@gmx.net>
 Martin Olsson <martin@minimum.se>
@@ -723,6 +749,8 @@ Matthew Denton <mdenton@skyportsystems.com>
 Matthew Holt <Matthew.Holt+git@gmail.com>
 Matthew Horsnell <matthew.horsnell@gmail.com>
 Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
+Matthieu Olivier <olivier.matthieu@gmail.com>
+Max Riveiro <kavu13@gmail.com>
 Maxim Khitrov <max@mxcrypt.com>
 Maxim Pimenov <mpimenov@google.com>
 Maxim Ushakov <ushakov@google.com>
@@ -806,6 +834,7 @@ Nicholas Waples <nwaples@gmail.com>
 Nick Cooper <nmvc@google.com>
 Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
 Nick Harper <nharper@google.com>
+Nick Leli <nicholasleli@gmail.com>
 Nick Patavalis <nick.patavalis@gmail.com>
 Nick Petroni <npetroni@cs.umd.edu>
 Nicolas Kaiser <nikai@nikai.net>
@@ -814,11 +843,13 @@ Nicolas S. Dade <nic.dade@gmail.com>
 Niels Widger <niels.widger@gmail.com>
 Nigel Kerr <nigel.kerr@gmail.com>
 Nigel Tao <nigeltao@golang.org>
+Nik Nyby <nnyby@columbia.edu>
 Niko Dziemba <niko@dziemba.com>
 Nikolay Turpitko <nikolay@turpitko.com>
 Noah Campbell <noahcampbell@gmail.com>
 Nodir Turakulov <nodir@google.com>
 Norberto Lopes <nlopes.ml@gmail.com>
+Odin Ugedal <odin@ugedal.com>
 Oleg Vakheta <helginet@gmail.com>
 Oleku Konko <oleku.konko@gmail.com>
 Oling Cat <olingcat@gmail.com>
@@ -837,6 +868,7 @@ Pascal S. de Kloe <pascal@quies.net>
 Patrick Crosby <patrick@stathat.com>
 Patrick Gavlin <pgavlin@gmail.com>
 Patrick Higgins <patrick.allen.higgins@gmail.com>
+Patrick Lee <pattyshack101@gmail.com>
 Patrick Mézard <patrick@mezard.eu>
 Patrick Mylund Nielsen <patrick@patrickmn.com>
 Patrick Riley <pfr@google.com>
@@ -894,15 +926,19 @@ Quan Tran <qeed.quan@gmail.com>
 Quan Yong Zhai <qyzhai@gmail.com>
 Quentin Perez <qperez@ocs.online.net>
 Quentin Smith <quentin@golang.org>
+Quinn Slack <sqs@sourcegraph.com>
 Quoc-Viet Nguyen <afelion@gmail.com>
 Radu Berinde <radu@cockroachlabs.com>
+Rafal Jeczalik <rjeczalik@gmail.com>
 Rahul Chaudhry <rahulchaudhry@chromium.org>
 Raif S. Naffah <go@naffah-raif.name>
 Rajat Goel <rajat.goel2010@gmail.com>
 Ralph Corderoy <ralph@inputplus.co.uk>
 Ramesh Dharan <dharan@google.com>
 Raph Levien <raph@google.com>
+Raphael Geronimi <raphael.geronimi@gmail.com>
 Raul Silvera <rsilvera@google.com>
+Rebecca Stambler <rstambler@golang.org>
 Reinaldo de Souza Jr <juniorz@gmail.com>
 Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
 Rhys Hiltner <rhys@justin.tv>
@@ -943,12 +979,14 @@ Rowan Worth <sqweek@gmail.com>
 Rui Ueyama <ruiu@google.com>
 Russ Cox <rsc@golang.org>
 Russell Haering <russellhaering@gmail.com>
+Ryan Bagwell <ryanbagwell@outlook.com>
 Ryan Barrett <ryanb@google.com>
 Ryan Brown <ribrdb@google.com>
 Ryan Hitchman <hitchmanr@gmail.com>
 Ryan Lower <rpjlower@gmail.com>
 Ryan Seys <ryan@ryanseys.com>
 Ryan Slade <ryanslade@gmail.com>
+Ryuzo Yamamoto <ryuzo.yamamoto@gmail.com>
 S.Çağlar Onur <caglar@10ur.org>
 Sai Cheemalapati <saicheems@google.com>
 Salmān Aljammāz <s@0x65.net>
@@ -1012,6 +1050,7 @@ Stéphane Travostino <stephane.travostino@gmail.com>
 Stephen Ma <stephenm@golang.org>
 Stephen McQuay <stephen@mcquay.me>
 Stephen Weinberg <stephen@q5comm.com>
+Steve Francia <spf@golang.org>
 Steve McCoy <mccoyst@gmail.com>
 Steve Newman <snewman@google.com>
 Steve Phillips <elimisteve@gmail.com>
@@ -1029,6 +1068,7 @@ Tad Glines <tad.glines@gmail.com>
 Taj Khattra <taj.khattra@gmail.com>
 Takashi Matsuo <tmatsuo@google.com>
 Takeshi YAMANASHI <9.nashi@gmail.com>
+Takuya Ueda <uedatakuya@gmail.com>
 Tal Shprecher <tshprecher@gmail.com>
 Tamir Duberstein <tamird@gmail.com>
 Tarmigan Casebolt <tarmigan@gmail.com>
@@ -1044,6 +1084,7 @@ Thomas Desrosiers <thomasdesr@gmail.com>
 Thomas Habets <habets@google.com>
 Thomas Kappler <tkappler@gmail.com>
 Thorben Krueger <thorben.krueger@gmail.com>
+Thordur Bjornsson <thorduri@secnorth.net>
 Tilman Dilo <tilman.dilo@gmail.com>
 Tim Cooijmans <timcooijmans@gmail.com>
 Tim Ebringer <tim.ebringer@gmail.com>
@@ -1072,6 +1113,7 @@ Trevor Strohman <trevor.strohman@gmail.com>
 Trey Lawrence <lawrence.trey@gmail.com>
 Trey Tacon <ttacon@gmail.com>
 Tristan Amini <tamini01@ca.ibm.com>
+Tristan Colgate <tcolgate@gmail.com>
 Tristan Ooohry <ooohry@gmail.com>
 Tudor Golubenco <tudor.g@gmail.com>
 Tuo Shan <sturbo89@gmail.com> <shantuo@google.com>
@@ -1132,8 +1174,10 @@ Yusuke Kagiwada <block.rxckin.beats@gmail.com>
 Yuusei Kuwana <kuwana@kumama.org>
 Yuval Pavel Zholkover <paulzhol@gmail.com>
 Yves Junqueira <yvesj@google.com> <yves.junqueira@gmail.com>
+Zac Bergquist <zbergquist99@gmail.com>
 Zev Goldstein <zev.goldstein@gmail.com>
 Zhongwei Yao <zhongwei.yao@arm.com>
 Ziad Hatahet <hatahet@gmail.com>
 Zorion Arrizabalaga <zorionk@gmail.com>
+Фахриддин Балтаев <faxriddinjon@gmail.com>
 申习之 <bronze1man@gmail.com>
index 281deecdfbdf1ce4e02283a878de29becad2a5b5..672cdf55686a7754f78e383440a3d5915fae528e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -5,39 +5,37 @@ reliable, and efficient software.
 
 ![Gopher image](doc/gopher/fiveyears.jpg)
 
-For documentation about how to install and use Go,
-visit https://golang.org/ or load doc/install-source.html
-in your web browser.
-
 Our canonical Git repository is located at https://go.googlesource.com/go.
 There is a mirror of the repository at https://github.com/golang/go.
 
-Go is the work of hundreds of contributors. We appreciate your help!
+Unless otherwise noted, the Go source files are distributed under the
+BSD-style license found in the LICENSE file.
 
-To contribute, please read the contribution guidelines:
-       https://golang.org/doc/contribute.html
+### Download and Install
 
-##### Note that we do not accept pull requests and that we use the issue tracker for bug reports and proposals only. Please ask questions on https://forum.golangbridge.org or https://groups.google.com/forum/#!forum/golang-nuts.
+#### Binary Distributions
 
-Unless otherwise noted, the Go source files are distributed
-under the BSD-style license found in the LICENSE file.
+Official binary distributions are available at https://golang.org/dl/.
 
---
+After downloading a binary release, visit https://golang.org/doc/install
+or load doc/install.html in your web browser for installation
+instructions.
 
-## Binary Distribution Notes
+#### Install From Source
 
-If you have just untarred a binary Go distribution, you need to set
-the environment variable $GOROOT to the full path of the go
-directory (the one containing this file).  You can omit the
-variable if you unpack it into /usr/local/go, or if you rebuild
-from sources by running all.bash (see doc/install-source.html).
-You should also add the Go binary directory $GOROOT/bin
-to your shell's path.
+If a binary distribution is not available for your combination of
+operating system and architecture, visit
+https://golang.org/doc/install/source or load doc/install-source.html
+in your web browser for source installation instructions.
 
-For example, if you extracted the tar file into $HOME/go, you might
-put the following in your .profile:
+### Contributing
 
-       export GOROOT=$HOME/go
-       export PATH=$PATH:$GOROOT/bin
+Go is the work of hundreds of contributors. We appreciate your help!
+
+To contribute, please read the contribution guidelines:
+       https://golang.org/doc/contribute.html
 
-See https://golang.org/doc/install or doc/install.html for more details.
+Note that the Go project does not use GitHub pull requests, and that
+we use the issue tracker for bug reports and proposals only. See
+https://golang.org/wiki/Questions for a list of places to ask
+questions about the Go language.
index 2062cbf0da36a9832a17a6bc15a771aae01dbd0d..857ebb5d7d25cc5bb9572f4703afec2c14f1cfa6 100644 (file)
@@ -338,3 +338,7 @@ pkg unicode, const Version = "6.2.0"
 pkg unicode, const Version = "6.3.0"
 pkg unicode, const Version = "7.0.0"
 pkg unicode, const Version = "8.0.0"
+pkg syscall (openbsd-386), const SYS_KILL = 37
+pkg syscall (openbsd-386-cgo), const SYS_KILL = 37
+pkg syscall (openbsd-amd64), const SYS_KILL = 37
+pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37
index d93de98e1a2b459c15c32bf0ff99bbbbbe86952c..fca7e03c9f999b37bb14926ea93080fdb729b4b7 100644 (file)
@@ -73,10 +73,8 @@ pkg database/sql, const LevelSnapshot = 5
 pkg database/sql, const LevelSnapshot IsolationLevel
 pkg database/sql, const LevelWriteCommitted = 3
 pkg database/sql, const LevelWriteCommitted IsolationLevel
-pkg database/sql/driver, func IsolationFromContext(context.Context) (IsolationLevel, bool)
-pkg database/sql/driver, func ReadOnlyFromContext(context.Context) bool
-pkg database/sql/driver, type ConnBeginContext interface { BeginContext }
-pkg database/sql/driver, type ConnBeginContext interface, BeginContext(context.Context) (Tx, error)
+pkg database/sql/driver, type ConnBeginTx interface { BeginTx }
+pkg database/sql/driver, type ConnBeginTx interface, BeginTx(context.Context, TxOptions) (Tx, error)
 pkg database/sql/driver, type ConnPrepareContext interface { PrepareContext }
 pkg database/sql/driver, type ConnPrepareContext interface, PrepareContext(context.Context, string) (Stmt, error)
 pkg database/sql/driver, type ExecerContext interface { ExecContext }
@@ -125,16 +123,17 @@ pkg database/sql/driver, type StmtExecContext interface { ExecContext }
 pkg database/sql/driver, type StmtExecContext interface, ExecContext(context.Context, []NamedValue) (Result, error)
 pkg database/sql/driver, type StmtQueryContext interface { QueryContext }
 pkg database/sql/driver, type StmtQueryContext interface, QueryContext(context.Context, []NamedValue) (Rows, error)
-pkg database/sql, func IsolationContext(context.Context, IsolationLevel) context.Context
+pkg database/sql/driver, type TxOptions struct
+pkg database/sql/driver, type TxOptions struct, Isolation IsolationLevel
+pkg database/sql/driver, type TxOptions struct, ReadOnly bool
 pkg database/sql, func Named(string, interface{}) NamedArg
-pkg database/sql, func ReadOnlyContext(context.Context) context.Context
 pkg database/sql, method (*ColumnType) DatabaseTypeName() string
 pkg database/sql, method (*ColumnType) DecimalSize() (int64, int64, bool)
 pkg database/sql, method (*ColumnType) Length() (int64, bool)
 pkg database/sql, method (*ColumnType) Name() string
 pkg database/sql, method (*ColumnType) Nullable() (bool, bool)
 pkg database/sql, method (*ColumnType) ScanType() reflect.Type
-pkg database/sql, method (*DB) BeginContext(context.Context) (*Tx, error)
+pkg database/sql, method (*DB) BeginTx(context.Context, *TxOptions) (*Tx, error)
 pkg database/sql, method (*DB) ExecContext(context.Context, string, ...interface{}) (Result, error)
 pkg database/sql, method (*DB) PingContext(context.Context) error
 pkg database/sql, method (*DB) PrepareContext(context.Context, string) (*Stmt, error)
@@ -155,6 +154,9 @@ pkg database/sql, type IsolationLevel int
 pkg database/sql, type NamedArg struct
 pkg database/sql, type NamedArg struct, Name string
 pkg database/sql, type NamedArg struct, Value interface{}
+pkg database/sql, type TxOptions struct
+pkg database/sql, type TxOptions struct, Isolation IsolationLevel
+pkg database/sql, type TxOptions struct, ReadOnly bool
 pkg debug/pe, method (*COFFSymbol) FullName(StringTable) (string, error)
 pkg debug/pe, method (StringTable) String(uint32) (string, error)
 pkg debug/pe, type File struct, COFFSymbols []COFFSymbol
@@ -174,7 +176,6 @@ pkg expvar, method (*Float) Value() float64
 pkg expvar, method (Func) Value() interface{}
 pkg expvar, method (*Int) Value() int64
 pkg expvar, method (*String) Value() string
-pkg go/build, type NoGoError struct, Ignored bool
 pkg go/doc, func IsPredeclared(string) bool
 pkg go/types, func Default(Type) Type
 pkg go/types, func IdenticalIgnoreTags(Type, Type) bool
@@ -238,21 +239,23 @@ pkg plugin, type Symbol interface {}
 pkg reflect, func Swapper(interface{}) func(int, int)
 pkg runtime, func MutexProfile([]BlockProfileRecord) (int, bool)
 pkg runtime, func SetMutexProfileFraction(int) int
+pkg runtime, type MemStats struct, NumForcedGC uint32
 pkg sort, func Slice(interface{}, func(int, int) bool)
 pkg sort, func SliceIsSorted(interface{}, func(int, int) bool) bool
 pkg sort, func SliceStable(interface{}, func(int, int) bool)
 pkg syscall (linux-arm-cgo), func TimevalToNsec(Timeval) int64
 pkg syscall (linux-arm), func TimevalToNsec(Timeval) int64
+pkg syscall (openbsd-386), const SYS_KILL = 122
+pkg syscall (openbsd-386-cgo), const SYS_KILL = 122
+pkg syscall (openbsd-amd64), const SYS_KILL = 122
+pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 122
 pkg syscall (windows-386), const ERROR_DIR_NOT_EMPTY = 145
 pkg syscall (windows-386), const ERROR_DIR_NOT_EMPTY Errno
 pkg syscall (windows-amd64), const ERROR_DIR_NOT_EMPTY = 145
 pkg syscall (windows-amd64), const ERROR_DIR_NOT_EMPTY Errno
 pkg testing, func CoverMode() string
 pkg testing, func MainStart(testDeps, []InternalTest, []InternalBenchmark, []InternalExample) *M
-pkg testing, method (*B) Context() context.Context
 pkg testing, method (*B) Name() string
-pkg testing, method (*T) Context() context.Context
 pkg testing, method (*T) Name() string
-pkg testing, type TB interface, Context() context.Context
 pkg testing, type TB interface, Name() string
 pkg time, func Until(Time) Duration
index 3e03c548fd189b8c014f5fc0b443ccdad326ef39..79dc7df322fadb6a58b2674d5aadbb8a0db55e6f 100644 (file)
@@ -838,6 +838,44 @@ It is a scaled mode as on the x86, but the only scale allowed is <code>1</code>.
 
 </ul>
 
+<h3 id="mips">MIPS, MIPS64</h3>
+
+<p>
+General purpose registers are named <code>R0</code> through <code>R31</code>,
+floating point registers are <code>F0</code> through <code>F31</code>.
+</p>
+
+<p>
+<code>R30</code> is reserved to point to <code>g</code>.
+<code>R23</code> is used as a temporary register.
+</p>
+
+<p>
+In a <code>TEXT</code> directive, the frame size <code>$-4</code> for MIPS or
+<code>$-8</code> for MIPS64 instructs the linker not to save <code>LR</code>.
+</p>
+
+<p>
+<code>SP</code> refers to the virtual stack pointer.
+For the hardware register, use <code>R29</code>.
+</p>
+
+<p>
+Addressing modes:
+</p>
+
+<ul>
+
+<li>
+<code>16(R1)</code>: The location at <code>R1</code> plus 16.
+</li>
+
+<li>
+<code>(R1)</code>: Alias for <code>0(R1)</code>.
+</li>
+
+</ul>
+
 <h3 id="unsupported_opcodes">Unsupported opcodes</h3>
 
 <p>
index 9978b523b422cdc12a7d6b5ae55f013e1b914a50..796431aa1445df252ec3725fd1b36155cd84ec8f 100644 (file)
@@ -160,9 +160,13 @@ $ <b>export GOPATH=$(go env GOPATH)</b>
 </pre>
 
 <p>
-To learn more about setting up the <code>GOPATH</code> environment variable,
-please see
-<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>'go help gopath'</code></a>
+To learn more about the <code>GOPATH</code> environment variable, see
+<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>'go help gopath'</code></a>.
+</p>
+
+<p>
+To use a custom workspace location,
+<a href="https://golang.org/wiki/SettingGOPATH">set the <code>GOPATH</code> environment variable</a>.
 </p>
 
 <h3 id="ImportPaths">Import paths</h3>
index c7492662481495ee3ac7d47755d467e8e5f5fdfb..5b81681c107de0c1ba96a1ae7dd8d7b60bc04f93 100644 (file)
@@ -67,7 +67,6 @@ official forums operated by the Go project (“Go spaces”):
     <li>The <a href="https://groups.google.com/group/golang-nuts">golang-nuts</a> and
         <a href="https://groups.google.com/group/golang-dev">golang-dev</a> mailing lists.
 <li>The #go-nuts IRC channel on Freenode.
-<li>The <a href="https://reddit.com/r/golang">/r/golang subreddit</a>.
 </ul>
 
 <p>
index bcf7b25c51158057b0c868050327cbf3ac8a30b0..f1a5b2799858966c51a19111e11369d5a34584db 100644 (file)
@@ -698,7 +698,7 @@ These files will be periodically updated based on the commit logs.
 <p>Code that you contribute should use the standard copyright header:</p>
 
 <pre>
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2017 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.
 </pre>
index 52a6e76723e94b7b4743268db132dc213c91ec84..f0e65ea29126c0904086d338a7424b68b64b0897 100644 (file)
@@ -4,7 +4,8 @@
 }-->
 
 <p><i>
-This applies to the <code>gc</code> toolchain. Gccgo has native gdb support.
+This applies to the standard toolchain (the <code>gc</code> Go
+compiler and tools). Gccgo has native gdb support.
 Besides this overview you might want to consult the
 <a href="http://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
 </i></p>
@@ -49,6 +50,14 @@ when debugging, pass the flags <code>-gcflags "-N -l"</code> to the
 debugged.
 </p>
 
+<p>
+If you want to use gdb to inspect a core dump, you can trigger a dump
+on a program crash, on systems that permit it, by setting
+<code>GOTRACEBACK=crash</code> in the environment (see the
+<a href="/pkg/runtime/#hdr-Environment_Variables"> runtime package
+documentation</a> for more info).
+</p>
+
 <h3 id="Common_Operations">Common Operations</h3>
 
 <ul>
@@ -130,7 +139,7 @@ the DWARF code.
 
 <p>
 If you're interested in what the debugging information looks like, run
-'<code>objdump -W 6.out</code>' and browse through the <code>.debug_*</code>
+'<code>objdump -W a.out</code>' and browse through the <code>.debug_*</code>
 sections.
 </p>
 
@@ -377,7 +386,9 @@ $3 = struct hchan&lt;*testing.T&gt;
 </pre>
 
 <p>
-That <code>struct hchan&lt;*testing.T&gt;</code> is the runtime-internal representation of a channel.  It is currently empty, or gdb would have pretty-printed it's contents.
+That <code>struct hchan&lt;*testing.T&gt;</code> is the
+runtime-internal representation of a channel. It is currently empty,
+or gdb would have pretty-printed its contents.
 </p>
 
 <p>
index 51957dff281788b9f6bb83793e53d69f2b6e9ff9..be340a35fdac58d2bed49a4c29ad7aec7aefc326 100644 (file)
@@ -69,6 +69,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.4">Go
 1.7.4 milestone</a> on our issue tracker for details.
 </p>
 
+<p>
+go1.7.5 (released 2017/01/26) includes fixes to the compiler, runtime,
+and the <code>crypto/x509</code> and <code>time</code> packages.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.5">Go
+1.7.5 milestone</a> on our issue tracker for details.
+</p>
+
 <h2 id="go1.6">go1.6 (released 2016/02/17)</h2>
 
 <p>
index 7166a76507420b47a0650fea436de547d79f83b0..e17461db2465dcf97a8695f899cac791afe25831 100644 (file)
@@ -519,7 +519,7 @@ Other changes:
        fix FreeBSD signal handling around thread creation (thanks Devon H. O'Dell),
        goroutine profile, stack dumps,
        implement runtime.osyield on FreeBSD 386, amd64 (thanks Devon H. O'Dell),
-       permit default behaviour of SIGTSTP, SIGTTIN, SIGTTOU,
+       permit default behavior of SIGTSTP, SIGTTIN, SIGTTOU,
        release unused memory to the OS (thanks Sébastien Paolacci),
        remove an obsolete file (thanks Mikio Hara).
 * spec: make all comparison results untyped bool,
@@ -4157,7 +4157,7 @@ Other changes in this release:
 * suffixarray: use binary search for both ends of Lookup (thanks Eric Eisner).
 * syscall: add missing network interface constants (thanks Mikio Hara).
 * template: treat map keys as zero, not non-existent (thanks Roger Peppe).
-* time: allow cancelling of After events (thanks Roger Peppe),
+* time: allow canceling of After events (thanks Roger Peppe),
         support Solaris zoneinfo directory.
 * token/position: added SetLinesForContent.
 * unicode: update to unicode 6.0.0.
@@ -5696,7 +5696,7 @@ This release contains many changes:
 * cmath: new complex math library (thanks Charles L. Dorian).
 * docs: update to match current coding style (thanks Christopher Wedgwood).
 * exp/eval: fix example and add target to Makefile (thanks Evan Shaw).
-* fmt: change behaviour of format verb %b to match %x when negative (thanks Andrei Vieru).
+* fmt: change behavior of format verb %b to match %x when negative (thanks Andrei Vieru).
 * gc: compile s == "" as len(s) == 0,
        distinguish fatal compiler bug from error+exit,
        fix alignment on non-amd64,
index ef27fd1818265128e808900067fe71b47072dea1..4f6a911541f0430dc5c4b91c60b1937971112ed1 100644 (file)
@@ -52,6 +52,19 @@ user libraries.  The Go 1.4 runtime is not fully merged, but that
 should not be visible to Go programs.
 </p>
 
+<p>
+The GCC 6 releases include a complete implementation of the Go 1.6.1
+user libraries.  The Go 1.6 runtime is not fully merged, but that
+should not be visible to Go programs.
+</p>
+
+<p>
+The GCC 7 releases are expected to include a complete implementation
+of the Go 1.8 user libraries.  As with earlier releases, the Go 1.8
+runtime is not fully merged, but that should not be visible to Go
+programs.
+</p>
+
 <h2 id="Source_code">Source code</h2>
 
 <p>
@@ -160,23 +173,6 @@ make
 make install
 </pre>
 
-<h3 id="Ubuntu">A note on Ubuntu</h3>
-
-<p>
-Current versions of Ubuntu and versions of GCC before 4.8 disagree on
-where system libraries and header files are found.  This is not a
-gccgo issue.  When building older versions of GCC, setting these
-environment variables while configuring and building gccgo may fix the
-problem.
-</p>
-
-<pre>
-LIBRARY_PATH=/usr/lib/x86_64-linux-gnu
-C_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
-CPLUS_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
-export LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH
-</pre>
-
 <h2 id="Using_gccgo">Using gccgo</h2>
 
 <p>
@@ -364,12 +360,15 @@ or with C++ code compiled using <code>extern "C"</code>.
 <h3 id="Types">Types</h3>
 
 <p>
-Basic types map directly: an <code>int</code> in Go is an <code>int</code>
-in C, an <code>int32</code> is an <code>int32_t</code>,
-etc.  Go <code>byte</code> is equivalent to C <code>unsigned
-char</code>.
-Pointers in Go are pointers in C. A Go <code>struct</code> is the same as C
-<code>struct</code> with the same fields and types.
+Basic types map directly: an <code>int32</code> in Go is
+an <code>int32_t</code> in C, an <code>int64</code> is
+an <code>int64_t</code>, etc.
+The Go type <code>int</code> is an integer that is the same size as a
+pointer, and as such corresponds to the C type <code>intptr_t</code>.
+Go <code>byte</code> is equivalent to C <code>unsigned char</code>.
+Pointers in Go are pointers in C.
+A Go <code>struct</code> is the same as C <code>struct</code> with the
+same fields and types.
 </p>
 
 <p>
@@ -380,7 +379,7 @@ structure (this is <b style="color: red;">subject to change</b>):
 <pre>
 struct __go_string {
   const unsigned char *__data;
-  int __length;
+  intptr_t __length;
 };
 </pre>
 
@@ -400,8 +399,8 @@ A slice in Go is a structure.  The current definition is
 <pre>
 struct __go_slice {
   void *__values;
-  int __count;
-  int __capacity;
+  intptr_t __count;
+  intptr_t __capacity;
 };
 </pre>
 
@@ -526,15 +525,3 @@ This procedure is full of unstated caveats and restrictions and we make no
 guarantee that it will not change in the future. It is more useful as a
 starting point for real Go code than as a regular procedure.
 </p>
-
-<h2 id="RTEMS_Port">RTEMS Port</h2>
-<p>
-The gccgo compiler has been ported to <a href="http://www.rtems.com/">
-<code>RTEMS</code></a>. <code>RTEMS</code> is a real-time executive
-that provides a high performance environment for embedded applications
-on a range of processors and embedded hardware. The current gccgo
-port is for x86. The goal is to extend the port to most of the
-<a href="http://www.rtems.org/wiki/index.php/SupportedCPUs">
-architectures supported by <code>RTEMS</code></a>. For more information on the port,
-as well as instructions on how to install it, please see this
-<a href="http://www.rtems.org/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
index 04818872287bd42bfe36e89046ab2fc72ecff018..af56ae6b3af1782581b2cbda7a910e9a5151b3f4 100644 (file)
@@ -86,10 +86,15 @@ have firmware that doesn't enable kernel FPU emulation; Go won't run on such mac
 On DragonFly BSD, Go now requires DragonFly 4.4.4 or later. <!-- CL 29491, CL 29971 -->
 </p>
 
+<p>
+On OpenBSD, Go now requires OpenBSD 5.9 or later. <!-- CL 34093 -->
+</p>
+
 <p>
 The Plan 9 port's networking support is now much more complete
 and matches the behavior of Unix and Windows with respect to deadlines
-and cancelation.
+and cancelation. For Plan 9 kernel requirements, see the
+<a href="https://golang.org/wiki/Plan9">Plan 9 wiki page</a>.
 </p>
 
 <p>
@@ -101,8 +106,9 @@ and cancelation.
 <p>
   Go 1.8 will be the last release to support Linux on ARMv5E and ARMv6 processors:
   Go 1.9 will likely require the ARMv6K (as found in the Raspberry Pi 1) or later.
-  To identify whether a Linux system is ARMv6K or later, run <code>go tool dist -check-armv6k</code>
-  (to facilitate testing, it is also possible to just copy the dist command to the
+  To identify whether a Linux system is ARMv6K or later, run
+  “<code>go</code> <code>tool</code> <code>dist</code> <code>-check-armv6k</code>”
+  (to facilitate testing, it is also possible to just copy the <code>dist</code> command to the
   system without installing a full copy of Go 1.8)
   and if the program terminates with output "ARMv6K supported." then the system
   implements ARMv6K or later.
@@ -133,8 +139,9 @@ For 64-bit x86 systems, the following instructions have been added:
 <code>MOVSHDUP</code>,
 <code>MOVSLDUP</code>,
 <code>VMOVDDUP</code>,
-<code>VMOVSHDUP</code>,
-and <code>VMOVSLDUP</code>.</p>
+<code>VMOVSHDUP</code>, and
+<code>VMOVSLDUP</code>.
+</p>
 
 <p>
 For 64-bit PPC systems, the common vector scalar instructions have been
@@ -216,7 +223,7 @@ added:
 <code>XXSEL</code>,
 <code>XXSI</code>,
 <code>XXSLDWI</code>,
-<code>XXSPLT</code>, and 
+<code>XXSPLT</code>, and
 <code>XXSPLTW</code>.
 </p>
 
@@ -224,8 +231,8 @@ added:
 
 <p> <!-- CL 27324, CL 27325 -->
 The <code>yacc</code> tool (previously available by running
-“<code>go</code> <code>tool</code> <code>yacc</code>”)
-has been removed. As of Go 1.7 it was no longer used by the Go compiler.
+“<code>go</code> <code>tool</code> <code>yacc</code>”) has been removed.
+As of Go 1.7 it was no longer used by the Go compiler.
 It has moved to the “tools” repository and is now available at
 <code><a href="https://godoc.org/golang.org/x/tools/cmd/goyacc">golang.org/x/tools/cmd/goyacc</a></code>.
 </p>
@@ -242,7 +249,7 @@ It has moved to the “tools” repository and is now available at
 
 <p> <!-- CL 33157 -->
   The <code>pprof</code> tool can now profile TLS servers
-  and skip certificate validation by using the "<code>https+insecure</code>"
+  and skip certificate validation by using the “<code>https+insecure</code>”
   URL scheme.
 </p>
 
@@ -250,37 +257,32 @@ It has moved to the “tools” repository and is now available at
   The callgrind output now has instruction-level granularity.
 </p>
 
-<p>
-  TODO: more. proto? standalone profiles with symbols?
-<pre>
-runtime/pprof: output CPU profiles in pprof protobuf format (CL 33071)
-runtime/pprof: write profiles in protobuf format. (CL 32257)
-</pre>
-</p>
-
 <h3 id="tool_trace">Trace</h3>
 
-<p>TODO:</p>
-<pre>
-cmd/trace: add option to output pprof files (CL 23324)
-cmd/trace: fix a runnable goroutine count bug (CL 25552)
-cmd/trace: move process-wide GC events to their own row (CL 30017)
-internal/trace: fix analysis of EvGoWaiting/EvGoInSyscall events (CL 25572)
-cmd/trace: annotate different mark worker types (CL 30702)
-</pre>
+<p> <!-- CL 23324 -->
+  The <code>trace</code> tool has a new <code>-pprof</code> flag for
+  producing pprof-compatible blocking and latency profiles from an
+  execution trace.
+</p>
+
+<p> <!-- CL 30017, CL 30702 -->
+  Garbage collection events are now shown more clearly in the
+  execution trace viewer. Garbage collection activity is shown on its
+  own row and GC helper goroutines are annotated with their roles.
+</p>
 
 <h3 id="tool_vet">Vet</h3>
 
 <p>Vet is stricter in some ways and looser where it
   previously caused false positives.</p>
 
-<p>Vet now checks copying of array of locks,
+<p>Vet now checks for copying an array of locks,
   duplicate JSON and XML struct field tags,
   non-space-separated struct tags,
   deferred calls to HTTP <code>Response.Body.Close</code>
-  before checking errors,
-  indexed arguments in <code>Printf</code>,
-  and improves existing checks.</p>
+  before checking errors, and
+  indexed arguments in <code>Printf</code>.
+  It also improves existing checks.</p>
 </p>
 
 <h3 id="compiler">Compiler Toolchain</h3>
@@ -299,14 +301,14 @@ and provides a better platform for optimizations
 such as bounds check elimination.
 The new back end reduces the CPU time required by
 <a href="https://golang.org/test/bench/go1/">our benchmark programs</a> by 20-30%
-on 32-bit ARM systems. For 64-bit x86 systems, which already used the SSA backend in
+on 32-bit ARM systems. For 64-bit x86 systems, which already used the SSA back end in
 Go 1.7, the gains are a more modest 0-10%. Other architectures will likely
 see improvements closer to the 32-bit ARM numbers.
 </p>
 
 <p>
   The temporary <code>-ssa=0</code> compiler flag introduced in Go 1.7
-  to disable the new backend has been removed in Go 1.8.
+  to disable the new back end has been removed in Go 1.8.
 </p>
 
 <p>
@@ -326,9 +328,21 @@ see improvements closer to the 32-bit ARM numbers.
 
 <h3 id="cmd_cgo">Cgo</h3>
 
+<p> <!-- CL 31141 -->
+The Go tool now remembers the value of the <code>CGO_ENABLED</code> environment
+variable set during <code>make.bash</code> and applies it to all future compilations
+by default to fix issue <a href="https://golang.org/issue/12808">#12808</a>.
+When doing native compilation, it is rarely necessary to explicitly set
+the <code>CGO_ENABLED</code> environment variable as <code>make.bash</code>
+will detect the correct setting automatically. The main reason to explicitly
+set the <code>CGO_ENABLED</code> environment variable is when your environment
+supports cgo, but you explicitly do not want cgo support, in which case, set
+<code>CGO_ENABLED=0</code> during <code>make.bash</code> or <code>all.bash</code>.
+</p>
+
 <p> <!-- CL 29991 -->
 The environment variable <code>PKG_CONFIG</code> may now be used to
-set the program to run to handle <code>#cgo pkg-config</code>
+set the program to run to handle <code>#cgo</code> <code>pkg-config</code>
 directives.  The default is <code>pkg-config</code>, the program
 always used by earlier releases.  This is intended to make it easier
 to cross-compile
@@ -378,12 +392,21 @@ version of gccgo.
   <code>%USERPROFILE%/go</code> on Windows.
 </p>
 
+<h3 id="go_get">Go get</h3>
+
+<p> <!-- CL 34818 -->
+  The “<code>go</code> <code>get</code>” command now always respects
+  HTTP proxy environment variables, regardless of whether
+  the <code style='white-space:nowrap'>-insecure</code> flag is used. In previous releases, the
+  <code style='white-space:nowrap'>-insecure</code> flag had the side effect of not using proxies.
+</p>
+
 <h3 id="go_bug">Go bug</h3>
 
 <p>
   The new
-  “<a href="/cmd/go/#hdr-Print_information_for_bug_reports"><code>go</code>
-   <code>bug</code></a>” command starts a bug report on GitHub, prefilled
+  “<a href="/cmd/go/#hdr-Print_information_for_bug_reports"><code>go</code> <code>bug</code></a>”
+  command starts a bug report on GitHub, prefilled
   with information about the current system.
 </p>
 
@@ -391,9 +414,8 @@ version of gccgo.
 
 <p> <!-- CL 25419 -->
   The
-  “<a href="/cmd/go/#hdr-Show_documentation_for_package_or_symbol"><code>go</code>
-   <code>doc</code></a>” command
-  now groups constants and variables with their type,
+  “<a href="/cmd/go/#hdr-Show_documentation_for_package_or_symbol"><code>go</code> <code>doc</code></a>”
+  command now groups constants and variables with their type,
   following the behavior of
   <a href="/cmd/godoc/"><code>godoc</code></a>.
 </p>
@@ -413,11 +435,11 @@ version of gccgo.
 <h3 id="plugin">Plugins</h3>
 
 <p>
-  Go now supports a “<code>plugin</code>” build mode for generating
-  plugins written in Go, and a
+  Go now provides early support for plugins with a “<code>plugin</code>”
+  build mode for generating plugins written in Go, and a
   new <a href="/pkg/plugin/"><code>plugin</code></a> package for
-  loading such plugins at run time. Plugin support is only currently
-  available on Linux and macOS.
+  loading such plugins at run time. Plugin support is currently only
+  available on Linux. Please report any issues.
 </p>
 
 <h2 id="runtime">Runtime</h2>
@@ -465,7 +487,7 @@ and give more detail.
 <h3 id="memstats">MemStats Documentation</h3>
 
 <p> <!-- CL 28972 -->
-  The runtime's <a href="/pkg/runtime/#MemStats"><code>MemStats</code></a>
+  The <a href="/pkg/runtime/#MemStats"><code>runtime.MemStats</code></a>
   type has been more thoroughly documented.
 </p>
 
@@ -503,7 +525,7 @@ There have been optimizations to implementations in the
 <a href="/pkg/strings/"><code>strings</code></a>,
 <a href="/pkg/syscall/"><code>syscall</code></a>,
 <a href="/pkg/text/template/"><code>text/template</code></a>, and
-<a href="/pkg/unicode/utf8/"><code>unicode/utf8</code></a>,
+<a href="/pkg/unicode/utf8/"><code>unicode/utf8</code></a>
 packages.
 </p>
 
@@ -595,9 +617,6 @@ now implements the new
     takes a context argument.</li>
   <li>There have been <a href="#database_sql">significant additions</a> to the
     <a href="/pkg/database/sql/">database/sql</a> package with context support.</li>
-  <li>The new <a href="/pkg/testing/#T.Context"><code>T.Context</code></a>
-    method in the <a href="/pkg/testing/">testing</a> package now returns a context for
-    the active test or benchmark.</li>
   <li>All nine of the new <code>Lookup</code> methods on the new
     <a href="/pkg/net/#Resolver"><code>net.Resolver</code></a> now
     take a context.</li>
@@ -611,7 +630,7 @@ now implements the new
 
 <p>
   Most users will want to use the new <code>-mutexprofile</code>
-  flag with <a href="/cmd/go/#hdr-Description_of_testing_flags"><code>go</code> <code>test</code></a>,
+  flag with “<a href="/cmd/go/#hdr-Description_of_testing_flags"><code>go</code> <code>test</code></a>”,
   and then use <a href="/cmd/pprof/">pprof</a> on the resultant file.
 </p>
 
@@ -622,13 +641,20 @@ now implements the new
   <a href="/pkg/runtime/#SetMutexProfileFraction"><code>SetMutexProfileFraction</code></a>.
 </p>
 
+<p>
+  A known limitation for Go 1.8 is that the profile only reports contention for
+  <a href="/pkg/sync/#Mutex"><code>sync.Mutex</code></a>,
+  not 
+  <a href="/pkg/sync/#RWMutex"><code>sync.RWMutex</code></a>.
+</p>
+
 <h3 id="minor_library_changes">Minor changes to the library</h3>
 
 <p>
 As always, there are various minor changes and updates to the library,
 made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
-in mind. The follow sections list the user visible changes and additions.
-Optimizations and bug fixes are not listed.
+in mind. The following sections list the user visible changes and additions.
+Optimizations and minor bug fixes are not listed.
 </p>
 
 <dl id="archive_tar"><dt><a href="/pkg/archive/tar/">archive/tar</a></dt>
@@ -645,23 +671,6 @@ Optimizations and bug fixes are not listed.
   </dd>
 </dl>
 
-<dl id="archive_zip"><dt><a href="/pkg/archive/zip/">archive/zip</a></dt>
-  <dd>
-
-    <p> <!-- CL 18274 -->
-      The
-      <a href="/pkg/archive/zip/#Reader"><code>Reader</code></a>
-      now supports modification times in
-      the NTFS, UNIX, and Extended Time Stamp metadata fields.
-      <!-- CL 30811 -->
-      The
-      <a href="/pkg/archive/zip/#Writer"><code>Writer</code></a>
-      now writes Extended Time Stamp fields.
-    </p>
-
-  </dd>
-</dl>
-
 <dl id="compress_flate"><dt><a href="/pkg/compress/flate/">compress/flate</a></dt>
   <dd>
 
@@ -669,11 +678,11 @@ Optimizations and bug fixes are not listed.
       There have been some minor fixes to the encoder to improve the
       compression ratio in certain situations. As a result, the exact
       encoded output of <code>DEFLATE</code> may be different from Go 1.7. Since
-      DEFLATE is the underlying compression of gzip, png, zlib, and zip,
+      <code>DEFLATE</code> is the underlying compression of gzip, png, zlib, and zip,
       those formats may have changed outputs.
     </p>
 
-    <p>
+    <p> <!-- CL 31174 -->
       The encoder, when operating in
       <a href="/pkg/compress/flate/#NoCompression"><code>NoCompression</code></a>
       mode, now produces a consistent output that is not dependent on
@@ -794,17 +803,12 @@ Optimizations and bug fixes are not listed.
       AES-128-CBC cipher suites with SHA-256 are also
       now supported.
     </p>
-    
+
   </dd>
 </dl>
 
 <dl id="crypto_x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
   <dd>
-    <p> <!-- CL 30578 -->
-      <a href="/pkg/crypto/x509/#SystemCertPool"><code>SystemCertPool</code></a>
-      is now implemented on Windows.
-    </p>
-
     <p> <!-- CL 24743 -->
       PSS signatures are now supported.
     </p>
@@ -835,87 +839,86 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       at <code>/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem</code>
       on Linux, to support RHEL and CentOS.
     </p>
-    
+
   </dd>
 </dl>
-    
+
 <dl id="database_sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
   <dd>
     <p>
-         The package now supports <code>context.Context</code>. There are new methods
-         ending in <code>Context</code> such as
-         <a href="/pkg/database/sql/#DB.QueryContext"><code>DB.QueryContext</code></a> and
-         <a href="/pkg/database/sql/#DB.PrepareContext"><code>DB.PrepareContext</code></a>
-         that take context arguments. Using the new <code>Context</code> methods ensures that
-         connections are closed and returned to the connection pool when the
-         request is done; enables canceling in-progress queries
-         should the driver support that; and allows the database
-         pool to cancel waiting for the next available connection.
+      The package now supports <code>context.Context</code>. There are new methods
+      ending in <code>Context</code> such as
+      <a href="/pkg/database/sql/#DB.QueryContext"><code>DB.QueryContext</code></a> and
+      <a href="/pkg/database/sql/#DB.PrepareContext"><code>DB.PrepareContext</code></a>
+      that take context arguments. Using the new <code>Context</code> methods ensures that
+      connections are closed and returned to the connection pool when the
+      request is done; enables canceling in-progress queries
+      should the driver support that; and allows the database
+      pool to cancel waiting for the next available connection.
     </p>
     <p>
       The <a href="/pkg/database/sql#IsolationLevel"><code>IsolationLevel</code></a>
-         can now be set when starting a transaction by setting the isolation level
-         on the <code>Context</code> then passing that <code>Context</code> to
-         <a href="/pkg/database/sql#DB.BeginContext"><code>DB.BeginContext</code></a>.
-         An error will be returned if an isolation level is selected that the driver
-         does not support. A read-only attribute may also be set on the transaction
-         with <a href="/pkg/database/sql/#ReadOnlyContext"><code>ReadOnlyContext</code></a>.
-       </p>
-       <p>
+      can now be set when starting a transaction by setting the isolation level
+      on <a href="/pkg/database/sql#TxOptions.Isolation"><code>TxOptions.Isolation</code></a> and passing
+      it to <a href="/pkg/database/sql#DB.BeginTx"><code>DB.BeginTx</code></a>.
+      An error will be returned if an isolation level is selected that the driver
+      does not support. A read-only attribute may also be set on the transaction
+      by setting <a href="/pkg/database/sql/#TxOptions.ReadOnly"><code>TxOptions.ReadOnly</code></a>
+      to true.
+    </p>
+    <p>
       Queries now expose the SQL column type information for drivers that support it.
-         Rows can return <a href="/pkg/database/sql#Rows.ColumnTypes"><code>ColumnTypes</code></a>
-         which can include SQL type information, column type lengths, and the Go type.
-    </p>
-       <p>
-          A <a href="/pkg/database/sql/#Rows"><code>Rows</code></a>
-          can now represent multiple result sets. After
-         <a href="/pkg/database/sql/#Rows.Next"><code>Rows.Next</code></a> returns false,
-         <a href="/pkg/database/sql/#Rows.NextResultSet"><code>Rows.NextResultSet</code></a>
-         may be called to advance to the next result set. The existing <code>Rows</code>
-         should continue to be used after it advances to the next result set.
-    </p>
-       <p>
-         <a href="/pkg/database/sql/#NamedArg"><code>NamedArg</code></a> may be used
-         as query arguments. The new function <a href="/pkg/database/sql/#Named"><code>Named</code></a>
-         helps create a <a href="/pkg/database/sql/#NamedArg"><code>NamedArg</code></a>
-         more succinctly.
-       <p>
-          If a driver supports the new
-          <a href="/pkg/database/sql/driver/#Pinger"><code>Pinger</code></a>
-          interface, the <code>DB</code>'s
-         <a href="/pkg/database/sql/#DB.Ping"><code>DB.Ping</code></a>
-         and
-          <a href="/pkg/database/sql/#DB.PingContext"><code>DB.PingContext</code></a>
-          methods will use that interface to check whether a
-          database connection is still valid.
-       </p>
+      Rows can return <a href="/pkg/database/sql#Rows.ColumnTypes"><code>ColumnTypes</code></a>
+      which can include SQL type information, column type lengths, and the Go type.
+    </p>
+    <p>
+      A <a href="/pkg/database/sql/#Rows"><code>Rows</code></a>
+      can now represent multiple result sets. After
+      <a href="/pkg/database/sql/#Rows.Next"><code>Rows.Next</code></a> returns false,
+      <a href="/pkg/database/sql/#Rows.NextResultSet"><code>Rows.NextResultSet</code></a>
+      may be called to advance to the next result set. The existing <code>Rows</code>
+      should continue to be used after it advances to the next result set.
+      </p>
+    <p>
+      <a href="/pkg/database/sql/#NamedArg"><code>NamedArg</code></a> may be used
+      as query arguments. The new function <a href="/pkg/database/sql/#Named"><code>Named</code></a>
+      helps create a <a href="/pkg/database/sql/#NamedArg"><code>NamedArg</code></a>
+      more succinctly.
+    <p>
+      If a driver supports the new
+      <a href="/pkg/database/sql/driver/#Pinger"><code>Pinger</code></a>
+      interface, the
+      <a href="/pkg/database/sql/#DB.Ping"><code>DB.Ping</code></a>
+      and
+      <a href="/pkg/database/sql/#DB.PingContext"><code>DB.PingContext</code></a>
+      methods will use that interface to check whether a
+      database connection is still valid.
+    </p>
     <p>
-         The new <code>Context</code> query methods work for all drivers, but
-         <code>Context</code> cancelation is not responsive unless the driver has been
-         updated to use them. The other features require driver support in
-         <a href="/pkg/database/sql/driver"><code>database/sql/driver</code></a>.
-         Driver authors should review the new interfaces. Users of existing
-         driver should review the driver documentation to see what
-         it supports and any system specific documentation on each feature.
-       </p>
+      The new <code>Context</code> query methods work for all drivers, but
+      <code>Context</code> cancelation is not responsive unless the driver has been
+      updated to use them. The other features require driver support in
+      <a href="/pkg/database/sql/driver"><code>database/sql/driver</code></a>.
+      Driver authors should review the new interfaces. Users of existing
+      driver should review the driver documentation to see what
+      it supports and any system specific documentation on each feature.
+    </p>
   </dd>
 </dl>
 
 <dl id="debug_pe"><dt><a href="/pkg/debug/pe/">debug/pe</a></dt>
   <dd>
     <p> <!-- CL 22720, CL 27212, CL 22181, CL 22332, CL 22336, Issue 15345 -->
-      The package has been fleshed out and is now used by <a href="/cmd/link/">the Go linker</a>.
-      New are
-      <a href="/pkg/debug/pe/#Reloc"><code>Reloc</code></a>,
-      <a href="/pkg/debug/pe/#Section"><code>Section</code></a>,
-      <a href="/pkg/debug/pe/#StringTable"><code>StringTable</code></a>,
-      the method
-      <a href="/pkg/debug/pe/#COFFSymbol.FullName"><code>COFFSymbol.FullName</code></a>,
+      The package has been extended and is now used by
+      <a href="/cmd/link/">the Go linker</a> to read <code>gcc</code>-generated object files.
+      The new
+      <a href="/pkg/debug/pe/#File.StringTable"><code>File.StringTable</code></a>
       and
-      <a href="/pkg/debug/pe/#File"><code>File</code></a>
-      fields
-      <a href="/pkg/debug/pe/#File.COFFSymbols"><code>COFFSymbols</code></a> and
-      <a href="/pkg/debug/pe/#File.StringTable"><code>StringTable</code></a>.
+      <a href="/pkg/debug/pe/#Section.Relocs"><code>Section.Relocs</code></a>
+      fields provide access to the COFF string table and COFF relocations.
+      The new
+      <a href="/pkg/debug/pe/#File.COFFSymbols"><code>File.COFFSymbols</code></a>
+      allows low-level access to the COFF symbol table.
       </p>
   </dd>
 </dl>
@@ -969,7 +972,6 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
     </p>
 
     <p> <!-- CL 30944 -->
-
       In previous versions of Go, unmarshaling a JSON <code>null</code> into an
       <a href="/pkg/encoding/json/#Unmarshaler"><code>Unmarshaler</code></a>
       was considered a no-op; now the <code>Unmarshaler</code>'s
@@ -1101,7 +1103,7 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       <a href="/pkg/math/big/#Int.ModInverse"><code>Int.ModInverse</code></a>
       now supports negative numbers.
     </p>
-    
+
   </dd>
 </dl>
 
@@ -1128,9 +1130,9 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
     <a href="/pkg/mime/#ParseMediaType"><code>ParseMediaType</code></a>
     now preserves unnecessary backslash escapes as literals,
     in order to support MSIE.
-    When MSIE sends a full file path (in "intranet mode"), it does not
-    escape backslashes: <code>"C:\dev\go\foo.txt"</code>, not
-    <code>"C:\\dev\\go\\foo.txt"</code>.
+    When MSIE sends a full file path (in “intranet mode”), it does not
+    escape backslashes: “<code>C:\dev\go\foo.txt</code>”, not
+    “<code>C:\\dev\\go\\foo.txt</code>”.
     If we see an unnecessary backslash escape, we now assume it is from MSIE
     and intended as a literal backslash.
     No known MIME generators emit unnecessary backslash escapes
@@ -1162,7 +1164,7 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
 
 <dl id="net"><dt><a href="/pkg/net/">net</a></dt>
   <dd>
-    
+
     <p><!-- CL 30164, CL 33473 -->
       The <a href="/pkg/net/#Conn"><code>Conn</code></a> documentation
       has been updated to clarify expectations of an interface
@@ -1183,8 +1185,8 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
     </p>
 
     <p><!-- CL 29951 -->
-      The new <a href="/pkg/net/#Buffers"><code>Buffers</code></a> types permits
-      more efficiently writing to the network from multiple discontiguous buffers
+      The new <a href="/pkg/net/#Buffers"><code>Buffers</code></a> type permits
+      writing to the network more efficiently from multiple discontiguous buffers
       in memory. On certain machines, for certain types of connections,
       this is optimized into an OS-specific batch write operation (such as <code>writev</code>).
     </p>
@@ -1201,8 +1203,8 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
     </p>
 
     <p><!-- CL 29233, CL 24901 -->
-      The Go DNS resolver now supports <code>resolv.conf</code>'s "<code>rotate</code>"
-      and "<code>option ndots:0</code>" options. The "<code>ndots</code>" option is
+      The Go DNS resolver now supports <code>resolv.conf</code>'s “<code>rotate</code>”
+      and “<code>option</code> <code>ndots:0</code>” options. The “<code>ndots</code>” option is
       now respected in the same way as <code>libresolve</code>.
     </p>
 
@@ -1229,7 +1231,7 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
         <a href="/pkg/net/http/#ServeContent"><code>ServeContent</code></a>
         now support HTTP <code>If-Match</code> conditional requests,
         in addition to the previous <code>If-None-Match</code>
-        support.
+        support for ETags properly formatted according to RFC 7232, section 2.3.
       </li>
     </ul>
 
@@ -1249,11 +1251,11 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
         existing <a href="/pkg/net/http/#CloseNotifier"><code>CloseNotifier</code></a>
         support. This functionality requires that the underlying
         <a href="/pkg/net/#Conn"><code>net.Conn</code></a> implements
-        <a href="#net">recently-clarified interface documentation</a>.
+        <a href="#net">recently clarified interface documentation</a>.
       </li>
 
       <li><!-- CL 32479 -->
-        To serve trailers known after the header has been written,
+        To serve trailers produced after the header has already been written,
         see the new
         <a href="/pkg/net/http/#TrailerPrefix"><code>TrailerPrefix</code></a>
         mechanism.
@@ -1280,7 +1282,7 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
 
     <p>Client &amp; Transport changes:</p>
     <ul>
-      <li><!-- CL 28930 -->
+      <li><!-- CL 28930, CL 31435 -->
         The <a href="/pkg/net/http/#Client"><code>Client</code></a>
         now copies most request headers on redirect. See
         <a href="/pkg/net/http/#Client">the documentation</a>
@@ -1294,9 +1296,17 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       </li>
 
       <li><!-- CL 31733, CL 29852 -->
-        The <code>Client</code> now supports 307 and 308 redirects.
-        If the redirect requires resending the request body,
-        the request must have the new
+        The <code>Client</code> now supports 301, 307, and 308 redirects.
+
+        For example, <code>Client.Post</code> now follows 301
+        redirects, converting them to <code>GET</code> requests
+        without bodies, like it did for 302 and 303 redirect responses
+        previously.
+
+        The <code>Client</code> now also follows 307 and 308
+        redirects, preserving the original request method and body, if
+        any. If the redirect requires resending the request body, the
+        request must have the new
         <a href="/pkg/net/http/#Request"><code>Request.GetBody</code></a>
         field defined.
         <a href="pkg/net/http/#NewRequest"><code>NewRequest</code></a>
@@ -1311,7 +1321,8 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
 
       <li><!-- CL 27117 -->
         The <code>Transport</code> will now retry non-idempotent
-        requests if no bytes were written before a network failure.
+        requests if no bytes were written before a network failure
+        and the request has no body.
       </li>
 
       <li><!-- CL 32481 -->
@@ -1324,9 +1335,25 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       <li> <!-- CL 28077 -->
         The <a href="/pkg/net/http/#DefaultTransport"><code>DefaultTransport.Dialer</code></a>
         now enables <code>DualStack</code> ("<a href="https://tools.ietf.org/html/rfc6555">Happy Eyeballs</a>") support,
-        to use IPv4 as a backup if it looks like IPv6 might be
+        allowing the use of IPv4 as a backup if it looks like IPv6 might be
         failing.
       </li>
+
+      <li> <!-- CL 31726 -->
+        The <a href="/pkg/net/http/#Transport"><code>Transport</code></a>
+        no longer reads a byte of a non-nil
+        <a href="/pkg/net/http/#Request.Body"><code>Request.Body</code></a>
+        when the
+        <a href="/pkg/net/http/#Request.ContentLength"><code>Request.ContentLength</code></a>
+        is zero to determine whether the <code>ContentLength</code>
+        is actually zero or just undefined.
+        To explicitly signal that a body has zero length,
+        either set it to <code>nil</code>, or set it to the new value
+        <a href="/pkg/net/http/#NoBody"><code>NoBody</code></a>.
+        The new <code>NoBody</code> value is intended for use by <code>Request</code>
+        constructor functions; it is used by
+        <a href="/pkg/net/http/#NewRequest"><code>NewRequest</code></a>.
+      </li>
     </ul>
 
   </dd>
@@ -1350,9 +1377,9 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
     The <a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a>
     has a new optional hook,
     <a href="/pkg/net/http/httputil/#ReverseProxy.ModifyResponse"><code>ModifyResponse</code></a>,
-    for modifying the response from the backend before proxying it to the client.
+    for modifying the response from the back end before proxying it to the client.
     </p>
-    
+
   </dd>
 </dl>
 
@@ -1362,7 +1389,7 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
     <p> <!-- CL 32176 -->
       Empty quoted strings are once again allowed in the name part of
       an address. That is, Go 1.4 and earlier accepted
-      <code>"" &lt;gopher@example.com&gt;</code>,
+      <code>""</code> <code>&lt;gopher@example.com&gt;</code>,
       but Go 1.5 introduced a bug that rejected this address.
       The address is recognized again.
     </p>
@@ -1377,7 +1404,7 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       allows parsing dates found in other
       header lines, such as the <code>Resent-Date:</code> header.
     </p>
-    
+
   </dd>
 </dl>
 
@@ -1385,10 +1412,10 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
   <dd>
 
     <p> <!-- CL 33143 -->
-      If an implementation of
-      the <a href="/pkg/net/smtp/#Auth"><code>Auth</code></a>
-      interface's <code>Start</code> method returns an
-      empty <code>toServer</code> value, the package no longer sends
+      If an implementation of the
+      <a href="/pkg/net/smtp/#Auth"><code>Auth.Start</code></a>
+      method returns an empty <code>toServer</code> value,
+      the package no longer sends
       trailing whitespace in the SMTP <code>AUTH</code> command,
       which some servers rejected.
     </p>
@@ -1399,14 +1426,17 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
 <dl id="net_url"><dt><a href="/pkg/net/url/">net/url</a></dt>
   <dd>
 
-    <p> <!-- CL 31322 --> The new functions
+    <p> <!-- CL 31322 -->
+      The new functions
       <a href="/pkg/net/url/#PathEscape"><code>PathEscape</code></a>
       and
       <a href="/pkg/net/url/#PathUnescape"><code>PathUnescape</code></a>
       are similar to the query escaping and unescaping functions but
-      for path elements.</p>
+      for path elements.
+    </p>
 
-    <p> <!-- CL 28933 --> The new methods
+    <p> <!-- CL 28933 -->
+      The new methods
       <a href="/pkg/net/url/#URL.Hostname"><code>URL.Hostname</code></a>
       and
       <a href="/pkg/net/url/#URL.Port"><code>URL.Port</code></a>
@@ -1414,7 +1444,8 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       correctly handling the case where the port may not be present.
     </p>
 
-    <p> <!-- CL 28343 --> The existing method
+    <p> <!-- CL 28343 -->
+      The existing method
       <a href="/pkg/net/url/#URL.ResolveReference"><code>URL.ResolveReference</code></a>
       now properly handles paths with escaped bytes without losing
       the escaping.
@@ -1433,7 +1464,7 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       now rejects URLs like <code>this_that:other/thing</code> instead of
       interpreting them as relative paths (<code>this_that</code> is not a valid scheme).
       To force interpretation as a relative path,
-      such URLs should be prefixed with <code>"./"</code>.
+      such URLs should be prefixed with “<code>./</code>”.
       The <code>URL.String</code> method now inserts this prefix as needed.
     </p>
 
@@ -1442,7 +1473,7 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
 
 <dl id="os"><dt><a href="/pkg/os/">os</a></dt>
   <dd>
-    <p>
+    <p> <!-- CL 16551 -->
       The new function
       <a href="/pkg/os/#Executable"><code>Executable</code></a> returns
       the path name of the running executable.
@@ -1463,12 +1494,12 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       existing empty directory.
       Previously it would fail when renaming to a non-empty directory
       but succeed when renaming to an empty directory.
-      This makes the behavior on Unix correspond to that on other systems.
+      This makes the behavior on Unix correspond to that of other systems.
     </p>
 
     <p> <!-- CL 32451 -->
       On Windows, long absolute paths are now transparently converted to
-      extended-length paths (paths that start with <code>\\?\</code>).
+      extended-length paths (paths that start with “<code>\\?\</code>”).
       This permits the package to work with files whose path names are
       longer than 260 characters.
     </p>
@@ -1493,16 +1524,15 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
 <dl id="path_filepath"><dt><a href="/pkg/path/filepath/">path/filepath</a></dt>
   <dd>
     <p>
-    <p>A number of bugs and corner cases on Windows were fixed:
-      <a href="/pkg/path/filepath/#Abs"><code>Abs</code></a> now calls <code>Clean</code> paths as documented,
+      A number of bugs and corner cases on Windows were fixed:
+      <a href="/pkg/path/filepath/#Abs"><code>Abs</code></a> now calls <code>Clean</code> as documented,
       <a href="/pkg/path/filepath/#Glob"><code>Glob</code></a> now matches
-      "<code>\\?\c:\*</code>",
+      “<code>\\?\c:\*</code>”,
       <a href="/pkg/path/filepath/#EvalSymlinks"><code>EvalSymlinks</code></a> now
-      correctly handles "<code>C:.</code>", and
+      correctly handles “<code>C:.</code>”, and
       <a href="/pkg/path/filepath/#Clean"><code>Clean</code></a> now properly
-      handles a leading "<code>..</code>" in the path.
-    <p>
-
+      handles a leading “<code>..</code>” in the path.
+    </p>
   </dd>
 </dl>
 
@@ -1584,9 +1614,9 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       June 31 and July 32.
     </p>
 
-    <p> <!-- CL 33029 -->
+    <p> <!-- CL 33029 --> <!-- CL 34816 -->
       The <code>tzdata</code> database has been updated to version
-      2016i for systems that don't already have a local time zone
+      2016j for systems that don't already have a local time zone
       database.
     </p>
 
@@ -1603,14 +1633,6 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       test or benchmark.
     </p>
 
-    <p><!-- CL 31724 -->
-      The new method
-      <a href="/pkg/testing/#T.Context"><code>T.Context</code></a>
-      (and <code>B.Context</code>) returns
-      a <a href="/pkg/context/#Context"><code>Context</code></a> for
-      the current running test or benchmark.
-    </p>
-
     <p><!-- CL 32483 -->
       The new function
       <a href="/pkg/testing/#CoverMode"><code>CoverMode</code></a>
@@ -1623,15 +1645,26 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       Previously, individual test cases would appear to pass,
       and only the overall execution of the test binary would fail.
     </p>
-   
+
+    <p><!-- CL 32455 -->
+      The signature of the
+      <a href="/pkg/testing/#MainStart"><code>MainStart</code></a>
+      function has changed, as allowed by the documentation. It is an
+      internal detail and not part of the Go 1 compatibility promise.
+      If you're not calling <code>MainStart</code> directly but see
+      errors, that likely means you set the
+      normally-empty <code>GOROOT</code> environment variable and it
+      doesn't match the version of your <code>go</code> command's binary.
+    </p>
+
   </dd>
 </dl>
 
 <dl id="unicode"><dt><a href="/pkg/unicode/">unicode</a></dt>
   <dd>
     <p><!-- CL 30935 -->
-      <code>SimpleFold</code> now returns its argument unchanged
-      if the provided input was an invalid rune.
+      <a href="/pkg/unicode/#SimpleFold"><code>SimpleFold</code></a>
+      now returns its argument unchanged if the provided input was an invalid rune.
       Previously, the implementation failed with an index bounds check panic.
     </p>
   </dd>
index e66ad387f3994dad85ffb4986ceb1f41c9bc70cd..caa9a728f804ca94e2f859f68387802d7c13265e 100644 (file)
@@ -29,7 +29,6 @@ cmd/link: fix -buildmode=pie / -linkshared combination (CL 28996)
 cmd/link: for -buildmode=exe pass -no-pie to external linker (CL 33106)
 cmd/link: insert trampolines for too-far jumps on ARM (CL 29397)
 cmd/link: non-executable stack support for Solaris (CL 24142)
-cmd/link: plugin support on darwin/amd64 (CL 29394)
 cmd/link: put text at address 0x1000000 on darwin/amd64 (CL 32185)
 cmd/link: remove the -shared flag (CL 28852)
 cmd/link: split large elf text sections on ppc64x (CL 27790)
index 5872eefb03f3d9ad7c8241a4d228711f6f24ca1c..c71126d25d8ddc676e4212dbb1d2b321d9ce68a7 100644 (file)
@@ -1,6 +1,6 @@
 <!--{
        "Title": "The Go Programming Language Specification",
-       "Subtitle": "Version of November 18, 2016",
+       "Subtitle": "Version of January 31, 2017",
        "Path": "/ref/spec"
 }-->
 
@@ -738,7 +738,7 @@ The method set of any other type <code>T</code> consists of all
 The method set of the corresponding <a href="#Pointer_types">pointer type</a> <code>*T</code>
 is the set of all methods declared with receiver <code>*T</code> or <code>T</code>
 (that is, it also contains the method set of <code>T</code>).
-Further rules apply to structs containing anonymous fields, as described
+Further rules apply to structs containing embedded fields, as described
 in the section on <a href="#Struct_types">struct types</a>.
 Any other type has an empty method set.
 In a method set, each method must have a
@@ -947,16 +947,16 @@ Moreover, the inner slices must be initialized individually.
 <p>
 A struct is a sequence of named elements, called fields, each of which has a
 name and a type. Field names may be specified explicitly (IdentifierList) or
-implicitly (AnonymousField).
+implicitly (EmbeddedField).
 Within a struct, non-<a href="#Blank_identifier">blank</a> field names must
 be <a href="#Uniqueness_of_identifiers">unique</a>.
 </p>
 
 <pre class="ebnf">
-StructType     = "struct" "{" { FieldDecl ";" } "}" .
-FieldDecl      = (IdentifierList Type | AnonymousField) [ Tag ] .
-AnonymousField = [ "*" ] TypeName .
-Tag            = string_lit .
+StructType    = "struct" "{" { FieldDecl ";" } "}" .
+FieldDecl     = (IdentifierList Type | EmbeddedField) [ Tag ] .
+EmbeddedField = [ "*" ] TypeName .
+Tag           = string_lit .
 </pre>
 
 <pre>
@@ -974,16 +974,15 @@ struct {
 </pre>
 
 <p>
-A field declared with a type but no explicit field name is an <i>anonymous field</i>,
-also called an <i>embedded</i> field or an embedding of the type in the struct.
-An embedded type must be specified as
+A field declared with a type but no explicit field name is called an <i>embedded field</i>.
+An embedded field must be specified as
 a type name <code>T</code> or as a pointer to a non-interface type name <code>*T</code>,
 and <code>T</code> itself may not be
 a pointer type. The unqualified type name acts as the field name.
 </p>
 
 <pre>
-// A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
+// A struct with four embedded fields of types T1, *T2, P.T3 and *P.T4
 struct {
        T1        // field name is T1
        *T2       // field name is T2
@@ -1000,15 +999,15 @@ in a struct type:
 
 <pre>
 struct {
-       T     // conflicts with anonymous field *T and *P.T
-       *T    // conflicts with anonymous field T and *P.T
-       *P.T  // conflicts with anonymous field T and *T
+       T     // conflicts with embedded field *T and *P.T
+       *T    // conflicts with embedded field T and *P.T
+       *P.T  // conflicts with embedded field T and *T
 }
 </pre>
 
 <p>
 A field or <a href="#Method_declarations">method</a> <code>f</code> of an
-anonymous field in a struct <code>x</code> is called <i>promoted</i> if
+embedded field in a struct <code>x</code> is called <i>promoted</i> if
 <code>x.f</code> is a legal <a href="#Selectors">selector</a> that denotes
 that field or method <code>f</code>.
 </p>
@@ -1025,7 +1024,7 @@ promoted methods are included in the method set of the struct as follows:
 </p>
 <ul>
        <li>
-       If <code>S</code> contains an anonymous field <code>T</code>,
+       If <code>S</code> contains an embedded field <code>T</code>,
        the <a href="#Method_sets">method sets</a> of <code>S</code>
        and <code>*S</code> both include promoted methods with receiver
        <code>T</code>. The method set of <code>*S</code> also
@@ -1033,7 +1032,7 @@ promoted methods are included in the method set of the struct as follows:
        </li>
 
        <li>
-       If <code>S</code> contains an anonymous field <code>*T</code>,
+       If <code>S</code> contains an embedded field <code>*T</code>,
        the method sets of <code>S</code> and <code>*S</code> both
        include promoted methods with receiver <code>T</code> or
        <code>*T</code>.
@@ -1434,8 +1433,8 @@ literal structure and corresponding components have identical types. In detail:
        <li>Two struct types are identical if they have the same sequence of fields,
            and if corresponding fields have the same names, and identical types,
            and identical tags.
-           Two anonymous fields are considered to have the same name. Lower-case field
-           names from different packages are always different.</li>
+           <a href="#Exported_identifiers">Non-exported</a> field names from different
+           packages are always different.</li>
 
        <li>Two pointer types are identical if they have identical base types.</li>
 
@@ -1445,8 +1444,9 @@ literal structure and corresponding components have identical types. In detail:
            Parameter and result names are not required to match.</li>
 
        <li>Two interface types are identical if they have the same set of methods
-           with the same names and identical function types. Lower-case method names from
-           different packages are always different. The order of the methods is irrelevant.</li>
+           with the same names and identical function types.
+           <a href="#Exported_identifiers">Non-exported</a> method names from different
+           packages are always different. The order of the methods is irrelevant.</li>
 
        <li>Two map types are identical if they have identical key and value types.</li>
 
@@ -1891,7 +1891,7 @@ type NewMutex Mutex
 type PtrMutex *Mutex
 
 // The method set of *PrintableMutex contains the methods
-// Lock and Unlock bound to its anonymous field Mutex.
+// Lock and Unlock bound to its embedded field Mutex.
 type PrintableMutex struct {
        Mutex
 }
@@ -2492,13 +2492,13 @@ If <code>x</code> is a package name, see the section on
 A selector <code>f</code> may denote a field or method <code>f</code> of
 a type <code>T</code>, or it may refer
 to a field or method <code>f</code> of a nested
-<a href="#Struct_types">anonymous field</a> of <code>T</code>.
-The number of anonymous fields traversed
+<a href="#Struct_types">embedded field</a> of <code>T</code>.
+The number of embedded fields traversed
 to reach <code>f</code> is called its <i>depth</i> in <code>T</code>.
 The depth of a field or method <code>f</code>
 declared in <code>T</code> is zero.
 The depth of a field or method <code>f</code> declared in
-an anonymous field <code>A</code> in <code>T</code> is the
+an embedded field <code>A</code> in <code>T</code> is the
 depth of <code>f</code> in <code>A</code> plus one.
 </p>
 
index 644819106da5a3d7046c48c2b6f9ac89580932a4..62d9a4a6b6b97e4ddd0673039479d93670176896 100644 (file)
@@ -11,6 +11,9 @@
 
 <h3 id="mailinglist"><a href="https://groups.google.com/group/golang-nuts">Go Nuts Mailing List</a></h3>
 <p>
+Get help from Go users, and share your work on the official mailing list.
+</p>
+<p>
 Search the <a href="https://groups.google.com/group/golang-nuts">golang-nuts</a>
 archives and consult the <a href="/doc/go_faq.html">FAQ</a> and
 <a href="//golang.org/wiki">wiki</a> before posting.
@@ -18,12 +21,12 @@ archives and consult the <a href="/doc/go_faq.html">FAQ</a> and
 
 <h3 id="forum"><a href="https://forum.golangbridge.org/">Go Forum</a></h3>
 <p>
-The <a href="https://forum.golangbridge.org/">Go Forum</a> is an alternate discussion
+The <a href="https://forum.golangbridge.org/">Go Forum</a> is a discussion
 forum for Go programmers.
 </p>
 
 <h3 id="slack"><a href="https://blog.gopheracademy.com/gophers-slack-community/">Gopher Slack</a></h3>
-<p>Get live support from the official Go slack channel.</p>
+<p>Get live support from other users in the Go slack channel.</p>
 
 <h3 id="irc"><a href="irc:irc.freenode.net/go-nuts">Go IRC Channel</a></h3>
 <p>Get live support at <b>#go-nuts</b> on <b>irc.freenode.net</b>, the official
index 4bf0ba35fb8e852c7cb071d15853666143898b83..efe864cb1a3188fddf924667dbcea04a4c2818ce 100644 (file)
@@ -147,6 +147,9 @@ either the git branch <code>release-branch.go1.4</code> or
 which contains the Go 1.4 source code plus accumulated fixes
 to keep the tools running on newer operating systems.
 (Go 1.4 was the last distribution in which the tool chain was written in C.)
+After unpacking the Go 1.4 source, <code>cd</code> to
+the <code>src</code> subdirectory and run <code>make.bash</code> (or,
+on Windows, <code>make.bat</code>).
 </p>
 
 <p>
index d8e04b78c259cba8e790e9244e8d40b4bed11274..6bff75c5a06ac60649f29be63de7fdca852562bb 100644 (file)
@@ -246,12 +246,12 @@ Then build it with the <code>go</code> tool:
 </p>
 
 <pre class="testUnix">
-$ <b>cd $HOME/go/src/hello
+$ <b>cd $HOME/go/src/hello</b>
 $ <b>go build</b>
 </pre>
 
-<pre class="testWindows" style="display: none">
-C:\&gt; <b>cd %USERPROFILE%\go\src\hello<b>
+<pre class="testWindows">
+C:\&gt; <b>cd %USERPROFILE%\go\src\hello</b>
 C:\Users\Gopher\go\src\hello&gt; <b>go build</b>
 </pre>
 
@@ -267,7 +267,7 @@ $ <b>./hello</b>
 hello, world
 </pre>
 
-<pre class="testWindows" style="display: none">
+<pre class="testWindows">
 C:\Users\Gopher\go\src\hello&gt; <b>hello</b>
 hello, world
 </pre>
@@ -313,16 +313,10 @@ environment variables under Windows</a>.
 <h2 id="help">Getting help</h2>
 
 <p>
-For real-time help, ask the helpful gophers in <code>#go-nuts</code> on the
-<a href="http://freenode.net/">Freenode</a> IRC server.
+  For help, see the <a href="/help/">list of Go mailing lists, forums, and places to chat</a>.
 </p>
 
 <p>
-The official mailing list for discussion of the Go language is
-<a href="//groups.google.com/group/golang-nuts">Go Nuts</a>.
-</p>
-
-<p>
-Report bugs using the
-<a href="//golang.org/issue">Go issue tracker</a>.
+  Report bugs either by running “<b><code>go</code> <code>bug</code></b>”, or
+  manually at the <a href="https://golang.org/issue">Go issue tracker</a>.
 </p>
index b70788e7b430e1e6c18624d9eb4621d6603dd661..4297c5f545f4208d71aa9c10de9a2dc9ae9ceaec 100755 (executable)
@@ -8,8 +8,8 @@
 # Consult http://www.iana.org/time-zones for the latest versions.
 
 # Versions to use.
-CODE=2016i
-DATA=2016i
+CODE=2016j
+DATA=2016j
 
 set -e
 rm -rf work
index e12d6dccaf1ac66991f17385fe811e8cec5da7da..d33dc1d2732850506f8927aae9d0ba8e487dd783 100644 (file)
Binary files a/lib/time/zoneinfo.zip and b/lib/time/zoneinfo.zip differ
index debdbfe4c505b10902dc372cfc5e9f04f0643def..777104e512209892d4fa856d9d791ad972dc9a35 100644 (file)
@@ -23,6 +23,18 @@ int I17537(S17537 *p);
 const int F17537(const char **p) {
        return **p;
 }
+
+// Calling this function used to trigger an error from the C compiler
+// (issue 18298).
+void F18298(const void *const *p) {
+}
+
+// Test that conversions between typedefs work as they used to.
+typedef const void *T18298_1;
+struct S18298 { int i; };
+typedef const struct S18298 *T18298_2;
+void G18298(T18298_1 t) {
+}
 */
 import "C"
 
@@ -39,4 +51,8 @@ func test17537(t *testing.T) {
        if got, want := C.F17537(&p), C.int(17); got != want {
                t.Errorf("got %d, want %d", got, want)
        }
+
+       C.F18298(nil)
+       var v18298 C.T18298_2
+       C.G18298(C.T18298_1(v18298))
 }
index f3b1f4c1762d5665e0a13134517737cb81835739..3c600463f0335447f8a36c44fb20f607519f2b64 100644 (file)
@@ -22,6 +22,14 @@ import (
 )
 
 func test18146(t *testing.T) {
+       if runtime.GOOS == "darwin" {
+               t.Skipf("skipping flaky test on %s; see golang.org/issue/18202", runtime.GOOS)
+       }
+
+       if runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" {
+               t.Skipf("skipping on %s", runtime.GOARCH)
+       }
+
        attempts := 1000
        threads := 4
 
@@ -29,6 +37,31 @@ func test18146(t *testing.T) {
                attempts = 100
        }
 
+       // Restrict the number of attempts based on RLIMIT_NPROC.
+       // Tediously, RLIMIT_NPROC was left out of the syscall package,
+       // probably because it is not in POSIX.1, so we define it here.
+       // It is not defined on Solaris.
+       var nproc int
+       setNproc := true
+       switch runtime.GOOS {
+       default:
+               setNproc = false
+       case "linux":
+               nproc = 6
+       case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd":
+               nproc = 7
+       }
+       if setNproc {
+               var rlim syscall.Rlimit
+               if syscall.Getrlimit(nproc, &rlim) == nil {
+                       max := int(rlim.Cur) / (threads + 5)
+                       if attempts > max {
+                               t.Logf("lowering attempts from %d to %d for RLIMIT_NPROC", attempts, max)
+                               attempts = max
+                       }
+               }
+       }
+
        if os.Getenv("test18146") == "exec" {
                runtime.GOMAXPROCS(1)
                for n := threads; n > 0; n-- {
@@ -40,7 +73,7 @@ func test18146(t *testing.T) {
                }
                runtime.GOMAXPROCS(threads)
                argv := append(os.Args, "-test.run=NoSuchTestExists")
-               if err := syscall.Exec(os.Args[0], argv, nil); err != nil {
+               if err := syscall.Exec(os.Args[0], argv, os.Environ()); err != nil {
                        t.Fatal(err)
                }
        }
diff --git a/misc/cgo/test/issue9400/asm_mipsx.s b/misc/cgo/test/issue9400/asm_mipsx.s
new file mode 100644 (file)
index 0000000..ddf33e9
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2016 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 mips mipsle
+// +build !gccgo
+
+#include "textflag.h"
+
+TEXT ·RewindAndSetgid(SB),NOSPLIT,$-4-0
+       // Rewind stack pointer so anything that happens on the stack
+       // will clobber the test pattern created by the caller
+       ADDU    $(1024*8), R29
+
+       // Ask signaller to setgid
+       MOVW    $1, R1
+       SYNC
+       MOVW    R1, ·Baton(SB)
+       SYNC
+
+       // Wait for setgid completion
+loop:
+       SYNC
+       MOVW    ·Baton(SB), R1
+       OR      R2, R2, R2      // hint that we're in a spin loop
+       BNE     R1, loop
+       SYNC
+
+       // Restore stack
+       ADDU    $(-1024*8), R29
+       RET
index b16adc7d88f9822081c4ee969085e916c85fd47e..2b7a1ec9ad0a01e0dcb34f37ca756afbc94011c3 100644 (file)
@@ -17,7 +17,7 @@ package cgotest
 static stack_t oss;
 static char signalStack[SIGSTKSZ];
 
-static void changeSignalStack() {
+static void changeSignalStack(void) {
        stack_t ss;
        memset(&ss, 0, sizeof ss);
        ss.ss_sp = signalStack;
@@ -29,7 +29,7 @@ static void changeSignalStack() {
        }
 }
 
-static void restoreSignalStack() {
+static void restoreSignalStack(void) {
 #if (defined(__x86_64__) || defined(__i386__)) && defined(__APPLE__)
        // The Darwin C library enforces a minimum that the kernel does not.
        // This is OK since we allocated this much space in mpreinit,
@@ -42,7 +42,7 @@ static void restoreSignalStack() {
        }
 }
 
-static int zero() {
+static int zero(void) {
        return 0;
 }
 */
index 9752006f79e71fba94cfae856f43d5005d42178e..6e8bf141cafa81ea340b12112395d3d163518421 100644 (file)
@@ -21,7 +21,7 @@ int main(void) {
 
   // The descriptor will be initialized in a thread, so we have to
   // give a chance to get opened.
-  for (i = 0; i < 100; i++) {
+  for (i = 0; i < 1000; i++) {
     n = read(fd, buf, sizeof buf);
     if (n >= 0)
       break;
diff --git a/misc/cgo/testplugin/src/iface/main.go b/misc/cgo/testplugin/src/iface/main.go
new file mode 100644 (file)
index 0000000..5e7e4d8
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "iface_i"
+       "log"
+       "plugin"
+)
+
+func main() {
+       a, err := plugin.Open("iface_a.so")
+       if err != nil {
+               log.Fatalf(`plugin.Open("iface_a.so"): %v`, err)
+       }
+       b, err := plugin.Open("iface_b.so")
+       if err != nil {
+               log.Fatalf(`plugin.Open("iface_b.so"): %v`, err)
+       }
+
+       af, err := a.Lookup("F")
+       if err != nil {
+               log.Fatalf(`a.Lookup("F") failed: %v`, err)
+       }
+       bf, err := b.Lookup("F")
+       if err != nil {
+               log.Fatalf(`b.Lookup("F") failed: %v`, err)
+       }
+       if af.(func() interface{})() != bf.(func() interface{})() {
+               panic("empty interfaces not equal")
+       }
+
+       ag, err := a.Lookup("G")
+       if err != nil {
+               log.Fatalf(`a.Lookup("G") failed: %v`, err)
+       }
+       bg, err := b.Lookup("G")
+       if err != nil {
+               log.Fatalf(`b.Lookup("G") failed: %v`, err)
+       }
+       if ag.(func() iface_i.I)() != bg.(func() iface_i.I)() {
+               panic("nonempty interfaces not equal")
+       }
+}
diff --git a/misc/cgo/testplugin/src/iface_a/a.go b/misc/cgo/testplugin/src/iface_a/a.go
new file mode 100644 (file)
index 0000000..29d2e27
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "iface_i"
+
+//go:noinline
+func F() interface{} {
+       return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+       return (*iface_i.T)(nil)
+}
diff --git a/misc/cgo/testplugin/src/iface_b/b.go b/misc/cgo/testplugin/src/iface_b/b.go
new file mode 100644 (file)
index 0000000..29d2e27
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "iface_i"
+
+//go:noinline
+func F() interface{} {
+       return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+       return (*iface_i.T)(nil)
+}
diff --git a/misc/cgo/testplugin/src/iface_i/i.go b/misc/cgo/testplugin/src/iface_i/i.go
new file mode 100644 (file)
index 0000000..31c8038
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 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 iface_i
+
+type I interface {
+       M()
+}
+
+type T struct {
+}
+
+func (t *T) M() {
+}
+
+// *T implements I
diff --git a/misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go b/misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go
new file mode 100644 (file)
index 0000000..70fd054
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2017 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 dynamodbstreamsevt
+
+import "encoding/json"
+
+var foo json.RawMessage
+
+type Event struct{}
+
+func (e *Event) Dummy() {}
diff --git a/misc/cgo/testplugin/src/issue18676/main.go b/misc/cgo/testplugin/src/issue18676/main.go
new file mode 100644 (file)
index 0000000..c75409d
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2017 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.
+
+// The bug happened like this:
+// 1) The main binary adds an itab for *json.UnsupportedValueError / error
+//    (concrete type / interface type).  This itab goes in hash bucket 0x111.
+// 2) The plugin adds that same itab again.  That makes a cycle in the itab
+//    chain rooted at hash bucket 0x111.
+// 3) The main binary then asks for the itab for *dynamodbstreamsevt.Event /
+//    json.Unmarshaler.  This itab happens to also live in bucket 0x111.
+//    The lookup code goes into an infinite loop searching for this itab.
+// The code is carefully crafted so that the two itabs are both from the
+// same bucket, and so that the second itab doesn't exist in
+// the itab hashmap yet (so the entire linked list must be searched).
+package main
+
+import (
+       "encoding/json"
+       "issue18676/dynamodbstreamsevt"
+       "plugin"
+)
+
+func main() {
+       plugin.Open("plugin.so")
+
+       var x interface{} = (*dynamodbstreamsevt.Event)(nil)
+       if _, ok := x.(json.Unmarshaler); !ok {
+               println("something")
+       }
+}
diff --git a/misc/cgo/testplugin/src/issue18676/plugin.go b/misc/cgo/testplugin/src/issue18676/plugin.go
new file mode 100644 (file)
index 0000000..8a3b85a
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "C"
+
+import "issue18676/dynamodbstreamsevt"
+
+func F(evt *dynamodbstreamsevt.Event) {}
index 7a62242134338e63a3b3e408b17b769425f900bb..edcef2c77e9167fa6548b534bafc0d9dc2c4a319 100644 (file)
@@ -9,7 +9,10 @@ import "C"
 
 import "common"
 
-func F() int { return 3 }
+func F() int {
+       _ = make([]byte, 1<<21) // trigger stack unwind, Issue #18190.
+       return 3
+}
 
 func ReadCommonX() int {
        return common.X
index 6c23a5e63373c96c77664cca24dbb6613cb900c2..9c507fc36581c7676052ed444c463198aa3621a4 100644 (file)
@@ -4,12 +4,21 @@
 
 package main
 
-// // No C code required.
+//#include <errno.h>
+//#include <string.h>
 import "C"
 
-import "common"
+// #include
+// void cfunc() {} // uses cgo_topofstack
+
+import (
+       "common"
+       "strings"
+)
 
 func init() {
+       _ = strings.NewReplacer() // trigger stack unwind, Issue #18190.
+       C.strerror(C.EIO)         // uses cgo_topofstack
        common.X = 2
 }
 
index fee99a758c0c0aea6cd81efe760b9349631e993b..ab7430acc37f95e580492a1aa341c51e5eaa41e6 100755 (executable)
@@ -15,8 +15,8 @@ goos=$(go env GOOS)
 goarch=$(go env GOARCH)
 
 function cleanup() {
-       rm -f plugin*.so unnamed*.so
-       rm -rf host pkg sub
+       rm -f plugin*.so unnamed*.so iface*.so
+       rm -rf host pkg sub iface issue18676
 }
 trap cleanup EXIT
 
@@ -32,3 +32,15 @@ GOPATH=$(pwd) go build -buildmode=plugin unnamed2.go
 GOPATH=$(pwd) go build host
 
 LD_LIBRARY_PATH=$(pwd) ./host
+
+# Test that types and itabs get properly uniqified.
+GOPATH=$(pwd) go build -buildmode=plugin iface_a
+GOPATH=$(pwd) go build -buildmode=plugin iface_b
+GOPATH=$(pwd) go build iface
+LD_LIBRARY_PATH=$(pwd) ./iface
+
+# Test for issue 18676 - make sure we don't add the same itab twice.
+# The buggy code hangs forever, so use a timeout to check for that.
+GOPATH=$(pwd) go build -buildmode=plugin -o plugin.so src/issue18676/plugin.go
+GOPATH=$(pwd) go build -o issue18676 src/issue18676/main.go
+timeout 10s ./issue18676
diff --git a/misc/cgo/testsanitizers/msan_shared.go b/misc/cgo/testsanitizers/msan_shared.go
new file mode 100644 (file)
index 0000000..966947c
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2017 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.
+
+// This program segfaulted during libpreinit when built with -msan:
+// http://golang.org/issue/18707
+
+package main
+
+import "C"
+
+func main() {}
index 01cce956b8fccb02a20cefde06fedfcee8bce895..4da85020d89800a3db00594b1b7937b04b6646c3 100755 (executable)
@@ -24,8 +24,14 @@ msan=yes
 
 TMPDIR=${TMPDIR:-/tmp}
 echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
-if $CC -fsanitize=memory -c ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$.o 2>&1 | grep "unrecognized" >& /dev/null; then
-  echo "skipping msan tests: -fsanitize=memory not supported"
+if $CC -fsanitize=memory -o ${TMPDIR}/testsanitizers$$ ${TMPDIR}/testsanitizers$$.c 2>&1 | grep "unrecognized" >& /dev/null; then
+  echo "skipping msan tests: $CC -fsanitize=memory not supported"
+  msan=no
+elif ! test -x ${TMPDIR}/testsanitizers$$; then
+  echo "skipping msan tests: $CC -fsanitize-memory did not generate an executable"
+  msan=no
+elif ! ${TMPDIR}/testsanitizers$$ >/dev/null 2>&1; then
+  echo "skipping msan tests: $CC -fsanitize-memory generates broken executable"
   msan=no
 fi
 rm -f ${TMPDIR}/testsanitizers$$.*
@@ -62,6 +68,25 @@ fi
 
 status=0
 
+testmsanshared() {
+  goos=$(go env GOOS)
+  suffix="-installsuffix testsanitizers"
+  libext="so"
+  if [ "$goos" == "darwin" ]; then
+         libext="dylib"
+  fi
+  go build -msan -buildmode=c-shared $suffix -o ${TMPDIR}/libmsanshared.$libext msan_shared.go
+
+       echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c
+  $CC $(go env GOGCCFLAGS) -fsanitize=memory -o ${TMPDIR}/testmsanshared ${TMPDIR}/testmsanshared.c ${TMPDIR}/libmsanshared.$libext
+
+  if ! LD_LIBRARY_PATH=. ${TMPDIR}/testmsanshared; then
+    echo "FAIL: msan_shared"
+    status=1
+  fi
+  rm -f ${TMPDIR}/{testmsanshared,testmsanshared.c,libmsanshared.$libext}
+}
+
 if test "$msan" = "yes"; then
     if ! go build -msan std; then
        echo "FAIL: build -msan std"
@@ -102,6 +127,8 @@ if test "$msan" = "yes"; then
        echo "FAIL: msan_fail"
        status=1
     fi
+
+    testmsanshared
 fi
 
 if test "$tsan" = "yes"; then
@@ -145,6 +172,7 @@ if test "$tsan" = "yes"; then
     testtsan tsan3.go
     testtsan tsan4.go
     testtsan tsan8.go
+    testtsan tsan9.go
 
     # These tests are only reliable using clang or GCC version 7 or later.
     # Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
diff --git a/misc/cgo/testsanitizers/tsan9.go b/misc/cgo/testsanitizers/tsan9.go
new file mode 100644 (file)
index 0000000..f166d8b
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2016 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 failed when run under the C/C++ ThreadSanitizer. The
+// TSAN library was not keeping track of whether signals should be
+// delivered on the alternate signal stack, and the Go signal handler
+// was not preserving callee-saved registers from C callers.
+
+/*
+#cgo CFLAGS: -g -fsanitize=thread
+#cgo LDFLAGS: -g -fsanitize=thread
+
+#include <stdlib.h>
+#include <sys/time.h>
+
+void spin() {
+       size_t n;
+       struct timeval tvstart, tvnow;
+       int diff;
+       void *prev = NULL, *cur;
+
+       gettimeofday(&tvstart, NULL);
+       for (n = 0; n < 1<<20; n++) {
+               cur = malloc(n);
+               free(prev);
+               prev = cur;
+
+               gettimeofday(&tvnow, NULL);
+               diff = (tvnow.tv_sec - tvstart.tv_sec) * 1000 * 1000 + (tvnow.tv_usec - tvstart.tv_usec);
+
+               // Profile frequency is 100Hz so we should definitely
+               // get a signal in 50 milliseconds.
+               if (diff > 50 * 1000) {
+                       break;
+               }
+       }
+
+       free(prev);
+}
+*/
+import "C"
+
+import (
+       "io/ioutil"
+       "runtime/pprof"
+       "time"
+)
+
+func goSpin() {
+       start := time.Now()
+       for n := 0; n < 1<<20; n++ {
+               _ = make([]byte, n)
+               if time.Since(start) > 50*time.Millisecond {
+                       break
+               }
+       }
+}
+
+func main() {
+       pprof.StartCPUProfile(ioutil.Discard)
+       go C.spin()
+       goSpin()
+       pprof.StopCPUProfile()
+}
index af4f91550f2094beb4152d5fb59b7d7252585054..f0766e511ec5b3e60f9365afa5d2154793d8349c 100644 (file)
@@ -815,3 +815,14 @@ func TestImplicitInclusion(t *testing.T) {
        goCmd(t, "install", "-linkshared", "implicitcmd")
        run(t, "running executable linked against library that contains same package as it", "./bin/implicitcmd")
 }
+
+// Tests to make sure that the type fields of empty interfaces and itab
+// fields of nonempty interfaces are unique even across modules,
+// so that interface equality works correctly.
+func TestInterface(t *testing.T) {
+       goCmd(t, "install", "-buildmode=shared", "-linkshared", "iface_a")
+       // Note: iface_i gets installed implicitly as a dependency of iface_a.
+       goCmd(t, "install", "-buildmode=shared", "-linkshared", "iface_b")
+       goCmd(t, "install", "-linkshared", "iface")
+       run(t, "running type/itab uniqueness tester", "./bin/iface")
+}
index a518b4efe2955e785b7c46fddf9513bf89902624..9f86710db01a4438fe4ab7fb7e8f3b13829592f5 100644 (file)
@@ -5,6 +5,8 @@ import (
        "reflect"
 )
 
+var SlicePtr interface{} = &[]int{}
+
 var V int = 1
 
 var HasMask []string = []string{"hi"}
index 31fbedd31c55826162940883cb457ec4f05e4ab7..84302a811f0919b9035b8da22814581af1d122a0 100644 (file)
@@ -7,6 +7,20 @@ import (
        "runtime"
 )
 
+// Having a function declared in the main package triggered
+// golang.org/issue/18250
+func DeclaredInMain() {
+}
+
+type C struct {
+}
+
+func F() *C {
+       return nil
+}
+
+var slicePtr interface{} = &[]int{}
+
 func main() {
        defer depBase.ImplementedInAsm()
        // This code below causes various go.itab.* symbols to be generated in
@@ -15,4 +29,16 @@ func main() {
        reflect.TypeOf(os.Stdout).Elem()
        runtime.GC()
        depBase.V = depBase.F() + 1
+
+       var c *C
+       if reflect.TypeOf(F).Out(0) != reflect.TypeOf(c) {
+               panic("bad reflection results, see golang.org/issue/18252")
+       }
+
+       sp := reflect.New(reflect.TypeOf(slicePtr).Elem())
+       s := sp.Interface()
+
+       if reflect.TypeOf(s) != reflect.TypeOf(slicePtr) {
+               panic("bad reflection results, see golang.org/issue/18729")
+       }
 }
diff --git a/misc/cgo/testshared/src/iface/main.go b/misc/cgo/testshared/src/iface/main.go
new file mode 100644 (file)
index 0000000..3d5b54e
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "iface_a"
+import "iface_b"
+
+func main() {
+       if iface_a.F() != iface_b.F() {
+               panic("empty interfaces not equal")
+       }
+       if iface_a.G() != iface_b.G() {
+               panic("non-empty interfaces not equal")
+       }
+}
diff --git a/misc/cgo/testshared/src/iface_a/a.go b/misc/cgo/testshared/src/iface_a/a.go
new file mode 100644 (file)
index 0000000..e11047c
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 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 iface_a
+
+import "iface_i"
+
+//go:noinline
+func F() interface{} {
+       return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+       return (*iface_i.T)(nil)
+}
diff --git a/misc/cgo/testshared/src/iface_b/b.go b/misc/cgo/testshared/src/iface_b/b.go
new file mode 100644 (file)
index 0000000..47aee2e
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 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 iface_b
+
+import "iface_i"
+
+//go:noinline
+func F() interface{} {
+       return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+       return (*iface_i.T)(nil)
+}
diff --git a/misc/cgo/testshared/src/iface_i/i.go b/misc/cgo/testshared/src/iface_i/i.go
new file mode 100644 (file)
index 0000000..31c8038
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 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 iface_i
+
+type I interface {
+       M()
+}
+
+type T struct {
+}
+
+func (t *T) M() {
+}
+
+// *T implements I
index 9cad49fe7d86f5fda9a6fff0497e2d092a9baaff..9141c8c4474c22360de932545f3881e204a490a3 100755 (executable)
@@ -17,4 +17,4 @@ else
        exit 1
 fi
 
-exec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH "$@"
+exec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH -mios-version-min=6.0 "$@"
index 1eeb289c7d249ce60f96425489a879267a5040ff..3de341b9c59170805f0fefc7387a0921f9a8e1a7 100644 (file)
@@ -99,7 +99,7 @@ func main() {
        // Approximately 1 in a 100 binaries fail to start. If it happens,
        // try again. These failures happen for several reasons beyond
        // our control, but all of them are safe to retry as they happen
-       // before lldb encounters the initial getwd breakpoint. As we
+       // before lldb encounters the initial SIGUSR2 stop. As we
        // know the tests haven't started, we are not hiding flaky tests
        // with this retry.
        for i := 0; i < 5; i++ {
@@ -204,6 +204,11 @@ func run(bin string, args []string) (err error) {
        var opts options
        opts, args = parseArgs(args)
 
+       // Pass the suffix for the current working directory as the
+       // first argument to the test. For iOS, cmd/go generates
+       // special handling of this argument.
+       args = append([]string{"cwdSuffix=" + pkgpath}, args...)
+
        // ios-deploy invokes lldb to give us a shell session with the app.
        s, err := newSession(appdir, args, opts)
        if err != nil {
@@ -224,6 +229,7 @@ func run(bin string, args []string) (err error) {
        s.do(`process handle SIGHUP  --stop false --pass true --notify false`)
        s.do(`process handle SIGPIPE --stop false --pass true --notify false`)
        s.do(`process handle SIGUSR1 --stop false --pass true --notify false`)
+       s.do(`process handle SIGUSR2 --stop true --pass false --notify true`) // sent by test harness
        s.do(`process handle SIGCONT --stop false --pass true --notify false`)
        s.do(`process handle SIGSEGV --stop false --pass true --notify false`) // does not work
        s.do(`process handle SIGBUS  --stop false --pass true --notify false`) // does not work
@@ -236,20 +242,9 @@ func run(bin string, args []string) (err error) {
                return nil
        }
 
-       s.do(`breakpoint set -n getwd`) // in runtime/cgo/gcc_darwin_arm.go
-
        started = true
 
-       s.doCmd("run", "stop reason = breakpoint", 20*time.Second)
-
-       // Move the current working directory into the faux gopath.
-       if pkgpath != "src" {
-               s.do(`breakpoint delete 1`)
-               s.do(`expr char* $mem = (char*)malloc(512)`)
-               s.do(`expr $mem = (char*)getwd($mem, 512)`)
-               s.do(`expr $mem = (char*)strcat($mem, "/` + pkgpath + `")`)
-               s.do(`call (void)chdir($mem)`)
-       }
+       s.doCmd("run", "stop reason = signal SIGUSR2", 20*time.Second)
 
        startTestsLen := s.out.Len()
        fmt.Fprintln(s.in, `process continue`)
@@ -520,13 +515,11 @@ func copyLocalData(dstbase string) (pkgpath string, err error) {
 
        // Copy timezone file.
        //
-       // Typical apps have the zoneinfo.zip in the root of their app bundle,
+       // Apps have the zoneinfo.zip in the root of their app bundle,
        // read by the time package as the working directory at initialization.
-       // As we move the working directory to the GOROOT pkg directory, we
-       // install the zoneinfo.zip file in the pkgpath.
        if underGoRoot {
                err := cp(
-                       filepath.Join(dstbase, pkgpath),
+                       dstbase,
                        filepath.Join(cwd, "lib", "time", "zoneinfo.zip"),
                )
                if err != nil {
index 9bbc9a97454302656331fefdc80224ea45d6de6a..f6c3ead3beabd20aca92de87c2b9ab2fba664556 100644 (file)
@@ -13,7 +13,6 @@ import (
        "hash/crc32"
        "io"
        "os"
-       "time"
 )
 
 var (
@@ -290,16 +289,13 @@ func readDirectoryHeader(f *File, r io.Reader) error {
                // Other zip authors might not even follow the basic format,
                // and we'll just ignore the Extra content in that case.
                b := readBuf(f.Extra)
-
-       Extras:
                for len(b) >= 4 { // need at least tag and size
                        tag := b.uint16()
                        size := b.uint16()
                        if int(size) > len(b) {
                                break
                        }
-                       switch tag {
-                       case zip64ExtraId:
+                       if tag == zip64ExtraId {
                                // update directory values from the zip64 extra block.
                                // They should only be consulted if the sizes read earlier
                                // are maxed out.
@@ -327,42 +323,7 @@ func readDirectoryHeader(f *File, r io.Reader) error {
                                        }
                                        f.headerOffset = int64(eb.uint64())
                                }
-                               break Extras
-
-                       case ntfsExtraId:
-                               if size == 32 {
-                                       eb := readBuf(b[:size])
-                                       eb.uint32() // reserved
-                                       eb.uint16() // tag1
-                                       size1 := eb.uint16()
-                                       if size1 == 24 {
-                                               sub := readBuf(eb[:size1])
-                                               lo := sub.uint32()
-                                               hi := sub.uint32()
-                                               tick := (uint64(uint64(lo)|uint64(hi)<<32) - 116444736000000000) / 10000000
-                                               f.SetModTime(time.Unix(int64(tick), 0))
-                                       }
-                               }
-                               break Extras
-
-                       case unixExtraId:
-                               if size >= 12 {
-                                       eb := readBuf(b[:size])
-                                       eb.uint32()          // AcTime
-                                       epoch := eb.uint32() // ModTime
-                                       f.SetModTime(time.Unix(int64(epoch), 0))
-                                       break Extras
-                               }
-                       case exttsExtraId:
-                               if size >= 3 {
-                                       eb := readBuf(b[:size])
-                                       flags := eb.uint8()  // Flags
-                                       epoch := eb.uint32() // AcTime/ModTime/CrTime
-                                       if flags&1 != 0 {
-                                               f.SetModTime(time.Unix(int64(epoch), 0))
-                                       }
-                                       break Extras
-                               }
+                               break
                        }
                        b = b[size:]
                }
@@ -547,12 +508,6 @@ func findSignatureInBlock(b []byte) int {
 
 type readBuf []byte
 
-func (b *readBuf) uint8() uint8 {
-       v := uint8((*b)[0])
-       *b = (*b)[1:]
-       return v
-}
-
 func (b *readBuf) uint16() uint16 {
        v := binary.LittleEndian.Uint16(*b)
        *b = (*b)[2:]
index 576a1697a444959376f46b927ebf82023b059687..dfaae784361b7184ffdc36e89bd955cae0bd7233 100644 (file)
@@ -65,13 +65,13 @@ var tests = []ZipTest{
                        {
                                Name:    "test.txt",
                                Content: []byte("This is a test text file.\n"),
-                               Mtime:   "09-05-10 02:12:00",
+                               Mtime:   "09-05-10 12:12:02",
                                Mode:    0644,
                        },
                        {
                                Name:  "gophercolor16x16.png",
                                File:  "gophercolor16x16.png",
-                               Mtime: "09-05-10 05:52:58",
+                               Mtime: "09-05-10 15:52:58",
                                Mode:  0644,
                        },
                },
@@ -83,13 +83,13 @@ var tests = []ZipTest{
                        {
                                Name:    "test.txt",
                                Content: []byte("This is a test text file.\n"),
-                               Mtime:   "09-05-10 02:12:00",
+                               Mtime:   "09-05-10 12:12:02",
                                Mode:    0644,
                        },
                        {
                                Name:  "gophercolor16x16.png",
                                File:  "gophercolor16x16.png",
-                               Mtime: "09-05-10 05:52:58",
+                               Mtime: "09-05-10 15:52:58",
                                Mode:  0644,
                        },
                },
@@ -144,17 +144,6 @@ var tests = []ZipTest{
                Name: "unix.zip",
                File: crossPlatform,
        },
-       {
-               Name: "extra-timestamp.zip",
-               File: []ZipTestFile{
-                       {
-                               Name:    "hello.txt",
-                               Content: []byte(""),
-                               Mtime:   "01-06-16 12:25:56",
-                               Mode:    0666,
-                       },
-               },
-       },
        {
                // created by Go, before we wrote the "optional" data
                // descriptor signatures (which are required by OS X)
@@ -163,13 +152,13 @@ var tests = []ZipTest{
                        {
                                Name:    "foo.txt",
                                Content: []byte("foo\n"),
-                               Mtime:   "03-09-12 00:59:10",
+                               Mtime:   "03-08-12 16:59:10",
                                Mode:    0644,
                        },
                        {
                                Name:    "bar.txt",
                                Content: []byte("bar\n"),
-                               Mtime:   "03-09-12 00:59:12",
+                               Mtime:   "03-08-12 16:59:12",
                                Mode:    0644,
                        },
                },
@@ -216,13 +205,13 @@ var tests = []ZipTest{
                        {
                                Name:    "foo.txt",
                                Content: []byte("foo\n"),
-                               Mtime:   "03-09-12 00:59:10",
+                               Mtime:   "03-08-12 16:59:10",
                                Mode:    0644,
                        },
                        {
                                Name:    "bar.txt",
                                Content: []byte("bar\n"),
-                               Mtime:   "03-09-12 00:59:12",
+                               Mtime:   "03-08-12 16:59:12",
                                Mode:    0644,
                        },
                },
@@ -236,14 +225,14 @@ var tests = []ZipTest{
                        {
                                Name:       "foo.txt",
                                Content:    []byte("foo\n"),
-                               Mtime:      "03-09-12 00:59:10",
+                               Mtime:      "03-08-12 16:59:10",
                                Mode:       0644,
                                ContentErr: ErrChecksum,
                        },
                        {
                                Name:    "bar.txt",
                                Content: []byte("bar\n"),
-                               Mtime:   "03-09-12 00:59:12",
+                               Mtime:   "03-08-12 16:59:12",
                                Mode:    0644,
                        },
                },
index 287571ed3aa09da158b9c4ec394e78fefad1c650..e92d02f8a2e872ddab84503a6ea0cd4e238faa78 100644 (file)
@@ -63,9 +63,6 @@ const (
 
        // extra header id's
        zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field
-       ntfsExtraId  = 0x000a // NTFS Extra Field
-       unixExtraId  = 0x000d // UNIX Extra Field
-       exttsExtraId = 0x5455 // Extended Timestamp Extra Field
 )
 
 // FileHeader describes a file within a zip file.
diff --git a/src/archive/zip/testdata/extra-timestamp.zip b/src/archive/zip/testdata/extra-timestamp.zip
deleted file mode 100644 (file)
index 819e22c..0000000
Binary files a/src/archive/zip/testdata/extra-timestamp.zip and /dev/null differ
index ea4559e698428acd02aba0d5992a729debe2e7ee..8940e25560e4501703a739e1321421deba2cffec 100644 (file)
@@ -103,18 +103,6 @@ func (w *Writer) Close() error {
                        b.uint32(h.UncompressedSize)
                }
 
-               // use Extended Timestamp Extra Field.
-               if h.ModifiedTime != 0 || h.ModifiedDate != 0 {
-                       mt := uint32(h.ModTime().Unix())
-                       var mbuf [9]byte // 2x uint16 + uint8 + uint32
-                       eb := writeBuf(mbuf[:])
-                       eb.uint16(exttsExtraId)
-                       eb.uint16(5)  // size = uint8 + uint32
-                       eb.uint8(1)   // flags = modtime
-                       eb.uint32(mt) // ModTime
-                       h.Extra = append(h.Extra, mbuf[:]...)
-               }
-
                b.uint16(uint16(len(h.Name)))
                b.uint16(uint16(len(h.Extra)))
                b.uint16(uint16(len(h.Comment)))
@@ -397,11 +385,6 @@ func (w nopCloser) Close() error {
 
 type writeBuf []byte
 
-func (b *writeBuf) uint8(v uint8) {
-       (*b)[0] = v
-       *b = (*b)[1:]
-}
-
 func (b *writeBuf) uint16(v uint16) {
        binary.LittleEndian.PutUint16(*b, v)
        *b = (*b)[2:]
index f20daa0e3d3fa5de8da311af178ab787a44771ed..86841c755f160ee371976556d03b1506b7c271e2 100644 (file)
@@ -11,7 +11,6 @@ import (
        "math/rand"
        "os"
        "testing"
-       "time"
 )
 
 // TODO(adg): a more sophisticated test suite
@@ -21,7 +20,6 @@ type WriteTest struct {
        Data   []byte
        Method uint16
        Mode   os.FileMode
-       Mtime  string
 }
 
 var writeTests = []WriteTest{
@@ -30,35 +28,30 @@ var writeTests = []WriteTest{
                Data:   []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
                Method: Store,
                Mode:   0666,
-               Mtime:  "02-01-08 00:01:02",
        },
        {
                Name:   "bar",
                Data:   nil, // large data set in the test
                Method: Deflate,
                Mode:   0644,
-               Mtime:  "03-02-08 01:02:03",
        },
        {
                Name:   "setuid",
                Data:   []byte("setuid file"),
                Method: Deflate,
                Mode:   0755 | os.ModeSetuid,
-               Mtime:  "04-03-08 02:03:04",
        },
        {
                Name:   "setgid",
                Data:   []byte("setgid file"),
                Method: Deflate,
                Mode:   0755 | os.ModeSetgid,
-               Mtime:  "05-04-08 03:04:04",
        },
        {
                Name:   "symlink",
                Data:   []byte("../link/target"),
                Method: Deflate,
                Mode:   0755 | os.ModeSymlink,
-               Mtime:  "03-02-08 11:22:33",
        },
 }
 
@@ -155,11 +148,6 @@ func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
        if wt.Mode != 0 {
                header.SetMode(wt.Mode)
        }
-       mtime, err := time.Parse("01-02-06 15:04:05", wt.Mtime)
-       if err != nil {
-               t.Fatal("time.Parse:", err)
-       }
-       header.SetModTime(mtime)
        f, err := w.CreateHeader(header)
        if err != nil {
                t.Fatal(err)
@@ -190,21 +178,6 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
        if !bytes.Equal(b, wt.Data) {
                t.Errorf("File contents %q, want %q", b, wt.Data)
        }
-
-       mtime, err := time.Parse("01-02-06 15:04:05", wt.Mtime)
-       if err != nil {
-               t.Fatal("time.Parse:", err)
-       }
-
-       diff := mtime.Sub(f.ModTime())
-       if diff < 0 {
-               diff = -diff
-       }
-
-       // allow several time span
-       if diff > 5*time.Second {
-               t.Errorf("File modtime %v, want %v", mtime, f.ModTime())
-       }
 }
 
 func BenchmarkCompressedZipGarbage(b *testing.B) {
index 8801e904130ae10c70c158f5ade2dc11d87db3d0..57edb2cabf4c91bb30940e881ef0589e020b50f8 100644 (file)
@@ -15,7 +15,6 @@ import (
        "internal/testenv"
        "io"
        "io/ioutil"
-       "reflect"
        "sort"
        "strings"
        "testing"
@@ -114,44 +113,6 @@ func TestFileHeaderRoundTrip64(t *testing.T) {
        testHeaderRoundTrip(fh, uint32max, fh.UncompressedSize64, t)
 }
 
-func TestZeroFileRoundTrip(t *testing.T) {
-       var b bytes.Buffer
-       w := NewWriter(&b)
-       if _, err := w.Create(""); err != nil {
-               t.Fatal(err)
-       }
-       if err := w.Close(); err != nil {
-               t.Fatal(err)
-       }
-       r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len()))
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       // Verify that fields that should reasonably be the zero value stays
-       // as the zero value.
-       var want FileHeader
-       if len(r.File) != 1 {
-               t.Fatalf("len(r.File) = %d, want 1", len(r.File))
-       }
-       fh := r.File[0].FileHeader
-       got := FileHeader{
-               Name:               fh.Name,
-               ModifiedTime:       fh.ModifiedTime,
-               ModifiedDate:       fh.ModifiedDate,
-               UncompressedSize:   fh.UncompressedSize,
-               UncompressedSize64: fh.UncompressedSize64,
-               ExternalAttrs:      fh.ExternalAttrs,
-               Comment:            fh.Comment,
-       }
-       if len(fh.Extra) > 0 {
-               got.Extra = fh.Extra
-       }
-       if !reflect.DeepEqual(got, want) {
-               t.Errorf("FileHeader mismatch:\ngot  %#v\nwant %#v", got, want)
-       }
-}
-
 type repeatedByte struct {
        off int64
        b   byte
index 2ee3d738ef996551a004837899b94ba0771b67e9..196419dc3da5999ada51eda442a9d06ff8ae04f3 100644 (file)
@@ -23,7 +23,7 @@ type Buffer struct {
 
 // The readOp constants describe the last action performed on
 // the buffer, so that UnreadRune and UnreadByte can check for
-// invalid usage. opReadRuneX constants are choosen such that
+// invalid usage. opReadRuneX constants are chosen such that
 // converted to int they correspond to the rune size that was read.
 type readOp int
 
index 670a73f546c98ef9d2d7fc22bc27fc2fe119107c..5ea2d941ca2ea9f9609c2c3531f7373ebd31aeb4 100644 (file)
@@ -1210,6 +1210,8 @@ func (p *Package) gccMachine() []string {
                return []string{"-m64"}
        case "mips64", "mips64le":
                return []string{"-mabi=64"}
+       case "mips", "mipsle":
+               return []string{"-mabi=32"}
        }
        return nil
 }
@@ -1727,6 +1729,15 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
                if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
                        t.Go = c.goVoidPtr
                        t.C.Set("void*")
+                       dq := dt.Type
+                       for {
+                               if d, ok := dq.(*dwarf.QualType); ok {
+                                       t.C.Set(d.Qual + " " + t.C.String())
+                                       dq = d.Type
+                               } else {
+                                       break
+                               }
+                       }
                        break
                }
 
index 09216fdd83d516758ed6a8269085a433ef56d000..f8cfd3ce5c2091efddc372949c3becacd6f06d12 100644 (file)
@@ -303,7 +303,9 @@ func genhash(sym *Sym, t *Type) {
        typecheckslice(fn.Nbody.Slice(), Etop)
        Curfn = nil
        popdcl()
-       testdclstack()
+       if debug_dclstack != 0 {
+               testdclstack()
+       }
 
        // Disable safemode while compiling this code: the code we
        // generate internally can refer to unsafe.Pointer.
@@ -493,7 +495,9 @@ func geneq(sym *Sym, t *Type) {
        typecheckslice(fn.Nbody.Slice(), Etop)
        Curfn = nil
        popdcl()
-       testdclstack()
+       if debug_dclstack != 0 {
+               testdclstack()
+       }
 
        // Disable safemode while compiling this code: the code we
        // generate internally can refer to unsafe.Pointer.
index 27e9848640fed82add17733dbff2b568deddd73b..b7036869b8044537c5a1598d87a9d22d290bd025 100644 (file)
@@ -74,7 +74,13 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
                        lastzero = o
                }
                o += w
-               if o >= Thearch.MAXWIDTH {
+               maxwidth := Thearch.MAXWIDTH
+               // On 32-bit systems, reflect tables impose an additional constraint
+               // that each field start offset must fit in 31 bits.
+               if maxwidth < 1<<32 {
+                       maxwidth = 1<<31 - 1
+               }
+               if o >= maxwidth {
                        yyerror("type %L too large", errtype)
                        o = 8 // small but nonzero
                }
index e6082edbeb29b98e389d1c2188eb037dac1e26fc..9eb31e152a22a1d5f9dceb9fea62dcb801b2c7cf 100644 (file)
@@ -175,6 +175,14 @@ func f(b []byte, i int) uint64 {
        },
        {"amd64", "linux", `
 import "encoding/binary"
+func f(b []byte, v uint64) {
+       binary.BigEndian.PutUint64(b, v)
+}
+`,
+               []string{"\tBSWAPQ\t"},
+       },
+       {"amd64", "linux", `
+import "encoding/binary"
 func f(b []byte) uint32 {
        return binary.BigEndian.Uint32(b)
 }
@@ -186,6 +194,14 @@ import "encoding/binary"
 func f(b []byte, i int) uint32 {
        return binary.BigEndian.Uint32(b[i:])
 }
+`,
+               []string{"\tBSWAPL\t"},
+       },
+       {"amd64", "linux", `
+import "encoding/binary"
+func f(b []byte, v uint32) {
+       binary.BigEndian.PutUint32(b, v)
+}
 `,
                []string{"\tBSWAPL\t"},
        },
@@ -205,6 +221,19 @@ func f(b []byte, i int) uint32 {
 `,
                []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
        },
+
+       // Structure zeroing.  See issue #18370.
+       {"amd64", "linux", `
+type T struct {
+       a, b, c int
+}
+func f(t *T) {
+       *t = T{}
+}
+`,
+               []string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"},
+       },
+       // TODO: add a test for *t = T{3,4,5} when we fix that.
 }
 
 // mergeEnvLists merges the two environment lists such that
index ab86c3a52387f618a15a196741e5abf73a343515..06bb6975a9d25685f5e7702fcb32543217b37f71 100644 (file)
@@ -140,11 +140,12 @@ const debugFormat = false // default: false
 const forceObjFileStability = true
 
 // Current export format version. Increase with each format change.
-// 3: added aliasTag and export of aliases
-// 2: removed unused bool in ODCL export
+// 4: type name objects support type aliases, uses aliasTag
+// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
+// 2: removed unused bool in ODCL export (compiler only)
 // 1: header format change (more regular), export package for _ struct fields
 // 0: Go1.7 encoding
-const exportVersion = 3
+const exportVersion = 4
 
 // exportInlined enables the export of inlined function bodies and related
 // dependencies. The compiler should work w/o any loss of functionality with
@@ -351,8 +352,8 @@ func export(out *bufio.Writer, trace bool) int {
                        p.tracef("\n")
                }
 
-               if sym.Flags&SymAlias != 0 {
-                       Fatalf("exporter: unexpected alias %v in inlined function body", sym)
+               if sym.isAlias() {
+                       Fatalf("exporter: unexpected type alias %v in inlined function body", sym)
                }
 
                p.obj(sym)
@@ -446,30 +447,6 @@ func unidealType(typ *Type, val Val) *Type {
 }
 
 func (p *exporter) obj(sym *Sym) {
-       if sym.Flags&SymAlias != 0 {
-               p.tag(aliasTag)
-               p.pos(nil) // TODO(gri) fix position information
-               // Aliases can only be exported from the package that
-               // declares them (aliases to aliases are resolved to the
-               // original object, and so are uses of aliases in inlined
-               // exported function bodies). Thus, we only need the alias
-               // name without package qualification.
-               if sym.Pkg != localpkg {
-                       Fatalf("exporter: export of non-local alias: %v", sym)
-               }
-               p.string(sym.Name)
-               orig := sym.Def.Sym
-               if orig.Flags&SymAlias != 0 {
-                       Fatalf("exporter: original object %v marked as alias", sym)
-               }
-               p.qualifiedName(orig)
-               return
-       }
-
-       if sym != sym.Def.Sym {
-               Fatalf("exporter: exported object %v is not original %v", sym, sym.Def.Sym)
-       }
-
        // Exported objects may be from different packages because they
        // may be re-exported via an exported alias or as dependencies in
        // exported inlined function bodies. Thus, exported object names
@@ -509,7 +486,13 @@ func (p *exporter) obj(sym *Sym) {
                        Fatalf("exporter: export of incomplete type %v", sym)
                }
 
-               p.tag(typeTag)
+               if sym.isAlias() {
+                       p.tag(aliasTag)
+                       p.pos(n)
+                       p.qualifiedName(sym)
+               } else {
+                       p.tag(typeTag)
+               }
                p.typ(t)
 
        case ONAME:
@@ -870,19 +853,29 @@ func (p *exporter) methodList(t *Type) {
 
 func (p *exporter) method(m *Field) {
        p.pos(m.Nname)
-       p.fieldName(m)
+       p.methodName(m.Sym)
        p.paramList(m.Type.Params(), false)
        p.paramList(m.Type.Results(), false)
 }
 
-// fieldName is like qualifiedName but it doesn't record the package for exported names.
 func (p *exporter) fieldName(t *Field) {
        name := t.Sym.Name
        if t.Embedded != 0 {
-               name = "" // anonymous field
-               if bname := basetypeName(t.Type); bname != "" && !exportname(bname) {
-                       // anonymous field with unexported base type name
-                       name = "?" // unexported name to force export of package
+               // anonymous field - we distinguish between 3 cases:
+               // 1) field name matches base type name and is exported
+               // 2) field name matches base type name and is not exported
+               // 3) field name doesn't match base type name (alias name)
+               bname := basetypeName(t.Type)
+               if name == bname {
+                       if exportname(name) {
+                               name = "" // 1) we don't need to know the field name or package
+                       } else {
+                               name = "?" // 2) use unexported name "?" to force package export
+                       }
+               } else {
+                       // 3) indicate alias and export name as is
+                       // (this requires an extra "@" but this is a rare case)
+                       p.string("@")
                }
        }
        p.string(name)
@@ -891,16 +884,23 @@ func (p *exporter) fieldName(t *Field) {
        }
 }
 
+// methodName is like qualifiedName but it doesn't record the package for exported names.
+func (p *exporter) methodName(sym *Sym) {
+       p.string(sym.Name)
+       if !exportname(sym.Name) {
+               p.pkg(sym.Pkg)
+       }
+}
+
 func basetypeName(t *Type) string {
        s := t.Sym
        if s == nil && t.IsPtr() {
                s = t.Elem().Sym // deref
        }
-       // s should exist, but be conservative
        if s != nil {
                return s.Name
        }
-       return ""
+       return "" // unnamed type
 }
 
 func (p *exporter) paramList(params *Type, numbered bool) {
@@ -1002,7 +1002,7 @@ func parName(f *Field, numbered bool) string {
                Fatalf("invalid symbol name: %s", name)
        }
 
-       // Functions that can be inlined use numbered parameters so we can distingish them
+       // Functions that can be inlined use numbered parameters so we can distinguish them
        // from other names in their context after inlining (i.e., the parameter numbering
        // is a form of parameter rewriting). See issue 4326 for an example and test case.
        if forceObjFileStability || numbered {
@@ -1799,7 +1799,7 @@ const (
        nilTag
        unknownTag // not used by gc (only appears in packages with errors)
 
-       // Aliases
+       // Type aliases
        aliasTag
 )
 
@@ -1837,7 +1837,7 @@ var tagString = [...]string{
        -nilTag:      "nil",
        -unknownTag:  "unknown",
 
-       // Aliases
+       // Type aliases
        -aliasTag: "alias",
 }
 
@@ -1891,7 +1891,7 @@ func predeclared() []*Type {
                        Types[TCOMPLEX128],
                        Types[TSTRING],
 
-                       // aliases
+                       // basic type aliases
                        bytetype,
                        runetype,
 
index 1d668412a181d05b6bc330865fc3e24535b1884e..752f65be425ec55bea71d7513538f7e1e640a348 100644 (file)
@@ -86,10 +86,10 @@ func Import(in *bufio.Reader) {
 
        // read version specific flags - extend as necessary
        switch p.version {
-       // case 4:
+       // case 5:
        //      ...
        //      fallthrough
-       case 3, 2, 1:
+       case 4, 3, 2, 1:
                p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
                p.trackAllTypes = p.bool()
                p.posInfoFormat = p.bool()
@@ -217,7 +217,9 @@ func Import(in *bufio.Reader) {
        typecheckok = tcok
        resumecheckwidth()
 
-       testdclstack() // debugging only
+       if debug_dclstack != 0 {
+               testdclstack()
+       }
 }
 
 func formatErrorf(format string, args ...interface{}) {
@@ -315,6 +317,12 @@ func (p *importer) obj(tag int) {
                val := p.value(typ)
                importconst(sym, idealType(typ), nodlit(val))
 
+       case aliasTag:
+               p.pos()
+               sym := p.qualifiedName()
+               typ := p.typ()
+               importalias(sym, typ)
+
        case typeTag:
                p.typ()
 
@@ -354,17 +362,6 @@ func (p *importer) obj(tag int) {
                        }
                }
 
-       case aliasTag:
-               p.pos()
-               alias := importpkg.Lookup(p.string())
-               orig := p.qualifiedName()
-
-               // Although the protocol allows the alias to precede the original,
-               // this never happens in files produced by gc.
-               alias.Flags |= SymAlias
-               alias.Def = orig.Def
-               importsym(alias, orig.Def.Op)
-
        default:
                formatErrorf("unexpected object (tag = %d)", tag)
        }
@@ -471,14 +468,7 @@ func (p *importer) typ() *Type {
                        result := p.paramList()
                        nointerface := p.bool()
 
-                       base := recv[0].Type
-                       star := false
-                       if base.IsPtr() {
-                               base = base.Elem()
-                               star = true
-                       }
-
-                       n := methodname0(sym, star, base.Sym)
+                       n := newfuncname(methodname(sym, recv[0].Type))
                        n.Type = functypefield(recv[0], params, result)
                        checkwidth(n.Type)
                        addmethod(sym, n.Type, false, nointerface)
@@ -581,19 +571,22 @@ func (p *importer) fieldList() (fields []*Field) {
 
 func (p *importer) field() *Field {
        p.pos()
-       sym := p.fieldName()
+       sym, alias := p.fieldName()
        typ := p.typ()
        note := p.string()
 
        f := newField()
        if sym.Name == "" {
-               // anonymous field - typ must be T or *T and T must be a type name
+               // anonymous field: typ must be T or *T and T must be a type name
                s := typ.Sym
                if s == nil && typ.IsPtr() {
                        s = typ.Elem().Sym // deref
                }
                sym = sym.Pkg.Lookup(s.Name)
                f.Embedded = 1
+       } else if alias {
+               // anonymous field: we have an explicit name because it's a type alias
+               f.Embedded = 1
        }
 
        f.Sym = sym
@@ -616,7 +609,7 @@ func (p *importer) methodList() (methods []*Field) {
 
 func (p *importer) method() *Field {
        p.pos()
-       sym := p.fieldName()
+       sym := p.methodName()
        params := p.paramList()
        result := p.paramList()
 
@@ -627,18 +620,44 @@ func (p *importer) method() *Field {
        return f
 }
 
-func (p *importer) fieldName() *Sym {
+func (p *importer) fieldName() (*Sym, bool) {
        name := p.string()
        if p.version == 0 && name == "_" {
-               // version 0 didn't export a package for _ fields
+               // version 0 didn't export a package for _ field names
                // but used the builtin package instead
-               return builtinpkg.Lookup(name)
+               return builtinpkg.Lookup(name), false
        }
        pkg := localpkg
-       if name != "" && !exportname(name) {
-               if name == "?" {
-                       name = ""
+       alias := false
+       switch name {
+       case "":
+               // 1) field name matches base type name and is exported: nothing to do
+       case "?":
+               // 2) field name matches base type name and is not exported: need package
+               name = ""
+               pkg = p.pkg()
+       case "@":
+               // 3) field name doesn't match base type name (alias name): need name and possibly package
+               name = p.string()
+               alias = true
+               fallthrough
+       default:
+               if !exportname(name) {
+                       pkg = p.pkg()
                }
+       }
+       return pkg.Lookup(name), alias
+}
+
+func (p *importer) methodName() *Sym {
+       name := p.string()
+       if p.version == 0 && name == "_" {
+               // version 0 didn't export a package for _ method names
+               // but used the builtin package instead
+               return builtinpkg.Lookup(name)
+       }
+       pkg := localpkg
+       if !exportname(name) {
                pkg = p.pkg()
        }
        return pkg.Lookup(name)
index e02e2feb016b6498866aeda2462dbae383dddd27..71b323f8a1d1b2796b079578e3b05346d1a6e6dc 100644 (file)
@@ -15,6 +15,7 @@ var runtimeDecls = [...]struct {
        {"panicwrap", funcTag, 7},
        {"gopanic", funcTag, 9},
        {"gorecover", funcTag, 12},
+       {"goschedguarded", funcTag, 5},
        {"printbool", funcTag, 14},
        {"printfloat", funcTag, 16},
        {"printint", funcTag, 18},
index 98e25fefb899c710c28b14f36748be88f5aa9cf5..69511155f4728b431531d51f14139861e9f84b13 100644 (file)
@@ -21,6 +21,7 @@ func panicwrap(string, string, string)
 
 func gopanic(interface{})
 func gorecover(*int32) interface{}
+func goschedguarded()
 
 func printbool(bool)
 func printfloat(float64)
index 8af78c156af3fa442b1b7e2db489145270c4278f..6cf970dbad6bf07e7f18d7e98c518cffe2463a78 100644 (file)
@@ -5,6 +5,7 @@
 package gc
 
 import (
+       "cmd/compile/internal/syntax"
        "cmd/internal/obj"
        "cmd/internal/src"
        "fmt"
@@ -520,10 +521,6 @@ func funchdr(n *Node) {
                Fatalf("funchdr: dclcontext = %d", dclcontext)
        }
 
-       if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
-               makefuncsym(n.Func.Nname.Sym)
-       }
-
        dclcontext = PAUTO
        funcstart(n)
 
@@ -696,10 +693,20 @@ func typedcl0(s *Sym) *Node {
 
 // node n, which was returned by typedcl0
 // is being declared to have uncompiled type t.
-// return the ODCLTYPE node to use.
-func typedcl1(n *Node, t *Node, local bool) *Node {
-       n.Name.Param.Ntype = t
-       n.Local = local
+// returns the ODCLTYPE node to use.
+func typedcl1(n *Node, t *Node, pragma syntax.Pragma, alias bool) *Node {
+       if pragma != 0 && alias {
+               yyerror("cannot specify directive with type alias")
+               pragma = 0
+       }
+
+       n.Local = true
+
+       p := n.Name.Param
+       p.Ntype = t
+       p.Pragma = pragma
+       p.Alias = alias
+
        return nod(ODCLTYPE, n, nil)
 }
 
@@ -1154,19 +1161,19 @@ bad:
        return nil
 }
 
-func methodname(n *Node, t *Node) *Node {
+// methodname is a misnomer because this now returns a Sym, rather
+// than an ONAME.
+// TODO(mdempsky): Reconcile with methodsym.
+func methodname(s *Sym, recv *Type) *Sym {
        star := false
-       if t.Op == OIND {
+       if recv.IsPtr() {
                star = true
-               t = t.Left
+               recv = recv.Elem()
        }
 
-       return methodname0(n.Sym, star, t.Sym)
-}
-
-func methodname0(s *Sym, star bool, tsym *Sym) *Node {
+       tsym := recv.Sym
        if tsym == nil || isblanksym(s) {
-               return newfuncname(s)
+               return s
        }
 
        var p string
@@ -1182,14 +1189,13 @@ func methodname0(s *Sym, star bool, tsym *Sym) *Node {
                s = Pkglookup(p, tsym.Pkg)
        }
 
-       return newfuncname(s)
+       return s
 }
 
 // Add a method, declared as a function.
 // - msym is the method symbol
 // - t is function type (with receiver)
 func addmethod(msym *Sym, t *Type, local, nointerface bool) {
-       // get field sym
        if msym == nil {
                Fatalf("no method symbol")
        }
@@ -1310,7 +1316,7 @@ func funcsym(s *Sym) *Sym {
        s1 := Pkglookup(s.Name+"·f", s.Pkg)
        if !Ctxt.Flag_dynlink && s1.Def == nil {
                s1.Def = newfuncname(s1)
-               s1.Def.Func.Shortname = newname(s)
+               s1.Def.Func.Shortname = s
                funcsyms = append(funcsyms, s1.Def)
        }
        s.Fsym = s1
@@ -1327,8 +1333,11 @@ func makefuncsym(s *Sym) {
                return
        }
        s1 := funcsym(s)
+       if s1.Def != nil {
+               return
+       }
        s1.Def = newfuncname(s1)
-       s1.Def.Func.Shortname = newname(s)
+       s1.Def.Func.Shortname = s
        funcsyms = append(funcsyms, s1.Def)
 }
 
index b4c15e40b1d14ac31adfe567158d2f15f47db85c..58b2bf8121bf73cace44cd7cf1d18099c3b27024 100644 (file)
@@ -45,8 +45,8 @@ func exportsym(n *Node) {
                fmt.Printf("export symbol %v\n", n.Sym)
        }
 
-       // Ensure original object is on exportlist before aliases.
-       if n.Sym.Flags&SymAlias != 0 {
+       // Ensure original types are on exportlist before type aliases.
+       if n.Sym.isAlias() {
                exportlist = append(exportlist, n.Sym.Def)
        }
 
@@ -83,7 +83,7 @@ func autoexport(n *Node, ctxt Class) {
        if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
                return
        }
-       if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method
+       if n.Type != nil && n.Type.IsKind(TFUNC) && n.Type.Recv() != nil { // method
                return
        }
 
@@ -348,6 +348,27 @@ func importvar(s *Sym, t *Type) {
        }
 }
 
+// importalias declares symbol s as an imported type alias with type t.
+func importalias(s *Sym, t *Type) {
+       importsym(s, OTYPE)
+       if s.Def != nil && s.Def.Op == OTYPE {
+               if eqtype(t, s.Def.Type) {
+                       return
+               }
+               yyerror("inconsistent definition for type alias %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
+       }
+
+       n := newname(s)
+       n.Op = OTYPE
+       s.Importdef = importpkg
+       n.Type = t
+       declare(n, PEXTERN)
+
+       if Debug['E'] != 0 {
+               fmt.Printf("import type %v = %L\n", s, t)
+       }
+}
+
 func dumpasmhdr() {
        b, err := bio.Create(asmhdr)
        if err != nil {
index 6e973eee5cb6443a00559807df80528df1d5eb42..e76d38a64b1b988937e1c04d9c4014d09aea360a 100644 (file)
@@ -1077,6 +1077,7 @@ var opprec = []int{
        OSEND:         3,
        OANDAND:       2,
        OOROR:         1,
+
        // Statements handled by stmtfmt
        OAS:         -1,
        OAS2:        -1,
@@ -1104,7 +1105,8 @@ var opprec = []int{
        OSWITCH:     -1,
        OXCASE:      -1,
        OXFALL:      -1,
-       OEND:        0,
+
+       OEND: 0,
 }
 
 func (n *Node) exprfmt(s fmt.State, prec int) {
index 26b11a27b6f584ff1d2070441acb6ab3e1c9ac2f..07c4d03b8bd71af6fd7bed9db3f44997ac96af44 100644 (file)
@@ -64,9 +64,12 @@ const (
        SymSiggen
        SymAsm
        SymAlgGen
-       SymAlias // alias, original is Sym.Def.Sym
 )
 
+func (sym *Sym) isAlias() bool {
+       return sym.Def != nil && sym.Def.Sym != sym
+}
+
 // The Class of a variable/function describes the "storage class"
 // of a variable or function. During parsing, storage classes are
 // called declaration contexts.
@@ -88,7 +91,7 @@ const (
 // of the compilers arrays.
 //
 // typedef     struct
-// {                                   // must not move anything
+// {                           // must not move anything
 //     uchar   array[8];       // pointer to data
 //     uchar   nel[4];         // number of elements
 //     uchar   cap[4];         // allocated number of elements
@@ -105,7 +108,7 @@ var sizeof_Array int // runtime sizeof(Array)
 // of the compilers strings.
 //
 // typedef     struct
-// {                                   // must not move anything
+// {                           // must not move anything
 //     uchar   array[8];       // pointer to data
 //     uchar   nel[4];         // number of elements
 // } String;
index 1f4f18eb80feba7c23c6753b402b97f4e0c97a7a..a9f041c4c37954ab17ced21b868ff86b304d5844 100644 (file)
@@ -31,11 +31,12 @@ var (
 )
 
 var (
-       Debug_append  int
-       Debug_closure int
-       Debug_panic   int
-       Debug_slice   int
-       Debug_wb      int
+       Debug_append   int
+       Debug_closure  int
+       debug_dclstack int
+       Debug_panic    int
+       Debug_slice    int
+       Debug_wb       int
 )
 
 // Debug arguments.
@@ -49,6 +50,7 @@ var debugtab = []struct {
        {"append", &Debug_append},         // print information about append compilation
        {"closure", &Debug_closure},       // print information about closure compilation
        {"disablenil", &disable_checknil}, // disable nil checks
+       {"dclstack", &debug_dclstack},     // run internal dclstack checks
        {"gcprog", &Debug_gcprog},         // print dump of GC programs
        {"nil", &Debug_checknil},          // print information about nil checks
        {"panic", &Debug_panic},           // do not hide any compiler panic
@@ -329,7 +331,6 @@ func Main() {
        timings.Stop()
        timings.AddEvent(int64(lines), "lines")
 
-       testdclstack()
        finishUniverse()
 
        typecheckok = true
@@ -342,13 +343,16 @@ func Main() {
        // Phase 1: const, type, and names and types of funcs.
        //   This will gather all the information about types
        //   and methods but doesn't depend on any of it.
+       //   We also defer type alias declarations until phase 2
+       //   to avoid cycles like #18640.
        defercheckwidth()
 
        // Don't use range--typecheck can add closures to xtop.
        timings.Start("fe", "typecheck", "top1")
        for i := 0; i < len(xtop); i++ {
-               if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 {
-                       xtop[i] = typecheck(xtop[i], Etop)
+               n := xtop[i]
+               if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
+                       xtop[i] = typecheck(n, Etop)
                }
        }
 
@@ -358,8 +362,9 @@ func Main() {
        // Don't use range--typecheck can add closures to xtop.
        timings.Start("fe", "typecheck", "top2")
        for i := 0; i < len(xtop); i++ {
-               if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 {
-                       xtop[i] = typecheck(xtop[i], Etop)
+               n := xtop[i]
+               if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
+                       xtop[i] = typecheck(n, Etop)
                }
        }
        resumecheckwidth()
@@ -369,8 +374,9 @@ func Main() {
        timings.Start("fe", "typecheck", "func")
        var fcount int64
        for i := 0; i < len(xtop); i++ {
-               if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE {
-                       Curfn = xtop[i]
+               n := xtop[i]
+               if op := n.Op; op == ODCLFUNC || op == OCLOSURE {
+                       Curfn = n
                        decldepth = 1
                        saveerrors()
                        typecheckslice(Curfn.Nbody.Slice(), Etop)
@@ -462,8 +468,9 @@ func Main() {
        timings.Start("be", "compilefuncs")
        fcount = 0
        for i := 0; i < len(xtop); i++ {
-               if xtop[i].Op == ODCLFUNC {
-                       funccompile(xtop[i])
+               n := xtop[i]
+               if n.Op == ODCLFUNC {
+                       funccompile(n)
                        fcount++
                }
        }
@@ -931,7 +938,7 @@ func clearImports() {
                        continue
                }
 
-               if s.Def.Sym != s && s.Flags&SymAlias == 0 {
+               if s.isAlias() {
                        // throw away top-level name left over
                        // from previous import . "x"
                        if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
index 1207c3f6149a2e902797c501427c9c1874b0e126..e4378544f0114d5225d9a761185bd9ed6b44bbcd 100644 (file)
@@ -51,6 +51,7 @@ func parseFiles(filenames []string) uint {
                if nsyntaxerrors != 0 {
                        errorexit()
                }
+               // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
                testdclstack()
        }
 
@@ -215,11 +216,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
 
 func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
        names := p.declNames(decl.NameList)
-
-       var typ *Node
-       if decl.Type != nil {
-               typ = p.typeExpr(decl.Type)
-       }
+       typ := p.typeExprOrNil(decl.Type)
 
        var exprs []*Node
        if decl.Values != nil {
@@ -232,11 +229,7 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
 
 func (p *noder) constDecl(decl *syntax.ConstDecl) []*Node {
        names := p.declNames(decl.NameList)
-
-       var typ *Node
-       if decl.Type != nil {
-               typ = p.typeExpr(decl.Type)
-       }
+       typ := p.typeExprOrNil(decl.Type)
 
        var exprs []*Node
        if decl.Values != nil {
@@ -248,14 +241,11 @@ func (p *noder) constDecl(decl *syntax.ConstDecl) []*Node {
 
 func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
        name := typedcl0(p.name(decl.Name))
-       name.Name.Param.Pragma = decl.Pragma
 
-       var typ *Node
-       if decl.Type != nil {
-               typ = p.typeExpr(decl.Type)
-       }
+       // decl.Type may be nil but in that case we got a syntax error during parsing
+       typ := p.typeExprOrNil(decl.Type)
 
-       return typedcl1(name, typ, true)
+       return typedcl1(name, typ, syntax.Pragma(decl.Pragma), decl.Alias)
 }
 
 func (p *noder) declNames(names []*syntax.Name) []*Node {
@@ -320,19 +310,19 @@ func (p *noder) funcHeader(fun *syntax.FuncDecl) *Node {
                                yyerror("func main must have no arguments and no return values")
                        }
                }
-
-               f.Func.Nname = newfuncname(name)
        } else {
-               // Receiver MethodName Signature
-
-               f.Func.Shortname = newfuncname(name)
-               f.Func.Nname = methodname(f.Func.Shortname, t.Left.Right)
+               f.Func.Shortname = name
+               name = nblank.Sym // filled in by typecheckfunc
        }
 
+       f.Func.Nname = newfuncname(name)
        f.Func.Nname.Name.Defn = f
        f.Func.Nname.Name.Param.Ntype = t // TODO: check if nname already has an ntype
 
-       declare(f.Func.Nname, PFUNC)
+       if fun.Recv == nil {
+               declare(f.Func.Nname, PFUNC)
+       }
+
        funchdr(f)
        return f
 }
@@ -528,6 +518,13 @@ func (p *noder) typeExpr(typ syntax.Expr) *Node {
        return p.expr(typ)
 }
 
+func (p *noder) typeExprOrNil(typ syntax.Expr) *Node {
+       if typ != nil {
+               return p.expr(typ)
+       }
+       return nil
+}
+
 func (p *noder) chanDir(dir syntax.ChanDir) ChanDir {
        switch dir {
        case 0:
@@ -1088,6 +1085,7 @@ func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
                p.linknames = append(p.linknames, linkname{pos, f[1], f[2]})
 
        case strings.HasPrefix(text, "go:cgo_"):
+               // TODO(gri): lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
                p.pragcgobuf += pragcgo(text)
                fallthrough // because of //go:cgo_unsafe_args
        default:
index 08ed5604dadee55ac40c9b780f2b77de53f46c58..6d5f2aa208d229d92dd41f0f4e75432330653c90 100644 (file)
@@ -213,7 +213,7 @@ func dumpglobls() {
        }
 
        for _, n := range funcsyms {
-               dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0)
+               dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname, 0)
                ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA)
        }
 
index 4f9d92ed8a1333adbdc178332d8c275b919f988f..7cd02749a564584ba6cada5af28d90c729a30cfa 100644 (file)
@@ -511,7 +511,7 @@ func isExportedField(ft *Field) (bool, *Pkg) {
 // dnameField dumps a reflect.name for a struct field.
 func dnameField(s *Sym, ot int, spkg *Pkg, ft *Field) int {
        var name string
-       if ft.Sym != nil && ft.Embedded == 0 {
+       if ft.Sym != nil {
                name = ft.Sym.Name
        }
        isExported, fpkg := isExportedField(ft)
@@ -998,7 +998,6 @@ func itabname(t, itype *Type) *Node {
                Fatalf("itabname(%v, %v)", t, itype)
        }
        s := Pkglookup(t.tconv(FmtLeft)+","+itype.tconv(FmtLeft), itabpkg)
-       Linksym(s).Set(obj.AttrLocal, true)
        if s.Def == nil {
                n := newname(s)
                n.Type = Types[TUINT8]
@@ -1346,7 +1345,14 @@ ok:
                        // ../../../../runtime/type.go:/structField
                        ot = dnameField(s, ot, pkg, f)
                        ot = dsymptr(s, ot, dtypesym(f.Type), 0)
-                       ot = duintptr(s, ot, uint64(f.Offset))
+                       offsetAnon := uint64(f.Offset) << 1
+                       if offsetAnon>>1 != uint64(f.Offset) {
+                               Fatalf("%v: bad field offset for %s", t, f.Sym.Name)
+                       }
+                       if f.Embedded != 0 {
+                               offsetAnon |= 1
+                       }
+                       ot = duintptr(s, ot, offsetAnon)
                }
        }
 
@@ -1411,15 +1417,15 @@ func dumptypestructs() {
                // }
                o := dsymptr(i.sym, 0, dtypesym(i.itype), 0)
                o = dsymptr(i.sym, o, dtypesym(i.t), 0)
-               o += Widthptr + 8                      // skip link/bad/unused fields
+               o += Widthptr + 8                      // skip link/bad/inhash fields
                o += len(imethods(i.itype)) * Widthptr // skip fun method pointers
                // at runtime the itab will contain pointers to types, other itabs and
                // method functions. None are allocated on heap, so we can use obj.NOPTR.
-               ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR|obj.LOCAL))
+               ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR))
 
                ilink := Pkglookup(i.t.tconv(FmtLeft)+","+i.itype.tconv(FmtLeft), itablinkpkg)
                dsymptr(ilink, 0, i.sym, 0)
-               ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA|obj.LOCAL))
+               ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA))
        }
 
        // process ptabs
index 7a07d4ea0c779f6579db0a4d3b4ffb145b78b0a5..29819e92b2ccc9f779c0c34b03f89cab7240d475 100644 (file)
@@ -1078,6 +1078,8 @@ func anylit(n *Node, var_ *Node, init *Nodes) {
 
                var r *Node
                if n.Right != nil {
+                       // n.Right is stack temporary used as backing store.
+                       init.Append(nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410)
                        r = nod(OADDR, n.Right, nil)
                        r = typecheck(r, Erv)
                } else {
@@ -1195,7 +1197,7 @@ func getlit(lit *Node) int {
        return -1
 }
 
-// stataddr sets nam to the static address of n and reports whether it succeeeded.
+// stataddr sets nam to the static address of n and reports whether it succeeded.
 func stataddr(nam *Node, n *Node) bool {
        if n == nil {
                return false
index ef60ad7acceeade9dba4fcceaea7992b09839e4c..da6b69fc5e26e70c9744673f91f0b77290a39c02 100644 (file)
@@ -65,6 +65,9 @@ func buildssa(fn *Node) *ssa.Func {
        s.config = initssa()
        s.f = s.config.NewFunc()
        s.f.Name = name
+       if fn.Func.Pragma&Nosplit != 0 {
+               s.f.NoSplit = true
+       }
        s.exitCode = fn.Func.Exit
        s.panics = map[funcLine]*ssa.Block{}
        s.config.DebugTest = s.config.DebugHashMatch("GOSSAHASH", name)
index f067ce86f28fa9fb4ec07258654a164dd1a15404..6a5e1a478e6d4d572b7691d892cba6fd8d7ec5be 100644 (file)
@@ -1804,7 +1804,9 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
        funcbody(fn)
        Curfn = fn
        popdcl()
-       testdclstack()
+       if debug_dclstack != 0 {
+               testdclstack()
+       }
 
        // wrappers where T is anonymous (struct or interface) can be duplicated.
        if rcvr.IsStruct() || rcvr.IsInterface() || rcvr.IsPtr() && rcvr.Elem().IsStruct() {
index 3039aeb4025e803fedb4d5ef56839259b7d2cded..923055c9622d3e131e783a911d988c946152ef3e 100644 (file)
@@ -32,7 +32,7 @@ type Node struct {
        // func
        Func *Func
 
-       // ONAME
+       // ONAME, OTYPE, OPACK, OLABEL, some OLITERAL
        Name *Name
 
        Sym *Sym        // various
@@ -64,8 +64,8 @@ type Node struct {
        Noescape  bool  // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
        Walkdef   uint8 // tracks state during typecheckdef; 2 == loop detected
        Typecheck uint8 // tracks state during typechecking; 2 == loop detected
-       Local     bool
-       IsStatic  bool // whether this Node will be converted to purely static data
+       Local     bool  // type created in this file (see also Type.Local); TODO(gri): move this into flags
+       IsStatic  bool  // whether this Node will be converted to purely static data
        Initorder uint8
        Used      bool // for variable/label declared and not used error
        Isddd     bool // is the argument variadic
@@ -185,14 +185,14 @@ func (n *Node) SetIota(x int64) {
        n.Xoffset = x
 }
 
-// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, some OLITERAL).
+// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
 type Name struct {
        Pack      *Node  // real package for import . names
        Pkg       *Pkg   // pkg for OPACK nodes
        Heapaddr  *Node  // temp holding heap address of param (could move to Param?)
        Defn      *Node  // initializing assignment
        Curfn     *Node  // function for local variables
-       Param     *Param // additional fields for ONAME
+       Param     *Param // additional fields for ONAME, OTYPE
        Decldepth int32  // declaration loop depth, increased for every loop or label
        Vargen    int32  // unique name for ONAME within a function.  Function outputs are numbered starting at one.
        Funcdepth int32
@@ -285,15 +285,16 @@ type Param struct {
        Innermost *Node
        Outer     *Node
 
-       // OTYPE pragmas
+       // OTYPE
        //
        // TODO: Should Func pragmas also be stored on the Name?
        Pragma syntax.Pragma
+       Alias  bool // node is alias for Ntype (only used when type-checking ODCLTYPE)
 }
 
 // Func holds Node fields used only with function-like nodes.
 type Func struct {
-       Shortname  *Node
+       Shortname  *Sym
        Enter      Nodes // for example, allocate and initialize memory for escaping parameters
        Exit       Nodes
        Cvars      Nodes   // closure params
@@ -387,7 +388,7 @@ const (
        ODCLFUNC  // func f() or func (r) f()
        ODCLFIELD // struct field, interface field, or func/method argument/return value.
        ODCLCONST // const pi = 3.14
-       ODCLTYPE  // type Int int
+       ODCLTYPE  // type Int int or type Int = int
 
        ODELETE    // delete(Left, Right)
        ODOT       // Left.Sym (Left is of struct type)
index 0334339d43f349b00dd2aa4ece3c3dfc11523802..6be8d9155ba1fe0004f53a24eec40e6274bf4d08 100644 (file)
@@ -106,7 +106,7 @@ func testSliceSetElement() {
 func testSlicePanic1() {
        defer func() {
                if r := recover(); r != nil {
-                       println("paniced as expected")
+                       println("panicked as expected")
                }
        }()
 
@@ -119,7 +119,7 @@ func testSlicePanic1() {
 func testSlicePanic2() {
        defer func() {
                if r := recover(); r != nil {
-                       println("paniced as expected")
+                       println("panicked as expected")
                }
        }()
 
index 897e874ee5d1ac579b9d9fcba17b1658419a93f8..03053a6134a925181b462df46c18368f410b7033 100644 (file)
@@ -73,7 +73,7 @@ func testStructSlice() {
 func testStringSlicePanic() {
        defer func() {
                if r := recover(); r != nil {
-                       println("paniced as expected")
+                       println("panicked as expected")
                }
        }()
 
@@ -148,7 +148,7 @@ func testInt64Index() {
 func testInt64IndexPanic() {
        defer func() {
                if r := recover(); r != nil {
-                       println("paniced as expected")
+                       println("panicked as expected")
                }
        }()
 
@@ -161,7 +161,7 @@ func testInt64IndexPanic() {
 func testInt64SlicePanic() {
        defer func() {
                if r := recover(); r != nil {
-                       println("paniced as expected")
+                       println("panicked as expected")
                }
        }()
 
index 6143d95f576547596224e2685a055e4a3bce35ab..249cd3e3b95e5ae1f2c96e432745afac3aaac039 100644 (file)
@@ -214,7 +214,7 @@ func (t *Type) FuncType() *FuncType {
        return t.Extra.(*FuncType)
 }
 
-// InterMethType contains Type fields specific to interface method psuedo-types.
+// InterMethType contains Type fields specific to interface method pseudo-types.
 type InterMethType struct {
        Nname *Node
 }
index 70d9da4b2dfb2589682aecbcebe9c0b75dc30950..1467189458b82a6a71370aea52c04d492ee6cfc6 100644 (file)
@@ -97,16 +97,16 @@ func typekind(t *Type) string {
        return fmt.Sprintf("etype=%d", et)
 }
 
-// sprint_depchain prints a dependency chain of nodes into fmt.
+// sprint_depchain prints a dependency chain of nodes into trace.
 // It is used by typecheck in the case of OLITERAL nodes
 // to print constant definition loops.
-func sprint_depchain(fmt_ *string, stack []*Node, cur *Node, first *Node) {
+func sprint_depchain(trace *string, stack []*Node, cur *Node, first *Node) {
        for i := len(stack) - 1; i >= 0; i-- {
                if n := stack[i]; n.Op == cur.Op {
                        if n != first {
-                               sprint_depchain(fmt_, stack[:i], n, first)
+                               sprint_depchain(trace, stack[:i], n, first)
                        }
-                       *fmt_ += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
+                       *trace += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
                        return
                }
        }
@@ -153,7 +153,6 @@ func typecheck(n *Node, top int) *Node {
        if n.Typecheck == 2 {
                // Typechecking loop. Trying printing a meaningful message,
                // otherwise a stack trace of typechecking.
-               var fmt_ string
                switch n.Op {
                // We can already diagnose variables used as types.
                case ONAME:
@@ -161,22 +160,30 @@ func typecheck(n *Node, top int) *Node {
                                yyerror("%v is not a type", n)
                        }
 
+               case OTYPE:
+                       if top&Etype == Etype {
+                               var trace string
+                               sprint_depchain(&trace, typecheck_tcstack, n, n)
+                               yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, trace)
+                       }
+
                case OLITERAL:
                        if top&(Erv|Etype) == Etype {
                                yyerror("%v is not a type", n)
                                break
                        }
-                       sprint_depchain(&fmt_, typecheck_tcstack, n, n)
-                       yyerrorl(n.Pos, "constant definition loop%s", fmt_)
+                       var trace string
+                       sprint_depchain(&trace, typecheck_tcstack, n, n)
+                       yyerrorl(n.Pos, "constant definition loop%s", trace)
                }
 
                if nsavederrors+nerrors == 0 {
-                       fmt_ = ""
+                       var trace string
                        for i := len(typecheck_tcstack) - 1; i >= 0; i-- {
                                x := typecheck_tcstack[i]
-                               fmt_ += fmt.Sprintf("\n\t%v %v", x.Line(), x)
+                               trace += fmt.Sprintf("\n\t%v %v", x.Line(), x)
                        }
-                       yyerror("typechecking loop involving %v%s", n, fmt_)
+                       yyerror("typechecking loop involving %v%s", n, trace)
                }
 
                lineno = lno
@@ -860,7 +867,7 @@ OpSwitch:
                        }
 
                        if n.Type.Etype != TFUNC || !n.IsMethod() {
-                               yyerror("type %v has no method %S", n.Left.Type, n.Right.Sym)
+                               yyerror("type %v has no method %S", n.Left.Type, n.Sym)
                                n.Type = nil
                                return n
                        }
@@ -3430,7 +3437,14 @@ func typecheckfunc(n *Node) {
        t.SetNname(n.Func.Nname)
        rcvr := t.Recv()
        if rcvr != nil && n.Func.Shortname != nil {
-               addmethod(n.Func.Shortname.Sym, t, true, n.Func.Pragma&Nointerface != 0)
+               n.Func.Nname.Sym = methodname(n.Func.Shortname, rcvr.Type)
+               declare(n.Func.Nname, PFUNC)
+
+               addmethod(n.Func.Shortname, t, true, n.Func.Pragma&Nointerface != 0)
+       }
+
+       if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
+               makefuncsym(n.Func.Nname.Sym)
        }
 }
 
@@ -3579,8 +3593,6 @@ func typecheckdeftype(n *Node) {
 
        // copy new type and clear fields
        // that don't come along.
-       // anything zeroed here must be zeroed in
-       // typedcl2 too.
        copytype(n, t)
 
 ret:
@@ -3759,12 +3771,29 @@ func typecheckdef(n *Node) *Node {
                n.Name.Defn = typecheck(n.Name.Defn, Etop) // fills in n->type
 
        case OTYPE:
+               if p := n.Name.Param; p.Alias {
+                       // Type alias declaration: Simply use the rhs type - no need
+                       // to create a new type.
+                       // If we have a syntax error, p.Ntype may be nil.
+                       if p.Ntype != nil {
+                               p.Ntype = typecheck(p.Ntype, Etype)
+                               n.Type = p.Ntype.Type
+                               if n.Type == nil {
+                                       n.Diag = true
+                                       goto ret
+                               }
+                               n.Sym.Def = p.Ntype
+                       }
+                       break
+               }
+
+               // regular type declaration
                if Curfn != nil {
                        defercheckwidth()
                }
                n.Walkdef = 1
                n.Type = typ(TFORW)
-               n.Type.Sym = n.Sym
+               n.Type.Sym = n.Sym // TODO(gri) this also happens in typecheckdeftype(n) - where should it happen?
                nerrors0 := nerrors
                typecheckdeftype(n)
                if n.Type.Etype == TFORW && nerrors > nerrors0 {
@@ -3772,7 +3801,6 @@ func typecheckdef(n *Node) *Node {
                        // but it was reported. Silence future errors.
                        n.Type.Broke = true
                }
-
                if Curfn != nil {
                        resumecheckwidth()
                }
index 30c9c3783af187cbefa9797e038f0c984691fdca..d23aebeafbb78cf23ec14fd6f94e1a53a9d0370e 100644 (file)
@@ -398,6 +398,14 @@ func lexinit1() {
        // errortype.Orig = makeErrorInterface()
        s.Def = typenod(errortype)
 
+       // We create separate byte and rune types for better error messages
+       // rather than just creating type alias *Sym's for the uint8 and
+       // int32 types. Hence, (bytetype|runtype).Sym.isAlias() is false.
+       // TODO(gri) Should we get rid of this special case (at the cost
+       // of less informative error messages involving bytes and runes)?
+       // (Alternatively, we could introduce an OTALIAS node representing
+       // type aliases, albeit at the cost of having to deal with it everywhere).
+
        // byte alias
        s = Pkglookup("byte", builtinpkg)
        bytetype = typ(TUINT8)
index cfc63738d645b4fa5c3b8bd137b8e9d166805800..790a1ae255e4efd9fa6d88806467c18b5c4a3244 100644 (file)
@@ -57,8 +57,13 @@ func startProfile() {
                        Fatalf("%v", err)
                }
                atExit(func() {
-                       runtime.GC() // profile all outstanding allocations
-                       if err := pprof.WriteHeapProfile(f); err != nil {
+                       // Profile all outstanding allocations.
+                       runtime.GC()
+                       // compilebench parses the memory profile to extract memstats,
+                       // which are only written in the legacy pprof format.
+                       // See golang.org/issue/18641 and runtime/pprof/pprof.go:writeHeap.
+                       const writeLegacyFormat = 1
+                       if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
                                Fatalf("%v", err)
                        }
                })
index 4db28342a29bce3cd52245f0a19087f62c9f772f..87084bc82ad3c49812c79e89be6234465d63d428 100644 (file)
@@ -694,6 +694,10 @@ opswitch:
                        break
                }
 
+               if !instrumenting && iszero(n.Right) && !needwritebarrier(n.Left, n.Right) {
+                       break
+               }
+
                switch n.Right.Op {
                default:
                        n.Right = walkexpr(n.Right, init)
@@ -3113,12 +3117,12 @@ func walkcompare(n *Node, init *Nodes) *Node {
                cmpr = cmpr.Left
        }
 
-       if !islvalue(cmpl) || !islvalue(cmpr) {
-               Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
-       }
-
        // Chose not to inline. Call equality function directly.
        if !inline {
+               if !islvalue(cmpl) || !islvalue(cmpr) {
+                       Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
+               }
+
                // eq algs take pointers
                pl := temp(ptrto(t))
                al := nod(OAS, pl, nod(OADDR, cmpl, nil))
index 018a4bcc907206b814c1b3c138afc687231b338f..c26ace4c32db8deb04807019c168660841424f52 100644 (file)
@@ -6,7 +6,7 @@ package ssa
 
 // checkbce prints all bounds checks that are present in the function.
 // Useful to find regressions. checkbce is only activated when with
-// corresponsing debug options, so it's off by default.
+// corresponding debug options, so it's off by default.
 // See test/checkbce.go
 func checkbce(f *Func) {
        if f.pass.debug <= 0 {
index 02d74673348f76fd9d6e6194cb76334dfadf87e7..975845f258796c9f0c0f7d6f29832985ddcd032c 100644 (file)
@@ -5,6 +5,7 @@
 package ssa
 
 import (
+       "cmd/internal/obj"
        "cmd/internal/src"
        "fmt"
        "log"
@@ -350,6 +351,8 @@ var passes = [...]pass{
        {name: "writebarrier", fn: writebarrier, required: true}, // expand write barrier ops
        {name: "fuse", fn: fuse},
        {name: "dse", fn: dse},
+       {name: "insert resched checks", fn: insertLoopReschedChecks,
+               disabled: obj.Preemptibleloops_enabled == 0}, // insert resched checks in loops.
        {name: "tighten", fn: tighten}, // move values closer to their uses
        {name: "lower", fn: lower, required: true},
        {name: "lowered cse", fn: cse},
@@ -379,7 +382,13 @@ type constraint struct {
 }
 
 var passOrder = [...]constraint{
-       // prove reliese on common-subexpression elimination for maximum benefits.
+       // "insert resched checks" uses mem, better to clean out stores first.
+       {"dse", "insert resched checks"},
+       // insert resched checks adds new blocks containing generic instructions
+       {"insert resched checks", "lower"},
+       {"insert resched checks", "tighten"},
+
+       // prove relies on common-subexpression elimination for maximum benefits.
        {"generic cse", "prove"},
        // deadcode after prove to eliminate all new dead blocks.
        {"prove", "generic deadcode"},
index 1cde6c85302506146e4989871502a11b1da6aa74..1cf05ef1cdd5a440e688ce85bfc50c255c22f850 100644 (file)
@@ -94,7 +94,7 @@ type Logger interface {
        // Warnl writes compiler messages in the form expected by "errorcheck" tests
        Warnl(pos src.XPos, fmt_ string, args ...interface{})
 
-       // Fowards the Debug flags from gc
+       // Forwards the Debug flags from gc
        Debug_checknil() bool
        Debug_wb() bool
 }
index e92ae329914c4c6851aa19bd479f27940811a1fc..e931f2285b75788120e9be1be94ebf32e481d63f 100644 (file)
@@ -25,6 +25,7 @@ type Func struct {
        vid        idAlloc     // value ID allocator
 
        scheduled bool // Values in Blocks are in final order
+       NoSplit   bool // true if function is marked as nosplit.  Used by schedule check pass.
 
        // when register allocation is done, maps value ids to locations
        RegAlloc []Location
index dce61e3b8a1e8d65518f334814a4466d02d86bd4..e8d5be258218018c1a280eeb68a4639431589f9d 100644 (file)
@@ -12,7 +12,7 @@ import "strings"
 //  - Integer types live in the low portion of registers. Upper portions are junk.
 //  - Boolean types use the low-order byte of a register. 0=false, 1=true.
 //    Upper bytes are junk.
-//  - *const instructions may use a constant larger than the instuction can encode.
+//  - *const instructions may use a constant larger than the instruction can encode.
 //    In this case the assembler expands to multiple instructions and uses tmp
 //    register (R27).
 
index 5bf3c0091a16f68c5bb5a24a104d4ff58b8ad194..e296d0600d0ad13419576fc683876d31990f4cd0 100644 (file)
@@ -12,7 +12,7 @@ import "strings"
 //  - Integer types live in the low portion of registers. Upper portions are junk.
 //  - Boolean types use the low-order byte of a register. 0=false, 1=true.
 //    Upper bytes are junk.
-//  - *const instructions may use a constant larger than the instuction can encode.
+//  - *const instructions may use a constant larger than the instruction can encode.
 //    In this case the assembler expands to multiple instructions and uses tmp
 //    register (R11).
 
index d7d7fece28aac691602398388f69346ee7a9ac0c..020d6930d7c3b7998668fd60d2251592a7f52aab 100644 (file)
@@ -12,7 +12,7 @@ import "strings"
 //  - Integer types live in the low portion of registers. Upper portions are junk.
 //  - Boolean types use the low-order byte of a register. 0=false, 1=true.
 //    Upper bytes are junk.
-//  - *const instructions may use a constant larger than the instuction can encode.
+//  - *const instructions may use a constant larger than the instruction can encode.
 //    In this case the assembler expands to multiple instructions and uses tmp
 //    register (R23).
 
index c803c4951967b5fd19c29d0a7b8fc5c08ae888c9..78b961ffb2a8e854254fc629f2213e1fd6c6f6a4 100644 (file)
@@ -13,7 +13,7 @@ import "strings"
 //  - Boolean types use the low-order byte of a register. 0=false, 1=true.
 //    Upper bytes are junk.
 //  - Unused portions of AuxInt are filled by sign-extending the used portion.
-//  - *const instructions may use a constant larger than the instuction can encode.
+//  - *const instructions may use a constant larger than the instruction can encode.
 //    In this case the assembler expands to multiple instructions and uses tmp
 //    register (R23).
 
index 0e0f1f9c1e79c9bc19b1b3d4640760f8cc471914..cad753e591d8c995feece7eedea7a471a890940d 100644 (file)
 (Geq32F x y) -> (FGreaterEqual (FCMPU x y))
 (Geq64F x y) -> (FGreaterEqual (FCMPU x y))
 
-(Geq8U x y)  -> (GreaterEqual (CMPU (ZeroExt8to32 x) (ZeroExt8to32 y)))
-(Geq16U x y) -> (GreaterEqual (CMPU (ZeroExt16to32 x) (ZeroExt16to32 y)))
-(Geq32U x y) -> (GreaterEqual (CMPU x y))
+(Geq8U x y)  -> (GreaterEqual (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Geq16U x y) -> (GreaterEqual (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Geq32U x y) -> (GreaterEqual (CMPWU x y))
 (Geq64U x y) -> (GreaterEqual (CMPU x y))
 
 // Absorb pseudo-ops into blocks.
index d7a1363c0cf8bae135790bafdd2277f6e77d3eef..003479774a486baba8b7e502c599f13145157792 100644 (file)
@@ -12,7 +12,7 @@ import "strings"
 //  - Less-than-64-bit integer types live in the low portion of registers.
 //    For now, the upper portion is junk; sign/zero-extension might be optimized in the future, but not yet.
 //  - Boolean types are zero or 1; stored in a byte, but loaded with AMOVBZ so the upper bytes of a register are zero.
-//  - *const instructions may use a constant larger than the instuction can encode.
+//  - *const instructions may use a constant larger than the instruction can encode.
 //    In this case the assembler expands to multiple instructions and uses tmp
 //    register (R31).
 
index 3e0533a95142d3bb8f883a8b609339086bca9ce7..be0d581fe099289c09ee805370af5588848cdee7 100644 (file)
 (MOVDEQ y _ (FlagLT)) -> y
 (MOVDEQ y _ (FlagGT)) -> y
 
-(MOVDNE _ y (FlagEQ)) -> y
-(MOVDNE x _ (FlagLT)) -> x
-(MOVDNE x _ (FlagGT)) -> x
+(MOVDNE y _ (FlagEQ)) -> y
+(MOVDNE _ x (FlagLT)) -> x
+(MOVDNE _ x (FlagGT)) -> x
 
 (MOVDLT y _ (FlagEQ)) -> y
 (MOVDLT _ x (FlagLT)) -> x
diff --git a/src/cmd/compile/internal/ssa/loopreschedchecks.go b/src/cmd/compile/internal/ssa/loopreschedchecks.go
new file mode 100644 (file)
index 0000000..7e6f0d8
--- /dev/null
@@ -0,0 +1,517 @@
+// Copyright 2016 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 ssa
+
+import "fmt"
+
+// an edgeMemCtr records a backedge, together with the memory and
+// counter phi functions at the target of the backedge that must
+// be updated when a rescheduling check replaces the backedge.
+type edgeMemCtr struct {
+       e Edge
+       m *Value // phi for memory at dest of e
+       c *Value // phi for counter at dest of e
+}
+
+// a rewriteTarget is a a value-argindex pair indicating
+// where a rewrite is applied.  Note that this is for values,
+// not for block controls, because block controls are not targets
+// for the rewrites performed in inserting rescheduling checks.
+type rewriteTarget struct {
+       v *Value
+       i int
+}
+
+type rewrite struct {
+       before, after *Value          // before is the expected value before rewrite, after is the new value installed.
+       rewrites      []rewriteTarget // all the targets for this rewrite.
+}
+
+func (r *rewrite) String() string {
+       s := "\n\tbefore=" + r.before.String() + ", after=" + r.after.String()
+       for _, rw := range r.rewrites {
+               s += ", (i=" + fmt.Sprint(rw.i) + ", v=" + rw.v.LongString() + ")"
+       }
+       s += "\n"
+       return s
+}
+
+const initialRescheduleCounterValue = 1021 // Largest 10-bit prime. 97 nSec loop bodies will check every 100 uSec.
+
+// insertLoopReschedChecks inserts rescheduling checks on loop backedges.
+func insertLoopReschedChecks(f *Func) {
+       // TODO: when split information is recorded in export data, insert checks only on backedges that can be reached on a split-call-free path.
+
+       // Loop reschedule checks decrement a per-function counter
+       // shared by all loops, and when the counter becomes non-positive
+       // a call is made to a rescheduling check in the runtime.
+       //
+       // Steps:
+       // 1. locate backedges.
+       // 2. Record memory definitions at block end so that
+       //    the SSA graph for mem can be prperly modified.
+       // 3. Define a counter and record its future uses (at backedges)
+       //    (Same process as 2, applied to a single definition of the counter.
+       //     difference for mem is that there are zero-to-many existing mem
+       //     definitions, versus exactly one for the new counter.)
+       // 4. Ensure that phi functions that will-be-needed for mem and counter
+       //    are present in the graph, initially with trivial inputs.
+       // 5. Record all to-be-modified uses of mem and counter;
+       //    apply modifications (split into two steps to simplify and
+       //    avoided nagging order-dependences).
+       // 6. Rewrite backedges to include counter check, reschedule check,
+       //    and modify destination phi function appropriately with new
+       //    definitions for mem and counter.
+
+       if f.NoSplit { // nosplit functions don't reschedule.
+               return
+       }
+
+       backedges := backedges(f)
+       if len(backedges) == 0 { // no backedges means no rescheduling checks.
+               return
+       }
+
+       lastMems := findLastMems(f)
+
+       idom := f.Idom()
+       sdom := f.sdom()
+
+       if f.pass.debug > 2 {
+               fmt.Printf("before %s = %s\n", f.Name, sdom.treestructure(f.Entry))
+       }
+
+       tofixBackedges := []edgeMemCtr{}
+
+       for _, e := range backedges { // TODO: could filter here by calls in loops, if declared and inferred nosplit are recorded in export data.
+               tofixBackedges = append(tofixBackedges, edgeMemCtr{e, nil, nil})
+       }
+
+       // It's possible that there is no memory state (no global/pointer loads/stores or calls)
+       if lastMems[f.Entry.ID] == nil {
+               lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Pos, OpInitMem, TypeMem)
+       }
+
+       memDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, the mem def seen at its bottom. Could be from earlier block.
+
+       // Propagate last mem definitions forward through successor blocks.
+       po := f.postorder()
+       for i := len(po) - 1; i >= 0; i-- {
+               b := po[i]
+               mem := lastMems[b.ID]
+               for j := 0; mem == nil; j++ { // if there's no def, then there's no phi, so the visible mem is identical in all predecessors.
+                       // loop because there might be backedges that haven't been visited yet.
+                       mem = memDefsAtBlockEnds[b.Preds[j].b.ID]
+               }
+               memDefsAtBlockEnds[b.ID] = mem
+       }
+
+       // Set up counter.  There are no phis etc pre-existing for it.
+       counter0 := f.Entry.NewValue0I(f.Entry.Pos, OpConst32, f.Config.fe.TypeInt32(), initialRescheduleCounterValue)
+       ctrDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, def visible at its end, if that def will be used.
+
+       // There's a minor difference between memDefsAtBlockEnds and ctrDefsAtBlockEnds;
+       // because the counter only matter for loops and code that reaches them, it is nil for blocks where the ctr is no
+       // longer live.  This will avoid creation of dead phi functions.  This optimization is ignored for the mem variable
+       // because it is harder and also less likely to be helpful, though dead code elimination ought to clean this out anyhow.
+
+       for _, emc := range tofixBackedges {
+               e := emc.e
+               // set initial uses of counter zero (note available-at-bottom and use are the same thing initially.)
+               // each back-edge will be rewritten to include a reschedule check, and that will use the counter.
+               src := e.b.Preds[e.i].b
+               ctrDefsAtBlockEnds[src.ID] = counter0
+       }
+
+       // Push uses towards root
+       for _, b := range f.postorder() {
+               bd := ctrDefsAtBlockEnds[b.ID]
+               if bd == nil {
+                       continue
+               }
+               for _, e := range b.Preds {
+                       p := e.b
+                       if ctrDefsAtBlockEnds[p.ID] == nil {
+                               ctrDefsAtBlockEnds[p.ID] = bd
+                       }
+               }
+       }
+
+       // Maps from block to newly-inserted phi function in block.
+       newmemphis := make(map[*Block]rewrite)
+       newctrphis := make(map[*Block]rewrite)
+
+       // Insert phi functions as necessary for future changes to flow graph.
+       for i, emc := range tofixBackedges {
+               e := emc.e
+               h := e.b
+
+               // find the phi function for the memory input at "h", if there is one.
+               var headerMemPhi *Value // look for header mem phi
+
+               for _, v := range h.Values {
+                       if v.Op == OpPhi && v.Type.IsMemory() {
+                               headerMemPhi = v
+                       }
+               }
+
+               if headerMemPhi == nil {
+                       // if the header is nil, make a trivial phi from the dominator
+                       mem0 := memDefsAtBlockEnds[idom[h.ID].ID]
+                       headerMemPhi = newPhiFor(h, mem0)
+                       newmemphis[h] = rewrite{before: mem0, after: headerMemPhi}
+                       addDFphis(mem0, h, h, f, memDefsAtBlockEnds, newmemphis)
+
+               }
+               tofixBackedges[i].m = headerMemPhi
+
+               var headerCtrPhi *Value
+               rw, ok := newctrphis[h]
+               if !ok {
+                       headerCtrPhi = newPhiFor(h, counter0)
+                       newctrphis[h] = rewrite{before: counter0, after: headerCtrPhi}
+                       addDFphis(counter0, h, h, f, ctrDefsAtBlockEnds, newctrphis)
+               } else {
+                       headerCtrPhi = rw.after
+               }
+               tofixBackedges[i].c = headerCtrPhi
+       }
+
+       rewriteNewPhis(f.Entry, f.Entry, f, memDefsAtBlockEnds, newmemphis)
+       rewriteNewPhis(f.Entry, f.Entry, f, ctrDefsAtBlockEnds, newctrphis)
+
+       if f.pass.debug > 0 {
+               for b, r := range newmemphis {
+                       fmt.Printf("b=%s, rewrite=%s\n", b, r.String())
+               }
+
+               for b, r := range newctrphis {
+                       fmt.Printf("b=%s, rewrite=%s\n", b, r.String())
+               }
+       }
+
+       // Apply collected rewrites.
+       for _, r := range newmemphis {
+               for _, rw := range r.rewrites {
+                       rw.v.SetArg(rw.i, r.after)
+               }
+       }
+
+       for _, r := range newctrphis {
+               for _, rw := range r.rewrites {
+                       rw.v.SetArg(rw.i, r.after)
+               }
+       }
+
+       zero := f.Entry.NewValue0I(f.Entry.Pos, OpConst32, f.Config.fe.TypeInt32(), 0)
+       one := f.Entry.NewValue0I(f.Entry.Pos, OpConst32, f.Config.fe.TypeInt32(), 1)
+
+       // Rewrite backedges to include reschedule checks.
+       for _, emc := range tofixBackedges {
+               e := emc.e
+               headerMemPhi := emc.m
+               headerCtrPhi := emc.c
+               h := e.b
+               i := e.i
+               p := h.Preds[i]
+               bb := p.b
+               mem0 := headerMemPhi.Args[i]
+               ctr0 := headerCtrPhi.Args[i]
+               // bb e->p h,
+               // Because we're going to insert a rare-call, make sure the
+               // looping edge still looks likely.
+               likely := BranchLikely
+               if p.i != 0 {
+                       likely = BranchUnlikely
+               }
+               bb.Likely = likely
+
+               // rewrite edge to include reschedule check
+               // existing edges:
+               //
+               // bb.Succs[p.i] == Edge{h, i}
+               // h.Preds[i] == p == Edge{bb,p.i}
+               //
+               // new block(s):
+               // test:
+               //    ctr1 := ctr0 - 1
+               //    if ctr1 <= 0 { goto sched }
+               //    goto join
+               // sched:
+               //    mem1 := call resched (mem0)
+               //    goto join
+               // join:
+               //    ctr2 := phi(ctr1, counter0) // counter0 is the constant
+               //    mem2 := phi(mem0, mem1)
+               //    goto h
+               //
+               // and correct arg i of headerMemPhi and headerCtrPhi
+               //
+               // EXCEPT: block containing only phi functions is bad
+               // for the register allocator.  Therefore, there is no
+               // join, and instead branches targeting join instead target
+               // the header, and the other phi functions within header are
+               // adjusted for the additional input.
+
+               test := f.NewBlock(BlockIf)
+               sched := f.NewBlock(BlockPlain)
+
+               test.Pos = bb.Pos
+               sched.Pos = bb.Pos
+
+               //    ctr1 := ctr0 - 1
+               //    if ctr1 <= 0 { goto sched }
+               //    goto header
+               ctr1 := test.NewValue2(bb.Pos, OpSub32, f.Config.fe.TypeInt32(), ctr0, one)
+               cmp := test.NewValue2(bb.Pos, OpLeq32, f.Config.fe.TypeBool(), ctr1, zero)
+               test.SetControl(cmp)
+               test.AddEdgeTo(sched) // if true
+               // if false -- rewrite edge to header.
+               // do NOT remove+add, because that will perturb all the other phi functions
+               // as well as messing up other edges to the header.
+               test.Succs = append(test.Succs, Edge{h, i})
+               h.Preds[i] = Edge{test, 1}
+               headerMemPhi.SetArg(i, mem0)
+               headerCtrPhi.SetArg(i, ctr1)
+
+               test.Likely = BranchUnlikely
+
+               // sched:
+               //    mem1 := call resched (mem0)
+               //    goto header
+               resched := f.Config.fe.Syslook("goschedguarded")
+               mem1 := sched.NewValue1A(bb.Pos, OpStaticCall, TypeMem, resched, mem0)
+               sched.AddEdgeTo(h)
+               headerMemPhi.AddArg(mem1)
+               headerCtrPhi.AddArg(counter0)
+
+               bb.Succs[p.i] = Edge{test, 0}
+               test.Preds = append(test.Preds, Edge{bb, p.i})
+
+               // Must correct all the other phi functions in the header for new incoming edge.
+               // Except for mem and counter phis, it will be the same value seen on the original
+               // backedge at index i.
+               for _, v := range h.Values {
+                       if v.Op == OpPhi && v != headerMemPhi && v != headerCtrPhi {
+                               v.AddArg(v.Args[i])
+                       }
+               }
+       }
+
+       f.invalidateCFG()
+
+       if f.pass.debug > 2 {
+               sdom = newSparseTree(f, f.Idom())
+               fmt.Printf("after %s = %s\n", f.Name, sdom.treestructure(f.Entry))
+       }
+
+       return
+}
+
+// newPhiFor inserts a new Phi function into b,
+// with all inputs set to v.
+func newPhiFor(b *Block, v *Value) *Value {
+       phiV := b.NewValue0(b.Pos, OpPhi, v.Type)
+
+       for range b.Preds {
+               phiV.AddArg(v)
+       }
+       return phiV
+}
+
+// rewriteNewPhis updates newphis[h] to record all places where the new phi function inserted
+// in block h will replace a previous definition.  Block b is the block currently being processed;
+// if b has its own phi definition then it takes the place of h.
+// defsForUses provides information about other definitions of the variable that are present
+// (and if nil, indicates that the variable is no longer live)
+func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Block]rewrite) {
+       // If b is a block with a new phi, then a new rewrite applies below it in the dominator tree.
+       if _, ok := newphis[b]; ok {
+               h = b
+       }
+       change := newphis[h]
+       x := change.before
+       y := change.after
+
+       // Apply rewrites to this block
+       if x != nil { // don't waste time on the common case of no definition.
+               p := &change.rewrites
+               for _, v := range b.Values {
+                       if v == y { // don't rewrite self -- phi inputs are handled below.
+                               continue
+                       }
+                       for i, w := range v.Args {
+                               if w != x {
+                                       continue
+                               }
+                               *p = append(*p, rewriteTarget{v, i})
+                       }
+               }
+
+               // Rewrite appropriate inputs of phis reached in successors
+               // in dominance frontier, self, and dominated.
+               // If the variable def reaching uses in b is itself defined in b, then the new phi function
+               // does not reach the successors of b.  (This assumes a bit about the structure of the
+               // phi use-def graph, but it's true for memory and the inserted counter.)
+               if dfu := defsForUses[b.ID]; dfu != nil && dfu.Block != b {
+                       for _, e := range b.Succs {
+                               s := e.b
+                               if sphi, ok := newphis[s]; ok { // saves time to find the phi this way.
+                                       *p = append(*p, rewriteTarget{sphi.after, e.i})
+                                       continue
+                               }
+                               for _, v := range s.Values {
+                                       if v.Op == OpPhi && v.Args[e.i] == x {
+                                               *p = append(*p, rewriteTarget{v, e.i})
+                                               break
+                                       }
+                               }
+                       }
+               }
+               newphis[h] = change
+       }
+
+       sdom := f.sdom()
+
+       for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
+               rewriteNewPhis(h, c, f, defsForUses, newphis) // TODO: convert to explicit stack from recursion.
+       }
+}
+
+// addDFphis creates new trivial phis that are necessary to correctly reflect (within SSA)
+// a new definition for variable "x" inserted at h (usually but not necessarily a phi).
+// These new phis can only occur at the dominance frontier of h; block s is in the dominance
+// frontier of h if h does not strictly dominate s and if s is a successor of a block b where
+// either b = h or h strictly dominates b.
+// These newly created phis are themselves new definitions that may require addition of their
+// own trivial phi functions in their own dominance frontier, and this is handled recursively.
+func addDFphis(x *Value, h, b *Block, f *Func, defForUses []*Value, newphis map[*Block]rewrite) {
+       oldv := defForUses[b.ID]
+       if oldv != x { // either a new definition replacing x, or nil if it is proven that there are no uses reachable from b
+               return
+       }
+       sdom := f.sdom()
+       idom := f.Idom()
+outer:
+       for _, e := range b.Succs {
+               s := e.b
+               // check phi functions in the dominance frontier
+               if sdom.isAncestor(h, s) {
+                       continue // h dominates s, successor of b, therefore s is not in the frontier.
+               }
+               if _, ok := newphis[s]; ok {
+                       continue // successor s of b already has a new phi function, so there is no need to add another.
+               }
+               if x != nil {
+                       for _, v := range s.Values {
+                               if v.Op == OpPhi && v.Args[e.i] == x {
+                                       continue outer // successor s of b has an old phi function, so there is no need to add another.
+                               }
+                       }
+               }
+
+               old := defForUses[idom[s.ID].ID] // new phi function is correct-but-redundant, combining value "old" on all inputs.
+               headerPhi := newPhiFor(s, old)
+               // the new phi will replace "old" in block s and all blocks dominated by s.
+               newphis[s] = rewrite{before: old, after: headerPhi} // record new phi, to have inputs labeled "old" rewritten to "headerPhi"
+               addDFphis(old, s, s, f, defForUses, newphis)        // the new definition may also create new phi functions.
+       }
+       for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
+               addDFphis(x, h, c, f, defForUses, newphis) // TODO: convert to explicit stack from recursion.
+       }
+}
+
+// findLastMems maps block ids to last memory-output op in a block, if any
+func findLastMems(f *Func) []*Value {
+
+       var stores []*Value
+       lastMems := make([]*Value, f.NumBlocks())
+       storeUse := f.newSparseSet(f.NumValues())
+       defer f.retSparseSet(storeUse)
+       for _, b := range f.Blocks {
+               // Find all the stores in this block. Categorize their uses:
+               //  storeUse contains stores which are used by a subsequent store.
+               storeUse.clear()
+               stores = stores[:0]
+               var memPhi *Value
+               for _, v := range b.Values {
+                       if v.Op == OpPhi {
+                               if v.Type.IsMemory() {
+                                       memPhi = v
+                               }
+                               continue
+                       }
+                       if v.Type.IsMemory() {
+                               stores = append(stores, v)
+                               if v.Op == OpSelect1 {
+                                       // Use the arg of the tuple-generating op.
+                                       v = v.Args[0]
+                               }
+                               for _, a := range v.Args {
+                                       if a.Block == b && a.Type.IsMemory() {
+                                               storeUse.add(a.ID)
+                                       }
+                               }
+                       }
+               }
+               if len(stores) == 0 {
+                       lastMems[b.ID] = memPhi
+                       continue
+               }
+
+               // find last store in the block
+               var last *Value
+               for _, v := range stores {
+                       if storeUse.contains(v.ID) {
+                               continue
+                       }
+                       if last != nil {
+                               b.Fatalf("two final stores - simultaneous live stores %s %s", last, v)
+                       }
+                       last = v
+               }
+               if last == nil {
+                       b.Fatalf("no last store found - cycle?")
+               }
+               lastMems[b.ID] = last
+       }
+       return lastMems
+}
+
+type backedgesState struct {
+       b *Block
+       i int
+}
+
+// backedges returns a slice of successor edges that are back
+// edges.  For reducible loops, edge.b is the header.
+func backedges(f *Func) []Edge {
+       edges := []Edge{}
+       mark := make([]markKind, f.NumBlocks())
+       stack := []backedgesState{}
+
+       mark[f.Entry.ID] = notExplored
+       stack = append(stack, backedgesState{f.Entry, 0})
+
+       for len(stack) > 0 {
+               l := len(stack)
+               x := stack[l-1]
+               if x.i < len(x.b.Succs) {
+                       e := x.b.Succs[x.i]
+                       stack[l-1].i++
+                       s := e.b
+                       if mark[s.ID] == notFound {
+                               mark[s.ID] = notExplored
+                               stack = append(stack, backedgesState{s, 0})
+                       } else if mark[s.ID] == notExplored {
+                               edges = append(edges, e)
+                       }
+               } else {
+                       mark[x.b.ID] = done
+                       stack = stack[0 : l-1]
+               }
+       }
+       return edges
+}
index 0a7477c6ffe8a3c45f5df54b615d4ef1391d8357..ac30b705e4e2830418e30f1e1145d8d40daf034c 100644 (file)
@@ -82,7 +82,7 @@ func nilcheckelim(f *Func) {
                                }
                        }
 
-                       // Next, process values in the block.
+                       // Next, eliminate any redundant nil checks in this block.
                        i := 0
                        for _, v := range b.Values {
                                b.Values[i] = v
@@ -105,13 +105,10 @@ func nilcheckelim(f *Func) {
                                                        f.Config.Warnl(v.Pos, "removed nil check")
                                                }
                                                v.reset(OpUnknown)
+                                               // TODO: f.freeValue(v)
                                                i--
                                                continue
                                        }
-                                       // Record the fact that we know ptr is non nil, and remember to
-                                       // undo that information when this dominator subtree is done.
-                                       nonNilValues[ptr.ID] = true
-                                       work = append(work, bp{op: ClearPtr, ptr: ptr})
                                }
                        }
                        for j := i; j < len(b.Values); j++ {
@@ -119,6 +116,21 @@ func nilcheckelim(f *Func) {
                        }
                        b.Values = b.Values[:i]
 
+                       // Finally, find redundant nil checks for subsequent blocks.
+                       // Note that we can't add these until the loop above is done, as the
+                       // values in the block are not ordered in any way when this pass runs.
+                       // This was the cause of issue #18725.
+                       for _, v := range b.Values {
+                               if v.Op != OpNilCheck {
+                                       continue
+                               }
+                               ptr := v.Args[0]
+                               // Record the fact that we know ptr is non nil, and remember to
+                               // undo that information when this dominator subtree is done.
+                               nonNilValues[ptr.ID] = true
+                               work = append(work, bp{op: ClearPtr, ptr: ptr})
+                       }
+
                        // Add all dominated blocks to the work list.
                        for w := sdom[node.block.ID].child; w != nil; w = sdom[w.ID].sibling {
                                work = append(work, bp{op: Work, block: w})
@@ -132,6 +144,8 @@ func nilcheckelim(f *Func) {
 }
 
 // All platforms are guaranteed to fault if we load/store to anything smaller than this address.
+//
+// This should agree with minLegalPointer in the runtime.
 const minZeroPage = 4096
 
 // nilcheckelim2 eliminates unnecessary nil checks.
index 315d7203d4293261b6d9ba5475701f677c38e72a..4c3164f2313f453414bb96609b6b652a2a2b65e5 100644 (file)
@@ -21,7 +21,7 @@ type opInfo struct {
        name              string
        reg               regInfo
        auxType           auxType
-       argLen            int32 // the number of arugments, -1 if variable length
+       argLen            int32 // the number of arguments, -1 if variable length
        asm               obj.As
        generic           bool // this is a generic (arch-independent) opcode
        rematerializeable bool // this op is rematerializeable
index bb25debdd63fc6e4eedc043ac3ea17014effa6e1..1f8092e4b9d954c8807d9e19b09187071d7982a5 100644 (file)
@@ -760,7 +760,7 @@ func (s *regAllocState) regalloc(f *Func) {
                        liveSet.add(e.ID)
                }
                if v := b.Control; v != nil && s.values[v.ID].needReg {
-                       s.addUse(v.ID, int32(len(b.Values)), b.Pos) // psuedo-use by control value
+                       s.addUse(v.ID, int32(len(b.Values)), b.Pos) // pseudo-use by control value
                        liveSet.add(v.ID)
                }
                for i := len(b.Values) - 1; i >= 0; i-- {
index dfae789210a56b5ccc6f8432f109545c33dd6026..c78971f801ccd0e9e46dec65bdfa2f51d96ea272 100644 (file)
@@ -1543,12 +1543,12 @@ func rewriteValuePPC64_OpGeq16U(v *Value, config *Config) bool {
        _ = b
        // match: (Geq16U x y)
        // cond:
-       // result: (GreaterEqual (CMPU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+       // result: (GreaterEqual (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
        for {
                x := v.Args[0]
                y := v.Args[1]
                v.reset(OpPPC64GreaterEqual)
-               v0 := b.NewValue0(v.Pos, OpPPC64CMPU, TypeFlags)
+               v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, TypeFlags)
                v1 := b.NewValue0(v.Pos, OpZeroExt16to32, config.fe.TypeUInt32())
                v1.AddArg(x)
                v0.AddArg(v1)
@@ -1598,12 +1598,12 @@ func rewriteValuePPC64_OpGeq32U(v *Value, config *Config) bool {
        _ = b
        // match: (Geq32U x y)
        // cond:
-       // result: (GreaterEqual (CMPU x y))
+       // result: (GreaterEqual (CMPWU x y))
        for {
                x := v.Args[0]
                y := v.Args[1]
                v.reset(OpPPC64GreaterEqual)
-               v0 := b.NewValue0(v.Pos, OpPPC64CMPU, TypeFlags)
+               v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, TypeFlags)
                v0.AddArg(x)
                v0.AddArg(y)
                v.AddArg(v0)
@@ -1687,12 +1687,12 @@ func rewriteValuePPC64_OpGeq8U(v *Value, config *Config) bool {
        _ = b
        // match: (Geq8U x y)
        // cond:
-       // result: (GreaterEqual (CMPU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+       // result: (GreaterEqual (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
        for {
                x := v.Args[0]
                y := v.Args[1]
                v.reset(OpPPC64GreaterEqual)
-               v0 := b.NewValue0(v.Pos, OpPPC64CMPU, TypeFlags)
+               v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, TypeFlags)
                v1 := b.NewValue0(v.Pos, OpZeroExt8to32, config.fe.TypeUInt32())
                v1.AddArg(x)
                v0.AddArg(v1)
index c7e002a5b355a5810eba47ba8955a90d923025a1..07350014cfec973d683dc6c478226d1f48ba4931 100644 (file)
@@ -9847,11 +9847,11 @@ func rewriteValueS390X_OpS390XMOVDNE(v *Value, config *Config) bool {
                v.AddArg(cmp)
                return true
        }
-       // match: (MOVDNE _ y (FlagEQ))
+       // match: (MOVDNE y _ (FlagEQ))
        // cond:
        // result: y
        for {
-               y := v.Args[1]
+               y := v.Args[0]
                v_2 := v.Args[2]
                if v_2.Op != OpS390XFlagEQ {
                        break
@@ -9861,11 +9861,11 @@ func rewriteValueS390X_OpS390XMOVDNE(v *Value, config *Config) bool {
                v.AddArg(y)
                return true
        }
-       // match: (MOVDNE x _ (FlagLT))
+       // match: (MOVDNE _ x (FlagLT))
        // cond:
        // result: x
        for {
-               x := v.Args[0]
+               x := v.Args[1]
                v_2 := v.Args[2]
                if v_2.Op != OpS390XFlagLT {
                        break
@@ -9875,11 +9875,11 @@ func rewriteValueS390X_OpS390XMOVDNE(v *Value, config *Config) bool {
                v.AddArg(x)
                return true
        }
-       // match: (MOVDNE x _ (FlagGT))
+       // match: (MOVDNE _ x (FlagGT))
        // cond:
        // result: x
        for {
-               x := v.Args[0]
+               x := v.Args[1]
                v_2 := v.Args[2]
                if v_2.Op != OpS390XFlagGT {
                        break
index 7c82a60d0fa8fc1e26e4660e4370e4d4ca59645e..8e5b9f3e5bd68023bffdcd81beb0ab4b41fecbd1 100644 (file)
@@ -4,7 +4,10 @@
 
 package ssa
 
-import "fmt"
+import (
+       "fmt"
+       "strings"
+)
 
 type SparseTreeNode struct {
        child   *Block
@@ -67,6 +70,34 @@ func newSparseTree(f *Func, parentOf []*Block) SparseTree {
        return t
 }
 
+// treestructure provides a string description of the dominator
+// tree and flow structure of block b and all blocks that it
+// dominates.
+func (t SparseTree) treestructure(b *Block) string {
+       return t.treestructure1(b, 0)
+}
+func (t SparseTree) treestructure1(b *Block, i int) string {
+       s := "\n" + strings.Repeat("\t", i) + b.String() + "->["
+       for i, e := range b.Succs {
+               if i > 0 {
+                       s = s + ","
+               }
+               s = s + e.b.String()
+       }
+       s += "]"
+       if c0 := t[b.ID].child; c0 != nil {
+               s += "("
+               for c := c0; c != nil; c = t[c.ID].sibling {
+                       if c != c0 {
+                               s += " "
+                       }
+                       s += t.treestructure1(c, i+1)
+               }
+               s += ")"
+       }
+       return s
+}
+
 // numberBlock assigns entry and exit numbers for b and b's
 // children in an in-order walk from a gappy sequence, where n
 // is the first number not yet assigned or reserved. N should
index fcca293402a9263d5deaa79feed0add6191335dc..1bfe9fe44f4d24bb5d71c99c03e5ebaa1d6a778a 100644 (file)
@@ -38,7 +38,7 @@ func writebarrier(f *Func) {
        valueLoop:
                for i, v := range b.Values {
                        switch v.Op {
-                       case OpStoreWB, OpMoveWB, OpMoveWBVolatile:
+                       case OpStoreWB, OpMoveWB, OpMoveWBVolatile, OpZeroWB:
                                if IsStackAddr(v.Args[0]) {
                                        switch v.Op {
                                        case OpStoreWB:
index 82c6c1907fce3bd24e23e07ca5cfad7b9a354e74..b788efb3ec3924a1e2165e0a8d129ae5d862d7e3 100644 (file)
@@ -75,6 +75,7 @@ type (
        // Name Type
        TypeDecl struct {
                Name   *Name
+               Alias  bool
                Type   Expr
                Group  *Group // nil means not part of a group
                Pragma Pragma
index e70ac3d714af350aae9b28f841461b58159c0597..fd16f580fb43b792f3fd10646fc362f8525e901c 100644 (file)
@@ -390,7 +390,7 @@ func (p *parser) constDecl(group *Group) Decl {
        return d
 }
 
-// TypeSpec = identifier Type .
+// TypeSpec = identifier [ "=" ] Type .
 func (p *parser) typeDecl(group *Group) Decl {
        if trace {
                defer p.trace("typeDecl")()
@@ -400,6 +400,7 @@ func (p *parser) typeDecl(group *Group) Decl {
        d.init(p)
 
        d.Name = p.name()
+       d.Alias = p.got(_Assign)
        d.Type = p.tryType()
        if d.Type == nil {
                p.syntax_error("in type declaration")
index 0cacf1e5d496015cade1116ba0b50918ab2cf868..43876a25c20f098afbc7e36103c6e974e94d5ae3 100644 (file)
@@ -619,7 +619,11 @@ func (p *printer) printRawNode(n Node) {
                if n.Group == nil {
                        p.print(_Type, blank)
                }
-               p.print(n.Name, blank, n.Type)
+               p.print(n.Name, blank)
+               if n.Alias {
+                       p.print(_Assign, blank)
+               }
+               p.print(n.Type)
 
        case *VarDecl:
                if n.Group == nil {
index dc9a32b6d38478f9efe161c565d80204b056f046..14652f4ac6566b539044983b3fd4763f8b986f31 100644 (file)
@@ -22,3 +22,20 @@ func TestPrint(t *testing.T) {
        Fprint(os.Stdout, ast, true)
        fmt.Println()
 }
+
+func TestPrintString(t *testing.T) {
+       for _, want := range []string{
+               "package p",
+               "package p; type _ = int; type T1 = struct{}; type ( _ = *struct{}; T2 = float32 )",
+               // TODO(gri) expand
+       } {
+               ast, err := ParseBytes(nil, []byte(want), nil, nil, 0)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+               if got := String(ast); got != want {
+                       t.Errorf("%q: got %q", want, got)
+               }
+       }
+}
index b7d9125d60a70224bed05df9c503cc9467b19738..ee140702d3d0620b6755e4f6d8c349b4627fdeda 100644 (file)
@@ -151,11 +151,12 @@ type Block struct {
 // File is a wrapper for the state of a file used in the parser.
 // The basic parse tree walker is a method of this type.
 type File struct {
-       fset      *token.FileSet
-       name      string // Name of file.
-       astFile   *ast.File
-       blocks    []Block
-       atomicPkg string // Package name for "sync/atomic" in this file.
+       fset       *token.FileSet
+       name       string // Name of file.
+       astFile    *ast.File
+       blocks     []Block
+       atomicPkg  string                // Package name for "sync/atomic" in this file.
+       directives map[*ast.Comment]bool // Map of compiler directives to whether it's processed in ast.Visitor or not.
 }
 
 // Visit implements the ast.Visitor interface.
@@ -247,8 +248,11 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
                // to appear in syntactically incorrect places. //go: appears at the beginning of
                // the line and is syntactically safe.
                for _, c := range n.List {
-                       if strings.HasPrefix(c.Text, "//go:") && f.fset.Position(c.Slash).Column == 1 {
+                       if f.isDirective(c) {
                                list = append(list, c)
+
+                               // Mark compiler directive as handled.
+                               f.directives[c] = true
                        }
                }
                n.List = list
@@ -360,17 +364,27 @@ func annotate(name string) {
        if err != nil {
                log.Fatalf("cover: %s: %s", name, err)
        }
-       // Remove comments. Or else they interfere with new AST.
-       parsedFile.Comments = nil
 
        file := &File{
-               fset:    fset,
-               name:    name,
-               astFile: parsedFile,
+               fset:       fset,
+               name:       name,
+               astFile:    parsedFile,
+               directives: map[*ast.Comment]bool{},
        }
        if *mode == "atomic" {
                file.atomicPkg = file.addImport(atomicPackagePath)
        }
+
+       for _, cg := range parsedFile.Comments {
+               for _, c := range cg.List {
+                       if file.isDirective(c) {
+                               file.directives[c] = false
+                       }
+               }
+       }
+       // Remove comments. Or else they interfere with new AST.
+       parsedFile.Comments = nil
+
        ast.Walk(file, file.astFile)
        fd := os.Stdout
        if *output != "" {
@@ -381,6 +395,17 @@ func annotate(name string) {
                }
        }
        fd.Write(initialComments(content)) // Retain '// +build' directives.
+
+       // Retain compiler directives that are not processed in ast.Visitor.
+       // Some compiler directives like "go:linkname" and "go:cgo_"
+       // can be not attached to anything in the tree and hence will not be printed by printer.
+       // So, we have to explicitly print them here.
+       for cd, handled := range file.directives {
+               if !handled {
+                       fmt.Fprintln(fd, cd.Text)
+               }
+       }
+
        file.print(fd)
        // After printing the source tree, add some declarations for the counters etc.
        // We could do this by adding to the tree, but it's easier just to print the text.
@@ -391,6 +416,11 @@ func (f *File) print(w io.Writer) {
        printer.Fprint(w, f.fset, f.astFile)
 }
 
+// isDirective reports whether a comment is a compiler directive.
+func (f *File) isDirective(c *ast.Comment) bool {
+       return strings.HasPrefix(c.Text, "//go:") && f.fset.Position(c.Slash).Column == 1
+}
+
 // intLiteral returns an ast.BasicLit representing the integer value.
 func (f *File) intLiteral(i int) *ast.BasicLit {
        node := &ast.BasicLit{
index 50a7ce829f1c00d4eb31ebe44b32b82b53f255b8..81ac8ae467775d070370cb793d75b71f98f68042 100644 (file)
@@ -90,6 +90,11 @@ func TestCover(t *testing.T) {
        if got, err := regexp.MatchString(".*\n//go:nosplit\nfunc someFunction().*", string(file)); err != nil || !got {
                t.Errorf("misplaced compiler directive: got=(%v, %v); want=(true; nil)", got, err)
        }
+       // "go:linkname" compiler directive should be present.
+       if got, err := regexp.MatchString(`.*go\:linkname some\_name some\_name.*`, string(file)); err != nil || !got {
+               t.Errorf("'go:linkname' compiler directive not found: got=(%v, %v); want=(true; nil)", got, err)
+       }
+
        // No other comments should be present in generated code.
        c := ".*// This comment shouldn't appear in generated go code.*"
        if got, err := regexp.MatchString(c, string(file)); err != nil || got {
index 61b40eaa740927be44ba1714adede1493ae4b315..5effa2d7e905fa6d398d729707bfb9621fd06699 100644 (file)
 
 package main
 
+import _ "unsafe" // for go:linkname
+
+//go:linkname some_name some_name
+
 const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"
 
 func testAll() {
index 6fb788456024c863ce8e3cc800567633637b897d..4d0b1a0b4100640ee5e39a3e8d1a96bbb29cf0cd 100644 (file)
@@ -1107,8 +1107,8 @@ var cgoEnabled = map[string]bool{
        "linux/arm64":     true,
        "linux/ppc64":     false,
        "linux/ppc64le":   true,
-       "linux/mips":      false,
-       "linux/mipsle":    false,
+       "linux/mips":      true,
+       "linux/mipsle":    true,
        "linux/mips64":    true,
        "linux/mips64le":  true,
        "linux/s390x":     true,
index 054f4dde452e993481a635e71589ee85e3d5298e..c51dcead2b3fd8d47d00a71490145cb61ba7026b 100644 (file)
@@ -15,7 +15,6 @@ import (
        "os/exec"
        "path/filepath"
        "regexp"
-       "runtime"
        "strconv"
        "strings"
        "sync"
@@ -354,7 +353,7 @@ func (t *tester) registerTests() {
 
        // This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
        // See issue 18153.
-       if runtime.GOOS == "linux" {
+       if t.goos == "linux" {
                t.tests = append(t.tests, distTest{
                        name:    "cmd_go_test_terminal",
                        heading: "cmd/go terminal test",
@@ -568,7 +567,7 @@ func (t *tester) registerTests() {
                if t.gohostos == "linux" && t.goarch == "amd64" {
                        t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
                }
-               if t.gohostos == "linux" && t.goarch == "amd64" {
+               if t.goos == "linux" && t.goarch == "amd64" {
                        t.registerTest("testsanitizers", "../misc/cgo/testsanitizers", "./test.bash")
                }
                if t.hasBash() && t.goos != "android" && !t.iOS() && t.gohostos != "windows" {
@@ -704,7 +703,7 @@ func (t *tester) extLink() bool {
                "darwin-arm", "darwin-arm64",
                "dragonfly-386", "dragonfly-amd64",
                "freebsd-386", "freebsd-amd64", "freebsd-arm",
-               "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le",
+               "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x",
                "netbsd-386", "netbsd-amd64",
                "openbsd-386", "openbsd-amd64",
                "windows-386", "windows-amd64":
@@ -741,7 +740,7 @@ func (t *tester) internalLink() bool {
        // Internally linking cgo is incomplete on some architectures.
        // https://golang.org/issue/10373
        // https://golang.org/issue/14449
-       if t.goarch == "arm64" || t.goarch == "mips64" || t.goarch == "mips64le" {
+       if t.goarch == "arm64" || t.goarch == "mips64" || t.goarch == "mips64le" || t.goarch == "mips" || t.goarch == "mipsle" {
                return false
        }
        return true
@@ -786,8 +785,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
                // linux-arm64 is missing because it causes the external linker
                // to crash, see https://golang.org/issue/17138
                switch pair {
-               case "linux-386", "linux-amd64", "linux-arm",
-                       "darwin-amd64":
+               case "linux-386", "linux-amd64", "linux-arm":
                        return true
                }
                return false
index 1c054fd566a0a3683ddbf86c56e833821a23580f..1244476ab2f18b05b04b6e4a54e178011696681e 100644 (file)
@@ -71,6 +71,7 @@ var tests = []test{
                        `const MultiLineConst = ...`,                                   // Multi line constant.
                        `var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`,  // Multi line variable.
                        `func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`, // Multi line function.
+                       `type T1 = T2`, // Type alias
                },
                []string{
                        `const internalConstant = 2`,        // No internal constants.
@@ -89,6 +90,7 @@ var tests = []test{
                        `unexportedTypedConstant`,           // No unexported typed constant.
                        `Field`,                             // No fields.
                        `Method`,                            // No methods.
+                       `type T1 T2`, // Type alias does not display as type declaration.
                },
        },
        // Package dump -u
@@ -265,6 +267,18 @@ var tests = []test{
                        `error`,                          // No embedded error.
                },
        },
+       // Type T1 dump (alias).
+       {
+               "type T1",
+               []string{p+".T1"},
+               []string{
+                       `type T1 = T2`,
+               },
+               []string{
+                       `type T1 T2`,
+                       `type ExportedType`,
+               },
+       },
        // Type -u with unexported fields.
        {
                "type with unexported fields and -u",
index daa6ed358cdce0e2234421532cc7eb9753e97c1c..32d08f21fd04a33d4136a3f30e7355cd1fc5b8a7 100644 (file)
@@ -258,7 +258,11 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
                return fmt.Sprintf("func %s%s%s", recv, name, fnc)
 
        case *ast.TypeSpec:
-               return fmt.Sprintf("type %s %s", n.Name.Name, pkg.oneLineNodeDepth(n.Type, depth))
+               sep := " "
+               if n.Assign.IsValid() {
+                       sep = " = "
+               }
+               return fmt.Sprintf("type %s%s%s", n.Name.Name, sep, pkg.oneLineNodeDepth(n.Type, depth))
 
        case *ast.FuncType:
                var params []string
index 924daa171b259a38aa7f12523a85e4262b18d822..0ebea67d58e50a942b2dc371f7c78b04cc78498c 100644 (file)
@@ -172,3 +172,7 @@ const (
 )
 
 const ConstGroup4 ExportedType = ExportedType{}
+
+type T2 int
+
+type T1 = T2
index b4807420b076bb66579acd5d9591e5b4d12aad3f..3d5dd2b39725883fd01bb5541d8604c268ddd4fc 100644 (file)
@@ -17,7 +17,7 @@
 //     clean       remove object files
 //     doc         show documentation for package or symbol
 //     env         print Go environment information
-//     bug         print information for bug reports
+//     bug         start a bug report
 //     fix         run go tool fix on packages
 //     fmt         run gofmt on package sources
 //     generate    generate Go files by processing source
 // each named variable on its own line.
 //
 //
-// Print information for bug reports
+// Start a bug report
 //
 // Usage:
 //
 //     go bug
 //
-// Bug prints information that helps file effective bug reports.
-//
-// Bugs may be reported at https://golang.org/issue/new.
+// Bug opens the default browser and starts a new bug report.
+// The report includes useful system information.
 //
 //
 // Run go tool fix on packages
 // unless that directory holds a Go distribution.
 // Run "go env GOPATH" to see the current GOPATH.
 //
+// See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
+//
 // Each directory listed in GOPATH must have a prescribed structure:
 //
 // The src directory holds source code.  The path below src
 //         text from Log and Logf calls even if the test succeeds.
 //
 // The following flags are also recognized by 'go test' and can be used to
-// profile the tests during execution::
+// profile the tests during execution:
 //
 //     -benchmem
 //         Print memory allocation statistics for benchmarks.
 //         Writes test binary as -c would.
 //
 //     -mutexprofilefraction n
-//         Sample 1 in n stack traces of goroutines holding a
+//         Sample 1 in n stack traces of goroutines holding a
 //         contended mutex.
 //
 //     -outputdir directory
 // is compared exactly against the comment (see examples below). If the last
 // comment begins with "Unordered output:" then the output is compared to the
 // comment, however the order of the lines is ignored. An example with no such
-// comment, or with no text after "Output:" is compiled but not executed.
+// comment is compiled but not executed. An example with no text after
+// "Output:" is compiled, executed, and expected to produce no output.
 //
 // Godoc displays the body of ExampleXXX to demonstrate the use
 // of the function, constant, or variable XXX.  An example of a method M with
index cbd258b80bde5f030f5f791ec831e368c89bed6a..658f6dabd90417b7c4efd8608948560f5f0365b2 100644 (file)
@@ -20,11 +20,10 @@ import (
 var cmdBug = &Command{
        Run:       runBug,
        UsageLine: "bug",
-       Short:     "print information for bug reports",
+       Short:     "start a bug report",
        Long: `
-Bug prints information that helps file effective bug reports.
-
-Bugs may be reported at https://golang.org/issue/new.
+Bug opens the default browser and starts a new bug report.
+The report includes useful system information.
        `,
 }
 
index e053b28c989272063e81cd95ebec9c958eb1d6a3..98a650918a30d7d6ae80ff78551b4ad93fa32d33 100644 (file)
@@ -413,8 +413,7 @@ func buildModeInit() {
                } else {
                        switch platform {
                        case "linux/amd64", "linux/arm", "linux/arm64", "linux/386",
-                               "android/amd64", "android/arm", "android/arm64", "android/386",
-                               "darwin/amd64":
+                               "android/amd64", "android/arm", "android/arm64", "android/386":
                        default:
                                fatalf("-buildmode=plugin not supported on %s\n", platform)
                        }
@@ -2406,8 +2405,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
 func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
        // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
        inc := filepath.Join(goroot, "pkg", "include")
-       ofile := obj + "asm.o"
-       args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
+       args := []interface{}{buildToolExec, tool("asm"), "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
        if p.ImportPath == "runtime" && goarch == "386" {
                for _, arg := range buildAsmflags {
                        if arg == "-dynlink" {
@@ -2415,13 +2413,16 @@ func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]s
                        }
                }
        }
+       var ofiles []string
        for _, sfile := range sfiles {
-               args = append(args, mkAbs(p.Dir, sfile))
-       }
-       if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
-               return nil, err
+               ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
+               ofiles = append(ofiles, ofile)
+               a := append(args, "-o", ofile, mkAbs(p.Dir, sfile))
+               if err := b.run(p.Dir, p.ImportPath, nil, a...); err != nil {
+                       return nil, err
+               }
        }
-       return []string{ofile}, nil
+       return ofiles, nil
 }
 
 // toolVerify checks that the command line args writes the same output file
@@ -3218,6 +3219,8 @@ func (b *builder) gccArchArgs() []string {
                return []string{"-m64", "-march=z196"}
        case "mips64", "mips64le":
                return []string{"-mabi=64"}
+       case "mips", "mipsle":
+               return []string{"-mabi=32", "-march=mips32"}
        }
        return nil
 }
index 82408d6a392222ebbf1c7d28b828fea6add9fbd0..1d7677c615c176e0150576e831bc58ae5f83db52 100644 (file)
@@ -205,6 +205,10 @@ var downloadRootCache = map[string]bool{}
 // download runs the download half of the get command
 // for the package named by the argument.
 func download(arg string, parent *Package, stk *importStack, mode int) {
+       if mode&useVendor != 0 {
+               // Caller is responsible for expanding vendor paths.
+               panic("internal error: download mode has useVendor set")
+       }
        load := func(path string, mode int) *Package {
                if parent == nil {
                        return loadPackage(path, stk)
@@ -315,32 +319,42 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
                }
 
                // Process dependencies, now that we know what they are.
-               for _, path := range p.Imports {
+               imports := p.Imports
+               if mode&getTestDeps != 0 {
+                       // Process test dependencies when -t is specified.
+                       // (But don't get test dependencies for test dependencies:
+                       // we always pass mode 0 to the recursive calls below.)
+                       imports = stringList(imports, p.TestImports, p.XTestImports)
+               }
+               for i, path := range imports {
                        if path == "C" {
                                continue
                        }
-                       // Don't get test dependencies recursively.
-                       // Imports is already vendor-expanded.
-                       download(path, p, stk, 0)
-               }
-               if mode&getTestDeps != 0 {
-                       // Process test dependencies when -t is specified.
-                       // (Don't get test dependencies for test dependencies.)
-                       // We pass useVendor here because p.load does not
-                       // vendor-expand TestImports and XTestImports.
-                       // The call to loadImport inside download needs to do that.
-                       for _, path := range p.TestImports {
-                               if path == "C" {
-                                       continue
-                               }
-                               download(path, p, stk, useVendor)
+                       // Fail fast on import naming full vendor path.
+                       // Otherwise expand path as needed for test imports.
+                       // Note that p.Imports can have additional entries beyond p.build.Imports.
+                       orig := path
+                       if i < len(p.build.Imports) {
+                               orig = p.build.Imports[i]
                        }
-                       for _, path := range p.XTestImports {
-                               if path == "C" {
-                                       continue
+                       if j, ok := findVendor(orig); ok {
+                               stk.push(path)
+                               err := &PackageError{
+                                       ImportStack: stk.copy(),
+                                       Err:         "must be imported as " + path[j+len("vendor/"):],
                                }
-                               download(path, p, stk, useVendor)
+                               stk.pop()
+                               errorf("%s", err)
+                               continue
+                       }
+                       // If this is a test import, apply vendor lookup now.
+                       // We cannot pass useVendor to download, because
+                       // download does caching based on the value of path,
+                       // so it must be the fully qualified path already.
+                       if i >= len(p.Imports) {
+                               path = vendoredImportPath(p, path)
                        }
+                       download(path, p, stk, 0)
                }
 
                if isWildcard {
index 1c84512ed49cabb109d3df407bdb66506893d570..ef5348bba40ff8844911e57dce951ad904086cf9 100644 (file)
@@ -1885,6 +1885,26 @@ func TestGoTestCpuprofileDashOControlsBinaryLocation(t *testing.T) {
        tg.wantExecutable("myerrors.test"+exeSuffix, "go test -cpuprofile -o myerrors.test did not create myerrors.test")
 }
 
+func TestGoTestMutexprofileLeavesBinaryBehind(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       // TODO: tg.parallel()
+       tg.makeTempdir()
+       tg.cd(tg.path("."))
+       tg.run("test", "-mutexprofile", "errors.prof", "errors")
+       tg.wantExecutable("errors.test"+exeSuffix, "go test -mutexprofile did not create errors.test")
+}
+
+func TestGoTestMutexprofileDashOControlsBinaryLocation(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       // TODO: tg.parallel()
+       tg.makeTempdir()
+       tg.cd(tg.path("."))
+       tg.run("test", "-mutexprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
+       tg.wantExecutable("myerrors.test"+exeSuffix, "go test -mutexprofile -o myerrors.test did not create myerrors.test")
+}
+
 func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
@@ -2247,6 +2267,28 @@ func TestCoverageImportMainLoop(t *testing.T) {
        tg.grepStderr("not an importable package", "did not detect import main")
 }
 
+func TestTestEmpty(t *testing.T) {
+       if !canRace {
+               t.Skip("no race detector")
+       }
+
+       wd, _ := os.Getwd()
+       testdata := filepath.Join(wd, "testdata")
+
+       for _, dir := range []string{"pkg", "test", "xtest", "pkgtest", "pkgxtest", "pkgtestxtest", "testxtest"} {
+               t.Run(dir, func(t *testing.T) {
+                       tg := testgo(t)
+                       defer tg.cleanup()
+                       tg.setenv("GOPATH", testdata)
+                       tg.cd(filepath.Join(testdata, "src/empty/"+dir))
+                       tg.run("test", "-cover", "-coverpkg=.", "-race")
+               })
+               if testing.Short() {
+                       break
+               }
+       }
+}
+
 func TestBuildDryRunWithCgo(t *testing.T) {
        if !canCgo {
                t.Skip("skipping because cgo not enabled")
@@ -3357,9 +3399,11 @@ func TestCgoConsistentResults(t *testing.T) {
        if !canCgo {
                t.Skip("skipping because cgo not enabled")
        }
-       if runtime.GOOS == "solaris" {
-               // See https://golang.org/issue/13247
-               t.Skip("skipping because Solaris builds are known to be inconsistent; see #13247")
+       switch runtime.GOOS {
+       case "freebsd":
+               testenv.SkipFlaky(t, 15405)
+       case "solaris":
+               testenv.SkipFlaky(t, 13247)
        }
 
        tg := testgo(t)
@@ -3700,6 +3744,13 @@ func TestMatchesOnlySubtestParallelIsOK(t *testing.T) {
        tg.grepBoth(okPattern, "go test did not say ok")
 }
 
+// Issue 18845
+func TestBenchTimeout(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go")
+}
+
 func TestLinkXImportPathEscape(t *testing.T) {
        // golang.org/issue/16710
        tg := testgo(t)
@@ -3727,3 +3778,42 @@ func TestLdBindNow(t *testing.T) {
        tg.setenv("LD_BIND_NOW", "1")
        tg.run("help")
 }
+
+// Issue 18225.
+// This is really a cmd/asm issue but this is a convenient place to test it.
+func TestConcurrentAsm(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.parallel()
+       asm := `DATA ·constants<>+0x0(SB)/8,$0
+GLOBL ·constants<>(SB),8,$8
+`
+       tg.tempFile("go/src/p/a.s", asm)
+       tg.tempFile("go/src/p/b.s", asm)
+       tg.tempFile("go/src/p/p.go", `package p`)
+       tg.setenv("GOPATH", tg.path("go"))
+       tg.run("build", "p")
+}
+
+// Issue 18778.
+func TestDotDotDotOutsideGOPATH(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+
+       tg.tempFile("pkgs/a.go", `package x`)
+       tg.tempFile("pkgs/a_test.go", `package x_test
+import "testing"
+func TestX(t *testing.T) {}`)
+
+       tg.tempFile("pkgs/a/a.go", `package a`)
+       tg.tempFile("pkgs/a/a_test.go", `package a_test
+import "testing"
+func TestA(t *testing.T) {}`)
+
+       tg.cd(tg.path("pkgs"))
+       tg.run("build", "./...")
+       tg.run("test", "./...")
+       tg.run("list", "./...")
+       tg.grepStdout("pkgs$", "expected package not listed")
+       tg.grepStdout("pkgs/a", "expected package not listed")
+}
index fb69d8ec543c786e23279708edd9b6f93cfb4a29..0c663ad463f679302a8280c85f8e32fad32844b7 100644 (file)
@@ -295,6 +295,8 @@ to a subdirectory named "go" in the user's home directory
 unless that directory holds a Go distribution.
 Run "go env GOPATH" to see the current GOPATH.
 
+See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
+
 Each directory listed in GOPATH must have a prescribed structure:
 
 The src directory holds source code.  The path below src
index 1dc2c12c64edafe300df06eadd3ba3754a6bf2cb..dcb4e9fea5f9fa0ec8e75add4516566ef712c43d 100644 (file)
@@ -33,6 +33,7 @@ var httpClient = http.DefaultClient
 var impatientInsecureHTTPClient = &http.Client{
        Timeout: 5 * time.Second,
        Transport: &http.Transport{
+               Proxy: http.ProxyFromEnvironment,
                TLSClientConfig: &tls.Config{
                        InsecureSkipVerify: true,
                },
index 852a1a0db9b68ae5505b7cd982e4e0dad1820f52..e40f9420c7e2217f9e126cf5f636c282c532d959 100644 (file)
@@ -178,7 +178,9 @@ func (p *Package) copyBuild(pp *build.Package) {
        p.CgoCXXFLAGS = pp.CgoCXXFLAGS
        p.CgoLDFLAGS = pp.CgoLDFLAGS
        p.CgoPkgConfig = pp.CgoPkgConfig
-       p.Imports = pp.Imports
+       // We modify p.Imports in place, so make copy now.
+       p.Imports = make([]string, len(pp.Imports))
+       copy(p.Imports, pp.Imports)
        p.TestGoFiles = pp.TestGoFiles
        p.TestImports = pp.TestImports
        p.XTestGoFiles = pp.XTestGoFiles
@@ -427,7 +429,7 @@ func setErrorPos(p *Package, importPos []token.Position) *Package {
 func cleanImport(path string) string {
        orig := path
        path = pathpkg.Clean(path)
-       if strings.HasPrefix(orig, "./") && path != ".." && path != "." && !strings.HasPrefix(path, "../") {
+       if strings.HasPrefix(orig, "./") && path != ".." && !strings.HasPrefix(path, "../") {
                path = "./" + path
        }
        return path
@@ -953,6 +955,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                if p.Name == "main" && goarch == "arm" {
                        importPaths = append(importPaths, "math")
                }
+               // In coverage atomic mode everything depends on sync/atomic.
+               if testCoverMode == "atomic" && (!p.Standard || (p.ImportPath != "runtime/cgo" && p.ImportPath != "runtime/race" && p.ImportPath != "sync/atomic")) {
+                       importPaths = append(importPaths, "sync/atomic")
+               }
        }
 
        // Runtime and its internal packages depend on runtime/internal/sys,
index f27144c48557790a7e9f3e852b18936a8a1d75ea..6482f0fd32301a83a0bb9174170705b204587ef7 100644 (file)
@@ -200,7 +200,7 @@ const testFlag2 = `
            text from Log and Logf calls even if the test succeeds.
 
 The following flags are also recognized by 'go test' and can be used to
-profile the tests during execution::
+profile the tests during execution:
 
        -benchmem
            Print memory allocation statistics for benchmarks.
@@ -243,7 +243,7 @@ profile the tests during execution::
            Writes test binary as -c would.
 
        -mutexprofilefraction n
-           Sample 1 in n stack traces of goroutines holding a
+           Sample 1 in n stack traces of goroutines holding a
            contended mutex.
 
        -outputdir directory
@@ -334,7 +334,8 @@ If the last comment in the function starts with "Output:" then the output
 is compared exactly against the comment (see examples below). If the last
 comment begins with "Unordered output:" then the output is compared to the
 comment, however the order of the lines is ignored. An example with no such
-comment, or with no text after "Output:" is compiled but not executed.
+comment is compiled but not executed. An example with no text after
+"Output:" is compiled, executed, and expected to produce no output.
 
 Godoc displays the body of ExampleXXX to demonstrate the use
 of the function, constant, or variable XXX.  An example of a method M with
@@ -893,9 +894,13 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 
        if buildContext.GOOS == "darwin" {
                if buildContext.GOARCH == "arm" || buildContext.GOARCH == "arm64" {
-                       t.NeedCgo = true
+                       t.IsIOS = true
+                       t.NeedOS = true
                }
        }
+       if t.TestMain == nil {
+               t.NeedOS = true
+       }
 
        for _, cp := range pmain.imports {
                if len(cp.coverVars) > 0 {
@@ -1342,7 +1347,8 @@ type testFuncs struct {
        NeedTest    bool
        ImportXtest bool
        NeedXtest   bool
-       NeedCgo     bool
+       NeedOS      bool
+       IsIOS       bool
        Cover       []coverInfo
 }
 
@@ -1443,7 +1449,7 @@ var testmainTmpl = template.Must(template.New("main").Parse(`
 package main
 
 import (
-{{if not .TestMain}}
+{{if .NeedOS}}
        "os"
 {{end}}
        "testing"
@@ -1459,8 +1465,10 @@ import (
        _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
 {{end}}
 
-{{if .NeedCgo}}
+{{if .IsIOS}}
+       "os/signal"
        _ "runtime/cgo"
+       "syscall"
 {{end}}
 )
 
@@ -1522,6 +1530,32 @@ func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts
 {{end}}
 
 func main() {
+{{if .IsIOS}}
+       // Send a SIGUSR2, which will be intercepted by LLDB to
+       // tell the test harness that installation was successful.
+       // See misc/ios/go_darwin_arm_exec.go.
+       signal.Notify(make(chan os.Signal), syscall.SIGUSR2)
+       syscall.Kill(0, syscall.SIGUSR2)
+       signal.Reset(syscall.SIGUSR2)
+
+       // The first argument supplied to an iOS test is an offset
+       // suffix for the current working directory.
+       // Process it here, and remove it from os.Args.
+       const hdr = "cwdSuffix="
+       if len(os.Args) < 2 || len(os.Args[1]) <= len(hdr) || os.Args[1][:len(hdr)] != hdr {
+               panic("iOS test not passed a working directory suffix")
+       }
+       suffix := os.Args[1][len(hdr):]
+       dir, err := os.Getwd()
+       if err != nil {
+               panic(err)
+       }
+       if err := os.Chdir(dir + "/" + suffix); err != nil {
+               panic(err)
+       }
+       os.Args = append([]string{os.Args[0]}, os.Args[2:]...)
+{{end}}
+
 {{if .CoverEnabled}}
        testing.RegisterCover(testing.Cover{
                Mode: {{printf "%q" .CoverMode}},
diff --git a/src/cmd/go/testdata/src/empty/pkg/pkg.go b/src/cmd/go/testdata/src/empty/pkg/pkg.go
new file mode 100644 (file)
index 0000000..c89cd18
--- /dev/null
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/empty/pkgtest/pkg.go b/src/cmd/go/testdata/src/empty/pkgtest/pkg.go
new file mode 100644 (file)
index 0000000..c89cd18
--- /dev/null
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/empty/pkgtest/test_test.go b/src/cmd/go/testdata/src/empty/pkgtest/test_test.go
new file mode 100644 (file)
index 0000000..c89cd18
--- /dev/null
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go b/src/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go
new file mode 100644 (file)
index 0000000..c89cd18
--- /dev/null
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go b/src/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go
new file mode 100644 (file)
index 0000000..c89cd18
--- /dev/null
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go b/src/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go
new file mode 100644 (file)
index 0000000..9b64e8e
--- /dev/null
@@ -0,0 +1 @@
+package p_test
diff --git a/src/cmd/go/testdata/src/empty/pkgxtest/pkg.go b/src/cmd/go/testdata/src/empty/pkgxtest/pkg.go
new file mode 100644 (file)
index 0000000..c89cd18
--- /dev/null
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go b/src/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go
new file mode 100644 (file)
index 0000000..9b64e8e
--- /dev/null
@@ -0,0 +1 @@
+package p_test
diff --git a/src/cmd/go/testdata/src/empty/test/test_test.go b/src/cmd/go/testdata/src/empty/test/test_test.go
new file mode 100644 (file)
index 0000000..c89cd18
--- /dev/null
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/empty/testxtest/test_test.go b/src/cmd/go/testdata/src/empty/testxtest/test_test.go
new file mode 100644 (file)
index 0000000..c89cd18
--- /dev/null
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/empty/testxtest/xtest_test.go b/src/cmd/go/testdata/src/empty/testxtest/xtest_test.go
new file mode 100644 (file)
index 0000000..9b64e8e
--- /dev/null
@@ -0,0 +1 @@
+package p_test
diff --git a/src/cmd/go/testdata/src/empty/xtest/xtest_test.go b/src/cmd/go/testdata/src/empty/xtest/xtest_test.go
new file mode 100644 (file)
index 0000000..9b64e8e
--- /dev/null
@@ -0,0 +1 @@
+package p_test
diff --git a/src/cmd/go/testdata/timeoutbench_test.go b/src/cmd/go/testdata/timeoutbench_test.go
new file mode 100644 (file)
index 0000000..57a8888
--- /dev/null
@@ -0,0 +1,10 @@
+package timeoutbench_test
+
+import (
+       "testing"
+       "time"
+)
+
+func BenchmarkSleep1s(b *testing.B) {
+       time.Sleep(1 * time.Second)
+}
index cf4d2b47ff9cfbdfcf00283ad9b4a4ea7b933adb..fa53bfcdf095b3ddfa2000016eb440478da79807 100644 (file)
@@ -151,10 +151,10 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                                testBench = true
                        case "timeout":
                                testTimeout = value
-                       case "blockprofile", "cpuprofile", "memprofile":
+                       case "blockprofile", "cpuprofile", "memprofile", "mutexprofile":
                                testProfile = true
                                testNeedBinary = true
-                       case "mutexprofile", "trace":
+                       case "trace":
                                testProfile = true
                        case "coverpkg":
                                testCover = true
index 226b5377b985b835e72051cb61eb3deab1faee9b..deec02e3413d6809f5b0209b7dd9101ca91bd124 100644 (file)
@@ -188,6 +188,42 @@ func TestVendorGetUpdate(t *testing.T) {
        tg.run("get", "-u", "github.com/rsc/go-get-issue-11864")
 }
 
+func TestVendorGetU(t *testing.T) {
+       testenv.MustHaveExternalNetwork(t)
+
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.makeTempdir()
+       tg.setenv("GOPATH", tg.path("."))
+       tg.run("get", "-u", "github.com/rsc/go-get-issue-11864")
+}
+
+func TestVendorGetTU(t *testing.T) {
+       testenv.MustHaveExternalNetwork(t)
+
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.makeTempdir()
+       tg.setenv("GOPATH", tg.path("."))
+       tg.run("get", "-t", "-u", "github.com/rsc/go-get-issue-11864/...")
+}
+
+func TestVendorGetBadVendor(t *testing.T) {
+       testenv.MustHaveExternalNetwork(t)
+
+       for _, suffix := range []string{"bad/imp", "bad/imp2", "bad/imp3", "..."} {
+               t.Run(suffix, func(t *testing.T) {
+                       tg := testgo(t)
+                       defer tg.cleanup()
+                       tg.makeTempdir()
+                       tg.setenv("GOPATH", tg.path("."))
+                       tg.runFail("get", "-t", "-u", "github.com/rsc/go-get-issue-18219/"+suffix)
+                       tg.grepStderr("must be imported as", "did not find error about vendor import")
+                       tg.mustNotExist(tg.path("src/github.com/rsc/vendor"))
+               })
+       }
+}
+
 func TestGetSubmodules(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)
 
diff --git a/src/cmd/gofmt/testdata/typealias.golden b/src/cmd/gofmt/testdata/typealias.golden
new file mode 100644 (file)
index 0000000..bbbbf32
--- /dev/null
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+       _  = chan<- int
+       aa = interface{}
+       bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+       _   chan<- int
+       _   = chan<- int
+       aa0 interface{}
+       aaa = interface{}
+       bb0 p.BB
+       bbb = p.BB
+)
diff --git a/src/cmd/gofmt/testdata/typealias.input b/src/cmd/gofmt/testdata/typealias.input
new file mode 100644 (file)
index 0000000..6e49328
--- /dev/null
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+       _ = chan<- int
+       aa = interface{}
+       bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+       _ chan<- int
+       _ = chan<- int
+       aa0 interface{}
+       aaa = interface{}
+       bb0 p.BB
+       bbb = p.BB
+)
index 1852dc74f63b7d4e0f014932d38c9d8f87316210..732ce1963477618250bf68b0cfbba9a1d40d95ee 100644 (file)
@@ -13,8 +13,9 @@ import (
 // go-specific code shared across loaders (5l, 6l, 8l).
 
 var (
-       framepointer_enabled int
-       Fieldtrack_enabled   int
+       framepointer_enabled     int
+       Fieldtrack_enabled       int
+       Preemptibleloops_enabled int
 )
 
 // Toolchain experiments.
@@ -27,6 +28,7 @@ var exper = []struct {
 }{
        {"fieldtrack", &Fieldtrack_enabled},
        {"framepointer", &framepointer_enabled},
+       {"preemptibleloops", &Preemptibleloops_enabled},
 }
 
 func addexp(s string) {
index d3d819e9cef7c77deaafcfe6da0d2a0549ac2342..87ddcd2bb317deeec5db5b1515ec455a7c12e2fd 100644 (file)
@@ -32,6 +32,7 @@ package mips
 import (
        "cmd/internal/obj"
        "cmd/internal/sys"
+       "encoding/binary"
        "fmt"
        "math"
 )
@@ -533,6 +534,43 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
                }
        }
 
+       if ctxt.Mode&Mips32 != 0 {
+               // rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access
+               for p = cursym.Text; p != nil; p = p1 {
+                       p1 = p.Link
+
+                       if p.As != AMOVD {
+                               continue
+                       }
+                       if p.From.Type != obj.TYPE_MEM && p.To.Type != obj.TYPE_MEM {
+                               continue
+                       }
+
+                       p.As = AMOVF
+                       q = ctxt.NewProg()
+                       *q = *p
+                       q.Link = p.Link
+                       p.Link = q
+                       p1 = q.Link
+
+                       var regOff int16
+                       if ctxt.Arch.ByteOrder == binary.BigEndian {
+                               regOff = 1 // load odd register first
+                       }
+                       if p.From.Type == obj.TYPE_MEM {
+                               reg := REG_F0 + (p.To.Reg-REG_F0)&^1
+                               p.To.Reg = reg + regOff
+                               q.To.Reg = reg + 1 - regOff
+                               q.From.Offset += 4
+                       } else if p.To.Type == obj.TYPE_MEM {
+                               reg := REG_F0 + (p.From.Reg-REG_F0)&^1
+                               p.From.Reg = reg + regOff
+                               q.From.Reg = reg + 1 - regOff
+                               q.To.Offset += 4
+                       }
+               }
+       }
+
        if nosched {
                // if we don't do instruction scheduling, simply add
                // NOP after each branch instruction.
index 5eadcb708cb2ee65e8fb7467c63d62c02a0f8551..517550c72d4dcbd701f3eed40153d4b18111f111 100644 (file)
@@ -6,9 +6,8 @@ package obj
 
 import "log"
 
-func addvarint(ctxt *Link, d *Pcdata, val uint32) {
-       var v uint32
-       for v = val; v >= 0x80; v >>= 7 {
+func addvarint(d *Pcdata, v uint32) {
+       for ; v >= 0x80; v >>= 7 {
                d.P = append(d.P, uint8(v|0x80))
        }
        d.P = append(d.P, uint8(v))
@@ -98,7 +97,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
                }
 
                if started != 0 {
-                       addvarint(ctxt, dst, uint32((p.Pc-pc)/int64(ctxt.Arch.MinLC)))
+                       addvarint(dst, uint32((p.Pc-pc)/int64(ctxt.Arch.MinLC)))
                        pc = p.Pc
                }
 
@@ -108,7 +107,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
                } else {
                        delta <<= 1
                }
-               addvarint(ctxt, dst, delta)
+               addvarint(dst, delta)
                oldval = val
                started = 1
                val = valfunc(ctxt, func_, val, p, 1, arg)
@@ -118,8 +117,8 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
                if ctxt.Debugpcln != 0 {
                        ctxt.Logf("%6x done\n", uint64(func_.Text.Pc+func_.Size))
                }
-               addvarint(ctxt, dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC)))
-               addvarint(ctxt, dst, 0) // terminator
+               addvarint(dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC)))
+               addvarint(dst, 0) // terminator
        }
 
        if ctxt.Debugpcln != 0 {
index 6de617cd788ca4ebb3fe8e64d31d84a59fc2f0e7..09c1312df5edbc46a1eb65a1263aca4b01793245 100644 (file)
@@ -4,9 +4,9 @@ package obj
 
 import "fmt"
 
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLS"
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLS"
 
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 195, 206, 216, 225, 235, 249, 263, 279, 293, 307, 318, 332, 347, 364, 382, 403, 413, 424, 437}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 248, 262, 276, 292, 306, 320, 331, 345, 360, 377, 395, 416, 426, 437, 450}
 
 func (i RelocType) String() string {
        i -= 1
index 4feaa096a796a84b7c0004120ee275bda286822b..05b90d20f206f1f111560069b89d38c465ca8cf8 100644 (file)
@@ -104,7 +104,7 @@ func archinit(ctxt *ld.Link) {
                        *ld.FlagDataAddr = 0
                }
                if *ld.FlagRound == -1 {
-                       *ld.FlagRound = 4096
+                       *ld.FlagRound = 0x10000
                }
 
        case obj.Hnacl:
index c9ee8847ad2bf0dfca86c53c3d7c944827de0201..7d00ff167553d860096bc65a54617c7948d55195 100644 (file)
@@ -184,7 +184,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
        // Internally linking cgo is incomplete on some architectures.
        // https://golang.org/issue/10373
        // https://golang.org/issue/14449
-       if iscgo && SysArch.InFamily(sys.ARM64, sys.MIPS64) {
+       if iscgo && SysArch.InFamily(sys.ARM64, sys.MIPS64, sys.MIPS) {
                return true, obj.GOARCH + " does not support internal cgo"
        }
 
index ed8193294ec631d8e26a21a098446918cb45c7d3..aca8973a8598823c6295288ab8cdf6774b36f003 100644 (file)
@@ -1250,7 +1250,7 @@ func (p *GCProg) AddSym(s *Symbol) {
 }
 
 // dataSortKey is used to sort a slice of data symbol *Symbol pointers.
-// The sort keys are kept inline to improve cache behaviour while sorting.
+// The sort keys are kept inline to improve cache behavior while sorting.
 type dataSortKey struct {
        size int64
        name string
@@ -2114,6 +2114,7 @@ func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64) (*S
                // Create new section, set the starting Vaddr
                sect = addsection(&Segtext, ".text", 05)
                sect.Vaddr = va
+               sym.Sect = sect
 
                // Create a symbol for the start of the secondary text sections
                ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
index d111b005d9828cdfcee2076cb1253e1567467ce0..d898c40c1c77ecbb55846437abeeb26b9a4d9172 100644 (file)
@@ -255,7 +255,7 @@ func decodetypeStructFieldType(s *Symbol, i int) *Symbol {
 
 func decodetypeStructFieldOffs(arch *sys.Arch, s *Symbol, i int) int64 {
        off := decodetypeStructFieldArrayOff(s, i)
-       return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
+       return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize) >> 1)
 }
 
 // InterfaceType.methods.length
index 61d3e4fb720ecd1299540652816fcc2e11a90807..22d2c548c373e0c3b91f4805e8035fd3f64192cf 100644 (file)
@@ -1080,7 +1080,7 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
                epcs = s
 
                dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version))
-               dsym.Attr |= AttrHidden
+               dsym.Attr |= AttrHidden | AttrReachable
                dsym.Type = obj.SDWARFINFO
                for _, r := range dsym.R {
                        if r.Type == obj.R_DWARFREF && r.Sym.Size == 0 {
index 7304b5b0d3e98e9a6d4af53d8b8b9f67b39052c2..1d8a5dd35e6dc21881ef7c581749372e6eca8359 100644 (file)
@@ -962,7 +962,7 @@ func Elfinit(ctxt *Link) {
                                ehdr.flags = 0x5000002 // has entry point, Version5 EABI
                        }
                } else if SysArch.Family == sys.MIPS {
-                       ehdr.flags = 0x50000000 /* MIPS 32 */
+                       ehdr.flags = 0x50001004 /* MIPS 32 CPIC O32*/
                }
                fallthrough
        default:
@@ -2777,7 +2777,7 @@ func Elfadddynsym(ctxt *Link, s *Symbol) {
                /* type */
                t := STB_GLOBAL << 4
 
-               // TODO(mwhudson): presumably the behaviour should actually be the same on both arm and 386.
+               // TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
                if SysArch.Family == sys.I386 && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
                        t |= STT_FUNC
                } else if SysArch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT {
index a2700d9698271c9b8ce2a478c322348450f3eac6..74d79d394c641fa59bf174825f5a3514b3a085fe 100644 (file)
@@ -1257,6 +1257,8 @@ func hostlinkArchArgs() []string {
                // nothing needed
        case sys.MIPS64:
                return []string{"-mabi=64"}
+       case sys.MIPS:
+               return []string{"-mabi=32"}
        }
        return nil
 }
index c88af64a3ac2a5a034f07fdb46df92ad1269142c..f3687daa91306da209f7a192607287f4914e2e6b 100644 (file)
@@ -684,6 +684,29 @@ func machosymorder(ctxt *Link) {
        }
 }
 
+// machoShouldExport reports whether a symbol needs to be exported.
+//
+// When dynamically linking, all non-local variables and plugin-exported
+// symbols need to be exported.
+func machoShouldExport(ctxt *Link, s *Symbol) bool {
+       if !ctxt.DynlinkingGo() || s.Attr.Local() {
+               return false
+       }
+       if Buildmode == BuildmodePlugin && strings.HasPrefix(s.Extname, *flagPluginPath) {
+               return true
+       }
+       if strings.HasPrefix(s.Name, "type.") && !strings.HasPrefix(s.Name, "type..") {
+               // reduce runtime typemap pressure, but do not
+               // export alg functions (type..*), as these
+               // appear in pclntable.
+               return true
+       }
+       if strings.HasPrefix(s.Name, "go.link.pkghash") {
+               return true
+       }
+       return s.Type >= obj.SELFSECT // only writable sections
+}
+
 func machosymtab(ctxt *Link) {
        symtab := ctxt.Syms.Lookup(".machosymtab", 0)
        symstr := ctxt.Syms.Lookup(".machosymstr", 0)
@@ -692,13 +715,17 @@ func machosymtab(ctxt *Link) {
                s := sortsym[i]
                Adduint32(ctxt, symtab, uint32(symstr.Size))
 
+               export := machoShouldExport(ctxt, s)
+
                // In normal buildmodes, only add _ to C symbols, as
                // Go symbols have dot in the name.
                //
-               // When dynamically linking, prefix all non-local
-               // symbols with _ as dlsym on darwin requires it to
-               // resolve any symbol.
-               if !strings.Contains(s.Extname, ".") || (ctxt.DynlinkingGo() && !s.Attr.Local()) {
+               // Do not export C symbols in plugins, as runtime C
+               // symbols like crosscall2 are in pclntab and end up
+               // pointing at the host binary, breaking unwinding.
+               // See Issue #18190.
+               cexport := !strings.Contains(s.Extname, ".") && (Buildmode != BuildmodePlugin || onlycsymbol(s))
+               if cexport || export {
                        Adduint8(ctxt, symstr, '_')
                }
 
@@ -711,7 +738,7 @@ func machosymtab(ctxt *Link) {
                        Adduint16(ctxt, symtab, 0)                  // desc
                        adduintxx(ctxt, symtab, 0, SysArch.PtrSize) // no value
                } else {
-                       if s.Attr.CgoExport() || (ctxt.DynlinkingGo() && !s.Attr.Local()) {
+                       if s.Attr.CgoExport() || export {
                                Adduint8(ctxt, symtab, 0x0f)
                        } else {
                                Adduint8(ctxt, symtab, 0x0e)
index 5a6c425f3eceb9b7410ed63df399a83cd4efab0e..479425f2111ef6191778e136049b55921bc966e4 100644 (file)
@@ -154,10 +154,26 @@ func renumberfiles(ctxt *Link, files []*Symbol, d *Pcdata) {
        *d = out
 }
 
+// onlycsymbol reports whether this is a cgo symbol provided by the
+// runtime and only used from C code.
+func onlycsymbol(s *Symbol) bool {
+       switch s.Name {
+       case "_cgo_topofstack", "_cgo_panic", "crosscall2":
+               return true
+       }
+       return false
+}
+
 func container(s *Symbol) int {
+       if s == nil {
+               return 0
+       }
+       if Buildmode == BuildmodePlugin && Headtype == obj.Hdarwin && onlycsymbol(s) {
+               return 1
+       }
        // We want to generate func table entries only for the "lowest level" symbols,
        // not containers of subsymbols.
-       if s != nil && s.Type&obj.SCONTAINER != 0 {
+       if s.Type&obj.SCONTAINER != 0 {
                return 1
        }
        return 0
@@ -232,6 +248,9 @@ func (ctxt *Link) pclntab() {
                setaddr(ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), s)
                setuintxx(ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint64(funcstart), int64(SysArch.PtrSize))
 
+               // Write runtime._func. Keep in sync with ../../../../runtime/runtime2.go:/_func
+               // and package debug/gosym.
+
                // fixed size of struct, checked below
                off := funcstart
 
index 98ce3ad79b8f4f9467e0cc4dd7e32fd0a96062bc..dd0e5407e828c46b5aaa8ca8e46ce4350fa70155 100644 (file)
@@ -602,8 +602,7 @@ func (ctxt *Link) symtab() {
        adduint(ctxt, moduledata, uint64(nitablinks))
        adduint(ctxt, moduledata, uint64(nitablinks))
        // The ptab slice
-       if ptab := ctxt.Syms.ROLookup("go.plugin.tabs", 0); ptab != nil {
-               ptab.Attr |= AttrReachable
+       if ptab := ctxt.Syms.ROLookup("go.plugin.tabs", 0); ptab != nil && ptab.Attr.Reachable() {
                ptab.Attr |= AttrLocal
                ptab.Type = obj.SRODATA
 
index b2c72893a114833cf8016246ff2b2e2a53851a0b..a591b06dfa02828770268f21c03af692732957f4 100644 (file)
@@ -47,7 +47,33 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 }
 
 func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
-       return -1
+       ld.Thearch.Lput(uint32(sectoff))
+
+       elfsym := r.Xsym.ElfsymForReloc()
+       switch r.Type {
+       default:
+               return -1
+
+       case obj.R_ADDR:
+               if r.Siz != 4 {
+                       return -1
+               }
+               ld.Thearch.Lput(ld.R_MIPS_32 | uint32(elfsym)<<8)
+
+       case obj.R_ADDRMIPS:
+               ld.Thearch.Lput(ld.R_MIPS_LO16 | uint32(elfsym)<<8)
+
+       case obj.R_ADDRMIPSU:
+               ld.Thearch.Lput(ld.R_MIPS_HI16 | uint32(elfsym)<<8)
+
+       case obj.R_ADDRMIPSTLS:
+               ld.Thearch.Lput(ld.R_MIPS_TLS_TPREL_LO16 | uint32(elfsym)<<8)
+
+       case obj.R_CALLMIPS, obj.R_JMPMIPS:
+               ld.Thearch.Lput(ld.R_MIPS_26 | uint32(elfsym)<<8)
+       }
+
+       return 0
 }
 
 func elfsetupplt(ctxt *ld.Link) {
@@ -58,9 +84,50 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
        return -1
 }
 
+func applyrel(r *ld.Reloc, s *ld.Symbol, val *int64, t int64) {
+       o := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
+       switch r.Type {
+       case obj.R_ADDRMIPS, obj.R_ADDRMIPSTLS:
+               *val = int64(o&0xffff0000 | uint32(t)&0xffff)
+       case obj.R_ADDRMIPSU:
+               *val = int64(o&0xffff0000 | uint32((t+(1<<15))>>16)&0xffff)
+       case obj.R_CALLMIPS, obj.R_JMPMIPS:
+               *val = int64(o&0xfc000000 | uint32(t>>2)&^0xfc000000)
+       }
+}
+
 func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
        if ld.Linkmode == ld.LinkExternal {
-               return -1
+               switch r.Type {
+               default:
+                       return -1
+
+               case obj.R_ADDRMIPS, obj.R_ADDRMIPSU:
+
+                       r.Done = 0
+
+                       // set up addend for eventual relocation via outer symbol.
+                       rs := r.Sym
+                       r.Xadd = r.Add
+                       for rs.Outer != nil {
+                               r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
+                               rs = rs.Outer
+                       }
+
+                       if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+                               ld.Errorf(s, "missing section for %s", rs.Name)
+                       }
+                       r.Xsym = rs
+                       applyrel(r, s, val, r.Xadd)
+                       return 0
+
+               case obj.R_ADDRMIPSTLS, obj.R_CALLMIPS, obj.R_JMPMIPS:
+                       r.Done = 0
+                       r.Xsym = r.Sym
+                       r.Xadd = r.Add
+                       applyrel(r, s, val, r.Add)
+                       return 0
+               }
        }
 
        switch r.Type {
@@ -72,23 +139,33 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
                *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
                return 0
 
-       case obj.R_ADDRMIPS,
-               obj.R_ADDRMIPSU:
+       case obj.R_ADDRMIPS, obj.R_ADDRMIPSU:
                t := ld.Symaddr(r.Sym) + r.Add
-               o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
-               if r.Type == obj.R_ADDRMIPS {
-                       *val = int64(o1&0xffff0000 | uint32(t)&0xffff)
-               } else {
-                       *val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff)
-               }
+               applyrel(r, s, val, t)
                return 0
 
-       case obj.R_CALLMIPS,
-               obj.R_JMPMIPS:
-               // Low 26 bits = (S + A) >> 2
+       case obj.R_CALLMIPS, obj.R_JMPMIPS:
                t := ld.Symaddr(r.Sym) + r.Add
-               o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
-               *val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000)
+
+               if t&3 != 0 {
+                       ld.Errorf(s, "direct call is not aligned: %s %x", r.Sym.Name, t)
+               }
+
+               // check if target address is in the same 256 MB region as the next instruction
+               if (s.Value+int64(r.Off)+4)&0xf0000000 != (t & 0xf0000000) {
+                       ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
+               }
+
+               applyrel(r, s, val, t)
+               return 0
+
+       case obj.R_ADDRMIPSTLS:
+               // thread pointer is at 0x7000 offset from the start of TLS data area
+               t := ld.Symaddr(r.Sym) + r.Add - 0x7000
+               if t < -32768 || t >= 32678 {
+                       ld.Errorf(s, "TLS offset out of range %d", t)
+               }
+               applyrel(r, s, val, t)
                return 0
        }
 
index 30b964d883bffdea3932ebc6ba50e6ce7735fd06..10fc7164637d199ecc4ebb25905cc7dbbdb95a59 100644 (file)
@@ -166,7 +166,7 @@ func TestDisasmExtld(t *testing.T) {
                t.Skipf("skipping on %s, no support for external linking, issue 9038", runtime.GOARCH)
        case "arm64":
                t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
-       case "mips64", "mips64le":
+       case "mips64", "mips64le", "mips", "mipsle":
                t.Skipf("skipping on %s, issue 12559 and 12560", runtime.GOARCH)
        case "s390x":
                t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
index 931985a7f2891b7dd1d0829c36f468e151c67eac..0f1ed6eece053877749e62fd4f10ec828b9f24e2 100644 (file)
@@ -780,14 +780,14 @@ func processFlags(p *profile.Profile, ui plugin.UI, f *flags) error {
 
        var err error
        si, sm := *f.flagSampleIndex, *f.flagMean || *f.flagMeanDelay
-       si, err = sampleIndex(p, &f.flagTotalDelay, si, 1, "delay", "-total_delay", err)
-       si, err = sampleIndex(p, &f.flagMeanDelay, si, 1, "delay", "-mean_delay", err)
-       si, err = sampleIndex(p, &f.flagContentions, si, 0, "contentions", "-contentions", err)
+       si, err = sampleIndex(p, &f.flagTotalDelay, si, "delay", "-total_delay", err)
+       si, err = sampleIndex(p, &f.flagMeanDelay, si, "delay", "-mean_delay", err)
+       si, err = sampleIndex(p, &f.flagContentions, si, "contentions", "-contentions", err)
 
-       si, err = sampleIndex(p, &f.flagInUseSpace, si, 1, "inuse_space", "-inuse_space", err)
-       si, err = sampleIndex(p, &f.flagInUseObjects, si, 0, "inuse_objects", "-inuse_objects", err)
-       si, err = sampleIndex(p, &f.flagAllocSpace, si, 1, "alloc_space", "-alloc_space", err)
-       si, err = sampleIndex(p, &f.flagAllocObjects, si, 0, "alloc_objects", "-alloc_objects", err)
+       si, err = sampleIndex(p, &f.flagInUseSpace, si, "inuse_space", "-inuse_space", err)
+       si, err = sampleIndex(p, &f.flagInUseObjects, si, "inuse_objects", "-inuse_objects", err)
+       si, err = sampleIndex(p, &f.flagAllocSpace, si, "alloc_space", "-alloc_space", err)
+       si, err = sampleIndex(p, &f.flagAllocObjects, si, "alloc_objects", "-alloc_objects", err)
 
        if si == -1 {
                // Use last value if none is requested.
@@ -806,7 +806,6 @@ func processFlags(p *profile.Profile, ui plugin.UI, f *flags) error {
 
 func sampleIndex(p *profile.Profile, flag **bool,
        sampleIndex int,
-       newSampleIndex int,
        sampleType, option string,
        err error) (int, error) {
        if err != nil || !**flag {
@@ -816,11 +815,12 @@ func sampleIndex(p *profile.Profile, flag **bool,
        if sampleIndex != -1 {
                return 0, fmt.Errorf("set at most one sample value selection option")
        }
-       if newSampleIndex >= len(p.SampleType) ||
-               p.SampleType[newSampleIndex].Type != sampleType {
-               return 0, fmt.Errorf("option %s not valid for this profile", option)
+       for index, s := range p.SampleType {
+               if sampleType == s.Type {
+                       return index, nil
+               }
        }
-       return newSampleIndex, nil
+       return 0, fmt.Errorf("option %s not valid for this profile", option)
 }
 
 func countFlags(bs []*bool) int {
index 14875c16dbb3f4b6a77bab04a983ad4c57fdfead..f897c9086f706aaa5b897e077467ea3fda0f3399 100644 (file)
@@ -123,7 +123,7 @@ func symbolsFromBinaries(prof *profile.Profile, g graph, rx *regexp.Regexp, addr
        // Walk all mappings looking for matching functions with samples.
        var objSyms []*objSymbol
        for _, m := range prof.Mapping {
-               if !hasSamples[filepath.Base(m.File)] {
+               if !hasSamples[m.File] {
                        if address == nil || !(m.Start <= *address && *address <= m.Limit) {
                                continue
                        }
index 7ab7e3861f79a7f88c18f8e3963cb1e11f0d77e0..458985d1fa012abeae8aa5a4a51dd99c038fd90c 100644 (file)
@@ -229,7 +229,7 @@ func assemblyPerSourceLine(objSyms []*objSymbol, rs nodes, src string, obj plugi
 func findMatchingSymbol(objSyms []*objSymbol, ns nodes) *objSymbol {
        for _, n := range ns {
                for _, o := range objSyms {
-                       if filepath.Base(o.sym.File) == n.info.objfile &&
+                       if o.sym.File == n.info.objfile &&
                                o.sym.Start <= n.info.address-o.base &&
                                n.info.address-o.base <= o.sym.End {
                                return o
index 4975b103e31be3cf592772350571368175aee817..d8f12afea4922b3206413f9575b5c144a3c5c143 100644 (file)
@@ -17,7 +17,7 @@ const svgPanJS = `
  *  - Mouse zooming (using the wheel)
  *  - Object dragging
  *
- * You can configure the behaviour of the pan/zoom/drag with the variables
+ * You can configure the behavior of the pan/zoom/drag with the variables
  * listed in the CONFIGURATION section of this file.
  *
  * Known issues:
index d233e9a96020bebffc71518359473df0abc837db..984911c489f9d70c8c71e371ccbc6c1ac452146f 100644 (file)
@@ -44,7 +44,7 @@ func checkCgoCall(f *File, node ast.Node) {
        }
 
        for _, arg := range x.Args {
-               if !typeOKForCgoCall(cgoBaseType(f, arg)) {
+               if !typeOKForCgoCall(cgoBaseType(f, arg), make(map[types.Type]bool)) {
                        f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
                }
 
@@ -53,7 +53,7 @@ func checkCgoCall(f *File, node ast.Node) {
                        arg = conv.Args[0]
                }
                if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND {
-                       if !typeOKForCgoCall(cgoBaseType(f, u.X)) {
+                       if !typeOKForCgoCall(cgoBaseType(f, u.X), make(map[types.Type]bool)) {
                                f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
                        }
                }
@@ -110,23 +110,24 @@ func cgoBaseType(f *File, arg ast.Expr) types.Type {
        return f.pkg.types[arg].Type
 }
 
-// typeOKForCgoCall returns true if the type of arg is OK to pass to a
+// typeOKForCgoCall reports whether the type of arg is OK to pass to a
 // C function using cgo. This is not true for Go types with embedded
-// pointers.
-func typeOKForCgoCall(t types.Type) bool {
-       if t == nil {
+// pointers. m is used to avoid infinite recursion on recursive types.
+func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool {
+       if t == nil || m[t] {
                return true
        }
+       m[t] = true
        switch t := t.Underlying().(type) {
        case *types.Chan, *types.Map, *types.Signature, *types.Slice:
                return false
        case *types.Pointer:
-               return typeOKForCgoCall(t.Elem())
+               return typeOKForCgoCall(t.Elem(), m)
        case *types.Array:
-               return typeOKForCgoCall(t.Elem())
+               return typeOKForCgoCall(t.Elem(), m)
        case *types.Struct:
                for i := 0; i < t.NumFields(); i++ {
-                       if !typeOKForCgoCall(t.Field(i).Type()) {
+                       if !typeOKForCgoCall(t.Field(i).Type(), m) {
                                return false
                        }
                }
index 31c1257a47017401a53811c7d874608bf85f0de2..27eb5d465174dd7a75a477d4386fdd7bf6156176 100644 (file)
@@ -93,13 +93,15 @@ func checkCopyLocksReturnStmt(f *File, rs *ast.ReturnStmt) {
 
 // checkCopyLocksCallExpr detects lock copy in the arguments to a function call
 func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) {
-       if id, ok := ce.Fun.(*ast.Ident); ok && id.Name == "new" && f.pkg.types[id].IsBuiltin() {
-               // Skip 'new(Type)' for built-in 'new'
-               return
+       if id, ok := ce.Fun.(*ast.Ident); ok && f.pkg.types[id].IsBuiltin() {
+               switch id.Name {
+               case "new", "len", "cap":
+                       return
+               }
        }
        for _, x := range ce.Args {
                if path := lockPathRhs(f, x); path != nil {
-                       f.Badf(x.Pos(), "function call copies lock value: %v", path)
+                       f.Badf(x.Pos(), "call of %s copies lock value: %v", f.gofmt(ce.Fun), path)
                }
        }
 }
index 814bbda59499f8a5a5b25dfa5e6bd5a50a2e2d03..872fde79ce37bbb34754e08eaf9e2b7df1a051f3 100644 (file)
@@ -54,14 +54,37 @@ func checkCanonicalFieldTag(f *File, field *ast.Field, seen *map[[2]string]token
                if val == "" || val == "-" || val[0] == ',' {
                        continue
                }
+               if key == "xml" && len(field.Names) > 0 && field.Names[0].Name == "XMLName" {
+                       // XMLName defines the XML element name of the struct being
+                       // checked. That name cannot collide with element or attribute
+                       // names defined on other fields of the struct. Vet does not have a
+                       // check for untagged fields of type struct defining their own name
+                       // by containing a field named XMLName; see issue 18256.
+                       continue
+               }
                if i := strings.Index(val, ","); i >= 0 {
+                       if key == "xml" {
+                               // Use a separate namespace for XML attributes.
+                               for _, opt := range strings.Split(val[i:], ",") {
+                                       if opt == "attr" {
+                                               key += " attribute" // Key is part of the error message.
+                                               break
+                                       }
+                               }
+                       }
                        val = val[:i]
                }
                if *seen == nil {
                        *seen = map[[2]string]token.Pos{}
                }
                if pos, ok := (*seen)[[2]string{key, val}]; ok {
-                       f.Badf(field.Pos(), "struct field %s repeats %s tag %q also at %s", field.Names[0].Name, key, val, f.loc(pos))
+                       var name string
+                       if len(field.Names) > 0 {
+                               name = field.Names[0].Name
+                       } else {
+                               name = field.Type.(*ast.Ident).Name
+                       }
+                       f.Badf(field.Pos(), "struct field %s repeats %s tag %q also at %s", name, key, val, f.loc(pos))
                } else {
                        (*seen)[[2]string{key, val}] = field.Pos()
                }
index 25d395b1ea89008cb38c62c11a1cae12285696d0..d0df7cf6787fe00f12054f9fed434a8b8e1edad7 100644 (file)
@@ -52,5 +52,8 @@ func CgoTests() {
        C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2)))
        C.f(unsafe.Pointer(&st2))
 
+       type cgoStruct struct{ p *cgoStruct }
+       C.f(unsafe.Pointer(&cgoStruct{}))
+
        C.CBytes([]byte("hello"))
 }
index 35ed766f1da7e26010bcd7d3285c534c5ebf8b83..6fabbc337a0d6ac5865ca7fc8684551ac0ab4a7f 100644 (file)
@@ -67,7 +67,7 @@ func BadFunc() {
 
        // override 'new' keyword
        new := func(interface{}) {}
-       new(t) // ERROR "function call copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
+       new(t) // ERROR "call of new copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
 
        // copy of array of locks
        var muA [5]sync.Mutex
@@ -88,6 +88,20 @@ func BadFunc() {
        fmuSlice := fmuA[:] // OK
 }
 
+func LenAndCapOnLockArrays() {
+       var a [5]sync.Mutex
+       aLen := len(a) // OK
+       aCap := cap(a) // OK
+
+       // override 'len' and 'cap' keywords
+
+       len := func(interface{}) {}
+       len(a) // ERROR "call of len copies lock value: sync.Mutex"
+
+       cap := func(interface{}) {}
+       cap(a) // ERROR "call of cap copies lock value: sync.Mutex"
+}
+
 // SyncTypesCheck checks copying of sync.* types except sync.Mutex
 func SyncTypesCheck() {
        // sync.RWMutex copying
index bfafa124fabb5feeeeef45015e28796dfb0795fb..d51ff27cda04fde453b16bd925bf91bed7fae0f5 100644 (file)
@@ -86,8 +86,10 @@ func FuncCallInterfaceArg(f func(a int, b interface{})) {
        f(1, "foo")
        f(2, &t)
        f(3, &sync.Mutex{})
-       f(4, m) // ERROR "function call copies lock value: sync.Mutex"
-       f(5, t) // ERROR "function call copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
+       f(4, m) // ERROR "call of f copies lock value: sync.Mutex"
+       f(5, t) // ERROR "call of f copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
+       var fntab []func(t)
+       fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
 }
 
 // Returning lock via interface value
index cba990fccd1a9b0f7e66b20f14da1b3d3a1de2fb..363aa898bf91b536289b6acf61ce01910b16f5ab 100644 (file)
@@ -6,6 +6,8 @@
 
 package testdata
 
+import "encoding/xml"
+
 type StructTagTest struct {
        A   int "hello"            // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
        B   int "\tx:\"y\""        // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
@@ -37,30 +39,44 @@ type JSONEmbeddedField struct {
        unexp                     `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363
 }
 
+type AnonymousJSON struct{}
+type AnonymousXML struct{}
+
 type DuplicateJSONFields struct {
        JSON              int `json:"a"`
-       DuplicateJSON     int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:41"
+       DuplicateJSON     int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:46"
        IgnoredJSON       int `json:"-"`
        OtherIgnoredJSON  int `json:"-"`
        OmitJSON          int `json:",omitempty"`
        OtherOmitJSON     int `json:",omitempty"`
-       DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:41"
+       DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:46"
        NonJSON           int `foo:"a"`
        DuplicateNonJSON  int `foo:"a"`
        Embedded          struct {
                DuplicateJSON int `json:"a"` // OK because its not in the same struct type
        }
+       AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at testdata/structtag.go:46"
 
        XML              int `xml:"a"`
-       DuplicateXML     int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:54"
+       DuplicateXML     int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:60"
        IgnoredXML       int `xml:"-"`
        OtherIgnoredXML  int `xml:"-"`
        OmitXML          int `xml:",omitempty"`
        OtherOmitXML     int `xml:",omitempty"`
-       DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:54"
+       DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:60"
        NonXML           int `foo:"a"`
        DuplicateNonXML  int `foo:"a"`
        Embedded         struct {
                DuplicateXML int `xml:"a"` // OK because its not in the same struct type
        }
+       AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at testdata/structtag.go:60"
+       Attribute    struct {
+               XMLName     xml.Name `xml:"b"`
+               NoDup       int      `xml:"b"`                // OK because XMLName above affects enclosing struct.
+               Attr        int      `xml:"b,attr"`           // OK because <b b="0"><b>0</b></b> is valid.
+               DupAttr     int      `xml:"b,attr"`           // ERROR "struct field DupAttr repeats xml attribute tag .b. also at testdata/structtag.go:76"
+               DupOmitAttr int      `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at testdata/structtag.go:76"
+
+               AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at testdata/structtag.go:76"
+       }
 }
index 725f013a7dfc71c6c5a364343de7dcf8c5d2261b..b3d5c663a714c755503a254f74f41a2dc5aff312 100644 (file)
@@ -143,6 +143,7 @@ func TestVetDirs(t *testing.T) {
                "divergent",
                "buildtag",
                "incomplete", // incomplete examples
+               "cgo",
        } {
                dir := dir
                t.Run(dir, func(t *testing.T) {
index a6c3080db3efe5f49467b28e703aed888e560b02..95fb18958561b311a6d545cdc4cb976f34ab6cf4 100644 (file)
@@ -204,12 +204,6 @@ func TestMTF(t *testing.T) {
        }
 }
 
-var (
-       digits = mustLoadFile("testdata/e.txt.bz2")
-       twain  = mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2")
-       random = mustLoadFile("testdata/random.data.bz2")
-)
-
 func benchmarkDecode(b *testing.B, compressed []byte) {
        // Determine the uncompressed size of testfile.
        uncompressedSize, err := io.Copy(ioutil.Discard, NewReader(bytes.NewReader(compressed)))
@@ -227,6 +221,18 @@ func benchmarkDecode(b *testing.B, compressed []byte) {
        }
 }
 
-func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) }
-func BenchmarkDecodeTwain(b *testing.B)  { benchmarkDecode(b, twain) }
-func BenchmarkDecodeRand(b *testing.B)   { benchmarkDecode(b, random) }
+func BenchmarkDecodeDigits(b *testing.B) {
+       digits := mustLoadFile("testdata/e.txt.bz2")
+       b.ResetTimer()
+       benchmarkDecode(b, digits)
+}
+func BenchmarkDecodeTwain(b *testing.B) {
+       twain := mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2")
+       b.ResetTimer()
+       benchmarkDecode(b, twain)
+}
+func BenchmarkDecodeRand(b *testing.B) {
+       random := mustLoadFile("testdata/random.data.bz2")
+       b.ResetTimer()
+       benchmarkDecode(b, random)
+}
index 97265b3ca27ad091af42e7bf2ff120dd5e54f277..4d6a5357d881da4d90aba22d65728c60c075e287 100644 (file)
@@ -136,14 +136,17 @@ func (d *compressor) fillDeflate(b []byte) int {
                        delta := d.hashOffset - 1
                        d.hashOffset -= delta
                        d.chainHead -= delta
-                       for i, v := range d.hashPrev {
+
+                       // Iterate over slices instead of arrays to avoid copying
+                       // the entire table onto the stack (Issue #18625).
+                       for i, v := range d.hashPrev[:] {
                                if int(v) > delta {
                                        d.hashPrev[i] = uint32(int(v) - delta)
                                } else {
                                        d.hashPrev[i] = 0
                                }
                        }
-                       for i, v := range d.hashHead {
+                       for i, v := range d.hashHead[:] {
                                if int(v) > delta {
                                        d.hashHead[i] = uint32(int(v) - delta)
                                } else {
index 521a2603658b9bba53c7138f2c950750a2eecba9..fbea761721a3e4115437c0bf244068daf86cfca7 100644 (file)
@@ -12,6 +12,7 @@ import (
        "io"
        "io/ioutil"
        "reflect"
+       "runtime/debug"
        "sync"
        "testing"
 )
@@ -864,3 +865,33 @@ func TestBestSpeedMaxMatchOffset(t *testing.T) {
                }
        }
 }
+
+func TestMaxStackSize(t *testing.T) {
+       // This test must not run in parallel with other tests as debug.SetMaxStack
+       // affects all goroutines.
+       n := debug.SetMaxStack(1 << 16)
+       defer debug.SetMaxStack(n)
+
+       var wg sync.WaitGroup
+       defer wg.Wait()
+
+       b := make([]byte, 1<<20)
+       for level := HuffmanOnly; level <= BestCompression; level++ {
+               // Run in separate goroutine to increase probability of stack regrowth.
+               wg.Add(1)
+               go func(level int) {
+                       defer wg.Done()
+                       zw, err := NewWriter(ioutil.Discard, level)
+                       if err != nil {
+                               t.Errorf("level %d, NewWriter() = %v, want nil", level, err)
+                       }
+                       if n, err := zw.Write(b); n != len(b) || err != nil {
+                               t.Errorf("level %d, Write() = (%d, %v), want (%d, nil)", level, n, err, len(b))
+                       }
+                       if err := zw.Close(); err != nil {
+                               t.Errorf("level %d, Close() = %v, want nil", level, err)
+                       }
+                       zw.Reset(ioutil.Discard)
+               }(level)
+       }
+}
index a1636a37d67cfa9826e78de10618c94faa12f5d6..08298b76bbb2da5a7882d439d61d8428b28f632a 100644 (file)
@@ -60,7 +60,7 @@ func newDeflateFast() *deflateFast {
 func (e *deflateFast) encode(dst []token, src []byte) []token {
        // Ensure that e.cur doesn't wrap.
        if e.cur > 1<<30 {
-               *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
+               e.resetAll()
        }
 
        // This check isn't in the Snappy implementation, but there, the caller
@@ -265,6 +265,21 @@ func (e *deflateFast) reset() {
 
        // Protect against e.cur wraparound.
        if e.cur > 1<<30 {
-               *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
+               e.resetAll()
+       }
+}
+
+// resetAll resets the deflateFast struct and is only called in rare
+// situations to prevent integer overflow. It manually resets each field
+// to avoid causing large stack growth.
+//
+// See https://golang.org/issue/18636.
+func (e *deflateFast) resetAll() {
+       // This is equivalent to:
+       //      *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
+       e.cur = maxStoreBlockSize
+       e.prev = e.prev[:0]
+       for i := range e.table {
+               e.table[i] = tableEntry{}
        }
 }
index e76d47cc4ee5700d9faedfeb8b94a3c7370ac3ae..30c1390dfd7faf0ca4d2e1e37c8868db2f9e2089 100644 (file)
@@ -9,11 +9,17 @@ import (
        "testing"
 )
 
-// Per golang.org/issue/14937, check that every .gz file
-// in the tree has a zero mtime.
+// TestGZIPFilesHaveZeroMTimes checks that every .gz file in the tree
+// has a zero MTIME. This is a requirement for the Debian maintainers
+// to be able to have deterministic packages.
+//
+// See https://golang.org/issue/14937.
 func TestGZIPFilesHaveZeroMTimes(t *testing.T) {
-       if testing.Short() && testenv.Builder() == "" {
-               t.Skip("skipping in short mode")
+       // To avoid spurious false positives due to untracked GZIP files that
+       // may be in the user's GOROOT (Issue 18604), we only run this test on
+       // the builders, which should have a clean checkout of the tree.
+       if testenv.Builder() == "" {
+               t.Skip("skipping test on non-builder")
        }
        goroot, err := filepath.EvalSymlinks(runtime.GOROOT())
        if err != nil {
index 2d604a04d3abdfd4e657a4a313fcf0a51c0a277e..6efc06cbe59355bce15d5e886a0e54155594d5c4 100644 (file)
@@ -595,14 +595,14 @@ func XTestCancelRemoves(t testingT) {
        _, cancel := WithCancel(ctx)
        checkChildren("with WithCancel child ", ctx, 1)
        cancel()
-       checkChildren("after cancelling WithCancel child", ctx, 0)
+       checkChildren("after canceling WithCancel child", ctx, 0)
 
        ctx, _ = WithCancel(Background())
        checkChildren("after creation", ctx, 0)
        _, cancel = WithTimeout(ctx, 60*time.Minute)
        checkChildren("with WithTimeout child ", ctx, 1)
        cancel()
-       checkChildren("after cancelling WithTimeout child", ctx, 0)
+       checkChildren("after canceling WithTimeout child", ctx, 0)
 }
 
 func XTestWithCancelCanceledParent(t testingT) {
index 6030c25ee37b82a9ed8adc180958a1b54f307e78..28d0ac90cf3c42040fc11337ce8fd2c2d1e23598 100644 (file)
@@ -27,7 +27,7 @@ type aesCipherAsm struct {
 // cryptBlocks invokes the cipher message (KM) instruction with
 // the given function code. This is equivalent to AES in ECB
 // mode. The length must be a multiple of BlockSize (16).
-//go:noesape
+//go:noescape
 func cryptBlocks(c code, key, dst, src *byte, length int)
 
 var useAsm = cipherhw.AESGCMSupport()
index aee73a7c52c75eb2f6d2c1e451c3905949debfd1..cbac5ff0ea155feaa14bfbdf372876aaf56cb0e5 100644 (file)
@@ -4,6 +4,13 @@
 
 // Package aes implements AES encryption (formerly Rijndael), as defined in
 // U.S. Federal Information Processing Standards Publication 197.
+//
+// The AES operations in this package are not implemented using constant-time algorithms.
+// An exception is when running on systems with enabled hardware support for AES
+// that makes these operations constant-time. Examples include amd64 systems using AES-NI
+// extensions and s390x systems using Message-Security-Assist extensions.
+// On such systems, when the result of NewCipher is passed to cipher.NewGCM,
+// the GHASH operation used by GCM is also constant-time.
 package aes
 
 // This file contains AES constants - 8720 bytes of initialized data.
index 9eaaf7c21ebe5e431d3b66f372a0339f6658ebb5..438310d3dee74ccd96207025b492bf1f48dfd557 100644 (file)
@@ -257,7 +257,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
        if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
                // The AESNI code decrypts and authenticates concurrently, and
                // so overwrites dst in the event of a tag mismatch. That
-               // behaviour is mimicked here in order to be consistent across
+               // behavior is mimicked here in order to be consistent across
                // platforms.
                for i := range out {
                        out[i] = 0
index cfc5769a80e7718377965ab2f824a49296ac7b98..62085aac0fe58b68bd4095fd24b3bc92823369b1 100644 (file)
@@ -74,6 +74,10 @@ type gcm struct {
 
 // NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode
 // with the standard nonce length.
+//
+// In general, the GHASH operation performed by this implementation of GCM is not constant-time.
+// An exception is when the underlying Block was created by aes.NewCipher
+// on systems with hardware support for AES. See the crypto/aes package documentation for details.
 func NewGCM(cipher Block) (AEAD, error) {
        return NewGCMWithNonceSize(cipher, gcmStandardNonceSize)
 }
@@ -184,7 +188,7 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
        if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
                // The AESNI code decrypts and authenticates concurrently, and
                // so overwrites dst in the event of a tag mismatch. That
-               // behaviour is mimicked here in order to be consistent across
+               // behavior is mimicked here in order to be consistent across
                // platforms.
                for i := range out {
                        out[i] = 0
index e9b6a0c25328a000a24066de31a1d7588e426754..bc0c3e34629d377e6d0ea125d3f7333ab79ad635 100644 (file)
@@ -3,6 +3,8 @@
 // license that can be found in the LICENSE file.
 
 // Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3.
+//
+// The DSA operations in this package are not implemented using constant-time algorithms.
 package dsa
 
 import (
@@ -189,17 +191,21 @@ func fermatInverse(k, P *big.Int) *big.Int {
 // Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
 // to the byte-length of the subgroup. This function does not perform that
 // truncation itself.
+//
+// Be aware that calling Sign with an attacker-controlled PrivateKey may
+// require an arbitrary amount of CPU.
 func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
        // FIPS 186-3, section 4.6
 
        n := priv.Q.BitLen()
-       if n&7 != 0 {
+       if priv.Q.Sign() <= 0 || priv.P.Sign() <= 0 || priv.G.Sign() <= 0 || priv.X.Sign() <= 0 || n&7 != 0 {
                err = ErrInvalidPublicKey
                return
        }
        n >>= 3
 
-       for {
+       var attempts int
+       for attempts = 10; attempts > 0; attempts-- {
                k := new(big.Int)
                buf := make([]byte, n)
                for {
@@ -208,6 +214,10 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
                                return
                        }
                        k.SetBytes(buf)
+                       // priv.Q must be >= 128 because the test above
+                       // requires it to be > 0 and that
+                       //    ceil(log_2(Q)) mod 8 = 0
+                       // Thus this loop will quickly terminate.
                        if k.Sign() > 0 && k.Cmp(priv.Q) < 0 {
                                break
                        }
@@ -235,6 +245,12 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
                }
        }
 
+       // Only degenerate private keys will require more than a handful of
+       // attempts.
+       if attempts == 0 {
+               return nil, nil, ErrInvalidPublicKey
+       }
+
        return
 }
 
index 568416d0dfb23377129b7db9d5081a4cb762e4ae..8600059f0329fe26271a1d726e0923bcd9288ce5 100644 (file)
@@ -73,6 +73,14 @@ func TestParameterGeneration(t *testing.T) {
        testParameterGeneration(t, L3072N256, 3072, 256)
 }
 
+func fromHex(s string) *big.Int {
+       result, ok := new(big.Int).SetString(s, 16)
+       if !ok {
+               panic(s)
+       }
+       return result
+}
+
 func TestSignAndVerify(t *testing.T) {
        var priv PrivateKey
        priv.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16)
@@ -83,3 +91,33 @@ func TestSignAndVerify(t *testing.T) {
 
        testSignAndVerify(t, 0, &priv)
 }
+
+func TestSigningWithDegenerateKeys(t *testing.T) {
+       // Signing with degenerate private keys should not cause an infinite
+       // loop.
+       badKeys := []struct {
+               p, q, g, y, x string
+       }{
+               {"00", "01", "00", "00", "00"},
+               {"01", "ff", "00", "00", "00"},
+       }
+
+       for i, test := range badKeys {
+               priv := PrivateKey{
+                       PublicKey: PublicKey{
+                               Parameters: Parameters{
+                                       P: fromHex(test.p),
+                                       Q: fromHex(test.q),
+                                       G: fromHex(test.g),
+                               },
+                               Y: fromHex(test.y),
+                       },
+                       X: fromHex(test.x),
+               }
+
+               hashed := []byte("testing")
+               if _, _, err := Sign(rand.Reader, &priv, hashed); err == nil {
+                       t.Errorf("#%d: unexpected success", i)
+               }
+       }
+}
index c02df45d10502d129bf3bf48406593492d8d85c9..d3527243e78a4f5fc755a91ed556b5f266eab101 100644 (file)
@@ -367,18 +367,24 @@ func initP521() {
 }
 
 // P256 returns a Curve which implements P-256 (see FIPS 186-3, section D.2.3)
+//
+// The cryptographic operations are implemented using constant-time algorithms.
 func P256() Curve {
        initonce.Do(initAll)
        return p256
 }
 
 // P384 returns a Curve which implements P-384 (see FIPS 186-3, section D.2.4)
+//
+// The cryptographic operations do not use constant-time algorithms.
 func P384() Curve {
        initonce.Do(initAll)
        return p384
 }
 
 // P521 returns a Curve which implements P-521 (see FIPS 186-3, section D.2.5)
+//
+// The cryptographic operations do not use constant-time algorithms.
 func P521() Curve {
        initonce.Do(initAll)
        return p521
index de266ca77a773efd404da2668c666d0b79b738b8..22d0e2429cdfb292106804d7b23b24eb3b5087bb 100644 (file)
@@ -35,7 +35,9 @@ func initP224() {
        p224FromBig(&p224.b, p224.B)
 }
 
-// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2)
+// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2).
+//
+// The cryptographic operations are implemented using constant-time algorithms.
 func P224() Curve {
        initonce.Do(initAll)
        return p224
index f809a9b9bc888e186fe9176124a16f5d9f479393..1de4fcb473eab9dda4bc88b0c2fe0a13dcb27662 100644 (file)
@@ -18,6 +18,8 @@
 // with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract
 // over the public-key primitive, the PrivateKey struct implements the
 // Decrypter and Signer interfaces from the crypto package.
+//
+// The RSA operations in this package are not implemented using constant-time algorithms.
 package rsa
 
 import (
index 0cdb43b422fdcccaaf3b1e03fe86723990fbb9fa..77c8ec39060e499db66d1b7853c69aaa4d72f4ee 100644 (file)
@@ -225,7 +225,7 @@ end:
        RET
 
 
-// This is the implementation using AVX2. It is based on:
+// This is the implementation using AVX2, BMI1 and BMI2. It is based on:
 // "SHA-1 implementation with Intel(R) AVX2 instruction set extensions"
 // From http://software.intel.com/en-us/articles
 // (look for improving-the-performance-of-the-secure-hash-algorithm-1)
@@ -1459,15 +1459,19 @@ TEXT ·blockAVX2(SB),$1408-32
 
 
 // func checkAVX2() bool
-// returns whether AVX2 is supported
+// returns whether AVX2, BMI1 and BMI2 are supported
 TEXT ·checkAVX2(SB),NOSPLIT,$0
-       CMPB runtime·support_avx2(SB), $1
-       JE   has
-        MOVB    $0, ret+0(FP)
-       RET
-has:
+       CMPB runtime·support_avx2(SB), $0
+       JE   noavx2
+       CMPB runtime·support_bmi1(SB), $0  // check for ANDNL instruction
+       JE   noavx2
+       CMPB runtime·support_bmi2(SB), $0  // check for RORXL instruction
+       JE   noavx2
         MOVB    $1, ret+0(FP)
        RET
+noavx2:
+        MOVB    $0, ret+0(FP)
+       RET
 
 
 DATA K_XMM_AR<>+0x00(SB)/4,$0x5a827999
index edf7ad1a3bc6e3addc702e1e37d121c2505e2fea..e9705b94b12abf0bf8c62a430bfc6a3a0bacd047 100644 (file)
        ADDL  y3, h                        // h = t1 + S0 + MAJ                                 // --
 
 TEXT ·block(SB), 0, $536-32
-       CMPB runtime·support_avx2(SB), $1
+       CMPB runtime·support_avx2(SB), $0
+       JE   noavx2bmi2
+       CMPB runtime·support_bmi2(SB), $1  // check for RORXL instruction
        JE   avx2
+noavx2bmi2:
 
        MOVQ p_base+8(FP), SI
        MOVQ p_len+16(FP), DX
index 05146743acbba6010f3ac868bf2184303e11cf92..beb0f1926d89947d9603f0dbc2561ae08320d67f 100644 (file)
@@ -84,15 +84,15 @@ var cipherSuites = []*cipherSuite{
        {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
        {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
        {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
-       {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
+       {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
        {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
-       {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, cipherAES, macSHA256, nil},
+       {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
        {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
        {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
        {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
        {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
        {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
-       {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
+       {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
        {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
        {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
        {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
index 4b2702a716893cf67ed7b4b0e3c84d4538be1650..03895a723fa25670946dd973378014c9ed04f901 100644 (file)
@@ -37,7 +37,7 @@ type Conn struct {
        vers          uint16  // TLS version
        haveVers      bool    // version has been negotiated
        config        *Config // configuration passed to constructor
-       // handshakeComplete is true if the connection is currently transfering
+       // handshakeComplete is true if the connection is currently transferring
        // application data (i.e. is not currently processing a handshake).
        handshakeComplete bool
        // handshakes counts the number of handshakes performed on the
index f2e5aea2bce5ed6d7305c2d8fdfd233b0d63c2fd..615d1e5576fdaab8c772eadae62a3d146757cc6d 100644 (file)
@@ -6,8 +6,8 @@
 package tls
 
 // BUG(agl): The crypto/tls package only implements some countermeasures
-// against Lucky13 attacks on CBC-mode encryption. See
-// http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
+// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
+// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
 // https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
 
 import (
index fea33df379aebdce57f78c6cc6a412e61acea99d..71ffbdf0e0460bd2df3d2a4e269f6056e3bd6b0d 100644 (file)
@@ -4,7 +4,11 @@
 
 package x509
 
-import "encoding/pem"
+import (
+       "encoding/pem"
+       "errors"
+       "runtime"
+)
 
 // CertPool is a set of certificates.
 type CertPool struct {
@@ -26,6 +30,11 @@ func NewCertPool() *CertPool {
 // Any mutations to the returned pool are not written to disk and do
 // not affect any other pool.
 func SystemCertPool() (*CertPool, error) {
+       if runtime.GOOS == "windows" {
+               // Issue 16736, 18609:
+               return nil, errors.New("crypto/x509: system root pool is not available on Windows")
+       }
+
        return loadSystemRoots()
 }
 
index 59b303d64f74efc92137858ee39252d6e7e25e31..66cdb5ea261f0d2535224bbce4fa186872291f8f 100644 (file)
@@ -7,17 +7,22 @@
 package x509
 
 import (
+       "bufio"
        "bytes"
+       "crypto/sha1"
        "encoding/pem"
        "fmt"
+       "io"
        "io/ioutil"
        "os"
        "os/exec"
-       "strconv"
+       "path/filepath"
+       "strings"
        "sync"
-       "syscall"
 )
 
+var debugExecDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
+
 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
        return nil, nil
 }
@@ -27,7 +32,35 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
 // even if the tests are run with cgo enabled.
 // The linker will not include these unused functions in binaries built with cgo enabled.
 
+// execSecurityRoots finds the macOS list of trusted root certificates
+// using only command-line tools. This is our fallback path when cgo isn't available.
+//
+// The strategy is as follows:
+//
+// 1. Run "security trust-settings-export" and "security
+//    trust-settings-export -d" to discover the set of certs with some
+//    user-tweaked trust policy. We're too lazy to parse the XML (at
+//    least at this stage of Go 1.8) to understand what the trust
+//    policy actually is. We just learn that there is _some_ policy.
+//
+// 2. Run "security find-certificate" to dump the list of system root
+//    CAs in PEM format.
+//
+// 3. For each dumped cert, conditionally verify it with "security
+//    verify-cert" if that cert was in the set discovered in Step 1.
+//    Without the Step 1 optimization, running "security verify-cert"
+//    150-200 times takes 3.5 seconds. With the optimization, the
+//    whole process takes about 180 milliseconds with 1 untrusted root
+//    CA. (Compared to 110ms in the cgo path)
 func execSecurityRoots() (*CertPool, error) {
+       hasPolicy, err := getCertsWithTrustPolicy()
+       if err != nil {
+               return nil, err
+       }
+       if debugExecDarwinRoots {
+               println(fmt.Sprintf("crypto/x509: %d certs have a trust policy", len(hasPolicy)))
+       }
+
        cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
        data, err := cmd.Output()
        if err != nil {
@@ -35,22 +68,49 @@ func execSecurityRoots() (*CertPool, error) {
        }
 
        var (
-               mu    sync.Mutex
-               roots = NewCertPool()
+               mu          sync.Mutex
+               roots       = NewCertPool()
+               numVerified int // number of execs of 'security verify-cert', for debug stats
        )
-       add := func(cert *Certificate) {
-               mu.Lock()
-               defer mu.Unlock()
-               roots.AddCert(cert)
-       }
+
        blockCh := make(chan *pem.Block)
        var wg sync.WaitGroup
+
+       // Using 4 goroutines to pipe into verify-cert seems to be
+       // about the best we can do. The verify-cert binary seems to
+       // just RPC to another server with coarse locking anyway, so
+       // running 16 at a time for instance doesn't help at all. Due
+       // to the "if hasPolicy" check below, though, we will rarely
+       // (or never) call verify-cert on stock macOS systems, though.
+       // The hope is that we only call verify-cert when the user has
+       // tweaked their trust policy. These 4 goroutines are only
+       // defensive in the pathological case of many trust edits.
        for i := 0; i < 4; i++ {
                wg.Add(1)
                go func() {
                        defer wg.Done()
                        for block := range blockCh {
-                               verifyCertWithSystem(block, add)
+                               cert, err := ParseCertificate(block.Bytes)
+                               if err != nil {
+                                       continue
+                               }
+                               sha1CapHex := fmt.Sprintf("%X", sha1.Sum(block.Bytes))
+
+                               valid := true
+                               verifyChecks := 0
+                               if hasPolicy[sha1CapHex] {
+                                       verifyChecks++
+                                       if !verifyCertWithSystem(block, cert) {
+                                               valid = false
+                                       }
+                               }
+
+                               mu.Lock()
+                               numVerified += verifyChecks
+                               if valid {
+                                       roots.AddCert(cert)
+                               }
+                               mu.Unlock()
                        }
                }()
        }
@@ -67,67 +127,118 @@ func execSecurityRoots() (*CertPool, error) {
        }
        close(blockCh)
        wg.Wait()
+
+       if debugExecDarwinRoots {
+               mu.Lock()
+               defer mu.Unlock()
+               println(fmt.Sprintf("crypto/x509: ran security verify-cert %d times", numVerified))
+       }
+
        return roots, nil
 }
 
-func verifyCertWithSystem(block *pem.Block, add func(*Certificate)) {
+func verifyCertWithSystem(block *pem.Block, cert *Certificate) bool {
        data := pem.EncodeToMemory(block)
-       var cmd *exec.Cmd
-       if needsTmpFiles() {
-               f, err := ioutil.TempFile("", "cert")
-               if err != nil {
-                       fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
-                       return
-               }
-               defer os.Remove(f.Name())
-               if _, err := f.Write(data); err != nil {
-                       fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
-                       return
-               }
-               if err := f.Close(); err != nil {
-                       fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
-                       return
-               }
-               cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l")
-       } else {
-               cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", "/dev/stdin", "-l")
-               cmd.Stdin = bytes.NewReader(data)
-       }
-       if cmd.Run() == nil {
-               // Non-zero exit means untrusted
-               cert, err := ParseCertificate(block.Bytes)
-               if err != nil {
-                       return
-               }
 
-               add(cert)
+       f, err := ioutil.TempFile("", "cert")
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
+               return false
+       }
+       defer os.Remove(f.Name())
+       if _, err := f.Write(data); err != nil {
+               fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
+               return false
+       }
+       if err := f.Close(); err != nil {
+               fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
+               return false
+       }
+       cmd := exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l", "-L")
+       var stderr bytes.Buffer
+       if debugExecDarwinRoots {
+               cmd.Stderr = &stderr
+       }
+       if err := cmd.Run(); err != nil {
+               if debugExecDarwinRoots {
+                       println(fmt.Sprintf("crypto/x509: verify-cert rejected %s: %q", cert.Subject.CommonName, bytes.TrimSpace(stderr.Bytes())))
+               }
+               return false
+       }
+       if debugExecDarwinRoots {
+               println(fmt.Sprintf("crypto/x509: verify-cert approved %s", cert.Subject.CommonName))
        }
+       return true
 }
 
-var versionCache struct {
-       sync.Once
-       major int
-}
+// getCertsWithTrustPolicy returns the set of certs that have a
+// possibly-altered trust policy. The keys of the map are capitalized
+// sha1 hex of the raw cert.
+// They are the certs that should be checked against `security
+// verify-cert` to see whether the user altered the default trust
+// settings. This code is only used for cgo-disabled builds.
+func getCertsWithTrustPolicy() (map[string]bool, error) {
+       set := map[string]bool{}
+       td, err := ioutil.TempDir("", "x509trustpolicy")
+       if err != nil {
+               return nil, err
+       }
+       defer os.RemoveAll(td)
+       run := func(file string, args ...string) error {
+               file = filepath.Join(td, file)
+               args = append(args, file)
+               cmd := exec.Command("/usr/bin/security", args...)
+               var stderr bytes.Buffer
+               cmd.Stderr = &stderr
+               if err := cmd.Run(); err != nil {
+                       // If there are no trust settings, the
+                       // `security trust-settings-export` command
+                       // fails with:
+                       //    exit status 1, SecTrustSettingsCreateExternalRepresentation: No Trust Settings were found.
+                       // Rather than match on English substrings that are probably
+                       // localized on macOS, just interpret any failure to mean that
+                       // there are no trust settings.
+                       if debugExecDarwinRoots {
+                               println(fmt.Sprintf("crypto/x509: exec %q: %v, %s", cmd.Args, err, stderr.Bytes()))
+                       }
+                       return nil
+               }
 
-// needsTmpFiles reports whether the OS is <= 10.11 (which requires real
-// files as arguments to the security command).
-func needsTmpFiles() bool {
-       versionCache.Do(func() {
-               release, err := syscall.Sysctl("kern.osrelease")
+               f, err := os.Open(file)
                if err != nil {
-                       return
+                       return err
                }
-               for i, c := range release {
-                       if c == '.' {
-                               release = release[:i]
+               defer f.Close()
+
+               // Gather all the runs of 40 capitalized hex characters.
+               br := bufio.NewReader(f)
+               var hexBuf bytes.Buffer
+               for {
+                       b, err := br.ReadByte()
+                       isHex := ('A' <= b && b <= 'F') || ('0' <= b && b <= '9')
+                       if isHex {
+                               hexBuf.WriteByte(b)
+                       } else {
+                               if hexBuf.Len() == 40 {
+                                       set[hexBuf.String()] = true
+                               }
+                               hexBuf.Reset()
+                       }
+                       if err == io.EOF {
                                break
                        }
+                       if err != nil {
+                               return err
+                       }
                }
-               major, err := strconv.Atoi(release)
-               if err != nil {
-                       return
-               }
-               versionCache.major = major
-       })
-       return versionCache.major <= 15
+
+               return nil
+       }
+       if err := run("user", "trust-settings-export"); err != nil {
+               return nil, fmt.Errorf("dump-trust-settings (user): %v", err)
+       }
+       if err := run("admin", "trust-settings-export", "-d"); err != nil {
+               return nil, fmt.Errorf("dump-trust-settings (admin): %v", err)
+       }
+       return set, nil
 }
index c8ca3ead70034aa89cc6ba7c23351694a9cbab81..2784ce2f0faacf55c3e1e48e2b60260049237400 100644 (file)
@@ -7,6 +7,7 @@ package x509
 import (
        "runtime"
        "testing"
+       "time"
 )
 
 func TestSystemRoots(t *testing.T) {
@@ -15,22 +16,33 @@ func TestSystemRoots(t *testing.T) {
                t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
        }
 
-       sysRoots := systemRootsPool()         // actual system roots
+       t0 := time.Now()
+       sysRoots := systemRootsPool() // actual system roots
+       sysRootsDuration := time.Since(t0)
+
+       t1 := time.Now()
        execRoots, err := execSecurityRoots() // non-cgo roots
+       execSysRootsDuration := time.Since(t1)
 
        if err != nil {
                t.Fatalf("failed to read system roots: %v", err)
        }
 
+       t.Logf("    cgo sys roots: %v", sysRootsDuration)
+       t.Logf("non-cgo sys roots: %v", execSysRootsDuration)
+
        for _, tt := range []*CertPool{sysRoots, execRoots} {
                if tt == nil {
                        t.Fatal("no system roots")
                }
-               // On Mavericks, there are 212 bundled certs; require only
-               // 150 here, since this is just a sanity check, and the
-               // exact number will vary over time.
+               // On Mavericks, there are 212 bundled certs, at least
+               // there was at one point in time on one machine.
+               // (Maybe it was a corp laptop with extra certs?)
+               // Other OS X users report
+               // 135, 142, 145...  Let's try requiring at least 100,
+               // since this is just a sanity check.
                t.Logf("got %d roots", len(tt.certs))
-               if want, have := 150, len(tt.certs); have < want {
+               if want, have := 100, len(tt.certs); have < want {
                        t.Fatalf("want at least %d system roots, have %d", want, have)
                }
        }
index ca2fba5cb421fe7b7925358fa50d15061da99cc5..a936fec7d8447dbc27669b4ff9aae4f2a32288e2 100644 (file)
@@ -226,6 +226,11 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
 }
 
 func loadSystemRoots() (*CertPool, error) {
+       // TODO: restore this functionality on Windows. We tried to do
+       // it in Go 1.8 but had to revert it. See Issue 18609.
+       // Returning (nil, nil) was the old behavior, prior to CL 30578.
+       return nil, nil
+
        const CRYPT_E_NOT_FOUND = 0x80092004
 
        store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT"))
index 0d3de30beca6311d601503fed0f559e618f11cce..29345a1755c8e1cde125946ae1cd3eb3299256e7 100644 (file)
@@ -153,7 +153,7 @@ type VerifyOptions struct {
        CurrentTime   time.Time // if zero, the current time is used
        // KeyUsage specifies which Extended Key Usage values are acceptable.
        // An empty list means ExtKeyUsageServerAuth. Key usage is considered a
-       // constraint down the chain which mirrors Windows CryptoAPI behaviour,
+       // constraint down the chain which mirrors Windows CryptoAPI behavior,
        // but not the spec. To accept any key usage, include ExtKeyUsageAny.
        KeyUsages []ExtKeyUsage
 }
@@ -262,7 +262,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
 // WARNING: this doesn't do any revocation checking.
 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
        // Platform-specific verification needs the ASN.1 contents so
-       // this makes the behaviour consistent across platforms.
+       // this makes the behavior consistent across platforms.
        if len(c.Raw) == 0 {
                return nil, errNotParsed
        }
index d9077db653260c3bed213ae9f89b2b5de1804f69..949ce0185615516f5bdbede356e5f9f5d84eb70d 100644 (file)
@@ -1850,13 +1850,20 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
                return nil, err
        }
 
+       // Force revocation times to UTC per RFC 5280.
+       revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts))
+       for i, rc := range revokedCerts {
+               rc.RevocationTime = rc.RevocationTime.UTC()
+               revokedCertsUTC[i] = rc
+       }
+
        tbsCertList := pkix.TBSCertificateList{
                Version:             1,
                Signature:           signatureAlgorithm,
                Issuer:              c.Subject.ToRDNSequence(),
                ThisUpdate:          now.UTC(),
                NextUpdate:          expiry.UTC(),
-               RevokedCertificates: revokedCerts,
+               RevokedCertificates: revokedCertsUTC,
        }
 
        // Authority Key Id
index 354545ccbcbe70974a1a8c8d1ad586e600aef6df..b085dad90f06a5f78a21e91d0f4ea5f2ef102522 100644 (file)
@@ -24,6 +24,7 @@ import (
        "net"
        "os/exec"
        "reflect"
+       "runtime"
        "strings"
        "testing"
        "time"
@@ -850,17 +851,31 @@ func TestCRLCreation(t *testing.T) {
        block, _ = pem.Decode([]byte(pemCertificate))
        cert, _ := ParseCertificate(block.Bytes)
 
-       now := time.Unix(1000, 0)
+       loc := time.FixedZone("Oz/Atlantis", int((2 * time.Hour).Seconds()))
+
+       now := time.Unix(1000, 0).In(loc)
+       nowUTC := now.UTC()
        expiry := time.Unix(10000, 0)
 
        revokedCerts := []pkix.RevokedCertificate{
                {
                        SerialNumber:   big.NewInt(1),
+                       RevocationTime: nowUTC,
+               },
+               {
+                       SerialNumber: big.NewInt(42),
+                       // RevocationTime should be converted to UTC before marshaling.
                        RevocationTime: now,
                },
+       }
+       expectedCerts := []pkix.RevokedCertificate{
+               {
+                       SerialNumber:   big.NewInt(1),
+                       RevocationTime: nowUTC,
+               },
                {
                        SerialNumber:   big.NewInt(42),
-                       RevocationTime: now,
+                       RevocationTime: nowUTC,
                },
        }
 
@@ -869,10 +884,14 @@ func TestCRLCreation(t *testing.T) {
                t.Errorf("error creating CRL: %s", err)
        }
 
-       _, err = ParseDERCRL(crlBytes)
+       parsedCRL, err := ParseDERCRL(crlBytes)
        if err != nil {
                t.Errorf("error reparsing CRL: %s", err)
        }
+       if !reflect.DeepEqual(parsedCRL.TBSCertList.RevokedCertificates, expectedCerts) {
+               t.Errorf("RevokedCertificates mismatch: got %v; want %v.",
+                       parsedCRL.TBSCertList.RevokedCertificates, expectedCerts)
+       }
 }
 
 func fromBase64(in string) []byte {
@@ -1459,6 +1478,9 @@ func TestMultipleRDN(t *testing.T) {
 }
 
 func TestSystemCertPool(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               t.Skip("not implemented on Windows; Issue 16736, 18609")
+       }
        _, err := SystemCertPool()
        if err != nil {
                t.Fatal(err)
index 7c05ce24480d9f59d10225fdaa2259f857fed466..1071446227fb4f25caf22600715e0c47fde02ce3 100644 (file)
@@ -111,25 +111,32 @@ func ctxDriverStmtQuery(ctx context.Context, si driver.Stmt, nvdargs []driver.Na
 
 var errLevelNotSupported = errors.New("sql: selected isolation level is not supported")
 
-func ctxDriverBegin(ctx context.Context, ci driver.Conn) (driver.Tx, error) {
-       if ciCtx, is := ci.(driver.ConnBeginContext); is {
-               return ciCtx.BeginContext(ctx)
+func ctxDriverBegin(ctx context.Context, opts *TxOptions, ci driver.Conn) (driver.Tx, error) {
+       if ciCtx, is := ci.(driver.ConnBeginTx); is {
+               dopts := driver.TxOptions{}
+               if opts != nil {
+                       dopts.Isolation = driver.IsolationLevel(opts.Isolation)
+                       dopts.ReadOnly = opts.ReadOnly
+               }
+               return ciCtx.BeginTx(ctx, dopts)
        }
 
        if ctx.Done() == context.Background().Done() {
                return ci.Begin()
        }
 
-       // Check the transaction level in ctx. If set and non-default
-       // then return an error here as the BeginContext driver value is not supported.
-       if level, ok := driver.IsolationFromContext(ctx); ok && level != driver.IsolationLevel(LevelDefault) {
-               return nil, errors.New("sql: driver does not support non-default isolation level")
-       }
+       if opts != nil {
+               // Check the transaction level. If the transaction level is non-default
+               // then return an error here as the BeginTx driver value is not supported.
+               if opts.Isolation != LevelDefault {
+                       return nil, errors.New("sql: driver does not support non-default isolation level")
+               }
 
-       // Check for a read-only parameter in ctx. If a read-only transaction is
-       // requested return an error as the BeginContext driver value is not supported.
-       if ro := driver.ReadOnlyFromContext(ctx); ro {
-               return nil, errors.New("sql: driver does not support read-only transactions")
+               // If a read-only transaction is requested return an error as the
+               // BeginTx driver value is not supported.
+               if opts.ReadOnly {
+                       return nil, errors.New("sql: driver does not support read-only transactions")
+               }
        }
 
        txi, err := ci.Begin()
index 2e47cd9ee73b6da1343ab57b33308068dd797304..d66196fd48174811613d330dd1ae0e44d809dfbf 100644 (file)
@@ -10,7 +10,6 @@ package driver
 
 import (
        "context"
-       "database/sql/internal"
        "errors"
        "reflect"
 )
@@ -157,7 +156,7 @@ type Conn interface {
 
        // Begin starts and returns a new transaction.
        //
-       // Deprecated: Drivers should implement ConnBeginContext instead (or additionally).
+       // Deprecated: Drivers should implement ConnBeginTx instead (or additionally).
        Begin() (Tx, error)
 }
 
@@ -169,41 +168,35 @@ type ConnPrepareContext interface {
        PrepareContext(ctx context.Context, query string) (Stmt, error)
 }
 
-// IsolationLevel is the transaction isolation level stored in Context.
+// IsolationLevel is the transaction isolation level stored in TxOptions.
 //
 // This type should be considered identical to sql.IsolationLevel along
 // with any values defined on it.
 type IsolationLevel int
 
-// IsolationFromContext extracts the isolation level from a Context.
-func IsolationFromContext(ctx context.Context) (level IsolationLevel, ok bool) {
-       level, ok = ctx.Value(internal.IsolationLevelKey{}).(IsolationLevel)
-       return level, ok
-}
-
-// ReadOnlyFromContext extracts the read-only property from a Context.
-// When readonly is true the transaction must be set to read-only
-// or return an error.
-func ReadOnlyFromContext(ctx context.Context) (readonly bool) {
-       readonly, _ = ctx.Value(internal.ReadOnlyKey{}).(bool)
-       return readonly
+// TxOptions holds the transaction options.
+//
+// This type should be considered identical to sql.TxOptions.
+type TxOptions struct {
+       Isolation IsolationLevel
+       ReadOnly  bool
 }
 
-// ConnBeginContext enhances the Conn interface with context.
-type ConnBeginContext interface {
-       // BeginContext starts and returns a new transaction.
+// ConnBeginTx enhances the Conn interface with context and TxOptions.
+type ConnBeginTx interface {
+       // BeginTx starts and returns a new transaction.
        // If the context is canceled by the user the sql package will
        // call Tx.Rollback before discarding and closing the connection.
        //
-       // This must call IsolationFromContext to determine if there is a set
-       // isolation level. If the driver does not support setting the isolation
-       // level and one is set or if there is a set isolation level
-       // but the set level is not supported, an error must be returned.
+       // This must check opts.Isolation to determine if there is a set
+       // isolation level. If the driver does not support a non-default
+       // level and one is set or if there is a non-default isolation level
+       // that is not supported, an error must be returned.
        //
-       // This must also call ReadOnlyFromContext to determine if the read-only
+       // This must also check opts.ReadOnly to determine if the read-only
        // value is true to either set the read-only transaction property if supported
        // or return an error if it is not supported.
-       BeginContext(ctx context.Context) (Tx, error)
+       BeginTx(ctx context.Context, opts TxOptions) (Tx, error)
 }
 
 // Result is the result of a query execution.
diff --git a/src/database/sql/internal/types.go b/src/database/sql/internal/types.go
deleted file mode 100644 (file)
index 1895144..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2016 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 internal
-
-// Context keys that set transaction properties for sql.BeginContext.
-type (
-       IsolationLevelKey struct{} // context value is driver.IsolationLevel
-       ReadOnlyKey       struct{} // context value is bool
-)
index 3d957e1450cf40c88a1ba4554d19cdd7c125c64c..feb91223a9e9b99f48fa65e041afd6f7d309e791 100644 (file)
@@ -8,14 +8,16 @@
 // The sql package must be used in conjunction with a database driver.
 // See https://golang.org/s/sqldrivers for a list of drivers.
 //
-// For more usage examples, see the wiki page at
+// Drivers that do not support context cancelation will not return until
+// after the query is completed.
+//
+// For usage examples, see the wiki page at
 // https://golang.org/s/sqlwiki.
 package sql
 
 import (
        "context"
        "database/sql/driver"
-       "database/sql/internal"
        "errors"
        "fmt"
        "io"
@@ -69,19 +71,26 @@ func Drivers() []string {
        return list
 }
 
-// A NamedArg used as an argument to Query or Exec
-// binds to the corresponding named parameter in the SQL statement.
+// A NamedArg is a named argument. NamedArg values may be used as
+// arguments to Query or Exec and bind to the corresponding named
+// parameter in the SQL statement.
+//
+// For a more concise way to create NamedArg values, see
+// the Named function.
 type NamedArg struct {
        _Named_Fields_Required struct{}
 
-       // Name of the parameter placeholder. If empty the ordinal position in the
-       // argument list will be used.
+       // Name is the name of the parameter placeholder.
+       //
+       // If empty, the ordinal position in the argument list will be
+       // used.
        //
        // Name must omit any symbol prefix.
        Name string
 
-       // Value of the parameter. It may be assigned the same value types as
-       // the query arguments.
+       // Value is the value of the parameter.
+       // It may be assigned the same value types as the query
+       // arguments.
        Value interface{}
 }
 
@@ -105,12 +114,10 @@ func Named(name string, value interface{}) NamedArg {
        return NamedArg{Name: name, Value: value}
 }
 
-// IsolationLevel is the transaction isolation level stored in Context.
-// The IsolationLevel is set with IsolationContext and the context
-// should be passed to BeginContext.
+// IsolationLevel is the transaction isolation level used in TxOptions.
 type IsolationLevel int
 
-// Various isolation levels that drivers may support in BeginContext.
+// Various isolation levels that drivers may support in BeginTx.
 // If a driver does not support a given isolation level an error may be returned.
 //
 // See https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels.
@@ -125,18 +132,12 @@ const (
        LevelLinearizable
 )
 
-// IsolationContext returns a new Context that carries the provided isolation level.
-// The context must contain the isolation level before beginning the transaction
-// with BeginContext.
-func IsolationContext(ctx context.Context, level IsolationLevel) context.Context {
-       return context.WithValue(ctx, internal.IsolationLevelKey{}, driver.IsolationLevel(level))
-}
-
-// ReadOnlyWithContext returns a new Context that carries the provided
-// read-only transaction property. The context must contain the read-only property
-// before beginning the transaction with BeginContext.
-func ReadOnlyContext(ctx context.Context) context.Context {
-       return context.WithValue(ctx, internal.ReadOnlyKey{}, true)
+// TxOptions holds the transaction options to be used in DB.BeginTx.
+type TxOptions struct {
+       // Isolation is the transaction isolation level.
+       // If zero, the driver or database's default level is used.
+       Isolation IsolationLevel
+       ReadOnly  bool
 }
 
 // RawBytes is a byte slice that holds a reference to memory owned by
@@ -1301,28 +1302,27 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row {
        return db.QueryRowContext(context.Background(), query, args...)
 }
 
-// BeginContext starts a transaction.
+// BeginTx starts a transaction.
 //
 // The provided context is used until the transaction is committed or rolled back.
 // If the context is canceled, the sql package will roll back
 // the transaction. Tx.Commit will return an error if the context provided to
-// BeginContext is canceled.
+// BeginTx is canceled.
 //
-// An isolation level may be set by setting the value in the context
-// before calling this. If a non-default isolation level is used
-// that the driver doesn't support an error will be returned. Different drivers
-// may have slightly different meanings for the same isolation level.
-func (db *DB) BeginContext(ctx context.Context) (*Tx, error) {
+// The provided TxOptions is optional and may be nil if defaults should be used.
+// If a non-default isolation level is used that the driver doesn't support,
+// an error will be returned.
+func (db *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
        var tx *Tx
        var err error
        for i := 0; i < maxBadConnRetries; i++ {
-               tx, err = db.begin(ctx, cachedOrNewConn)
+               tx, err = db.begin(ctx, opts, cachedOrNewConn)
                if err != driver.ErrBadConn {
                        break
                }
        }
        if err == driver.ErrBadConn {
-               return db.begin(ctx, alwaysNewConn)
+               return db.begin(ctx, opts, alwaysNewConn)
        }
        return tx, err
 }
@@ -1330,17 +1330,17 @@ func (db *DB) BeginContext(ctx context.Context) (*Tx, error) {
 // Begin starts a transaction. The default isolation level is dependent on
 // the driver.
 func (db *DB) Begin() (*Tx, error) {
-       return db.BeginContext(context.Background())
+       return db.BeginTx(context.Background(), nil)
 }
 
-func (db *DB) begin(ctx context.Context, strategy connReuseStrategy) (tx *Tx, err error) {
+func (db *DB) begin(ctx context.Context, opts *TxOptions, strategy connReuseStrategy) (tx *Tx, err error) {
        dc, err := db.conn(ctx, strategy)
        if err != nil {
                return nil, err
        }
        var txi driver.Tx
        withLock(dc, func() {
-               txi, err = ctxDriverBegin(ctx, dc.ci)
+               txi, err = ctxDriverBegin(ctx, opts, dc.ci)
        })
        if err != nil {
                db.putConn(dc, err)
@@ -1357,16 +1357,7 @@ func (db *DB) begin(ctx context.Context, strategy connReuseStrategy) (tx *Tx, er
                cancel: cancel,
                ctx:    ctx,
        }
-       go func(tx *Tx) {
-               select {
-               case <-tx.ctx.Done():
-                       if !tx.isDone() {
-                               // Discard and close the connection used to ensure the transaction
-                               // is closed and the resources are released.
-                               tx.rollback(true)
-                       }
-               }
-       }(tx)
+       go tx.awaitDone()
        return tx, nil
 }
 
@@ -1388,6 +1379,11 @@ func (db *DB) Driver() driver.Driver {
 type Tx struct {
        db *DB
 
+       // closemu prevents the transaction from closing while there
+       // is an active query. It is held for read during queries
+       // and exclusively during close.
+       closemu sync.RWMutex
+
        // dc is owned exclusively until Commit or Rollback, at which point
        // it's returned with putConn.
        dc  *driverConn
@@ -1413,6 +1409,20 @@ type Tx struct {
        ctx context.Context
 }
 
+// awaitDone blocks until the context in Tx is canceled and rolls back
+// the transaction if it's not already done.
+func (tx *Tx) awaitDone() {
+       // Wait for either the transaction to be committed or rolled
+       // back, or for the associated context to be closed.
+       <-tx.ctx.Done()
+
+       // Discard and close the connection used to ensure the
+       // transaction is closed and the resources are released.  This
+       // rollback does nothing if the transaction has already been
+       // committed or rolled back.
+       tx.rollback(true)
+}
+
 func (tx *Tx) isDone() bool {
        return atomic.LoadInt32(&tx.done) != 0
 }
@@ -1421,20 +1431,34 @@ func (tx *Tx) isDone() bool {
 // that has already been committed or rolled back.
 var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
 
+// close returns the connection to the pool and
+// must only be called by Tx.rollback or Tx.Commit.
 func (tx *Tx) close(err error) {
-       if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
-               panic("double close") // internal error
-       }
+       tx.closemu.Lock()
+       defer tx.closemu.Unlock()
+
        tx.db.putConn(tx.dc, err)
        tx.cancel()
        tx.dc = nil
        tx.txi = nil
 }
 
+// hookTxGrabConn specifies an optional hook to be called on
+// a successful call to (*Tx).grabConn. For tests.
+var hookTxGrabConn func()
+
 func (tx *Tx) grabConn(ctx context.Context) (*driverConn, error) {
+       select {
+       default:
+       case <-ctx.Done():
+               return nil, ctx.Err()
+       }
        if tx.isDone() {
                return nil, ErrTxDone
        }
+       if hookTxGrabConn != nil { // test hook
+               hookTxGrabConn()
+       }
        return tx.dc, nil
 }
 
@@ -1449,7 +1473,7 @@ func (tx *Tx) closePrepared() {
 
 // Commit commits the transaction.
 func (tx *Tx) Commit() error {
-       if tx.isDone() {
+       if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
                return ErrTxDone
        }
        select {
@@ -1471,7 +1495,7 @@ func (tx *Tx) Commit() error {
 // rollback aborts the transaction and optionally forces the pool to discard
 // the connection.
 func (tx *Tx) rollback(discardConn bool) error {
-       if tx.isDone() {
+       if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
                return ErrTxDone
        }
        var err error
@@ -1504,6 +1528,9 @@ func (tx *Tx) Rollback() error {
 // for the execution of the returned statement. The returned statement
 // will run in the transaction context.
 func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
+       tx.closemu.RLock()
+       defer tx.closemu.RUnlock()
+
        // TODO(bradfitz): We could be more efficient here and either
        // provide a method to take an existing Stmt (created on
        // perhaps a different Conn), and re-create it on this Conn if
@@ -1568,6 +1595,9 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
 // The returned statement operates within the transaction and will be closed
 // when the transaction has been committed or rolled back.
 func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt {
+       tx.closemu.RLock()
+       defer tx.closemu.RUnlock()
+
        // TODO(bradfitz): optimize this. Currently this re-prepares
        // each time. This is fine for now to illustrate the API but
        // we should really cache already-prepared statements
@@ -1619,6 +1649,9 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
 // ExecContext executes a query that doesn't return rows.
 // For example: an INSERT and UPDATE.
 func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
+       tx.closemu.RLock()
+       defer tx.closemu.RUnlock()
+
        dc, err := tx.grabConn(ctx)
        if err != nil {
                return nil, err
@@ -1662,6 +1695,9 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
 
 // QueryContext executes a query that returns rows, typically a SELECT.
 func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+       tx.closemu.RLock()
+       defer tx.closemu.RUnlock()
+
        dc, err := tx.grabConn(ctx)
        if err != nil {
                return nil, err
@@ -2039,25 +2075,21 @@ type Rows struct {
        // closed value is 1 when the Rows is closed.
        // Use atomic operations on value when checking value.
        closed    int32
-       ctxClose  chan struct{} // closed when Rows is closed, may be null.
+       cancel    func() // called when Rows is closed, may be nil.
        lastcols  []driver.Value
        lasterr   error       // non-nil only if closed is true
        closeStmt *driverStmt // if non-nil, statement to Close on close
 }
 
 func (rs *Rows) initContextClose(ctx context.Context) {
-       if ctx.Done() == context.Background().Done() {
-               return
-       }
+       ctx, rs.cancel = context.WithCancel(ctx)
+       go rs.awaitDone(ctx)
+}
 
-       rs.ctxClose = make(chan struct{})
-       go func() {
-               select {
-               case <-ctx.Done():
-                       rs.Close()
-               case <-rs.ctxClose:
-               }
-       }()
+// awaitDone blocks until the rows are closed or the context canceled.
+func (rs *Rows) awaitDone(ctx context.Context) {
+       <-ctx.Done()
+       rs.Close()
 }
 
 // Next prepares the next result row for reading with the Scan method. It
@@ -2087,7 +2119,7 @@ func (rs *Rows) Next() bool {
                }
                // The driver is at the end of the current result set.
                // Test to see if there is another result set after the current one.
-               // Only close Rows if there is no futher result sets to read.
+               // Only close Rows if there is no further result sets to read.
                if !nextResultSet.HasNextResultSet() {
                        rs.Close()
                }
@@ -2315,7 +2347,9 @@ func (rs *Rows) Scan(dest ...interface{}) error {
        return nil
 }
 
-var rowsCloseHook func(*Rows, *error)
+// rowsCloseHook returns a function so tests may install the
+// hook throug a test only mutex.
+var rowsCloseHook = func() func(*Rows, *error) { return nil }
 
 func (rs *Rows) isClosed() bool {
        return atomic.LoadInt32(&rs.closed) != 0
@@ -2329,13 +2363,15 @@ func (rs *Rows) Close() error {
        if !atomic.CompareAndSwapInt32(&rs.closed, 0, 1) {
                return nil
        }
-       if rs.ctxClose != nil {
-               close(rs.ctxClose)
-       }
+
        err := rs.rowsi.Close()
-       if fn := rowsCloseHook; fn != nil {
+       if fn := rowsCloseHook(); fn != nil {
                fn(rs, &err)
        }
+       if rs.cancel != nil {
+               rs.cancel()
+       }
+
        if rs.closeStmt != nil {
                rs.closeStmt.Close()
        }
index 1ec62178587d81ea445a3b92a24be620b38fb968..898df3b455b22cac915bdb19510cc9ba22f83cbe 100644 (file)
@@ -14,6 +14,7 @@ import (
        "runtime"
        "strings"
        "sync"
+       "sync/atomic"
        "testing"
        "time"
 )
@@ -326,9 +327,7 @@ func TestQueryContext(t *testing.T) {
 
        // And verify that the final rows.Next() call, which hit EOF,
        // also closed the rows connection.
-       if n := db.numFreeConns(); n != 1 {
-               t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
-       }
+       waitForFree(t, db, 5*time.Second, 1)
        if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
                t.Errorf("executed %d Prepare statements; want 1", prepares)
        }
@@ -345,6 +344,18 @@ func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
        return false
 }
 
+// waitForFree checks db.numFreeConns until either it equals want or
+// the maxWait time elapses.
+func waitForFree(t *testing.T, db *DB, maxWait time.Duration, want int) {
+       var numFree int
+       if !waitCondition(maxWait, 5*time.Millisecond, func() bool {
+               numFree = db.numFreeConns()
+               return numFree == want
+       }) {
+               t.Fatalf("free conns after hitting EOF = %d; want %d", numFree, want)
+       }
+}
+
 func TestQueryContextWait(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
@@ -361,9 +372,7 @@ func TestQueryContextWait(t *testing.T) {
        }
 
        // Verify closed rows connection after error condition.
-       if n := db.numFreeConns(); n != 1 {
-               t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
-       }
+       waitForFree(t, db, 5*time.Second, 1)
        if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
                t.Errorf("executed %d Prepare statements; want 1", prepares)
        }
@@ -375,7 +384,7 @@ func TestTxContextWait(t *testing.T) {
 
        ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*15)
 
-       tx, err := db.BeginContext(ctx)
+       tx, err := db.BeginTx(ctx, nil)
        if err != nil {
                t.Fatal(err)
        }
@@ -388,13 +397,7 @@ func TestTxContextWait(t *testing.T) {
                t.Fatalf("expected QueryContext to error with context deadline exceeded but returned %v", err)
        }
 
-       var numFree int
-       if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
-               numFree = db.numFreeConns()
-               return numFree == 0
-       }) {
-               t.Fatalf("free conns after hitting EOF = %d; want 0", numFree)
-       }
+       waitForFree(t, db, 5*time.Second, 0)
 
        // Ensure the dropped connection allows more connections to be made.
        // Checked on DB Close.
@@ -471,9 +474,7 @@ func TestMultiResultSetQuery(t *testing.T) {
 
        // And verify that the final rows.Next() call, which hit EOF,
        // also closed the rows connection.
-       if n := db.numFreeConns(); n != 1 {
-               t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
-       }
+       waitForFree(t, db, 5*time.Second, 1)
        if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
                t.Errorf("executed %d Prepare statements; want 1", prepares)
        }
@@ -1135,6 +1136,24 @@ func TestQueryRowClosingStmt(t *testing.T) {
        }
 }
 
+var atomicRowsCloseHook atomic.Value // of func(*Rows, *error)
+
+func init() {
+       rowsCloseHook = func() func(*Rows, *error) {
+               fn, _ := atomicRowsCloseHook.Load().(func(*Rows, *error))
+               return fn
+       }
+}
+
+func setRowsCloseHook(fn func(*Rows, *error)) {
+       if fn == nil {
+               // Can't change an atomic.Value back to nil, so set it to this
+               // no-op func instead.
+               fn = func(*Rows, *error) {}
+       }
+       atomicRowsCloseHook.Store(fn)
+}
+
 // Test issue 6651
 func TestIssue6651(t *testing.T) {
        db := newTestDB(t, "people")
@@ -1147,6 +1166,7 @@ func TestIssue6651(t *testing.T) {
                return fmt.Errorf(want)
        }
        defer func() { rowsCursorNextHook = nil }()
+
        err := db.QueryRow("SELECT|people|name|").Scan(&v)
        if err == nil || err.Error() != want {
                t.Errorf("error = %q; want %q", err, want)
@@ -1154,10 +1174,10 @@ func TestIssue6651(t *testing.T) {
        rowsCursorNextHook = nil
 
        want = "error in rows.Close"
-       rowsCloseHook = func(rows *Rows, err *error) {
+       setRowsCloseHook(func(rows *Rows, err *error) {
                *err = fmt.Errorf(want)
-       }
-       defer func() { rowsCloseHook = nil }()
+       })
+       defer setRowsCloseHook(nil)
        err = db.QueryRow("SELECT|people|name|").Scan(&v)
        if err == nil || err.Error() != want {
                t.Errorf("error = %q; want %q", err, want)
@@ -1830,7 +1850,9 @@ func TestStmtCloseDeps(t *testing.T) {
                db.dumpDeps(t)
        }
 
-       if len(stmt.css) > nquery {
+       if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+               return len(stmt.css) <= nquery
+       }) {
                t.Errorf("len(stmt.css) = %d; want <= %d", len(stmt.css), nquery)
        }
 
@@ -2576,10 +2598,10 @@ func TestIssue6081(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       rowsCloseHook = func(rows *Rows, err *error) {
+       setRowsCloseHook(func(rows *Rows, err *error) {
                *err = driver.ErrBadConn
-       }
-       defer func() { rowsCloseHook = nil }()
+       })
+       defer setRowsCloseHook(nil)
        for i := 0; i < 10; i++ {
                rows, err := stmt.Query()
                if err != nil {
@@ -2607,6 +2629,107 @@ func TestIssue6081(t *testing.T) {
        }
 }
 
+// TestIssue18429 attempts to stress rolling back the transaction from a
+// context cancel while simultaneously calling Tx.Rollback. Rolling back from a
+// context happens concurrently so tx.rollback and tx.Commit must guard against
+// double entry.
+//
+// In the test, a context is canceled while the query is in process so
+// the internal rollback will run concurrently with the explicitly called
+// Tx.Rollback.
+func TestIssue18429(t *testing.T) {
+       db := newTestDB(t, "people")
+       defer closeDB(t, db)
+
+       ctx := context.Background()
+       sem := make(chan bool, 20)
+       var wg sync.WaitGroup
+
+       const milliWait = 30
+
+       for i := 0; i < 100; i++ {
+               sem <- true
+               wg.Add(1)
+               go func() {
+                       defer func() {
+                               <-sem
+                               wg.Done()
+                       }()
+                       qwait := (time.Duration(rand.Intn(milliWait)) * time.Millisecond).String()
+
+                       ctx, cancel := context.WithTimeout(ctx, time.Duration(rand.Intn(milliWait))*time.Millisecond)
+                       defer cancel()
+
+                       tx, err := db.BeginTx(ctx, nil)
+                       if err != nil {
+                               return
+                       }
+                       // This is expected to give a cancel error many, but not all the time.
+                       // 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 {
+                               rows.Close()
+                       }
+                       // This call will race with the context cancel rollback to complete
+                       // if the rollback itself isn't guarded.
+                       tx.Rollback()
+               }()
+       }
+       wg.Wait()
+       time.Sleep(milliWait * 3 * time.Millisecond)
+}
+
+// TestIssue18719 closes the context right before use. The sql.driverConn
+// will nil out the ci on close in a lock, but if another process uses it right after
+// it will panic with on the nil ref.
+//
+// See https://golang.org/cl/35550 .
+func TestIssue18719(t *testing.T) {
+       db := newTestDB(t, "people")
+       defer closeDB(t, db)
+
+       ctx, cancel := context.WithCancel(context.Background())
+       defer cancel()
+
+       tx, err := db.BeginTx(ctx, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       hookTxGrabConn = func() {
+               cancel()
+
+               // Wait for the context to cancel and tx to rollback.
+               for tx.isDone() == false {
+                       time.Sleep(time.Millisecond * 3)
+               }
+       }
+       defer func() { hookTxGrabConn = nil }()
+
+       // This call will grab the connection and cancel the context
+       // after it has done so. Code after must deal with the canceled state.
+       rows, err := tx.QueryContext(ctx, "SELECT|people|name|")
+       if err != nil {
+               rows.Close()
+               t.Fatalf("expected error %v but got %v", nil, err)
+       }
+
+       // Rows may be ignored because it will be closed when the context is canceled.
+
+       // Do not explicitly rollback. The rollback will happen from the
+       // canceled context.
+
+       // Wait for connections to return to pool.
+       var numOpen int
+       if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+               numOpen = db.numOpenConns()
+               return numOpen == 0
+       }) {
+               t.Fatalf("open conns after hitting EOF = %d; want 0", numOpen)
+       }
+}
+
 func TestConcurrency(t *testing.T) {
        doConcurrentTest(t, new(concurrentDBQueryTest))
        doConcurrentTest(t, new(concurrentDBExecTest))
index 76d0b0c825f76b732eb92ffded8b6100e4c458f5..225fd0849c6f28f59b220e2e41c79c5775f71320 100644 (file)
@@ -535,7 +535,7 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
 
        // If no default value is given then the zero value for the type is
        // assumed to be the default value. This isn't obviously the correct
-       // behaviour, but it's what Go has traditionally done.
+       // behavior, but it's what Go has traditionally done.
        if params.optional && params.defaultValue == nil {
                if reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
                        return bytesEncoder(nil), nil
index 6f8c1550a09153e8f46749f5288541d7b2e55395..b7089be1a1b1adc9ce97f69be39650a7c5439953 100644 (file)
@@ -1561,18 +1561,23 @@ func TestWidthAndPrecision(t *testing.T) {
        }
 }
 
-// Panic is a type that panics in String.
-type Panic struct {
+// PanicS is a type that panics in String.
+type PanicS struct {
        message interface{}
 }
 
 // Value receiver.
-func (p Panic) GoString() string {
+func (p PanicS) String() string {
        panic(p.message)
 }
 
+// PanicGo is a type that panics in GoString.
+type PanicGo struct {
+       message interface{}
+}
+
 // Value receiver.
-func (p PanicString() string {
+func (p PanicGo) GoString() string {
        panic(p.message)
 }
 
@@ -1592,13 +1597,15 @@ var panictests = []struct {
        out string
 }{
        // String
-       {"%s", (*Panic)(nil), "<nil>"}, // nil pointer special case
-       {"%s", Panic{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
-       {"%s", Panic{3}, "%!s(PANIC=3)"},
+       {"%s", (*PanicS)(nil), "<nil>"}, // nil pointer special case
+       {"%s", PanicS{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
+       {"%s", PanicS{3}, "%!s(PANIC=3)"},
        // GoString
-       {"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case
-       {"%#v", Panic{io.ErrUnexpectedEOF}, "%!v(PANIC=unexpected EOF)"},
-       {"%#v", Panic{3}, "%!v(PANIC=3)"},
+       {"%#v", (*PanicGo)(nil), "<nil>"}, // nil pointer special case
+       {"%#v", PanicGo{io.ErrUnexpectedEOF}, "%!v(PANIC=unexpected EOF)"},
+       {"%#v", PanicGo{3}, "%!v(PANIC=3)"},
+       // Issue 18282. catchPanic should not clear fmtFlags permanently.
+       {"%#v", []interface{}{PanicGo{3}, PanicGo{3}}, "[]interface {}{%!v(PANIC=3), %!v(PANIC=3)}"},
        // Format
        {"%s", (*PanicF)(nil), "<nil>"}, // nil pointer special case
        {"%s", PanicF{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
index 75301a238e29c526f742f2f8e14aaf9ad1bb38e3..a7ef2e5ac210728da99aa51872744f81979d85cb 100644 (file)
@@ -535,7 +535,11 @@ func (p *pp) catchPanic(arg interface{}, verb rune) {
                        // Nested panics; the recursion in printArg cannot succeed.
                        panic(err)
                }
-               p.fmt.clearflags() // We are done, and for this output we want default behavior.
+
+               oldFlags := p.fmt.fmtFlags
+               // For this output we want default behavior.
+               p.fmt.clearflags()
+
                p.buf.WriteString(percentBangString)
                p.buf.WriteRune(verb)
                p.buf.WriteString(panicString)
@@ -543,6 +547,8 @@ func (p *pp) catchPanic(arg interface{}, verb rune) {
                p.printArg(err, 'v')
                p.panicking = false
                p.buf.WriteByte(')')
+
+               p.fmt.fmtFlags = oldFlags
        }
 }
 
@@ -813,16 +819,15 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) {
                        if f.Kind() == reflect.Slice && f.IsNil() {
                                p.buf.WriteString(nilParenString)
                                return
-                       } else {
-                               p.buf.WriteByte('{')
-                               for i := 0; i < f.Len(); i++ {
-                                       if i > 0 {
-                                               p.buf.WriteString(commaSpaceString)
-                                       }
-                                       p.printValue(f.Index(i), verb, depth+1)
+                       }
+                       p.buf.WriteByte('{')
+                       for i := 0; i < f.Len(); i++ {
+                               if i > 0 {
+                                       p.buf.WriteString(commaSpaceString)
                                }
-                               p.buf.WriteByte('}')
+                               p.printValue(f.Index(i), verb, depth+1)
                        }
+                       p.buf.WriteByte('}')
                } else {
                        p.buf.WriteByte('[')
                        for i := 0; i < f.Len(); i++ {
index a197b5a5bfcdb9e253a9b906b9370f44acbe2cc5..2ecc48b741fb174e941d46a9159db35b9cfdb5ef 100644 (file)
@@ -848,6 +848,7 @@ type (
        TypeSpec struct {
                Doc     *CommentGroup // associated documentation; or nil
                Name    *Ident        // type name
+               Assign  token.Pos     // position of '=', if any
                Type    Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
                Comment *CommentGroup // line comments; or nil
        }
index 1ce5e2e84b5da1a7c4f9ee74666783c8a0add675..a400c7152a668a3e28e89ef9f18ff90d5357269a 100644 (file)
@@ -70,10 +70,8 @@ func (s *Scope) String() string {
 // The Data fields contains object-specific data:
 //
 //     Kind    Data type         Data value
-//     Pkg     *types.Package    package scope
+//     Pkg     *Scope            package scope
 //     Con     int               iota for the respective declaration
-//     Con     != nil            constant value
-//     Typ     *Scope            (used as method scope during type checking - transient)
 //
 type Object struct {
        Kind ObjKind
index f6aabcb3af7bf121f5da7531765d4df63a954bd3..31456ea34389b9fbe35da0d6780d1468f23237b4 100644 (file)
@@ -76,8 +76,9 @@ type Context struct {
        // If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
        IsDir func(path string) bool
 
-       // HasSubdir reports whether dir is a subdirectory of
-       // (perhaps multiple levels below) root.
+       // HasSubdir reports whether dir is lexically a subdirectory of
+       // root, perhaps multiple levels below. It does not try to check
+       // whether dir exists.
        // If so, HasSubdir sets rel to a slash-separated path that
        // can be joined to root to produce a path equivalent to dir.
        // If HasSubdir is nil, Import uses an implementation built on
@@ -289,7 +290,8 @@ func defaultContext() Context {
        // in all releases >= Go 1.x. Code that requires Go 1.x or later should
        // say "+build go1.x", and code that should only be built before Go 1.x
        // (perhaps it is the stub to use in that case) should say "+build !go1.x".
-       c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8"}
+       // NOTE: If you add to this list, also update the doc comment in doc.go.
+       c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8", "go1.9"}
 
        env := os.Getenv("CGO_ENABLED")
        if env == "" {
@@ -438,16 +440,11 @@ func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
 // containing no buildable Go source files. (It may still contain
 // test files, files hidden by build tags, and so on.)
 type NoGoError struct {
-       Dir     string
-       Ignored bool // whether any Go files were ignored due to build tags
+       Dir string
 }
 
 func (e *NoGoError) Error() string {
-       msg := "no buildable Go source files in " + e.Dir
-       if e.Ignored {
-               msg += " (.go files ignored due to build tags)"
-       }
-       return msg
+       return "no buildable Go source files in " + e.Dir
 }
 
 // MultiplePackageError describes a directory containing
@@ -879,7 +876,7 @@ Found:
                return p, badGoError
        }
        if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
-               return p, &NoGoError{Dir: p.Dir, Ignored: len(p.IgnoredGoFiles) > 0}
+               return p, &NoGoError{p.Dir}
        }
 
        for tag := range allTags {
index 8ca8e5e04d41565f8df28cc173db4612f8a6c7a8..a9972416ef2feb264121704b38e43e5c349d8136 100644 (file)
@@ -93,17 +93,6 @@ func TestEmptyFolderImport(t *testing.T) {
        }
 }
 
-func TestIgnoredGoFilesImport(t *testing.T) {
-       _, err := Import(".", "testdata/ignored", 0)
-       e, ok := err.(*NoGoError)
-       if !ok {
-               t.Fatal(`Import("testdata/ignored") did not return NoGoError.`)
-       }
-       if !e.Ignored {
-               t.Fatal(`Import("testdata/ignored") should have ignored Go files.`)
-       }
-}
-
 func TestMultiplePackageImport(t *testing.T) {
        _, err := Import(".", "testdata/multi", 0)
        mpe, ok := err.(*MultiplePackageError)
index e6f228852b98e8827d525b9963a82cb80e440630..147eaf6aba3658e58f4b21204a764848e632917c 100644 (file)
@@ -179,7 +179,7 @@ var pkgDeps = map[string][]string{
        "runtime/trace":                     {"L0"},
        "text/tabwriter":                    {"L2"},
 
-       "testing":          {"L2", "context", "flag", "fmt", "internal/race", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
+       "testing":          {"L2", "flag", "fmt", "internal/race", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
        "testing/iotest":   {"L2", "log"},
        "testing/quick":    {"L2", "flag", "fmt", "reflect"},
        "internal/testenv": {"L2", "OS", "flag", "testing", "syscall"},
index 979d0477dfbfd4df9a26a6cf1573ca98791a0c8d..422e1a5ffd20023df05923e1b03ec2d1add2ae5c 100644 (file)
 //     - "go1.6", from Go version 1.6 onward
 //     - "go1.7", from Go version 1.7 onward
 //     - "go1.8", from Go version 1.8 onward
+//     - "go1.9", from Go version 1.9 onward
 //     - any additional words listed in ctxt.BuildTags
 //
 // If a file's name, after stripping the extension and a possible _test suffix,
diff --git a/src/go/build/testdata/ignored/ignored.go b/src/go/build/testdata/ignored/ignored.go
deleted file mode 100644 (file)
index 48a2ae8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-// +build alwaysignore
-
-package ignored
index ad8ba5378f3f13f7db193b5416bebb4439d0c18c..82e63100d4764d68516070e2e0e7fec2ac314011 100644 (file)
@@ -25,7 +25,7 @@ var files = flag.String("files", "", "consider only Go test files matching this
 
 const dataDir = "testdata"
 
-var templateTxt = readTemplate("template.txt")
+var templateTxt *template.Template
 
 func readTemplate(filename string) *template.Template {
        t := template.New(filename)
@@ -96,6 +96,9 @@ func test(t *testing.T, mode Mode) {
        if err != nil {
                t.Fatal(err)
        }
+       if templateTxt == nil {
+               templateTxt = readTemplate("template.txt")
+       }
 
        // test packages
        for _, pkg := range pkgs {
index 58abbba94ef15edcf2720c8ca43a3ae65a6e1df7..4fca828bf607344121016b57f19e591d2d20487a 100644 (file)
@@ -96,8 +96,12 @@ var importerTests = [...]importerTest{
        {pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1 + -1i)"},
        {pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1 + 1i)"},
        {pkgpath: "conversions", name: "Bits", want: "const Bits Units", wantval: `"bits"`},
-       // TODO: enable this entry once bug has been tracked down
-       //{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
+       {pkgpath: "time", name: "Duration", want: "type Duration int64"},
+       {pkgpath: "time", name: "Nanosecond", want: "const Nanosecond Duration", wantval: "1"},
+       {pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"},
+       {pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"},
+       {pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
+       {pkgpath: "alias", name: "IntAlias2", want: "type IntAlias2 = Int"},
 }
 
 func TestGoxImporter(t *testing.T) {
index 7312cb487921a4ea83ce9f4245fef59930583457..0d788653e37a31f4b1a44d97c021d19ff2fa78e4 100644 (file)
@@ -370,27 +370,41 @@ func (p *parser) parseConst(pkg *types.Package) *types.Const {
        return types.NewConst(token.NoPos, pkg, name, typ, val)
 }
 
-// TypeName = ExportedName .
-func (p *parser) parseTypeName() *types.TypeName {
+// NamedType = TypeName [ "=" ] Type { Method } .
+// TypeName  = ExportedName .
+// Method    = "func" "(" Param ")" Name ParamList ResultList ";" .
+func (p *parser) parseNamedType(n int) types.Type {
        pkg, name := p.parseExportedName()
        scope := pkg.Scope()
-       if obj := scope.Lookup(name); obj != nil {
-               return obj.(*types.TypeName)
+
+       if p.tok == '=' {
+               // type alias
+               p.next()
+               typ := p.parseType(pkg)
+               if obj := scope.Lookup(name); obj != nil {
+                       typ = obj.Type() // use previously imported type
+                       if typ == nil {
+                               p.errorf("%v (type alias) used in cycle", obj)
+                       }
+               } else {
+                       obj = types.NewTypeName(token.NoPos, pkg, name, typ)
+                       scope.Insert(obj)
+               }
+               p.typeMap[n] = typ
+               return typ
        }
-       obj := types.NewTypeName(token.NoPos, pkg, name, nil)
-       // a named type may be referred to before the underlying type
-       // is known - set it up
-       types.NewNamed(obj, nil, nil)
-       scope.Insert(obj)
-       return obj
-}
 
-// NamedType = TypeName Type { Method } .
-// Method    = "func" "(" Param ")" Name ParamList ResultList ";" .
-func (p *parser) parseNamedType(n int) types.Type {
-       obj := p.parseTypeName()
+       // named type
+       obj := scope.Lookup(name)
+       if obj == nil {
+               // a named type may be referred to before the underlying type
+               // is known - set it up
+               tname := types.NewTypeName(token.NoPos, pkg, name, nil)
+               types.NewNamed(tname, nil, nil)
+               scope.Insert(tname)
+               obj = tname
+       }
 
-       pkg := obj.Pkg()
        typ := obj.Type()
        p.typeMap[n] = typ
 
@@ -409,8 +423,8 @@ func (p *parser) parseNamedType(n int) types.Type {
                nt.SetUnderlying(underlying.Underlying())
        }
 
+       // collect associated methods
        for p.tok == scanner.Ident {
-               // collect associated methods
                p.expectKeyword("func")
                p.expect('(')
                receiver, _ := p.parseParam(pkg)
@@ -711,7 +725,10 @@ func (p *parser) parseType(pkg *types.Package) (t types.Type) {
 func (p *parser) parsePackageInit() PackageInit {
        name := p.parseUnquotedString()
        initfunc := p.parseUnquotedString()
-       priority := int(p.parseInt())
+       priority := -1
+       if p.version == "v1" {
+               priority = int(p.parseInt())
+       }
        return PackageInit{Name: name, InitFunc: initfunc, Priority: priority}
 }
 
@@ -766,6 +783,15 @@ func (p *parser) parseInitDataDirective() {
                }
                p.expect(';')
 
+       case "init_graph":
+               p.next()
+               // The graph data is thrown away for now.
+               for p.tok != ';' && p.tok != scanner.EOF {
+                       p.parseInt()
+                       p.parseInt()
+               }
+               p.expect(';')
+
        case "checksum":
                // Don't let the scanner try to parse the checksum as a number.
                defer func(mode uint) {
@@ -797,7 +823,7 @@ func (p *parser) parseDirective() {
        }
 
        switch p.lit {
-       case "v1", "v2", "priority", "init", "checksum":
+       case "v1", "v2", "priority", "init", "init_graph", "checksum":
                p.parseInitDataDirective()
 
        case "package":
diff --git a/src/go/internal/gccgoimporter/testdata/alias.gox b/src/go/internal/gccgoimporter/testdata/alias.gox
new file mode 100644 (file)
index 0000000..ced7d84
--- /dev/null
@@ -0,0 +1,4 @@
+v1;
+package alias;
+pkgpath alias;
+type <type 115 "I1" <type 116 interface { M1 (? <type 117 "IntAlias2" = <type 118 "IntAlias" = <type 119 "Int" <type -11>>>>) < type 114>; M2 () <type 1>; }>>;
diff --git a/src/go/internal/gccgoimporter/testdata/time.gox b/src/go/internal/gccgoimporter/testdata/time.gox
new file mode 100644 (file)
index 0000000..80c2dbc
Binary files /dev/null and b/src/go/internal/gccgoimporter/testdata/time.gox differ
diff --git a/src/go/internal/gccgoimporter/testdata/unicode.gox b/src/go/internal/gccgoimporter/testdata/unicode.gox
new file mode 100644 (file)
index 0000000..e70e539
Binary files /dev/null and b/src/go/internal/gccgoimporter/testdata/unicode.gox differ
index a8f349052ac1e38ce35c729b95559794c8c091f2..5badd337d9fc5874ed8b15aca15d381aaaf2a4c0 100644 (file)
@@ -98,10 +98,10 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 
        // read version specific flags - extend as necessary
        switch p.version {
-       // case 4:
+       // case 5:
        //      ...
        //      fallthrough
-       case 3, 2, 1:
+       case 4, 3, 2, 1:
                p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
                p.trackAllTypes = p.int() != 0
                p.posInfoFormat = p.int() != 0
@@ -208,7 +208,6 @@ func (p *importer) pkg() *types.Package {
 }
 
 // objTag returns the tag value for each object kind.
-// obj must not be a *types.Alias.
 func objTag(obj types.Object) int {
        switch obj.(type) {
        case *types.Const:
@@ -219,7 +218,6 @@ func objTag(obj types.Object) int {
                return varTag
        case *types.Func:
                return funcTag
-       // Aliases are not exported multiple times, thus we should not see them here.
        default:
                errorf("unexpected object: %v (%T)", obj, obj) // panics
                panic("unreachable")
@@ -237,14 +235,14 @@ func (p *importer) declare(obj types.Object) {
        pkg := obj.Pkg()
        if alt := pkg.Scope().Insert(obj); alt != nil {
                // This can only trigger if we import a (non-type) object a second time.
-               // Excluding aliases, this cannot happen because 1) we only import a package
+               // Excluding type aliases, this cannot happen because 1) we only import a package
                // once; and b) we ignore compiler-specific export data which may contain
                // functions whose inlined function bodies refer to other functions that
                // were already imported.
-               // However, aliases require reexporting the original object, so we need
+               // However, type aliases require reexporting the original type, so we need
                // to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
                // method importer.obj, switch case importing functions).
-               // Note that the original itself cannot be an alias.
+               // TODO(gri) review/update this comment once the gc compiler handles type aliases.
                if !sameObj(obj, alt) {
                        errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
                }
@@ -260,6 +258,13 @@ func (p *importer) obj(tag int) {
                val := p.value()
                p.declare(types.NewConst(pos, pkg, name, typ, val))
 
+       case aliasTag:
+               // TODO(gri) verify type alias hookup is correct
+               pos := p.pos()
+               pkg, name := p.qualifiedName()
+               typ := p.typ(nil)
+               p.declare(types.NewTypeName(pos, pkg, name, typ))
+
        case typeTag:
                p.typ(nil)
 
@@ -277,19 +282,6 @@ func (p *importer) obj(tag int) {
                sig := types.NewSignature(nil, params, result, isddd)
                p.declare(types.NewFunc(pos, pkg, name, sig))
 
-       case aliasTag:
-               pos := p.pos()
-               name := p.string()
-               var orig types.Object
-               if pkg, name := p.qualifiedName(); pkg != nil {
-                       orig = pkg.Scope().Lookup(name)
-               }
-               // Alias-related code. Keep for now.
-               _ = pos
-               _ = name
-               _ = orig
-               // p.declare(types.NewAlias(pos, p.pkgList[0], name, orig))
-
        default:
                errorf("unexpected object tag %d", tag)
        }
@@ -349,9 +341,7 @@ var (
 
 func (p *importer) qualifiedName() (pkg *types.Package, name string) {
        name = p.string()
-       if name != "" {
-               pkg = p.pkg()
-       }
+       pkg = p.pkg()
        return
 }
 
@@ -556,17 +546,17 @@ func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags [
                fields = make([]*types.Var, n)
                tags = make([]string, n)
                for i := range fields {
-                       fields[i] = p.field(parent)
-                       tags[i] = p.string()
+                       fields[i], tags[i] = p.field(parent)
                }
        }
        return
 }
 
-func (p *importer) field(parent *types.Package) *types.Var {
+func (p *importer) field(parent *types.Package) (*types.Var, string) {
        pos := p.pos()
-       pkg, name := p.fieldName(parent)
+       pkg, name, alias := p.fieldName(parent)
        typ := p.typ(parent)
+       tag := p.string()
 
        anonymous := false
        if name == "" {
@@ -578,12 +568,15 @@ func (p *importer) field(parent *types.Package) *types.Var {
                case *types.Named:
                        name = typ.Obj().Name()
                default:
-                       errorf("anonymous field expected")
+                       errorf("named base type expected")
                }
                anonymous = true
+       } else if alias {
+               // anonymous field: we have an explicit name because it's an alias
+               anonymous = true
        }
 
-       return types.NewField(pos, pkg, name, typ, anonymous)
+       return types.NewField(pos, pkg, name, typ, anonymous), tag
 }
 
 func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
@@ -598,31 +591,42 @@ func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
 
 func (p *importer) method(parent *types.Package) *types.Func {
        pos := p.pos()
-       pkg, name := p.fieldName(parent)
+       pkg, name, _ := p.fieldName(parent)
        params, isddd := p.paramList()
        result, _ := p.paramList()
        sig := types.NewSignature(nil, params, result, isddd)
        return types.NewFunc(pos, pkg, name, sig)
 }
 
-func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
-       name := p.string()
-       pkg := parent
+func (p *importer) fieldName(parent *types.Package) (pkg *types.Package, name string, alias bool) {
+       name = p.string()
+       pkg = parent
        if pkg == nil {
                // use the imported package instead
                pkg = p.pkgList[0]
        }
        if p.version == 0 && name == "_" {
                // version 0 didn't export a package for _ fields
-               return pkg, name
-       }
-       if name != "" && !exported(name) {
-               if name == "?" {
-                       name = ""
-               }
+               return
+       }
+       switch name {
+       case "":
+               // 1) field name matches base type name and is exported: nothing to do
+       case "?":
+               // 2) field name matches base type name and is not exported: need package
+               name = ""
                pkg = p.pkg()
+       case "@":
+               // 3) field name doesn't match type name (alias)
+               name = p.string()
+               alias = true
+               fallthrough
+       default:
+               if !exported(name) {
+                       pkg = p.pkg()
+               }
        }
-       return pkg, name
+       return
 }
 
 func (p *importer) paramList() (*types.Tuple, bool) {
@@ -893,7 +897,7 @@ const (
        nilTag     // only used by gc (appears in exported inlined function bodies)
        unknownTag // not used by gc (only appears in packages with errors)
 
-       // Aliases
+       // Type aliases
        aliasTag
 )
 
@@ -917,7 +921,7 @@ var predeclared = []types.Type{
        types.Typ[types.Complex128],
        types.Typ[types.String],
 
-       // aliases
+       // basic type aliases
        types.Universe.Lookup("byte").Type(),
        types.Universe.Lookup("rune").Type(),
 
index bff79cab4621abe6fe508ffe329266f6e5d311d8..724d8658a7dcb0d82783dd97e67d654e2a4f5783 100644 (file)
@@ -173,7 +173,7 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
 }
 
 // ParseExprFrom is a convenience function for parsing an expression.
-// The arguments have the same meaning as for Parse, but the source must
+// The arguments have the same meaning as for ParseFile, but the source must
 // be a valid Go (type or value) expression. Specifically, fset must not
 // be nil.
 //
index d3ef7db31eafbfe3c0f35007ce92e536bfebc8be..40c4a3e58d9cd0dce6b2ab781f6c424a70caa74b 100644 (file)
@@ -2327,7 +2327,10 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.
        // (Global identifiers are resolved in a separate phase after parsing.)
        spec := &ast.TypeSpec{Doc: doc, Name: ident}
        p.declare(spec, nil, p.topScope, ast.Typ, ident)
-
+       if p.tok == token.ASSIGN {
+               spec.Assign = p.pos
+               p.next()
+       }
        spec.Type = p.parseType()
        p.expectSemi() // call before accessing p.linecomment
        spec.Comment = p.lineComment
index f2732c0e2b18d142c121d98bf22de920f4b57eef..b2e1c11e9d538ed6c317e07740ce03c0d64f7866 100644 (file)
@@ -10,17 +10,12 @@ import (
        "testing"
 )
 
-var src = readFile("parser.go")
-
-func readFile(filename string) []byte {
-       data, err := ioutil.ReadFile(filename)
+func BenchmarkParse(b *testing.B) {
+       src, err := ioutil.ReadFile("parser.go")
        if err != nil {
-               panic(err)
+               b.Fatal(err)
        }
-       return data
-}
-
-func BenchmarkParse(b *testing.B) {
+       b.ResetTimer()
        b.SetBytes(int64(len(src)))
        for i := 0; i < b.N; i++ {
                if _, err := ParseFile(token.NewFileSet(), "", src, ParseComments); err != nil {
index cdd343ea3c1fd6df8c67772c24eaba6e8544725c..6f8ef6b0f775d98c918510fd4c878f28a11f64cb 100644 (file)
@@ -46,6 +46,8 @@ var valids = []string{
        `package p; const (x = 0; y; z)`, // issue 9639
        `package p; var _ = map[P]int{P{}:0, {}:1}`,
        `package p; var _ = map[*P]int{&P{}:0, {}:1}`,
+       `package p; type T = int`,
+       `package p; type (T = p.T; _ = struct{}; x = *T)`,
 }
 
 func TestValid(t *testing.T) {
index 11f26d45ea39429afb6eed2f4ee03588812dbaf5..08b8711c2d67c7cd8a599430ed58c49adf67fd97 100644 (file)
@@ -733,7 +733,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
 
        case *ast.FuncLit:
                p.expr(x.Type)
-               p.adjBlock(p.distanceFrom(x.Type.Pos()), blank, x.Body)
+               p.funcBody(p.distanceFrom(x.Type.Pos()), blank, x.Body)
 
        case *ast.ParenExpr:
                if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
@@ -825,6 +825,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                if x.Type != nil {
                        p.expr1(x.Type, token.HighestPrec, depth)
                }
+               p.level++
                p.print(x.Lbrace, token.LBRACE)
                p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace)
                // do not insert extra line break following a /*-style comment
@@ -837,6 +838,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                        mode |= noExtraBlank
                }
                p.print(mode, x.Rbrace, token.RBRACE, mode)
+               p.level--
 
        case *ast.Ellipsis:
                p.print(token.ELLIPSIS)
@@ -1445,6 +1447,9 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
                } else {
                        p.print(vtab)
                }
+               if s.Assign.IsValid() {
+                       p.print(token.ASSIGN, blank)
+               }
                p.expr(s.Type)
                p.setComment(s.Comment)
 
@@ -1557,18 +1562,23 @@ func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
        return bodySize
 }
 
-// adjBlock prints an "adjacent" block (e.g., a for-loop or function body) following
-// a header (e.g., a for-loop control clause or function signature) of given headerSize.
+// funcBody prints a function body following a function header of given headerSize.
 // If the header's and block's size are "small enough" and the block is "simple enough",
 // the block is printed on the current line, without line breaks, spaced from the header
 // by sep. Otherwise the block's opening "{" is printed on the current line, followed by
 // lines for the block's statements and its closing "}".
 //
-func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
+func (p *printer) funcBody(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
        if b == nil {
                return
        }
 
+       // save/restore composite literal nesting level
+       defer func(level int) {
+               p.level = level
+       }(p.level)
+       p.level = 0
+
        const maxSize = 100
        if headerSize+p.bodySize(b, maxSize) <= maxSize {
                p.print(sep, b.Lbrace, token.LBRACE)
@@ -1613,7 +1623,7 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
        }
        p.expr(d.Name)
        p.signature(d.Type.Params, d.Type.Results)
-       p.adjBlock(p.distanceFrom(d.Pos()), vtab, d.Body)
+       p.funcBody(p.distanceFrom(d.Pos()), vtab, d.Body)
 }
 
 func (p *printer) decl(decl ast.Decl) {
index eabf23e8b28691ec975c0fdcb5aee2584081f893..be61dad590eea02012364ae32c9c602d256f9c11 100644 (file)
@@ -58,6 +58,7 @@ type printer struct {
        // Current state
        output      []byte       // raw printer result
        indent      int          // current indentation
+       level       int          // level == 0: outside composite literal; level > 0: inside composite literal
        mode        pmode        // current printer mode
        impliedSemi bool         // if set, a linebreak implies a semicolon
        lastTok     token.Token  // last token printed (token.ILLEGAL if it's whitespace)
@@ -744,15 +745,19 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
                // follows on the same line but is not a comma, and not a "closing"
                // token immediately following its corresponding "opening" token,
                // add an extra separator unless explicitly disabled. Use a blank
-               // as separator unless we have pending linebreaks and they are not
-               // disabled, in which case we want a linebreak (issue 15137).
+               // as separator unless we have pending linebreaks, they are not
+               // disabled, and we are outside a composite literal, in which case
+               // we want a linebreak (issue 15137).
+               // TODO(gri) This has become overly complicated. We should be able
+               // to track whether we're inside an expression or statement and
+               // use that information to decide more directly.
                needsLinebreak := false
                if p.mode&noExtraBlank == 0 &&
                        last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line &&
                        tok != token.COMMA &&
                        (tok != token.RPAREN || p.prevOpen == token.LPAREN) &&
                        (tok != token.RBRACK || p.prevOpen == token.LBRACK) {
-                       if p.containsLinebreak() && p.mode&noExtraLinebreak == 0 {
+                       if p.containsLinebreak() && p.mode&noExtraLinebreak == 0 && p.level == 0 {
                                needsLinebreak = true
                        } else {
                                p.writeByte(' ', 1)
index 7676a26c1259eec0a56ca1a3c2930bc593f86de6..8b3a94ddcd03a0ac75ab7e6c2bbfa5dbb88c2b95 100644 (file)
@@ -103,3 +103,62 @@ label:
        mask := uint64(1)<<c - 1                // Allocation mask
        used := atomic.LoadUint64(&h.used)      // Current allocations
 }
+
+// Test cases for issue 18782
+var _ = [][]int{
+       /*       a, b, c, d, e */
+       /* a */ {0, 0, 0, 0, 0},
+       /* b */ {0, 5, 4, 4, 4},
+       /* c */ {0, 4, 5, 4, 4},
+       /* d */ {0, 4, 4, 5, 4},
+       /* e */ {0, 4, 4, 4, 5},
+}
+
+var _ = T{ /* a */ 0}
+
+var _ = T{ /* a */ /* b */ 0}
+
+var _ = T{     /* a */ /* b */
+       /* c */ 0,
+}
+
+var _ = T{     /* a */ /* b */
+       /* c */
+       /* d */ 0,
+}
+
+var _ = T{
+       /* a */
+       /* b */ 0,
+}
+
+var _ = T{ /* a */ {}}
+
+var _ = T{ /* a */ /* b */ {}}
+
+var _ = T{     /* a */ /* b */
+       /* c */ {},
+}
+
+var _ = T{     /* a */ /* b */
+       /* c */
+       /* d */ {},
+}
+
+var _ = T{
+       /* a */
+       /* b */ {},
+}
+
+var _ = []T{
+       func() {
+               var _ = [][]int{
+                       /*       a, b, c, d, e */
+                       /* a */ {0, 0, 0, 0, 0},
+                       /* b */ {0, 5, 4, 4, 4},
+                       /* c */ {0, 4, 5, 4, 4},
+                       /* d */ {0, 4, 4, 5, 4},
+                       /* e */ {0, 4, 4, 4, 5},
+               }
+       },
+}
index 4a055c82772886a0b2ea165d7b2abc987e458235..8d38c4194bbcd73e3ba0f58d59775edfa09b6501 100644 (file)
@@ -103,3 +103,66 @@ label:
    mask := uint64(1)<<c - 1 // Allocation mask
    used := atomic.LoadUint64(&h.used) // Current allocations
 }
+
+// Test cases for issue 18782
+var _ = [][]int{
+   /*       a, b, c, d, e */
+   /* a */ {0, 0, 0, 0, 0},
+   /* b */ {0, 5, 4, 4, 4},
+   /* c */ {0, 4, 5, 4, 4},
+   /* d */ {0, 4, 4, 5, 4},
+   /* e */ {0, 4, 4, 4, 5},
+}
+
+var _ = T{ /* a */ 0,
+}
+
+var _ = T{ /* a */ /* b */ 0,
+}
+
+var _ = T{ /* a */ /* b */
+   /* c */ 0,
+}
+
+var _ = T{ /* a */ /* b */
+   /* c */
+   /* d */ 0,
+}
+
+var _ = T{
+   /* a */
+   /* b */ 0,
+}
+
+var _ = T{ /* a */ {},
+}
+
+var _ = T{ /* a */ /* b */ {},
+}
+
+var _ = T{ /* a */ /* b */
+   /* c */ {},
+}
+
+var _ = T{ /* a */ /* b */
+   /* c */
+   /* d */ {},
+}
+
+var _ = T{
+   /* a */
+   /* b */ {},
+}
+
+var _ = []T{
+   func() {
+      var _ = [][]int{
+         /*       a, b, c, d, e */
+         /* a */ {0, 0, 0, 0, 0},
+         /* b */ {0, 5, 4, 4, 4},
+         /* c */ {0, 4, 5, 4, 4},
+         /* d */ {0, 4, 4, 5, 4},
+         /* e */ {0, 4, 4, 4, 5},
+      }
+   },
+}
index 82f5e0f9147be69128d1a0183bfb058d65443b55..d4ea545658cee9a633baab8b00b9b4b2cb1c88d7 100644 (file)
@@ -985,3 +985,18 @@ func _(struct {
        x       int
        y       int
 })     // no extra comma between } and )
+
+// alias declarations
+
+type c0 struct{}
+type c1 = C
+type c2 = struct{ x int }
+type c3 = p.C
+type (
+       s       struct{}
+       a       = A
+       b       = A
+       c       = foo
+       d       = interface{}
+       ddd     = p.Foo
+)
index a0a3783b846fbed661713caee409bdc41ec1afef..50386eb8d5deb7d84571f735794cb8cfd41a72fe 100644 (file)
@@ -999,3 +999,18 @@ func _(struct {
        x int
        y int
 }) // no extra comma between } and )
+
+// alias declarations
+
+type c0 struct{}
+type c1 = C
+type c2 = struct{ x int}
+type c3 = p.C
+type (
+       s struct{}
+       a = A
+       b = A
+       c = foo
+       d = interface{}
+       ddd = p.Foo
+)
\ No newline at end of file
index 44949895a7b9db03eb0c2a438c3009436d701551..5b911cb96cccbe2ca960012bdb46e0608d2cf710 100644 (file)
@@ -5,7 +5,7 @@
 // Package types declares the data types and implements
 // the algorithms for type-checking of Go packages. Use
 // Config.Check to invoke the type checker for a package.
-// Alternatively, create a new type checked with NewChecker
+// Alternatively, create a new type checker with NewChecker
 // and invoke it incrementally by calling Checker.Files.
 //
 // Type-checking consists of several interdependent phases:
index 1208eb8b3a1641af38c7558ed4c3a118acb7ef90..92c6d75e704fbefd5fa69433672365746171da8d 100644 (file)
@@ -1295,155 +1295,3 @@ func f(x int) { y := x; print(y) }
                }
        }
 }
-
-// Alias-related code. Keep for now.
-/*
-func TestAliases(t *testing.T) {
-       testenv.MustHaveGoBuild(t)
-
-       const src = `
-package b
-
-import (
-       "./testdata/alias"
-       a "./testdata/alias"
-       "math"
-)
-
-const (
-       c1 = alias.Pi1
-       c2 => a.Pi1
-       c3 => a.Pi2
-       c4 => math.Pi
-)
-
-var (
-       v1 => alias.Default
-       v2 => a.Default
-       v3 = f1
-)
-
-type (
-       t1 => alias.Context
-       t2 => a.Context
-)
-
-func f1 => alias.Sin
-func f2 => a.Sin
-
-func _() {
-       assert(c1 == alias.Pi1 && c2 == a.Pi1 && c3 == a.Pi2 && c4 == math.Pi)
-       assert(c2 == c2 && c2 == c3 && c3 == c4)
-       v1 = v2 // must be assignable
-       var _ *t1 = new(t2) // must be assignable
-       var _ t2 = alias.Default
-       f1(1) // must be callable
-       f2(1)
-       _ = alias.Sin(1)
-       _ = a.Sin(1)
-}
-`
-
-       if out := compile(t, "testdata", "alias.go"); out != "" {
-               defer os.Remove(out)
-       }
-
-       DefPredeclaredTestFuncs() // declare assert built-in for testing
-       mustTypecheck(t, "Aliases", src, nil)
-}
-
-func compile(t *testing.T, dirname, filename string) string {
-       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", filename)
-       cmd.Dir = dirname
-       out, err := cmd.CombinedOutput()
-       if err != nil {
-               t.Logf("%s", out)
-               t.Fatalf("go tool compile %s failed: %s", filename, err)
-       }
-       // filename should end with ".go"
-       return filepath.Join(dirname, filename[:len(filename)-2]+"o")
-}
-
-func TestAliasDefUses(t *testing.T) {
-       testenv.MustHaveGoBuild(t)
-
-       const src = `
-package p
-
-import(
-       "go/build"
-       "go/types"
-)
-
-// Defs
-const Invalid => types.Invalid
-type Struct => types.Struct
-var Default => build.Default
-func Implements => types.Implements
-
-// Uses
-const _ = Invalid
-var _ types.Struct = Struct{} // types must be identical
-var _ build.Context = Default
-var _ = Implements(nil, nil)
-`
-
-       info := Info{
-               Defs: make(map[*ast.Ident]Object),
-               Uses: make(map[*ast.Ident]Object),
-       }
-       mustTypecheck(t, "TestAliasDefUses", src, &info)
-
-       // verify Defs
-       defs := map[string]string{
-               "Invalid":    "types.Invalid",
-               "Struct":     "types.Struct",
-               "Default":    "build.Default",
-               "Implements": "types.Implements",
-       }
-
-       for ident, obj := range info.Defs {
-               if alias, ok := obj.(*Alias); ok {
-                       if want := defs[ident.Name]; want != "" {
-                               orig := alias.Orig()
-                               if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
-                                       t.Errorf("%v: got %v, want %v", ident, got, want)
-                               }
-                               delete(defs, ident.Name) // mark as found
-                       } else {
-                               t.Errorf("unexpected alias def of %v", ident)
-                       }
-               }
-       }
-
-       if len(defs) != 0 {
-               t.Errorf("missing aliases: %v", defs)
-       }
-
-       // verify Uses
-       uses := map[string]string{
-               "Invalid":    "types.Invalid",
-               "Struct":     "types.Struct",
-               "Default":    "build.Default",
-               "Implements": "types.Implements",
-       }
-
-       for ident, obj := range info.Uses {
-               if alias, ok := obj.(*Alias); ok {
-                       if want := uses[ident.Name]; want != "" {
-                               orig := alias.Orig()
-                               if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
-                                       t.Errorf("%v: got %v, want %v", ident, got, want)
-                               }
-                               delete(uses, ident.Name) // mark as found
-                       } else {
-                               t.Errorf("unexpected alias use of %v", ident)
-                       }
-               }
-       }
-
-       if len(uses) != 0 {
-               t.Errorf("missing aliases: %v", defs)
-       }
-}
-*/
index 8e5c5371f229f7a98f0aef7dbafecdeed2413d0d..7f5823c8295c1aba77f26df51a92e2d4f656994c 100644 (file)
@@ -275,8 +275,6 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
        // so we don't need a "package" mode for operands: package names
        // can only appear in qualified identifiers which are mapped to
        // selector expressions.
-       // (see also decl.go: checker.aliasDecl)
-       // TODO(gri) factor this code out and share with checker.aliasDecl
        if ident, ok := e.X.(*ast.Ident); ok {
                _, obj := check.scope.LookupParent(ident.Name, check.pos)
                if pname, _ := obj.(*PkgName); pname != nil {
@@ -296,12 +294,6 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
                                // ok to continue
                        }
                        check.recordUse(e.Sel, exp)
-                       exp = original(exp)
-
-                       // avoid further errors if the imported object is an alias that's broken
-                       if exp == nil {
-                               goto Error
-                       }
 
                        // Simplified version of the code for *ast.Idents:
                        // - imported objects are always fully initialized
index f8445752695c3d3238f60d7d2fbcebfba9e5aec4..24b3365717b631af8fe0ae5733a516d32c2aa78e 100644 (file)
@@ -68,11 +68,11 @@ var tests = [][]string{
        {"testdata/decls1.src"},
        {"testdata/decls2a.src", "testdata/decls2b.src"},
        {"testdata/decls3.src"},
+       {"testdata/decls4.src"},
        {"testdata/const0.src"},
        {"testdata/const1.src"},
        {"testdata/constdecl.src"},
        {"testdata/vardecl.src"},
-       //{"testdata/aliasdecl.src"},
        {"testdata/expr0.src"},
        {"testdata/expr1.src"},
        {"testdata/expr2.src"},
index dced7a6d6dc9163f0e161576728dba0082e77a06..7428f8f99500a78a03a8e8798237095637e4e9ed 100644 (file)
@@ -81,14 +81,10 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
                check.varDecl(obj, d.lhs, d.typ, d.init)
        case *TypeName:
                // invalid recursive types are detected via path
-               check.typeDecl(obj, d.typ, def, path)
+               check.typeDecl(obj, d.typ, def, path, d.alias)
        case *Func:
                // functions may be recursive - no need to track dependencies
                check.funcDecl(obj, d)
-       // Alias-related code. Keep for now.
-       // case *Alias:
-       //      // aliases cannot be recursive - no need to track dependencies
-       //      check.aliasDecl(obj, d)
        default:
                unreachable()
        }
@@ -219,33 +215,42 @@ func (n *Named) setUnderlying(typ Type) {
        }
 }
 
-func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName) {
+func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName, alias bool) {
        assert(obj.typ == nil)
 
        // type declarations cannot use iota
        assert(check.iota == nil)
 
-       named := &Named{obj: obj}
-       def.setUnderlying(named)
-       obj.typ = named // make sure recursive type declarations terminate
-
-       // determine underlying type of named
-       check.typExpr(typ, named, append(path, obj))
-
-       // The underlying type of named may be itself a named type that is
-       // incomplete:
-       //
-       //      type (
-       //              A B
-       //              B *C
-       //              C A
-       //      )
-       //
-       // The type of C is the (named) type of A which is incomplete,
-       // and which has as its underlying type the named type B.
-       // Determine the (final, unnamed) underlying type by resolving
-       // any forward chain (they always end in an unnamed type).
-       named.underlying = underlying(named.underlying)
+       if alias {
+
+               obj.typ = Typ[Invalid]
+               obj.typ = check.typExpr(typ, nil, append(path, obj))
+
+       } else {
+
+               named := &Named{obj: obj}
+               def.setUnderlying(named)
+               obj.typ = named // make sure recursive type declarations terminate
+
+               // determine underlying type of named
+               check.typExpr(typ, named, append(path, obj))
+
+               // The underlying type of named may be itself a named type that is
+               // incomplete:
+               //
+               //      type (
+               //              A B
+               //              B *C
+               //              C A
+               //      )
+               //
+               // The type of C is the (named) type of A which is incomplete,
+               // and which has as its underlying type the named type B.
+               // Determine the (final, unnamed) underlying type by resolving
+               // any forward chain (they always end in an unnamed type).
+               named.underlying = underlying(named.underlying)
+
+       }
 
        // check and add associated methods
        // TODO(gri) It's easy to create pathological cases where the
@@ -268,21 +273,23 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
 
        // spec: "If the base type is a struct type, the non-blank method
        // and field names must be distinct."
-       base := obj.typ.(*Named)
-       if t, _ := base.underlying.(*Struct); t != nil {
-               for _, fld := range t.fields {
-                       if fld.name != "_" {
-                               assert(mset.insert(fld) == nil)
+       base, _ := obj.typ.(*Named) // nil if receiver base type is type alias
+       if base != nil {
+               if t, _ := base.underlying.(*Struct); t != nil {
+                       for _, fld := range t.fields {
+                               if fld.name != "_" {
+                                       assert(mset.insert(fld) == nil)
+                               }
                        }
                }
-       }
 
-       // Checker.Files may be called multiple times; additional package files
-       // may add methods to already type-checked types. Add pre-existing methods
-       // so that we can detect redeclarations.
-       for _, m := range base.methods {
-               assert(m.name != "_")
-               assert(mset.insert(m) == nil)
+               // Checker.Files may be called multiple times; additional package files
+               // may add methods to already type-checked types. Add pre-existing methods
+               // so that we can detect redeclarations.
+               for _, m := range base.methods {
+                       assert(m.name != "_")
+                       assert(mset.insert(m) == nil)
+               }
        }
 
        // type-check methods
@@ -295,7 +302,7 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
                                case *Var:
                                        check.errorf(m.pos, "field and method with the same name %s", m.name)
                                case *Func:
-                                       check.errorf(m.pos, "method %s already declared for %s", m.name, base)
+                                       check.errorf(m.pos, "method %s already declared for %s", m.name, obj)
                                default:
                                        unreachable()
                                }
@@ -303,9 +310,12 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
                                continue
                        }
                }
+
+               // type-check
                check.objDecl(m, nil, nil)
+
                // methods with blank _ names cannot be found - don't keep them
-               if m.name != "_" {
+               if base != nil && m.name != "_" {
                        base.methods = append(base.methods, m)
                }
        }
@@ -333,106 +343,6 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
        }
 }
 
-// original returns the original Object if obj is an Alias;
-// otherwise it returns obj. The result is never an Alias,
-// but it may be nil.
-func original(obj Object) Object {
-       // an alias stands for the original object; use that one instead
-       if alias, _ := obj.(*disabledAlias); alias != nil {
-               obj = alias.orig
-               // aliases always refer to non-alias originals
-               if _, ok := obj.(*disabledAlias); ok {
-                       panic("original is an alias")
-               }
-       }
-       return obj
-}
-
-func (check *Checker) aliasDecl(obj *disabledAlias, decl *declInfo) {
-       assert(obj.typ == nil)
-
-       // alias declarations cannot use iota
-       assert(check.iota == nil)
-
-       // assume alias is invalid to start with
-       obj.typ = Typ[Invalid]
-
-       // rhs must be package-qualified identifer pkg.sel (see also call.go: checker.selector)
-       // TODO(gri) factor this code out and share with checker.selector
-       rhs := decl.init
-       var pkg *Package
-       var sel *ast.Ident
-       if sexpr, ok := rhs.(*ast.SelectorExpr); ok {
-               if ident, ok := sexpr.X.(*ast.Ident); ok {
-                       _, obj := check.scope.LookupParent(ident.Name, check.pos)
-                       if pname, _ := obj.(*PkgName); pname != nil {
-                               assert(pname.pkg == check.pkg)
-                               check.recordUse(ident, pname)
-                               pname.used = true
-                               pkg = pname.imported
-                               sel = sexpr.Sel
-                       }
-               }
-       }
-       if pkg == nil {
-               check.errorf(rhs.Pos(), "invalid alias: %v is not a package-qualified identifier", rhs)
-               return
-       }
-
-       // qualified identifier must denote an exported object
-       orig := pkg.scope.Lookup(sel.Name)
-       if orig == nil || !orig.Exported() {
-               if !pkg.fake {
-                       check.errorf(rhs.Pos(), "%s is not exported by package %s", sel.Name, pkg.name)
-               }
-               return
-       }
-       check.recordUse(sel, orig)
-       orig = original(orig)
-
-       // avoid further errors if the imported object is an alias that's broken
-       if orig == nil {
-               return
-       }
-
-       // An alias declaration must not refer to package unsafe.
-       if orig.Pkg() == Unsafe {
-               check.errorf(rhs.Pos(), "invalid alias: %s refers to package unsafe (%v)", obj.Name(), orig)
-               return
-       }
-
-       // The original must be of the same kind as the alias declaration.
-       var why string
-       switch obj.kind {
-       case token.CONST:
-               if _, ok := orig.(*Const); !ok {
-                       why = "constant"
-               }
-       case token.TYPE:
-               if _, ok := orig.(*TypeName); !ok {
-                       why = "type"
-               }
-       case token.VAR:
-               if _, ok := orig.(*Var); !ok {
-                       why = "variable"
-               }
-       case token.FUNC:
-               if _, ok := orig.(*Func); !ok {
-                       why = "function"
-               }
-       default:
-               unreachable()
-       }
-       if why != "" {
-               check.errorf(rhs.Pos(), "invalid alias: %v is not a %s", orig, why)
-               return
-       }
-
-       // alias is valid
-       obj.typ = orig.Type()
-       obj.orig = orig
-}
-
 func (check *Checker) declStmt(decl ast.Decl) {
        pkg := check.pkg
 
@@ -540,7 +450,7 @@ func (check *Checker) declStmt(decl ast.Decl) {
                                // the innermost containing block."
                                scopePos := s.Name.Pos()
                                check.declare(check.scope, s.Name, obj, scopePos)
-                               check.typeDecl(obj, s.Type, nil, nil)
+                               check.typeDecl(obj, s.Type, nil, nil, s.Assign.IsValid())
 
                        default:
                                check.invalidAST(s.Pos(), "const, type, or var declaration expected")
index 8882e5063a4599b52553b8a7ba2f4a4de64ee44c..2a2fb3fc591d3880fc0e269859425b37cfcf9694 100644 (file)
@@ -239,10 +239,10 @@ func fib(x int) int {
        // type S string:
        //   defined at fib.go:4:6
        //   used at 6:23
-       // type int int:
+       // type int:
        //   defined at -
        //   used at 8:12, 8:17
-       // type string string:
+       // type string:
        //   defined at -
        //   used at 4:8
        // var b S:
index 3caca5519b63c3b5d8d8d9646471be64cbe94c34..ee8202d9e42d77d0133277755e0568a3aefaede1 100644 (file)
@@ -67,24 +67,22 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
        }
 
        typ, isPtr := deref(T)
-       named, _ := typ.(*Named)
 
        // *typ where typ is an interface has no methods.
-       if isPtr {
-               utyp := typ
-               if named != nil {
-                       utyp = named.underlying
-               }
-               if _, ok := utyp.(*Interface); ok {
-                       return
-               }
+       if isPtr && IsInterface(typ) {
+               return
        }
 
        // Start with typ as single entry at shallowest depth.
-       // If typ is not a named type, insert a nil type instead.
-       current := []embeddedType{{named, nil, isPtr, false}}
-
-       // named types that we have seen already, allocated lazily
+       current := []embeddedType{{typ, nil, isPtr, false}}
+
+       // Named types that we have seen already, allocated lazily.
+       // Used to avoid endless searches in case of recursive types.
+       // Since only Named types can be used for recursive types, we
+       // only need to track those.
+       // (If we ever allow type aliases to construct recursive types,
+       // we must use type identity rather than pointer equality for
+       // the map key comparison, as we do in consolidateMultiples.)
        var seen map[*Named]bool
 
        // search current depth
@@ -93,11 +91,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
 
                // look for (pkg, name) in all types at current depth
                for _, e := range current {
-                       // The very first time only, e.typ may be nil.
-                       // In this case, we don't have a named type and
-                       // we simply continue with the underlying type.
-                       if e.typ != nil {
-                               if seen[e.typ] {
+                       typ := e.typ
+
+                       // If we have a named type, we may have associated methods.
+                       // Look for those first.
+                       if named, _ := typ.(*Named); named != nil {
+                               if seen[named] {
                                        // We have seen this type before, at a more shallow depth
                                        // (note that multiples of this type at the current depth
                                        // were consolidated before). The type at that depth shadows
@@ -108,10 +107,10 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
                                if seen == nil {
                                        seen = make(map[*Named]bool)
                                }
-                               seen[e.typ] = true
+                               seen[named] = true
 
                                // look for a matching attached method
-                               if i, m := lookupMethod(e.typ.methods, pkg, name); m != nil {
+                               if i, m := lookupMethod(named.methods, pkg, name); m != nil {
                                        // potential match
                                        assert(m.typ != nil)
                                        index = concat(e.index, i)
@@ -124,7 +123,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
                                }
 
                                // continue with underlying type
-                               typ = e.typ.underlying
+                               typ = named.underlying
                        }
 
                        switch t := typ.(type) {
@@ -147,16 +146,15 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
                                        // we have a name collision on the same depth; in either
                                        // case we don't need to look further).
                                        // Embedded fields are always of the form T or *T where
-                                       // T is a named type. If e.typ appeared multiple times at
+                                       // T is a type name. If e.typ appeared multiple times at
                                        // this depth, f.typ appears multiple times at the next
                                        // depth.
                                        if obj == nil && f.anonymous {
-                                               // Ignore embedded basic types - only user-defined
-                                               // named types can have methods or struct fields.
                                                typ, isPtr := deref(f.typ)
-                                               if t, _ := typ.(*Named); t != nil {
-                                                       next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
-                                               }
+                                               // TODO(gri) optimization: ignore types that can't
+                                               // have fields or methods (only Named, Struct, and
+                                               // Interface types need to be considered).
+                                               next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
                                        }
                                }
 
@@ -193,12 +191,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
        return nil, nil, false // not found
 }
 
-// embeddedType represents an embedded named type
+// embeddedType represents an embedded type
 type embeddedType struct {
-       typ       *Named // nil means use the outer typ variable instead
-       index     []int  // embedded field indices, starting with index at depth 0
-       indirect  bool   // if set, there was a pointer indirection on the path to this field
-       multiples bool   // if set, typ appears multiple times at this depth
+       typ       Type
+       index     []int // embedded field indices, starting with index at depth 0
+       indirect  bool  // if set, there was a pointer indirection on the path to this field
+       multiples bool  // if set, typ appears multiple times at this depth
 }
 
 // consolidateMultiples collects multiple list entries with the same type
@@ -209,10 +207,10 @@ func consolidateMultiples(list []embeddedType) []embeddedType {
                return list // at most one entry - nothing to do
        }
 
-       n := 0                       // number of entries w/ unique type
-       prev := make(map[*Named]int) // index at which type was previously seen
+       n := 0                     // number of entries w/ unique type
+       prev := make(map[Type]int) // index at which type was previously seen
        for _, e := range list {
-               if i, found := prev[e.typ]; found {
+               if i, found := lookupType(prev, e.typ); found {
                        list[i].multiples = true
                        // ignore this entry
                } else {
@@ -224,6 +222,21 @@ func consolidateMultiples(list []embeddedType) []embeddedType {
        return list[:n]
 }
 
+func lookupType(m map[Type]int, typ Type) (int, bool) {
+       // fast path: maybe the types are equal
+       if i, found := m[typ]; found {
+               return i, true
+       }
+
+       for t, i := range m {
+               if Identical(t, typ) {
+                       return i, true
+               }
+       }
+
+       return 0, false
+}
+
 // MissingMethod returns (nil, false) if V implements T, otherwise it
 // returns a missing method required by T and whether it is missing or
 // just has the wrong type.
index b27f2dac34a2553f9cf8bc32773409c58834f58e..4f791d9d51c64e2bda2bec460c7708b2a5054803 100644 (file)
@@ -72,24 +72,22 @@ func NewMethodSet(T Type) *MethodSet {
        var base methodSet
 
        typ, isPtr := deref(T)
-       named, _ := typ.(*Named)
 
        // *typ where typ is an interface has no methods.
-       if isPtr {
-               utyp := typ
-               if named != nil {
-                       utyp = named.underlying
-               }
-               if _, ok := utyp.(*Interface); ok {
-                       return &emptyMethodSet
-               }
+       if isPtr && IsInterface(typ) {
+               return &emptyMethodSet
        }
 
        // Start with typ as single entry at shallowest depth.
-       // If typ is not a named type, insert a nil type instead.
-       current := []embeddedType{{named, nil, isPtr, false}}
-
-       // named types that we have seen already, allocated lazily
+       current := []embeddedType{{typ, nil, isPtr, false}}
+
+       // Named types that we have seen already, allocated lazily.
+       // Used to avoid endless searches in case of recursive types.
+       // Since only Named types can be used for recursive types, we
+       // only need to track those.
+       // (If we ever allow type aliases to construct recursive types,
+       // we must use type identity rather than pointer equality for
+       // the map key comparison, as we do in consolidateMultiples.)
        var seen map[*Named]bool
 
        // collect methods at current depth
@@ -101,11 +99,12 @@ func NewMethodSet(T Type) *MethodSet {
                var mset methodSet
 
                for _, e := range current {
-                       // The very first time only, e.typ may be nil.
-                       // In this case, we don't have a named type and
-                       // we simply continue with the underlying type.
-                       if e.typ != nil {
-                               if seen[e.typ] {
+                       typ := e.typ
+
+                       // If we have a named type, we may have associated methods.
+                       // Look for those first.
+                       if named, _ := typ.(*Named); named != nil {
+                               if seen[named] {
                                        // We have seen this type before, at a more shallow depth
                                        // (note that multiples of this type at the current depth
                                        // were consolidated before). The type at that depth shadows
@@ -116,12 +115,12 @@ func NewMethodSet(T Type) *MethodSet {
                                if seen == nil {
                                        seen = make(map[*Named]bool)
                                }
-                               seen[e.typ] = true
+                               seen[named] = true
 
-                               mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples)
+                               mset = mset.add(named.methods, e.index, e.indirect, e.multiples)
 
                                // continue with underlying type
-                               typ = e.typ.underlying
+                               typ = named.underlying
                        }
 
                        switch t := typ.(type) {
@@ -130,16 +129,15 @@ func NewMethodSet(T Type) *MethodSet {
                                        fset = fset.add(f, e.multiples)
 
                                        // Embedded fields are always of the form T or *T where
-                                       // T is a named type. If typ appeared multiple times at
+                                       // T is a type name. If typ appeared multiple times at
                                        // this depth, f.Type appears multiple times at the next
                                        // depth.
                                        if f.anonymous {
-                                               // Ignore embedded basic types - only user-defined
-                                               // named types can have methods or struct fields.
                                                typ, isPtr := deref(f.typ)
-                                               if t, _ := typ.(*Named); t != nil {
-                                                       next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
-                                               }
+                                               // TODO(gri) optimization: ignore types that can't
+                                               // have fields or methods (only Named, Struct, and
+                                               // Interface types need to be considered).
+                                               next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
                                        }
                                }
 
index 6c0c5c4a244de8ac5f703ed4a7bae986bcf5e084..3c44348696600191e46d0d7e22919dd4ca99f0f1 100644 (file)
@@ -25,7 +25,7 @@ type Object interface {
        Name() string   // package local object name
        Type() Type     // object type
        Exported() bool // reports whether the name starts with a capital letter
-       Id() string     // object id (see Id below)
+       Id() string     // object name if exported, qualified name if not exported (see func Id)
 
        // String returns a human-readable string of the object.
        String() string
@@ -64,15 +64,10 @@ func Id(pkg *Package, name string) string {
        // inside a package and outside a package - which breaks some
        // tests)
        path := "_"
-       // TODO(gri): shouldn't !ast.IsExported(name) => pkg != nil be an precondition?
-       // if pkg == nil {
-       //      panic("nil package in lookup of unexported name")
-       // }
-       if pkg != nil {
+       // pkg is nil for objects in Universe scope and possibly types
+       // introduced via Eval (see also comment in object.sameId)
+       if pkg != nil && pkg.path != "" {
                path = pkg.path
-               if path == "" {
-                       path = "_"
-               }
        }
        return path + "." + name
 }
@@ -154,7 +149,7 @@ func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val constant.V
 func (obj *Const) Val() constant.Value { return obj.val }
 func (*Const) isDependency()           {} // a constant may be a dependency of an initialization expression
 
-// A TypeName represents a declared type.
+// A TypeName represents a name for a (named or alias) type.
 type TypeName struct {
        object
 }
@@ -163,6 +158,26 @@ func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
        return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}}
 }
 
+// IsAlias reports whether obj is an alias name for a type.
+func (obj *TypeName) IsAlias() bool {
+       switch t := obj.typ.(type) {
+       case nil:
+               return false
+       case *Basic:
+               // Any user-defined type name for a basic type is an alias for a
+               // basic type (because basic types are pre-declared in the Universe
+               // scope, outside any package scope), and so is any type name with
+               // a different name than the name of the basic type it refers to.
+               // Additionaly, we need to look for "byte" and "rune" because they
+               // are aliases but have the same names (for better error messages).
+               return obj.pkg != nil || t.name != obj.name || t == universeByte || t == universeRune
+       case *Named:
+               return obj != t.obj
+       default:
+               return true
+       }
+}
+
 // A Variable represents a declared variable (including function parameters and results, and struct fields).
 type Var struct {
        object
@@ -215,28 +230,6 @@ func (obj *Func) FullName() string {
 func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
 func (*Func) isDependency()     {} // a function may be a dependency of an initialization expression
 
-// An Alias represents a declared alias.
-type disabledAlias struct {
-       object
-       orig Object      // aliased constant, type, variable, or function; never an alias
-       kind token.Token // token.CONST, token.TYPE, token.VAR, or token.FUNC (only needed during resolve phase)
-}
-
-func disabledNewAlias(pos token.Pos, pkg *Package, name string, orig Object) *disabledAlias {
-       var typ Type = Typ[Invalid]
-       if orig != nil {
-               typ = orig.Type()
-       }
-       // No need to set a valid Alias.kind - that field is only used during identifier
-       // resolution (1st type-checker pass). We could store the field outside but it's
-       // easier to keep it here.
-       return &disabledAlias{object{nil, pos, pkg, name, typ, 0, token.NoPos}, orig, token.ILLEGAL}
-}
-
-// Orig returns the aliased object, or nil if there was an error.
-// The returned object is never an Alias.
-func (obj *disabledAlias) disabledOrig() Object { return obj.orig }
-
 // A Label represents a declared label.
 type Label struct {
        object
@@ -264,7 +257,9 @@ type Nil struct {
 }
 
 func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
+       var tname *TypeName
        typ := obj.Type()
+
        switch obj := obj.(type) {
        case *PkgName:
                fmt.Fprintf(buf, "package %s", obj.Name())
@@ -277,8 +272,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                buf.WriteString("const")
 
        case *TypeName:
+               tname = obj
                buf.WriteString("type")
-               typ = typ.Underlying()
 
        case *Var:
                if obj.isField {
@@ -295,10 +290,6 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                }
                return
 
-       // Alias-related code. Keep for now.
-       // case *Alias:
-       //      buf.WriteString("alias")
-
        case *Label:
                buf.WriteString("label")
                typ = nil
@@ -322,10 +313,27 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                writePackage(buf, obj.Pkg(), qf)
        }
        buf.WriteString(obj.Name())
-       if typ != nil {
-               buf.WriteByte(' ')
-               WriteType(buf, typ, qf)
+
+       if typ == nil {
+               return
+       }
+
+       if tname != nil {
+               // We have a type object: Don't print anything more for
+               // basic types since there's no more information (names
+               // are the same; see also comment in TypeName.IsAlias).
+               if _, ok := typ.(*Basic); ok {
+                       return
+               }
+               if tname.IsAlias() {
+                       buf.WriteString(" =")
+               } else {
+                       typ = typ.Underlying()
+               }
        }
+
+       buf.WriteByte(' ')
+       WriteType(buf, typ, qf)
 }
 
 func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) {
@@ -353,15 +361,14 @@ func ObjectString(obj Object, qf Qualifier) string {
        return buf.String()
 }
 
-func (obj *PkgName) String() string       { return ObjectString(obj, nil) }
-func (obj *Const) String() string         { return ObjectString(obj, nil) }
-func (obj *TypeName) String() string      { return ObjectString(obj, nil) }
-func (obj *Var) String() string           { return ObjectString(obj, nil) }
-func (obj *Func) String() string          { return ObjectString(obj, nil) }
-func (obj *disabledAlias) String() string { return ObjectString(obj, nil) }
-func (obj *Label) String() string         { return ObjectString(obj, nil) }
-func (obj *Builtin) String() string       { return ObjectString(obj, nil) }
-func (obj *Nil) String() string           { return ObjectString(obj, nil) }
+func (obj *PkgName) String() string  { return ObjectString(obj, nil) }
+func (obj *Const) String() string    { return ObjectString(obj, nil) }
+func (obj *TypeName) String() string { return ObjectString(obj, nil) }
+func (obj *Var) String() string      { return ObjectString(obj, nil) }
+func (obj *Func) String() string     { return ObjectString(obj, nil) }
+func (obj *Label) String() string    { return ObjectString(obj, nil) }
+func (obj *Builtin) String() string  { return ObjectString(obj, nil) }
+func (obj *Nil) String() string      { return ObjectString(obj, nil) }
 
 func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
        if f.typ != nil {
diff --git a/src/go/types/object_test.go b/src/go/types/object_test.go
new file mode 100644 (file)
index 0000000..16d7d5c
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2016 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 types
+
+import "testing"
+
+func TestIsAlias(t *testing.T) {
+       check := func(obj *TypeName, want bool) {
+               if got := obj.IsAlias(); got != want {
+                       t.Errorf("%v: got IsAlias = %v; want %v", obj, got, want)
+               }
+       }
+
+       // predeclared types
+       for _, name := range Universe.Names() {
+               if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil {
+                       check(obj, name == "byte" || name == "rune")
+               }
+       }
+
+       // various other types
+       pkg := NewPackage("p", "p")
+       t1 := NewTypeName(0, pkg, "t1", nil)
+       n1 := NewNamed(t1, new(Struct), nil)
+       for _, test := range []struct {
+               name  *TypeName
+               alias bool
+       }{
+               {NewTypeName(0, nil, "t0", nil), false}, // no type yet
+               {NewTypeName(0, pkg, "t0", nil), false}, // no type yet
+               {t1, false},                             // type name refers to named type and vice versa
+               {NewTypeName(0, nil, "t2", new(Interface)), true}, // type name refers to unnamed type
+               {NewTypeName(0, pkg, "t3", n1), true},             // type name refers to named type with different type name
+               {NewTypeName(0, nil, "t4", Typ[Int32]), true},     // type name refers to basic type with different name
+               {NewTypeName(0, nil, "int32", Typ[Int32]), false}, // type name refers to basic type with same name
+               {NewTypeName(0, pkg, "int32", Typ[Int32]), true},  // type name is declared in user-defined package (outside Universe)
+               {NewTypeName(0, nil, "rune", Typ[Rune]), true},    // type name refers to basic type rune which is an alias already
+       } {
+               check(test.name, test.alias)
+       }
+}
index 21fd81e3c26c01d7abe0e8bef03d4e1905c88b75..c3b87dd9cd42fa27388bb1a1150a8a36da0f6a1a 100644 (file)
@@ -139,7 +139,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
        case *Basic:
                // Basic types are singletons except for the rune and byte
                // aliases, thus we cannot solely rely on the x == y check
-               // above.
+               // above. See also comment in TypeName.IsAlias.
                if y, ok := y.(*Basic); ok {
                        return x.kind == y.kind
                }
index 046e147456da875782f79307eb3947e596f1d7f4..939f70a9ca883ffa20b48a2e61da933a225efc30 100644 (file)
@@ -14,13 +14,14 @@ import (
        "unicode"
 )
 
-// A declInfo describes a package-level const, type, var, func, or alias declaration.
+// A declInfo describes a package-level const, type, var, or func declaration.
 type declInfo struct {
        file  *Scope        // scope of file containing this declaration
        lhs   []*Var        // lhs of n:1 variable declarations, or nil
        typ   ast.Expr      // type, or nil
        init  ast.Expr      // init/orig expression, or nil
        fdecl *ast.FuncDecl // func declaration, or nil
+       alias bool          // type alias declaration
 
        // The deps field tracks initialization expression dependencies.
        // As a special (overloaded) case, it also tracks dependencies of
@@ -274,13 +275,6 @@ func (check *Checker) collectObjects() {
                                                        check.declare(fileScope, nil, obj, token.NoPos)
                                                }
 
-                                       // Alias-related code. Keep for now.
-                                       // case *ast.AliasSpec:
-                                       //      obj := NewAlias(s.Name.Pos(), pkg, s.Name.Name, nil)
-                                       //      obj.typ = nil // unresolved
-                                       //      obj.kind = d.Tok
-                                       //      check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, init: s.Orig})
-
                                        case *ast.ValueSpec:
                                                switch d.Tok {
                                                case token.CONST:
@@ -347,7 +341,7 @@ func (check *Checker) collectObjects() {
 
                                        case *ast.TypeSpec:
                                                obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
-                                               check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type})
+                                               check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type, alias: s.Assign.IsValid()})
 
                                        default:
                                                check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
index 1c6d7b5299309738d7a9e523ca4278a08151006e..06d2c93dda3edff3945ddd25a2abb3ab06896eb8 100644 (file)
@@ -157,6 +157,7 @@ func TestStdFixed(t *testing.T) {
                "issue11362.go", // canonical import path check
                "issue15002.go", // uses Mmap; testTestDir should consult build tags
                "issue16369.go", // go/types handles this correctly - not an issue
+               "issue18459.go", // go/types doesn't check validity of //go:xxx directives
        )
 }
 
diff --git a/src/go/types/testdata/decls4.src b/src/go/types/testdata/decls4.src
new file mode 100644 (file)
index 0000000..5e5e2e9
--- /dev/null
@@ -0,0 +1,150 @@
+// Copyright 2016 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.
+
+// type aliases
+
+package decls4
+
+type (
+       T0 [10]int
+       T1 []byte
+       T2 struct {
+               x int
+       }
+       T3 interface{
+               m() T2
+       }
+       T4 func(int, T0) chan T2
+)
+
+type (
+       Ai = int
+       A0 = T0
+       A1 = T1
+       A2 = T2
+       A3 = T3
+       A4 = T4
+
+       A10 = [10]int
+       A11 = []byte
+       A12 = struct {
+               x int
+       }
+       A13 = interface{
+               m() A2
+       }
+       A14 = func(int, A0) chan A2
+)
+
+// check assignment compatibility due to equality of types
+var (
+       xi_ int
+       ai Ai = xi_
+
+       x0 T0
+       a0 A0 = x0
+
+       x1 T1
+       a1 A1 = x1
+
+       x2 T2
+       a2 A2 = x2
+
+       x3 T3
+       a3 A3 = x3
+
+       x4 T4
+       a4 A4 = x4
+)
+
+// alias receiver types
+func (Ai /* ERROR "invalid receiver" */) m1() {}
+func (T0) m1() {}
+func (A0) m1 /* ERROR already declared */ () {}
+func (A0) m2 () {}
+func (A3 /* ERROR invalid receiver */ ) m1 () {}
+func (A10 /* ERROR invalid receiver */ ) m1() {}
+
+// x0 has methods m1, m2 declared via receiver type names T0 and A0
+var _ interface{ m1(); m2() } = x0
+
+// cycles
+type (
+       C2 /* ERROR illegal cycle */ = C2
+       C3 /* ERROR illegal cycle */ = C4
+       C4 = C3
+       C5 struct {
+               f *C6
+       }
+       C6 = C5
+       C7 /* ERROR illegal cycle */  struct {
+               f C8
+       }
+       C8 = C7
+)
+
+// embedded fields
+var (
+       s0 struct { T0 }
+       s1 struct { A0 } = s0 /* ERROR cannot use */ // embedded field names are different
+)
+
+// embedding and lookup of fields and methods
+func _(s struct{A0}) { s.A0 = x0 }
+
+type eX struct{xf int}
+
+func (eX) xm()
+
+type eY = struct{eX} // field/method set of eY includes xf, xm
+
+type eZ = *struct{eX} // field/method set of eZ includes xf, xm
+
+type eA struct {
+       eX // eX contributes xf, xm to eA
+}
+
+type eA2 struct {
+       *eX // *eX contributes xf, xm to eA
+}
+
+type eB struct {
+       eY // eY contributes xf, xm to eB
+}
+
+type eB2 struct {
+       *eY // *eY contributes xf, xm to eB
+}
+
+type eC struct {
+       eZ // eZ contributes xf, xm to eC
+}
+
+var (
+       _ = eA{}.xf
+       _ = eA{}.xm
+       _ = eA2{}.xf
+       _ = eA2{}.xm
+       _ = eB{}.xf
+       _ = eB{}.xm
+       _ = eB2{}.xf
+       _ = eB2{}.xm
+       _ = eC{}.xf
+       _ = eC{}.xm
+)
+
+// ambiguous selectors due to embedding via type aliases
+type eD struct {
+       eY
+       eZ
+}
+
+var (
+       _ = eD /* ERROR ambiguous selector */ {}.xf
+       _ = eD /* ERROR ambiguous selector */ {}.xm
+)
+
+var (
+       _ interface{ xm() } = eD /* ERROR missing method xm */ {}
+)
\ No newline at end of file
index 47378e744c06c6e0624ef0af2dffdc4bea08cf97..0f8a7adc2470279311079997189268c8c2ad3d2f 100644 (file)
@@ -56,6 +56,7 @@ func RelativeTo(pkg *Package) Qualifier {
 // This flag is exported in the x/tools/go/types package. We don't
 // need it at the moment in the std repo and so we don't export it
 // anymore. We should eventually try to remove it altogether.
+// TODO(gri) remove this
 var gcCompatibilityMode bool
 
 // TypeString returns the string representation of typ.
index ecc0a7da02127aae70e43027e35ae0d61aed990a..1e906fc4d88dd82098ecbed4b033ac114ffa3a40 100644 (file)
@@ -45,17 +45,6 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
                delete(check.unusedDotImports[scope], pkg)
        }
 
-       // Alias-related code. Keep for now.
-       // An alias stands for the original object; use that one instead.
-       // TODO(gri) We should be able to factor out the Typ[Invalid] test.
-       // if alias, _ := obj.(*Alias); alias != nil {
-       //      obj = original(obj)
-       //      if obj == nil || typ == Typ[Invalid] {
-       //              return
-       //      }
-       //      assert(typ == obj.Type())
-       // }
-
        switch obj := obj.(type) {
        case *PkgName:
                check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
@@ -661,47 +650,41 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
                        }
                } else {
                        // anonymous field
-                       name := anonymousFieldIdent(f.Type)
+                       // spec: "An embedded type must be specified as a type name T or as a pointer
+                       // to a non-interface type name *T, and T itself may not be a pointer type."
                        pos := f.Type.Pos()
+                       name := anonymousFieldIdent(f.Type)
+                       if name == nil {
+                               check.invalidAST(pos, "anonymous field type %s has no name", f.Type)
+                               continue
+                       }
                        t, isPtr := deref(typ)
-                       switch t := t.(type) {
+                       // Because we have a name, typ must be of the form T or *T, where T is the name
+                       // of a (named or alias) type, and t (= deref(typ)) must be the type of T.
+                       switch t := t.Underlying().(type) {
                        case *Basic:
                                if t == Typ[Invalid] {
                                        // error was reported before
                                        continue
                                }
+
                                // unsafe.Pointer is treated like a regular pointer
                                if t.kind == UnsafePointer {
                                        check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
                                        continue
                                }
-                               add(f, name, true, pos)
-
-                       case *Named:
-                               // spec: "An embedded type must be specified as a type name
-                               // T or as a pointer to a non-interface type name *T, and T
-                               // itself may not be a pointer type."
-                               switch u := t.underlying.(type) {
-                               case *Basic:
-                                       // unsafe.Pointer is treated like a regular pointer
-                                       if u.kind == UnsafePointer {
-                                               check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
-                                               continue
-                                       }
-                               case *Pointer:
-                                       check.errorf(pos, "anonymous field type cannot be a pointer")
+
+                       case *Pointer:
+                               check.errorf(pos, "anonymous field type cannot be a pointer")
+                               continue
+
+                       case *Interface:
+                               if isPtr {
+                                       check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
                                        continue
-                               case *Interface:
-                                       if isPtr {
-                                               check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
-                                               continue
-                                       }
                                }
-                               add(f, name, true, pos)
-
-                       default:
-                               check.invalidAST(pos, "anonymous field type %s must be named", typ)
                        }
+                       add(f, name, true, pos)
                }
        }
 
@@ -714,7 +697,10 @@ func anonymousFieldIdent(e ast.Expr) *ast.Ident {
        case *ast.Ident:
                return e
        case *ast.StarExpr:
-               return anonymousFieldIdent(e.X)
+               // *T is valid, but **T is not
+               if _, ok := e.X.(*ast.StarExpr); !ok {
+                       return anonymousFieldIdent(e.X)
+               }
        case *ast.SelectorExpr:
                return e.Sel
        }
index 3cab7288c97f5e8532e22bc796aee90fca8d730f..9e4b86594d8128d93ad406be78c2f3bcbcd365f4 100644 (file)
@@ -420,6 +420,7 @@ func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
 // A LimitedReader reads from R but limits the amount of
 // data returned to just N bytes. Each call to Read
 // updates N to reflect the new amount remaining.
+// Read returns EOF when N <= 0 or when the underlying R returns EOF.
 type LimitedReader struct {
        R Reader // underlying reader
        N int64  // max bytes remaining
index 46e45a60e8b7f3ba719f3146f52a7330bf58c0e8..d784846862c455cd8ce9deef25ddb62db6425a1e 100644 (file)
@@ -4,13 +4,19 @@
 
 package io
 
+type eofReader struct{}
+
+func (eofReader) Read([]byte) (int, error) {
+       return 0, EOF
+}
+
 type multiReader struct {
        readers []Reader
 }
 
 func (mr *multiReader) Read(p []byte) (n int, err error) {
        for len(mr.readers) > 0 {
-               // Optimization to flatten nested multiReaders (Issue 13558)
+               // Optimization to flatten nested multiReaders (Issue 13558).
                if len(mr.readers) == 1 {
                        if r, ok := mr.readers[0].(*multiReader); ok {
                                mr.readers = r.readers
@@ -19,7 +25,9 @@ func (mr *multiReader) Read(p []byte) (n int, err error) {
                }
                n, err = mr.readers[0].Read(p)
                if err == EOF {
-                       mr.readers[0] = nil // permit earlier GC
+                       // Use eofReader instead of nil to avoid nil panic
+                       // after performing flatten (Issue 18232).
+                       mr.readers[0] = eofReader{} // permit earlier GC
                        mr.readers = mr.readers[1:]
                }
                if n > 0 || err != EOF {
index 16e351a87911ec0877f4b2f6c9d55dab0b116ce7..1a6292fa8ac2c59c0bfae489d304d7fb76e4fa7d 100644 (file)
@@ -264,3 +264,27 @@ func TestMultiReaderFreesExhaustedReaders(t *testing.T) {
                t.Fatalf(`ReadFull = %d (%q), %v; want 2, "ar", nil`, n, buf[:n], err)
        }
 }
+
+func TestInterleavedMultiReader(t *testing.T) {
+       r1 := strings.NewReader("123")
+       r2 := strings.NewReader("45678")
+
+       mr1 := MultiReader(r1, r2)
+       mr2 := MultiReader(mr1)
+
+       buf := make([]byte, 4)
+
+       // Have mr2 use mr1's []Readers.
+       // Consume r1 (and clear it for GC to handle) and consume part of r2.
+       n, err := ReadFull(mr2, buf)
+       if got := string(buf[:n]); got != "1234" || err != nil {
+               t.Errorf(`ReadFull(mr2) = (%q, %v), want ("1234", nil)`, got, err)
+       }
+
+       // Consume the rest of r2 via mr1.
+       // This should not panic even though mr2 cleared r1.
+       n, err = ReadFull(mr1, buf)
+       if got := string(buf[:n]); got != "5678" || err != nil {
+               t.Errorf(`ReadFull(mr1) = (%q, %v), want ("5678", nil)`, got, err)
+       }
+}
index 6145872391f8b59e4f6542a80261029db1f42e6c..b6e7755f64cc40cf6c461330fd3bbeba550da826 100644 (file)
@@ -85,6 +85,7 @@ func (p *pipe) write(b []byte) (n int, err error) {
                }
                if p.werr != nil {
                        err = ErrClosedPipe
+                       break
                }
                p.wwait.Wait()
        }
index b16e6530693578680d79fe5794ef7818a141d635..95930e86a4ebbd134da26b5f6f663bcfdb16c306 100644 (file)
@@ -247,6 +247,18 @@ func TestPipeWriteClose(t *testing.T) {
        }
 }
 
+// Test close on Write side during Write.
+func TestPipeWriteClose2(t *testing.T) {
+       c := make(chan int, 1)
+       _, w := Pipe()
+       go delayClose(t, w, c, pipeTest{})
+       n, err := w.Write(make([]byte, 64))
+       <-c
+       if n != 0 || err != ErrClosedPipe {
+               t.Errorf("write to closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
+       }
+}
+
 func TestWriteEmpty(t *testing.T) {
        r, w := Pipe()
        go func() {
index a2c1b580f524e453a61d8ed45cfdbb4ead2f1ab5..1d8dabce12b65ad0bdaa03b2aac66c2d6dfe972b 100644 (file)
@@ -404,8 +404,11 @@ func (x *Int) BitLen() int {
 
 // Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
 // If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
-// See Knuth, volume 2, section 4.6.3.
+//
+// Modular exponentation of inputs of a particular size is not a
+// cryptographically constant-time operation.
 func (z *Int) Exp(x, y, m *Int) *Int {
+       // See Knuth, volume 2, section 4.6.3.
        var yWords nat
        if !y.neg {
                yWords = y.abs
index 0b9d160fd432cfca79a241cfe1cfd819e8e1fb2f..1ab9fc53261c445ef167f0e9fee7acabbcf89e9f 100644 (file)
@@ -188,33 +188,17 @@ func (s *byRFC6724) Less(i, j int) bool {
 
        // Rule 9: Use longest matching prefix.
        // When DA and DB belong to the same address family (both are IPv6 or
-       // both are IPv4): If CommonPrefixLen(Source(DA), DA) >
+       // both are IPv4 [but see below]): If CommonPrefixLen(Source(DA), DA) >
        // CommonPrefixLen(Source(DB), DB), then prefer DA.  Similarly, if
        // CommonPrefixLen(Source(DA), DA) < CommonPrefixLen(Source(DB), DB),
        // then prefer DB.
-       da4 := DA.To4() != nil
-       db4 := DB.To4() != nil
-       if da4 == db4 {
+       //
+       // However, applying this rule to IPv4 addresses causes
+       // problems (see issues 13283 and 18518), so limit to IPv6.
+       if DA.To4() == nil && DB.To4() == nil {
                commonA := commonPrefixLen(SourceDA, DA)
                commonB := commonPrefixLen(SourceDB, DB)
 
-               // CommonPrefixLen doesn't really make sense for IPv4, and even
-               // causes problems for common load balancing practices
-               // (e.g., https://golang.org/issue/13283).  Glibc instead only
-               // uses CommonPrefixLen for IPv4 when the source and destination
-               // addresses are on the same subnet, but that requires extra
-               // work to find the netmask for our source addresses. As a
-               // simpler heuristic, we limit its use to when the source and
-               // destination belong to the same special purpose block.
-               if da4 {
-                       if !sameIPv4SpecialPurposeBlock(SourceDA, DA) {
-                               commonA = 0
-                       }
-                       if !sameIPv4SpecialPurposeBlock(SourceDB, DB) {
-                               commonB = 0
-                       }
-               }
-
                if commonA > commonB {
                        return preferDA
                }
@@ -404,28 +388,3 @@ func commonPrefixLen(a, b IP) (cpl int) {
        }
        return
 }
-
-// sameIPv4SpecialPurposeBlock reports whether a and b belong to the same
-// address block reserved by the IANA IPv4 Special-Purpose Address Registry:
-// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
-func sameIPv4SpecialPurposeBlock(a, b IP) bool {
-       a, b = a.To4(), b.To4()
-       if a == nil || b == nil || a[0] != b[0] {
-               return false
-       }
-       // IANA defines more special-purpose blocks, but these are the only
-       // ones likely to be relevant to typical Go systems.
-       switch a[0] {
-       case 10: // 10.0.0.0/8: Private-Use
-               return true
-       case 127: // 127.0.0.0/8: Loopback
-               return true
-       case 169: // 169.254.0.0/16: Link Local
-               return a[1] == 254 && b[1] == 254
-       case 172: // 172.16.0.0/12: Private-Use
-               return a[1]&0xf0 == 16 && b[1]&0xf0 == 16
-       case 192: // 192.168.0.0/16: Private-Use
-               return a[1] == 168 && b[1] == 168
-       }
-       return false
-}
index 80aa4eb195b535ffb1811b2c60660221def9429c..d6e0e63c3b590c0dbef100df972853dfa76376f7 100644 (file)
@@ -117,27 +117,6 @@ func TestSortByRFC6724(t *testing.T) {
                        },
                        reverse: false,
                },
-
-               // Prefer longer common prefixes, but only for IPv4 address
-               // pairs in the same special-purpose block.
-               {
-                       in: []IPAddr{
-                               {IP: ParseIP("1.2.3.4")},
-                               {IP: ParseIP("10.55.0.1")},
-                               {IP: ParseIP("10.66.0.1")},
-                       },
-                       srcs: []IP{
-                               ParseIP("1.2.3.5"),
-                               ParseIP("10.66.1.2"),
-                               ParseIP("10.66.1.2"),
-                       },
-                       want: []IPAddr{
-                               {IP: ParseIP("10.66.0.1")},
-                               {IP: ParseIP("10.55.0.1")},
-                               {IP: ParseIP("1.2.3.4")},
-                       },
-                       reverse: true,
-               },
        }
        for i, tt := range tests {
                inCopy := make([]IPAddr, len(tt.in))
@@ -268,67 +247,3 @@ func TestRFC6724CommonPrefixLength(t *testing.T) {
        }
 
 }
-
-func mustParseCIDRs(t *testing.T, blocks ...string) []*IPNet {
-       res := make([]*IPNet, len(blocks))
-       for i, block := range blocks {
-               var err error
-               _, res[i], err = ParseCIDR(block)
-               if err != nil {
-                       t.Fatalf("ParseCIDR(%s) failed: %v", block, err)
-               }
-       }
-       return res
-}
-
-func TestSameIPv4SpecialPurposeBlock(t *testing.T) {
-       blocks := mustParseCIDRs(t,
-               "10.0.0.0/8",
-               "127.0.0.0/8",
-               "169.254.0.0/16",
-               "172.16.0.0/12",
-               "192.168.0.0/16",
-       )
-
-       addrs := []struct {
-               ip    IP
-               block int // index or -1
-       }{
-               {IP{1, 2, 3, 4}, -1},
-               {IP{2, 3, 4, 5}, -1},
-               {IP{10, 2, 3, 4}, 0},
-               {IP{10, 6, 7, 8}, 0},
-               {IP{127, 0, 0, 1}, 1},
-               {IP{127, 255, 255, 255}, 1},
-               {IP{169, 254, 77, 99}, 2},
-               {IP{169, 254, 44, 22}, 2},
-               {IP{169, 255, 0, 1}, -1},
-               {IP{172, 15, 5, 6}, -1},
-               {IP{172, 16, 32, 41}, 3},
-               {IP{172, 31, 128, 9}, 3},
-               {IP{172, 32, 88, 100}, -1},
-               {IP{192, 168, 1, 1}, 4},
-               {IP{192, 168, 128, 42}, 4},
-               {IP{192, 169, 1, 1}, -1},
-       }
-
-       for i, addr := range addrs {
-               for j, block := range blocks {
-                       got := block.Contains(addr.ip)
-                       want := addr.block == j
-                       if got != want {
-                               t.Errorf("%d/%d. %s.Contains(%s): got %v, want %v", i, j, block, addr.ip, got, want)
-                       }
-               }
-       }
-
-       for i, addr1 := range addrs {
-               for j, addr2 := range addrs {
-                       got := sameIPv4SpecialPurposeBlock(addr1.ip, addr2.ip)
-                       want := addr1.block >= 0 && addr1.block == addr2.block
-                       if got != want {
-                               t.Errorf("%d/%d. sameIPv4SpecialPurposeBlock(%s, %s): got %v, want %v", i, j, addr1.ip, addr2.ip, got, want)
-                       }
-               }
-       }
-}
index 5db35858941fe03d937987507ed4412d2d8b8c9e..50bba5a49e426eb465a1f1910ee0da14150edc8f 100644 (file)
@@ -163,7 +163,7 @@ func parseNetwork(ctx context.Context, net string) (afnet string, proto int, err
        return "", 0, UnknownNetworkError(net)
 }
 
-// resolverAddrList resolves addr using hint and returns a list of
+// resolveAddrList resolves addr using hint and returns a list of
 // addresses. The result contains at least one address when error is
 // nil.
 func (r *Resolver) resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) {
@@ -265,6 +265,9 @@ func (r *Resolver) resolveAddrList(ctx context.Context, op, network, addr string
 //     Dial("ip6:ipv6-icmp", "2001:db8::1")
 //
 // For Unix networks, the address must be a file system path.
+//
+// If the host is resolved to multiple addresses,
+// Dial will try each address in order until one succeeds.
 func Dial(network, address string) (Conn, error) {
        var d Dialer
        return d.Dial(network, address)
@@ -299,6 +302,14 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
 // connected, any expiration of the context will not affect the
 // connection.
 //
+// When using TCP, and the host in the address parameter resolves to multiple
+// network addresses, any dial timeout (from d.Timeout or ctx) is spread
+// over each consecutive dial, such that each is given an appropriate
+// fraction of the time to connect.
+// For example, if a host has 4 IP addresses and the timeout is 1 minute,
+// the connect to each single address will be given 15 seconds to complete
+// before trying the next one.
+//
 // See func Dial for a description of the network and address
 // parameters.
 func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) {
index 6ba8e950b8c1b5b9211b18f76a933eb1519efe8b..9919d72ce3b79b90500835e3a46ec3cf2b38d183 100644 (file)
@@ -142,6 +142,8 @@ func TestDialerDualStackFDLeak(t *testing.T) {
                t.Skipf("%s does not have full support of socktest", runtime.GOOS)
        case "windows":
                t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
+       case "openbsd":
+               testenv.SkipFlaky(t, 15157)
        }
        if !supportsIPv4 || !supportsIPv6 {
                t.Skip("both IPv4 and IPv6 are required")
index 29803028498d123e7fd863f0a6d1901846f47788..4dd4e16b0fdf153ced644c629f67394f5b3797c1 100644 (file)
@@ -444,7 +444,7 @@ func goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder)
                        return
                }
        }
-       ips, err := goLookupIPOrder(ctx, name, order)
+       ips, _, err := goLookupIPCNAMEOrder(ctx, name, order)
        if err != nil {
                return
        }
@@ -472,27 +472,28 @@ func goLookupIPFiles(name string) (addrs []IPAddr) {
 // The libc versions are in cgo_*.go.
 func goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
        order := systemConf().hostLookupOrder(host)
-       return goLookupIPOrder(ctx, host, order)
+       addrs, _, err = goLookupIPCNAMEOrder(ctx, host, order)
+       return
 }
 
-func goLookupIPOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, err error) {
+func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, cname string, err error) {
        if order == hostLookupFilesDNS || order == hostLookupFiles {
                addrs = goLookupIPFiles(name)
                if len(addrs) > 0 || order == hostLookupFiles {
-                       return addrs, nil
+                       return addrs, name, nil
                }
        }
        if !isDomainName(name) {
                // See comment in func lookup above about use of errNoSuchHost.
-               return nil, &DNSError{Err: errNoSuchHost.Error(), Name: name}
+               return nil, "", &DNSError{Err: errNoSuchHost.Error(), Name: name}
        }
        resolvConf.tryUpdate("/etc/resolv.conf")
        resolvConf.mu.RLock()
        conf := resolvConf.dnsConfig
        resolvConf.mu.RUnlock()
        type racer struct {
-               fqdn string
-               rrs  []dnsRR
+               cname string
+               rrs   []dnsRR
                error
        }
        lane := make(chan racer, 1)
@@ -501,20 +502,23 @@ func goLookupIPOrder(ctx context.Context, name string, order hostLookupOrder) (a
        for _, fqdn := range conf.nameList(name) {
                for _, qtype := range qtypes {
                        go func(qtype uint16) {
-                               _, rrs, err := tryOneName(ctx, conf, fqdn, qtype)
-                               lane <- racer{fqdn, rrs, err}
+                               cname, rrs, err := tryOneName(ctx, conf, fqdn, qtype)
+                               lane <- racer{cname, rrs, err}
                        }(qtype)
                }
                for range qtypes {
                        racer := <-lane
                        if racer.error != nil {
                                // Prefer error for original name.
-                               if lastErr == nil || racer.fqdn == name+"." {
+                               if lastErr == nil || fqdn == name+"." {
                                        lastErr = racer.error
                                }
                                continue
                        }
                        addrs = append(addrs, addrRecordList(racer.rrs)...)
+                       if cname == "" {
+                               cname = racer.cname
+                       }
                }
                if len(addrs) > 0 {
                        break
@@ -532,24 +536,16 @@ func goLookupIPOrder(ctx context.Context, name string, order hostLookupOrder) (a
                        addrs = goLookupIPFiles(name)
                }
                if len(addrs) == 0 && lastErr != nil {
-                       return nil, lastErr
+                       return nil, "", lastErr
                }
        }
-       return addrs, nil
+       return addrs, cname, nil
 }
 
-// goLookupCNAME is the native Go implementation of LookupCNAME.
-// Used only if cgoLookupCNAME refuses to handle the request
-// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupCNAME(ctx context.Context, name string) (cname string, err error) {
-       _, rrs, err := lookup(ctx, name, dnsTypeCNAME)
-       if err != nil {
-               return
-       }
-       cname = rrs[0].(*dnsRR_CNAME).Cname
+// goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME.
+func goLookupCNAME(ctx context.Context, host string) (cname string, err error) {
+       order := systemConf().hostLookupOrder(host)
+       _, cname, err = goLookupIPCNAMEOrder(ctx, host, order)
        return
 }
 
index 7dc364de508f37dd3dee9966d97766d12bb99c2d..85267bbddc02a28e8d0ea3c1d8dee8bcee29ca34 100644 (file)
@@ -455,14 +455,14 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
                name := fmt.Sprintf("order %v", order)
 
                // First ensure that we get an error when contacting a non-existent host.
-               _, err := goLookupIPOrder(context.Background(), "notarealhost", order)
+               _, _, err := goLookupIPCNAMEOrder(context.Background(), "notarealhost", order)
                if err == nil {
                        t.Errorf("%s: expected error while looking up name not in hosts file", name)
                        continue
                }
 
                // Now check that we get an address when the name appears in the hosts file.
-               addrs, err := goLookupIPOrder(context.Background(), "thor", order) // entry is in "testdata/hosts"
+               addrs, _, err := goLookupIPCNAMEOrder(context.Background(), "thor", order) // entry is in "testdata/hosts"
                if err != nil {
                        t.Errorf("%s: expected to successfully lookup host entry", name)
                        continue
@@ -744,8 +744,11 @@ func TestRetryTimeout(t *testing.T) {
        }
        defer conf.teardown()
 
-       if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will timeout
-               "nameserver 192.0.2.2"}); err != nil {
+       testConf := []string{
+               "nameserver 192.0.2.1", // the one that will timeout
+               "nameserver 192.0.2.2",
+       }
+       if err := conf.writeAndUpdate(testConf); err != nil {
                t.Fatal(err)
        }
 
@@ -771,28 +774,10 @@ func TestRetryTimeout(t *testing.T) {
                        t.Error("deadline didn't change")
                }
 
-               r := &dnsMsg{
-                       dnsMsgHdr: dnsMsgHdr{
-                               id:                  q.id,
-                               response:            true,
-                               recursion_available: true,
-                       },
-                       question: q.question,
-                       answer: []dnsRR{
-                               &dnsRR_CNAME{
-                                       Hdr: dnsRR_Header{
-                                               Name:   q.question[0].Name,
-                                               Rrtype: dnsTypeCNAME,
-                                               Class:  dnsClassINET,
-                                       },
-                                       Cname: "golang.org",
-                               },
-                       },
-               }
-               return r, nil
+               return mockTXTResponse(q), nil
        }
 
-       _, err = goLookupCNAME(context.Background(), "www.golang.org")
+       _, err = LookupTXT("www.golang.org")
        if err != nil {
                t.Fatal(err)
        }
@@ -838,36 +823,40 @@ func testRotate(t *testing.T, rotate bool, nameservers, wantServers []string) {
        var usedServers []string
        d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
                usedServers = append(usedServers, s)
-
-               r := &dnsMsg{
-                       dnsMsgHdr: dnsMsgHdr{
-                               id:                  q.id,
-                               response:            true,
-                               recursion_available: true,
-                       },
-                       question: q.question,
-                       answer: []dnsRR{
-                               &dnsRR_CNAME{
-                                       Hdr: dnsRR_Header{
-                                               Name:   q.question[0].Name,
-                                               Rrtype: dnsTypeCNAME,
-                                               Class:  dnsClassINET,
-                                       },
-                                       Cname: "golang.org",
-                               },
-                       },
-               }
-               return r, nil
+               return mockTXTResponse(q), nil
        }
 
        // len(nameservers) + 1 to allow rotation to get back to start
        for i := 0; i < len(nameservers)+1; i++ {
-               if _, err := goLookupCNAME(context.Background(), "www.golang.org"); err != nil {
+               if _, err := LookupTXT("www.golang.org"); err != nil {
                        t.Fatal(err)
                }
        }
 
        if !reflect.DeepEqual(usedServers, wantServers) {
-               t.Fatalf("rotate=%t got used servers:\n%v\nwant:\n%v", rotate, usedServers, wantServers)
+               t.Errorf("rotate=%t got used servers:\n%v\nwant:\n%v", rotate, usedServers, wantServers)
        }
 }
+
+func mockTXTResponse(q *dnsMsg) *dnsMsg {
+       r := &dnsMsg{
+               dnsMsgHdr: dnsMsgHdr{
+                       id:                  q.id,
+                       response:            true,
+                       recursion_available: true,
+               },
+               question: q.question,
+               answer: []dnsRR{
+                       &dnsRR_TXT{
+                               Hdr: dnsRR_Header{
+                                       Name:   q.question[0].Name,
+                                       Rrtype: dnsTypeTXT,
+                                       Class:  dnsClassINET,
+                               },
+                               Txt: "ok",
+                       },
+               },
+       }
+
+       return r
+}
index fe2b0196ef66840049e8886cc98c18684876079a..0005538e70bd80ba432489360d1fea76dd62a4df 100644 (file)
@@ -163,22 +163,23 @@ func refererForURL(lastReq, newReq *url.URL) string {
        return referer
 }
 
-func (c *Client) send(req *Request, deadline time.Time) (*Response, error) {
+// didTimeout is non-nil only if err != nil.
+func (c *Client) send(req *Request, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
        if c.Jar != nil {
                for _, cookie := range c.Jar.Cookies(req.URL) {
                        req.AddCookie(cookie)
                }
        }
-       resp, err := send(req, c.transport(), deadline)
+       resp, didTimeout, err = send(req, c.transport(), deadline)
        if err != nil {
-               return nil, err
+               return nil, didTimeout, err
        }
        if c.Jar != nil {
                if rc := resp.Cookies(); len(rc) > 0 {
                        c.Jar.SetCookies(req.URL, rc)
                }
        }
-       return resp, nil
+       return resp, nil, nil
 }
 
 func (c *Client) deadline() time.Time {
@@ -197,22 +198,22 @@ func (c *Client) transport() RoundTripper {
 
 // send issues an HTTP request.
 // Caller should close resp.Body when done reading from it.
-func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error) {
+func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
        req := ireq // req is either the original request, or a modified fork
 
        if rt == nil {
                req.closeBody()
-               return nil, errors.New("http: no Client.Transport or DefaultTransport")
+               return nil, alwaysFalse, errors.New("http: no Client.Transport or DefaultTransport")
        }
 
        if req.URL == nil {
                req.closeBody()
-               return nil, errors.New("http: nil Request.URL")
+               return nil, alwaysFalse, errors.New("http: nil Request.URL")
        }
 
        if req.RequestURI != "" {
                req.closeBody()
-               return nil, errors.New("http: Request.RequestURI can't be set in client requests.")
+               return nil, alwaysFalse, errors.New("http: Request.RequestURI can't be set in client requests.")
        }
 
        // forkReq forks req into a shallow clone of ireq the first
@@ -245,7 +246,7 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
        }
        stopTimer, didTimeout := setRequestCancel(req, rt, deadline)
 
-       resp, err := rt.RoundTrip(req)
+       resp, err = rt.RoundTrip(req)
        if err != nil {
                stopTimer()
                if resp != nil {
@@ -259,7 +260,7 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
                                err = errors.New("http: server gave HTTP response to HTTPS client")
                        }
                }
-               return nil, err
+               return nil, didTimeout, err
        }
        if !deadline.IsZero() {
                resp.Body = &cancelTimerBody{
@@ -268,12 +269,17 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
                        reqDidTimeout: didTimeout,
                }
        }
-       return resp, nil
+       return resp, nil, nil
 }
 
 // setRequestCancel sets the Cancel field of req, if deadline is
 // non-zero. The RoundTripper's type is used to determine whether the legacy
 // CancelRequest behavior should be used.
+//
+// As background, there are three ways to cancel a request:
+// First was Transport.CancelRequest. (deprecated)
+// Second was Request.Cancel (this mechanism).
+// Third was Request.Context.
 func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), didTimeout func() bool) {
        if deadline.IsZero() {
                return nop, alwaysFalse
@@ -285,7 +291,7 @@ func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTi
        req.Cancel = cancel
 
        doCancel := func() {
-               // The new way:
+               // The newer way (the second way in the func comment):
                close(cancel)
 
                // The legacy compatibility way, used only
@@ -407,19 +413,28 @@ func (c *Client) checkRedirect(req *Request, via []*Request) error {
 
 // redirectBehavior describes what should happen when the
 // client encounters a 3xx status code from the server
-func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirectMethod string, shouldRedirect bool) {
+func redirectBehavior(reqMethod string, resp *Response, ireq *Request) (redirectMethod string, shouldRedirect, includeBody bool) {
        switch resp.StatusCode {
        case 301, 302, 303:
-               redirectMethod = "GET"
+               redirectMethod = reqMethod
                shouldRedirect = true
+               includeBody = false
+
+               // RFC 2616 allowed automatic redirection only with GET and
+               // HEAD requests. RFC 7231 lifts this restriction, but we still
+               // restrict other methods to GET to maintain compatibility.
+               // See Issue 18570.
+               if reqMethod != "GET" && reqMethod != "HEAD" {
+                       redirectMethod = "GET"
+               }
        case 307, 308:
                redirectMethod = reqMethod
                shouldRedirect = true
+               includeBody = true
 
                // Treat 307 and 308 specially, since they're new in
                // Go 1.8, and they also require re-sending the request body.
-               loc := resp.Header.Get("Location")
-               if loc == "" {
+               if resp.Header.Get("Location") == "" {
                        // 308s have been observed in the wild being served
                        // without Location headers. Since Go 1.7 and earlier
                        // didn't follow these codes, just stop here instead
@@ -428,7 +443,6 @@ func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirec
                        shouldRedirect = false
                        break
                }
-               ireq := via[0]
                if ireq.GetBody == nil && ireq.outgoingLength() != 0 {
                        // We had a request body, and 307/308 require
                        // re-sending it, but GetBody is not defined. So just
@@ -437,8 +451,7 @@ func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirec
                        shouldRedirect = false
                }
        }
-
-       return redirectMethod, shouldRedirect
+       return redirectMethod, shouldRedirect, includeBody
 }
 
 // Do sends an HTTP request and returns an HTTP response, following
@@ -464,6 +477,16 @@ func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirec
 // the returned Response.Body is already closed.
 //
 // Generally Get, Post, or PostForm will be used instead of Do.
+//
+// If the server replies with a redirect, the Client first uses the
+// CheckRedirect function to determine whether the redirect should be
+// followed. If permitted, a 301, 302, or 303 redirect causes
+// subsequent requests to use HTTP method GET
+// (or HEAD if the original request was HEAD), with no body.
+// A 307 or 308 redirect preserves the original HTTP method and body,
+// provided that the Request.GetBody function is defined.
+// The NewRequest function automatically sets GetBody for common
+// standard library body types.
 func (c *Client) Do(req *Request) (*Response, error) {
        if req.URL == nil {
                req.closeBody()
@@ -471,11 +494,14 @@ func (c *Client) Do(req *Request) (*Response, error) {
        }
 
        var (
-               deadline       = c.deadline()
-               reqs           []*Request
-               resp           *Response
-               copyHeaders    = c.makeHeadersCopier(req)
+               deadline    = c.deadline()
+               reqs        []*Request
+               resp        *Response
+               copyHeaders = c.makeHeadersCopier(req)
+
+               // Redirect behavior:
                redirectMethod string
+               includeBody    bool
        )
        uerr := func(err error) error {
                req.closeBody()
@@ -513,7 +539,7 @@ func (c *Client) Do(req *Request) (*Response, error) {
                                Cancel:   ireq.Cancel,
                                ctx:      ireq.ctx,
                        }
-                       if ireq.GetBody != nil {
+                       if includeBody && ireq.GetBody != nil {
                                req.Body, err = ireq.GetBody()
                                if err != nil {
                                        return nil, uerr(err)
@@ -565,8 +591,9 @@ func (c *Client) Do(req *Request) (*Response, error) {
 
                reqs = append(reqs, req)
                var err error
-               if resp, err = c.send(req, deadline); err != nil {
-                       if !deadline.IsZero() && !time.Now().Before(deadline) {
+               var didTimeout func() bool
+               if resp, didTimeout, err = c.send(req, deadline); err != nil {
+                       if !deadline.IsZero() && didTimeout() {
                                err = &httpError{
                                        err:     err.Error() + " (Client.Timeout exceeded while awaiting headers)",
                                        timeout: true,
@@ -576,7 +603,7 @@ func (c *Client) Do(req *Request) (*Response, error) {
                }
 
                var shouldRedirect bool
-               redirectMethod, shouldRedirect = redirectBehavior(req.Method, resp, reqs)
+               redirectMethod, shouldRedirect, includeBody = redirectBehavior(req.Method, resp, reqs[0])
                if !shouldRedirect {
                        return resp, nil
                }
@@ -666,6 +693,9 @@ func defaultCheckRedirect(req *Request, via []*Request) error {
 // Post is a wrapper around DefaultClient.Post.
 //
 // To set custom headers, use NewRequest and DefaultClient.Do.
+//
+// See the Client.Do method documentation for details on how redirects
+// are handled.
 func Post(url string, contentType string, body io.Reader) (resp *Response, err error) {
        return DefaultClient.Post(url, contentType, body)
 }
@@ -678,6 +708,9 @@ func Post(url string, contentType string, body io.Reader) (resp *Response, err e
 // request.
 //
 // To set custom headers, use NewRequest and Client.Do.
+//
+// See the Client.Do method documentation for details on how redirects
+// are handled.
 func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error) {
        req, err := NewRequest("POST", url, body)
        if err != nil {
@@ -697,6 +730,9 @@ func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Res
 // Caller should close resp.Body when done reading from it.
 //
 // PostForm is a wrapper around DefaultClient.PostForm.
+//
+// See the Client.Do method documentation for details on how redirects
+// are handled.
 func PostForm(url string, data url.Values) (resp *Response, err error) {
        return DefaultClient.PostForm(url, data)
 }
@@ -709,6 +745,9 @@ func PostForm(url string, data url.Values) (resp *Response, err error) {
 //
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
+//
+// See the Client.Do method documentation for details on how redirects
+// are handled.
 func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
        return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
 }
index a5f58cb5cb0ed14adbccd78316cc8a7e54156a33..4f674dd8d6c785ca45b06781f2b2a247344db6ce 100644 (file)
@@ -26,6 +26,7 @@ import (
        "strconv"
        "strings"
        "sync"
+       "sync/atomic"
        "testing"
        "time"
 )
@@ -359,25 +360,25 @@ func TestPostRedirects(t *testing.T) {
        wantSegments := []string{
                `POST / "first"`,
                `POST /?code=301&next=302 "c301"`,
-               `GET /?code=302 "c301"`,
-               `GET / "c301"`,
+               `GET /?code=302 ""`,
+               `GET / ""`,
                `POST /?code=302&next=302 "c302"`,
-               `GET /?code=302 "c302"`,
-               `GET / "c302"`,
+               `GET /?code=302 ""`,
+               `GET / ""`,
                `POST /?code=303&next=301 "c303wc301"`,
-               `GET /?code=301 "c303wc301"`,
-               `GET / "c303wc301"`,
+               `GET /?code=301 ""`,
+               `GET / ""`,
                `POST /?code=304 "c304"`,
                `POST /?code=305 "c305"`,
                `POST /?code=307&next=303,308,302 "c307"`,
                `POST /?code=303&next=308,302 "c307"`,
-               `GET /?code=308&next=302 "c307"`,
+               `GET /?code=308&next=302 ""`,
                `GET /?code=302 "c307"`,
-               `GET / "c307"`,
+               `GET / ""`,
                `POST /?code=308&next=302,301 "c308"`,
                `POST /?code=302&next=301 "c308"`,
-               `GET /?code=301 "c308"`,
-               `GET / "c308"`,
+               `GET /?code=301 ""`,
+               `GET / ""`,
                `POST /?code=404 "c404"`,
        }
        want := strings.Join(wantSegments, "\n")
@@ -398,20 +399,20 @@ func TestDeleteRedirects(t *testing.T) {
        wantSegments := []string{
                `DELETE / "first"`,
                `DELETE /?code=301&next=302,308 "c301"`,
-               `GET /?code=302&next=308 "c301"`,
-               `GET /?code=308 "c301"`,
+               `GET /?code=302&next=308 ""`,
+               `GET /?code=308 ""`,
                `GET / "c301"`,
                `DELETE /?code=302&next=302 "c302"`,
-               `GET /?code=302 "c302"`,
-               `GET / "c302"`,
+               `GET /?code=302 ""`,
+               `GET / ""`,
                `DELETE /?code=303 "c303"`,
-               `GET / "c303"`,
+               `GET / ""`,
                `DELETE /?code=307&next=301,308,303,302,304 "c307"`,
                `DELETE /?code=301&next=308,303,302,304 "c307"`,
-               `GET /?code=308&next=303,302,304 "c307"`,
+               `GET /?code=308&next=303,302,304 ""`,
                `GET /?code=303&next=302,304 "c307"`,
-               `GET /?code=302&next=304 "c307"`,
-               `GET /?code=304 "c307"`,
+               `GET /?code=302&next=304 ""`,
+               `GET /?code=304 ""`,
                `DELETE /?code=308&next=307 "c308"`,
                `DELETE /?code=307 "c308"`,
                `DELETE / "c308"`,
@@ -431,7 +432,11 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa
        ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
                log.Lock()
                slurp, _ := ioutil.ReadAll(r.Body)
-               fmt.Fprintf(&log.Buffer, "%s %s %q\n", r.Method, r.RequestURI, slurp)
+               fmt.Fprintf(&log.Buffer, "%s %s %q", r.Method, r.RequestURI, slurp)
+               if cl := r.Header.Get("Content-Length"); r.Method == "GET" && len(slurp) == 0 && (r.ContentLength != 0 || cl != "") {
+                       fmt.Fprintf(&log.Buffer, " (but with body=%T, content-length = %v, %q)", r.Body, r.ContentLength, cl)
+               }
+               log.WriteByte('\n')
                log.Unlock()
                urlQuery := r.URL.Query()
                if v := urlQuery.Get("code"); v != "" {
@@ -474,7 +479,24 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa
        want = strings.TrimSpace(want)
 
        if got != want {
-               t.Errorf("Log differs.\n Got:\n%s\nWant:\n%s\n", got, want)
+               got, want, lines := removeCommonLines(got, want)
+               t.Errorf("Log differs after %d common lines.\n\nGot:\n%s\n\nWant:\n%s\n", lines, got, want)
+       }
+}
+
+func removeCommonLines(a, b string) (asuffix, bsuffix string, commonLines int) {
+       for {
+               nl := strings.IndexByte(a, '\n')
+               if nl < 0 {
+                       return a, b, commonLines
+               }
+               line := a[:nl+1]
+               if !strings.HasPrefix(b, line) {
+                       return a, b, commonLines
+               }
+               commonLines++
+               a = a[len(line):]
+               b = b[len(line):]
        }
 }
 
@@ -1664,9 +1686,9 @@ func TestClientRedirectTypes(t *testing.T) {
                3: {method: "POST", serverStatus: 307, wantMethod: "POST"},
                4: {method: "POST", serverStatus: 308, wantMethod: "POST"},
 
-               5: {method: "HEAD", serverStatus: 301, wantMethod: "GET"},
-               6: {method: "HEAD", serverStatus: 302, wantMethod: "GET"},
-               7: {method: "HEAD", serverStatus: 303, wantMethod: "GET"},
+               5: {method: "HEAD", serverStatus: 301, wantMethod: "HEAD"},
+               6: {method: "HEAD", serverStatus: 302, wantMethod: "HEAD"},
+               7: {method: "HEAD", serverStatus: 303, wantMethod: "HEAD"},
                8: {method: "HEAD", serverStatus: 307, wantMethod: "HEAD"},
                9: {method: "HEAD", serverStatus: 308, wantMethod: "HEAD"},
 
@@ -1738,3 +1760,76 @@ func TestClientRedirectTypes(t *testing.T) {
                res.Body.Close()
        }
 }
+
+// issue18239Body is an io.ReadCloser for TestTransportBodyReadError.
+// Its Read returns readErr and increments *readCalls atomically.
+// Its Close returns nil and increments *closeCalls atomically.
+type issue18239Body struct {
+       readCalls  *int32
+       closeCalls *int32
+       readErr    error
+}
+
+func (b issue18239Body) Read([]byte) (int, error) {
+       atomic.AddInt32(b.readCalls, 1)
+       return 0, b.readErr
+}
+
+func (b issue18239Body) Close() error {
+       atomic.AddInt32(b.closeCalls, 1)
+       return nil
+}
+
+// Issue 18239: make sure the Transport doesn't retry requests with bodies.
+// (Especially if Request.GetBody is not defined.)
+func TestTransportBodyReadError(t *testing.T) {
+       setParallel(t)
+       defer afterTest(t)
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               if r.URL.Path == "/ping" {
+                       return
+               }
+               buf := make([]byte, 1)
+               n, err := r.Body.Read(buf)
+               w.Header().Set("X-Body-Read", fmt.Sprintf("%v, %v", n, err))
+       }))
+       defer ts.Close()
+       tr := &Transport{}
+       defer tr.CloseIdleConnections()
+       c := &Client{Transport: tr}
+
+       // Do one initial successful request to create an idle TCP connection
+       // for the subsequent request to reuse. (The Transport only retries
+       // requests on reused connections.)
+       res, err := c.Get(ts.URL + "/ping")
+       if err != nil {
+               t.Fatal(err)
+       }
+       res.Body.Close()
+
+       var readCallsAtomic int32
+       var closeCallsAtomic int32 // atomic
+       someErr := errors.New("some body read error")
+       body := issue18239Body{&readCallsAtomic, &closeCallsAtomic, someErr}
+
+       req, err := NewRequest("POST", ts.URL, body)
+       if err != nil {
+               t.Fatal(err)
+       }
+       _, err = tr.RoundTrip(req)
+       if err != someErr {
+               t.Errorf("Got error: %v; want Request.Body read error: %v", err, someErr)
+       }
+
+       // And verify that our Body wasn't used multiple times, which
+       // would indicate retries. (as it buggily was during part of
+       // Go 1.8's dev cycle)
+       readCalls := atomic.LoadInt32(&readCallsAtomic)
+       closeCalls := atomic.LoadInt32(&closeCallsAtomic)
+       if readCalls != 1 {
+               t.Errorf("read calls = %d; want 1", readCalls)
+       }
+       if closeCalls != 1 {
+               t.Errorf("close calls = %d; want 1", closeCalls)
+       }
+}
index fd899034a7e747acee83edc2b0eee86837e34b52..4536b2ff5deb1ae8a7d464107a8dac66b7da9da3 100644 (file)
@@ -855,10 +855,12 @@ type http2Framer struct {
        // If the limit is hit, MetaHeadersFrame.Truncated is set true.
        MaxHeaderListSize uint32
 
-       logReads bool
+       logReads, logWrites bool
 
-       debugFramer    *http2Framer // only use for logging written writes
-       debugFramerBuf *bytes.Buffer
+       debugFramer       *http2Framer // only use for logging written writes
+       debugFramerBuf    *bytes.Buffer
+       debugReadLoggerf  func(string, ...interface{})
+       debugWriteLoggerf func(string, ...interface{})
 }
 
 func (fr *http2Framer) maxHeaderListSize() uint32 {
@@ -892,7 +894,7 @@ func (f *http2Framer) endWrite() error {
                byte(length>>16),
                byte(length>>8),
                byte(length))
-       if http2logFrameWrites {
+       if f.logWrites {
                f.logWrite()
        }
 
@@ -914,10 +916,10 @@ func (f *http2Framer) logWrite() {
        f.debugFramerBuf.Write(f.wbuf)
        fr, err := f.debugFramer.ReadFrame()
        if err != nil {
-               log.Printf("http2: Framer %p: failed to decode just-written frame", f)
+               f.debugWriteLoggerf("http2: Framer %p: failed to decode just-written frame", f)
                return
        }
-       log.Printf("http2: Framer %p: wrote %v", f, http2summarizeFrame(fr))
+       f.debugWriteLoggerf("http2: Framer %p: wrote %v", f, http2summarizeFrame(fr))
 }
 
 func (f *http2Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }
@@ -938,9 +940,12 @@ const (
 // NewFramer returns a Framer that writes frames to w and reads them from r.
 func http2NewFramer(w io.Writer, r io.Reader) *http2Framer {
        fr := &http2Framer{
-               w:        w,
-               r:        r,
-               logReads: http2logFrameReads,
+               w:                 w,
+               r:                 r,
+               logReads:          http2logFrameReads,
+               logWrites:         http2logFrameWrites,
+               debugReadLoggerf:  log.Printf,
+               debugWriteLoggerf: log.Printf,
        }
        fr.getReadBuf = func(size uint32) []byte {
                if cap(fr.readBuf) >= int(size) {
@@ -1022,7 +1027,7 @@ func (fr *http2Framer) ReadFrame() (http2Frame, error) {
                return nil, err
        }
        if fr.logReads {
-               log.Printf("http2: Framer %p: read %v", fr, http2summarizeFrame(f))
+               fr.debugReadLoggerf("http2: Framer %p: read %v", fr, http2summarizeFrame(f))
        }
        if fh.Type == http2FrameHeaders && fr.ReadMetaHeaders != nil {
                return fr.readMetaFrame(f.(*http2HeadersFrame))
@@ -1922,8 +1927,8 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
        hdec.SetEmitEnabled(true)
        hdec.SetMaxStringLength(fr.maxHeaderStringLen())
        hdec.SetEmitFunc(func(hf hpack.HeaderField) {
-               if http2VerboseLogs && http2logFrameReads {
-                       log.Printf("http2: decoded hpack field %+v", hf)
+               if http2VerboseLogs && fr.logReads {
+                       fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
                }
                if !httplex.ValidHeaderFieldValue(hf.Value) {
                        invalid = http2headerFieldValueError(hf.Value)
@@ -3136,6 +3141,10 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
                pushEnabled:       true,
        }
 
+       if sc.hs.WriteTimeout != 0 {
+               sc.conn.SetWriteDeadline(time.Time{})
+       }
+
        if s.NewWriteScheduler != nil {
                sc.writeSched = s.NewWriteScheduler()
        } else {
@@ -3285,8 +3294,7 @@ type http2stream struct {
        numTrailerValues int64
        weight           uint8
        state            http2streamState
-       sentReset        bool   // only true once detached from streams map
-       gotReset         bool   // only true once detacted from streams map
+       resetQueued      bool   // RST_STREAM queued for write; set by sc.resetStream
        gotTrailerHeader bool   // HEADER frame for trailers was seen
        wroteHeaders     bool   // whether we wrote headers (not status 100)
        reqBuf           []byte // if non-nil, body pipe buffer to return later at EOF
@@ -3682,13 +3690,25 @@ func (sc *http2serverConn) writeFrameFromHandler(wr http2FrameWriteRequest) erro
 func (sc *http2serverConn) writeFrame(wr http2FrameWriteRequest) {
        sc.serveG.check()
 
+       // If true, wr will not be written and wr.done will not be signaled.
        var ignoreWrite bool
 
+       if wr.StreamID() != 0 {
+               _, isReset := wr.write.(http2StreamError)
+               if state, _ := sc.state(wr.StreamID()); state == http2stateClosed && !isReset {
+                       ignoreWrite = true
+               }
+       }
+
        switch wr.write.(type) {
        case *http2writeResHeaders:
                wr.stream.wroteHeaders = true
        case http2write100ContinueHeadersFrame:
                if wr.stream.wroteHeaders {
+
+                       if wr.done != nil {
+                               panic("wr.done != nil for write100ContinueHeadersFrame")
+                       }
                        ignoreWrite = true
                }
        }
@@ -3712,14 +3732,14 @@ func (sc *http2serverConn) startFrameWrite(wr http2FrameWriteRequest) {
        if st != nil {
                switch st.state {
                case http2stateHalfClosedLocal:
-                       panic("internal error: attempt to send frame on half-closed-local stream")
-               case http2stateClosed:
-                       if st.sentReset || st.gotReset {
+                       switch wr.write.(type) {
+                       case http2StreamError, http2handlerPanicRST, http2writeWindowUpdate:
 
-                               sc.scheduleFrameWrite()
-                               return
+                       default:
+                               panic(fmt.Sprintf("internal error: attempt to send frame on a half-closed-local stream: %v", wr))
                        }
-                       panic(fmt.Sprintf("internal error: attempt to send a write %v on a closed stream", wr))
+               case http2stateClosed:
+                       panic(fmt.Sprintf("internal error: attempt to send frame on a closed stream: %v", wr))
                }
        }
        if wpp, ok := wr.write.(*http2writePushPromise); ok {
@@ -3727,9 +3747,7 @@ func (sc *http2serverConn) startFrameWrite(wr http2FrameWriteRequest) {
                wpp.promisedID, err = wpp.allocatePromisedID()
                if err != nil {
                        sc.writingFrameAsync = false
-                       if wr.done != nil {
-                               wr.done <- err
-                       }
+                       wr.replyToWriter(err)
                        return
                }
        }
@@ -3762,24 +3780,9 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
        sc.writingFrameAsync = false
 
        wr := res.wr
-       st := wr.stream
-
-       closeStream := http2endsStream(wr.write)
-
-       if _, ok := wr.write.(http2handlerPanicRST); ok {
-               sc.closeStream(st, http2errHandlerPanicked)
-       }
-
-       if ch := wr.done; ch != nil {
-               select {
-               case ch <- res.err:
-               default:
-                       panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
-               }
-       }
-       wr.write = nil
 
-       if closeStream {
+       if http2writeEndsStream(wr.write) {
+               st := wr.stream
                if st == nil {
                        panic("internal error: expecting non-nil stream")
                }
@@ -3787,13 +3790,24 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
                case http2stateOpen:
 
                        st.state = http2stateHalfClosedLocal
-                       errCancel := http2streamError(st.id, http2ErrCodeCancel)
-                       sc.resetStream(errCancel)
+                       sc.resetStream(http2streamError(st.id, http2ErrCodeCancel))
                case http2stateHalfClosedRemote:
                        sc.closeStream(st, http2errHandlerComplete)
                }
+       } else {
+               switch v := wr.write.(type) {
+               case http2StreamError:
+
+                       if st, ok := sc.streams[v.StreamID]; ok {
+                               sc.closeStream(st, v)
+                       }
+               case http2handlerPanicRST:
+                       sc.closeStream(wr.stream, http2errHandlerPanicked)
+               }
        }
 
+       wr.replyToWriter(res.err)
+
        sc.scheduleFrameWrite()
 }
 
@@ -3890,8 +3904,7 @@ func (sc *http2serverConn) resetStream(se http2StreamError) {
        sc.serveG.check()
        sc.writeFrame(http2FrameWriteRequest{write: se})
        if st, ok := sc.streams[se.StreamID]; ok {
-               st.sentReset = true
-               sc.closeStream(st, se)
+               st.resetQueued = true
        }
 }
 
@@ -4030,7 +4043,6 @@ func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error {
                return http2ConnectionError(http2ErrCodeProtocol)
        }
        if st != nil {
-               st.gotReset = true
                st.cancelCtx()
                sc.closeStream(st, http2streamError(f.StreamID, f.ErrCode))
        }
@@ -4145,7 +4157,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
 
                return http2ConnectionError(http2ErrCodeProtocol)
        }
-       if st == nil || state != http2stateOpen || st.gotTrailerHeader {
+       if st == nil || state != http2stateOpen || st.gotTrailerHeader || st.resetQueued {
 
                if sc.inflow.available() < int32(f.Length) {
                        return http2streamError(id, http2ErrCodeFlowControl)
@@ -4154,6 +4166,10 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
                sc.inflow.take(int32(f.Length))
                sc.sendWindowUpdate(nil, int(f.Length))
 
+               if st != nil && st.resetQueued {
+
+                       return nil
+               }
                return http2streamError(id, http2ErrCodeStreamClosed)
        }
        if st.body == nil {
@@ -4251,6 +4267,10 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
        }
 
        if st := sc.streams[f.StreamID]; st != nil {
+               if st.resetQueued {
+
+                       return nil
+               }
                return st.processTrailerHeaders(f)
        }
 
@@ -5216,7 +5236,7 @@ func (sc *http2serverConn) startPush(msg http2startPushRequest) {
                        scheme:    msg.url.Scheme,
                        authority: msg.url.Host,
                        path:      msg.url.RequestURI(),
-                       header:    msg.header,
+                       header:    http2cloneHeader(msg.header),
                })
                if err != nil {
 
@@ -5647,6 +5667,10 @@ func http2authorityAddr(scheme string, authority string) (addr string) {
        if a, err := idna.ToASCII(host); err == nil {
                host = a
        }
+
+       if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
+               return host + ":" + port
+       }
        return net.JoinHostPort(host, port)
 }
 
@@ -7376,9 +7400,10 @@ type http2writeContext interface {
        HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
 }
 
-// endsStream reports whether the given frame writer w will locally
-// close the stream.
-func http2endsStream(w http2writeFramer) bool {
+// writeEndsStream reports whether w writes a frame that will transition
+// the stream to a half-closed local state. This returns false for RST_STREAM,
+// which closes the entire stream (not just the local half).
+func http2writeEndsStream(w http2writeFramer) bool {
        switch v := w.(type) {
        case *http2writeData:
                return v.endStream
@@ -7386,7 +7411,7 @@ func http2endsStream(w http2writeFramer) bool {
                return v.endStream
        case nil:
 
-               panic("endsStream called on nil writeFramer")
+               panic("writeEndsStream called on nil writeFramer")
        }
        return false
 }
@@ -7832,6 +7857,20 @@ func (wr http2FrameWriteRequest) String() string {
        return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
 }
 
+// replyToWriter sends err to wr.done and panics if the send must block
+// This does nothing if wr.done is nil.
+func (wr *http2FrameWriteRequest) replyToWriter(err error) {
+       if wr.done == nil {
+               return
+       }
+       select {
+       case wr.done <- err:
+       default:
+               panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
+       }
+       wr.write = nil
+}
+
 // writeQueue is used by implementations of WriteScheduler.
 type http2writeQueue struct {
        s []http2FrameWriteRequest
index 3b7417911fa6cf28ec9b2688818d130483c34007..ea7b38c8fc6e0be959e65aa7e2f1648774cb16da 100644 (file)
@@ -146,7 +146,8 @@ type ClientTrace struct {
        Wait100Continue func()
 
        // WroteRequest is called with the result of writing the
-       // request and any body.
+       // request and any body. It may be called multiple times
+       // in the case of retried requests.
        WroteRequest func(WroteRequestInfo)
 }
 
index 15116816328693db674f02a85cd446188b91b720..7104c3745452ad42853fe00193231812263aa736 100644 (file)
@@ -18,11 +18,16 @@ import (
        "time"
 )
 
-// One of the copies, say from b to r2, could be avoided by using a more
-// elaborate trick where the other copy is made during Request/Response.Write.
-// This would complicate things too much, given that these functions are for
-// debugging only.
+// drainBody reads all of b to memory and then returns two equivalent
+// ReadClosers yielding the same bytes.
+//
+// It returns an error if the initial slurp of all bytes fails. It does not attempt
+// to make the returned ReadClosers have identical error-matching behavior.
 func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
+       if b == http.NoBody {
+               // No copying needed. Preserve the magic sentinel meaning of NoBody.
+               return http.NoBody, http.NoBody, nil
+       }
        var buf bytes.Buffer
        if _, err = buf.ReadFrom(b); err != nil {
                return nil, b, err
index 2e980d39f8af924aa7daefcf38d29a8d58ffb04a..f881020fef7e57a341a4704d600bb7b79643ab86 100644 (file)
@@ -184,6 +184,18 @@ var dumpTests = []dumpTest{
                WantDump: "POST /v2/api/?login HTTP/1.1\r\n" +
                        "Host: passport.myhost.com\r\n\r\n",
        },
+
+       // Issue 18506: make drainBody recognize NoBody. Otherwise
+       // this was turning into a chunked request.
+       {
+               Req: *mustNewRequest("POST", "http://example.com/foo", http.NoBody),
+
+               WantDumpOut: "POST /foo HTTP/1.1\r\n" +
+                       "Host: example.com\r\n" +
+                       "User-Agent: Go-http-client/1.1\r\n" +
+                       "Content-Length: 0\r\n" +
+                       "Accept-Encoding: gzip\r\n\r\n",
+       },
 }
 
 func TestDumpRequest(t *testing.T) {
index 78675057085c23bce6c5282af50ff67bf7aaf520..79c8fe27702fbbece3b81451c9aa23db5891ecfc 100644 (file)
@@ -30,6 +30,8 @@ type ReverseProxy struct {
        // the request into a new request to be sent
        // using Transport. Its response is then copied
        // back to the original client unmodified.
+       // Director must not access the provided Request
+       // after returning.
        Director func(*http.Request)
 
        // The transport used to perform proxy requests.
index 96fa619683c0e80f1b367fff8a2fe291e5990e24..fb6bb0aab5873a4c6148ff6a22c428d1b9e04439 100644 (file)
@@ -341,6 +341,18 @@ func (r *Request) ProtoAtLeast(major, minor int) bool {
                r.ProtoMajor == major && r.ProtoMinor >= minor
 }
 
+// protoAtLeastOutgoing is like ProtoAtLeast, but is for outgoing
+// requests (see issue 18407) where these fields aren't supposed to
+// matter.  As a minor fix for Go 1.8, at least treat (0, 0) as
+// matching HTTP/1.1 or HTTP/1.0.  Only HTTP/1.1 is used.
+// TODO(bradfitz): ideally remove this whole method. It shouldn't be used.
+func (r *Request) protoAtLeastOutgoing(major, minor int) bool {
+       if r.ProtoMajor == 0 && r.ProtoMinor == 0 && major == 1 && minor <= 1 {
+               return true
+       }
+       return r.ProtoAtLeast(major, minor)
+}
+
 // UserAgent returns the client's User-Agent, if sent in the request.
 func (r *Request) UserAgent() string {
        return r.Header.Get("User-Agent")
@@ -600,6 +612,12 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
                }
        }
 
+       if bw, ok := w.(*bufio.Writer); ok && tw.FlushHeaders {
+               if err := bw.Flush(); err != nil {
+                       return err
+               }
+       }
+
        // Write body and trailer
        err = tw.WriteBody(w)
        if err != nil {
@@ -731,6 +749,12 @@ func validMethod(method string) bool {
 // net/http/httptest package, use ReadRequest, or manually update the
 // Request fields. See the Request type's documentation for the
 // difference between inbound and outbound request fields.
+//
+// If body is of type *bytes.Buffer, *bytes.Reader, or
+// *strings.Reader, the returned request's ContentLength is set to its
+// exact value (instead of -1), GetBody is populated (so 307 and 308
+// redirects can replay the body), and Body is set to NoBody if the
+// ContentLength is 0.
 func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
        if method == "" {
                // We document that "" means "GET" for Request.Method, and people have
@@ -1293,3 +1317,18 @@ func (r *Request) outgoingLength() int64 {
        }
        return -1
 }
+
+// requestMethodUsuallyLacksBody reports whether the given request
+// method is one that typically does not involve a request body.
+// This is used by the Transport (via
+// transferWriter.shouldSendChunkedRequestBody) to determine whether
+// we try to test-read a byte from a non-nil Request.Body when
+// Request.outgoingLength() returns -1. See the comments in
+// shouldSendChunkedRequestBody.
+func requestMethodUsuallyLacksBody(method string) bool {
+       switch method {
+       case "GET", "HEAD", "DELETE", "OPTIONS", "PROPFIND", "SEARCH":
+               return true
+       }
+       return false
+}
index c398e645392e218c51e0fa92309c03966c3394ad..eb65b9f736f5ba81e923f1b33ce837b757e1bc5b 100644 (file)
@@ -5,14 +5,17 @@
 package http
 
 import (
+       "bufio"
        "bytes"
        "errors"
        "fmt"
        "io"
        "io/ioutil"
+       "net"
        "net/url"
        "strings"
        "testing"
+       "time"
 )
 
 type reqWriteTest struct {
@@ -566,6 +569,138 @@ func TestRequestWrite(t *testing.T) {
        }
 }
 
+func TestRequestWriteTransport(t *testing.T) {
+       t.Parallel()
+
+       matchSubstr := func(substr string) func(string) error {
+               return func(written string) error {
+                       if !strings.Contains(written, substr) {
+                               return fmt.Errorf("expected substring %q in request: %s", substr, written)
+                       }
+                       return nil
+               }
+       }
+
+       noContentLengthOrTransferEncoding := func(req string) error {
+               if strings.Contains(req, "Content-Length: ") {
+                       return fmt.Errorf("unexpected Content-Length in request: %s", req)
+               }
+               if strings.Contains(req, "Transfer-Encoding: ") {
+                       return fmt.Errorf("unexpected Transfer-Encoding in request: %s", req)
+               }
+               return nil
+       }
+
+       all := func(checks ...func(string) error) func(string) error {
+               return func(req string) error {
+                       for _, c := range checks {
+                               if err := c(req); err != nil {
+                                       return err
+                               }
+                       }
+                       return nil
+               }
+       }
+
+       type testCase struct {
+               method string
+               clen   int64 // ContentLength
+               body   io.ReadCloser
+               want   func(string) error
+
+               // optional:
+               init         func(*testCase)
+               afterReqRead func()
+       }
+
+       tests := []testCase{
+               {
+                       method: "GET",
+                       want:   noContentLengthOrTransferEncoding,
+               },
+               {
+                       method: "GET",
+                       body:   ioutil.NopCloser(strings.NewReader("")),
+                       want:   noContentLengthOrTransferEncoding,
+               },
+               {
+                       method: "GET",
+                       clen:   -1,
+                       body:   ioutil.NopCloser(strings.NewReader("")),
+                       want:   noContentLengthOrTransferEncoding,
+               },
+               // A GET with a body, with explicit content length:
+               {
+                       method: "GET",
+                       clen:   7,
+                       body:   ioutil.NopCloser(strings.NewReader("foobody")),
+                       want: all(matchSubstr("Content-Length: 7"),
+                               matchSubstr("foobody")),
+               },
+               // A GET with a body, sniffing the leading "f" from "foobody".
+               {
+                       method: "GET",
+                       clen:   -1,
+                       body:   ioutil.NopCloser(strings.NewReader("foobody")),
+                       want: all(matchSubstr("Transfer-Encoding: chunked"),
+                               matchSubstr("\r\n1\r\nf\r\n"),
+                               matchSubstr("oobody")),
+               },
+               // But a POST request is expected to have a body, so
+               // no sniffing happens:
+               {
+                       method: "POST",
+                       clen:   -1,
+                       body:   ioutil.NopCloser(strings.NewReader("foobody")),
+                       want: all(matchSubstr("Transfer-Encoding: chunked"),
+                               matchSubstr("foobody")),
+               },
+               {
+                       method: "POST",
+                       clen:   -1,
+                       body:   ioutil.NopCloser(strings.NewReader("")),
+                       want:   all(matchSubstr("Transfer-Encoding: chunked")),
+               },
+               // Verify that a blocking Request.Body doesn't block forever.
+               {
+                       method: "GET",
+                       clen:   -1,
+                       init: func(tt *testCase) {
+                               pr, pw := io.Pipe()
+                               tt.afterReqRead = func() {
+                                       pw.Close()
+                               }
+                               tt.body = ioutil.NopCloser(pr)
+                       },
+                       want: matchSubstr("Transfer-Encoding: chunked"),
+               },
+       }
+
+       for i, tt := range tests {
+               if tt.init != nil {
+                       tt.init(&tt)
+               }
+               req := &Request{
+                       Method: tt.method,
+                       URL: &url.URL{
+                               Scheme: "http",
+                               Host:   "example.com",
+                       },
+                       Header:        make(Header),
+                       ContentLength: tt.clen,
+                       Body:          tt.body,
+               }
+               got, err := dumpRequestOut(req, tt.afterReqRead)
+               if err != nil {
+                       t.Errorf("test[%d]: %v", i, err)
+                       continue
+               }
+               if err := tt.want(string(got)); err != nil {
+                       t.Errorf("test[%d]: %v", i, err)
+               }
+       }
+}
+
 type closeChecker struct {
        io.Reader
        closed bool
@@ -672,3 +807,76 @@ func TestRequestWriteError(t *testing.T) {
                t.Fatalf("writeCalls constant is outdated in test")
        }
 }
+
+// dumpRequestOut is a modified copy of net/http/httputil.DumpRequestOut.
+// Unlike the original, this version doesn't mutate the req.Body and
+// try to restore it. It always dumps the whole body.
+// And it doesn't support https.
+func dumpRequestOut(req *Request, onReadHeaders func()) ([]byte, error) {
+
+       // Use the actual Transport code to record what we would send
+       // on the wire, but not using TCP.  Use a Transport with a
+       // custom dialer that returns a fake net.Conn that waits
+       // for the full input (and recording it), and then responds
+       // with a dummy response.
+       var buf bytes.Buffer // records the output
+       pr, pw := io.Pipe()
+       defer pr.Close()
+       defer pw.Close()
+       dr := &delegateReader{c: make(chan io.Reader)}
+
+       t := &Transport{
+               Dial: func(net, addr string) (net.Conn, error) {
+                       return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
+               },
+       }
+       defer t.CloseIdleConnections()
+
+       // Wait for the request before replying with a dummy response:
+       go func() {
+               req, err := ReadRequest(bufio.NewReader(pr))
+               if err == nil {
+                       if onReadHeaders != nil {
+                               onReadHeaders()
+                       }
+                       // Ensure all the body is read; otherwise
+                       // we'll get a partial dump.
+                       io.Copy(ioutil.Discard, req.Body)
+                       req.Body.Close()
+               }
+               dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n")
+       }()
+
+       _, err := t.RoundTrip(req)
+       if err != nil {
+               return nil, err
+       }
+       return buf.Bytes(), nil
+}
+
+// delegateReader is a reader that delegates to another reader,
+// once it arrives on a channel.
+type delegateReader struct {
+       c chan io.Reader
+       r io.Reader // nil until received from c
+}
+
+func (r *delegateReader) Read(p []byte) (int, error) {
+       if r.r == nil {
+               r.r = <-r.c
+       }
+       return r.r.Read(p)
+}
+
+// dumpConn is a net.Conn that writes to Writer and reads from Reader.
+type dumpConn struct {
+       io.Writer
+       io.Reader
+}
+
+func (c *dumpConn) Close() error                       { return nil }
+func (c *dumpConn) LocalAddr() net.Addr                { return nil }
+func (c *dumpConn) RemoteAddr() net.Addr               { return nil }
+func (c *dumpConn) SetDeadline(t time.Time) error      { return nil }
+func (c *dumpConn) SetReadDeadline(t time.Time) error  { return nil }
+func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
index 593b1f3cdd5ef7e05a9a2c7fb9d83c4640671c8f..73dd56e8c426562c966aaf56954a06b4655e9517 100644 (file)
@@ -481,11 +481,11 @@ func TestServerTimeouts(t *testing.T) {
        if err != nil {
                t.Fatalf("http Get #1: %v", err)
        }
-       got, _ := ioutil.ReadAll(r.Body)
+       got, err := ioutil.ReadAll(r.Body)
        expected := "req=1"
-       if string(got) != expected {
-               t.Errorf("Unexpected response for request #1; got %q; expected %q",
-                       string(got), expected)
+       if string(got) != expected || err != nil {
+               t.Errorf("Unexpected response for request #1; got %q ,%v; expected %q, nil",
+                       string(got), err, expected)
        }
 
        // Slow client that should timeout.
@@ -496,6 +496,7 @@ func TestServerTimeouts(t *testing.T) {
        }
        buf := make([]byte, 1)
        n, err := conn.Read(buf)
+       conn.Close()
        latency := time.Since(t1)
        if n != 0 || err != io.EOF {
                t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
@@ -507,14 +508,14 @@ func TestServerTimeouts(t *testing.T) {
        // Hit the HTTP server successfully again, verifying that the
        // previous slow connection didn't run our handler.  (that we
        // get "req=2", not "req=3")
-       r, err = Get(ts.URL)
+       r, err = c.Get(ts.URL)
        if err != nil {
                t.Fatalf("http Get #2: %v", err)
        }
-       got, _ = ioutil.ReadAll(r.Body)
+       got, err = ioutil.ReadAll(r.Body)
        expected = "req=2"
-       if string(got) != expected {
-               t.Errorf("Get #2 got %q, want %q", string(got), expected)
+       if string(got) != expected || err != nil {
+               t.Errorf("Get #2 got %q, %v, want %q, nil", string(got), err, expected)
        }
 
        if !testing.Short() {
@@ -534,6 +535,56 @@ func TestServerTimeouts(t *testing.T) {
        }
 }
 
+// Test that the HTTP/2 server handles Server.WriteTimeout (Issue 18437)
+func TestHTTP2WriteDeadlineExtendedOnNewRequest(t *testing.T) {
+       if testing.Short() {
+               t.Skip("skipping in short mode")
+       }
+       setParallel(t)
+       defer afterTest(t)
+       ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {}))
+       ts.Config.WriteTimeout = 250 * time.Millisecond
+       ts.TLS = &tls.Config{NextProtos: []string{"h2"}}
+       ts.StartTLS()
+       defer ts.Close()
+
+       tr := newTLSTransport(t, ts)
+       defer tr.CloseIdleConnections()
+       if err := ExportHttp2ConfigureTransport(tr); err != nil {
+               t.Fatal(err)
+       }
+       c := &Client{Transport: tr}
+
+       for i := 1; i <= 3; i++ {
+               req, err := NewRequest("GET", ts.URL, nil)
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               // fail test if no response after 1 second
+               ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+               defer cancel()
+               req = req.WithContext(ctx)
+
+               r, err := c.Do(req)
+               select {
+               case <-ctx.Done():
+                       if ctx.Err() == context.DeadlineExceeded {
+                               t.Fatalf("http2 Get #%d response timed out", i)
+                       }
+               default:
+               }
+               if err != nil {
+                       t.Fatalf("http2 Get #%d: %v", i, err)
+               }
+               r.Body.Close()
+               if r.ProtoMajor != 2 {
+                       t.Fatalf("http2 Get expected HTTP/2.0, got %q", r.Proto)
+               }
+               time.Sleep(ts.Config.WriteTimeout / 2)
+       }
+}
+
 // golang.org/issue/4741 -- setting only a write timeout that triggers
 // shouldn't cause a handler to block forever on reads (next HTTP
 // request) that will never happen.
@@ -5038,3 +5089,226 @@ func testServerKeepAlivesEnabled(t *testing.T, h2 bool) {
                t.Fatalf("test server has active conns")
        }
 }
+
+// Issue 18447: test that the Server's ReadTimeout is stopped while
+// the server's doing its 1-byte background read between requests,
+// waiting for the connection to maybe close.
+func TestServerCancelsReadTimeoutWhenIdle(t *testing.T) {
+       setParallel(t)
+       defer afterTest(t)
+       const timeout = 250 * time.Millisecond
+       ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               select {
+               case <-time.After(2 * timeout):
+                       fmt.Fprint(w, "ok")
+               case <-r.Context().Done():
+                       fmt.Fprint(w, r.Context().Err())
+               }
+       }))
+       ts.Config.ReadTimeout = timeout
+       ts.Start()
+       defer ts.Close()
+
+       tr := &Transport{}
+       defer tr.CloseIdleConnections()
+       c := &Client{Transport: tr}
+
+       res, err := c.Get(ts.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+       slurp, err := ioutil.ReadAll(res.Body)
+       res.Body.Close()
+       if err != nil {
+               t.Fatal(err)
+       }
+       if string(slurp) != "ok" {
+               t.Fatalf("Got: %q, want ok", slurp)
+       }
+}
+
+// Issue 18535: test that the Server doesn't try to do a background
+// read if it's already done one.
+func TestServerDuplicateBackgroundRead(t *testing.T) {
+       setParallel(t)
+       defer afterTest(t)
+
+       const goroutines = 5
+       const requests = 2000
+
+       hts := httptest.NewServer(HandlerFunc(NotFound))
+       defer hts.Close()
+
+       reqBytes := []byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")
+
+       var wg sync.WaitGroup
+       for i := 0; i < goroutines; i++ {
+               wg.Add(1)
+               go func() {
+                       defer wg.Done()
+                       cn, err := net.Dial("tcp", hts.Listener.Addr().String())
+                       if err != nil {
+                               t.Error(err)
+                               return
+                       }
+                       defer cn.Close()
+
+                       wg.Add(1)
+                       go func() {
+                               defer wg.Done()
+                               io.Copy(ioutil.Discard, cn)
+                       }()
+
+                       for j := 0; j < requests; j++ {
+                               if t.Failed() {
+                                       return
+                               }
+                               _, err := cn.Write(reqBytes)
+                               if err != nil {
+                                       t.Error(err)
+                                       return
+                               }
+                       }
+               }()
+       }
+       wg.Wait()
+}
+
+// Test that the bufio.Reader returned by Hijack includes any buffered
+// byte (from the Server's backgroundRead) in its buffer. We want the
+// Handler code to be able to tell that a byte is available via
+// bufio.Reader.Buffered(), without resorting to Reading it
+// (potentially blocking) to get at it.
+func TestServerHijackGetsBackgroundByte(t *testing.T) {
+       if runtime.GOOS == "plan9" {
+               t.Skip("skipping test; see https://golang.org/issue/18657")
+       }
+       setParallel(t)
+       defer afterTest(t)
+       done := make(chan struct{})
+       inHandler := make(chan bool, 1)
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               defer close(done)
+
+               // Tell the client to send more data after the GET request.
+               inHandler <- true
+
+               // Wait until the HTTP server sees the extra data
+               // after the GET request. The HTTP server fires the
+               // close notifier here, assuming it's a pipelined
+               // request, as documented.
+               select {
+               case <-w.(CloseNotifier).CloseNotify():
+               case <-time.After(5 * time.Second):
+                       t.Error("timeout")
+                       return
+               }
+
+               conn, buf, err := w.(Hijacker).Hijack()
+               if err != nil {
+                       t.Error(err)
+                       return
+               }
+               defer conn.Close()
+               n := buf.Reader.Buffered()
+               if n != 1 {
+                       t.Errorf("buffered data = %d; want 1", n)
+               }
+               peek, err := buf.Reader.Peek(3)
+               if string(peek) != "foo" || err != nil {
+                       t.Errorf("Peek = %q, %v; want foo, nil", peek, err)
+               }
+       }))
+       defer ts.Close()
+
+       cn, err := net.Dial("tcp", ts.Listener.Addr().String())
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer cn.Close()
+       if _, err := cn.Write([]byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")); err != nil {
+               t.Fatal(err)
+       }
+       <-inHandler
+       if _, err := cn.Write([]byte("foo")); err != nil {
+               t.Fatal(err)
+       }
+
+       if err := cn.(*net.TCPConn).CloseWrite(); err != nil {
+               t.Fatal(err)
+       }
+       select {
+       case <-done:
+       case <-time.After(2 * time.Second):
+               t.Error("timeout")
+       }
+}
+
+// Like TestServerHijackGetsBackgroundByte above but sending a
+// immediate 1MB of data to the server to fill up the server's 4KB
+// buffer.
+func TestServerHijackGetsBackgroundByte_big(t *testing.T) {
+       if runtime.GOOS == "plan9" {
+               t.Skip("skipping test; see https://golang.org/issue/18657")
+       }
+       setParallel(t)
+       defer afterTest(t)
+       done := make(chan struct{})
+       const size = 8 << 10
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               defer close(done)
+
+               // Wait until the HTTP server sees the extra data
+               // after the GET request. The HTTP server fires the
+               // close notifier here, assuming it's a pipelined
+               // request, as documented.
+               select {
+               case <-w.(CloseNotifier).CloseNotify():
+               case <-time.After(5 * time.Second):
+                       t.Error("timeout")
+                       return
+               }
+
+               conn, buf, err := w.(Hijacker).Hijack()
+               if err != nil {
+                       t.Error(err)
+                       return
+               }
+               defer conn.Close()
+               slurp, err := ioutil.ReadAll(buf.Reader)
+               if err != nil {
+                       t.Errorf("Copy: %v", err)
+               }
+               allX := true
+               for _, v := range slurp {
+                       if v != 'x' {
+                               allX = false
+                       }
+               }
+               if len(slurp) != size {
+                       t.Errorf("read %d; want %d", len(slurp), size)
+               } else if !allX {
+                       t.Errorf("read %q; want %d 'x'", slurp, size)
+               }
+       }))
+       defer ts.Close()
+
+       cn, err := net.Dial("tcp", ts.Listener.Addr().String())
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer cn.Close()
+       if _, err := fmt.Fprintf(cn, "GET / HTTP/1.1\r\nHost: e.com\r\n\r\n%s",
+               strings.Repeat("x", size)); err != nil {
+               t.Fatal(err)
+       }
+       if err := cn.(*net.TCPConn).CloseWrite(); err != nil {
+               t.Fatal(err)
+       }
+
+       select {
+       case <-done:
+       case <-time.After(2 * time.Second):
+               t.Error("timeout")
+       }
+}
index 6df9c260e4a37c33885826d23988fa2c5e659b9a..df70a15193bc6adb0127f250d4c2e3edb033e6e2 100644 (file)
@@ -164,7 +164,7 @@ type Flusher interface {
 // should always test for this ability at runtime.
 type Hijacker interface {
        // Hijack lets the caller take over the connection.
-       // After a call to Hijack(), the HTTP server library
+       // After a call to Hijack the HTTP server library
        // will not do anything else with the connection.
        //
        // It becomes the caller's responsibility to manage
@@ -174,6 +174,9 @@ type Hijacker interface {
        // already set, depending on the configuration of the
        // Server. It is the caller's responsibility to set
        // or clear those deadlines as needed.
+       //
+       // The returned bufio.Reader may contain unprocessed buffered
+       // data from the client.
        Hijack() (net.Conn, *bufio.ReadWriter, error)
 }
 
@@ -293,6 +296,11 @@ func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
        rwc.SetDeadline(time.Time{})
 
        buf = bufio.NewReadWriter(c.bufr, bufio.NewWriter(rwc))
+       if c.r.hasByte {
+               if _, err := c.bufr.Peek(c.bufr.Buffered() + 1); err != nil {
+                       return nil, nil, fmt.Errorf("unexpected Peek failure reading buffered byte: %v", err)
+               }
+       }
        c.setState(rwc, StateHijacked)
        return
 }
@@ -636,7 +644,11 @@ func (cr *connReader) startBackgroundRead() {
        if cr.inRead {
                panic("invalid concurrent Body.Read call")
        }
+       if cr.hasByte {
+               return
+       }
        cr.inRead = true
+       cr.conn.rwc.SetReadDeadline(time.Time{})
        go cr.backgroundRead()
 }
 
index beafb7ac97f4014d74394bc7770e41d97e469b59..4f47637aa76a6af7005a885f020cfec5484320ae 100644 (file)
@@ -17,6 +17,7 @@ import (
        "strconv"
        "strings"
        "sync"
+       "time"
 
        "golang_org/x/net/lex/httplex"
 )
@@ -33,6 +34,23 @@ func (r errorReader) Read(p []byte) (n int, err error) {
        return 0, r.err
 }
 
+type byteReader struct {
+       b    byte
+       done bool
+}
+
+func (br *byteReader) Read(p []byte) (n int, err error) {
+       if br.done {
+               return 0, io.EOF
+       }
+       if len(p) == 0 {
+               return 0, nil
+       }
+       br.done = true
+       p[0] = br.b
+       return 1, io.EOF
+}
+
 // transferWriter inspects the fields of a user-supplied Request or Response,
 // sanitizes them without changing the user object and provides methods for
 // writing the respective header, body and trailer in wire format.
@@ -46,6 +64,9 @@ type transferWriter struct {
        TransferEncoding []string
        Trailer          Header
        IsResponse       bool
+
+       FlushHeaders bool            // flush headers to network before body
+       ByteReadCh   chan readResult // non-nil if probeRequestBody called
 }
 
 func newTransferWriter(r interface{}) (t *transferWriter, err error) {
@@ -62,14 +83,11 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
                t.Close = rr.Close
                t.TransferEncoding = rr.TransferEncoding
                t.Trailer = rr.Trailer
-               atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
-
+               atLeastHTTP11 = rr.protoAtLeastOutgoing(1, 1)
                t.Body = rr.Body
+               t.BodyCloser = rr.Body
                t.ContentLength = rr.outgoingLength()
-               if t.Body != nil {
-                       t.BodyCloser = rr.Body
-               }
-               if t.ContentLength < 0 && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
+               if t.ContentLength < 0 && len(t.TransferEncoding) == 0 && atLeastHTTP11 && t.shouldSendChunkedRequestBody() {
                        t.TransferEncoding = []string{"chunked"}
                }
        case *Response:
@@ -84,7 +102,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
                t.TransferEncoding = rr.TransferEncoding
                t.Trailer = rr.Trailer
                atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
-               t.ResponseToHEAD = noBodyExpected(t.Method)
+               t.ResponseToHEAD = noResponseBodyExpected(t.Method)
        }
 
        // Sanitize Body,ContentLength,TransferEncoding
@@ -112,7 +130,100 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
        return t, nil
 }
 
-func noBodyExpected(requestMethod string) bool {
+// shouldSendChunkedRequestBody reports whether we should try to send a
+// chunked request body to the server. In particular, the case we really
+// want to prevent is sending a GET or other typically-bodyless request to a
+// server with a chunked body when the body has zero bytes, since GETs with
+// bodies (while acceptable according to specs), even zero-byte chunked
+// bodies, are approximately never seen in the wild and confuse most
+// servers. See Issue 18257, as one example.
+//
+// The only reason we'd send such a request is if the user set the Body to a
+// non-nil value (say, ioutil.NopCloser(bytes.NewReader(nil))) and didn't
+// set ContentLength, or NewRequest set it to -1 (unknown), so then we assume
+// there's bytes to send.
+//
+// This code tries to read a byte from the Request.Body in such cases to see
+// whether the body actually has content (super rare) or is actually just
+// a non-nil content-less ReadCloser (the more common case). In that more
+// common case, we act as if their Body were nil instead, and don't send
+// a body.
+func (t *transferWriter) shouldSendChunkedRequestBody() bool {
+       // Note that t.ContentLength is the corrected content length
+       // from rr.outgoingLength, so 0 actually means zero, not unknown.
+       if t.ContentLength >= 0 || t.Body == nil { // redundant checks; caller did them
+               return false
+       }
+       if requestMethodUsuallyLacksBody(t.Method) {
+               // Only probe the Request.Body for GET/HEAD/DELETE/etc
+               // requests, because it's only those types of requests
+               // that confuse servers.
+               t.probeRequestBody() // adjusts t.Body, t.ContentLength
+               return t.Body != nil
+       }
+       // For all other request types (PUT, POST, PATCH, or anything
+       // made-up we've never heard of), assume it's normal and the server
+       // can deal with a chunked request body. Maybe we'll adjust this
+       // later.
+       return true
+}
+
+// probeRequestBody reads a byte from t.Body to see whether it's empty
+// (returns io.EOF right away).
+//
+// But because we've had problems with this blocking users in the past
+// (issue 17480) when the body is a pipe (perhaps waiting on the response
+// headers before the pipe is fed data), we need to be careful and bound how
+// long we wait for it. This delay will only affect users if all the following
+// are true:
+//   * the request body blocks
+//   * the content length is not set (or set to -1)
+//   * the method doesn't usually have a body (GET, HEAD, DELETE, ...)
+//   * there is no transfer-encoding=chunked already set.
+// In other words, this delay will not normally affect anybody, and there
+// are workarounds if it does.
+func (t *transferWriter) probeRequestBody() {
+       t.ByteReadCh = make(chan readResult, 1)
+       go func(body io.Reader) {
+               var buf [1]byte
+               var rres readResult
+               rres.n, rres.err = body.Read(buf[:])
+               if rres.n == 1 {
+                       rres.b = buf[0]
+               }
+               t.ByteReadCh <- rres
+       }(t.Body)
+       timer := time.NewTimer(200 * time.Millisecond)
+       select {
+       case rres := <-t.ByteReadCh:
+               timer.Stop()
+               if rres.n == 0 && rres.err == io.EOF {
+                       // It was empty.
+                       t.Body = nil
+                       t.ContentLength = 0
+               } else if rres.n == 1 {
+                       if rres.err != nil {
+                               t.Body = io.MultiReader(&byteReader{b: rres.b}, errorReader{rres.err})
+                       } else {
+                               t.Body = io.MultiReader(&byteReader{b: rres.b}, t.Body)
+                       }
+               } else if rres.err != nil {
+                       t.Body = errorReader{rres.err}
+               }
+       case <-timer.C:
+               // Too slow. Don't wait. Read it later, and keep
+               // assuming that this is ContentLength == -1
+               // (unknown), which means we'll send a
+               // "Transfer-Encoding: chunked" header.
+               t.Body = io.MultiReader(finishAsyncByteRead{t}, t.Body)
+               // Request that Request.Write flush the headers to the
+               // network before writing the body, since our body may not
+               // become readable until it's seen the response headers.
+               t.FlushHeaders = true
+       }
+}
+
+func noResponseBodyExpected(requestMethod string) bool {
        return requestMethod == "HEAD"
 }
 
@@ -216,7 +327,9 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
                if err != nil {
                        return err
                }
-               if err = t.BodyCloser.Close(); err != nil {
+       }
+       if t.BodyCloser != nil {
+               if err := t.BodyCloser.Close(); err != nil {
                        return err
                }
        }
@@ -366,7 +479,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
        // or close connection when finished, since multipart is not supported yet
        switch {
        case chunked(t.TransferEncoding):
-               if noBodyExpected(t.RequestMethod) {
+               if noResponseBodyExpected(t.RequestMethod) {
                        t.Body = NoBody
                } else {
                        t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}
@@ -498,7 +611,7 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
        }
 
        // Logic based on response type or status
-       if noBodyExpected(requestMethod) {
+       if noResponseBodyExpected(requestMethod) {
                // For HTTP requests, as part of hardening against request
                // smuggling (RFC 7230), don't allow a Content-Length header for
                // methods which don't permit bodies. As an exception, allow
@@ -861,3 +974,21 @@ func parseContentLength(cl string) (int64, error) {
        return n, nil
 
 }
+
+// finishAsyncByteRead finishes reading the 1-byte sniff
+// from the ContentLength==0, Body!=nil case.
+type finishAsyncByteRead struct {
+       tw *transferWriter
+}
+
+func (fr finishAsyncByteRead) Read(p []byte) (n int, err error) {
+       if len(p) == 0 {
+               return
+       }
+       rres := <-fr.tw.ByteReadCh
+       n, err = rres.n, rres.err
+       if n == 1 {
+               p[0] = rres.b
+       }
+       return
+}
index e48454877340e8b9df8c065a14142f73247ca351..571943d6e5cd9935d43005c138e7211a97820964 100644 (file)
@@ -923,6 +923,9 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
                // value.
                select {
                case <-req.Cancel:
+                       // It was an error due to cancelation, so prioritize that
+                       // error value. (Issue 16049)
+                       return nil, errRequestCanceledConn
                case <-req.Context().Done():
                        return nil, req.Context().Err()
                case err := <-cancelc:
@@ -935,9 +938,6 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
                        // return the original error message:
                        return nil, v.err
                }
-               // It was an error due to cancelation, so prioritize that
-               // error value. (Issue 16049)
-               return nil, errRequestCanceledConn
        case pc := <-idleConnCh:
                // Another request finished first and its net.Conn
                // became available before our dial. Or somebody
@@ -1384,7 +1384,7 @@ func (pc *persistConn) closeConnIfStillIdle() {
 //
 // The startBytesWritten value should be the value of pc.nwrite before the roundTrip
 // started writing the request.
-func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, err error) (out error) {
+func (pc *persistConn) mapRoundTripErrorFromReadLoop(req *Request, startBytesWritten int64, err error) (out error) {
        if err == nil {
                return nil
        }
@@ -1399,7 +1399,7 @@ func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, er
        }
        if pc.isBroken() {
                <-pc.writeLoopDone
-               if pc.nwrite == startBytesWritten {
+               if pc.nwrite == startBytesWritten && req.outgoingLength() == 0 {
                        return nothingWrittenError{err}
                }
        }
@@ -1410,7 +1410,7 @@ func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, er
 // up to Transport.RoundTrip method when persistConn.roundTrip sees
 // its pc.closech channel close, indicating the persistConn is dead.
 // (after closech is closed, pc.closed is valid).
-func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) error {
+func (pc *persistConn) mapRoundTripErrorAfterClosed(req *Request, startBytesWritten int64) error {
        if err := pc.canceled(); err != nil {
                return err
        }
@@ -1428,7 +1428,7 @@ func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) err
        // see if we actually managed to write anything. If not, we
        // can retry the request.
        <-pc.writeLoopDone
-       if pc.nwrite == startBytesWritten {
+       if pc.nwrite == startBytesWritten && req.outgoingLength() == 0 {
                return nothingWrittenError{err}
        }
 
@@ -1710,7 +1710,7 @@ func (pc *persistConn) writeLoop() {
                        }
                        if err != nil {
                                wr.req.Request.closeBody()
-                               if pc.nwrite == startBytesWritten {
+                               if pc.nwrite == startBytesWritten && wr.req.outgoingLength() == 0 {
                                        err = nothingWrittenError{err}
                                }
                        }
@@ -1911,14 +1911,14 @@ WaitResponse:
                                respHeaderTimer = timer.C
                        }
                case <-pc.closech:
-                       re = responseAndError{err: pc.mapRoundTripErrorAfterClosed(startBytesWritten)}
+                       re = responseAndError{err: pc.mapRoundTripErrorAfterClosed(req.Request, startBytesWritten)}
                        break WaitResponse
                case <-respHeaderTimer:
                        pc.close(errTimeout)
                        re = responseAndError{err: errTimeout}
                        break WaitResponse
                case re = <-resc:
-                       re.err = pc.mapRoundTripErrorFromReadLoop(startBytesWritten, re.err)
+                       re.err = pc.mapRoundTripErrorFromReadLoop(req.Request, startBytesWritten, re.err)
                        break WaitResponse
                case <-cancelChan:
                        pc.t.CancelRequest(req.Request)
index 5a402657cc3f5357626ea7e8ebf1c0bdd1517b6d..a58b1839cc6e09e30d5f1a975a6f8394008dae98 100644 (file)
@@ -36,6 +36,7 @@ import (
        "strconv"
        "strings"
        "sync"
+       "sync/atomic"
        "testing"
        "time"
 )
@@ -1083,8 +1084,10 @@ func waitNumGoroutine(nmax int) int {
 func TestTransportPersistConnLeak(t *testing.T) {
        // Not parallel: counts goroutines
        defer afterTest(t)
-       gotReqCh := make(chan bool)
-       unblockCh := make(chan bool)
+
+       const numReq = 25
+       gotReqCh := make(chan bool, numReq)
+       unblockCh := make(chan bool, numReq)
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
                gotReqCh <- true
                <-unblockCh
@@ -1098,14 +1101,15 @@ func TestTransportPersistConnLeak(t *testing.T) {
 
        n0 := runtime.NumGoroutine()
 
-       const numReq = 25
-       didReqCh := make(chan bool)
+       didReqCh := make(chan bool, numReq)
+       failed := make(chan bool, numReq)
        for i := 0; i < numReq; i++ {
                go func() {
                        res, err := c.Get(ts.URL)
                        didReqCh <- true
                        if err != nil {
                                t.Errorf("client fetch error: %v", err)
+                               failed <- true
                                return
                        }
                        res.Body.Close()
@@ -1114,7 +1118,13 @@ func TestTransportPersistConnLeak(t *testing.T) {
 
        // Wait for all goroutines to be stuck in the Handler.
        for i := 0; i < numReq; i++ {
-               <-gotReqCh
+               select {
+               case <-gotReqCh:
+                       // ok
+               case <-failed:
+                       close(unblockCh)
+                       return
+               }
        }
 
        nhigh := runtime.NumGoroutine()
@@ -2536,6 +2546,13 @@ type closerFunc func() error
 
 func (f closerFunc) Close() error { return f() }
 
+type writerFuncConn struct {
+       net.Conn
+       write func(p []byte) (n int, err error)
+}
+
+func (c writerFuncConn) Write(p []byte) (n int, err error) { return c.write(p) }
+
 // Issue 4677. If we try to reuse a connection that the server is in the
 // process of closing, we may end up successfully writing out our request (or a
 // portion of our request) only to find a connection error when we try to read
@@ -2548,66 +2565,78 @@ func (f closerFunc) Close() error { return f() }
 func TestRetryIdempotentRequestsOnError(t *testing.T) {
        defer afterTest(t)
 
+       var (
+               mu     sync.Mutex
+               logbuf bytes.Buffer
+       )
+       logf := func(format string, args ...interface{}) {
+               mu.Lock()
+               defer mu.Unlock()
+               fmt.Fprintf(&logbuf, format, args...)
+               logbuf.WriteByte('\n')
+       }
+
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               logf("Handler")
+               w.Header().Set("X-Status", "ok")
        }))
        defer ts.Close()
 
-       tr := &Transport{}
+       var writeNumAtomic int32
+       tr := &Transport{
+               Dial: func(network, addr string) (net.Conn, error) {
+                       logf("Dial")
+                       c, err := net.Dial(network, ts.Listener.Addr().String())
+                       if err != nil {
+                               logf("Dial error: %v", err)
+                               return nil, err
+                       }
+                       return &writerFuncConn{
+                               Conn: c,
+                               write: func(p []byte) (n int, err error) {
+                                       if atomic.AddInt32(&writeNumAtomic, 1) == 2 {
+                                               logf("intentional write failure")
+                                               return 0, errors.New("second write fails")
+                                       }
+                                       logf("Write(%q)", p)
+                                       return c.Write(p)
+                               },
+                       }, nil
+               },
+       }
+       defer tr.CloseIdleConnections()
        c := &Client{Transport: tr}
 
-       const N = 2
-       retryc := make(chan struct{}, N)
        SetRoundTripRetried(func() {
-               retryc <- struct{}{}
+               logf("Retried.")
        })
        defer SetRoundTripRetried(nil)
 
-       for n := 0; n < 100; n++ {
-               // open 2 conns
-               errc := make(chan error, N)
-               for i := 0; i < N; i++ {
-                       // start goroutines, send on errc
-                       go func() {
-                               res, err := c.Get(ts.URL)
-                               if err == nil {
-                                       res.Body.Close()
-                               }
-                               errc <- err
-                       }()
-               }
-               for i := 0; i < N; i++ {
-                       if err := <-errc; err != nil {
-                               t.Fatal(err)
-                       }
-               }
-
-               ts.CloseClientConnections()
-               for i := 0; i < N; i++ {
-                       go func() {
-                               res, err := c.Get(ts.URL)
-                               if err == nil {
-                                       res.Body.Close()
-                               }
-                               errc <- err
-                       }()
+       for i := 0; i < 3; i++ {
+               res, err := c.Get("http://fake.golang/")
+               if err != nil {
+                       t.Fatalf("i=%d: Get = %v", i, err)
                }
+               res.Body.Close()
+       }
 
-               for i := 0; i < N; i++ {
-                       if err := <-errc; err != nil {
-                               t.Fatal(err)
-                       }
-               }
-               for i := 0; i < N; i++ {
-                       select {
-                       case <-retryc:
-                               // we triggered a retry, test was successful
-                               t.Logf("finished after %d runs\n", n)
-                               return
-                       default:
-                       }
-               }
+       mu.Lock()
+       got := logbuf.String()
+       mu.Unlock()
+       const want = `Dial
+Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Handler
+intentional write failure
+Retried.
+Dial
+Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Handler
+Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Handler
+`
+       if got != want {
+               t.Errorf("Log of events differs. Got:\n%s\nWant:\n%s", got, want)
        }
-       t.Fatal("did not trigger any retries")
 }
 
 // Issue 6981
index 301a5cfd223aaa8f96de9b1c72634966ec0cc768..b3297f249d6c41a9cee3083f12e6fb654088267b 100644 (file)
@@ -172,6 +172,9 @@ func InterfaceByName(name string) (*Interface, error) {
 // An ipv6ZoneCache represents a cache holding partial network
 // interface information. It is used for reducing the cost of IPv6
 // addressing scope zone resolution.
+//
+// Multiple names sharing the index are managed by first-come
+// first-served basis for consistency.
 type ipv6ZoneCache struct {
        sync.RWMutex                // guard the following
        lastFetched  time.Time      // last time routing information was fetched
@@ -202,7 +205,9 @@ func (zc *ipv6ZoneCache) update(ift []Interface) {
        zc.toName = make(map[int]string, len(ift))
        for _, ifi := range ift {
                zc.toIndex[ifi.Name] = ifi.Index
-               zc.toName[ifi.Index] = ifi.Name
+               if _, ok := zc.toName[ifi.Index]; !ok {
+                       zc.toName[ifi.Index] = ifi.Name
+               }
        }
 }
 
index c5b454d3bded07f53917377c77eeb6d61f54a62d..db3364c1b317e18f7ff9b6c59820d0d1a0675149 100644 (file)
@@ -90,7 +90,7 @@ func CIDRMask(ones, bits int) IPMask {
 
 // Well-known IPv4 addresses
 var (
-       IPv4bcast     = IPv4(255, 255, 255, 255) // broadcast
+       IPv4bcast     = IPv4(255, 255, 255, 255) // limited broadcast
        IPv4allsys    = IPv4(224, 0, 0, 1)       // all systems
        IPv4allrouter = IPv4(224, 0, 0, 2)       // all routers
        IPv4zero      = IPv4(0, 0, 0, 0)         // all zeros
@@ -153,6 +153,12 @@ func (ip IP) IsLinkLocalUnicast() bool {
 
 // IsGlobalUnicast reports whether ip is a global unicast
 // address.
+//
+// The identification of global unicast addresses uses address type
+// identification as defined in RFC 1122, RFC 4632 and RFC 4291 with
+// the exception of IPv4 directed broadcast addresses.
+// It returns true even if ip is in IPv4 private address space or
+// local IPv6 unicast address space.
 func (ip IP) IsGlobalUnicast() bool {
        return (len(ip) == IPv4len || len(ip) == IPv6len) &&
                !ip.Equal(IPv4bcast) &&
@@ -654,13 +660,14 @@ func ParseIP(s string) IP {
        return nil
 }
 
-// ParseCIDR parses s as a CIDR notation IP address and mask,
+// ParseCIDR parses s as a CIDR notation IP address and prefix length,
 // like "192.0.2.0/24" or "2001:db8::/32", as defined in
 // RFC 4632 and RFC 4291.
 //
-// It returns the IP address and the network implied by the IP
-// and mask. For example, ParseCIDR("198.51.100.1/24") returns
-// the IP address 198.51.100.1 and the network 198.51.100.0/24.
+// It returns the IP address and the network implied by the IP and
+// prefix length.
+// For example, ParseCIDR("192.0.2.1/24") returns the IP address
+// 198.0.2.1 and the network 198.0.2.0/24.
 func ParseCIDR(s string) (IP, *IPNet, error) {
        i := byteIndex(s, '/')
        if i < 0 {
index b3cc03e00d46f4478a4cddaea0dcc0b2181084b7..d994fc67c65825f221f4b42dc25723b56159f953 100644 (file)
@@ -9,6 +9,18 @@ import (
        "syscall"
 )
 
+// BUG(mikio): On every POSIX platform, reads from the "ip4" network
+// using the ReadFrom or ReadFromIP method might not return a complete
+// IPv4 packet, including its header, even if there is space
+// available. This can occur even in cases where Read or ReadMsgIP
+// could return a complete packet. For this reason, it is recommended
+// that you do not use these methods if it is important to receive a
+// full packet.
+//
+// The Go 1 compatibility guidelines make it impossible for us to
+// change the behavior of these methods; use Read or ReadMsgIP
+// instead.
+
 // BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgIP and
 // WriteMsgIP methods of IPConn are not implemented.
 
index d5e229fb9cf6dd910108c906df97a5f12ad80a49..8f4b702e480624c340ac96714abab84f15c0d707 100644 (file)
@@ -11,18 +11,6 @@ import (
        "syscall"
 )
 
-// BUG(mikio): On every POSIX platform, reads from the "ip4" network
-// using the ReadFrom or ReadFromIP method might not return a complete
-// IPv4 packet, including its header, even if there is space
-// available. This can occur even in cases where Read or ReadMsgIP
-// could return a complete packet. For this reason, it is recommended
-// that you do not uses these methods if it is important to receive a
-// full packet.
-//
-// The Go 1 compatibility guidelines make it impossible for us to
-// change the behavior of these methods; use Read or ReadMsgIP
-// instead.
-
 func sockaddrToIP(sa syscall.Sockaddr) Addr {
        switch sa := sa.(type) {
        case *syscall.SockaddrInet4:
index 29cd4b6fd0d0352a7c6842a143cd3dfe82dd6e8d..5d33b26a91e0291b54ba232a176e6eaae6e28519 100644 (file)
@@ -43,6 +43,13 @@ var resolveIPAddrTests = []resolveIPAddrTest{
        {"l2tp", "127.0.0.1", nil, UnknownNetworkError("l2tp")},
        {"l2tp:gre", "127.0.0.1", nil, UnknownNetworkError("l2tp:gre")},
        {"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
+
+       {"ip4", "2001:db8::1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
+       {"ip4:icmp", "2001:db8::1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
+       {"ip6", "127.0.0.1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
+       {"ip6", "::ffff:127.0.0.1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
+       {"ip6:ipv6-icmp", "127.0.0.1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
+       {"ip6:ipv6-icmp", "::ffff:127.0.0.1", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
 }
 
 func TestResolveIPAddr(t *testing.T) {
@@ -54,21 +61,17 @@ func TestResolveIPAddr(t *testing.T) {
        defer func() { testHookLookupIP = origTestHookLookupIP }()
        testHookLookupIP = lookupLocalhost
 
-       for i, tt := range resolveIPAddrTests {
+       for _, tt := range resolveIPAddrTests {
                addr, err := ResolveIPAddr(tt.network, tt.litAddrOrName)
-               if err != tt.err {
-                       t.Errorf("#%d: %v", i, err)
-               } else if !reflect.DeepEqual(addr, tt.addr) {
-                       t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
-               }
-               if err != nil {
+               if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
+                       t.Errorf("ResolveIPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
                        continue
                }
-               rtaddr, err := ResolveIPAddr(addr.Network(), addr.String())
-               if err != nil {
-                       t.Errorf("#%d: %v", i, err)
-               } else if !reflect.DeepEqual(rtaddr, addr) {
-                       t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+               if err == nil {
+                       addr2, err := ResolveIPAddr(addr.Network(), addr.String())
+                       if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
+                               t.Errorf("(%q, %q): ResolveIPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
+                       }
                }
        }
 }
index c91e2017d412e5c03d86aa64af41484d7712180a..f1394a7ed87fc427f0bb03e067c16178916b7250 100644 (file)
@@ -10,6 +10,13 @@ import (
        "context"
 )
 
+// BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the
+// "tcp" and "udp" networks does not listen for both IPv4 and IPv6
+// connections. This is due to the fact that IPv4 traffic will not be
+// routed to an IPv6 socket - two separate sockets are required if
+// both address families are to be supported.
+// See inet6(4) for details.
+
 var (
        // supportsIPv4 reports whether the platform supports IPv4
        // networking functionality.
index f4fab3f9aa3436889dd2136674e42c63840f93ed..ff280c3e4e84e8adc7f8319c94bda916df00a645 100644 (file)
@@ -12,13 +12,6 @@ import (
        "syscall"
 )
 
-// BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the
-// "tcp" and "udp" networks does not listen for both IPv4 and IPv6
-// connections. This is due to the fact that IPv4 traffic will not be
-// routed to an IPv6 socket - two separate sockets are required if
-// both address families are to be supported.
-// See inet6(4) for details.
-
 func probeIPv4Stack() bool {
        s, err := socketFunc(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
        switch err {
index 8b5cab0894f8bae64e817bc354b96f156c2a4932..cc2013e432516d914d3bac53022228699ca19184 100644 (file)
@@ -233,20 +233,32 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por
        return port, nil
 }
 
-// LookupCNAME returns the canonical DNS host for the given name.
+// LookupCNAME returns the canonical name for the given host.
 // Callers that do not care about the canonical name can call
 // LookupHost or LookupIP directly; both take care of resolving
 // the canonical name as part of the lookup.
-func LookupCNAME(name string) (cname string, err error) {
-       return DefaultResolver.lookupCNAME(context.Background(), name)
+//
+// A canonical name is the final name after following zero
+// or more CNAME records.
+// LookupCNAME does not return an error if host does not
+// contain DNS "CNAME" records, as long as host resolves to
+// address records.
+func LookupCNAME(host string) (cname string, err error) {
+       return DefaultResolver.lookupCNAME(context.Background(), host)
 }
 
-// LookupCNAME returns the canonical DNS host for the given name.
+// LookupCNAME returns the canonical name for the given host.
 // Callers that do not care about the canonical name can call
 // LookupHost or LookupIP directly; both take care of resolving
 // the canonical name as part of the lookup.
-func (r *Resolver) LookupCNAME(ctx context.Context, name string) (cname string, err error) {
-       return r.lookupCNAME(ctx, name)
+//
+// A canonical name is the final name after following zero
+// or more CNAME records.
+// LookupCNAME does not return an error if host does not
+// contain DNS "CNAME" records, as long as host resolves to
+// address records.
+func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
+       return r.lookupCNAME(ctx, host)
 }
 
 // LookupSRV tries to resolve an SRV query of the given service,
index 11f2349afe6663bc2dd070810e11ec87aa5fc06a..f81e220fc8ce65ff4b262734c96f8cdfd4f3db43 100644 (file)
@@ -198,6 +198,10 @@ func (*Resolver) lookupPort(ctx context.Context, network, service string) (port
 func (*Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {
        lines, err := queryDNS(ctx, name, "cname")
        if err != nil {
+               if stringsHasSuffix(err.Error(), "dns failure") {
+                       cname = name + "."
+                       err = nil
+               }
                return
        }
        if len(lines) > 0 {
index 656bebb9b87531794baaa798b5b147de0ead8841..36db56acd03741da35a113bf93e4e0097e37f9a3 100644 (file)
@@ -243,14 +243,15 @@ func TestLookupIPv6LinkLocalAddr(t *testing.T) {
        }
 }
 
-var lookupIANACNAMETests = []struct {
+var lookupCNAMETests = []struct {
        name, cname string
 }{
        {"www.iana.org", "icann.org."},
        {"www.iana.org.", "icann.org."},
+       {"www.google.com", "google.com."},
 }
 
-func TestLookupIANACNAME(t *testing.T) {
+func TestLookupCNAME(t *testing.T) {
        if testenv.Builder() == "" {
                testenv.MustHaveExternalNetwork(t)
        }
@@ -259,7 +260,7 @@ func TestLookupIANACNAME(t *testing.T) {
                t.Skip("IPv4 is required")
        }
 
-       for _, tt := range lookupIANACNAMETests {
+       for _, tt := range lookupCNAMETests {
                cname, err := LookupCNAME(tt.name)
                if err != nil {
                        t.Fatal(err)
index 35f253c1da24a7e72a2cdb6f396484f3c70f2ff8..be2ced9c393fd62c5e1b60879da135bd129c6494 100644 (file)
@@ -72,17 +72,20 @@ func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, e
                // cgo not available (or netgo); fall back to Go's DNS resolver
                order = hostLookupFilesDNS
        }
-       return goLookupIPOrder(ctx, host, order)
+       addrs, _, err = goLookupIPCNAMEOrder(ctx, host, order)
+       return
 }
 
 func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
-       // TODO: use the context if there ever becomes a need. Related
-       // is issue 15321. But port lookup generally just involves
-       // local files, and the os package has no context support. The
-       // files might be on a remote filesystem, though. This should
-       // probably race goroutines if ctx != context.Background().
        if !r.PreferGo && systemConf().canUseCgo() {
                if port, err, ok := cgoLookupPort(ctx, network, service); ok {
+                       if err != nil {
+                               // Issue 18213: if cgo fails, first check to see whether we
+                               // have the answer baked-in to the net package.
+                               if port, err := goLookupPort(network, service); err == nil {
+                                       return port, nil
+                               }
+                       }
                        return port, err
                }
        }
index bc9ffe15a4654b915c465ac0d3ac0d8355bb479f..cebb2d0558976f578b2cbeb176e8504a614c15fd 100644 (file)
@@ -24,7 +24,7 @@ func toJson(v interface{}) string {
        return string(data)
 }
 
-func TestLookupMX(t *testing.T) {
+func TestNSLookupMX(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)
 
        for _, server := range nslookupTestServers {
@@ -49,7 +49,7 @@ func TestLookupMX(t *testing.T) {
        }
 }
 
-func TestLookupCNAME(t *testing.T) {
+func TestNSLookupCNAME(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)
 
        for _, server := range nslookupTestServers {
@@ -72,7 +72,7 @@ func TestLookupCNAME(t *testing.T) {
        }
 }
 
-func TestLookupNS(t *testing.T) {
+func TestNSLookupNS(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)
 
        for _, server := range nslookupTestServers {
@@ -98,7 +98,7 @@ func TestLookupNS(t *testing.T) {
        }
 }
 
-func TestLookupTXT(t *testing.T) {
+func TestNSLookupTXT(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)
 
        for _, server := range nslookupTestServers {
index 4e0478194e57bb4e650f99dfd2a96694d06c7da9..868d1e4784f2110e4e152a5d5e2a49f0d5bb5e01 100644 (file)
@@ -10,12 +10,11 @@ package net
 
 import "sync"
 
-var servicesError error
 var onceReadServices sync.Once
 
 func readServices() {
-       var file *file
-       if file, servicesError = open("/etc/services"); servicesError != nil {
+       file, err := open("/etc/services")
+       if err != nil {
                return
        }
        for line, ok := file.readLine(); ok; line, ok = file.readLine() {
index 573e834911b74115389dcbca7ff372f80fe1722c..54bf0cfccc3a44979d5fde9a049a92ebb1f1c1d5 100644 (file)
@@ -317,10 +317,11 @@ var resolveTCPAddrTests = []resolveTCPAddrTest{
        {"tcp", "[2001:db8::1]:http", &TCPAddr{IP: ParseIP("2001:db8::1"), Port: 80}, nil},
        {"tcp4", "127.0.0.1:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil},
        {"tcp4", "[::ffff:127.0.0.1]:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil},
+       {"tcp6", "[2001:db8::1]:http", &TCPAddr{IP: ParseIP("2001:db8::1"), Port: 80}, nil},
+
        {"tcp4", "[2001:db8::1]:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
        {"tcp6", "127.0.0.1:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
        {"tcp6", "[::ffff:127.0.0.1]:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
-       {"tcp6", "[2001:db8::1]:http", &TCPAddr{IP: ParseIP("2001:db8::1"), Port: 80}, nil},
 }
 
 func TestResolveTCPAddr(t *testing.T) {
@@ -331,13 +332,13 @@ func TestResolveTCPAddr(t *testing.T) {
        for _, tt := range resolveTCPAddrTests {
                addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
                if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
-                       t.Errorf("ResolveTCPAddr(%q, %q) = %v, %v, want %v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
+                       t.Errorf("ResolveTCPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
                        continue
                }
                if err == nil {
                        addr2, err := ResolveTCPAddr(addr.Network(), addr.String())
                        if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
-                               t.Errorf("(%q, %q): ResolveTCPAddr(%q, %q) = %v, %v, want %v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
+                               t.Errorf("(%q, %q): ResolveTCPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
                        }
                }
        }
index 29d769c5a5864076c93814aa8661afce347ace53..708cc10120912eacf04022e49d6e727fc8892fff 100644 (file)
@@ -72,6 +72,17 @@ var resolveUDPAddrTests = []resolveUDPAddrTest{
        {"udp", ":12345", &UDPAddr{Port: 12345}, nil},
 
        {"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
+
+       {"udp", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
+       {"udp", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("::ffff:127.0.0.1"), Port: 53}, nil},
+       {"udp", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
+       {"udp4", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
+       {"udp4", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
+       {"udp6", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
+
+       {"udp4", "[2001:db8::1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
+       {"udp6", "127.0.0.1:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
+       {"udp6", "[::ffff:127.0.0.1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
 }
 
 func TestResolveUDPAddr(t *testing.T) {
@@ -79,21 +90,17 @@ func TestResolveUDPAddr(t *testing.T) {
        defer func() { testHookLookupIP = origTestHookLookupIP }()
        testHookLookupIP = lookupLocalhost
 
-       for i, tt := range resolveUDPAddrTests {
+       for _, tt := range resolveUDPAddrTests {
                addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName)
-               if err != tt.err {
-                       t.Errorf("#%d: %v", i, err)
-               } else if !reflect.DeepEqual(addr, tt.addr) {
-                       t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
-               }
-               if err != nil {
+               if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
+                       t.Errorf("ResolveUDPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
                        continue
                }
-               rtaddr, err := ResolveUDPAddr(addr.Network(), addr.String())
-               if err != nil {
-                       t.Errorf("#%d: %v", i, err)
-               } else if !reflect.DeepEqual(rtaddr, addr) {
-                       t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+               if err == nil {
+                       addr2, err := ResolveUDPAddr(addr.Network(), addr.String())
+                       if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
+                               t.Errorf("(%q, %q): ResolveUDPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
+                       }
                }
        }
 }
index d3ac7ab4b9168deca638b485b0cc304e78592c84..34337450a08c7d78b9efe9faae81ef1087bf73ee 100644 (file)
@@ -247,6 +247,11 @@ func TestStdinClose(t *testing.T) {
 }
 
 // Issue 17647.
+// It used to be the case that TestStdinClose, above, would fail when
+// run under the race detector. This test is a variant of TestStdinClose
+// that also used to fail when run under the race detector.
+// This test is run by cmd/dist under the race detector to verify that
+// the race detector no longer reports any problems.
 func TestStdinCloseRace(t *testing.T) {
        cmd := helperCommand(t, "stdinClose")
        stdin, err := cmd.StdinPipe()
@@ -262,7 +267,12 @@ func TestStdinCloseRace(t *testing.T) {
                }
        }()
        go func() {
-               io.Copy(stdin, strings.NewReader(stdinCloseTestString))
+               // Send the wrong string, so that the child fails even
+               // if the other goroutine doesn't manage to kill it first.
+               // This test is to check that the race detector does not
+               // falsely report an error, so it doesn't matter how the
+               // child process fails.
+               io.Copy(stdin, strings.NewReader("unexpected string"))
                if err := stdin.Close(); err != nil {
                        t.Errorf("stdin.Close: %v", err)
                }
@@ -978,7 +988,7 @@ func TestContextCancel(t *testing.T) {
                        break
                }
                if time.Since(start) > time.Second {
-                       t.Fatal("cancelling context did not stop program")
+                       t.Fatal("canceling context did not stop program")
                }
                time.Sleep(time.Millisecond)
        }
index de245c54792b012258f8fcaad848cccf023789e4..d45a00b12396a64cdf50fca59540392538cc5abf 100644 (file)
@@ -260,7 +260,7 @@ func Create(name string) (*File, error) {
 var lstat = Lstat
 
 // Rename renames (moves) oldpath to newpath.
-// If newpath already exists, Rename replaces it.
+// If newpath already exists and is not a directory, Rename replaces it.
 // OS-specific restrictions may apply when oldpath and newpath are in different directories.
 // If there is an error, it will be of type *LinkError.
 func Rename(oldpath, newpath string) error {
index b1e20b78398191004e14bfd22bc74b74cbb6aec6..7ad9aac70e25101ffca31b7a7ba4cad98cd166c8 100644 (file)
@@ -54,12 +54,15 @@ var sysdir = func() *sysDir {
        case "darwin":
                switch runtime.GOARCH {
                case "arm", "arm64":
+                       /// At this point the test harness has not had a chance
+                       // to move us into the ./src/os directory, so the
+                       // current working directory is the root of the app.
                        wd, err := syscall.Getwd()
                        if err != nil {
                                wd = err.Error()
                        }
                        return &sysDir{
-                               filepath.Join(wd, "..", ".."),
+                               wd,
                                []string{
                                        "ResourceRules.plist",
                                        "Info.plist",
@@ -1708,51 +1711,62 @@ func TestLongPath(t *testing.T) {
                        t.Fatalf("RemoveAll failed: %v", err)
                }
        }(tmpdir)
+
+       // Test the boundary of 247 and fewer bytes (normal) and 248 and more bytes (adjusted).
+       sizes := []int{247, 248, 249, 400}
        for len(tmpdir) < 400 {
                tmpdir += "/dir3456789"
        }
-       if err := MkdirAll(tmpdir, 0755); err != nil {
-               t.Fatalf("MkdirAll failed: %v", err)
-       }
-       data := []byte("hello world\n")
-       if err := ioutil.WriteFile(tmpdir+"/foo.txt", data, 0644); err != nil {
-               t.Fatalf("ioutil.WriteFile() failed: %v", err)
-       }
-       if err := Rename(tmpdir+"/foo.txt", tmpdir+"/bar.txt"); err != nil {
-               t.Fatalf("Rename failed: %v", err)
-       }
-       mtime := time.Now().Truncate(time.Minute)
-       if err := Chtimes(tmpdir+"/bar.txt", mtime, mtime); err != nil {
-               t.Fatalf("Chtimes failed: %v", err)
-       }
-       names := []string{"bar.txt"}
-       if testenv.HasSymlink() {
-               if err := Symlink(tmpdir+"/bar.txt", tmpdir+"/symlink.txt"); err != nil {
-                       t.Fatalf("Symlink failed: %v", err)
-               }
-               names = append(names, "symlink.txt")
-       }
-       if testenv.HasLink() {
-               if err := Link(tmpdir+"/bar.txt", tmpdir+"/link.txt"); err != nil {
-                       t.Fatalf("Link failed: %v", err)
-               }
-               names = append(names, "link.txt")
-       }
-       for _, wantSize := range []int64{int64(len(data)), 0} {
-               for _, name := range names {
-                       path := tmpdir + "/" + name
-                       dir, err := Stat(path)
-                       if err != nil {
-                               t.Fatalf("Stat(%q) failed: %v", path, err)
+       for _, sz := range sizes {
+               t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) {
+                       sizedTempDir := tmpdir[:sz-1] + "x" // Ensure it does not end with a slash.
+
+                       // The various sized runs are for this call to trigger the boundary
+                       // condition.
+                       if err := MkdirAll(sizedTempDir, 0755); err != nil {
+                               t.Fatalf("MkdirAll failed: %v", err)
                        }
-                       filesize := size(path, t)
-                       if dir.Size() != filesize || filesize != wantSize {
-                               t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
+                       data := []byte("hello world\n")
+                       if err := ioutil.WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil {
+                               t.Fatalf("ioutil.WriteFile() failed: %v", err)
                        }
-               }
-               if err := Truncate(tmpdir+"/bar.txt", 0); err != nil {
-                       t.Fatalf("Truncate failed: %v", err)
-               }
+                       if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil {
+                               t.Fatalf("Rename failed: %v", err)
+                       }
+                       mtime := time.Now().Truncate(time.Minute)
+                       if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil {
+                               t.Fatalf("Chtimes failed: %v", err)
+                       }
+                       names := []string{"bar.txt"}
+                       if testenv.HasSymlink() {
+                               if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil {
+                                       t.Fatalf("Symlink failed: %v", err)
+                               }
+                               names = append(names, "symlink.txt")
+                       }
+                       if testenv.HasLink() {
+                               if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil {
+                                       t.Fatalf("Link failed: %v", err)
+                               }
+                               names = append(names, "link.txt")
+                       }
+                       for _, wantSize := range []int64{int64(len(data)), 0} {
+                               for _, name := range names {
+                                       path := sizedTempDir + "/" + name
+                                       dir, err := Stat(path)
+                                       if err != nil {
+                                               t.Fatalf("Stat(%q) failed: %v", path, err)
+                                       }
+                                       filesize := size(path, t)
+                                       if dir.Size() != filesize || filesize != wantSize {
+                                               t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
+                                       }
+                               }
+                               if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil {
+                                       t.Fatalf("Truncate failed: %v", err)
+                               }
+                       }
+               })
        }
 }
 
index ccac1c0b64b6ab87cbe4f100a37ac56c026fad49..101b026dc9e1b89bf09cfcab8a8e377f65a35103 100644 (file)
@@ -139,13 +139,16 @@ func dirname(path string) string {
 func fixLongPath(path string) string {
        // Do nothing (and don't allocate) if the path is "short".
        // Empirically (at least on the Windows Server 2013 builder),
-       // the kernel is arbitrarily okay with <= 248 bytes. That
+       // the kernel is arbitrarily okay with < 248 bytes. That
        // matches what the docs above say:
        // "When using an API to create a directory, the specified
        // path cannot be so long that you cannot append an 8.3 file
        // name (that is, the directory name cannot exceed MAX_PATH
        // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
-       if len(path) <= 248 {
+       //
+       // The MSDN docs appear to say that a normal path that is 248 bytes long
+       // will work; empirically the path must be less then 248 bytes long.
+       if len(path) < 248 {
                // Don't fix. (This is how Go 1.7 and earlier worked,
                // not automatically generating the \\?\ form)
                return path
index 7b44397afb324c54679150f2eca3f060655ff58a..ad61992ad311ead4def63fbf9293c6c9d25850c0 100644 (file)
@@ -15,31 +15,39 @@ var (
 )
 
 // User represents a user account.
-//
-// On POSIX systems Uid and Gid contain a decimal number
-// representing uid and gid. On windows Uid and Gid
-// contain security identifier (SID) in a string format.
-// On Plan 9, Uid, Gid, Username, and Name will be the
-// contents of /dev/user.
 type User struct {
-       Uid      string // user ID
-       Gid      string // primary group ID
+       // Uid is the user ID.
+       // On POSIX systems, this is a decimal number representing the uid.
+       // On Windows, this is a security identifier (SID) in a string format.
+       // On Plan 9, this is the contents of /dev/user.
+       Uid string
+       // Gid is the primary group ID.
+       // On POSIX systems, this is a decimal number representing the gid.
+       // On Windows, this is a SID in a string format.
+       // On Plan 9, this is the contents of /dev/user.
+       Gid string
+       // Username is the login name.
        Username string
-       Name     string
-       HomeDir  string
+       // Name is the user's real or display name.
+       // It might be blank.
+       // On POSIX systems, this is the first (or only) entry in the GECOS field
+       // list.
+       // On Windows, this is the user's display name.
+       // On Plan 9, this is the contents of /dev/user.
+       Name string
+       // HomeDir is the path to the user's home directory (if they have one).
+       HomeDir string
 }
 
 // Group represents a grouping of users.
 //
-// On POSIX systems Gid contains a decimal number
-// representing the group ID.
+// On POSIX systems Gid contains a decimal number representing the group ID.
 type Group struct {
        Gid  string // group ID
        Name string // group name
 }
 
-// UnknownUserIdError is returned by LookupId when
-// a user cannot be found.
+// UnknownUserIdError is returned by LookupId when a user cannot be found.
 type UnknownUserIdError int
 
 func (e UnknownUserIdError) Error() string {
index 60d46d9d421d21efb821a06afbffbb14c26bc343..ec792fc831aefbb77380fa27aef591b2fd1f3430 100644 (file)
@@ -18,6 +18,9 @@ func volumeNameLen(path string) int {
 }
 
 // HasPrefix exists for historical compatibility and should not be used.
+//
+// Deprecated: HasPrefix does not respect path boundaries and
+// does not ignore case when required.
 func HasPrefix(p, prefix string) bool {
        return strings.HasPrefix(p, prefix)
 }
index dddcac0a5c774f9b7179f889f545d6e72a062516..d77ff24cdc3186d64295b9ea06d361002a96edf1 100644 (file)
@@ -21,7 +21,8 @@ func volumeNameLen(path string) int {
 
 // HasPrefix exists for historical compatibility and should not be used.
 //
-// Deprecated: Use strings.HasPrefix instead.
+// Deprecated: HasPrefix does not respect path boundaries and
+// does not ignore case when required.
 func HasPrefix(p, prefix string) bool {
        return strings.HasPrefix(p, prefix)
 }
index 359703de2695390da242f154a74e21f892f078e0..0d8b62015c56846883da962fe319df7b33635fa9 100644 (file)
@@ -65,6 +65,9 @@ func volumeNameLen(path string) int {
 }
 
 // HasPrefix exists for historical compatibility and should not be used.
+//
+// Deprecated: HasPrefix does not respect path boundaries and
+// does not ignore case when required.
 func HasPrefix(p, prefix string) bool {
        if strings.HasPrefix(p, prefix) {
                return true
index bb05aabc924292e4d084700c11710300b831c9ef..f771fe3a8a342c371b40a3f2e6271c80ecbfc557 100644 (file)
@@ -47,7 +47,7 @@ func baseIsDotDot(path string) bool {
        return path[i+1:] == ".."
 }
 
-// toNorm returns the normalized path that is guranteed to be unique.
+// toNorm returns the normalized path that is guaranteed to be unique.
 // It should accept the following formats:
 //   * UNC paths                              (e.g \\server\share\foo\bar)
 //   * absolute paths                         (e.g C:\foo\bar)
index 5c822bd9ba5e50768f93123483efbe3dfd704a6e..b86099a4f6f0206aeb9a0dbf182243a74d4e0712 100644 (file)
@@ -4,7 +4,7 @@
 
 // Package plugin implements loading and symbol resolution of Go plugins.
 //
-// Currently plugins only work on Linux and Darwin.
+// Currently plugins only work on Linux.
 //
 // A plugin is a Go main package with exported functions and variables that
 // has been built with:
index 033a18171de96b966bc9f2233689dd5d49191d93..0be306dc5418e52ff65c57d8fbf072a43210654d 100644 (file)
@@ -26,6 +26,8 @@ import (
        "unsafe"
 )
 
+var sink interface{}
+
 func TestBool(t *testing.T) {
        v := ValueOf(true)
        if v.Bool() != true {
@@ -3689,7 +3691,7 @@ func checkSameType(t *testing.T, x, y interface{}) {
 
 func TestArrayOf(t *testing.T) {
        // check construction and use of type not in binary
-       for _, table := range []struct {
+       tests := []struct {
                n          int
                value      func(i int) interface{}
                comparable bool
@@ -3767,7 +3769,9 @@ func TestArrayOf(t *testing.T) {
                        comparable: true,
                        want:       "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
                },
-       } {
+       }
+
+       for _, table := range tests {
                at := ArrayOf(table.n, TypeOf(table.value(0)))
                v := New(at).Elem()
                vok := New(at).Elem()
@@ -4133,50 +4137,58 @@ func TestStructOfExportRules(t *testing.T) {
                f()
        }
 
-       for i, test := range []struct {
+       tests := []struct {
                field     StructField
                mustPanic bool
                exported  bool
        }{
                {
-                       field:     StructField{Name: "", Type: TypeOf(S1{})},
-                       mustPanic: false,
-                       exported:  true,
+                       field:    StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{})},
+                       exported: true,
                },
                {
-                       field:     StructField{Name: "", Type: TypeOf((*S1)(nil))},
-                       mustPanic: false,
-                       exported:  true,
+                       field:    StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil))},
+                       exported: true,
                },
                {
-                       field:     StructField{Name: "", Type: TypeOf(s2{})},
-                       mustPanic: false,
-                       exported:  false,
+                       field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{})},
+                       mustPanic: true,
                },
                {
-                       field:     StructField{Name: "", Type: TypeOf((*s2)(nil))},
-                       mustPanic: false,
-                       exported:  false,
+                       field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil))},
+                       mustPanic: true,
                },
                {
-                       field:     StructField{Name: "", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+                       field:     StructField{Name: "Name", Type: nil, PkgPath: ""},
                        mustPanic: true,
-                       exported:  true,
                },
                {
-                       field:     StructField{Name: "", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+                       field:     StructField{Name: "", Type: TypeOf(S1{}), PkgPath: ""},
                        mustPanic: true,
-                       exported:  true,
                },
                {
-                       field:     StructField{Name: "", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+                       field:     StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{}), PkgPath: "other/pkg"},
                        mustPanic: true,
-                       exported:  false,
                },
                {
-                       field:     StructField{Name: "", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+                       field:     StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+                       mustPanic: true,
+               },
+               {
+                       field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+                       mustPanic: true,
+               },
+               {
+                       field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+                       mustPanic: true,
+               },
+               {
+                       field:     StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"},
+                       mustPanic: true,
+               },
+               {
+                       field:     StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"},
                        mustPanic: true,
-                       exported:  false,
                },
                {
                        field:     StructField{Name: "S", Type: TypeOf(S1{})},
@@ -4184,81 +4196,68 @@ func TestStructOfExportRules(t *testing.T) {
                        exported:  true,
                },
                {
-                       field:     StructField{Name: "S", Type: TypeOf((*S1)(nil))},
-                       mustPanic: false,
-                       exported:  true,
+                       field:    StructField{Name: "S", Type: TypeOf((*S1)(nil))},
+                       exported: true,
                },
                {
-                       field:     StructField{Name: "S", Type: TypeOf(s2{})},
-                       mustPanic: false,
-                       exported:  true,
+                       field:    StructField{Name: "S", Type: TypeOf(s2{})},
+                       exported: true,
                },
                {
-                       field:     StructField{Name: "S", Type: TypeOf((*s2)(nil))},
-                       mustPanic: false,
-                       exported:  true,
+                       field:    StructField{Name: "S", Type: TypeOf((*s2)(nil))},
+                       exported: true,
                },
                {
                        field:     StructField{Name: "s", Type: TypeOf(S1{})},
                        mustPanic: true,
-                       exported:  false,
                },
                {
                        field:     StructField{Name: "s", Type: TypeOf((*S1)(nil))},
                        mustPanic: true,
-                       exported:  false,
                },
                {
                        field:     StructField{Name: "s", Type: TypeOf(s2{})},
                        mustPanic: true,
-                       exported:  false,
                },
                {
                        field:     StructField{Name: "s", Type: TypeOf((*s2)(nil))},
                        mustPanic: true,
-                       exported:  false,
                },
                {
                        field:     StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
                        mustPanic: true, // TODO(sbinet): creating a name with a package path
-                       exported:  false,
                },
                {
                        field:     StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
                        mustPanic: true, // TODO(sbinet): creating a name with a package path
-                       exported:  false,
                },
                {
                        field:     StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
                        mustPanic: true, // TODO(sbinet): creating a name with a package path
-                       exported:  false,
                },
                {
                        field:     StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
                        mustPanic: true, // TODO(sbinet): creating a name with a package path
-                       exported:  false,
                },
                {
                        field:     StructField{Name: "", Type: TypeOf(ΦType{})},
-                       mustPanic: false,
-                       exported:  true,
+                       mustPanic: true,
                },
                {
                        field:     StructField{Name: "", Type: TypeOf(φType{})},
-                       mustPanic: false,
-                       exported:  false,
+                       mustPanic: true,
                },
                {
-                       field:     StructField{Name: "Φ", Type: TypeOf(0)},
-                       mustPanic: false,
-                       exported:  true,
+                       field:    StructField{Name: "Φ", Type: TypeOf(0)},
+                       exported: true,
                },
                {
-                       field:     StructField{Name: "φ", Type: TypeOf(0)},
-                       mustPanic: false,
-                       exported:  false,
+                       field:    StructField{Name: "φ", Type: TypeOf(0)},
+                       exported: false,
                },
-       } {
+       }
+
+       for i, test := range tests {
                testPanic(i, test.mustPanic, func() {
                        typ := StructOf([]StructField{test.field})
                        if typ == nil {
@@ -4268,7 +4267,7 @@ func TestStructOfExportRules(t *testing.T) {
                        field := typ.Field(0)
                        n := field.Name
                        if n == "" {
-                               n = field.Type.Name()
+                               panic("field.Name must not be empty")
                        }
                        exported := isExported(n)
                        if exported != test.exported {
@@ -4346,7 +4345,7 @@ func TestStructOfGenericAlg(t *testing.T) {
                {Name: "S1", Type: st1},
        })
 
-       for _, table := range []struct {
+       tests := []struct {
                rt  Type
                idx []int
        }{
@@ -4427,7 +4426,9 @@ func TestStructOfGenericAlg(t *testing.T) {
                        ),
                        idx: []int{2},
                },
-       } {
+       }
+
+       for _, table := range tests {
                v1 := New(table.rt).Elem()
                v2 := New(table.rt).Elem()
 
@@ -4529,18 +4530,21 @@ func TestStructOfWithInterface(t *testing.T) {
        type Iface interface {
                Get() int
        }
-       for i, table := range []struct {
+       tests := []struct {
+               name string
                typ  Type
                val  Value
                impl bool
        }{
                {
+                       name: "StructI",
                        typ:  TypeOf(StructI(want)),
                        val:  ValueOf(StructI(want)),
                        impl: true,
                },
                {
-                       typ: PtrTo(TypeOf(StructI(want))),
+                       name: "StructI",
+                       typ:  PtrTo(TypeOf(StructI(want))),
                        val: ValueOf(func() interface{} {
                                v := StructI(want)
                                return &v
@@ -4548,7 +4552,8 @@ func TestStructOfWithInterface(t *testing.T) {
                        impl: true,
                },
                {
-                       typ: PtrTo(TypeOf(StructIPtr(want))),
+                       name: "StructIPtr",
+                       typ:  PtrTo(TypeOf(StructIPtr(want))),
                        val: ValueOf(func() interface{} {
                                v := StructIPtr(want)
                                return &v
@@ -4556,6 +4561,7 @@ func TestStructOfWithInterface(t *testing.T) {
                        impl: true,
                },
                {
+                       name: "StructIPtr",
                        typ:  TypeOf(StructIPtr(want)),
                        val:  ValueOf(StructIPtr(want)),
                        impl: false,
@@ -4565,13 +4571,16 @@ func TestStructOfWithInterface(t *testing.T) {
                //      val:  ValueOf(StructI(want)),
                //      impl: true,
                // },
-       } {
+       }
+
+       for i, table := range tests {
                rt := StructOf(
                        []StructField{
                                {
-                                       Name:    "",
-                                       PkgPath: "",
-                                       Type:    table.typ,
+                                       Name:      table.name,
+                                       Anonymous: true,
+                                       PkgPath:   "",
+                                       Type:      table.typ,
                                },
                        },
                )
@@ -5331,6 +5340,72 @@ func TestCallGC(t *testing.T) {
        f2("four", "five5", "six666", "seven77", "eight888")
 }
 
+// Issue 18635 (function version).
+func TestKeepFuncLive(t *testing.T) {
+       // Test that we keep makeFuncImpl live as long as it is
+       // referenced on the stack.
+       typ := TypeOf(func(i int) {})
+       var f, g func(in []Value) []Value
+       f = func(in []Value) []Value {
+               clobber()
+               i := int(in[0].Int())
+               if i > 0 {
+                       // We can't use Value.Call here because
+                       // runtime.call* will keep the makeFuncImpl
+                       // alive. However, by converting it to an
+                       // interface value and calling that,
+                       // reflect.callReflect is the only thing that
+                       // can keep the makeFuncImpl live.
+                       //
+                       // Alternate between f and g so that if we do
+                       // reuse the memory prematurely it's more
+                       // likely to get obviously corrupted.
+                       MakeFunc(typ, g).Interface().(func(i int))(i - 1)
+               }
+               return nil
+       }
+       g = func(in []Value) []Value {
+               clobber()
+               i := int(in[0].Int())
+               MakeFunc(typ, f).Interface().(func(i int))(i)
+               return nil
+       }
+       MakeFunc(typ, f).Call([]Value{ValueOf(10)})
+}
+
+// Issue 18635 (method version).
+type KeepMethodLive struct{}
+
+func (k KeepMethodLive) Method1(i int) {
+       clobber()
+       if i > 0 {
+               ValueOf(k).MethodByName("Method2").Interface().(func(i int))(i - 1)
+       }
+}
+
+func (k KeepMethodLive) Method2(i int) {
+       clobber()
+       ValueOf(k).MethodByName("Method1").Interface().(func(i int))(i)
+}
+
+func TestKeepMethodLive(t *testing.T) {
+       // Test that we keep methodValue live as long as it is
+       // referenced on the stack.
+       KeepMethodLive{}.Method1(10)
+}
+
+// clobber tries to clobber unreachable memory.
+func clobber() {
+       runtime.GC()
+       for i := 1; i < 32; i++ {
+               for j := 0; j < 10; j++ {
+                       obj := make([]*byte, i)
+                       sink = obj
+               }
+       }
+       runtime.GC()
+}
+
 type funcLayoutTest struct {
        rcvr, t                  Type
        size, argsize, retOffset uintptr
@@ -5951,6 +6026,7 @@ func TestSwapper(t *testing.T) {
                        want: []pairPtr{{5, 6, &c}, {3, 4, &b}, {1, 2, &a}},
                },
        }
+
        for i, tt := range tests {
                inStr := fmt.Sprint(tt.in)
                Swapper(tt.in)(tt.i, tt.j)
@@ -5976,3 +6052,38 @@ func TestUnaddressableField(t *testing.T) {
                lv.Set(rv)
        })
 }
+
+
+type Tint int
+
+type Tint2 = Tint
+
+type Talias1 struct {
+       byte
+       uint8
+       int
+       int32
+       rune
+}
+
+type Talias2 struct {
+       Tint
+       Tint2
+}
+
+func TestAliasNames(t *testing.T) {
+       t1 := Talias1{byte: 1, uint8: 2, int: 3, int32: 4, rune: 5}
+       out := fmt.Sprintf("%#v", t1)
+       want := "reflect_test.Talias1{byte:0x1, uint8:0x2, int:3, int32:4, rune:5}"
+       if out != want {
+               t.Errorf("Talias1 print:\nhave: %s\nwant: %s", out, want)
+       }
+
+       t2 := Talias2{Tint: 1, Tint2: 2}
+       out = fmt.Sprintf("%#v", t2)
+       want = "reflect_test.Talias2{Tint:1, Tint2:2}"
+       if out != want {
+               t.Errorf("Talias2 print:\nhave: %s\nwant: %s", out, want)
+       }
+}
+
index a7efeb8262a99b92fec548db8e0cbee7d1bb5d2d..885966db6fe92a35ebe1058e2f4e464f130b45db 100644 (file)
@@ -12,9 +12,12 @@ import (
 
 // makeFuncImpl is the closure value implementing the function
 // returned by MakeFunc.
+// The first two words of this type must be kept in sync with
+// methodValue and runtime.reflectMethodValue.
+// Any changes should be reflected in all three.
 type makeFuncImpl struct {
        code  uintptr
-       stack *bitVector // stack bitmap for args - offset known to runtime
+       stack *bitVector
        typ   *funcType
        fn    func([]Value) []Value
 }
@@ -70,11 +73,12 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 // word in the passed-in argument frame.
 func makeFuncStub()
 
-// This type is partially duplicated as runtime.reflectMethodValue.
-// Any changes should be reflected in both.
+// The first two words of this type must be kept in sync with
+// makeFuncImpl and runtime.reflectMethodValue.
+// Any changes should be reflected in all three.
 type methodValue struct {
        fn     uintptr
-       stack  *bitVector // stack bitmap for args - offset known to runtime
+       stack  *bitVector
        method int
        rcvr   Value
 }
index 9d6e7a6846781f7513760da833e01b9a56bf99a4..fbfda3a363d574555391bf955c855015ab891814 100644 (file)
@@ -417,9 +417,17 @@ type sliceType struct {
 
 // Struct field
 type structField struct {
-       name   name    // name is empty for embedded fields
-       typ    *rtype  // type of field
-       offset uintptr // byte offset of field within struct
+       name       name    // name is always non-empty
+       typ        *rtype  // type of field
+       offsetAnon uintptr // byte offset of field<<1 | isAnonymous
+}
+
+func (f *structField) offset() uintptr {
+       return f.offsetAnon >> 1
+}
+
+func (f *structField) anon() bool {
+       return f.offsetAnon&1 != 0
 }
 
 // structType represents a struct type.
@@ -1215,16 +1223,8 @@ func (t *structType) Field(i int) (f StructField) {
        }
        p := &t.fields[i]
        f.Type = toType(p.typ)
-       if name := p.name.name(); name != "" {
-               f.Name = name
-       } else {
-               t := f.Type
-               if t.Kind() == Ptr {
-                       t = t.Elem()
-               }
-               f.Name = t.Name()
-               f.Anonymous = true
-       }
+       f.Name = p.name.name()
+       f.Anonymous = p.anon()
        if !p.name.isExported() {
                f.PkgPath = p.name.pkgPath()
                if f.PkgPath == "" {
@@ -1234,7 +1234,7 @@ func (t *structType) Field(i int) (f StructField) {
        if tag := p.name.tag(); tag != "" {
                f.Tag = StructTag(tag)
        }
-       f.Offset = p.offset
+       f.Offset = p.offset()
 
        // NOTE(rsc): This is the only allocation in the interface
        // presented by a reflect.Type. It would be nice to avoid,
@@ -1321,19 +1321,15 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel
                        visited[t] = true
                        for i := range t.fields {
                                f := &t.fields[i]
-                               // Find name and type for field f.
-                               var fname string
+                               // Find name and (for anonymous field) type for field f.
+                               fname := f.name.name()
                                var ntyp *rtype
-                               if name := f.name.name(); name != "" {
-                                       fname = name
-                               } else {
+                               if f.anon() {
                                        // Anonymous field of type T or *T.
-                                       // Name taken from type.
                                        ntyp = f.typ
                                        if ntyp.Kind() == Ptr {
                                                ntyp = ntyp.Elem().common()
                                        }
-                                       fname = ntyp.Name()
                                }
 
                                // Does it match?
@@ -1390,14 +1386,12 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
        if name != "" {
                for i := range t.fields {
                        tf := &t.fields[i]
-                       tfname := tf.name.name()
-                       if tfname == "" {
-                               hasAnon = true
-                               continue
-                       }
-                       if tfname == name {
+                       if tf.name.name() == name {
                                return t.Field(i), true
                        }
+                       if tf.anon() {
+                               hasAnon = true
+                       }
                }
        }
        if !hasAnon {
@@ -1694,7 +1688,7 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
                        if cmpTags && tf.name.tag() != vf.name.tag() {
                                return false
                        }
-                       if tf.offset != vf.offset {
+                       if tf.offsetAnon != vf.offsetAnon {
                                return false
                        }
                        if !tf.name.isExported() {
@@ -2403,6 +2397,9 @@ func StructOf(fields []StructField) Type {
        lastzero := uintptr(0)
        repr = append(repr, "struct {"...)
        for i, field := range fields {
+               if field.Name == "" {
+                       panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name")
+               }
                if field.Type == nil {
                        panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
                }
@@ -2415,13 +2412,11 @@ func StructOf(fields []StructField) Type {
                        hasPtr = true
                }
 
-               name := ""
                // Update string and hash
-               if f.name.nameLen() > 0 {
-                       hash = fnv1(hash, []byte(f.name.name())...)
-                       repr = append(repr, (" " + f.name.name())...)
-                       name = f.name.name()
-               } else {
+               name := f.name.name()
+               hash = fnv1(hash, []byte(name)...)
+               repr = append(repr, (" " + name)...)
+               if f.anon() {
                        // Embedded field
                        if f.typ.Kind() == Ptr {
                                // Embedded ** and *interface{} are illegal
@@ -2429,11 +2424,7 @@ func StructOf(fields []StructField) Type {
                                if k := elem.Kind(); k == Ptr || k == Interface {
                                        panic("reflect.StructOf: illegal anonymous field type " + ft.String())
                                }
-                               name = elem.String()
-                       } else {
-                               name = ft.String()
                        }
-                       // TODO(sbinet) check for syntactically impossible type names?
 
                        switch f.typ.Kind() {
                        case Interface:
@@ -2565,11 +2556,12 @@ func StructOf(fields []StructField) Type {
                comparable = comparable && (ft.alg.equal != nil)
                hashable = hashable && (ft.alg.hash != nil)
 
-               f.offset = align(size, uintptr(ft.align))
+               offset := align(size, uintptr(ft.align))
                if ft.align > typalign {
                        typalign = ft.align
                }
-               size = f.offset + ft.size
+               size = offset + ft.size
+               f.offsetAnon |= offset << 1
 
                if ft.size == 0 {
                        lastzero = size
@@ -2761,7 +2753,7 @@ func StructOf(fields []StructField) Type {
                typ.alg.hash = func(p unsafe.Pointer, seed uintptr) uintptr {
                        o := seed
                        for _, ft := range typ.fields {
-                               pi := unsafe.Pointer(uintptr(p) + ft.offset)
+                               pi := unsafe.Pointer(uintptr(p) + ft.offset())
                                o = ft.typ.alg.hash(pi, o)
                        }
                        return o
@@ -2771,8 +2763,8 @@ func StructOf(fields []StructField) Type {
        if comparable {
                typ.alg.equal = func(p, q unsafe.Pointer) bool {
                        for _, ft := range typ.fields {
-                               pi := unsafe.Pointer(uintptr(p) + ft.offset)
-                               qi := unsafe.Pointer(uintptr(q) + ft.offset)
+                               pi := unsafe.Pointer(uintptr(p) + ft.offset())
+                               qi := unsafe.Pointer(uintptr(q) + ft.offset())
                                if !ft.typ.alg.equal(pi, qi) {
                                        return false
                                }
@@ -2794,25 +2786,27 @@ func StructOf(fields []StructField) Type {
 }
 
 func runtimeStructField(field StructField) structField {
-       exported := field.PkgPath == ""
-       if field.Name == "" {
-               t := field.Type.(*rtype)
-               if t.Kind() == Ptr {
-                       t = t.Elem().(*rtype)
-               }
-               exported = t.nameOff(t.str).isExported()
-       } else if exported {
-               b0 := field.Name[0]
-               if ('a' <= b0 && b0 <= 'z') || b0 == '_' {
-                       panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but has no PkgPath")
-               }
+       if field.PkgPath != "" {
+               panic("reflect.StructOf: StructOf does not allow unexported fields")
+       }
+
+       // Best-effort check for misuse.
+       // Since PkgPath is empty, not much harm done if Unicode lowercase slips through.
+       c := field.Name[0]
+       if 'a' <= c && c <= 'z' || c == '_' {
+               panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath")
+       }
+
+       offsetAnon := uintptr(0)
+       if field.Anonymous {
+               offsetAnon |= 1
        }
 
-       _ = resolveReflectType(field.Type.common())
+       resolveReflectType(field.Type.common()) // install in runtime
        return structField{
-               name:   newName(field.Name, string(field.Tag), field.PkgPath, exported),
-               typ:    field.Type.common(),
-               offset: 0,
+               name:       newName(field.Name, string(field.Tag), "", true),
+               typ:        field.Type.common(),
+               offsetAnon: offsetAnon,
        }
 }
 
@@ -2835,7 +2829,7 @@ func typeptrdata(t *rtype) uintptr {
                        }
                }
                f := st.fields[field]
-               return f.offset + f.typ.ptrdata
+               return f.offset() + f.typ.ptrdata
 
        default:
                panic("reflect.typeptrdata: unexpected type, " + t.String())
@@ -3209,7 +3203,7 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
                tt := (*structType)(unsafe.Pointer(t))
                for i := range tt.fields {
                        f := &tt.fields[i]
-                       addTypeBits(bv, offset+f.offset, f.typ)
+                       addTypeBits(bv, offset+f.offset(), f.typ)
                }
        }
 }
index 042414ffe78556ba56f3eb6853673f6c6edbc20e..1abfbe6f65029d2f83b2498579213a3b6b7d156c 100644 (file)
@@ -538,6 +538,11 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
                        off += typ.size
                }
        }
+
+       // runtime.getArgInfo expects to be able to find ctxt on the
+       // stack when it finds our caller, makeFuncStub. Make sure it
+       // doesn't get garbage collected.
+       runtime.KeepAlive(ctxt)
 }
 
 // methodReceiver returns information about the receiver
@@ -650,6 +655,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
        // though it's a heap object.
        memclrNoHeapPointers(args, frametype.size)
        framePool.Put(args)
+
+       // See the comment in callReflect.
+       runtime.KeepAlive(ctxt)
 }
 
 // funcName returns the name of f, for use in error messages.
@@ -755,7 +763,7 @@ func (v Value) Field(i int) Value {
        fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
        // Using an unexported field forces flagRO.
        if !field.name.isExported() {
-               if field.name.name() == "" {
+               if field.anon() {
                        fl |= flagEmbedRO
                } else {
                        fl |= flagStickyRO
@@ -766,7 +774,7 @@ func (v Value) Field(i int) Value {
        // In the former case, we want v.ptr + offset.
        // In the latter case, we must have field.offset = 0,
        // so v.ptr + field.offset is still okay.
-       ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
+       ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset())
        return Value{typ, ptr, fl}
 }
 
index 88fb708c7e2cc768cb07aea7e1203a4f86f83ad9..ea7c5c128d84c4ef840918736e500e4bd3a9c1db 100644 (file)
@@ -1,6 +1,139 @@
-This is a very incomplete and probably out-of-date guide to
-programming in the Go runtime and how it differs from writing normal
-Go.
+This is a living document and at times it will be out of date. It is
+intended to articulate how programming in the Go runtime differs from
+writing normal Go. It focuses on pervasive concepts rather than
+details of particular interfaces.
+
+Scheduler structures
+====================
+
+The scheduler manages three types of resources that pervade the
+runtime: Gs, Ms, and Ps. It's important to understand these even if
+you're not working on the scheduler.
+
+Gs, Ms, Ps
+----------
+
+A "G" is simply a goroutine. It's represented by type `g`. When a
+goroutine exits, its `g` object is returned to a pool of free `g`s and
+can later be reused for some other goroutine.
+
+An "M" is an OS thread that can be executing user Go code, runtime
+code, a system call, or be idle. It's represented by type `m`. There
+can be any number of Ms at a time since any number of threads may be
+blocked in system calls.
+
+Finally, a "P" represents the resources required to execute user Go
+code, such as scheduler and memory allocator state. It's represented
+by type `p`. There are exactly `GOMAXPROCS` Ps. A P can be thought of
+like a CPU in the OS scheduler and the contents of the `p` type like
+per-CPU state. This is a good place to put state that needs to be
+sharded for efficiency, but doesn't need to be per-thread or
+per-goroutine.
+
+The scheduler's job is to match up a G (the code to execute), an M
+(where to execute it), and a P (the rights and resources to execute
+it). When an M stops executing user Go code, for example by entering a
+system call, it returns its P to the idle P pool. In order to resume
+executing user Go code, for example on return from a system call, it
+must acquire a P from the idle pool.
+
+All `g`, `m`, and `p` objects are heap allocated, but are never freed,
+so their memory remains type stable. As a result, the runtime can
+avoid write barriers in the depths of the scheduler.
+
+User stacks and system stacks
+-----------------------------
+
+Every non-dead G has a *user stack* associated with it, which is what
+user Go code executes on. User stacks start small (e.g., 2K) and grow
+or shrink dynamically.
+
+Every M has a *system stack* associated with it (also known as the M's
+"g0" stack because it's implemented as a stub G) and, on Unix
+platforms, a *signal stack* (also known as the M's "gsignal" stack).
+System and signal stacks cannot grow, but are large enough to execute
+runtime and cgo code (8K in a pure Go binary; system-allocated in a
+cgo binary).
+
+Runtime code often temporarily switches to the system stack using
+`systemstack`, `mcall`, or `asmcgocall` to perform tasks that must not
+be preempted, that must not grow the user stack, or that switch user
+goroutines. Code running on the system stack is implicitly
+non-preemptible and the garbage collector does not scan system stacks.
+While running on the system stack, the current user stack is not used
+for execution.
+
+`getg()` and `getg().m.curg`
+----------------------------
+
+To get the current user `g`, use `getg().m.curg`.
+
+`getg()` alone returns the current `g`, but when executing on the
+system or signal stacks, this will return the current M's "g0" or
+"gsignal", respectively. This is usually not what you want.
+
+To determine if you're running on the user stack or the system stack,
+use `getg() == getg().m.curg`.
+
+Error handling and reporting
+============================
+
+Errors that can reasonably be recovered from in user code should use
+`panic` like usual. However, there are some situations where `panic`
+will cause an immediate fatal error, such as when called on the system
+stack or when called during `mallocgc`.
+
+Most errors in the runtime are not recoverable. For these, use
+`throw`, which dumps the traceback and immediately terminates the
+process. In general, `throw` should be passed a string constant to
+avoid allocating in perilous situations. By convention, additional
+details are printed before `throw` using `print` or `println` and the
+messages are prefixed with "runtime:".
+
+For runtime error debugging, it's useful to run with
+`GOTRACEBACK=system` or `GOTRACEBACK=crash`.
+
+Synchronization
+===============
+
+The runtime has multiple synchronization mechanisms. They differ in
+semantics and, in particular, in whether they interact with the
+goroutine scheduler or the OS scheduler.
+
+The simplest is `mutex`, which is manipulated using `lock` and
+`unlock`. This should be used to protect shared structures for short
+periods. Blocking on a `mutex` directly blocks the M, without
+interacting with the Go scheduler. This means it is safe to use from
+the lowest levels of the runtime, but also prevents any associated G
+and P from being rescheduled.
+
+For one-shot notifications, use `note`, which provides `notesleep` and
+`notewakeup`. Unlike traditional UNIX `sleep`/`wakeup`, `note`s are
+race-free, so `notesleep` returns immediately if the `notewakeup` has
+already happened. A `note` can be reset after use with `noteclear`,
+which must not race with a sleep or wakeup. Like `mutex`, blocking on
+a `note` blocks the M. However, there are different ways to sleep on a
+`note`:`notesleep` also prevents rescheduling of any associated G and
+P, while `notetsleepg` acts like a blocking system call that allows
+the P to be reused to run another G. This is still less efficient than
+blocking the G directly since it consumes an M.
+
+To interact directly with the goroutine scheduler, use `gopark` and
+`goready`. `gopark` parks the current goroutine—putting it in the
+"waiting" state and removing it from the scheduler's run queue—and
+schedules another goroutine on the current M/P. `goready` puts a
+parked goroutine back in the "runnable" state and adds it to the run
+queue.
+
+In summary,
+
+<table>
+<tr><th></th><th colspan="3">Blocks</th></tr>
+<tr><th>Interface</th><th>G</th><th>M</th><th>P</th></tr>
+<tr><td>mutex</td><td>Y</td><td>Y</td><td>Y</td></tr>
+<tr><td>note</td><td>Y</td><td>Y</td><td>Y/N</td></tr>
+<tr><td>park</td><td>Y</td><td>N</td><td>N</td></tr>
+</table>
 
 Unmanaged memory
 ================
index 9ffd297d842eab9b5ec98059c36b798137888969..cb428d6de3cbf745d33cfb5b1dfd3cbca9eb6542 100644 (file)
@@ -75,11 +75,24 @@ no7:
        TESTL   $(1<<5), runtime·cpuid_ebx7(SB) // check for AVX2 bit
        JEQ     noavx2
        MOVB    $1, runtime·support_avx2(SB)
-       JMP     nocpuinfo
+       JMP     testbmi1
 noavx:
        MOVB    $0, runtime·support_avx(SB)
 noavx2:
        MOVB    $0, runtime·support_avx2(SB)
+testbmi1:
+       // Detect BMI1 and BMI2 extensions as per
+       // 5.1.16.1 Detection of VEX-encoded GPR Instructions,
+       //   LZCNT and TZCNT, PREFETCHW chapter of [1]
+       MOVB    $0, runtime·support_bmi1(SB)
+       TESTL   $(1<<3), runtime·cpuid_ebx7(SB) // check for BMI1 bit
+       JEQ     testbmi2
+       MOVB    $1, runtime·support_bmi1(SB)
+testbmi2:
+       MOVB    $0, runtime·support_bmi2(SB)
+       TESTL   $(1<<8), runtime·cpuid_ebx7(SB) // check for BMI2 bit
+       JEQ     nocpuinfo
+       MOVB    $1, runtime·support_bmi2(SB)
 nocpuinfo:     
        
        // if there is an _cgo_init, call it.
@@ -742,7 +755,7 @@ havem:
        MOVQ    (g_sched+gobuf_pc)(SI), BX
        MOVQ    BX, -8(DI)
        // Compute the size of the frame, including return PC and, if
-       // GOEXPERIMENT=framepointer, the saved based pointer
+       // GOEXPERIMENT=framepointer, the saved base pointer
        MOVQ    ctxt+24(FP), BX
        LEAQ    fv+0(FP), AX
        SUBQ    SP, AX
index cd855c7d3409d4ae2080a1085189fe56022e2be0..73da768897b8882d7339427025ea37db960d555f 100644 (file)
 #define        REGCTXT R22
 
 TEXT runtime·rt0_go(SB),NOSPLIT,$0
-       // R29 = stack; R1 = argc; R2 = argv
+       // R29 = stack; R4 = argc; R5 = argv
 
        ADDU    $-12, R29
-       MOVW    R1, 4(R29)      // argc
-       MOVW    R2, 8(R29)      // argv
+       MOVW    R4, 4(R29)      // argc
+       MOVW    R5, 8(R29)      // argv
 
        // create istack out of the given (operating system) stack.
        // _cgo_init may update stackguard.
@@ -28,7 +28,16 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
        MOVW    R1, (g_stack+stack_lo)(g)
        MOVW    R29, (g_stack+stack_hi)(g)
 
-// TODO(mips32): cgo
+       // if there is a _cgo_init, call it using the gcc ABI.
+       MOVW    _cgo_init(SB), R25
+       BEQ     R25, nocgo
+       ADDU    $-16, R29
+       MOVW    R0, R7  // arg 3: not used
+       MOVW    R0, R6  // arg 2: not used
+       MOVW    $setg_gcc<>(SB), R5     // arg 1: setg
+       MOVW    g, R4   // arg 0: G
+       JAL     (R25)
+       ADDU    $16, R29
 
 nocgo:
        // update stackguard after _cgo_init
@@ -434,7 +443,7 @@ TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8
        JMP     (R4)
 
 // Save state of caller into g->sched. Smashes R1.
-TEXT gosave<>(SB),NOSPLIT,$0
+TEXT gosave<>(SB),NOSPLIT,$-4
        MOVW    R31, (g_sched+gobuf_pc)(g)
        MOVW    R29, (g_sched+gobuf_sp)(g)
        MOVW    R0, (g_sched+gobuf_lr)(g)
@@ -449,22 +458,168 @@ TEXT gosave<>(SB),NOSPLIT,$0
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
 // See cgocall.go for more details.
-// Not implemented.
 TEXT ·asmcgocall(SB),NOSPLIT,$0-12
-       UNDEF
+       MOVW    fn+0(FP), R25
+       MOVW    arg+4(FP), R4
+
+       MOVW    R29, R3 // save original stack pointer
+       MOVW    g, R2
+
+       // Figure out if we need to switch to m->g0 stack.
+       // We get called to create new OS threads too, and those
+       // come in on the m->g0 stack already.
+       MOVW    g_m(g), R5
+       MOVW    m_g0(R5), R6
+       BEQ     R6, g, g0
+
+       JAL     gosave<>(SB)
+       MOVW    R6, g
+       JAL     runtime·save_g(SB)
+       MOVW    (g_sched+gobuf_sp)(g), R29
+
+       // Now on a scheduling stack (a pthread-created stack).
+g0:
+       // Save room for two of our pointers and O32 frame.
+       ADDU    $-24, R29
+       AND     $~7, R29        // O32 ABI expects 8-byte aligned stack on function entry
+       MOVW    R2, 16(R29)     // save old g on stack
+       MOVW    (g_stack+stack_hi)(R2), R2
+       SUBU    R3, R2
+       MOVW    R2, 20(R29)     // save depth in old g stack (can't just save SP, as stack might be copied during a callback)
+       JAL     (R25)
+
+       // Restore g, stack pointer. R2 is return value.
+       MOVW    16(R29), g
+       JAL     runtime·save_g(SB)
+       MOVW    (g_stack+stack_hi)(g), R5
+       MOVW    20(R29), R6
+       SUBU    R6, R5
+       MOVW    R5, R29
+
+       MOVW    R2, ret+8(FP)
+       RET
 
 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
 // Turn the fn into a Go func (by taking its address) and call
 // cgocallback_gofunc.
-// Not implemented.
-TEXT runtime·cgocallback(SB),NOSPLIT,$0-16
-       UNDEF
+TEXT runtime·cgocallback(SB),NOSPLIT,$16-16
+       MOVW    $fn+0(FP), R1
+       MOVW    R1, 4(R29)
+       MOVW    frame+4(FP), R1
+       MOVW    R1, 8(R29)
+       MOVW    framesize+8(FP), R1
+       MOVW    R1, 12(R29)
+       MOVW    ctxt+12(FP), R1
+       MOVW    R1, 16(R29)
+       MOVW    $runtime·cgocallback_gofunc(SB), R1
+       JAL     (R1)
+       RET
 
-// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
 // See cgocall.go for more details.
-// Not implemented.
-TEXT ·cgocallback_gofunc(SB),NOSPLIT,$0-16
-       UNDEF
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-16
+       NO_LOCAL_POINTERS
+
+       // Load m and g from thread-local storage.
+       MOVB    runtime·iscgo(SB), R1
+       BEQ     R1, nocgo
+       JAL     runtime·load_g(SB)
+nocgo:
+
+       // If g is nil, Go did not create the current thread.
+       // Call needm to obtain one for temporary use.
+       // In this case, we're running on the thread stack, so there's
+       // lots of space, but the linker doesn't know. Hide the call from
+       // the linker analysis by using an indirect call.
+       BEQ     g, needm
+
+       MOVW    g_m(g), R3
+       MOVW    R3, savedm-4(SP)
+       JMP     havem
+
+needm:
+       MOVW    g, savedm-4(SP) // g is zero, so is m.
+       MOVW    $runtime·needm(SB), R4
+       JAL     (R4)
+
+       // Set m->sched.sp = SP, so that if a panic happens
+       // during the function we are about to execute, it will
+       // have a valid SP to run on the g0 stack.
+       // The next few lines (after the havem label)
+       // will save this SP onto the stack and then write
+       // the same SP back to m->sched.sp. That seems redundant,
+       // but if an unrecovered panic happens, unwindm will
+       // restore the g->sched.sp from the stack location
+       // and then systemstack will try to use it. If we don't set it here,
+       // that restored SP will be uninitialized (typically 0) and
+       // will not be usable.
+       MOVW    g_m(g), R3
+       MOVW    m_g0(R3), R1
+       MOVW    R29, (g_sched+gobuf_sp)(R1)
+
+havem:
+       // Now there's a valid m, and we're running on its m->g0.
+       // Save current m->g0->sched.sp on stack and then set it to SP.
+       // Save current sp in m->g0->sched.sp in preparation for
+       // switch back to m->curg stack.
+       // NOTE: unwindm knows that the saved g->sched.sp is at 4(R29) aka savedsp-8(SP).
+       MOVW    m_g0(R3), R1
+       MOVW    (g_sched+gobuf_sp)(R1), R2
+       MOVW    R2, savedsp-8(SP)
+       MOVW    R29, (g_sched+gobuf_sp)(R1)
+
+       // Switch to m->curg stack and call runtime.cgocallbackg.
+       // Because we are taking over the execution of m->curg
+       // but *not* resuming what had been running, we need to
+       // save that information (m->curg->sched) so we can restore it.
+       // We can restore m->curg->sched.sp easily, because calling
+       // runtime.cgocallbackg leaves SP unchanged upon return.
+       // To save m->curg->sched.pc, we push it onto the stack.
+       // This has the added benefit that it looks to the traceback
+       // routine like cgocallbackg is going to return to that
+       // PC (because the frame we allocate below has the same
+       // size as cgocallback_gofunc's frame declared above)
+       // so that the traceback will seamlessly trace back into
+       // the earlier calls.
+       //
+       // In the new goroutine, -4(SP) is unused (where SP refers to
+       // m->curg's SP while we're setting it up, before we've adjusted it).
+       MOVW    m_curg(R3), g
+       JAL     runtime·save_g(SB)
+       MOVW    (g_sched+gobuf_sp)(g), R2 // prepare stack as R2
+       MOVW    (g_sched+gobuf_pc)(g), R4
+       MOVW    R4, -12(R2)
+       MOVW    ctxt+12(FP), R1
+       MOVW    R1, -8(R2)
+       MOVW    $-12(R2), R29
+       JAL     runtime·cgocallbackg(SB)
+
+       // Restore g->sched (== m->curg->sched) from saved values.
+       MOVW    0(R29), R4
+       MOVW    R4, (g_sched+gobuf_pc)(g)
+       MOVW    $12(R29), R2
+       MOVW    R2, (g_sched+gobuf_sp)(g)
+
+       // Switch back to m->g0's stack and restore m->g0->sched.sp.
+       // (Unlike m->curg, the g0 goroutine never uses sched.pc,
+       // so we do not have to restore it.)
+       MOVW    g_m(g), R3
+       MOVW    m_g0(R3), g
+       JAL     runtime·save_g(SB)
+       MOVW    (g_sched+gobuf_sp)(g), R29
+       MOVW    savedsp-8(SP), R2
+       MOVW    R2, (g_sched+gobuf_sp)(g)
+
+       // If the m on entry was nil, we called needm above to borrow an m
+       // for the duration of the call. Since the call is over, return it with dropm.
+       MOVW    savedm-4(SP), R3
+       BNE     R3, droppedm
+       MOVW    $runtime·dropm(SB), R4
+       JAL     (R4)
+droppedm:
+
+       // Done!
+       RET
 
 // void setg(G*); set g. for use by needm.
 // This only happens if iscgo, so jump straight to save_g
@@ -475,9 +630,10 @@ TEXT runtime·setg(SB),NOSPLIT,$0-4
 
 // void setg_gcc(G*); set g in C TLS.
 // Must obey the gcc calling convention.
-// Not implemented.
 TEXT setg_gcc<>(SB),NOSPLIT,$0
-       UNDEF
+       MOVW    R4, g
+       JAL     runtime·save_g(SB)
+       RET
 
 TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
        MOVW    8(R29), R1      // LR saved by caller
@@ -764,9 +920,23 @@ TEXT runtime·return0(SB),NOSPLIT,$0
 
 // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
 // Must obey the gcc calling convention.
-// Not implemented.
 TEXT _cgo_topofstack(SB),NOSPLIT,$-4
-       UNDEF
+       // g (R30), R3 and REGTMP (R23) might be clobbered by load_g. R30 and R23
+       // are callee-save in the gcc calling convention, so save them.
+       MOVW    R23, R8
+       MOVW    g, R9
+       MOVW    R31, R10 // this call frame does not save LR
+
+       JAL     runtime·load_g(SB)
+       MOVW    g_m(g), R1
+       MOVW    m_curg(R1), R1
+       MOVW    (g_stack+stack_hi)(R1), R2 // return value in R2
+
+       MOVW    R8, R23
+       MOVW    R9, g
+       MOVW    R10, R31
+
+       RET
 
 // The top-most function running on a goroutine
 // returns to goexit+PCQuantum.
diff --git a/src/runtime/cgo/asm_mipsx.s b/src/runtime/cgo/asm_mipsx.s
new file mode 100644 (file)
index 0000000..dd16af6
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2016 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 mips mipsle
+
+#include "textflag.h"
+
+/*
+ * void crosscall2(void (*fn)(void*, int32, uintptr), void*, int32, uintptr)
+ * Save registers and call fn with two arguments.
+ */
+TEXT crosscall2(SB),NOSPLIT,$-4
+       /*
+        * We still need to save all callee save register as before, and then
+        *  push 3 args for fn (R5, R6, R7).
+        * Also note that at procedure entry in gc world, 4(R29) will be the
+        *  first arg.
+        */
+
+       // Space for 9 caller-saved GPR + LR + 6 caller-saved FPR.
+       // O32 ABI allows us to smash 16 bytes argument area of caller frame.
+       SUBU    $(4*14+8*6-16), R29
+       MOVW    R5, (4*1)(R29)
+       MOVW    R6, (4*2)(R29)
+       MOVW    R7, (4*3)(R29)
+       MOVW    R16, (4*4)(R29)
+       MOVW    R17, (4*5)(R29)
+       MOVW    R18, (4*6)(R29)
+       MOVW    R19, (4*7)(R29)
+       MOVW    R20, (4*8)(R29)
+       MOVW    R21, (4*9)(R29)
+       MOVW    R22, (4*10)(R29)
+       MOVW    R23, (4*11)(R29)
+       MOVW    g, (4*12)(R29)
+       MOVW    R31, (4*13)(R29)
+
+       MOVD    F20, (4*14)(R29)
+       MOVD    F22, (4*14+8*1)(R29)
+       MOVD    F24, (4*14+8*2)(R29)
+       MOVD    F26, (4*14+8*3)(R29)
+       MOVD    F28, (4*14+8*4)(R29)
+       MOVD    F30, (4*14+8*5)(R29)
+
+       JAL     runtime·load_g(SB)
+       JAL     (R4)
+
+       MOVW    (4*4)(R29), R16
+       MOVW    (4*5)(R29), R17
+       MOVW    (4*6)(R29), R18
+       MOVW    (4*7)(R29), R19
+       MOVW    (4*8)(R29), R20
+       MOVW    (4*9)(R29), R21
+       MOVW    (4*10)(R29), R22
+       MOVW    (4*11)(R29), R23
+       MOVW    (4*12)(R29), g
+       MOVW    (4*13)(R29), R31
+
+       MOVD    (4*14)(R29), F20
+       MOVD    (4*14+8*1)(R29), F22
+       MOVD    (4*14+8*2)(R29), F24
+       MOVD    (4*14+8*3)(R29), F26
+       MOVD    (4*14+8*4)(R29), F28
+       MOVD    (4*14+8*5)(R29), F30
+
+       ADDU    $(4*14+8*6-16), R29
+       RET
diff --git a/src/runtime/cgo/gcc_linux_mipsx.c b/src/runtime/cgo/gcc_linux_mipsx.c
new file mode 100644 (file)
index 0000000..7ed9d87
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2016 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 cgo
+// +build linux
+// +build mips mipsle
+
+#include <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void *threadentry(void*);
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+void (*setg_gcc)(void*);
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+       pthread_attr_t attr;
+       sigset_t ign, oset;
+       pthread_t p;
+       size_t size;
+       int err;
+
+       sigfillset(&ign);
+       pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+       // Not sure why the memset is necessary here,
+       // but without it, we get a bogus stack size
+       // out of pthread_attr_getstacksize.  C'est la Linux.
+       memset(&attr, 0, sizeof attr);
+       pthread_attr_init(&attr);
+       size = 0;
+       pthread_attr_getstacksize(&attr, &size);
+       // Leave stacklo=0 and set stackhi=size; mstack will do the rest.
+       ts->g->stackhi = size;
+       err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+       pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+       if (err != 0) {
+               fatalf("pthread_create failed: %s", strerror(err));
+       }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+       ThreadStart ts;
+
+       ts = *(ThreadStart*)v;
+       free(v);
+
+       crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+       return nil;
+}
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+       pthread_attr_t attr;
+       size_t size;
+
+       setg_gcc = setg;
+
+       memset(&attr, 0, sizeof attr);
+       pthread_attr_init(&attr);
+       pthread_attr_getstacksize(&attr, &size);
+       g->stacklo = (uintptr)&attr - size + 4096;
+       pthread_attr_destroy(&attr);
+
+       if (x_cgo_inittls) {
+               x_cgo_inittls(tlsg, tlsbase);
+       }
+}
diff --git a/src/runtime/cgo/gcc_mipsx.S b/src/runtime/cgo/gcc_mipsx.S
new file mode 100644 (file)
index 0000000..c51c36a
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2016 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 mips mipsle
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard MIPS O32 ABI, where $16-$23, $30, and $f20-$f31
+ * are callee-save, so they must be saved explicitly, along with $31 (LR).
+ */
+.globl crosscall1
+.set noat
+crosscall1:
+       addiu   $29, $29, -88
+
+       sw      $31, 0($29)
+       sw      $16, 4($29)
+       sw      $17, 8($29)
+       sw      $18, 12($29)
+       sw      $19, 16($29)
+       sw      $20, 20($29)
+       sw      $21, 24($29)
+       sw      $22, 28($29)
+       sw      $23, 32($29)
+       sw      $30, 36($29)
+
+       sdc1    $f20, 40($29)
+       sdc1    $f22, 48($29)
+       sdc1    $f24, 56($29)
+       sdc1    $f26, 64($29)
+       sdc1    $f28, 72($29)
+       sdc1    $f30, 80($29)
+
+
+       move    $20, $4 // save R4
+       move    $4, $6
+       jalr    $5      // call setg_gcc
+       jalr    $20     // call fn
+
+       lw      $16, 4($29)
+       lw      $17, 8($29)
+       lw      $18, 12($29)
+       lw      $19, 16($29)
+       lw      $20, 20($29)
+       lw      $21, 24($29)
+       lw      $22, 28($29)
+       lw      $23, 32($29)
+       lw      $30, 36($29)
+       ldc1    $f20, 40($29)
+       ldc1    $f22, 48($29)
+       ldc1    $f24, 56($29)
+       ldc1    $f26, 64($29)
+       ldc1    $f28, 72($29)
+       ldc1    $f30, 80($29)
+
+       lw      $31, 0($29)
+
+       addiu   $29, $29, 88
+       jr      $31
+
+.set at
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
index 007406b42658f2b472b7dbf9cc2e227133ab78f8..879e786231389010090248523de5efa68116f78d 100644 (file)
@@ -286,6 +286,10 @@ func cgocallbackg1(ctxt uintptr) {
                // On mips64x, stack frame is two words and there's a saved LR between
                // SP and the stack frame and between the stack frame and the arguments.
                cb = (*args)(unsafe.Pointer(sp + 4*sys.PtrSize))
+       case "mips", "mipsle":
+               // On mipsx, stack frame is two words and there's a saved LR between
+               // SP and the stack frame and between the stack frame and the arguments.
+               cb = (*args)(unsafe.Pointer(sp + 4*sys.PtrSize))
        }
 
        // Invoke callback.
@@ -323,7 +327,7 @@ func unwindm(restore *bool) {
        switch GOARCH {
        default:
                throw("unwindm not implemented")
-       case "386", "amd64", "arm", "ppc64", "ppc64le", "mips64", "mips64le", "s390x":
+       case "386", "amd64", "arm", "ppc64", "ppc64le", "mips64", "mips64le", "s390x", "mips", "mipsle":
                sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + sys.MinFrameSize))
        case "arm64":
                sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 16))
@@ -527,7 +531,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
                        return
                }
                for _, f := range st.fields {
-                       cgoCheckArg(f.typ, add(p, f.offset), true, top, msg)
+                       cgoCheckArg(f.typ, add(p, f.offset()), true, top, msg)
                }
        case kindPtr, kindUnsafePointer:
                if indir {
index b22e8259add67fbd9a7ce2bf08fd8afc8aeaf852..5f3fb53423297be3356292429fee7543eaf284ed 100644 (file)
@@ -8,7 +8,7 @@ import "unsafe"
 
 // fastlog2 implements a fast approximation to the base 2 log of a
 // float64. This is used to compute a geometric distribution for heap
-// sampling, without introducing dependences into package math. This
+// sampling, without introducing dependencies into package math. This
 // uses a very rough approximation using the float64 exponent and the
 // first 25 bits of the mantissa. The top 5 bits of the mantissa are
 // used to load limits from a table of constants and the rest are used
@@ -29,5 +29,5 @@ func fastlog2(x float64) float64 {
 }
 
 // float64bits returns the IEEE 754 binary representation of f.
-// Taken from math.Float64bits to avoid dependences into package math.
+// Taken from math.Float64bits to avoid dependencies into package math.
 func float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
index c932e149ddda9c907a50eaf86a870a97730c06a4..46010d58fc28f0fad60f6784a4db5b33988bb2dc 100644 (file)
@@ -138,11 +138,8 @@ func additab(m *itab, locked, canfail bool) {
                throw("invalid itab locking")
        }
        h := itabhash(inter, typ)
-       if m == hash[h] {
-               println("duplicate itab for", typ.string(), "and", inter.typ.string())
-               throw("duplicate itabs")
-       }
        m.link = hash[h]
+       m.inhash = 1
        atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
 }
 
@@ -150,7 +147,14 @@ func itabsinit() {
        lock(&ifaceLock)
        for _, md := range activeModules() {
                for _, i := range md.itablinks {
-                       additab(i, true, false)
+                       // itablinks is a slice of pointers to the itabs used in this
+                       // module. A given itab may be used in more than one module
+                       // and thanks to the way global symbol resolution works, the
+                       // pointed-to itab may already have been inserted into the
+                       // global 'hash'.
+                       if i.inhash == 0 {
+                               additab(i, true, false)
+                       }
                }
        }
        unlock(&ifaceLock)
@@ -179,7 +183,7 @@ func panicnildottype(want *_type) {
 
 // The conv and assert functions below do very similar things.
 // The convXXX functions are guaranteed by the compiler to succeed.
-// The assertXXX functions may fail (either panicing or returning false,
+// The assertXXX functions may fail (either panicking or returning false,
 // depending on whether they are 1-result or 2-result).
 // The convXXX functions succeed on a nil input, whereas the assertXXX
 // functions fail on a nil input.
index 1c9efc3432e422fcbc4b3ae3e5e27f1a46c42988..da39dac5102923da939df0b637238aa42c7793d0 100644 (file)
@@ -157,6 +157,13 @@ const (
        _MaxGcproc = 32
 
        _MaxArena32 = 1<<32 - 1
+
+       // minLegalPointer is the smallest possible legal pointer.
+       // This is the smallest possible architectural page size,
+       // since we assume that the first page is never mapped.
+       //
+       // This should agree with minZeroPage in the compiler.
+       minLegalPointer uintptr = 4096
 )
 
 // physPageSize is the size in bytes of the OS's physical pages.
index 767b51f453bb124eb12b7ed5e474c1c3cdf7bc9d..0cf9cfbf4279ca4974573b5ee2e26ca63ef8b112 100644 (file)
@@ -13,6 +13,9 @@ import (
 )
 
 func TestMemStats(t *testing.T) {
+       // Make sure there's at least one forced GC.
+       GC()
+
        // Test that MemStats has sane values.
        st := new(MemStats)
        ReadMemStats(st)
@@ -24,7 +27,7 @@ func TestMemStats(t *testing.T) {
                st.HeapInuse == 0 || st.HeapObjects == 0 || st.StackInuse == 0 ||
                st.StackSys == 0 || st.MSpanInuse == 0 || st.MSpanSys == 0 || st.MCacheInuse == 0 ||
                st.MCacheSys == 0 || st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 ||
-               st.NextGC == 0 {
+               st.NextGC == 0 || st.NumForcedGC == 0 {
                t.Fatalf("Zero value: %+v", *st)
        }
 
@@ -33,7 +36,7 @@ func TestMemStats(t *testing.T) {
                st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 ||
                st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 ||
                st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 ||
-               st.NextGC > 1e10 || st.NumGC > 1e9 || st.PauseTotalNs > 1e11 {
+               st.NextGC > 1e10 || st.NumGC > 1e9 || st.NumForcedGC > 1e9 || st.PauseTotalNs > 1e11 {
                t.Fatalf("Insanely high value (overflow?): %+v", *st)
        }
 
@@ -72,6 +75,10 @@ func TestMemStats(t *testing.T) {
                        t.Fatalf("PauseTotalNs(%d) < sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
                }
        }
+
+       if st.NumForcedGC > st.NumGC {
+               t.Fatalf("NumForcedGC(%d) > NumGC(%d)", st.NumForcedGC, st.NumGC)
+       }
 }
 
 func TestStringConcatenationAllocs(t *testing.T) {
index 464f5fdc1b48b549030f885cb203291c92b2890c..c2286d3edd241ca1801565745d9829110677c432 100644 (file)
@@ -146,10 +146,16 @@ move_1or2:
 move_0:
        RET
 move_3or4:
+       CMPQ    BX, $4
+       JB      move_3
+       MOVL    (SI), AX
+       MOVL    AX, (DI)
+       RET
+move_3:
        MOVW    (SI), AX
-       MOVW    -2(SI)(BX*1), CX
+       MOVB    2(SI), CX
        MOVW    AX, (DI)
-       MOVW    CX, -2(DI)(BX*1)
+       MOVB    CX, 2(DI)
        RET
 move_5through7:
        MOVL    (SI), AX
index dbfa284c28bc6020592b2d33afdc8207d7fef4a1..74b8753b5f78f4f22f53346c2ce0b3f9113f2980 100644 (file)
@@ -6,6 +6,7 @@ package runtime_test
 
 import (
        "crypto/rand"
+       "encoding/binary"
        "fmt"
        "internal/race"
        . "runtime"
@@ -447,3 +448,22 @@ func BenchmarkCopyFat1024(b *testing.B) {
                _ = y
        }
 }
+
+func BenchmarkIssue18740(b *testing.B) {
+       // This tests that memmove uses one 4-byte load/store to move 4 bytes.
+       // It used to do 2 2-byte load/stores, which leads to a pipeline stall
+       // when we try to read the result with one 4-byte load.
+       var buf [4]byte
+       for j := 0; j < b.N; j++ {
+               s := uint32(0)
+               for i := 0; i < 4096; i += 4 {
+                       copy(buf[:], g[i:])
+                       s += binary.LittleEndian.Uint32(buf[:])
+               }
+               sink = uint64(s)
+       }
+}
+
+// TODO: 2 byte and 8 byte benchmarks also.
+
+var g [4096]byte
index cc79d4cfff377b764b7d863806f0d1670cf7f241..0b996d895080c9ba73bcab3666e5447ff96928a5 100644 (file)
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO(rsc): The code having to do with the heap bitmap needs very serious cleanup.
-// It has gotten completely out of control.
-
 // Garbage collector (GC).
 //
 // The GC runs concurrently with mutator threads, is type accurate (aka precise), allows multiple
 // Hudson, R., and Moss, J.E.B. Copying Garbage Collection without stopping the world.
 // Concurrency and Computation: Practice and Experience 15(3-5), 2003.
 //
-// TODO(austin): The rest of this comment is woefully out of date and
-// needs to be rewritten. There is no distinct scan phase any more and
-// we allocate black during GC.
+// 1. GC performs sweep termination.
+//
+//    a. Stop the world. This causes all Ps to reach a GC safe-point.
+//
+//    b. Sweep any unswept spans. There will only be unswept spans if
+//    this GC cycle was forced before the expected time.
+//
+// 2. GC performs the "mark 1" sub-phase. In this sub-phase, Ps are
+// allowed to locally cache parts of the work queue.
+//
+//    a. Prepare for the mark phase by setting gcphase to _GCmark
+//    (from _GCoff), enabling the write barrier, enabling mutator
+//    assists, and enqueueing root mark jobs. No objects may be
+//    scanned until all Ps have enabled the write barrier, which is
+//    accomplished using STW.
+//
+//    b. Start the world. From this point, GC work is done by mark
+//    workers started by the scheduler and by assists performed as
+//    part of allocation. The write barrier shades both the
+//    overwritten pointer and the new pointer value for any pointer
+//    writes (see mbarrier.go for details). Newly allocated objects
+//    are immediately marked black.
+//
+//    c. GC performs root marking jobs. This includes scanning all
+//    stacks, shading all globals, and shading any heap pointers in
+//    off-heap runtime data structures. Scanning a stack stops a
+//    goroutine, shades any pointers found on its stack, and then
+//    resumes the goroutine.
+//
+//    d. GC drains the work queue of grey objects, scanning each grey
+//    object to black and shading all pointers found in the object
+//    (which in turn may add those pointers to the work queue).
+//
+// 3. Once the global work queue is empty (but local work queue caches
+// may still contain work), GC performs the "mark 2" sub-phase.
+//
+//    a. GC stops all workers, disables local work queue caches,
+//    flushes each P's local work queue cache to the global work queue
+//    cache, and reenables workers.
+//
+//    b. GC again drains the work queue, as in 2d above.
+//
+// 4. Once the work queue is empty, GC performs mark termination.
+//
+//    a. Stop the world.
+//
+//    b. Set gcphase to _GCmarktermination, and disable workers and
+//    assists.
 //
-//  0. Set phase = GCscan from GCoff.
-//  1. Wait for all P's to acknowledge phase change.
-//         At this point all goroutines have passed through a GC safepoint and
-//         know we are in the GCscan phase.
-//  2. GC scans all goroutine stacks, mark and enqueues all encountered pointers
-//       (marking avoids most duplicate enqueuing but races may produce benign duplication).
-//       Preempted goroutines are scanned before P schedules next goroutine.
-//  3. Set phase = GCmark.
-//  4. Wait for all P's to acknowledge phase change.
-//  5. Now write barrier marks and enqueues black, grey, or white to white pointers.
-//       Malloc still allocates white (non-marked) objects.
-//  6. Meanwhile GC transitively walks the heap marking reachable objects.
-//  7. When GC finishes marking heap, it preempts P's one-by-one and
-//       retakes partial wbufs (filled by write barrier or during a stack scan of the goroutine
-//       currently scheduled on the P).
-//  8. Once the GC has exhausted all available marking work it sets phase = marktermination.
-//  9. Wait for all P's to acknowledge phase change.
-// 10. Malloc now allocates black objects, so number of unmarked reachable objects
-//        monotonically decreases.
-// 11. GC preempts P's one-by-one taking partial wbufs and marks all unmarked yet
-//        reachable objects.
-// 12. When GC completes a full cycle over P's and discovers no new grey
-//         objects, (which means all reachable objects are marked) set phase = GCoff.
-// 13. Wait for all P's to acknowledge phase change.
-// 14. Now malloc allocates white (but sweeps spans before use).
-//         Write barrier becomes nop.
-// 15. GC does background sweeping, see description below.
-// 16. When sufficient allocation has taken place replay the sequence starting at 0 above,
-//         see discussion of GC rate below.
-
-// Changing phases.
-// Phases are changed by setting the gcphase to the next phase and possibly calling ackgcphase.
-// All phase action must be benign in the presence of a change.
-// Starting with GCoff
-// GCoff to GCscan
-//     GSscan scans stacks and globals greying them and never marks an object black.
-//     Once all the P's are aware of the new phase they will scan gs on preemption.
-//     This means that the scanning of preempted gs can't start until all the Ps
-//     have acknowledged.
-//     When a stack is scanned, this phase also installs stack barriers to
-//     track how much of the stack has been active.
-//     This transition enables write barriers because stack barriers
-//     assume that writes to higher frames will be tracked by write
-//     barriers. Technically this only needs write barriers for writes
-//     to stack slots, but we enable write barriers in general.
-// GCscan to GCmark
-//     In GCmark, work buffers are drained until there are no more
-//     pointers to scan.
-//     No scanning of objects (making them black) can happen until all
-//     Ps have enabled the write barrier, but that already happened in
-//     the transition to GCscan.
-// GCmark to GCmarktermination
-//     The only change here is that we start allocating black so the Ps must acknowledge
-//     the change before we begin the termination algorithm
-// GCmarktermination to GSsweep
-//     Object currently on the freelist must be marked black for this to work.
-//     Are things on the free lists black or white? How does the sweep phase work?
+//    c. Drain any remaining work from the work queue (typically there
+//    will be none).
+//
+//    d. Perform other housekeeping like flushing mcaches.
+//
+// 5. GC performs the sweep phase.
+//
+//    a. Prepare for the sweep phase by setting gcphase to _GCoff,
+//    setting up sweep state and disabling the write barrier.
+//
+//    b. Start the world. From this point on, newly allocated objects
+//    are white, and allocating sweeps spans before use if necessary.
+//
+//    c. GC does concurrent sweeping in the background and in response
+//    to allocation. See description below.
+//
+// 6. When sufficient allocation has taken place, replay the sequence
+// starting with 1 above. See discussion of GC rate below.
 
 // Concurrent sweep.
 //
@@ -902,7 +905,7 @@ type gcMode int
 const (
        gcBackgroundMode gcMode = iota // concurrent GC and sweep
        gcForceMode                    // stop-the-world GC now, concurrent sweep
-       gcForceBlockMode               // stop-the-world GC now and STW sweep
+       gcForceBlockMode               // stop-the-world GC now and STW sweep (forced by user)
 )
 
 // gcShouldStart returns true if the exit condition for the _GCoff
@@ -966,6 +969,9 @@ func gcStart(mode gcMode, forceTrigger bool) {
                }
        }
 
+       // For stats, check if this GC was forced by the user.
+       forced := mode != gcBackgroundMode
+
        // In gcstoptheworld debug mode, upgrade the mode accordingly.
        // We do this after re-checking the transition condition so
        // that multiple goroutines that detect the heap trigger don't
@@ -1070,6 +1076,10 @@ func gcStart(mode gcMode, forceTrigger bool) {
                work.tMark, work.tMarkTerm = t, t
                work.heapGoal = work.heap0
 
+               if forced {
+                       memstats.numforcedgc++
+               }
+
                // Perform mark termination. This will restart the world.
                gcMarkTermination()
        }
@@ -1119,8 +1129,6 @@ top:
                // sitting in the per-P work caches.
                // Flush and disable work caches.
 
-               gcMarkRootCheck()
-
                // Disallow caching workbufs and indicate that we're in mark 2.
                gcBlackenPromptly = true
 
@@ -1143,6 +1151,16 @@ top:
                        })
                })
 
+               // Check that roots are marked. We should be able to
+               // do this before the forEachP, but based on issue
+               // #16083 there may be a (harmless) race where we can
+               // enter mark 2 while some workers are still scanning
+               // stacks. The forEachP ensures these scans are done.
+               //
+               // TODO(austin): Figure out the race and fix this
+               // properly.
+               gcMarkRootCheck()
+
                // Now we can start up mark 2 workers.
                atomic.Xaddint64(&gcController.dedicatedMarkWorkersNeeded, 0xffffffff)
                atomic.Xaddint64(&gcController.fractionalMarkWorkersNeeded, 0xffffffff)
index e74a451d0d44f7b8f69df6a58f61113a70f0f99a..fb5c488ffc37ed87e22ac91c569928842dd3940c 100644 (file)
@@ -405,7 +405,10 @@ func reimburseSweepCredit(unusableBytes uintptr) {
                // Nobody cares about the credit. Avoid the atomic.
                return
        }
-       if int64(atomic.Xadd64(&mheap_.spanBytesAlloc, -int64(unusableBytes))) < 0 {
+       nval := atomic.Xadd64(&mheap_.spanBytesAlloc, -int64(unusableBytes))
+       if int64(nval) < 0 {
+               // Debugging for #18043.
+               print("runtime: bad spanBytesAlloc=", nval, " (was ", nval+uint64(unusableBytes), ") unusableBytes=", unusableBytes, " sweepPagesPerByte=", mheap_.sweepPagesPerByte, "\n")
                throw("spanBytesAlloc underflow")
        }
 }
index 587d3c77a1040602ef0d439675f75d4cf36d5a48..0f897ba8e6998d1042ea8d6b4f61d180789de366 100644 (file)
@@ -54,6 +54,8 @@ func main() {
        fmt.Fprintln(&b, "package runtime")
        classes := makeClasses()
 
+       printComment(&b, classes)
+
        printClasses(&b, classes)
 
        out, err := format.Source(b.Bytes())
@@ -239,6 +241,20 @@ nextk:
        }
 }
 
+func printComment(w io.Writer, classes []class) {
+       fmt.Fprintf(w, "// %-5s  %-9s  %-10s  %-7s  %-11s\n", "class", "bytes/obj", "bytes/span", "objects", "waste bytes")
+       for i, c := range classes {
+               if i == 0 {
+                       continue
+               }
+               spanSize := c.npages * pageSize
+               objects := spanSize / c.size
+               waste := spanSize - c.size*(spanSize/c.size)
+               fmt.Fprintf(w, "// %5d  %9d  %10d  %7d  %11d\n", i, c.size, spanSize, objects, waste)
+       }
+       fmt.Fprintf(w, "\n")
+}
+
 func printClasses(w io.Writer, classes []class) {
        fmt.Fprintln(w, "const (")
        fmt.Fprintf(w, "_MaxSmallSize = %d\n", maxSmallSize)
index 7177c8e611b5dfdeff286b892b7f8a85e192c1c5..c0f3957e2891e3dadb514ef5c673bd15f64ead8c 100644 (file)
@@ -28,9 +28,11 @@ const msanenabled = true
 // the runtime, but operations like a slice copy can call msanread
 // anyhow for values on the stack. Just ignore msanread when running
 // on the system stack. The other msan functions are fine.
+//
+//go:nosplit
 func msanread(addr unsafe.Pointer, sz uintptr) {
        g := getg()
-       if g == g.m.g0 || g == g.m.gsignal {
+       if g == nil || g.m == nil || g == g.m.g0 || g == g.m.gsignal {
                return
        }
        domsanread(addr, sz)
index b80ab11389f4914fc572d32e7f1ece6bbe3941ad..41b9005731383a8a82156e0f4338f8e2ca11a7f2 100644 (file)
@@ -77,6 +77,7 @@ type mstats struct {
        pause_ns        [256]uint64 // circular buffer of recent gc pause lengths
        pause_end       [256]uint64 // circular buffer of recent gc end times (nanoseconds since 1970)
        numgc           uint32
+       numforcedgc     uint32  // number of user-forced GCs
        gc_cpu_fraction float64 // fraction of CPU time used by GC
        enablegc        bool
        debuggc         bool
@@ -100,8 +101,6 @@ type mstats struct {
        // must be complete.
        gc_trigger uint64
 
-       _ uint32 // force 8-byte alignment of heap_live and prevent an alignment check crash on MIPS32.
-
        // heap_live is the number of bytes considered live by the GC.
        // That is: retained by the most recent GC plus allocated
        // since then. heap_live <= heap_alloc, since heap_alloc
@@ -175,6 +174,7 @@ type MemStats struct {
        Lookups uint64
 
        // Mallocs is the cumulative count of heap objects allocated.
+       // The number of live objects is Mallocs - Frees.
        Mallocs uint64
 
        // Frees is the cumulative count of heap objects freed.
@@ -365,6 +365,10 @@ type MemStats struct {
        // NumGC is the number of completed GC cycles.
        NumGC uint32
 
+       // NumForcedGC is the number of GC cycles that were forced by
+       // the application calling the GC function.
+       NumForcedGC uint32
+
        // GCCPUFraction is the fraction of this program's available
        // CPU time used by the GC since the program started.
        //
@@ -394,9 +398,19 @@ type MemStats struct {
        //
        // This does not report allocations larger than BySize[60].Size.
        BySize [61]struct {
-               Size    uint32
+               // Size is the maximum byte size of an object in this
+               // size class.
+               Size uint32
+
+               // Mallocs is the cumulative count of heap objects
+               // allocated in this size class. The cumulative bytes
+               // of allocation is Size*Mallocs. The number of live
+               // objects in this size class is Mallocs - Frees.
                Mallocs uint64
-               Frees   uint64
+
+               // Frees is the cumulative count of heap objects freed
+               // in this size class.
+               Frees uint64
        }
 }
 
index 320c1281c28c24be771d6cb3e5c7efc2fbaaae57..a6efc0e3d1f11f10fe2770153bdfb8ee3baff8df 100644 (file)
@@ -91,6 +91,9 @@ func getproccount() int32 {
        const maxCPUs = 64 * 1024
        var buf [maxCPUs / (sys.PtrSize * 8)]uintptr
        r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
+       if r < 0 {
+               return 1
+       }
        n := int32(0)
        for _, v := range buf[:r/sys.PtrSize] {
                for v != 0 {
@@ -208,6 +211,26 @@ func sysargs(argc int32, argv **byte) {
                // Fall back to /proc/self/auxv.
                fd := open(&procAuxv[0], 0 /* O_RDONLY */, 0)
                if fd < 0 {
+                       // On Android, /proc/self/auxv might be unreadable (issue 9229), so we fallback to
+                       // try using mincore to detect the physical page size.
+                       // mincore should return EINVAL when address is not a multiple of system page size.
+                       const size = 256 << 10 // size of memory region to allocate
+                       p := mmap(nil, size, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+                       if uintptr(p) < 4096 {
+                               return
+                       }
+                       var n uintptr
+                       for n = 4 << 10; n < size; n <<= 1 {
+                               err := mincore(unsafe.Pointer(uintptr(p)+n), 1, &addrspace_vec[0])
+                               if err == 0 {
+                                       physPageSize = n
+                                       break
+                               }
+                       }
+                       if physPageSize == 0 {
+                               physPageSize = size
+                       }
+                       munmap(p, size)
                        return
                }
                var buf [128]uintptr
index 2b0834a5aa9dd5d539dad1bfee166973cedb4c8b..896ec15e6a83547eeb63848f8fdc68594fc0c1f3 100644 (file)
@@ -18,6 +18,12 @@ var armArch uint8 = 6 // we default to ARMv6
 var hwcap uint32      // set by setup_auxv
 
 func checkgoarm() {
+       // On Android, /proc/self/auxv might be unreadable and hwcap won't
+       // reflect the CPU capabilities. Assume that every Android arm device
+       // has the necessary floating point hardware available.
+       if GOOS == "android" {
+               return
+       }
        if goarm > 5 && hwcap&_HWCAP_VFP == 0 {
                print("runtime: this CPU has no floating point hardware, so it cannot run\n")
                print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n")
index 0db57f8c5b69965c19e6455552295df8b9ee37d4..75b8acdceb9d98e6b8325092914fbc70d9784eb4 100644 (file)
@@ -332,8 +332,12 @@ func goenvs() {
        stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
 }
 
+// exiting is set to non-zero when the process is exiting.
+var exiting uint32
+
 //go:nosplit
 func exit(code int32) {
+       atomic.Store(&exiting, 1)
        stdcall1(_ExitProcess, uintptr(code))
 }
 
@@ -510,7 +514,7 @@ func semacreate(mp *m) {
 // May run with m.p==nil, so write barriers are not allowed. This
 // function is called by newosproc0, so it is also required to
 // operate without stack guards.
-//go:nowritebarrierc
+//go:nowritebarrierrec
 //go:nosplit
 func newosproc(mp *m, stk unsafe.Pointer) {
        const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
@@ -519,6 +523,14 @@ func newosproc(mp *m, stk unsafe.Pointer) {
                _STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
 
        if thandle == 0 {
+               if atomic.Load(&exiting) != 0 {
+                       // CreateThread may fail if called
+                       // concurrently with ExitProcess. If this
+                       // happens, just freeze this thread and let
+                       // the process exit. See issue #18253.
+                       lock(&deadlock)
+                       lock(&deadlock)
+               }
                print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
                throw("runtime.newosproc")
        }
@@ -527,7 +539,7 @@ func newosproc(mp *m, stk unsafe.Pointer) {
 // Used by the C library build mode. On Linux this function would allocate a
 // stack, but that's not necessary for Windows. No stack guards are present
 // and the GC has not been initialized, so write barriers will fail.
-//go:nowritebarrierc
+//go:nowritebarrierrec
 //go:nosplit
 func newosproc0(mp *m, stk unsafe.Pointer) {
        newosproc(mp, stk)
index 73924365c34da7a2b17203c9367634d08479a04d..876bca7fd46c75bc6a967c6443633972eb39262d 100644 (file)
@@ -646,7 +646,7 @@ func startpanic_m() {
                freezetheworld()
                return
        case 1:
-               // Something failed while panicing, probably the print of the
+               // Something failed while panicking, probably the print of the
                // argument to panic().  Just print a stack trace and exit.
                _g_.m.dying = 2
                print("panic during panic\n")
index 845bf76e92c7fb448952f449fb9e97a35ebe16b0..8edb29c9fea5604febd823da1667b50f4531057b 100644 (file)
@@ -51,9 +51,14 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}, mismatch
        modulesinit()
        typelinksinit()
 
+       pluginftabverify(md)
+       moduledataverify1(md)
+
        lock(&ifaceLock)
        for _, i := range md.itablinks {
-               additab(i, true, false)
+               if i.inhash == 0 {
+                       additab(i, true, false)
+               }
        }
        unlock(&ifaceLock)
 
@@ -82,6 +87,35 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}, mismatch
        return md.pluginpath, syms, ""
 }
 
+func pluginftabverify(md *moduledata) {
+       badtable := false
+       for i := 0; i < len(md.ftab); i++ {
+               entry := md.ftab[i].entry
+               if md.minpc <= entry && entry <= md.maxpc {
+                       continue
+               }
+
+               f := (*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff]))
+               name := funcname(f)
+
+               // A common bug is f.entry has a relocation to a duplicate
+               // function symbol, meaning if we search for its PC we get
+               // a valid entry with a name that is useful for debugging.
+               name2 := "none"
+               entry2 := uintptr(0)
+               f2 := findfunc(entry)
+               if f2 != nil {
+                       name2 = funcname(f2)
+                       entry2 = f2.entry
+               }
+               badtable = true
+               println("ftab entry outside pc range: ", hex(entry), "/", hex(entry2), ": ", name, "/", name2)
+       }
+       if badtable {
+               throw("runtime: plugin has bad symbol table")
+       }
+}
+
 // inRange reports whether v0 or v1 are in the range [r0, r1].
 func inRange(r0, r1, v0, v1 uintptr) bool {
        return (v0 >= r0 && v0 <= r1) || (v1 >= r0 && v1 <= r1)
index aed5b8da9c628d1665e163a9e0ce68f725dba941..871fba0e5f99a1eae9257ad92bedc9f053afcf08 100644 (file)
@@ -386,12 +386,22 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro
                Sample:     make([]*profile.Sample, 0, len(keys)),
                SampleType: []*profile.ValueType{{Type: name, Unit: "count"}},
        }
+       locMap := make(map[uintptr]*profile.Location)
        for _, k := range keys {
                stk := p.Stack(index[k])
                c := count[k]
                locs := make([]*profile.Location, len(stk))
                for i, addr := range stk {
-                       locs[i] = &profile.Location{Address: uint64(addr) - 1}
+                       loc := locMap[addr]
+                       if loc == nil {
+                               loc = &profile.Location{
+                                       ID:      uint64(len(locMap) + 1),
+                                       Address: uint64(addr - 1),
+                               }
+                               prof.Location = append(prof.Location, loc)
+                               locMap[addr] = loc
+                       }
+                       locs[i] = loc
                }
                prof.Sample = append(prof.Sample, &profile.Sample{
                        Location: locs,
index fd0660780584807909ddedd9e21cad8c0b9aa0f0..8372283589d0a61dfbe11419f7dfb6085bfded83 100644 (file)
@@ -204,7 +204,11 @@ func profileOk(t *testing.T, need []string, prof bytes.Buffer, duration time.Dur
        }
 
        // Check that we got a reasonable number of samples.
-       if ideal := uintptr(duration * 100 / time.Second); samples == 0 || samples < ideal/4 {
+       // We used to always require at least ideal/4 samples,
+       // but that is too hard to guarantee on a loaded system.
+       // Now we accept 10 or more samples, which we take to be
+       // enough to show that at least some profiling is occurring.
+       if ideal := uintptr(duration * 100 / time.Second); samples == 0 || (samples < ideal/4 && samples < 10) {
                t.Logf("too few samples; got %d, want at least %d, ideally %d", samples, ideal/4, ideal)
                ok = false
        }
index cad1b1c0f45319f9b6b5d4bef79be60328d18d7a..f41672de73a67876b036f6a89068152c8cdf0742 100644 (file)
@@ -240,6 +240,16 @@ func Gosched() {
        mcall(gosched_m)
 }
 
+var alwaysFalse bool
+
+// goschedguarded does nothing, but is written in a way that guarantees a preemption check in its prologue.
+// Calls to this function are inserted by the compiler in otherwise uninterruptible loops (see insertLoopReschedChecks).
+func goschedguarded() {
+       if alwaysFalse {
+               goschedguarded()
+       }
+}
+
 // Puts the current goroutine into a waiting state and calls unlockf.
 // If unlockf returns false, the goroutine is resumed.
 // unlockf must not access this G's stack, as it may be moved between
@@ -632,10 +642,15 @@ func helpgc(nproc int32) {
 // sched.stopwait to in order to request that all Gs permanently stop.
 const freezeStopWait = 0x7fffffff
 
+// freezing is set to non-zero if the runtime is trying to freeze the
+// world.
+var freezing uint32
+
 // Similar to stopTheWorld but best-effort and can be called several times.
 // There is no reverse operation, used during crashing.
 // This function must not lock any mutexes.
 func freezetheworld() {
+       atomic.Store(&freezing, 1)
        // stopwait and preemption requests can be lost
        // due to races with concurrently executing threads,
        // so try several times
@@ -1018,15 +1033,30 @@ func stopTheWorldWithSema() {
                        preemptall()
                }
        }
+
+       // sanity checks
+       bad := ""
        if sched.stopwait != 0 {
-               throw("stopTheWorld: not stopped")
-       }
-       for i := 0; i < int(gomaxprocs); i++ {
-               p := allp[i]
-               if p.status != _Pgcstop {
-                       throw("stopTheWorld: not stopped")
+               bad = "stopTheWorld: not stopped (stopwait != 0)"
+       } else {
+               for i := 0; i < int(gomaxprocs); i++ {
+                       p := allp[i]
+                       if p.status != _Pgcstop {
+                               bad = "stopTheWorld: not stopped (status != _Pgcstop)"
+                       }
                }
        }
+       if atomic.Load(&freezing) != 0 {
+               // Some other thread is panicking. This can cause the
+               // sanity checks above to fail if the panic happens in
+               // the signal handler on a stopped thread. Either way,
+               // we should halt this thread.
+               lock(&deadlock)
+               lock(&deadlock)
+       }
+       if bad != "" {
+               throw(bad)
+       }
 }
 
 func mhelpgc() {
index 5e8c5c316159ef207ba46645c597bd63b08a0d9e..9a2e561246aa582fc18dcb2363c6610e58aaa5e7 100644 (file)
@@ -18,10 +18,11 @@ TEXT _main<>(SB),NOSPLIT,$-4
        // argv as argc string pointers followed by a NULL, envv as a
        // sequence of string pointers followed by a NULL, and auxv.
        // There is no TLS base pointer.
-       MOVW    0(R29), R1      // argc
-       ADD     $4, R29, R2     // argv
+       MOVW    0(R29), R4 // argc
+       ADD     $4, R29, R5 // argv
        JMP     main(SB)
 
 TEXT main(SB),NOSPLIT,$-4
-       MOVW    $runtime·rt0_go(SB), R4
-       JMP     (R4)
+        // In external linking, libc jumps to main with argc in R4, argv in R5
+       MOVW    $runtime·rt0_go(SB), R1
+       JMP     (R1)
index c2844375f7ac98472e64a8c9f47ccdf85b6fb5a2..f886961d6ad3dad94e7f2ac1d613cd75c092a79f 100644 (file)
@@ -7,6 +7,7 @@ package runtime_test
 import (
        "bytes"
        "fmt"
+       "go/build"
        "internal/testenv"
        "io/ioutil"
        "os"
@@ -67,7 +68,6 @@ func checkGdbPython(t *testing.T) {
 }
 
 const helloSource = `
-package main
 import "fmt"
 var gslice []string
 func main() {
@@ -85,9 +85,20 @@ func main() {
 `
 
 func TestGdbPython(t *testing.T) {
+       testGdbPython(t, false)
+}
+
+func TestGdbPythonCgo(t *testing.T) {
+       testGdbPython(t, true)
+}
+
+func testGdbPython(t *testing.T, cgo bool) {
        if runtime.GOARCH == "mips64" {
                testenv.SkipFlaky(t, 18173)
        }
+       if cgo && !build.Default.CgoEnabled {
+               t.Skip("skipping because cgo is not enabled")
+       }
 
        t.Parallel()
        checkGdbEnvironment(t)
@@ -100,8 +111,15 @@ func TestGdbPython(t *testing.T) {
        }
        defer os.RemoveAll(dir)
 
+       var buf bytes.Buffer
+       buf.WriteString("package main\n")
+       if cgo {
+               buf.WriteString(`import "C"` + "\n")
+       }
+       buf.WriteString(helloSource)
+
        src := filepath.Join(dir, "main.go")
-       err = ioutil.WriteFile(src, []byte(helloSource), 0644)
+       err = ioutil.WriteFile(src, buf.Bytes(), 0644)
        if err != nil {
                t.Fatalf("failed to create file: %v", err)
        }
index 696ea81e00f1556383852a2d2d71eaadbe16a604..1ceab0ad8c4a0b43d28d63cdd2921ae7da0e1454 100644 (file)
@@ -615,7 +615,7 @@ const (
 
 // Layout of in-memory per-function information prepared by linker
 // See https://golang.org/s/go12symtab.
-// Keep in sync with linker
+// Keep in sync with linker (../cmd/link/internal/ld/pcln.go:/pclntab)
 // and with package debug/gosym and with symtab.go in package runtime.
 type _func struct {
        entry   uintptr // start pc
@@ -640,7 +640,7 @@ type itab struct {
        _type  *_type
        link   *itab
        bad    int32
-       unused int32
+       inhash int32      // has this itab been added to hash?
        fun    [1]uintptr // variable sized
 }
 
@@ -745,6 +745,8 @@ var (
        lfenceBeforeRdtsc bool
        support_avx       bool
        support_avx2      bool
+       support_bmi1      bool
+       support_bmi2      bool
 
        goarm                uint8 // set by cmd/link on arm systems
        framepointer_enabled bool  // set by cmd/link
index 03e9e4a30ad93c679ea2342d78a72fc3527bd9e6..0d846b1470032c3941d3d6d7a4502bfcbb3a2a0e 100644 (file)
@@ -422,8 +422,62 @@ loop:
        gp.param = nil
        gopark(selparkcommit, nil, "select", traceEvGoBlockSelect, 2)
 
-       // someone woke us up
-       sellock(scases, lockorder)
+       // While we were asleep, some goroutine came along and completed
+       // one of the cases in the select and woke us up (called ready).
+       // As part of that process, the goroutine did a cas on done above
+       // (aka *sg.selectdone for all queued sg) to win the right to
+       // complete the select. Now done = 1.
+       //
+       // If we copy (grow) our own stack, we will update the
+       // selectdone pointers inside the gp.waiting sudog list to point
+       // at the new stack. Another goroutine attempting to
+       // complete one of our (still linked in) select cases might
+       // see the new selectdone pointer (pointing at the new stack)
+       // before the new stack has real data; if the new stack has done = 0
+       // (before the old values are copied over), the goroutine might
+       // do a cas via sg.selectdone and incorrectly believe that it has
+       // won the right to complete the select, executing a second
+       // communication and attempting to wake us (call ready) again.
+       //
+       // Then things break.
+       //
+       // The best break is that the goroutine doing ready sees the
+       // _Gcopystack status and throws, as in #17007.
+       // A worse break would be for us to continue on, start running real code,
+       // block in a semaphore acquisition (sema.go), and have the other
+       // goroutine wake us up without having really acquired the semaphore.
+       // That would result in the goroutine spuriously running and then
+       // queue up another spurious wakeup when the semaphore really is ready.
+       // In general the situation can cascade until something notices the
+       // problem and causes a crash.
+       //
+       // A stack shrink does not have this problem, because it locks
+       // all the channels that are involved first, blocking out the
+       // possibility of a cas on selectdone.
+       //
+       // A stack growth before gopark above does not have this
+       // problem, because we hold those channel locks (released by
+       // selparkcommit).
+       //
+       // A stack growth after sellock below does not have this
+       // problem, because again we hold those channel locks.
+       //
+       // The only problem is a stack growth during sellock.
+       // To keep that from happening, run sellock on the system stack.
+       //
+       // It might be that we could avoid this if copystack copied the
+       // stack before calling adjustsudogs. In that case,
+       // syncadjustsudogs would need to recopy the tiny part that
+       // it copies today, resulting in a little bit of extra copying.
+       //
+       // An even better fix, not for the week before a release candidate,
+       // would be to put space in every sudog and make selectdone
+       // point at (say) the space in the first sudog.
+
+       systemstack(func() {
+               sellock(scases, lockorder)
+       })
+
        sg = (*sudog)(gp.param)
        gp.param = nil
 
@@ -464,8 +518,15 @@ loop:
        }
 
        if cas == nil {
-               // This can happen if we were woken up by a close().
-               // TODO: figure that out explicitly so we don't need this loop.
+               // We can wake up with gp.param == nil (so cas == nil)
+               // when a channel involved in the select has been closed.
+               // It is easiest to loop and re-run the operation;
+               // we'll see that it's now closed.
+               // Maybe some day we can signal the close explicitly,
+               // but we'd have to distinguish close-on-reader from close-on-writer.
+               // It's easiest not to duplicate the code and just recheck above.
+               // We know that something closed, and things never un-close,
+               // so we won't block again.
                goto loop
        }
 
index 19173ac2117259e53a1db60b4bbedf47d52c4a7e..49c7579f275d3fb8c608bb7bdfc0658792e9582a 100644 (file)
@@ -212,25 +212,43 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
        }
 
        // If some non-Go code called sigaltstack, adjust.
+       setStack := false
+       var gsignalStack gsignalStack
        sp := uintptr(unsafe.Pointer(&sig))
        if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
-               var st stackt
-               sigaltstack(nil, &st)
-               if st.ss_flags&_SS_DISABLE != 0 {
-                       setg(nil)
-                       needm(0)
-                       noSignalStack(sig)
-                       dropm()
-               }
-               stsp := uintptr(unsafe.Pointer(st.ss_sp))
-               if sp < stsp || sp >= stsp+st.ss_size {
-                       setg(nil)
-                       needm(0)
-                       sigNotOnStack(sig)
-                       dropm()
+               if sp >= g.m.g0.stack.lo && sp < g.m.g0.stack.hi {
+                       // The signal was delivered on the g0 stack.
+                       // This can happen when linked with C code
+                       // using the thread sanitizer, which collects
+                       // signals then delivers them itself by calling
+                       // the signal handler directly when C code,
+                       // including C code called via cgo, calls a
+                       // TSAN-intercepted function such as malloc.
+                       st := stackt{ss_size: g.m.g0.stack.hi - g.m.g0.stack.lo}
+                       setSignalstackSP(&st, g.m.g0.stack.lo)
+                       setGsignalStack(&st, &gsignalStack)
+                       g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
+                       setStack = true
+               } else {
+                       var st stackt
+                       sigaltstack(nil, &st)
+                       if st.ss_flags&_SS_DISABLE != 0 {
+                               setg(nil)
+                               needm(0)
+                               noSignalStack(sig)
+                               dropm()
+                       }
+                       stsp := uintptr(unsafe.Pointer(st.ss_sp))
+                       if sp < stsp || sp >= stsp+st.ss_size {
+                               setg(nil)
+                               needm(0)
+                               sigNotOnStack(sig)
+                               dropm()
+                       }
+                       setGsignalStack(&st, &gsignalStack)
+                       g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
+                       setStack = true
                }
-               setGsignalStack(&st)
-               g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
        }
 
        setg(g.m.gsignal)
@@ -238,6 +256,9 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
        c.fixsigcode(sig)
        sighandler(sig, info, ctx, g)
        setg(g)
+       if setStack {
+               restoreGsignalStack(&gsignalStack)
+       }
 }
 
 // sigpanic turns a synchronous signal into a run-time panic.
@@ -585,7 +606,7 @@ func minitSignalStack() {
                signalstack(&_g_.m.gsignal.stack)
                _g_.m.newSigstack = true
        } else {
-               setGsignalStack(&st)
+               setGsignalStack(&st, nil)
                _g_.m.newSigstack = false
        }
 }
@@ -618,14 +639,32 @@ func unminitSignals() {
        }
 }
 
+// gsignalStack saves the fields of the gsignal stack changed by
+// setGsignalStack.
+type gsignalStack struct {
+       stack       stack
+       stackguard0 uintptr
+       stackguard1 uintptr
+       stackAlloc  uintptr
+       stktopsp    uintptr
+}
+
 // setGsignalStack sets the gsignal stack of the current m to an
 // alternate signal stack returned from the sigaltstack system call.
+// It saves the old values in *old for use by restoreGsignalStack.
 // This is used when handling a signal if non-Go code has set the
 // alternate signal stack.
 //go:nosplit
 //go:nowritebarrierrec
-func setGsignalStack(st *stackt) {
+func setGsignalStack(st *stackt, old *gsignalStack) {
        g := getg()
+       if old != nil {
+               old.stack = g.m.gsignal.stack
+               old.stackguard0 = g.m.gsignal.stackguard0
+               old.stackguard1 = g.m.gsignal.stackguard1
+               old.stackAlloc = g.m.gsignal.stackAlloc
+               old.stktopsp = g.m.gsignal.stktopsp
+       }
        stsp := uintptr(unsafe.Pointer(st.ss_sp))
        g.m.gsignal.stack.lo = stsp
        g.m.gsignal.stack.hi = stsp + st.ss_size
@@ -634,6 +673,19 @@ func setGsignalStack(st *stackt) {
        g.m.gsignal.stackAlloc = st.ss_size
 }
 
+// restoreGsignalStack restores the gsignal stack to the value it had
+// before entering the signal handler.
+//go:nosplit
+//go:nowritebarrierrec
+func restoreGsignalStack(st *gsignalStack) {
+       gp := getg().m.gsignal
+       gp.stack = st.stack
+       gp.stackguard0 = st.stackguard0
+       gp.stackguard1 = st.stackguard1
+       gp.stackAlloc = st.stackAlloc
+       gp.stktopsp = st.stktopsp
+}
+
 // signalstack sets the current thread's alternate signal stack to s.
 //go:nosplit
 func signalstack(s *stack) {
index ec30d15d36bf7379b566b3028d9eb39b13c229da..e616e95148ca9c14ab703c4be210a64bba2d23b6 100644 (file)
@@ -3,6 +3,74 @@
 
 package runtime
 
+// class  bytes/obj  bytes/span  objects  waste bytes
+//     1          8        8192     1024            0
+//     2         16        8192      512            0
+//     3         32        8192      256            0
+//     4         48        8192      170           32
+//     5         64        8192      128            0
+//     6         80        8192      102           32
+//     7         96        8192       85           32
+//     8        112        8192       73           16
+//     9        128        8192       64            0
+//    10        144        8192       56          128
+//    11        160        8192       51           32
+//    12        176        8192       46           96
+//    13        192        8192       42          128
+//    14        208        8192       39           80
+//    15        224        8192       36          128
+//    16        240        8192       34           32
+//    17        256        8192       32            0
+//    18        288        8192       28          128
+//    19        320        8192       25          192
+//    20        352        8192       23           96
+//    21        384        8192       21          128
+//    22        416        8192       19          288
+//    23        448        8192       18          128
+//    24        480        8192       17           32
+//    25        512        8192       16            0
+//    26        576        8192       14          128
+//    27        640        8192       12          512
+//    28        704        8192       11          448
+//    29        768        8192       10          512
+//    30        896        8192        9          128
+//    31       1024        8192        8            0
+//    32       1152        8192        7          128
+//    33       1280        8192        6          512
+//    34       1408       16384       11          896
+//    35       1536        8192        5          512
+//    36       1792       16384        9          256
+//    37       2048        8192        4            0
+//    38       2304       16384        7          256
+//    39       2688        8192        3          128
+//    40       3072       24576        8            0
+//    41       3200       16384        5          384
+//    42       3456       24576        7          384
+//    43       4096        8192        2            0
+//    44       4864       24576        5          256
+//    45       5376       16384        3          256
+//    46       6144       24576        4            0
+//    47       6528       32768        5          128
+//    48       6784       40960        6          256
+//    49       6912       49152        7          768
+//    50       8192        8192        1            0
+//    51       9472       57344        6          512
+//    52       9728       49152        5          512
+//    53      10240       40960        4            0
+//    54      10880       32768        3          128
+//    55      12288       24576        2            0
+//    56      13568       40960        3          256
+//    57      14336       57344        4            0
+//    58      16384       16384        1            0
+//    59      18432       73728        4            0
+//    60      19072       57344        3          128
+//    61      20480       40960        2            0
+//    62      21760       65536        3          256
+//    63      24576       24576        1            0
+//    64      27264       81920        3          128
+//    65      28672       57344        2            0
+//    66      32768       32768        1            0
+
 const (
        _MaxSmallSize   = 32768
        smallSizeDiv    = 8
index ea9a69aa1e2db22c22c80e798fbb94328a8a6465..0f1a5c1c55e12d5326f8c7040985ee5f85dc2dc5 100644 (file)
@@ -123,6 +123,9 @@ const (
        stackPoisonCopy  = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy
 
        stackCache = 1
+
+       // check the BP links during traceback.
+       debugCheckBP = false
 )
 
 const (
@@ -598,7 +601,7 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
                        pp := (*uintptr)(add(scanp, i*sys.PtrSize))
                retry:
                        p := *pp
-                       if f != nil && 0 < p && p < _PageSize && debug.invalidptr != 0 {
+                       if f != nil && 0 < p && p < minLegalPointer && debug.invalidptr != 0 {
                                // Looks like a junk value in a pointer slot.
                                // Live analysis wrong?
                                getg().m.traceback = 2
@@ -688,6 +691,16 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
                if stackDebug >= 3 {
                        print("      saved bp\n")
                }
+               if debugCheckBP {
+                       // Frame pointers should always point to the next higher frame on
+                       // the Go stack (or be nil, for the top frame on the stack).
+                       bp := *(*uintptr)(unsafe.Pointer(frame.varp))
+                       if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) {
+                               println("runtime: found invalid frame pointer")
+                               print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n")
+                               throw("bad frame pointer")
+                       }
+               }
                adjustpointer(adjinfo, unsafe.Pointer(frame.varp))
        }
 
@@ -719,6 +732,18 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
 
 func adjustctxt(gp *g, adjinfo *adjustinfo) {
        adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.ctxt))
+       if !framepointer_enabled {
+               return
+       }
+       if debugCheckBP {
+               bp := gp.sched.bp
+               if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) {
+                       println("runtime: found invalid top frame pointer")
+                       print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n")
+                       throw("bad top frame pointer")
+               }
+       }
+       adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.bp))
 }
 
 func adjustdefers(gp *g, adjinfo *adjustinfo) {
index f52190661cee83ee80e69eddb2fba1d775101a45..ed82783ca969f328c2ec11ad0e1ffd35710b2203 100644 (file)
@@ -285,6 +285,25 @@ func modulesinit() {
                        md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), md.ebss-md.bss)
                }
        }
+
+       // Modules appear in the moduledata linked list in the order they are
+       // loaded by the dynamic loader, with one exception: the
+       // firstmoduledata itself the module that contains the runtime. This
+       // is not always the first module (when using -buildmode=shared, it
+       // is typically libstd.so, the second module). The order matters for
+       // typelinksinit, so we swap the first module with whatever module
+       // contains the main function.
+       //
+       // See Issue #18729.
+       mainText := funcPC(main_main)
+       for i, md := range *modules {
+               if md.text <= mainText && mainText <= md.etext {
+                       (*modules)[0] = md
+                       (*modules)[i] = &firstmoduledata
+                       break
+               }
+       }
+
        atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
 }
 
index 88c7f9dd8ac5ce1bcdad49539bac6fb587e4059a..b950b69fe019167d8101a0afdbe1f0d0fb6a0468 100644 (file)
@@ -200,11 +200,28 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
        POPQ    BP
        RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
-       MOVQ    DI, 0(SP)
-       MOVQ    SI, 8(SP)
-       MOVQ    DX, 16(SP)
+TEXT runtime·sigtramp(SB),NOSPLIT,$72
+       // Save callee-saved C registers, since the caller may be a C signal handler.
+       MOVQ    BX,  bx-8(SP)
+       MOVQ    BP,  bp-16(SP)  // save in case GOEXPERIMENT=noframepointer is set
+       MOVQ    R12, r12-24(SP)
+       MOVQ    R13, r13-32(SP)
+       MOVQ    R14, r14-40(SP)
+       MOVQ    R15, r15-48(SP)
+       // We don't save mxcsr or the x87 control word because sigtrampgo doesn't
+       // modify them.
+
+       MOVQ    DX, ctx-56(SP)
+       MOVQ    SI, info-64(SP)
+       MOVQ    DI, signum-72(SP)
        CALL    runtime·sigtrampgo(SB)
+
+       MOVQ    r15-48(SP), R15
+       MOVQ    r14-40(SP), R14
+       MOVQ    r13-32(SP), R13
+       MOVQ    r12-24(SP), R12
+       MOVQ    bp-16(SP),  BP
+       MOVQ    bx-8(SP),   BX
        RET
 
 TEXT runtime·mmap(SB),NOSPLIT,$0
index 19007dc401156db4be4d383306b358560244c78f..158a60dec2e2a2125b5ae0985ad94d6de5bbee92 100644 (file)
@@ -196,11 +196,28 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
        POPQ    BP
        RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
-       MOVQ    DI, 0(SP)
-       MOVQ    SI, 8(SP)
-       MOVQ    DX, 16(SP)
+TEXT runtime·sigtramp(SB),NOSPLIT,$72
+       // Save callee-saved C registers, since the caller may be a C signal handler.
+       MOVQ    BX, bx-8(SP)
+       MOVQ    BP, bp-16(SP)  // save in case GOEXPERIMENT=noframepointer is set
+       MOVQ    R12, r12-24(SP)
+       MOVQ    R13, r13-32(SP)
+       MOVQ    R14, r14-40(SP)
+       MOVQ    R15, r15-48(SP)
+       // We don't save mxcsr or the x87 control word because sigtrampgo doesn't
+       // modify them.
+
+       MOVQ    DX, ctx-56(SP)
+       MOVQ    SI, info-64(SP)
+       MOVQ    DI, signum-72(SP)
        CALL    runtime·sigtrampgo(SB)
+
+       MOVQ    r15-48(SP), R15
+       MOVQ    r14-40(SP), R14
+       MOVQ    r13-32(SP), R13
+       MOVQ    r12-24(SP), R12
+       MOVQ    bp-16(SP),  BP
+       MOVQ    bx-8(SP),   BX
        RET
 
 TEXT runtime·mmap(SB),NOSPLIT,$0
index 1d798c741ed634ba7bbacbd7030507ac51001e95..45320c068a0d7647236d1cf54ddc9cc37a8cf6aa 100644 (file)
@@ -228,7 +228,15 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
        MOVL    AX, SP
        RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$12
+TEXT runtime·sigtramp(SB),NOSPLIT,$28
+       // Save callee-saved C registers, since the caller may be a C signal handler.
+       MOVL    BX, bx-4(SP)
+       MOVL    BP, bp-8(SP)
+       MOVL    SI, si-12(SP)
+       MOVL    DI, di-16(SP)
+       // We don't save mxcsr or the x87 control word because sigtrampgo doesn't
+       // modify them.
+
        MOVL    sig+0(FP), BX
        MOVL    BX, 0(SP)
        MOVL    info+4(FP), BX
@@ -236,6 +244,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
        MOVL    ctx+8(FP), BX
        MOVL    BX, 8(SP)
        CALL    runtime·sigtrampgo(SB)
+
+       MOVL    di-16(SP), DI
+       MOVL    si-12(SP), SI
+       MOVL    bp-8(SP),  BP
+       MOVL    bx-4(SP),  BX
        RET
 
 TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
index 832b98b6740b50fa282ace31def2d839929b5c07..6ddcb30ae204ddfa5e2f639cf4968646c44c223a 100644 (file)
@@ -244,12 +244,29 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
        POPQ    BP
        RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
-       MOVQ    DI, 0(SP)   // signum
-       MOVQ    SI, 8(SP)   // info
-       MOVQ    DX, 16(SP)  // ctx
+TEXT runtime·sigtramp(SB),NOSPLIT,$72
+       // Save callee-saved C registers, since the caller may be a C signal handler.
+       MOVQ    BX,  bx-8(SP)
+       MOVQ    BP,  bp-16(SP)  // save in case GOEXPERIMENT=noframepointer is set
+       MOVQ    R12, r12-24(SP)
+       MOVQ    R13, r13-32(SP)
+       MOVQ    R14, r14-40(SP)
+       MOVQ    R15, r15-48(SP)
+       // We don't save mxcsr or the x87 control word because sigtrampgo doesn't
+       // modify them.
+
+       MOVQ    DX, ctx-56(SP)
+       MOVQ    SI, info-64(SP)
+       MOVQ    DI, signum-72(SP)
        MOVQ    $runtime·sigtrampgo(SB), AX
        CALL AX
+
+       MOVQ    r15-48(SP), R15
+       MOVQ    r14-40(SP), R14
+       MOVQ    r13-32(SP), R13
+       MOVQ    r12-24(SP), R12
+       MOVQ    bp-16(SP),  BP
+       MOVQ    bx-8(SP),   BX
        RET
 
 // Used instead of sigtramp in programs that use cgo.
@@ -313,9 +330,9 @@ sigtrampnog:
        // Lock sigprofCallersUse.
        MOVL    $0, AX
        MOVL    $1, CX
-       MOVQ    $runtime·sigprofCallersUse(SB), BX
+       MOVQ    $runtime·sigprofCallersUse(SB), R11
        LOCK
-       CMPXCHGL        CX, 0(BX)
+       CMPXCHGL        CX, 0(R11)
        JNZ     sigtramp  // Skip stack trace if already locked.
 
        // Jump to the traceback function in runtime/cgo.
index 6f089f59328d5e30f482c90b674afe0c157c5c71..73ce06114c3abc4f47bc1cc2565a537ae318d423 100644 (file)
@@ -249,7 +249,7 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
        MOVW    fn+0(FP), R25
        MOVW    R29, R22
        SUBU    $16, R29
-       AND     $0x7, R29       // shadow space for 4 args aligned to 8 bytes as per O32 ABI
+       AND     $~7, R29        // shadow space for 4 args aligned to 8 bytes as per O32 ABI
        JAL     (R25)
        MOVW    R22, R29
        RET
index 50d35e5b5ca15df15e43deccb5afcfffa6ddb571..8c4f004a4b1398b17b33c3baa6dad0a1086cf9a8 100644 (file)
@@ -232,7 +232,15 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
        MOVL    AX, SP
        RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$12
+TEXT runtime·sigtramp(SB),NOSPLIT,$28
+       // Save callee-saved C registers, since the caller may be a C signal handler.
+       MOVL    BX, bx-4(SP)
+       MOVL    BP, bp-8(SP)
+       MOVL    SI, si-12(SP)
+       MOVL    DI, di-16(SP)
+       // We don't save mxcsr or the x87 control word because sigtrampgo doesn't
+       // modify them.
+
        MOVL    signo+0(FP), BX
        MOVL    BX, 0(SP)
        MOVL    info+4(FP), BX
@@ -240,6 +248,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
        MOVL    context+8(FP), BX
        MOVL    BX, 8(SP)
        CALL    runtime·sigtrampgo(SB)
+
+       MOVL    di-16(SP), DI
+       MOVL    si-12(SP), SI
+       MOVL    bp-8(SP),  BP
+       MOVL    bx-4(SP),  BX
        RET
 
 // int32 lwp_create(void *context, uintptr flags, void *lwpid);
index 2c50adb123d0a5127610f65a7264d76d49ec93b7..7c7771bcba634a9d7310d2c278aa5792b6515dcd 100644 (file)
@@ -250,13 +250,28 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
        POPQ    BP
        RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$32
-       MOVQ    DI, 0(SP)   // signum
-       MOVQ    SI, 8(SP)   // info
-       MOVQ    DX, 16(SP)  // ctx
-       MOVQ    R15, 24(SP) // for sigreturn
+TEXT runtime·sigtramp(SB),NOSPLIT,$72
+       // Save callee-saved C registers, since the caller may be a C signal handler.
+       MOVQ    BX,  bx-8(SP)
+       MOVQ    BP,  bp-16(SP)  // save in case GOEXPERIMENT=noframepointer is set
+       MOVQ    R12, r12-24(SP)
+       MOVQ    R13, r13-32(SP)
+       MOVQ    R14, r14-40(SP)
+       MOVQ    R15, r15-48(SP)
+       // We don't save mxcsr or the x87 control word because sigtrampgo doesn't
+       // modify them.
+
+       MOVQ    DX, ctx-56(SP)
+       MOVQ    SI, info-64(SP)
+       MOVQ    DI, signum-72(SP)
        CALL    runtime·sigtrampgo(SB)
-       MOVQ    24(SP), R15
+
+       MOVQ    r15-48(SP), R15
+       MOVQ    r14-40(SP), R14
+       MOVQ    r13-32(SP), R13
+       MOVQ    r12-24(SP), R12
+       MOVQ    bp-16(SP),  BP
+       MOVQ    bx-8(SP),   BX
        RET
 
 TEXT runtime·mmap(SB),NOSPLIT,$0
index e96939508869c643aae36029c80c673cbdf7f0ad..76d22b01311d1f381c53ebfeb7dacf44f0e68bba 100644 (file)
@@ -79,14 +79,15 @@ TEXT runtime·usleep(SB),NOSPLIT,$24
        INT     $0x80
        RET
 
-TEXT runtime·raise(SB),NOSPLIT,$12
+TEXT runtime·raise(SB),NOSPLIT,$16
        MOVL    $299, AX                // sys_getthrid
        INT     $0x80
        MOVL    $0, 0(SP)
-       MOVL    AX, 4(SP)               // arg 1 - pid
+       MOVL    AX, 4(SP)               // arg 1 - tid
        MOVL    sig+0(FP), AX
        MOVL    AX, 8(SP)               // arg 2 - signum
-       MOVL    $37, AX                 // sys_kill
+       MOVL    $0, 12(SP)              // arg 3 - tcb
+       MOVL    $119, AX                // sys_thrkill
        INT     $0x80
        RET
 
@@ -97,7 +98,7 @@ TEXT runtime·raiseproc(SB),NOSPLIT,$12
        MOVL    AX, 4(SP)               // arg 1 - pid
        MOVL    sig+0(FP), AX
        MOVL    AX, 8(SP)               // arg 2 - signum
-       MOVL    $37, AX                 // sys_kill
+       MOVL    $122, AX                // sys_kill
        INT     $0x80
        RET
 
@@ -212,7 +213,15 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
        MOVL    AX, SP
        RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$12
+TEXT runtime·sigtramp(SB),NOSPLIT,$28
+       // Save callee-saved C registers, since the caller may be a C signal handler.
+       MOVL    BX, bx-4(SP)
+       MOVL    BP, bp-8(SP)
+       MOVL    SI, si-12(SP)
+       MOVL    DI, di-16(SP)
+       // We don't save mxcsr or the x87 control word because sigtrampgo doesn't
+       // modify them.
+
        MOVL    signo+0(FP), BX
        MOVL    BX, 0(SP)
        MOVL    info+4(FP), BX
@@ -220,6 +229,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
        MOVL    context+8(FP), BX
        MOVL    BX, 8(SP)
        CALL    runtime·sigtrampgo(SB)
+
+       MOVL    di-16(SP), DI
+       MOVL    si-12(SP), SI
+       MOVL    bp-8(SP),  BP
+       MOVL    bx-4(SP),  BX
        RET
 
 // int32 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
index 01d6bd8e8538f84e4955e8856e5c6e8738b690c0..cf7a3fb7a9b952424b03013b97aba908a180ad0d 100644 (file)
@@ -156,9 +156,10 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 TEXT runtime·raise(SB),NOSPLIT,$16
        MOVL    $299, AX                // sys_getthrid
        SYSCALL
-       MOVQ    AX, DI                  // arg 1 - pid
+       MOVQ    AX, DI                  // arg 1 - tid
        MOVL    sig+0(FP), SI           // arg 2 - signum
-       MOVL    $37, AX                 // sys_kill
+       MOVQ    $0, DX                  // arg 3 - tcb
+       MOVL    $119, AX                // sys_thrkill
        SYSCALL
        RET
 
@@ -167,7 +168,7 @@ TEXT runtime·raiseproc(SB),NOSPLIT,$16
        SYSCALL
        MOVQ    AX, DI                  // arg 1 - pid
        MOVL    sig+0(FP), SI           // arg 2 - signum
-       MOVL    $37, AX                 // sys_kill
+       MOVL    $122, AX                // sys_kill
        SYSCALL
        RET
 
@@ -241,11 +242,28 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
        POPQ    BP
        RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
-       MOVQ    DI, 0(SP)
-       MOVQ    SI, 8(SP)
-       MOVQ    DX, 16(SP)
+TEXT runtime·sigtramp(SB),NOSPLIT,$72
+       // Save callee-saved C registers, since the caller may be a C signal handler.
+       MOVQ    BX,  bx-8(SP)
+       MOVQ    BP,  bp-16(SP)  // save in case GOEXPERIMENT=noframepointer is set
+       MOVQ    R12, r12-24(SP)
+       MOVQ    R13, r13-32(SP)
+       MOVQ    R14, r14-40(SP)
+       MOVQ    R15, r15-48(SP)
+       // We don't save mxcsr or the x87 control word because sigtrampgo doesn't
+       // modify them.
+
+       MOVQ    DX, ctx-56(SP)
+       MOVQ    SI, info-64(SP)
+       MOVQ    DI, signum-72(SP)
        CALL    runtime·sigtrampgo(SB)
+
+       MOVQ    r15-48(SP), R15
+       MOVQ    r14-40(SP), R14
+       MOVQ    r13-32(SP), R13
+       MOVQ    r12-24(SP), R12
+       MOVQ    bp-16(SP),  BP
+       MOVQ    bx-8(SP),   BX
        RET
 
 TEXT runtime·mmap(SB),NOSPLIT,$0
index e0f775d0eb5985532c7fb39470b2d1796301c98a..f573a028a0030a7d5f38b289fe83066e8797a91f 100644 (file)
@@ -87,9 +87,10 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 TEXT runtime·raise(SB),NOSPLIT,$12
        MOVW    $0x12B, R12
        SWI     $0                      // sys_getthrid
-                                       // arg 1 - pid, already in R0
+                                       // arg 1 - tid, already in R0
        MOVW    sig+0(FP), R1           // arg 2 - signum
-       MOVW    $37, R12                // sys_kill
+       MOVW    $0, R2                  // arg 3 - tcb
+       MOVW    $119, R12               // sys_thrkill
        SWI     $0
        RET
 
@@ -98,7 +99,7 @@ TEXT runtime·raiseproc(SB),NOSPLIT,$12
        SWI     $0                      // sys_getpid
                                        // arg 1 - pid, already in R0
        MOVW    sig+0(FP), R1           // arg 2 - signum
-       MOVW    $37, R12                // sys_kill
+       MOVW    $122, R12               // sys_kill
        SWI     $0
        RET
 
index 44afb91d96f1a252f3f87f1771200697c008f110..3da82961b9b74a21d5fe6da480e55d38a91180bf 100644 (file)
@@ -61,7 +61,7 @@ static void* cpuHogDriver(void* arg __attribute__ ((unused))) {
        return 0;
 }
 
-void runCPUHogThread() {
+void runCPUHogThread(void) {
        pthread_t tid;
        pthread_create(&tid, 0, cpuHogDriver, 0);
 }
index e8b0a04556a0f135f22e8ac9597d2fb96930101f..2a023f66caeb74f49933e2f9111b20beac3faa69 100644 (file)
@@ -15,16 +15,16 @@ package main
 
 char *p;
 
-static int f3() {
+static int f3(void) {
        *p = 0;
        return 0;
 }
 
-static int f2() {
+static int f2(void) {
        return f3();
 }
 
-static int f1() {
+static int f1(void) {
        return f2();
 }
 
index 95fbc32a7c848b73f6bc13522bfa6eb83cf64a76..a2c01d21672da1be726be9395554caa65d06689a 100644 (file)
 #include "textflag.h"
 
 // If !iscgo, this is a no-op.
+// NOTE: gogo asumes load_g only clobers g (R30) and REGTMP (R23)
 TEXT runtime·save_g(SB),NOSPLIT,$-4-0
        MOVB    runtime·iscgo(SB), R23
        BEQ     R23, nocgo
-       UNDEF
+
+       MOVW    R3, R23
+       MOVW    g, runtime·tls_g(SB) // TLS relocation clobbers R3
+       MOVW    R23, R3
+
 nocgo:
        RET
 
 TEXT runtime·load_g(SB),NOSPLIT,$-4-0
+       MOVW    runtime·tls_g(SB), g // TLS relocation clobbers R3
        RET
+
+GLOBL runtime·tls_g(SB), TLSBSS, $4
index 0049e82d631210d1346f736c6faa1ee53450c29f..180489fb2cfeb6165a20accf3c96df33c78dc02f 100644 (file)
@@ -546,7 +546,8 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
        return n
 }
 
-// reflectMethodValue is a partial duplicate of reflect.methodValue.
+// reflectMethodValue is a partial duplicate of reflect.makeFuncImpl
+// and reflect.methodValue.
 type reflectMethodValue struct {
        fn    uintptr
        stack *bitvector // args bitmap
index 3ecc54c72c7415ed5d6b72a6cea2d832c52b9f58..10442eff695e5eee59b42217f3bd47e17dd46ee6 100644 (file)
@@ -390,9 +390,13 @@ type ptrtype struct {
 }
 
 type structfield struct {
-       name   name
-       typ    *_type
-       offset uintptr
+       name       name
+       typ        *_type
+       offsetAnon uintptr
+}
+
+func (f *structfield) offset() uintptr {
+       return f.offsetAnon >> 1
 }
 
 type structtype struct {
@@ -650,7 +654,7 @@ func typesEqual(t, v *_type) bool {
                        if tf.name.tag() != vf.name.tag() {
                                return false
                        }
-                       if tf.offset != vf.offset {
+                       if tf.offsetAnon != vf.offsetAnon {
                                return false
                        }
                }
index 26aeec843f1599bf144259899b33d012561697e4..e75ba1502a94aadd8d461e9fe077efa3b56e500d 100644 (file)
@@ -18,6 +18,7 @@ import (
        "log"
        "os"
        "regexp"
+       "strings"
 )
 
 func main() {
@@ -38,10 +39,16 @@ func main() {
                re = regexp.MustCompile("Pad_cgo[A-Za-z0-9_]*")
                s = re.ReplaceAllString(s, "_")
 
+               // We want to keep X__val in Fsid. Hide it and restore it later.
+               s = strings.Replace(s, "X__val", "MKPOSTFSIDVAL", 1)
+
                // Replace other unwanted fields with blank identifiers.
                re = regexp.MustCompile("X_[A-Za-z0-9_]*")
                s = re.ReplaceAllString(s, "_")
 
+               // Restore X__val in Fsid.
+               s = strings.Replace(s, "MKPOSTFSIDVAL", "X__val", 1)
+
                // Force the type of RawSockaddr.Data to [14]int8 to match
                // the existing gccgo API.
                re = regexp.MustCompile("(Data\\s+\\[14\\])uint8")
index c19f6de649d8c922c3cb13a735d3f923129bc76d..c172534aebb579bc561750f00c8604c59a058dc9 100644 (file)
@@ -41,7 +41,6 @@ const (
        SYS_CHFLAGS        = 34  // { int sys_chflags(const char *path, u_int flags); }
        SYS_FCHFLAGS       = 35  // { int sys_fchflags(int fd, u_int flags); }
        SYS_SYNC           = 36  // { void sys_sync(void); }
-       SYS_KILL           = 37  // { int sys_kill(int pid, int signum); }
        SYS_STAT           = 38  // { int sys_stat(const char *path, struct stat *ub); }
        SYS_GETPPID        = 39  // { pid_t sys_getppid(void); }
        SYS_LSTAT          = 40  // { int sys_lstat(const char *path, struct stat *ub); }
@@ -113,6 +112,7 @@ const (
        SYS_READV          = 120 // { ssize_t sys_readv(int fd, \
        SYS_WRITEV         = 121 // { ssize_t sys_writev(int fd, \
        SYS_FCHOWN         = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
+       SYS_KILL           = 122 // { int sys_kill(int pid, int signum); }
        SYS_FCHMOD         = 124 // { int sys_fchmod(int fd, mode_t mode); }
        SYS_SETREUID       = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
        SYS_SETREGID       = 127 // { int sys_setregid(gid_t rgid, gid_t egid); }
index 86e04cd47e3a93fba0ee564f1a62e10eb5fb6591..356c18737516d546deaaf397c5498cbd55932e34 100644 (file)
@@ -41,7 +41,6 @@ const (
        SYS_CHFLAGS        = 34  // { int sys_chflags(const char *path, u_int flags); }
        SYS_FCHFLAGS       = 35  // { int sys_fchflags(int fd, u_int flags); }
        SYS_SYNC           = 36  // { void sys_sync(void); }
-       SYS_KILL           = 37  // { int sys_kill(int pid, int signum); }
        SYS_STAT           = 38  // { int sys_stat(const char *path, struct stat *ub); }
        SYS_GETPPID        = 39  // { pid_t sys_getppid(void); }
        SYS_LSTAT          = 40  // { int sys_lstat(const char *path, struct stat *ub); }
@@ -112,6 +111,7 @@ const (
        SYS_GETSOCKOPT     = 118 // { int sys_getsockopt(int s, int level, int name, \
        SYS_READV          = 120 // { ssize_t sys_readv(int fd, \
        SYS_WRITEV         = 121 // { ssize_t sys_writev(int fd, \
+       SYS_KILL           = 122 // { int sys_kill(int pid, int signum); }
        SYS_FCHOWN         = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
        SYS_FCHMOD         = 124 // { int sys_fchmod(int fd, mode_t mode); }
        SYS_SETREUID       = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
index 38b43caba673bc6910a854929ebfec1d1675fe6c..3e6b984a85fe1ad5cafc4c5b5922fcc37cc9d1f9 100644 (file)
@@ -42,7 +42,6 @@ const (
        SYS_CHFLAGS        = 34  // { int sys_chflags(const char *path, u_int flags); }
        SYS_FCHFLAGS       = 35  // { int sys_fchflags(int fd, u_int flags); }
        SYS_SYNC           = 36  // { void sys_sync(void); }
-       SYS_KILL           = 37  // { int sys_kill(int pid, int signum); }
        SYS_STAT           = 38  // { int sys_stat(const char *path, struct stat *ub); }
        SYS_GETPPID        = 39  // { pid_t sys_getppid(void); }
        SYS_LSTAT          = 40  // { int sys_lstat(const char *path, struct stat *ub); }
@@ -118,6 +117,7 @@ const (
        SYS_GETSOCKOPT     = 118 // { int sys_getsockopt(int s, int level, int name, \
        SYS_READV          = 120 // { ssize_t sys_readv(int fd, \
        SYS_WRITEV         = 121 // { ssize_t sys_writev(int fd, \
+       SYS_KILL           = 122 // { int sys_kill(int pid, int signum); }
        SYS_FCHOWN         = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
        SYS_FCHMOD         = 124 // { int sys_fchmod(int fd, mode_t mode); }
        SYS_SETREUID       = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
index cdde47863f7d584eebf9b84c321424908d3c5fa3..63c4a83b19cfe6efaf813818dc7da36a50701ad0 100644 (file)
@@ -140,7 +140,7 @@ type Dirent struct {
 }
 
 type Fsid struct {
-       _ [2]int32
+       X__val [2]int32
 }
 
 type Flock_t struct {
index b1c6d2eff045b8c347ff2bc832fd6f25587148b1..bcebb418c42572e1c26aa3427926667c596adf5b 100644 (file)
@@ -5,7 +5,6 @@
 package testing
 
 import (
-       "context"
        "flag"
        "fmt"
        "internal/race"
@@ -128,9 +127,6 @@ func (b *B) nsPerOp() int64 {
 
 // runN runs a single benchmark for the specified number of iterations.
 func (b *B) runN(n int) {
-       b.ctx, b.cancel = context.WithCancel(b.parentContext())
-       defer b.cancel()
-
        benchmarkLock.Lock()
        defer benchmarkLock.Unlock()
        // Try to get a comparable environment for each run
@@ -223,7 +219,7 @@ func (b *B) run1() bool {
        }
        // Only print the output if we know we are not going to proceed.
        // Otherwise it is printed in processBench.
-       if b.hasSub || b.finished {
+       if atomic.LoadInt32(&b.hasSub) != 0 || b.finished {
                tag := "BENCH"
                if b.skipped {
                        tag = "SKIP"
@@ -464,10 +460,13 @@ func (ctx *benchContext) processBench(b *B) {
 //
 // A subbenchmark is like any other benchmark. A benchmark that calls Run at
 // least once will not be measured itself and will be called once with N=1.
+//
+// Run may be called simultaneously from multiple goroutines, but all such
+// calls must happen before the outer benchmark function for b returns.
 func (b *B) Run(name string, f func(b *B)) bool {
        // Since b has subbenchmarks, we will no longer run it as a benchmark itself.
        // Release the lock and acquire it on exit to ensure locks stay paired.
-       b.hasSub = true
+       atomic.StoreInt32(&b.hasSub, 1)
        benchmarkLock.Unlock()
        defer benchmarkLock.Lock()
 
index 563e8656c60cd087a9a13904c7885dae706c64b7..bb7b3e09255ea167de3001248b55c83e20b21109 100644 (file)
@@ -6,7 +6,7 @@ package testing
 
 import (
        "bytes"
-       "context"
+       "fmt"
        "regexp"
        "strings"
        "sync/atomic"
@@ -278,33 +278,28 @@ func TestTRun(t *T) {
                ok:     true,
                maxPar: 4,
                f: func(t *T) {
-                       // t.Parallel doesn't work in the pseudo-T we start with:
-                       // it leaks a goroutine.
-                       // Call t.Run to get a real one.
-                       t.Run("X", func(t *T) {
-                               t.Parallel()
-                               for i := 0; i < 12; i++ {
-                                       t.Run("a", func(t *T) {
-                                               t.Parallel()
-                                               time.Sleep(time.Nanosecond)
-                                               for i := 0; i < 12; i++ {
-                                                       t.Run("b", func(t *T) {
-                                                               time.Sleep(time.Nanosecond)
-                                                               for i := 0; i < 12; i++ {
-                                                                       t.Run("c", func(t *T) {
-                                                                               t.Parallel()
-                                                                               time.Sleep(time.Nanosecond)
-                                                                               t.Run("d1", func(t *T) {})
-                                                                               t.Run("d2", func(t *T) {})
-                                                                               t.Run("d3", func(t *T) {})
-                                                                               t.Run("d4", func(t *T) {})
-                                                                       })
-                                                               }
-                                                       })
-                                               }
-                                       })
-                               }
-                       })
+                       t.Parallel()
+                       for i := 0; i < 12; i++ {
+                               t.Run("a", func(t *T) {
+                                       t.Parallel()
+                                       time.Sleep(time.Nanosecond)
+                                       for i := 0; i < 12; i++ {
+                                               t.Run("b", func(t *T) {
+                                                       time.Sleep(time.Nanosecond)
+                                                       for i := 0; i < 12; i++ {
+                                                               t.Run("c", func(t *T) {
+                                                                       t.Parallel()
+                                                                       time.Sleep(time.Nanosecond)
+                                                                       t.Run("d1", func(t *T) {})
+                                                                       t.Run("d2", func(t *T) {})
+                                                                       t.Run("d3", func(t *T) {})
+                                                                       t.Run("d4", func(t *T) {})
+                                                               })
+                                                       }
+                                               })
+                                       }
+                               })
+                       }
                },
        }, {
                desc:   "skip output",
@@ -347,7 +342,6 @@ func TestTRun(t *T) {
                        },
                        context: ctx,
                }
-               root.ctx, root.cancel = context.WithCancel(context.Background())
                ok := root.Run(tc.desc, tc.f)
                ctx.release()
 
@@ -364,7 +358,7 @@ func TestTRun(t *T) {
                want := strings.TrimSpace(tc.output)
                re := makeRegexp(want)
                if ok, err := regexp.MatchString(re, got); !ok || err != nil {
-                       t.Errorf("%s:ouput:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
+                       t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
                }
        }
 }
@@ -505,7 +499,7 @@ func TestBRun(t *T) {
                want := strings.TrimSpace(tc.output)
                re := makeRegexp(want)
                if ok, err := regexp.MatchString(re, got); !ok || err != nil {
-                       t.Errorf("%s:ouput:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
+                       t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
                }
        }
 }
@@ -522,3 +516,19 @@ func TestBenchmarkOutput(t *T) {
        Benchmark(func(b *B) { b.Error("do not print this output") })
        Benchmark(func(b *B) {})
 }
+
+func TestParallelSub(t *T) {
+       c := make(chan int)
+       block := make(chan int)
+       for i := 0; i < 10; i++ {
+               go func(i int) {
+                       <-block
+                       t.Run(fmt.Sprint(i), func(t *T) {})
+                       c <- 1
+               }(i)
+       }
+       close(block)
+       for i := 0; i < 10; i++ {
+               <-c
+       }
+}
index f08c5c6b8e22f02c1b51ddcee3d5e77f59ef3c72..bd19a31c27c85ad61e3e378d00641ec615accf21 100644 (file)
@@ -204,7 +204,6 @@ package testing
 
 import (
        "bytes"
-       "context"
        "errors"
        "flag"
        "fmt"
@@ -217,6 +216,7 @@ import (
        "strconv"
        "strings"
        "sync"
+       "sync/atomic"
        "time"
 )
 
@@ -262,16 +262,14 @@ type common struct {
        mu         sync.RWMutex // guards output, failed, and done.
        output     []byte       // Output generated by test or benchmark.
        w          io.Writer    // For flushToParent.
-       ctx        context.Context
-       cancel     context.CancelFunc
-       chatty     bool // A copy of the chatty flag.
-       ran        bool // Test or benchmark (or one of its subtests) was executed.
-       failed     bool // Test or benchmark has failed.
-       skipped    bool // Test of benchmark has been skipped.
-       finished   bool // Test function has completed.
-       done       bool // Test is finished and all subtests have completed.
-       hasSub     bool
-       raceErrors int // number of races detected during test
+       chatty     bool         // A copy of the chatty flag.
+       ran        bool         // Test or benchmark (or one of its subtests) was executed.
+       failed     bool         // Test or benchmark has failed.
+       skipped    bool         // Test of benchmark has been skipped.
+       finished   bool         // Test function has completed.
+       done       bool         // Test is finished and all subtests have completed.
+       hasSub     int32        // written atomically
+       raceErrors int          // number of races detected during test
 
        parent   *common
        level    int       // Nesting depth of test or benchmark.
@@ -283,13 +281,6 @@ type common struct {
        sub      []*T      // Queue of subtests to be run in parallel.
 }
 
-func (c *common) parentContext() context.Context {
-       if c == nil || c.parent == nil || c.parent.ctx == nil {
-               return context.Background()
-       }
-       return c.parent.ctx
-}
-
 // Short reports whether the -test.short flag is set.
 func Short() bool {
        return *short
@@ -386,7 +377,6 @@ func fmtDuration(d time.Duration) string {
 
 // TB is the interface common to T and B.
 type TB interface {
-       Context() context.Context
        Error(args ...interface{})
        Errorf(format string, args ...interface{})
        Fail()
@@ -434,15 +424,6 @@ func (c *common) Name() string {
        return c.name
 }
 
-// Context returns the context for the current test or benchmark.
-// The context is cancelled when the test or benchmark finishes.
-// A goroutine started during a test or benchmark can wait for the
-// context's Done channel to become readable as a signal that the
-// test or benchmark is over, so that the goroutine can exit.
-func (c *common) Context() context.Context {
-       return c.ctx
-}
-
 func (c *common) setRan() {
        if c.parent != nil {
                c.parent.setRan()
@@ -619,9 +600,6 @@ type InternalTest struct {
 }
 
 func tRunner(t *T, fn func(t *T)) {
-       t.ctx, t.cancel = context.WithCancel(t.parentContext())
-       defer t.cancel()
-
        // When this goroutine is done, either because fn(t)
        // returned normally or because a test failure triggered
        // a call to runtime.Goexit, record the duration and send
@@ -668,7 +646,7 @@ func tRunner(t *T, fn func(t *T)) {
                // Do not lock t.done to allow race detector to detect race in case
                // the user does not appropriately synchronizes a goroutine.
                t.done = true
-               if t.parent != nil && !t.hasSub {
+               if t.parent != nil && atomic.LoadInt32(&t.hasSub) == 0 {
                        t.setRan()
                }
                t.signal <- true
@@ -682,8 +660,11 @@ func tRunner(t *T, fn func(t *T)) {
 
 // Run runs f as a subtest of t called name. It reports whether f succeeded.
 // Run will block until all its parallel subtests have completed.
+//
+// Run may be called simultaneously from multiple goroutines, but all such
+// calls must happen before the outer test function for t returns.
 func (t *T) Run(name string, f func(t *T)) bool {
-       t.hasSub = true
+       atomic.StoreInt32(&t.hasSub, 1)
        testName, ok := t.context.match.fullName(&t.common, name)
        if !ok {
                return true
@@ -840,6 +821,7 @@ func (m *M) Run() int {
        haveExamples = len(m.examples) > 0
        testRan, testOk := runTests(m.deps.MatchString, m.tests)
        exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
+       stopAlarm()
        if !testRan && !exampleRan && *matchBenchmarks == "" {
                fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
        }
@@ -918,11 +900,11 @@ func (m *M) before() {
        if *cpuProfile != "" {
                f, err := os.Create(toOutputDir(*cpuProfile))
                if err != nil {
-                       fmt.Fprintf(os.Stderr, "testing: %s", err)
+                       fmt.Fprintf(os.Stderr, "testing: %s\n", err)
                        return
                }
                if err := m.deps.StartCPUProfile(f); err != nil {
-                       fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err)
+                       fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
                        f.Close()
                        return
                }
@@ -931,11 +913,11 @@ func (m *M) before() {
        if *traceFile != "" {
                f, err := os.Create(toOutputDir(*traceFile))
                if err != nil {
-                       fmt.Fprintf(os.Stderr, "testing: %s", err)
+                       fmt.Fprintf(os.Stderr, "testing: %s\n", err)
                        return
                }
                if err := trace.Start(f); err != nil {
-                       fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s", err)
+                       fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
                        f.Close()
                        return
                }
index 9954f9af8cda59b5b338edff38e88e12948cb16c..45e44683b43c017cfb4512a5d8b81e19308b9d80 100644 (file)
@@ -5,42 +5,14 @@
 package testing_test
 
 import (
-       "fmt"
        "os"
-       "runtime"
        "testing"
-       "time"
 )
 
-func TestMain(m *testing.M) {
-       g0 := runtime.NumGoroutine()
-
-       code := m.Run()
-       if code != 0 {
-               os.Exit(code)
-       }
+// This is exactly what a test would do without a TestMain.
+// It's here only so that there is at least one package in the
+// standard library with a TestMain, so that code is executed.
 
-       // Check that there are no goroutines left behind.
-       t0 := time.Now()
-       stacks := make([]byte, 1<<20)
-       for {
-               g1 := runtime.NumGoroutine()
-               if g1 == g0 {
-                       return
-               }
-               stacks = stacks[:runtime.Stack(stacks, true)]
-               time.Sleep(50 * time.Millisecond)
-               if time.Since(t0) > 2*time.Second {
-                       fmt.Fprintf(os.Stderr, "Unexpected leftover goroutines detected: %v -> %v\n%s\n", g0, g1, stacks)
-                       os.Exit(1)
-               }
-       }
-}
-
-func TestContextCancel(t *testing.T) {
-       ctx := t.Context()
-       // Tests we don't leak this goroutine:
-       go func() {
-               <-ctx.Done()
-       }()
+func TestMain(m *testing.M) {
+       os.Exit(m.Run())
 }
index 3fbfa734d054dd0cad62e5317964af971a5a0d7a..b903e1485c69a67b84e0d6efdb64d286d33e119e 100644 (file)
@@ -1101,8 +1101,9 @@ func parseTimeZone(value string) (length int, ok bool) {
                if value[4] == 'T' {
                        return 5, true
                }
-       case 4: // Must end in T to match.
-               if value[3] == 'T' {
+       case 4:
+               // Must end in T, except one special case.
+               if value[3] == 'T' || value[:4] == "WITA" {
                        return 4, true
                }
        case 3:
index aa4434a09c3315fd011fc688a35d570e42dc1996..219c2caee8fd4dda440d828db2de1b94ca4edb77 100644 (file)
@@ -405,6 +405,7 @@ var parseTimeZoneTests = []ParseTimeZoneTest{
        {"ESAST hi", 5, true},
        {"ESASTT hi", 0, false}, // run of upper-case letters too long.
        {"ESATY hi", 0, false},  // five letters must end in T.
+       {"WITA hi", 4, true},    // Issue #18251
 }
 
 func TestParseTimeZone(t *testing.T) {
index f0d34856b22023f2ff89df6dfb3399280a92e2cd..47550332126e28fa61dbc2ab2295bba23154fee9 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64,go1.7
+// +build go1.7,amd64,!gccgo,!appengine
 
 package chacha20poly1305
 
index 2fa9b555a89aa27f8fa3b937ba6af0921db026aa..39c58b44a373f76c550ff0e465509154f0fcf532 100644 (file)
@@ -4,7 +4,7 @@
 
 // This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
 
-// +build go1.7
+// +build go1.7,amd64,!gccgo,!appengine
 
 #include "textflag.h"
 // General register allocation
@@ -278,8 +278,15 @@ TEXT ·chacha20Poly1305Open(SB), 0, $288-97
        MOVQ ad+72(FP), adp
 
        // Check for AVX2 support
-       CMPB runtime·support_avx2(SB), $1
-       JE   chacha20Poly1305Open_AVX2
+       CMPB runtime·support_avx2(SB), $0
+       JE   noavx2bmi2Open
+
+       // Check BMI2 bit for MULXQ.
+       // runtime·cpuid_ebx7 is always available here
+       // because it passed avx2 check
+       TESTL $(1<<8), runtime·cpuid_ebx7(SB)
+       JNE   chacha20Poly1305Open_AVX2
+noavx2bmi2Open:
 
        // Special optimization, for very short buffers
        CMPQ inl, $128
@@ -1485,8 +1492,15 @@ TEXT ·chacha20Poly1305Seal(SB), 0, $288-96
        MOVQ ad+72(FP), adp
 
        // Check for AVX2 support
-       CMPB runtime·support_avx2(SB), $1
-       JE   chacha20Poly1305Seal_AVX2
+       CMPB runtime·support_avx2(SB), $0
+       JE   noavx2bmi2Seal
+
+       // Check BMI2 bit for MULXQ.
+       // runtime·cpuid_ebx7 is always available here
+       // because it passed avx2 check
+       TESTL $(1<<8), runtime·cpuid_ebx7(SB)
+       JNE   chacha20Poly1305Seal_AVX2
+noavx2bmi2Seal:
 
        // Special optimization, for very short buffers
        CMPQ inl, $128
@@ -1691,7 +1705,7 @@ sealSSETail64:
        MOVO  D1, ctr0Store
 
 sealSSETail64LoopA:
-       // Perform ChaCha rounds, while hashing the prevsiosly encrpyted ciphertext
+       // Perform ChaCha rounds, while hashing the previously encrypted ciphertext
        polyAdd(0(oup))
        polyMul
        LEAQ 16(oup), oup
@@ -1725,7 +1739,7 @@ sealSSETail128:
        MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
 
 sealSSETail128LoopA:
-       // Perform ChaCha rounds, while hashing the prevsiosly encrpyted ciphertext
+       // Perform ChaCha rounds, while hashing the previously encrypted ciphertext
        polyAdd(0(oup))
        polyMul
        LEAQ 16(oup), oup
@@ -1771,7 +1785,7 @@ sealSSETail192:
        MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr2Store
 
 sealSSETail192LoopA:
-       // Perform ChaCha rounds, while hashing the prevsiosly encrpyted ciphertext
+       // Perform ChaCha rounds, while hashing the previously encrypted ciphertext
        polyAdd(0(oup))
        polyMul
        LEAQ 16(oup), oup
index 1d4dcd33fde451771dfd4669a7b5803f8050e841..4c2eb703c327cddc1a3caea33cfc85e9b8dd59c1 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64 !go1.7
+// +build !amd64 !go1.7 gccgo appengine
 
 package chacha20poly1305
 
index bc75c61afcf6a7dd43b529396c65f469676fcef7..2edae63828a5f0d3efa73585d3882a31c3f4343c 100644 (file)
@@ -54,9 +54,9 @@
        ADCQ  t3, h1;                  \
        ADCQ  $0, h2
 
-DATA poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
-DATA poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
-GLOBL poly1305Mask<>(SB), RODATA, $16
+DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
+DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
+GLOBL ·poly1305Mask<>(SB), RODATA, $16
 
 // func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key)
 TEXT ·poly1305(SB), $0-32
@@ -67,8 +67,8 @@ TEXT ·poly1305(SB), $0-32
 
        MOVQ 0(AX), R11
        MOVQ 8(AX), R12
-       ANDQ poly1305Mask<>(SB), R11   // r0
-       ANDQ poly1305Mask<>+8(SB), R12 // r1
+       ANDQ ·poly1305Mask<>(SB), R11   // r0
+       ANDQ ·poly1305Mask<>+8(SB), R12 // r1
        XORQ R8, R8                    // h0
        XORQ R9, R9                    // h1
        XORQ R10, R10                  // h2
index 93167b27129c103620ee72bd4be9adfb9209ce5a..f70b4ac484518ba4a6e16009a769b0472e902bc1 100644 (file)
@@ -9,12 +9,12 @@
 // This code was translated into a form compatible with 5a from the public
 // domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305.
 
-DATA poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
-DATA poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
-DATA poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
-DATA poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
-DATA poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
-GLOBL poly1305_init_constants_armv6<>(SB), 8, $20
+DATA ·poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
+DATA ·poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
+DATA ·poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
+DATA ·poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
+DATA ·poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
+GLOBL ·poly1305_init_constants_armv6<>(SB), 8, $20
 
 // Warning: the linker may use R11 to synthesize certain instructions. Please
 // take care and verify that no synthetic instructions use it.
@@ -27,7 +27,7 @@ TEXT poly1305_init_ext_armv6<>(SB), NOSPLIT, $0
        ADD       $4, R13, R8
        MOVM.IB   [R4-R7], (R8)
        MOVM.IA.W (R1), [R2-R5]
-       MOVW      $poly1305_init_constants_armv6<>(SB), R7
+       MOVW      $·poly1305_init_constants_armv6<>(SB), R7
        MOVW      R2, R8
        MOVW      R2>>26, R9
        MOVW      R3>>20, g
diff --git a/test/alias2.go b/test/alias2.go
new file mode 100644 (file)
index 0000000..32c3654
--- /dev/null
@@ -0,0 +1,104 @@
+// errorcheck
+
+// Copyright 2016 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.
+
+// Test basic restrictions on type aliases.
+
+package p
+
+import (
+       "reflect"
+       . "reflect"
+)
+
+type T0 struct{}
+
+// Valid type alias declarations.
+
+type _ = T0
+type _ = int
+type _ = struct{}
+type _ = reflect.Value
+type _ = Value
+
+type (
+       A0 = T0
+       A1 = int
+       A2 = struct{}
+       A3 = reflect.Value
+       A4 = Value
+       A5 = Value
+
+       N0 A0
+)
+
+// Methods can be declared on the original named type and the alias.
+func (T0) m1()  {} // GCCGO_ERROR "previous"
+func (*T0) m1() {} // ERROR "method redeclared: T0\.m1|redefinition of .m1."
+func (A0) m1()  {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
+func (A0) m1()  {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
+func (A0) m2()  {}
+
+// Type aliases and the original type name can be used interchangeably.
+var _ A0 = T0{}
+var _ T0 = A0{}
+
+// But aliases and original types cannot be used with new types based on them.
+var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+
+var _ A5 = Value{}
+
+var _ interface {
+       m1()
+       m2()
+} = T0{}
+
+var _ interface {
+       m1()
+       m2()
+} = A0{}
+
+func _() {
+       type _ = T0
+       type _ = int
+       type _ = struct{}
+       type _ = reflect.Value
+       type _ = Value
+
+       type (
+               A0 = T0
+               A1 = int
+               A2 = struct{}
+               A3 = reflect.Value
+               A4 = Value
+               A5 Value
+
+               N0 A0
+       )
+
+       var _ A0 = T0{}
+       var _ T0 = A0{}
+
+       var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+       var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+
+       var _ A5 = Value{} // ERROR "cannot use reflect\.Value literal \(type reflect.Value\) as type A5 in assignment|incompatible type"
+}
+
+// Invalid type alias declarations.
+
+type _ = reflect.ValueOf // ERROR "reflect.ValueOf is not a type|expected type"
+
+func (A1) m() {} // ERROR "cannot define new methods on non-local type int|may not define methods on non-local type"
+func (A2) m() {} // ERROR "invalid receiver type"
+func (A3) m() {} // ERROR "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
+func (A4) m() {} // ERROR "reflect.Value.m redeclared in this block" "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
+
+type B1 = struct{}
+
+func (B1) m() {} // ERROR "m redeclared in this block" "invalid receiver type"
+
+// TODO(gri) expand
diff --git a/test/alias3.dir/a.go b/test/alias3.dir/a.go
new file mode 100644 (file)
index 0000000..09b3408
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2017 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 a
+
+import "go/build"
+
+type (
+       Float64 = float64
+       Rune    = rune
+)
+
+type (
+       Int       int
+       IntAlias  = Int
+       IntAlias2 = IntAlias
+       S         struct {
+               Int
+               IntAlias
+               IntAlias2
+       }
+)
+
+type (
+       Context = build.Context
+)
+
+type (
+       I1 interface {
+               M1(IntAlias2) Float64
+               M2() Context
+       }
+
+       I2 = interface {
+               M1(Int) float64
+               M2() build.Context
+       }
+)
+
+var i1 I1
+var i2 I2 = i1
diff --git a/test/alias3.dir/b.go b/test/alias3.dir/b.go
new file mode 100644 (file)
index 0000000..8a86cc0
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2017 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 b
+
+import (
+       "./a"
+       . "go/build"
+)
+
+func F(x float64) a.Float64 {
+       return x
+}
+
+type MyContext = Context // = build.Context
+
+var C a.Context = Default
+
+type S struct{}
+
+func (S) M1(x a.IntAlias) float64 { return a.Float64(x) }
+func (S) M2() Context             { return Default }
+
+var _ a.I1 = S{}
+var _ a.I2 = S{}
diff --git a/test/alias3.dir/c.go b/test/alias3.dir/c.go
new file mode 100644 (file)
index 0000000..161d593
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "./a"
+       "./b"
+)
+
+func main() {
+       var _ float64 = b.F(0)
+       var _ a.Rune = int32(0)
+
+       // embedded types can have different names but the same types
+       var s a.S
+       s.Int = 1
+       s.IntAlias = s.Int
+       s.IntAlias2 = s.Int
+
+       // aliases denote identical types across packages
+       var c a.Context = b.C
+       var _ b.MyContext = c
+}
diff --git a/test/alias3.go b/test/alias3.go
new file mode 100644 (file)
index 0000000..c3732c3
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2017 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 ignored
index 99d8c9754b1188bf2ca95afc9b39ebf4cc4e605c..af4fbac274c125756988ff517b8d47e041159fe1 100644 (file)
@@ -12,10 +12,10 @@ var fastabytes = makefasta()
 
 func makefasta() []byte {
        var n int = 25e6
-       if runtime.GOARCH == "arm" {
+       if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" {
                // TODO(dfc) remove this limitation after precise gc.
                // A value of 25e6 consumes 465mb of heap on 32bit
-               // platforms, which is too much for most ARM systems.
+               // platforms, which is too much for some systems.
                // A value of 25e5 produces a memory layout that
                // confuses the gc on 32bit platforms. So 25e4 it is.
                n = 25e4
diff --git a/test/fixedbugs/bug501.go b/test/fixedbugs/bug501.go
new file mode 100644 (file)
index 0000000..8e951b1
--- /dev/null
@@ -0,0 +1,24 @@
+// run
+
+// Copyright 2016 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.
+
+// Gccgo got a compiler crash compiling the addition of more than five
+// strings with mixed constants and variables.
+
+package main
+
+func F(s string) (string, error) {
+       return s, nil
+}
+
+func G(a, b, c string) (string, error) {
+       return F("a" + a + "b" + b + "c" + c)
+}
+
+func main() {
+       if got, _ := G("x", "y", "z"); got != "axbycz" {
+               panic(got)
+       }
+}
diff --git a/test/fixedbugs/gcc78763.go b/test/fixedbugs/gcc78763.go
new file mode 100644 (file)
index 0000000..3e34127
--- /dev/null
@@ -0,0 +1,19 @@
+// compile
+
+// Copyright 2016 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.
+
+// The gccgo compiler crashed while compiling this code.
+// https://gcc.gnu.org/PR78763.
+
+package p
+
+import "unsafe"
+
+func F() int {
+       if unsafe.Sizeof(0) == 8 {
+               return 8
+       }
+       return 0
+}
index 52fb51ad39944cc600fffc1c148f05c0cc2bfc6e..8831547da86d270afcf3fc0731359fa2569ae6a8 100644 (file)
@@ -1,4 +1,4 @@
-// +build linux,!mips,!mipsle,!ppc64
+// +build linux,!ppc64
 // run
 
 // Copyright 2015 The Go Authors. All rights reserved.
diff --git a/test/fixedbugs/issue10958.go b/test/fixedbugs/issue10958.go
new file mode 100644 (file)
index 0000000..86d2057
--- /dev/null
@@ -0,0 +1,95 @@
+// +build !nacl,disabled
+// buildrun -t 10  -gcflags=-d=ssa/insert_resched_checks/on,ssa/check/on
+
+// Copyright 2016 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.
+
+// Test is disabled because it flakes when run in all.bash
+// on some platforms, but is useful standalone to verify
+// that rescheduling checks are working (and we may wish
+// to investigate the flake, since it suggests that the
+// loop rescheduling check may not work right on those
+// platforms).
+
+// This checks to see that call-free infinite loops do not
+// block garbage collection.  IF YOU RUN IT STANDALONE without
+// -gcflags=-d=ssa/insert_resched_checks/on in a not-experimental
+// build, it should hang.
+
+package main
+
+import (
+       "runtime"
+)
+
+var someglobal1 int
+var someglobal2 int
+var someglobal3 int
+
+//go:noinline
+func f() {}
+
+func standinacorner1() {
+       for someglobal1&1 == 0 {
+               someglobal1++
+               someglobal1++
+       }
+}
+
+func standinacorner2(i int) {
+       // contains an irreducible loop containing changes to memory
+       if i != 0 {
+               goto midloop
+       }
+
+loop:
+       if someglobal2&1 != 0 {
+               goto done
+       }
+       someglobal2++
+midloop:
+       someglobal2++
+       goto loop
+
+done:
+       return
+}
+
+func standinacorner3() {
+       for someglobal3&1 == 0 {
+               if someglobal3&2 != 0 {
+                       for someglobal3&3 == 2 {
+                               someglobal3++
+                               someglobal3++
+                               someglobal3++
+                               someglobal3++
+                       }
+               }
+               someglobal3++
+               someglobal3++
+               someglobal3++
+               someglobal3++
+       }
+}
+
+func main() {
+       go standinacorner1()
+       go standinacorner2(0)
+       go standinacorner3()
+       // println("About to stand in a corner1")
+       for someglobal1 == 0 {
+               runtime.Gosched()
+       }
+       // println("About to stand in a corner2")
+       for someglobal2 == 0 {
+               runtime.Gosched()
+       }
+       // println("About to stand in a corner3")
+       for someglobal3 == 0 {
+               runtime.Gosched()
+       }
+       // println("About to GC")
+       runtime.GC()
+       // println("Success")
+}
index e0ef09760099b3fa639bd0dbaab84410e48f4733..c04a66202b63857de558d06c6d7cd876ae5c9781 100644 (file)
@@ -61,9 +61,9 @@ func f(n int) {
                binary.BigEndian.PutUint32(ill, 0x7fe00008) // trap
        case "ppc64le":
                binary.LittleEndian.PutUint32(ill, 0x7fe00008) // trap
-       case "mips64":
+       case "mips", "mips64":
                binary.BigEndian.PutUint32(ill, 0x00000034) // trap
-       case "mips64le":
+       case "mipsle", "mips64le":
                binary.LittleEndian.PutUint32(ill, 0x00000034) // trap
        case "s390x":
                binary.BigEndian.PutUint32(ill, 0) // undefined instruction
index 19c8264c6f810dc67b2a3a7f4ef8976200df1d7f..c4e3ffd33db9fa15353b60eb65b0197574ed0391 100644 (file)
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Test that an interface conversion error panics with an "interface
-// conversion" run-time error. It was (incorrectly) panicing with a
+// conversion" run-time error. It was (incorrectly) panicking with a
 // "nil pointer dereference."
 
 package main
diff --git a/test/fixedbugs/issue18392.go b/test/fixedbugs/issue18392.go
new file mode 100644 (file)
index 0000000..ad64238
--- /dev/null
@@ -0,0 +1,11 @@
+// errorcheck
+
+// Copyright 2017 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 p
+
+type A interface {
+       Fn(A.Fn) // ERROR "type A has no method A.Fn"
+}
diff --git a/test/fixedbugs/issue18410.go b/test/fixedbugs/issue18410.go
new file mode 100644 (file)
index 0000000..e9c6f86
--- /dev/null
@@ -0,0 +1,40 @@
+// run
+
+// Copyright 2016 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.
+
+// This checks partially initialized structure literals
+// used to create value.method functions have their
+// non-initialized fields properly zeroed/nil'd
+
+package main
+
+type X struct {
+       A, B, C *int
+}
+
+//go:noinline
+func (t X) Print() {
+       if t.B != nil {
+               panic("t.B must be nil")
+       }
+}
+
+//go:noinline
+func caller(f func()) {
+       f()
+}
+
+//go:noinline
+func test() {
+       var i, j int
+       x := X{A: &i, C: &j}
+       caller(func() { X{A: &i, C: &j}.Print() })
+       caller(X{A: &i, C: &j}.Print)
+       caller(x.Print)
+}
+
+func main() {
+       test()
+}
diff --git a/test/fixedbugs/issue18459.go b/test/fixedbugs/issue18459.go
new file mode 100644 (file)
index 0000000..ac07661
--- /dev/null
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2016 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.
+
+// Verify that we have a line number for this error.
+
+package main
+
+//go:nowritebarrier // ERROR "go:nowritebarrier only allowed in runtime"
+func main() {
+}
diff --git a/test/fixedbugs/issue18640.go b/test/fixedbugs/issue18640.go
new file mode 100644 (file)
index 0000000..c4f948b
--- /dev/null
@@ -0,0 +1,26 @@
+// compile
+
+// Copyright 2017 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 p
+
+type (
+       a = b
+       b struct {
+               *a
+       }
+
+       c struct {
+               *d
+       }
+       d = c
+
+       e = f
+       f = g
+       g = []h
+       h i
+       i = j
+       j = e
+)
diff --git a/test/fixedbugs/issue18655.go b/test/fixedbugs/issue18655.go
new file mode 100644 (file)
index 0000000..abc2600
--- /dev/null
@@ -0,0 +1,22 @@
+// errorcheck
+
+// Copyright 2017 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 p
+
+type T struct{}
+type A = T
+type B = T
+
+func (T) m() {}
+func (T) m() {} // ERROR "redeclared"
+func (A) m() {} // ERROR "redeclared"
+func (A) m() {} // ERROR "redeclared"
+func (B) m() {} // ERROR "redeclared"
+func (B) m() {} // ERROR "redeclared"
+
+func (*T) m() {} // ERROR "redeclared"
+func (*A) m() {} // ERROR "redeclared"
+func (*B) m() {} // ERROR "redeclared"
diff --git a/test/fixedbugs/issue18661.go b/test/fixedbugs/issue18661.go
new file mode 100644 (file)
index 0000000..8c83775
--- /dev/null
@@ -0,0 +1,18 @@
+// compile
+
+// Copyright 2017 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 p
+
+var (
+       e interface{}
+       s = struct{ a *int }{}
+       b = e == s
+)
+
+func test(obj interface{}) {
+       if obj != struct{ a *string }{} {
+       }
+}
diff --git a/test/fixedbugs/issue18725.go b/test/fixedbugs/issue18725.go
new file mode 100644 (file)
index 0000000..c632dba
--- /dev/null
@@ -0,0 +1,24 @@
+// run
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func panicWhenNot(cond bool) {
+       if cond {
+               os.Exit(0)
+       } else {
+               panic("nilcheck elim failed")
+       }
+}
+
+func main() {
+       e := (*string)(nil)
+       panicWhenNot(e == e)
+       // Should never reach this line.
+       panicWhenNot(*e == *e)
+}
diff --git a/test/fixedbugs/issue18808.go b/test/fixedbugs/issue18808.go
new file mode 100644 (file)
index 0000000..c98386e
--- /dev/null
@@ -0,0 +1,63 @@
+// run
+
+// Copyright 2017 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
+
+const lim = 0x80000000
+
+//go:noinline
+func eq(x uint32) {
+       if x == lim {
+               return
+       }
+       panic("x == lim returned false")
+}
+
+//go:noinline
+func neq(x uint32) {
+       if x != lim {
+               panic("x != lim returned true")
+       }
+}
+
+//go:noinline
+func gt(x uint32) {
+       if x > lim {
+               return
+       }
+       panic("x > lim returned false")
+}
+
+//go:noinline
+func gte(x uint32) {
+       if x >= lim {
+               return
+       }
+       panic("x >= lim returned false")
+}
+
+//go:noinline
+func lt(x uint32) {
+       if x < lim {
+               panic("x < lim returned true")
+       }
+}
+
+//go:noinline
+func lte(x uint32) {
+       if x <= lim {
+               panic("x <= lim returned true")
+       }
+}
+
+func main() {
+       eq(lim)
+       neq(lim)
+       gt(lim+1)
+       gte(lim+1)
+       lt(lim+1)
+       lte(lim+1)
+}
diff --git a/test/fixedbugs/issue6772.go b/test/fixedbugs/issue6772.go
new file mode 100644 (file)
index 0000000..4d0001c
--- /dev/null
@@ -0,0 +1,21 @@
+// errorcheck
+
+// Copyright 2016 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 p
+
+func f1() {
+       for a, a := range []int{1, 2, 3} { // ERROR "a repeated on left side of :="
+               println(a)
+       }
+}
+
+func f2() {
+       var a int
+       for a, a := range []int{1, 2, 3} { // ERROR "a repeated on left side of :="
+               println(a)
+       }
+       println(a)
+}
index 4fb231cfef9df5838471690da26a1f45ac489232..b23e1509e01da640e33a0023dd41817e02f2116d 100644 (file)
@@ -1,6 +1,7 @@
-// errorcheckwithauto -0 -l -live -wb=0
+// errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off
 // +build !ppc64,!ppc64le
 // ppc64 needs a better tighten pass to make f18 pass
+// rescheduling checks need to be turned off because there are some live variables across the inserted check call
 
 // Copyright 2014 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 8fdae8c075f0651243b99f3b06f07a0847154425..c681cba50c4cf1ce93c0c1fa278cd8c4a933d316 100644 (file)
@@ -40,23 +40,23 @@ var (
 )
 
 func f1() {
-       _ = *intp // ERROR "generated nil check"
+       _ = *intp // ERROR "removed nil check"
 
        // This one should be removed but the block copy needs
        // to be turned into its own pseudo-op in order to see
        // the indirect.
-       _ = *arrayp // ERROR "generated nil check"
+       _ = *arrayp // ERROR "removed nil check"
 
        // 0-byte indirect doesn't suffice.
        // we don't registerize globals, so there are no removed.* nil checks.
-       _ = *array0p // ERROR "generated nil check"
        _ = *array0p // ERROR "removed nil check"
+       _ = *array0p // ERROR "generated nil check"
 
-       _ = *intp    // ERROR "removed nil check"
+       _ = *intp    // ERROR "generated nil check"
        _ = *arrayp  // ERROR "removed nil check"
        _ = *structp // ERROR "generated nil check"
        _ = *emptyp  // ERROR "generated nil check"
-       _ = *arrayp  // ERROR "removed nil check"
+       _ = *arrayp  // ERROR "generated nil check"
 }
 
 func f2() {
@@ -71,15 +71,15 @@ func f2() {
                empty1p    *Empty1
        )
 
-       _ = *intp       // ERROR "generated nil check"
-       _ = *arrayp     // ERROR "generated nil check"
-       _ = *array0p    // ERROR "generated nil check"
-       _ = *array0p    // ERROR "removed.* nil check"
        _ = *intp       // ERROR "removed.* nil check"
        _ = *arrayp     // ERROR "removed.* nil check"
+       _ = *array0p    // ERROR "removed.* nil check"
+       _ = *array0p    // ERROR "generated nil check"
+       _ = *intp       // ERROR "generated nil check"
+       _ = *arrayp     // ERROR "removed.* nil check"
        _ = *structp    // ERROR "generated nil check"
        _ = *emptyp     // ERROR "generated nil check"
-       _ = *arrayp     // ERROR "removed.* nil check"
+       _ = *arrayp     // ERROR "generated nil check"
        _ = *bigarrayp  // ERROR "generated nil check" ARM removed nil check before indirect!!
        _ = *bigstructp // ERROR "generated nil check"
        _ = *empty1p    // ERROR "generated nil check"
@@ -122,16 +122,16 @@ func f3(x *[10000]int) {
        // x wasn't going to change across the function call.
        // But it's a little complex to do and in practice doesn't
        // matter enough.
-       _ = x[9999] // ERROR "removed nil check"
+       _ = x[9999] // ERROR "generated nil check" // TODO: fix
 }
 
 func f3a() {
        x := fx10k()
        y := fx10k()
        z := fx10k()
-       _ = &x[9] // ERROR "generated nil check"
-       y = z
        _ = &x[9] // ERROR "removed.* nil check"
+       y = z
+       _ = &x[9] // ERROR "generated nil check"
        x = y
        _ = &x[9] // ERROR "generated nil check"
 }
@@ -139,11 +139,11 @@ func f3a() {
 func f3b() {
        x := fx10k()
        y := fx10k()
-       _ = &x[9] // ERROR "generated nil check"
+       _ = &x[9] // ERROR "removed.* nil check"
        y = x
        _ = &x[9] // ERROR "removed.* nil check"
        x = y
-       _ = &x[9] // ERROR "removed.* nil check"
+       _ = &x[9] // ERROR "generated nil check"
 }
 
 func fx10() *[10]int
@@ -179,15 +179,15 @@ func f4(x *[10]int) {
        _ = x[9] // ERROR "generated nil check"  // bug would like to remove before indirect
 
        fx10()
-       _ = x[9] // ERROR "removed nil check"
+       _ = x[9] // ERROR "generated nil check"  // TODO: fix
 
        x = fx10()
        y := fx10()
-       _ = &x[9] // ERROR "generated nil check"
+       _ = &x[9] // ERROR "removed[a-z ]* nil check"
        y = x
        _ = &x[9] // ERROR "removed[a-z ]* nil check"
        x = y
-       _ = &x[9] // ERROR "removed[a-z ]* nil check"
+       _ = &x[9] // ERROR "generated nil check"
 }
 
 func f5(p *float32, q *float64, r *float32, s *float64) float64 {
index 5f4e62f5b15a79f983bf91e52fa8edeefc2e33c7..e0d531c116d2f7550ef2665fd173863a5eb042dc 100644 (file)
@@ -261,6 +261,8 @@ TestCases:
                var buf bytes.Buffer
                ptrSize := 4
                switch goarch {
+               case "mips", "mipsle":
+                       fmt.Fprintf(&buf, "#define CALL JAL\n#define REGISTER (R0)\n")
                case "mips64", "mips64le":
                        ptrSize = 8
                        fmt.Fprintf(&buf, "#define CALL JAL\n#define REGISTER (R0)\n")
index 5781253e3edf589770b4973ca951f6d9b82ddad4..84de32179f38a0a4b8e99e729c48a1b1cf8acc44 100644 (file)
@@ -1,5 +1,6 @@
 // +build amd64
-// errorcheck -0 -d=ssa/likelyadjust/debug=1
+// errorcheck -0 -d=ssa/likelyadjust/debug=1,ssa/insert_resched_checks/off
+// rescheduling check insertion is turend off because the inserted conditional branches perturb the errorcheck
 
 // Copyright 2016 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 0dee6b5caab41a96fde48b1a75ac4bef1f53ecbe..19ca3287651388d34ef71171930e708b6dd9a4af 100644 (file)
@@ -463,6 +463,7 @@ func (t *test) run() {
        }
 
        var args, flags []string
+       var tim int
        wantError := false
        wantAuto := false
        singlefilepkgs := false
@@ -478,7 +479,7 @@ func (t *test) run() {
                action = "rundir"
        case "cmpout":
                action = "run" // the run case already looks for <dir>/<test>.out files
-       case "compile", "compiledir", "build", "run", "runoutput", "rundir":
+       case "compile", "compiledir", "build", "run", "buildrun", "runoutput", "rundir":
                // nothing to do
        case "errorcheckandrundir":
                wantError = false // should be no error if also will run
@@ -505,6 +506,14 @@ func (t *test) run() {
                        wantError = false
                case "-s":
                        singlefilepkgs = true
+               case "-t": // timeout in seconds
+                       args = args[1:]
+                       var err error
+                       tim, err = strconv.Atoi(args[0])
+                       if err != nil {
+                               t.err = fmt.Errorf("need number of seconds for -t timeout, got %s instead", args[0])
+                       }
+
                default:
                        flags = append(flags, args[0])
                }
@@ -539,7 +548,31 @@ func (t *test) run() {
                } else {
                        cmd.Env = os.Environ()
                }
-               err := cmd.Run()
+
+               var err error
+
+               if tim != 0 {
+                       err = cmd.Start()
+                       // This command-timeout code adapted from cmd/go/test.go
+                       if err == nil {
+                               tick := time.NewTimer(time.Duration(tim) * time.Second)
+                               done := make(chan error)
+                               go func() {
+                                       done <- cmd.Wait()
+                               }()
+                               select {
+                               case err = <-done:
+                                       // ok
+                               case <-tick.C:
+                                       cmd.Process.Kill()
+                                       err = <-done
+                                       // err = errors.New("Test timeout")
+                               }
+                               tick.Stop()
+                       }
+               } else {
+                       err = cmd.Run()
+               }
                if err != nil {
                        err = fmt.Errorf("%s\n%s", err, buf.Bytes())
                }
@@ -671,6 +704,32 @@ func (t *test) run() {
                        t.err = err
                }
 
+       case "buildrun": // build binary, then run binary, instead of go run. Useful for timeout tests where failure mode is infinite loop.
+               // TODO: not supported on NaCl
+               useTmp = true
+               cmd := []string{"go", "build", "-o", "a.exe"}
+               if *linkshared {
+                       cmd = append(cmd, "-linkshared")
+               }
+               longdirgofile := filepath.Join(filepath.Join(cwd, t.dir), t.gofile)
+               cmd = append(cmd, flags...)
+               cmd = append(cmd, longdirgofile)
+               out, err := runcmd(cmd...)
+               if err != nil {
+                       t.err = err
+                       return
+               }
+               cmd = []string{"./a.exe"}
+               out, err = runcmd(append(cmd, args...)...)
+               if err != nil {
+                       t.err = err
+                       return
+               }
+
+               if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
+                       t.err = fmt.Errorf("incorrect output\n%s", out)
+               }
+
        case "run":
                useTmp = false
                cmd := []string{"go", "run"}
index 9ab2713535906194bc917ad50f76f4d062bc56ef..214d481164442aab25c7e5f9189933108a54c005 100644 (file)
@@ -28,6 +28,8 @@ var (
        i32, j32, k32 int32 = 0, 0, 1
        i64, j64, k64 int64 = 0, 0, 1
 
+       bb = []int16{2, 0}
+
        u, v, w       uint    = 0, 0, 1
        u8, v8, w8    uint8   = 0, 0, 1
        u16, v16, w16 uint16  = 0, 0, 1
@@ -124,6 +126,10 @@ var errorTests = []ErrorTest{
        ErrorTest{"int32 1/0", func() { use(k32 / j32) }, "divide"},
        ErrorTest{"int64 1/0", func() { use(k64 / j64) }, "divide"},
 
+       // From issue 5790, we should ensure that _ assignments
+       // still evaluate and generate zerodivide panics.
+       ErrorTest{"int16 _ = bb[0]/bb[1]", func() { _ = bb[0] / bb[1] }, "divide"},
+
        ErrorTest{"uint 0/0", func() { use(u / v) }, "divide"},
        ErrorTest{"uint8 0/0", func() { use(u8 / v8) }, "divide"},
        ErrorTest{"uint16 0/0", func() { use(u16 / v16) }, "divide"},
@@ -195,9 +201,6 @@ func alike(a, b float64) bool {
 func main() {
        bad := false
        for _, t := range errorTests {
-               if t.err != "" {
-                       continue
-               }
                err := error_(t.fn)
                switch {
                case t.err == "" && err == "":